You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
5.4 KiB

  1. <?php
  2. namespace App\Service\v3\Implementations;
  3. use App\Commons\Log;
  4. use App\Constants\v3\ErrorCode;
  5. use App\Constants\v3\LogLabel;
  6. use App\Constants\v3\OrderState;
  7. use App\Constants\v3\OrderType;
  8. use App\Constants\v3\Payment;
  9. use App\Exception\ErrorCodeException;
  10. use App\Model\v3\Order;
  11. use App\Model\v3\OrderMain;
  12. use App\Model\v3\User;
  13. use App\Service\v3\CcbPay;
  14. use App\Service\v3\Interfaces\PaymentServiceInterface;
  15. use Hyperf\Di\Annotation\Inject;
  16. /** @var Inject 注解使用 */
  17. /**
  18. * 建行支付
  19. */
  20. class CcbPayService implements PaymentServiceInterface
  21. {
  22. /**
  23. * @Inject
  24. * @var Log
  25. */
  26. protected Log $log;
  27. public function do($globalOrderId, $money, $userId, $notifyUrl)
  28. {
  29. try {
  30. // 待支付的,未超时(15min,900sec)的订单
  31. $orderMain = OrderMain::where('created_at', '>=', (time() - 900))
  32. ->where(['state' => OrderState::UNPAID, 'global_order_id' => $globalOrderId, 'user_id' => $userId])
  33. ->first();
  34. if (empty($orderMain)) {
  35. throw new ErrorCodeException(ErrorCode::ORDER_NOT_AVAILABLE, '[支付订单号]' . $globalOrderId);
  36. }
  37. $payMoney = $orderMain->money; // 注:此处单位是元,不是分
  38. if (env('APP_ENV') != 'prod' && $orderMain->type == OrderType::ONLINE) {
  39. $payMoney = 0.01;
  40. }
  41. $user = User::select('openid')->find($userId);
  42. // 设置分账规则
  43. $order = Order::with('store:id,card_no')->where('order_main_id', $globalOrderId)->get();
  44. $parList = [];
  45. $seqNo = 1;
  46. foreach ($order as $item) {
  47. if (!empty($item->store->card_no)) {
  48. $parList[] = [
  49. 'Seq_No' => $seqNo,
  50. 'Mkt_Mrch_Id' => $item->store->card_no,
  51. // 'Amt' => 0, // TODO 分账金额
  52. ];
  53. $seqNo++;
  54. }
  55. }
  56. $res = CcbPay::getInstance()->gatherPlaceOrder([
  57. 'Ittparty_Jrnl_No' => $globalOrderId,
  58. 'Main_Ordr_No' => $globalOrderId,
  59. 'Ordr_Tamt' => $payMoney, // 订单总金额
  60. 'Txn_Tamt' => $payMoney, // 应付金额
  61. 'Sub_Openid' => $user['openid'],
  62. 'Orderlist' => [
  63. 'Ordr_Amt' => $payMoney, // 订单商品总金额,即应付金额,所有商品订单金额之和等于主订单金额;
  64. 'Cmdty_Ordr_No' => $globalOrderId, // 返显输入接口中的客户方子订单编号
  65. 'Txnamt' => $payMoney, // 消费者实付金额,所有商品订单金额之和等于主交易总金额金额
  66. 'Mkt_Mrch_Id' => env('CCB_MKT_MRCH_ID'), // 商家编号
  67. 'Clrg_Rule_Id' => env('CCB_CLRG_RULE_ID'), // 分账规则编号,1.“Py_Ordr_Tpcd(订单类型)”为“02-消费券购买订单”时该字段无效,可不送;2.走默认分账策略,可不送;3.多个子订单时不可送
  68. 'Parlist' => $parList,
  69. ],
  70. ]);
  71. // 保存一下 $res['Py_Trn_No'] 参数,后续退款等都会用到
  72. $orderMain->py_trn_no = $res['Py_Trn_No'];
  73. $orderMain->save();
  74. // 返回支付参数给前端
  75. return [
  76. 'appId' => $res['Rtn_Par_Data']['appid'],
  77. 'timeStamp' => $res['Rtn_Par_Data']['timeStamp'],
  78. 'nonceStr' => $res['Rtn_Par_Data']['nonceStr'],
  79. 'package' => $res['Rtn_Par_Data']['package'],
  80. 'signType' => $res['Rtn_Par_Data']['signType'],
  81. 'paySign' => $res['Rtn_Par_Data']['paySign'],
  82. 'order_main_id' => $globalOrderId,
  83. ];
  84. } catch (\Exception $e) {
  85. $this->log->event(LogLabel::ORDER_PAYMENT_LOG, ['payment_do_exception_msg' => $e->getMessage()]);
  86. throw new ErrorCodeException(ErrorCode::PAYMENT_FAIL, '[稍后重试]');
  87. }
  88. }
  89. public function check()
  90. {
  91. // TODO: Implement check() method.
  92. }
  93. /**
  94. * 退款的整单,用户申请的退款
  95. * @param $globalOrderId
  96. * @param $userId
  97. * @return bool
  98. */
  99. public function undo($globalOrderId, $userId)
  100. {
  101. try{
  102. // 已支付的,未退款的,使用微信(或建行)支付的订单
  103. $orderMain = OrderMain::query()
  104. ->whereIn('state', [OrderState::PAID, OrderState::DELIVERY, OrderState::COMPLETED, OrderState::EVALUATED, OrderState::REFUNDING])
  105. ->where(['global_order_id' => $globalOrderId, 'user_id' => $userId, 'pay_type' => Payment::WECHAT, 'refund_time' => 0])
  106. ->first();
  107. if (empty($orderMain)) {
  108. throw new ErrorCodeException(ErrorCode::ORDER_NOT_AVAILABLE, '[支付订单号]' . $globalOrderId);
  109. }
  110. $result = CcbPay::getInstance()->refundOrder([
  111. 'Ittparty_Jrnl_No' => $globalOrderId,
  112. 'Py_Trn_No' => $orderMain->py_trn_no,
  113. ]);
  114. if (!isset($result['Refund_Rsp_St'])) { // 接口返回异常
  115. throw new ErrorCodeException(ErrorCode::REFUND_PAYMENT_FAIL, '退款异常,操作失败');
  116. } else if ($result['Refund_Rsp_St'] == '01') {
  117. throw new ErrorCodeException(ErrorCode::REFUND_PAYMENT_FAIL, '退款失败');
  118. } else if ($result['Refund_Rsp_St'] == '02') {
  119. throw new ErrorCodeException(ErrorCode::REFUND_PAYMENT_FAIL, '退款延迟等待');
  120. } else if ($result['Refund_Rsp_St'] == '03') {
  121. throw new ErrorCodeException(ErrorCode::REFUND_PAYMENT_FAIL, '退款结果不确定,请稍后查看退款结果');
  122. }
  123. return true;
  124. } catch (\Exception $e) {
  125. $this->log->event(LogLabel::ORDER_REFUND_LOG, ['payment_do_exception_msg' => $e->getMessage()]);
  126. throw new ErrorCodeException(ErrorCode::REFUND_PAYMENT_FAIL);
  127. }
  128. }
  129. public function payToWx($money, $tradeNo, $openId, $userName, $desc = '', $checkName = 'NO_CHECK')
  130. {
  131. throw new ErrorCodeException(500, 'payToWx未实现');
  132. }
  133. }