PaymentProvider.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <?php
  2. declare(strict_types=1);
  3. namespace SixShop\Lakala;
  4. use SixShop\Lakala\Dto\LocationInfo;
  5. use SixShop\Lakala\Facade\TransactionService;
  6. use SixShop\Lakala\OpenAPISDK\V3\Model\TradePreorderWechaAccBusiFields;
  7. use SixShop\Lakala\OpenAPISDK\V3\Model\TradePreorderWechaDetail;
  8. use SixShop\Lakala\OpenAPISDK\V3\Model\TradePreorderWechaGoodsDetail;
  9. use SixShop\Payment\Contracts\PaymentNotifyResult;
  10. use SixShop\Payment\Contracts\PaymentProviderInterface;
  11. use SixShop\Payment\Contracts\PaymentQueryResult;
  12. use SixShop\Payment\Contracts\PaymentRefundRequest;
  13. use SixShop\Payment\Contracts\PaymentRefundResult;
  14. use SixShop\Payment\Contracts\PaymentResponse;
  15. use SixShop\Payment\Entity\ExtensionPaymentEntity;
  16. use SixShop\Payment\Enum\PaymentBizEnum;
  17. use SixShop\Payment\Enum\PaymentStatusEnum;
  18. use SixShop\Payment\Event\PaymentSuccessEvent;
  19. use think\facade\Event;
  20. class PaymentProvider implements PaymentProviderInterface
  21. {
  22. public function __construct(
  23. private readonly Config $config,
  24. private readonly ExtensionPaymentEntity $extensionPaymentEntity,
  25. )
  26. {
  27. }
  28. #[\Override] public function create(array $order, PaymentBizEnum $bizType): PaymentResponse
  29. {
  30. $payment = $this->extensionPaymentEntity->where([
  31. 'order_id' => $order['id'],
  32. 'pay_type' => Extension::EXTENSION_ID,
  33. 'biz_type' => $bizType,
  34. ])->findOrEmpty();
  35. if (!$payment->isEmpty()) {
  36. // todo 判断订单是否支付成功
  37. // 支付时间结束关闭订单
  38. // 订单未支付可重新支付
  39. // 交易已关闭请重新下单
  40. //订单已付款请勿重复操作
  41. // 订单已退款请重新下单
  42. //订单已撤销请重新下单
  43. // 订单支付中请稍后再试
  44. // 订单支付失败请重新下单
  45. throw new \RuntimeException('开发测试中,请稍后再试');
  46. }
  47. $payment->transaction(function () use ($bizType, $order, $payment) {
  48. $randomDiscount = mt_rand(0, intval($this->config->random_discount_max * 100)) / 100;
  49. $order['pay_amount'] = $order['pay_amount'] - $randomDiscount;
  50. $order['pay_amount'] = max(0.01, round($order['pay_amount'], 2));
  51. $payment->save([
  52. 'user_id' => $order['user_id'],
  53. 'order_id' => $order['id'],
  54. 'order_sn' => $order['order_sn'],
  55. 'biz_type' => $bizType,
  56. 'pay_type' => Extension::EXTENSION_ID,
  57. 'amount' => $order['pay_amount'],
  58. 'status' => PaymentStatusEnum::PENDING
  59. ]);
  60. $expireDuration = 15; // 分钟
  61. $payment->expire_time = time() + $expireDuration * 60;
  62. $payment->payment_param = $this->createPaymentParam($order, $payment, $expireDuration);
  63. $payment->transaction_id = $payment->payment_param->trade_no;
  64. $payment->save();
  65. });
  66. return new PaymentResponse(orderNo: $payment->out_trade_no, type: Extension::EXTENSION_ID, raw: $payment->toArray());
  67. }
  68. #[\Override] public function notify(array $request): PaymentNotifyResult
  69. {
  70. throw new \Exception('Not implemented');
  71. }
  72. #[\Override] public function query(int $recordID): PaymentQueryResult
  73. {
  74. $payment = $this->extensionPaymentEntity->read($recordID);
  75. if ($payment->status === PaymentStatusEnum::PENDING) {
  76. $response = TransactionService::queryTrade($payment->transaction_id);
  77. // INIT-初始化 CREATE-下单成功 SUCCESS-交易成功 FAIL-交易失败 DEAL-交易处理中 UNKNOWN-未知状态 CLOSE-订单关闭 PART_REFUND-部分退款 REFUND-全部退款(或订单被撤销)
  78. $payment->status = match ($response->trade_state) {
  79. 'DEAL' => PaymentStatusEnum::PENDING,
  80. 'SUCCESS' => PaymentStatusEnum::SUCCESS,
  81. 'FAIL' => PaymentStatusEnum::FAIL,
  82. 'CLOSE' => PaymentStatusEnum::CLOSED,
  83. default => PaymentStatusEnum::PENDING,
  84. };
  85. if ($payment->status !== PaymentStatusEnum::PENDING) {
  86. $payment->status_desc = $response->trade_state_desc;
  87. $payment->payment_result = $response;
  88. if ($payment->status === PaymentStatusEnum::SUCCESS) {
  89. $payment->payment_time = time();
  90. $payment->save();
  91. Event::trigger(new PaymentSuccessEvent($payment['order_sn'], Extension::EXTENSION_ID, $payment->toArray(), $payment->biz_type));
  92. } else {
  93. $payment->save();
  94. }
  95. }
  96. }
  97. return new PaymentQueryResult(
  98. orderNo: $payment['out_trade_no'],
  99. status: $payment['status'],
  100. amount: (float)$payment['amount'],
  101. raw: $payment->toArray()
  102. );
  103. }
  104. #[\Override] public function refund(int $recordID, PaymentRefundRequest $param): PaymentRefundResult
  105. {
  106. throw new \Exception('Not implemented');
  107. }
  108. #[\Override] public function refundQuery(int $refundID): PaymentRefundResult
  109. {
  110. throw new \Exception('Not implemented');
  111. }
  112. private function createPaymentParam(array $order, ExtensionPaymentEntity $payment, int $expireDuration): object
  113. {
  114. $accBusiFields = new TradePreorderWechaAccBusiFields();
  115. $accBusiFields->setTimeoutExpress($expireDuration);
  116. $accBusiFields->setSubAppid($this->config->sub_appid);
  117. $accBusiFields->setUserId($order['params']['openid']);
  118. /*$detail = new TradePreorderWechaDetail();
  119. $detail->setCostPrice((float)$order['pay_amount']);
  120. $detail->setReceiptId('');
  121. $goodsDetailList = [];
  122. foreach ($order['order_goods'] as $goods) {
  123. $goodsDetail = new TradePreorderWechaGoodsDetail();
  124. $goodsDetail->setGoodsId((string)$goods['goods_id']);
  125. $goodsDetail->setQuantity($goods['num']);
  126. $goodsDetail->setWxpayGoodsId('');
  127. $goodsDetail->setPrice(round($goods['price']*100, 0));
  128. $goodsDetail->setGoodsName($goods['goods_name']);
  129. $goodsDetailList[] = $goodsDetail;
  130. }
  131. $detail->setGoodsDetail($goodsDetailList);
  132. $accBusiFields->setDetail($detail);*/
  133. return TransactionService::preOrder(
  134. outTradeNo: $payment['out_trade_no'],
  135. totalAmount: $payment['amount'],
  136. locationInfo: new LocationInfo(requestIP: $order['params']['ip']),
  137. subject: '订单:' . $order['order_sn'],
  138. settleType: '1', // 拉卡拉分账
  139. remark: $order['description'],
  140. accBusiFields: $accBusiFields,
  141. );
  142. }
  143. }