AliOrderService.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <?php
  2. namespace addons\Alitopay\common\services;
  3. use addons\Alitopay\common\enums\AlitoapyEnum;
  4. use addons\Alitopay\common\event\WithdrawToPayEvent;
  5. use addons\Alitopay\common\models\WithdrawLog;
  6. use common\helpers\LockHelper;
  7. use yii\helpers\Json;
  8. use addons\Alitopay\common\models\Order;
  9. use Yii;
  10. /**
  11. * 新交易订单服务
  12. * @package addons\Alitopay\common\services
  13. */
  14. class AliOrderService extends BaseService
  15. {
  16. /**
  17. * 进行提现支付(全局调用)
  18. *
  19. * @param array $params
  20. * [
  21. * mall_id => int, // 商城Id
  22. * ids => array, // 提现Ids
  23. * ]
  24. * @return array [boolean, string]
  25. */
  26. public function globalWithdrawToPay($params)
  27. {
  28. // 设置商城ID
  29. $this->setMallId($params['mall_id'] ?? 0);
  30. // 支付
  31. $count = $this->withdrawToPay($params['ids'] ?? []);
  32. if ($count === false) {
  33. return [false, $this->getErrorMsg()];
  34. }
  35. return [true, sprintf('打款成功%s笔', $count)];
  36. }
  37. /**
  38. * 进行提现支付
  39. *
  40. * @param array $ids
  41. * @return boolean|int
  42. */
  43. public function withdrawToPay(array $ids)
  44. {
  45. // 获取设置
  46. $setting = (new SettingService($this->mall_id))->getSetting();
  47. if (empty($setting)) return $this->error('未进行代付配置');
  48. // 查询代付提现订单
  49. $list = WithdrawLog::getAlitopayLogByIds($this->mall_id, $ids);
  50. if (empty($list)) return $this->error('没有符合条件的提现订单');
  51. // 加锁
  52. $uniqid = uniqid();
  53. $lock_key = 'alitopay_order_lock_' . $this->mall_id;
  54. if (!LockHelper::lock($lock_key, $uniqid)) return $this->error('操作频繁请稍后重试');
  55. // 拼接数据入表
  56. $insert_data = [];
  57. $time = time();
  58. foreach ($list as $cash) {
  59. // 收款对象
  60. $ali_user = Json::decode($cash['extra']);
  61. // 是否设置名称和账号
  62. if (empty($ali_user['name']) || empty($ali_user['mobile'])) {
  63. return $this->error("订单{$cash['order_no']},支付宝名称或者支付宝账号为空");
  64. }
  65. // 是否达到最低打款金额
  66. if ($cash['actual_num'] < AlitoapyEnum::MIX_WITHDRAW) {
  67. return $this->error("订单{$ali_user['name']},打款金额必须大于1元");
  68. }
  69. // 数据
  70. $data['mall_id'] = $this->mall_id;
  71. $data['order_sn'] = $time . rand(1000, 9999);
  72. $data['type'] = Order::TYPE_WITHDRAWAL;
  73. $data['money'] = $cash['actual_num'];
  74. $data['name'] = $ali_user['name'];
  75. $data['account'] = $ali_user['mobile'];
  76. $data['source_id'] = $cash['id'];
  77. $data['source_sn'] = $cash['order_no'];
  78. $data['created_at'] = $data['updated_at'] = $time;
  79. $insert_data[] = $data;
  80. }
  81. // 开启事务
  82. $db = Yii::$app->db->beginTransaction();
  83. try {
  84. // 批量插入
  85. Order::batchInsert($insert_data);
  86. // 批量修改打款中
  87. $order_ids = array_column($list, 'id');
  88. WithdrawLog::changeStatusToPayingByIds($order_ids);
  89. $db->commit();
  90. } catch (\Exception $e) {
  91. $db->rollBack();
  92. LockHelper::uLock($lock_key, $uniqid);
  93. return $this->error($e->getMessage());
  94. }
  95. // 批量进行打款
  96. $count = $this->aliPay($insert_data);
  97. LockHelper::uLock($lock_key, $uniqid);
  98. return $count;
  99. }
  100. /**
  101. * 支付宝进行支付
  102. *
  103. * @param array $list
  104. * @return int
  105. */
  106. private function aliPay(array $list)
  107. {
  108. $aliapy = new AlipayService($this->mall_id);
  109. // 创建一个批次号
  110. $out_batch_no = 'TX' . date('Ymd') . $this->mall_id . rand(1000, 9999);
  111. $count = 0;
  112. foreach ($list as $v) {
  113. // 打款
  114. $res = $aliapy->transfer(
  115. $v['money'], $v['name'], $v['account'], $v['order_sn']
  116. );
  117. if ($res['code'] == '10000') {
  118. // 打款成功
  119. Order::paySuccessBySourceIdAndOrderSn(
  120. $v['source_id'], $v['order_sn'],$res['order_id']
  121. );
  122. $count++;
  123. } else {
  124. // 打款失败
  125. Order::payFialBySourceIdAndOrderSn(
  126. $v['source_id'], $v['order_sn'], $res['sub_msg']
  127. );
  128. }
  129. }
  130. // 设置批次号
  131. Order::setOutBatchNoByOrderSn($out_batch_no, array_column($list, 'order_sn'));
  132. //支付宝代付-打款成功事件
  133. $event = new WithdrawToPayEvent($this->mall_id);
  134. $data = [
  135. 'mall_id'=>$this->mall_id,
  136. 'out_batch_no'=>$out_batch_no,
  137. ];
  138. \Yii::$app->services->events->dispatch($event,$data , $event->listeners);
  139. return $count;
  140. }
  141. /**
  142. * 全局调用使用 提现通道
  143. *
  144. * @param array $params
  145. * @return array
  146. */
  147. public function withdrawChannel(array $params)
  148. {
  149. $mall_id = $params['mall_id'] ?? 0;
  150. $setting = (new SettingService($mall_id))->getSetting();
  151. $is_install = !empty($setting) ? 1 : 0;
  152. return [
  153. 'alitopay' => [
  154. 'is_install' => $is_install,
  155. ],
  156. ];
  157. }
  158. /**
  159. * 全局调用使用 获取支付方式
  160. *
  161. * @param array $params
  162. * [
  163. * mall_id => int
  164. * ]
  165. * @return array
  166. */
  167. public function getWithdrawWay(array $params)
  168. {
  169. // 提现方式
  170. $way = [
  171. AlitoapyEnum::ALITOPAY => AlitoapyEnum::ALITOPAY_NAME
  172. ];
  173. $mall_id = $params['mall_id'] ?? 0;
  174. // mall_id为空 后台显示提现方式
  175. if (empty($mall_id)) return $way;
  176. $setting = (new SettingService($params['mall_id']))->getSetting();
  177. // 配置密钥后显示
  178. if (!empty($setting)) return $way;
  179. return [];
  180. }
  181. }