HuijuBill.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. <?php
  2. namespace common\components\payment;
  3. use addons\HuijuBill\common\enums\HuijuBillTypeEnum;
  4. use addons\HuijuBill\common\enums\StatusEnum;
  5. use addons\HuijuBill\common\global_func\Payment;
  6. use addons\HuijuBill\common\models\OrderModel;
  7. use addons\HuijuBill\common\models\OrderRefundModel;
  8. use common\components\payment\joinpay\util\RequestUtil;
  9. use common\helpers\Url;
  10. use addons\HuijuBill\common\logic\PayApiLogic;
  11. use common\models\common\MiddleMch;
  12. use common\models\common\PaymentTradeOrder;
  13. use Exception;
  14. use Yii;
  15. /**
  16. * 汇聚分账支付类
  17. *
  18. * Class HuijuBill
  19. * @package common\components\payment
  20. */
  21. class HuijuBill
  22. {
  23. /**
  24. * 配置
  25. *
  26. * @var array
  27. */
  28. protected $config;
  29. /**
  30. * 初始化
  31. *
  32. * @param array $config
  33. */
  34. public function __construct($config)
  35. {
  36. $this->config = $config;
  37. }
  38. /**
  39. * 支付接口
  40. * @param array $order
  41. * [
  42. * 'title' => '订单标题'
  43. * 'order_no' => '交易流水号'
  44. * 'amount' => 金额
  45. * 'mall_id' => 商城ID
  46. * 'notify_url' => '回调地址',
  47. * 'type' => '汇聚支付方式'
  48. * 'open_id' => '微信openid'
  49. * ]
  50. * @return array|mixed
  51. * @throws Exception
  52. */
  53. public function pay($order)
  54. {
  55. $mch = MiddleMch::getMch($order['mall_id']);
  56. $request = $this->getRequest($order, $mch);
  57. $res = (new PayApiLogic($mch))->create_order($request);
  58. OrderModel::addLog([
  59. 'mall_id' => $order['mall_id'],
  60. 'merchant_no' => $request['alt_mch_no'],
  61. 'trade_id' => $order['trade_id'],
  62. 'trade_type' => $order['type'],
  63. 'sys_order_no' => $res['sys_order_no'],
  64. 'trx_no' => $res['trx_no'],
  65. 'fee' => $res['alt_fee'],
  66. 'status' => $res['status'],
  67. ]);
  68. return $res;
  69. }
  70. /**
  71. * 获取请求参数
  72. *
  73. * @param array $order
  74. * @param MiddleMch $mch
  75. * @return array
  76. */
  77. private function getRequest($order, $mch)
  78. {
  79. $request = [
  80. 'alt_mch_no' => $this->config['merchant_no'], // 分账方
  81. 'order_no' => $order['order_no'], // 商户订单号
  82. 'amount' => $order['amount'], // 订单金额
  83. 'product_name' => $order['title'], // 商品名称
  84. 'product_desc' => $order['title'], // 商品描述
  85. 'mp' => '', // 公用回传参数,如果商户请求时传递了该参 数,则返回给商户时会原值传 回
  86. 'notify_url' => $order['notify_url'], // 服务器异步通知地址
  87. 'frp_code' => $order['type'], // 交易类型
  88. 'auth_code' => '', // 付款码数字,被扫支付必填
  89. 'buyerId' => '', // 支付宝服务窗 支付必填
  90. 'transaction_model' => '', // 微信/支付宝 H5 模式
  91. ];
  92. // 微信环境获取对应的openid
  93. if ($order['type'] == HuijuBillTypeEnum::WEIXIN_GZH) {
  94. $request['open_id'] = $order['open_id'] ?? '';
  95. $request['app_id'] = Yii::$app->services->setting->mall->get($order['mall_id'], 'wechat.app_id');
  96. }
  97. if ($order['type'] == HuijuBillTypeEnum::WEIXIN_XCX) {
  98. $request['open_id'] = $order['open_id'] ?? '';
  99. $request['app_id'] = Yii::$app->services->setting->mall->get($order['mall_id'], 'mini_program.app_id');
  100. }
  101. return $request;
  102. }
  103. /**
  104. * 查询订单支付状态
  105. * @params string $trade_no
  106. * @return array
  107. * @throws
  108. */
  109. public function query($trade_no)
  110. {
  111. $request = [
  112. 'p1_MerchantNo' => $this->config['merchant_no'],
  113. 'p2_OrderNo' => $trade_no,
  114. ];
  115. $secret = $this->config['merchant_secret'];
  116. $request['hmac'] = urlencode(RequestUtil::hmacRequest($request, $secret));
  117. $result = RequestUtil::http_post($this->order_query_url, $request);
  118. return json_decode($result, true);
  119. }
  120. /**
  121. * 退款
  122. * @param array $info
  123. * [
  124. * 'refund_order_no' => $refund_order_no,
  125. * 'out_refund_no' => $out_trade_no,
  126. * 'refund_amount' => 1,
  127. * 'refund_reason' => 1
  128. * ]
  129. *
  130. * @return bool
  131. * @throws
  132. */
  133. public function refund($data)
  134. {
  135. $mch = MiddleMch::getMch($data['mall_id']);
  136. // 获取支付流水单号
  137. $out_trade_no = PaymentTradeOrder::getOutTradeNoOfOrderNo($data['order_no']);
  138. if (empty($out_trade_no)) {
  139. throw new Exception("订单:{$data['order_no']} 支付流水单号不存在");
  140. }
  141. $res = (new PayApiLogic($mch))->order_refund([
  142. 'order_no' => $out_trade_no,
  143. 'refund_order_no' => $data['refund_order_no'],
  144. 'refund_amount' => $data['money'],
  145. 'reason' => $data['desc'],
  146. 'notify_url' => Url::toApi(['notify/huiju_bill_refund'], true), // 退款结果通知网址
  147. ]);
  148. // 添加记录
  149. OrderRefundModel::addLog([
  150. 'mall_id' => $data['mall_id'],
  151. 'out_trade_no' => $out_trade_no,
  152. 'sys_order_no' => $res['sys_order_no'],
  153. 'trx_no' => $res['trx_no'],
  154. 'refund_id' => $data['refund_id'],
  155. 'refund_amount' => $data['money'],
  156. 'refund_order_no' => $data['refund_order_no'],
  157. 'status' => $res['status'],
  158. ]);
  159. return true;
  160. }
  161. /**
  162. * 异步回调
  163. *
  164. * @param array $data
  165. * @return void
  166. */
  167. public function notify($data, $trade)
  168. {
  169. $mch = MiddleMch::getMch($trade->mall_id);
  170. if (empty($mch)) {
  171. throw new Exception('mch为空');
  172. }
  173. $data = (new PayApiLogic($mch))->order_query($data['sys_order_no']);
  174. // 是否支付成功
  175. if (isset($data['status']) && $data['status'] == StatusEnum::STATUS_100) {
  176. // 回调成功 删除缓存
  177. Payment::delAlipayHtml($data['order_no']);
  178. return true;
  179. }
  180. return false;
  181. }
  182. /**
  183. * 退款回调处理
  184. * @param $res
  185. * @return bool
  186. * @throws
  187. */
  188. public function refund_notify($data, $refund_order)
  189. {
  190. $mch = MiddleMch::getMch($refund_order->mall_id);
  191. if (empty($mch)) {
  192. throw new Exception('mch为空');
  193. }
  194. // 查询
  195. $data = (new PayApiLogic($mch))->order_refund_query($data['refund_order_no']);
  196. if (isset($data['status']) && $data['status'] == StatusEnum::STATUS_100) {
  197. return true;
  198. }
  199. return false;
  200. }
  201. }