HuifuBillShareService.php 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. <?php
  2. namespace addons\HuifuPay\common\service;
  3. use addons\HuifuPay\common\models\HuifuBillShare;
  4. use addons\HuifuPay\common\models\HuifuPayOrderModel;
  5. use addons\Store\common\models\Store;
  6. use addons\Store\common\models\StoreCashierOrder;
  7. use common\enums\AddonsEnum;
  8. use common\enums\RabbitMqEnum;
  9. use common\enums\StatusEnum;
  10. use common\helpers\FormatHelper;
  11. use common\models\mall\MallAddons;
  12. use common\models\user\User;
  13. class HuifuBillShareService
  14. {
  15. public function page(int $mall_id, array $params, int $store_id = 0)
  16. {
  17. $where = [
  18. ['mall_id' => $mall_id],
  19. ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]
  20. ];
  21. if (!empty($params['member'])) {
  22. $uids = User::find()->where(['mall_id' => $mall_id])
  23. ->andWhere(['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]])
  24. ->andWhere(['or', ['like', 'id', $params['member']], ['like', 'nickname', $params['member']], ['like', 'mobile', $params['member']]])
  25. ->select('id')->column();
  26. if (empty($uids)) return [];
  27. $where[] = ['user_id' => $uids];
  28. }
  29. $is_install_store = MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_STORE);
  30. if (!empty($store_id)) {
  31. $where[] = ['store_id' => $store_id];
  32. } else if (!empty($params['store']) && $is_install_store) {
  33. $sids = Store::find()->where(['mall_id' => $mall_id])
  34. ->andWhere(['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]])
  35. ->andWhere(['or', ['like', 'id', $params['store']], ['like', 'store_name', $params['store']]])
  36. ->select('id')->column();
  37. if (empty($sids)) return [];
  38. $where[] = ['store_id' => $sids];
  39. }
  40. if (!empty($params['out_trade_no'])) {
  41. $where[] = ['like', 'trade_no', $params['out_trade_no']];
  42. }
  43. if (!empty($params['order_no'])) {
  44. $where[] = ['like', 'order_no', $params['order_no']];
  45. }
  46. if (!empty($params['start_time'])) $where[] = ['>=', 'created_at', strtotime($params['start_time'])];
  47. if (!empty($params['end_time'])) $where[] = ['<=', 'created_at', strtotime($params['end_time'])];
  48. $ret = HuifuBillShare::listPage([
  49. 'where' => $where,
  50. 'order' => 'id desc',
  51. 'with' => ['order' => function($query) {
  52. $query->with(['user']);
  53. }],
  54. 'limit' => $params['limit'] ?? 10,
  55. ]);
  56. if (!empty(HuifuBillShare::getStaticError())) return HuifuBillShare::getStaticError();
  57. if (!empty($ret['list'])) {
  58. $stores = [];
  59. if ($is_install_store) {
  60. $sids = array_column($ret['list'], 'store_id');
  61. $stores = Store::lists([
  62. 'where' => [
  63. ['id' => $sids]
  64. ],
  65. 'index' => 'id'
  66. ]);
  67. }
  68. foreach ($ret['list'] as &$item) {
  69. $item['store'] = $stores[$item['store_id']] ?? null;
  70. if (strpos($item['order_no'], 'C') === 0) {
  71. // 这个属于收银台订单
  72. $item['order'] = StoreCashierOrder::getOne([['order_no' => $item['order_no']]], true, ['user']);
  73. }
  74. }
  75. }
  76. return $ret;
  77. }
  78. public static function shareRetry(int $mall_id, int $id)
  79. {
  80. $share = HuifuBillShare::findOne(['mall_id' => $mall_id, 'id' => $id]);
  81. if (empty($share)) return '记录不存在';
  82. if ($share->settle_status != 1) return '当前状态不可进行分佣';
  83. $ret = self::handleSync(['mall_id' => $mall_id, 'order_no' => $share->order_no]);
  84. if (!$ret) return '操作失败';
  85. return true;
  86. }
  87. /**
  88. *
  89. * @param int $mall_id
  90. * @param array $params
  91. * @return HuifuBillShare
  92. * @throws \Exception
  93. */
  94. public static function save(int $mall_id, array $params)
  95. {
  96. $model = new HuifuBillShare();
  97. $model->loadDefaultValues();
  98. $model->mall_id = $mall_id;
  99. $model->merchant_no = $params['merchant_no'];
  100. $model->trade_id = $params['trade_id'] ?? 0;
  101. $model->order_no = $params['order_no'];
  102. $model->share_amount = $params['share_amount'];
  103. $model->fee = $params['fee'];
  104. $model->store_id = $params['store_id'];
  105. $model->fee_rate = $params['fee_rate'];
  106. $model->trade_no = $params['trade_no'];
  107. $model->order_amount = $params['order_amount'];
  108. $model->settle_type = $params['settle_type'];
  109. if (!$model->save()) throw new \Exception($model->getErrorMessage());
  110. return $model;
  111. }
  112. public static function shareCommission(int $mall_id, string $order_no)
  113. {
  114. \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_ORDER, RabbitMqEnum::ORDER_QUEUE,
  115. ['mall_id' => $mall_id, 'order_no' => $order_no], self::class, 'handleSync');
  116. }
  117. public static function handleSync($params)
  118. {
  119. $config = \Yii::$app->services->setting->addons->get($params['mall_id'], AddonsEnum::ADDONS_NAME_HUIFU_PAY, 'basic');
  120. $share = HuifuBillShare::findOne(['mall_id' => $params['mall_id'], 'order_no' => $params['order_no']]);
  121. if ($share->settle_status != 1) return true;
  122. $pOrder = HuifuPayOrderModel::getOne([['trade_no' => $share->trade_no]], false, [], 'id desc');
  123. if (empty($pOrder)) {
  124. \Yii::error("支付订单不存在: {$share->trade_no}");
  125. return true;
  126. }
  127. $t = \Yii::$app->db->beginTransaction();
  128. try {
  129. // 请求汇付执行分账
  130. $huifuService = new HuifuService($share->mall_id);
  131. // 计算退款比例
  132. $refund_rate = 1;
  133. if ($share->refund_amount > 0) $refund_rate = bcsub($refund_rate, bcdiv($share->refund_amount, $share->order_amount, 2), 2);
  134. $share->pay_fee = bcmul($pOrder->notify['fee_amount'] ?? 1, $refund_rate, 2); // 如果存在退款那么就需要计算退款比例。
  135. $finally_amount = bcsub($share->order_amount, $share->refund_amount, 2);
  136. $finally_amount = bcsub($finally_amount, $share->pay_fee, 2);
  137. $share->finally_share_amount = bcmul($finally_amount, bcmul($share->fee_rate, 0.01, 4), 2); // 商家收到的钱
  138. $share->finally_fee = bcsub($finally_amount, $share->finally_share_amount, 2); // 平台收到的钱
  139. if (MallAddons::isInstall($params['mall_id'], AddonsEnum::ADDONS_NAME_STORE)) {
  140. //门店订单
  141. $commission = \addons\Store\common\models\StoreCommission::getOne([
  142. ['mall_id' => $params['mall_id']],
  143. ['order_no' => $params['order_no']],
  144. ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]],
  145. ['settle_type' => 4],
  146. ], true);
  147. \Yii::$app->custom->logs(__METHOD__ . "门店提成明细" . json_encode([
  148. 'params' => $params,
  149. 'commission' => $commission
  150. ]));
  151. if ($commission) {
  152. $share->finally_fee = $commission['amount_received'];//商家最终
  153. $share->finally_share_amount = bcsub($finally_amount, $share->finally_fee, 2); //平台最终
  154. }
  155. }
  156. $post = $share->toArray();
  157. $post['huifu_id'] = $config['huifupay_huifu_id'];
  158. $post['order_id'] = $share->order_no;
  159. $post['org_req_date'] = date('Ymd', $pOrder->created_at);
  160. $post['org_req_seq_id'] = $pOrder->hf_order_no;
  161. // 原交易为快捷支付必填:QUICK_PAY,
  162. // 原交易为余额支付必填:ACCT_PAYMENT;
  163. if ($pOrder->trade_type == 'fast_pay') {
  164. $post['pay_type'] = 'QUICK_PAY';
  165. } elseif ($pOrder->trade_type == 'balance_pay') {
  166. $post['pay_type'] = 'ACCT_PAYMENT';
  167. }
  168. $resp = $huifuService->shareCommission($post, [
  169. [
  170. 'id' => $share->merchant_no,
  171. 'num' => $share->finally_fee,
  172. ],
  173. [
  174. 'id' => $config['huifupay_huifu_id'],
  175. 'num' => $share->finally_share_amount,
  176. ]
  177. ]);
  178. if ($resp === false) {
  179. $share->response = [HuifuService::getStaticError()];
  180. $share->finally_fee = 0;
  181. $share->finally_share_amount = 0;
  182. } else {
  183. $share->response = $resp;
  184. $share->settle_status = 100;
  185. $share->settle_at = time(); // 结算时间
  186. }
  187. if (!$share->save()) throw new \Exception($share->getErrorMessage());
  188. $t->commit();
  189. } catch (\Exception $e) {
  190. var_dump($e->getMessage(), $e->getFile(), $e->getLine());
  191. \Yii::error(FormatHelper::exception($e, __METHOD__));
  192. $t->rollBack();
  193. return false;
  194. }
  195. return true;
  196. }
  197. public static function findOrder($mall_id, $order_no)
  198. {
  199. return HuifuBillShare::findOne(['order_no' => $order_no, 'mall_id' => $mall_id]);
  200. }
  201. public static function isEnableShare(int $mall_id)
  202. {
  203. $settings = \Yii::$app->services->setting->addons->get($mall_id, AddonsEnum::ADDONS_NAME_HUIFU_PAY, 'basic');
  204. if (empty($settings['huifupay_status'])) {
  205. return StatusEnum::DISABLED;
  206. }
  207. if (empty($settings['huifupay_ledger_status'])) {
  208. return StatusEnum::DISABLED;
  209. }
  210. return StatusEnum::ENABLED;
  211. }
  212. public static function shareProfit()
  213. {
  214. }
  215. }