AlipayScanPayService.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: yunzhong
  5. * Date: 2019/10/11
  6. * Time: 15:14
  7. */
  8. namespace app\common\services\alipay;
  9. use app\common\exceptions\AppException;
  10. use app\common\helpers\Url;
  11. use app\common\models\OrderPay;
  12. use app\common\models\PayOrder;
  13. use app\common\models\PayType;
  14. use app\common\services\Pay;
  15. use app\common\services\Utils;
  16. use Yansongda\Pay\Exceptions\GatewayException;
  17. use Yansongda\Pay\Gateways\Alipay\Support;
  18. use Yunshop\StoreCashier\store\common\service\RefreshToken;
  19. use Yunshop\StoreCashier\store\models\StoreAlipaySetting;
  20. class AlipayScanPayService extends Pay
  21. {
  22. /**
  23. * 订单支付/充值
  24. * @param array $data
  25. * @return mixed
  26. * @throws AppException
  27. * @throws \Exception
  28. */
  29. public function doPay($data = [])
  30. {
  31. if ($data['pay_type'] == 'alipay') {
  32. $third_type = '支付宝扫码支付';
  33. } else {
  34. $third_type = '支付宝人脸支付';
  35. }
  36. $op = '微信扫码支付 订单号:' . $data['order_no'];
  37. $pay_order_model = $this->log(1, $third_type, $data['amount'], $op, $data['order_no'], Pay::ORDER_STATUS_NON, \YunShop::app()->getMemberId());
  38. $alipay_set = \Setting::get('shop.alipay_set');
  39. $config = [
  40. 'app_id' => $alipay_set['app_id'],
  41. 'ali_public_key' => $alipay_set['alipay_public_key'],
  42. 'private_key' => $alipay_set['merchant_private_key'],
  43. 'notify_url' => Url::shopSchemeUrl('payment/alipay/jsapiNotifyUrl.php'),
  44. 'return_url' => Url::shopSchemeUrl('payment/alipay/returnUrl.php'),
  45. 'app_auth_token' => ''
  46. ];
  47. $order = [
  48. 'body' => \YunShop::app()->uniacid,
  49. 'subject' => $data['subject'], 0, 256,
  50. 'out_trade_no' => $data['pay_sn'],
  51. 'total_amount' => $data['amount'],
  52. 'auth_code' => $data['auth_code'],
  53. 'http_method' => 'GET',
  54. ];
  55. if ($this->getRoyalty($alipay_set)) {
  56. $order['extend_params'] = ['royalty_freeze' => true];
  57. }
  58. if (!$alipay_set['app_type']) {
  59. //第三方应用授权令牌,商户授权系统商开发模式下使用
  60. $config['app_auth_token'] = $this->getAuthToken();
  61. $order['sys_service_provider_id'] = $alipay_set['pid'];
  62. }
  63. try {
  64. $res = \Yansongda\Pay\Pay::alipay($config)->pos($order);
  65. } catch (GatewayException $e) {
  66. $raw = $e->raw;
  67. $method = str_replace('.', '_', 'alipay.trade.pay') . '_response';
  68. if ($raw[$method]['code'] == '10000' || $raw[$method]['code'] == '10003') {
  69. $res = $raw[$method];
  70. } else {
  71. throw $e;
  72. }
  73. }
  74. $pay_success = 0;
  75. if ($res['code'] == '10000') {
  76. //支付成功
  77. $pay_success = 1;
  78. } else if ($res['code'] == '10003') {
  79. //轮询
  80. for ($i = 1; $i < 12; $i++) {
  81. sleep(5);
  82. //查询交易状态
  83. try {
  84. $loop = \Yansongda\Pay\Pay::alipay($config)->find(['out_trade_no' => $data['pay_sn']]);
  85. } catch (GatewayException $e) {
  86. \Log::debug('支付宝扫码付查询支付结果异常:' . $e->getMessage());
  87. $loop = [];
  88. }
  89. if ($loop['code'] == '10000' && isset($loop['trade_status']) && in_array($loop['trade_status'], ["TRADE_FINISHED", "TRADE_SUCCESS"])) {
  90. //支付成功,结束轮询
  91. $pay_success = 1;
  92. break;
  93. } elseif ($loop['code'] == '10000' && isset($loop['trade_status']) && $loop['trade_status'] == 'TRADE_CLOSED') {
  94. //交易失败,结束轮询
  95. \Log::error('pos支付宝支付失败', [$res, $loop]);
  96. throw new AppException('支付宝支付失败!!!' . $loop['msg'] . '--' . $loop['sub_msg']);
  97. }
  98. }
  99. }
  100. if ($pay_success == 1) {
  101. self::payRequestDataLog($data['order_no'], $pay_order_model->type, $pay_order_model->third_type, json_encode($res));
  102. $res['royalty'] = $this->getRoyalty($alipay_set);
  103. return $res;
  104. } else {
  105. \Log::error('pos支付宝支付失败', [$res]);
  106. throw new AppException('支付宝支付失败!!!' . $res['msg'] . '--' . $res['sub_msg']);
  107. }
  108. }
  109. /**
  110. * 退款
  111. *
  112. * @param $out_trade_no 订单号
  113. * @param $totalmoney 订单总金额
  114. * @param $refundmoney 退款金额
  115. * @return mixed
  116. */
  117. public function doRefund($out_trade_no, $totalmoney, $refundmoney)
  118. {
  119. throw new AppException('业务正在维护, 请稍后重试.');
  120. $this->setPayService();
  121. $out_refund_no = $this->setUniacidNo(\YunShop::app()->uniacid);
  122. $op = '支付宝扫码退款 订单号:' . $out_trade_no . '退款单号:' . $out_refund_no . '退款金额:' . $refundmoney;
  123. if (empty($out_trade_no)) {
  124. throw new AppException('支付单号不存在');
  125. }
  126. $pay_type_id = OrderPay::get_paysn_by_pay_type_id($out_trade_no);
  127. $pay_type_name = PayType::get_pay_type_name($pay_type_id);
  128. $refund_order = $this->refundlog(Pay::PAY_TYPE_REFUND, $pay_type_name, $refundmoney, $op, $out_trade_no, Pay::ORDER_STATUS_NON, 0);
  129. //支付宝交易单号
  130. $pay_order_model = PayOrder::getPayOrderInfo($out_trade_no)->first();
  131. if (!$pay_order_model) {
  132. return false;
  133. }
  134. $refund_data = array(
  135. 'out_trade_no' => $pay_order_model->out_order_no,
  136. 'trade_no' => $pay_order_model->trade_no,
  137. 'refund_amount' => $refundmoney,
  138. 'refund_reason' => '正常退款',
  139. 'out_request_no' => $out_refund_no
  140. );
  141. $res = $this->payService->refund($refund_data);
  142. if ($res['code'] == '10000') {
  143. $refund_order->status = Pay::ORDER_STATUS_COMPLETE;
  144. $refund_order->trade_no = $res['trade_no'];
  145. $refund_order->save();
  146. $this->payResponseDataLog($out_trade_no, '支付宝扫码支付', json_encode($res));
  147. return true;
  148. }
  149. \Log::debug('---alipay-扫码/人脸---', [$refund_data, $res]);
  150. throw new AppException($res['msg'] . '-' . $res['sub_msg']);
  151. }
  152. /**
  153. * 提现
  154. *
  155. * @param $member_id 提现者用户ID
  156. * @param $out_trade_no 提现批次单号
  157. * @param $money 提现金额
  158. * @param $desc 提现说明
  159. * @param $type 只针对微信 1-企业支付(钱包) 2-红包
  160. * @return mixed
  161. */
  162. public function doWithdraw($member_id, $out_trade_no, $money, $desc, $type)
  163. {
  164. // TODO: Implement doWithdraw() method.
  165. }
  166. /**
  167. * 构造签名
  168. *
  169. * @return mixed
  170. */
  171. public function buildRequestSign()
  172. {
  173. // TODO: Implement buildRequestSign() method.
  174. }
  175. /**
  176. * @return mixed
  177. * @throws \Exception
  178. */
  179. public function getAuthToken()
  180. {
  181. $storeAlipaySetting = StoreAlipaySetting::uniacid()->where('store_id', request()->store_id)->first();
  182. if (!$storeAlipaySetting) {
  183. throw new AppException('门店未授权支付宝');
  184. }
  185. $app_auth_token = $storeAlipaySetting->app_auth_token;
  186. return $app_auth_token;
  187. }
  188. private function getRoyalty($set)
  189. {
  190. $result = 0;
  191. if ($set['royalty']) {
  192. $sub_set = StoreAlipaySetting::where('store_id', request()->store_id)->first();
  193. if ($sub_set->royalty && !$sub_set->no_authorized_royalty) {
  194. $result = 1;
  195. }
  196. }
  197. return $result;
  198. }
  199. private function setPayService()
  200. {
  201. $pay = \Setting::get('shop.pay');
  202. Utils::dataDecrypt($pay);
  203. $config = [
  204. 'app_id' => $pay['alipay_app_id'],
  205. 'ali_public_key' => $pay['rsa_public_key'],
  206. 'private_key' => $pay['rsa_private_key'],
  207. 'notify_url' => Url::shopSchemeUrl('payment/alipay/preNotifyUrl.php'),
  208. 'return_url' => Url::shopSchemeUrl('payment/alipay/returnUrl.php'),
  209. ];
  210. $this->payService = \Yansongda\Pay\Pay::alipay($config);
  211. }
  212. }