截流自动化的商城平台
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.

PayZhengSao.php 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | likeshop开源商城系统
  4. // +----------------------------------------------------------------------
  5. // | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
  6. // | gitee下载:https://gitee.com/likeshop_gitee
  7. // | github下载:https://github.com/likeshop-github
  8. // | 访问官网:https://www.likeshop.cn
  9. // | 访问社区:https://home.likeshop.cn
  10. // | 访问手册:http://doc.likeshop.cn
  11. // | 微信公众号:likeshop技术社区
  12. // | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
  13. // | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
  14. // | 禁止对系统程序代码以任何目的,任何形式的再发布
  15. // | likeshop团队版权所有并拥有最终解释权
  16. // +----------------------------------------------------------------------
  17. // | author: likeshop.cn.team
  18. // +----------------------------------------------------------------------
  19. namespace app\common\server\DouGong\pay;
  20. use app\common\enum\ClientEnum;
  21. use app\common\enum\IntegralOrderEnum;
  22. use app\common\enum\PayEnum;
  23. use app\common\logic\IntegralOrderRefundLogic;
  24. use app\common\logic\PayNotifyLogic;
  25. use app\common\model\integral\IntegralOrder;
  26. use app\common\model\order\Order;
  27. use app\common\model\order\OrderTrade;
  28. use app\common\model\RechargeOrder;
  29. use app\common\model\user\User;
  30. use app\common\model\user\UserAuth;
  31. use app\common\server\DouGong\BaseRequest;
  32. use app\common\server\WeChatServer;
  33. use Endroid\QrCode\QrCode;
  34. /**
  35. * @notes 聚合正扫
  36. * author lbzy
  37. * @datetime 2023-09-28 16:13:41
  38. * @class PayZhengSao
  39. * @package app\common\server\DouGong\pay
  40. */
  41. class PayZhengSao extends BaseRequest
  42. {
  43. protected $request_uri = '/v2/trade/payment/jspay';
  44. private $pays = [
  45. PayEnum::HFDG_WECHAT => [
  46. ClientEnum::mnp => 'T_MINIAPP',
  47. ClientEnum::oa => 'T_JSAPI',
  48. ClientEnum::ios => 'T_MINIAPP',
  49. ClientEnum::android => 'T_MINIAPP',
  50. ClientEnum::pc => 'T_JSAPI',
  51. ClientEnum::h5 => 'T_MINIAPP',
  52. ],
  53. PayEnum::HFDG_ALIPAY => [
  54. // ClientEnum::mnp => 'A_JSAPI',
  55. // ClientEnum::oa => 'A_JSAPI',
  56. ClientEnum::ios => 'A_NATIVE',
  57. ClientEnum::android => 'A_NATIVE',
  58. ClientEnum::pc => 'A_NATIVE',
  59. ClientEnum::h5 => 'A_NATIVE',
  60. ],
  61. ];
  62. protected function initialize()
  63. {
  64. $this->initUser();
  65. $this->initRequestData();
  66. $this->parseOrder();
  67. }
  68. private function initUser(): void
  69. {
  70. if (isset($this->params['user_id']) && $this->params['user_id'] > 0) {
  71. $this->userInfo = User::findOrEmpty($this->params['user_id'])->toArray();
  72. }
  73. if (isset($this->userInfo['id']) && $this->params['pay_way'] == PayEnum::HFDG_WECHAT) {
  74. switch ($this->params['client'] ?? '') {
  75. case ClientEnum::mnp:
  76. case ClientEnum::h5:
  77. case ClientEnum::ios:
  78. case ClientEnum::android:
  79. $this->userAuth = UserAuth::where('user_id', $this->params['user_id'])
  80. ->where('client', $this->params['client'])
  81. ->order('id desc')
  82. ->findOrEmpty()->toArray();
  83. $wechat_config = WeChatServer::getMnpConfig();
  84. break;
  85. case ClientEnum::oa:
  86. case ClientEnum::pc:
  87. $this->userAuth = UserAuth::where('user_id', $this->params['user_id'])
  88. ->where('client', $this->params['client'])
  89. ->order('id desc')
  90. ->findOrEmpty()->toArray();
  91. $wechat_config = WeChatServer::getOaConfig();
  92. break;
  93. default:
  94. break;
  95. }
  96. $this->config['appid'] = $wechat_config['app_id'] ?? '';
  97. $this->config['sub_appid'] = $wechat_config['app_id'] ?? '';
  98. $this->request_data['data']['wx_data']['sub_appid'] = $this->config['sub_appid'] ?? '';
  99. $this->request_data['data']['wx_data']['openid'] = $this->userAuth['openid'] ?? '';
  100. $this->request_data['data']['wx_data']['sub_openid'] = $this->userAuth['openid'] ?? '';
  101. }
  102. }
  103. protected function beforeRequestCheck() : bool
  104. {
  105. if ($this->params['pay_way'] == PayEnum::HFDG_WECHAT && empty($this->userAuth['openid'])) {
  106. $this->request_message = '支付失败:授权信息失效';
  107. return false;
  108. }
  109. return true;
  110. }
  111. protected function initRequestData()
  112. {
  113. // 请求日期req_date
  114. $this->request_data['data']['req_date'] = date("Ymd");
  115. // 交易类型trade_type
  116. $this->request_data['data']['trade_type'] = $this->pays[$this->params['pay_way']][$this->params['client']];
  117. // 商户id
  118. $this->request_data['data']['huifu_id'] = $this->config['huifu_id'];
  119. // 备注
  120. $this->request_data['data']['remark'] = implode('-', [
  121. $this->params['pay_way'],
  122. $this->params['client'],
  123. $this->params['from'],
  124. $this->params['order_id'],
  125. ]);
  126. // 回调
  127. if ($this->params['pay_way'] == PayEnum::HFDG_WECHAT) {
  128. $this->request_data['data']['notify_url'] = (string) url('pay/hfdgPayWechatNotify', [], false, true);
  129. }
  130. if ($this->params['pay_way'] == PayEnum::HFDG_ALIPAY) {
  131. $this->request_data['data']['notify_url'] = (string) url('pay/hfdgPayAlipayNotify', [], false, true);
  132. }
  133. }
  134. function getPayResult() : array
  135. {
  136. if ($this->request_success) {
  137. // 记录请求时间等信息
  138. $update = [
  139. 'hfdg_params' => [
  140. 'pay_request_time' => $_SERVER['REQUEST_TIME'],
  141. 'pay_request_date' => $this->request_data['data']['req_date'],
  142. 'req_seq_id' => $this->request_data['data']['req_seq_id'],
  143. ],
  144. ];
  145. switch ($this->params['from']) {
  146. case 'trade':
  147. OrderTrade::update($update, [ [ 'id', '=', $this->params['order_id'] ] ]);
  148. Order::update($update, [ [ 'trade_id', '=', $this->params['order_id'] ] ]);
  149. break;
  150. case 'order':
  151. Order::update($update, [ [ 'id', '=', $this->params['order_id'] ] ]);
  152. break;
  153. case 'recharge':
  154. RechargeOrder::update($update, [ [ 'id', '=', $this->params['order_id'] ] ]);
  155. break;
  156. case 'integral':
  157. IntegralOrder::update($update, [ [ 'id', '=', $this->params['order_id'] ] ]);
  158. break;
  159. default:
  160. break;
  161. }
  162. $data = '';
  163. $code = 1;
  164. if ($this->params['pay_way'] == PayEnum::HFDG_WECHAT) {
  165. switch ($this->params['client'] ?? '') {
  166. case ClientEnum::mnp:
  167. case ClientEnum::oa:
  168. case ClientEnum::pc:
  169. case ClientEnum::h5:
  170. case ClientEnum::ios:
  171. case ClientEnum::android:
  172. $data = json_decode($this->request_result['data']['pay_info'], true);
  173. break;
  174. default:
  175. break;
  176. }
  177. }
  178. if ($this->params['pay_way'] == PayEnum::HFDG_ALIPAY) {
  179. $code = 10001;
  180. switch ($this->params['client'] ?? '') {
  181. case ClientEnum::pc:
  182. $qrCode = new QrCode();
  183. $qrCode->setText($this->request_result["data"]["qr_code"]);
  184. $qrCode->setSize(1000);
  185. $base64 = chunk_split(base64_encode($qrCode->writeString()));
  186. $data = 'data:image/png;base64,' . $base64;
  187. break;
  188. case ClientEnum::h5:
  189. case ClientEnum::ios:
  190. case ClientEnum::android:
  191. $data = $this->request_result["data"]["qr_code"];
  192. break;
  193. default:
  194. break;
  195. }
  196. }
  197. return [
  198. 'code' => $code,
  199. 'msg' => $this->request_message,
  200. 'show' => 0,
  201. 'pay_way' => $this->params['pay_way'],
  202. 'data' => $data,
  203. ];
  204. }
  205. return [
  206. 'code' => 0,
  207. 'msg' => $this->request_message,
  208. 'show' => 1,
  209. 'pay_way' => $this->params['pay_way'],
  210. 'data' => [],
  211. ];
  212. }
  213. protected function parseOrder()
  214. {
  215. // 请求流水号
  216. $this->request_data['data']['req_seq_id'] = $this->params['order']['sn'] . mt_rand(100000, 999999);
  217. // 交易金额
  218. $this->request_data['data']['trans_amt'] = bcadd($this->params['order']['order_amount'], 0, 2);
  219. // 商品描述
  220. switch ($this->params['from']) {
  221. case 'trade':
  222. $this->request_data['data']['goods_desc'] = "商品总订单";
  223. break;
  224. case 'order':
  225. $this->request_data['data']['goods_desc'] = "商品子订单";
  226. break;
  227. case 'recharge':
  228. $this->request_data['data']['goods_desc'] = "充值";
  229. break;
  230. case 'integral':
  231. $this->request_data['data']['goods_desc'] = "积分商城";
  232. break;
  233. default:
  234. $this->request_data['data']['goods_desc'] = "商品";
  235. break;
  236. }
  237. }
  238. static function asyncSuccessDeal($async_result)
  239. {
  240. $data = (array) json_decode($async_result['resp_data'], true);
  241. $remarks = explode('-', $data['remark']);
  242. switch ($remarks[2]) {
  243. case 'order':
  244. $order = Order::findOrEmpty($remarks[3]);
  245. if (! $order || $order['pay_status'] >= PayEnum::ISPAID) {
  246. break ;
  247. }
  248. PayNotifyLogic::handle('order', $order['order_sn'], [ 'transaction_id' => $data['hf_seq_id'] ]);
  249. break;
  250. case 'trade':
  251. $order_trade = OrderTrade::findOrEmpty($remarks[3]);
  252. $orders = Order::where(['trade_id' => $remarks[3] ])->select();
  253. foreach ($orders as $order) {
  254. if (!$order || $order['pay_status'] >= PayEnum::ISPAID) {
  255. break 2;
  256. }
  257. }
  258. PayNotifyLogic::handle('trade', $order_trade['t_sn'], [ 'transaction_id' => $data['hf_seq_id'] ]);
  259. break;
  260. case 'recharge':
  261. $order = RechargeOrder::findOrEmpty($remarks[3]);
  262. if (! $order || $order['pay_status'] >= PayEnum::ISPAID) {
  263. break ;
  264. }
  265. PayNotifyLogic::handle('recharge', $order['order_sn'], [ 'transaction_id' => $data['hf_seq_id'] ]);
  266. break;
  267. case 'integral':
  268. $order = IntegralOrder::findOrEmpty($remarks[3]);
  269. if (! $order || $order['refund_status'] == IntegralOrderEnum::IS_REFUND) {
  270. // 没有订单记录 或者 订单已发生退款 中断后续操作
  271. break ;
  272. }
  273. if ($order['order_status'] == IntegralOrderEnum::ORDER_STATUS_DOWN) {
  274. // 收到支付回调时,订单已被关闭, 则进行退款操作
  275. IntegralOrderRefundLogic::refundOrderAmount($order['id']);
  276. break ;
  277. }
  278. if ($order['pay_status'] >= PayEnum::ISPAID) {
  279. break ;
  280. }
  281. PayNotifyLogic::handle('integral', $order['order_sn'], [ 'transaction_id' => $data['hf_seq_id'] ]);
  282. break;
  283. }
  284. return true;
  285. }
  286. }