DistributionBase.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. <?php
  2. namespace addons\Distribution\common\logic\reward;
  3. use addons\Distribution\common\enums\ComputingEnum;
  4. use addons\Distribution\common\enums\DistributionEnum;
  5. use addons\Distribution\common\models\Distribution;
  6. use common\enums\AddonsEnum;
  7. use common\enums\RabbitMqEnum;
  8. use common\enums\StatusEnum;
  9. use common\enums\UserWalletEnum;
  10. use common\helpers\TaskHelper;
  11. use common\helpers\FormatHelper;
  12. use common\models\mall\MallAddons;
  13. use common\models\user\UserDigital;
  14. use PhpAmqpLib\Message\AMQPMessage;
  15. use services\common\UserWalletService;
  16. abstract class DistributionBase
  17. {
  18. public $mall_id;
  19. public $user_id;
  20. public $basic_conf;
  21. public $distribution_list = [];
  22. public $order_detail = [];
  23. public $name = '';//佣金:price;积分:score
  24. public $distribution_goods_setting = [];
  25. public $regular_bonus_handle_class = '\addons\RegularBonus\common\services\CommissionService';
  26. /** @var \addons\RegularBonus\common\services\CommissionService|null $regular_bonus_handle_instance */
  27. public $regular_bonus_handle_instance;
  28. public $is_enable_regular_bonus = 0;
  29. public $regular_bonus_goods_setting = [];
  30. const PRICE_NAME_MAP = [
  31. UserWalletEnum::FIRST => '直推奖励',
  32. UserWalletEnum::SECOND => '间推奖励',
  33. UserWalletEnum::THIRD => '分销奖励',
  34. ];
  35. public function __construct($mall_id, $user_id, $basic_conf, $distribution_list, $order_detail, $name = 'commission')
  36. {
  37. $this->mall_id = $mall_id;
  38. $this->name = $name;
  39. $this->user_id = $user_id;
  40. $this->basic_conf = $basic_conf;
  41. $this->distribution_list = $distribution_list;
  42. $this->order_detail = $order_detail;
  43. }
  44. public function addFrozenCommission()
  45. {
  46. // 验证
  47. $config = $this->getLevelConfig();
  48. $regular_bonus_setting = $this->regular_bonus_goods_setting;
  49. if (!isset($this->basic_conf['is_self_buy'])) $this->basic_conf['is_self_buy'] = 0;
  50. $level = $this->basic_conf['level'];
  51. if (empty($level)) return;
  52. if(!empty($this->distribution_goods_setting) && $this->name == 'score'){
  53. $extra = !empty($this->distribution_goods_setting['extra']) && is_string($this->distribution_goods_setting['extra']) ? json_decode($this->distribution_goods_setting['extra'], true) : [];
  54. $enable_limit_level = isset($extra['score']) ? $extra['score']['enable_limit_level'] : 0;
  55. if($enable_limit_level == 1) {
  56. $limit_level = isset($extra['score']) ? $extra['score']['limit_level'] : [];
  57. $u_istribute = Distribution::find()->where(['mall_id' => $this->mall_id, 'user_id' => $this->user_id, 'status' => StatusEnum::ENABLED])->select('user_id,level')->one();
  58. if(empty($u_istribute) || !in_array($u_istribute->level, (array)$limit_level)) return;
  59. }
  60. }
  61. ['money' => $money, 'multiple' => $multiple, 'extension' => $extension] = $this->getRules('order_detail');
  62. $prize_key_map = [DistributionEnum::DI_FIRST, DistributionEnum::DI_SECOND, DistributionEnum::DI_THIRD];
  63. $prize_list = [];
  64. $regular_bonus_prize_list = [];
  65. for ($deep = 0; $deep < $level; $deep++) {
  66. if (!empty($this->distribution_list[$deep])) {
  67. if (isset($config[$this->distribution_list[$deep]->level])) {
  68. $config_arr = $config[$this->distribution_list[$deep]->level];
  69. } else {
  70. if(empty($this->order_detail['store_id'])&&empty($this->order_detail['mch_id'])){
  71. $config_arr = json_decode($this->basic_conf[$this->name],true);
  72. }else{
  73. $config_arr =[];
  74. }
  75. }
  76. $prize = $this->computing($config_arr, $money, $prize_key_map[$deep] . '_prize', $multiple);
  77. \Yii::error("{$this->distribution_list[$deep]->user_id} => {$prize}");
  78. if ($this->name == 'score' && $this->basic_conf['is_reward_score_limit']) {
  79. //开启了分销商积分上限值,重新计算奖励积分
  80. $prize = $this->computeResultsInScore($this->distribution_list[$deep]->user_id, $prize);
  81. }
  82. if ($prize > 0) {
  83. // 批处理组装数据
  84. $prize_list[$this->distribution_list[$deep]->user_id] = ['price' => $prize, 'distribution_id' => $this->distribution_list[$deep]->id, 'deep'=>$prize_key_map[$deep],'distribution_level' => $this->distribution_list[$deep]->level];
  85. }
  86. // 定期分红业务
  87. if (isset($regular_bonus_setting[$this->distribution_list[$deep]->level])) {
  88. $config_arr = $regular_bonus_setting[$this->distribution_list[$deep]->level];
  89. } else {
  90. if(empty($this->order_detail['store_id'])&&empty($this->order_detail['mch_id'])){
  91. $config_arr = [];
  92. }else{
  93. $config_arr =[];
  94. }
  95. }
  96. $prize = $this->computing($config_arr, $money, $prize_key_map[$deep] . '_prize', $multiple);
  97. if ($prize > 0) {
  98. // 批处理组装数据
  99. $regular_bonus_prize_list[$this->distribution_list[$deep]->user_id] = ['price' => $prize, 'distribution_id' => $this->distribution_list[$deep]->id, 'deep'=>$prize_key_map[$deep],'distribution_level' => $this->distribution_list[$deep]->level];
  100. }
  101. }
  102. }
  103. $insert_wallet = $this->packagingData($prize_list, $extension);
  104. $regular_bonus_wallet = $this->organizeData($regular_bonus_prize_list, $extension);
  105. if(!empty($regular_bonus_wallet)){
  106. $insert_wallet = array_merge($insert_wallet,$regular_bonus_wallet);
  107. }
  108. // 批量插入数据
  109. $money = 0;
  110. \Yii::error(json_encode($insert_wallet, JSON_UNESCAPED_UNICODE));
  111. try {
  112. //投递到资产队列
  113. $this->handleInsertWallet($insert_wallet, $money);
  114. $this->addRewardConfigLog();
  115. return $money;
  116. } catch (\Exception $e) {
  117. \Yii::error('DistributionBase:addFrozenCommission'.$e->getMessage());
  118. \Yii::error('DistributionBase:addFrozenCommission:info'.json_encode([
  119. 'file'=>$e->getFile(),
  120. 'line'=>$e->getLine(),
  121. 'msg'=>$e->getMessage(),
  122. ]));
  123. return 0 ;
  124. }
  125. }
  126. private function computing($config, $money, $prize_key, $multiple = 1)
  127. {
  128. $is_percent_key = "is_percent";
  129. $num = 0;
  130. if (isset($config[$is_percent_key]) && isset($config[$prize_key])) {
  131. $prize = $config[$prize_key] ?: 0;
  132. $prize = $prize > 0 ? $prize : 0;
  133. $num = $config[$is_percent_key] == 0 ? $money * $prize / 100 * $multiple : $prize * $multiple;
  134. }
  135. return $num;
  136. }
  137. abstract public function getLevelConfig();
  138. abstract public function getRules($source_table);
  139. abstract public function addRewardConfigLog();
  140. public function organizeData($prize_list, $extension)
  141. {
  142. return [];
  143. }
  144. public function handleInsertWallet($insert_wallet, &$money)
  145. {
  146. //投递到资产队列
  147. if($insert_wallet){
  148. $status = StatusEnum::ENABLED;
  149. if($this->name != 'digital'){
  150. $res = UserWalletService::batchHandleByQueue($insert_wallet);
  151. if (empty($res)) throw new \Exception(UserWalletService::getStaticError());
  152. }
  153. foreach ($insert_wallet as $k=>$user){
  154. if($user['wallet_type'] == 'digital'){
  155. $res = UserDigital::handleUserDigital($user['mall_id'],$user['user_id'],$user['money'],$user['is_frozen'],$user);
  156. if($res === false) throw new \Exception(UserDigital::getStaticError());
  157. }
  158. if($user['from_type'] == AddonsEnum::ADDONS_NAME_REGULAR_BONUS.'_'.DistributionEnum::ADDONS_NAME) continue;
  159. $distribution = Distribution::findOne(['user_id'=>$user['user_id'],'status'=>[StatusEnum::ENABLED,StatusEnum::DISABLED],'mall_id'=>$this->mall_id]);
  160. if(empty($distribution)) continue;
  161. $field = 'total_'.$this->name;
  162. $distribution->$field += $user['money'];
  163. $money +=$user['money'];
  164. $res = $distribution->save();
  165. if (empty($res)) throw new \Exception(Distribution::getStaticError());
  166. }
  167. if($this->is_enable_regular_bonus){
  168. TaskHelper::pushTaskQueue(RabbitMqEnum::EXCHANGE_TASK,RabbitMqEnum::TASK_QUEUE, [
  169. 'mall_id' => $this->mall_id, 'order_detail_id' => $this->order_detail['id'], 'addons_name' => DistributionEnum::ADDONS_NAME, 'status' => (int)$status,
  170. ], $this->regular_bonus_handle_class, 'handleAgentOrDistributionWalletData', function(AMQPMessage $message){
  171. // 生产错误
  172. \Yii::error('发送异步任务失败');
  173. });
  174. }
  175. if (MallAddons::isInstall($this->mall_id, AddonsEnum::ADDONS_NAME_MEMBER_EQUAL_PROFITS) && $this->name == 'commission') {
  176. // 触发会员平级分润奖励
  177. $commision_data_list = ['commision_data_list' => $insert_wallet, 'addons' => AddonsEnum::ADDONS_NAME_DISTRIBUTION, 'order_no' => $this->order_detail['order_no'], 'order_detail' => $this->order_detail];
  178. \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_ORDER, RabbitMqEnum::ORDER_QUEUE, $commision_data_list,\addons\MemberEqualProfits\common\services\CommisionLogService::class, 'handle');
  179. }
  180. }
  181. }
  182. public function computeResultsInScore($user_id, $score)
  183. {
  184. if ($score <= 0) {
  185. return $score;
  186. }
  187. $distribution = Distribution::find()->where(['mall_id' => $this->mall_id, 'user_id' => $user_id, 'status' => StatusEnum::ENABLED])->select('user_id,total_score')->one();
  188. //累计积分
  189. $total_score = $distribution->total_score;
  190. //累计积分大于等于积分上限值不可继续获得积分
  191. if ($total_score >= $this->basic_conf['reward_score_limit'] || $this->basic_conf['reward_score_limit'] == 0) {
  192. return 0;
  193. }
  194. //计算还可获得的积分值
  195. $available_score = bcsub($this->basic_conf['reward_score_limit'], $total_score, 2);
  196. //获得积分值不可超过积分上限值
  197. return min($score, $available_score);
  198. }
  199. }