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.

136 lines
3.8 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\Exception\ErrorCodeException;
  8. use App\Model\v3\OrderMain;
  9. use App\Model\v3\User;
  10. use App\Service\v3\Interfaces\GoodsActivityServiceInterface;
  11. use App\Service\v3\Interfaces\PaymentServiceInterface;
  12. use EasyWeChat\Factory;
  13. use Hyperf\Guzzle\CoroutineHandler;
  14. use Hyperf\Di\Annotation\Inject;
  15. class PaymentService implements PaymentServiceInterface
  16. {
  17. /**
  18. * @Inject
  19. * @var Log
  20. */
  21. protected $log;
  22. /**
  23. * @Inject
  24. * @var GoodsActivityServiceInterface
  25. */
  26. protected $goodsActivityService;
  27. public function do($globalOrderId, $money, $userId)
  28. {
  29. try {
  30. $config = config('wxpay');
  31. $app = Factory::payment($config);
  32. $app['guzzle_handler'] = CoroutineHandler::class;
  33. // 待支付的,未超时(15min,900sec)的订单
  34. $orderMain = OrderMain::query()
  35. ->where(['state' => OrderState::UNPAID, 'global_order_id' => $globalOrderId, 'user_id' => $userId])
  36. ->where('created_at', '>=', (time()-900))
  37. ->first();
  38. if (empty($orderMain)) {
  39. throw new ErrorCodeException(ErrorCode::ORDER_NOT_AVAILABLE, '[支付订单号]'.$globalOrderId);
  40. }
  41. $payMoney = bcmul((string)$orderMain->money, 100, 0);
  42. if (env('APP_ENV') != 'prod') {
  43. $payMoney = 1;
  44. }
  45. $user = User::select('openid')->find($userId);
  46. $result = $app->order->unify([
  47. 'body' => '懒族生活 - 外卖下单',
  48. 'out_trade_no' => $orderMain->global_order_id,
  49. 'total_fee' => $payMoney,
  50. 'notify_url' => config('site_host') . '/wechat/notify/wxminionline',
  51. 'trade_type' => 'JSAPI',
  52. 'openid' => $user['openid'],
  53. ]);
  54. if ($result['return_code'] == 'FAIL') {
  55. throw new ErrorCodeException(ErrorCode::PAYMENT_FAIL, '[支付失败]'.$result['return_msg']);
  56. }
  57. // 返回支付参数给前端
  58. $parameters = [
  59. 'appId' => $result['appid'],
  60. 'timeStamp' => '' . time() . '',
  61. 'nonceStr' => uniqid(),
  62. 'package' => 'prepay_id=' . $result['prepay_id'],
  63. 'signType' => 'MD5'
  64. ];
  65. $parameters['paySign'] = $this->signture($parameters, $config['key']);
  66. return $parameters;
  67. } catch (\Exception $e) {
  68. $this->log->event(LogLabel::ORDER_PAYMENT_LOG, ['payment_exception_msg' => $e->getMessage()]);
  69. throw new ErrorCodeException(ErrorCode::PAYMENT_FAIL, '[支付失败]'.$e->getMessage());
  70. }
  71. }
  72. public function check()
  73. {
  74. // TODO: Implement check() method.
  75. }
  76. public function undo()
  77. {
  78. // TODO: Implement undo() method.
  79. }
  80. /**
  81. * 支付参数加签
  82. * @param $parameters
  83. * @param $key
  84. * @return string
  85. */
  86. private function signture($parameters, $key)
  87. {
  88. // 按字典序排序参数
  89. ksort($parameters);
  90. // http_query
  91. $queryParams = $this->http_query($parameters);
  92. // 加入KEY
  93. $queryParams = $queryParams . "&key=" . $key;
  94. // MD5加密
  95. $queryParams = md5($queryParams);
  96. // 字符转为大写
  97. return strtoupper($queryParams);
  98. }
  99. /**
  100. * 参数转为http query字串
  101. * @param $parameters
  102. * @return string
  103. */
  104. private function http_query($parameters) {
  105. $http_query = [];
  106. foreach ($parameters as $key => $value) {
  107. $http_query[] = $key.'='.$value;
  108. }
  109. return implode('&', $http_query);
  110. }
  111. }