123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- <?php
- namespace app\common\Service\Pay\Provider;
- use think\Log;
- use think\Exception;
- use think\exception\HttpResponseException;
- use Yansongda\Pay\Pay;
- use app\common\Enum\ChannelEnum;
- /**
- * 抖音支付提供器
- */
- class Douyin extends Base
- {
- /**
- * 构造函数
- * @param mixed $payService
- * @param string $platform
- * @param string $channel
- */
- public function __construct($payService, $platform = null, $channel = null)
- {
- parent::__construct($payService, $platform, $channel);
- }
- /**
- * 抖音支付
- * @param array $order
- * @param array $config
- * @return array
- */
- public function pay($order, $config = [])
- {
- $this->init('douyin', $config);
- // 按照抖音支付API要求构建订单参数
- $orderData = [
- 'out_order_no' => $order['out_order_no'] ?? $order['out_trade_no'],
- 'total_amount' => intval(bcmul((string)$order['total_amount'], '100')), // 抖音支付金额单位为分
- 'subject' => $order['subject'] ?? '商品支付',
- 'body' => $order['body'] ?? '商品支付',
- 'valid_time' => $config['valid_time'] ?? 600, // 默认10分钟
- ];
- // 添加可选参数
- if (isset($order['cp_extra'])) {
- $orderData['cp_extra'] = $order['cp_extra'];
- }
-
- if (isset($config['disable_msg'])) {
- $orderData['disable_msg'] = $config['disable_msg'];
- }
-
- if (isset($config['msg_page'])) {
- $orderData['msg_page'] = $config['msg_page'];
- }
- // 获取支付方法
- $method = $this->getMethod('douyin');
-
- // 调用 Yansongda\Pay 进行支付
- $result = Pay::douyin()->$method($orderData);
- Log::write('抖音支付预下单响应:' . json_encode($result->toArray(), JSON_UNESCAPED_UNICODE));
- return $result;
- }
- /**
- * 转账功能(抖音支付暂不支持)
- * @param array $payload
- * @param array $config
- * @return array
- */
- public function transfer($payload, $config = [])
- {
- throw new Exception('抖音支付暂不支持转账功能');
- }
- /**
- * 支付回调处理
- * @param callable $callback
- * @param array $config
- * @return string
- */
- public function notify($callback, $config = [])
- {
- $this->init('douyin', $config);
-
- try {
- // 使用 Yansongda\Pay 处理回调验签
- $data = Pay::douyin()->callback();
-
- Log::write('抖音支付回调原始数据:' . json_encode($data, JSON_UNESCAPED_UNICODE));
-
- // 处理支付成功回调
- if ($data['type'] === 'payment') {
- // 格式化数据为统一格式
-
- $arrMsg = json_decode($data['msg'], true);
-
- $callbackData = [
- 'out_trade_no' => $arrMsg['cp_orderno'] ?? '',
- 'transaction_id' => $arrMsg['order_id'] ?? '',
- 'total_amount' => $arrMsg['total_amount'] ?? 0,
- 'pay_fee' => $arrMsg['total_amount'] ?? 0, // 抖音支付金额单位为分,这里保持原样
- 'notify_time' => date('Y-m-d H:i:s'),
- // 'buyer_info' => $data['buyer_info'] ?? '',
- // 'cp_extra' => $data['cp_extra'] ?? ''
- ];
- $result = $callback($callbackData, $data);
- return $result;
- }
- Log::error('抖音支付回调类型不支持: ' . ($data['type'] ?? 'unknown'));
- return 'fail';
- } catch (HttpResponseException $e) {
- $data = $e->getResponse()->getData();
- $message = $data ? ($data['msg'] ?? '') : $e->getMessage();
- $this->logPayment('抖音支付回调HttpResponseException', ['error' => $message], 'error');
- return 'fail';
- } catch (\Exception $e) {
- $this->logPayment('抖音支付回调异常', ['error' => $e->getMessage()], 'error');
- return 'fail';
- }
- }
- /**
- * 退款
- * @param array $order_data
- * @param array $config
- * @return array
- */
- public function refund($order_data, $config = [])
- {
- $this->init('douyin', $config);
- // 构建退款参数
- $refundData = [
- 'out_order_no' => $order_data['out_trade_no'],
- 'out_refund_no' => $order_data['out_refund_no'],
- 'refund_amount' => intval($order_data['refund_amount']), // 抖音退款金额单位为分
- 'reason' => $order_data['reason'] ?? '用户申请退款',
- ];
- // 如果有回调地址配置
- if (isset($config['notify_url'])) {
- $refundData['notify_url'] = $config['notify_url'];
- }
- // 调用 Yansongda\Pay 进行退款
- $result = Pay::douyin()->refund($refundData);
- Log::write('抖音退款响应:' . json_encode($result->toArray(), JSON_UNESCAPED_UNICODE));
- return $result;
- }
- /**
- * 退款回调处理
- * @param callable $callback
- * @param array $config
- * @return string
- */
- public function notifyRefund($callback, $config = [])
- {
- $this->init('douyin', $config);
-
- try {
- // 使用 Yansongda\Pay 处理退款回调验签
- $data = Pay::douyin()->callback();
-
- Log::write('抖音退款回调原始数据:' . json_encode($data, JSON_UNESCAPED_UNICODE));
-
- // 处理退款成功回调
- if ($data['type'] === 'refund' && $data['msg'] === 'success') {
- $result = $callback($data, $data);
- return $result;
- }
- Log::error('抖音退款回调类型不支持: ' . ($data['type'] ?? 'unknown'));
- return 'fail';
- } catch (HttpResponseException $e) {
- $data = $e->getResponse()->getData();
- $message = $data ? ($data['msg'] ?? '') : $e->getMessage();
- $this->logPayment('抖音退款回调HttpResponseException', ['error' => $message], 'error');
- return 'fail';
- } catch (\Exception $e) {
- $this->logPayment('抖音退款回调异常', ['error' => $e->getMessage()], 'error');
- return 'fail';
- }
- }
- /**
- * 格式化支付参数
- * @param array $config
- * @param array $data
- * @param string $type
- * @return array
- */
- protected function formatConfig($config, $data = [], $type = 'normal')
- {
- // 设置抖音支付的基本配置
- $config['app_id'] = $data['app_id'] ?? '';
- $config['secret'] = $data['secret'] ?? $data['salt'] ?? '';
-
- // 设置回调URL
- $platform = $this->platform ?? 'DouyinMiniProgram';
- $config['notify_url'] = request()->domain() . '/api/pay/notify/payment/douyin/platform/' . $platform;
-
- // 设置抖音支付网关(沙盒和生产环境)
- if (isset($config['sandbox']) && $config['sandbox']) {
- $config['mode'] = Pay::MODE_SANDBOX;
- } else {
- $config['mode'] = Pay::MODE_NORMAL;
- }
- return $config;
- }
- }
|