PoolPrizeLogic.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. <?php
  2. namespace addons\Boss\common\logic;
  3. use addons\Boss\common\enums\BossEnum;
  4. use addons\Boss\common\models\AddonsBoss;
  5. use addons\Boss\common\models\AddonsBossCommissionItemSetting;
  6. use addons\Boss\common\models\BossPoolPrizeCommissionLog;
  7. use addons\Boss\common\models\BossPoolPrizeJob;
  8. use addons\Boss\common\models\BossPoolPrizeOrderLog;
  9. use addons\Boss\common\models\BossPoolPrizePerformance;
  10. use common\enums\StatusEnum;
  11. use common\models\mall\MallAddons;
  12. use common\models\user\UserPartitionRelationship;
  13. use common\traits\ErrorTrait;
  14. use services\common\UserWalletService;
  15. /**
  16. * 奖金池逻辑层
  17. */
  18. class PoolPrizeLogic
  19. {
  20. use ErrorTrait;
  21. public function record($order, $order_status)
  22. {
  23. try {
  24. $mall_id = $order['mall_id'];
  25. // 判断用户插件是否安装
  26. if (MallAddons::isInstall($mall_id, BossEnum::ADDONS_NAME) == 0) return true;
  27. // 获取基础配置
  28. $config = \Yii::$app->services->setting->addons->get($mall_id, BossEnum::ADDONS_NAME, 'basic');
  29. // 判断是否开启插件分润
  30. if ($config['is_enable'] == StatusEnum::DISABLED) return true;
  31. if ($config['is_prize_pool'] == StatusEnum::DISABLED) return true;
  32. if (($config['performance_settlement_method'] ?? 0) == $order_status) {
  33. $this->recordPerformance($order);
  34. }
  35. if ($config['prize_pool_time'] == $order_status) {
  36. $this->recordOrderLog($order, $config);
  37. }
  38. } catch (\Exception $e) {
  39. \Yii::error(__METHOD__ . ', err:' . $e->getMessage());
  40. }
  41. }
  42. public function send($mall_id, $config, $start_at, $end_at, $job_id)
  43. {
  44. try {
  45. $pool_prize_amount = 0;
  46. $prize_pool_source = $config['prize_pool_source'] ?? 1;
  47. if ($prize_pool_source == 1) {
  48. // 周期内奖金池总金额
  49. $pool_prize_amount = BossPoolPrizeOrderLog::find()->where([
  50. 'and',
  51. ['mall_id' => $mall_id],
  52. ['status' => StatusEnum::ENABLED],
  53. ['settlement_status' => StatusEnum::DISABLED],
  54. ['between', 'date', $start_at, $end_at]
  55. ])->sum('amount') ?? 0;
  56. } else if ($prize_pool_source == 2) {
  57. // 自定义奖金池金额
  58. $pool_prize_amount = $config['prize_pool_amount'] ?? 0;
  59. }
  60. if ($pool_prize_amount <= 0) return true;
  61. $boss_list = AddonsBoss::lists([
  62. 'where' => [
  63. ['mall_id' => $mall_id],
  64. ['status' => StatusEnum::ENABLED]
  65. ],
  66. 'select' => 'id,user_id'
  67. ]);
  68. $boss_uid = array_column($boss_list, 'user_id') ?? [];
  69. if (empty($boss_uid)) return true;
  70. // 周期内奖金池总业绩
  71. $all_performance = BossPoolPrizePerformance::find()->where([
  72. 'and',
  73. ['mall_id' => $mall_id],
  74. ['user_id' => $boss_uid],
  75. ['status' => StatusEnum::ENABLED],
  76. ['between', 'date', $start_at, $end_at],
  77. ])->sum('performance') ?? 0;
  78. if ($all_performance <= 0) return true;
  79. // 周期内奖金池各个用户的业绩
  80. $users_performance = BossPoolPrizePerformance::find()->where([
  81. 'and',
  82. ['mall_id' => $mall_id],
  83. ['user_id' => $boss_uid],
  84. ['status' => StatusEnum::ENABLED],
  85. ['between', 'date', $start_at, $end_at],
  86. ])->select('SUM(performance) AS total_performance, user_id')
  87. ->groupBy('user_id')
  88. ->indexBy('user_id')
  89. ->asArray()
  90. ->all();
  91. $user_ids = array_column($users_performance, 'user_id') ?? [];
  92. if (empty($user_ids)) return true;
  93. $num = count($users_performance);
  94. $boss_uid_list = array_column($boss_list, 'id', 'user_id');
  95. $rows = [];
  96. $period_num = 0;
  97. $period_amount = 0;
  98. $period_performance = array_sum(array_column($users_performance, 'total_performance') ?? []);
  99. foreach ($users_performance as $user_id => $performance) {
  100. $amount = bcdiv(bcmul($performance['total_performance'], $pool_prize_amount, 4), $all_performance, 2);
  101. $rows[] = [
  102. 'boss_id' => $boss_uid_list[$user_id] ?? 0,
  103. 'mall_id' => $mall_id,
  104. 'user_id' => $user_id,
  105. 'num' => $num,
  106. 'total_amount' => $pool_prize_amount,
  107. 'total_performance' => $all_performance,
  108. 'personal_performance' => $performance['total_performance'],
  109. 'amount' => $amount,
  110. 'start_at' => $start_at,
  111. 'end_at' => $end_at,
  112. 'created_at' => time(),
  113. 'updated_at' => time(),
  114. 'billing_cycle' => $config['prize_pool_period'],
  115. 'job_id' => $job_id,
  116. ];
  117. $period_num += 1;
  118. $period_amount += $amount;
  119. }
  120. if (empty($rows)) throw new \Exception('奖金池佣金记录为空');
  121. $job = BossPoolPrizeJob::findOne($job_id);
  122. $t = \Yii::$app->db->beginTransaction();
  123. try {
  124. $insert_wallet = [];
  125. $columns = ['boss_id', 'mall_id', 'user_id', 'num', 'total_amount', 'total_performance', 'personal_performance', 'amount', 'start_at', 'end_at', 'created_at', 'updated_at', 'billing_cycle', 'job_id'];
  126. $res = \Yii::$app->db->createCommand()->batchInsert(BossPoolPrizeCommissionLog::tableName(), $columns, $rows)->execute();
  127. if (!$res) throw new \Exception('批量生成奖金池佣金记录失败');
  128. BossPoolPrizeOrderLog::updateAll(
  129. ['settlement_status' => StatusEnum::ENABLED, 'updated_at' => time()],
  130. ['and', ['mall_id' => $mall_id, 'settlement_status' => StatusEnum::DISABLED], ['between', 'date', $start_at, $end_at]]
  131. );
  132. $k = 1;
  133. $page_log = 1000;
  134. while ($log_list = BossPoolPrizeCommissionLog::find()->where(['mall_id' => $mall_id, 'start_at' => $start_at, 'end_at' => $end_at])
  135. ->offset(($k - 1) * $page_log)->limit($page_log)->asArray()->all()
  136. ) {
  137. foreach ($log_list as $log) {
  138. $boss = AddonsBoss::findOne(['mall_id' => $log['mall_id'], 'user_id' => $log['user_id'], 'status' => StatusEnum::ENABLED]);
  139. if (!$boss) continue;
  140. $boss->bonus_pool_commission += $log['amount'];
  141. $boss->total_commission += $log['amount'];
  142. $boss->save();
  143. $insert_wallet[] = [
  144. 'mall_id' => $log['mall_id'],
  145. 'user_id' => $log['user_id'],
  146. 'is_frozen' => false,
  147. 'wallet_type' => 'commission',
  148. 'money' => $log['amount'],
  149. 'desc' => '奖金池分红',
  150. 'source_table' => BossPoolPrizeCommissionLog::tableName(),
  151. 'source_table_id' => $log['id'],
  152. 'from_type' => BossEnum::ADDONS_NAME,
  153. 'capital_type' => BossEnum::ADDONS_NAME,
  154. ];
  155. }
  156. $k++;
  157. }
  158. $job->num = $period_num;
  159. $job->total_amount = $period_amount;
  160. $job->total_performance = $period_performance;
  161. $job->period_total_amount = $pool_prize_amount;
  162. $job->save();
  163. $t->commit();
  164. } catch (\Exception $ex) {
  165. $t->rollback();
  166. throw $ex;
  167. }
  168. if ($insert_wallet) {
  169. UserWalletService::batchHandleByQueue($insert_wallet);
  170. }
  171. } catch (\Exception $e) {
  172. \Yii::error(__METHOD__ . ', err:' . $e->getMessage());
  173. return true;
  174. }
  175. }
  176. /**
  177. * @Description: 记录分红池业绩
  178. * @Author: zsan
  179. * @DateTime 2023-10-12 10:00:30
  180. * @param array $order
  181. * @return bool
  182. */
  183. public function recordPerformance($order)
  184. {
  185. try {
  186. $mall_id = $order['mall_id'];
  187. $user_id = $order['user_id'];
  188. $pid_arr = UserPartitionRelationship::getParentIdArr($user_id);
  189. $pid_arr[] = $user_id;
  190. $boss_list = AddonsBoss::find()
  191. ->where(['mall_id' => $mall_id, 'user_id' => $pid_arr, 'status' => StatusEnum::ENABLED])
  192. ->select('id, user_id, mall_id, status, level')
  193. ->asArray()->all();
  194. if (empty($boss_list)) return true;
  195. $config = \Yii::$app->services->setting->addons->get($mall_id, BossEnum::ADDONS_NAME, 'basic');
  196. if (!empty($config['boss_level'])) $config['boss_level'] = json_decode($config['boss_level'], true);
  197. foreach ($boss_list as $boss) {
  198. if (!empty($config['boss_level']) && !in_array($boss['level'], $config['boss_level'])) continue;
  199. if (BossPoolPrizePerformance::setData([
  200. 'user_id' => $boss['user_id'],
  201. 'mall_id' => $mall_id,
  202. 'date' => date('Ymd'),
  203. 'performance' => $order['pay_money']
  204. ]) === false) {
  205. \Yii::error('err:,' . BossPoolPrizePerformance::getStaticError());
  206. }
  207. }
  208. return true;
  209. } catch (\Exception $e) {
  210. \Yii::error(__METHOD__ . ',err:' . $e->getMessage());
  211. return false;
  212. }
  213. }
  214. /**
  215. * @Description: 记录进入奖金池的订单
  216. * @Author: zsan
  217. * @DateTime 2023-10-12 10:37:38
  218. * @param array $order
  219. * @param array $config
  220. * @return bool
  221. */
  222. public function recordOrderLog($order, $config)
  223. {
  224. try {
  225. $user_id = $order['user_id'];
  226. $mall_id = $order['mall_id'];
  227. $order_detail = $order['detail'];
  228. $goods_ids = array_column($order_detail, 'goods_id');
  229. $setting = AddonsBossCommissionItemSetting::lists([
  230. 'where' => [
  231. ['mall_id' => $mall_id],
  232. ['item_id' => $goods_ids],
  233. ['commission_type' => 'commission'],
  234. ['status' => StatusEnum::ENABLED],
  235. ['is_prize_pool' => StatusEnum::ENABLED],
  236. ],
  237. 'select' => 'is_prize_pool,prize_pool_type,prize_pool_num,item_id',
  238. 'index' => 'item_id',
  239. ]);
  240. if (empty($setting)) return true;
  241. $amount = 0;
  242. foreach ($order_detail as $detail) {
  243. if (isset($setting[$detail['goods_id']])) {
  244. $prize_pool_type = $setting[$detail['goods_id']]['prize_pool_type']; //0百分比 1固定值
  245. $prize_pool_num = $setting[$detail['goods_id']]['prize_pool_num'];
  246. if ($prize_pool_type == 1) {
  247. $amount += bcmul($prize_pool_num, $detail['num'], 2);
  248. } else {
  249. $order_money = 0;
  250. if ($config['compute_type'] == 0) $order_money = $detail['goods_price']; // 支付金额
  251. if ($config['compute_type'] == 1) $order_money = $detail['goods_price'] - bcmul($detail['cost_price'], $detail['num'], 2) + $detail['adjust_money']; // 商品利润
  252. if ($config['compute_type'] == 2) $order_money = bcmul($detail['price'], $detail['num'], 2); // 商品售价
  253. $amount += $order_money * $prize_pool_num / 100;
  254. }
  255. }
  256. }
  257. if ($amount > 0) {
  258. if (BossPoolPrizeOrderLog::setData([
  259. 'mall_id' => $mall_id,
  260. 'user_id' => $user_id,
  261. 'date' => date('Ymd'),
  262. 'amount' => $amount,
  263. 'order_id' => $order['id'],
  264. 'order_no' => $order['order_no'],
  265. ]) === false) {
  266. throw new \Exception(BossPoolPrizeOrderLog::getStaticError());
  267. }
  268. }
  269. return true;
  270. } catch (\Exception $e) {
  271. \Yii::error(__METHOD__ . ',err:' . $e->getMessage());
  272. return false;
  273. }
  274. }
  275. }