RewardLogic.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. <?php
  2. namespace addons\WriteOff\common\logic;
  3. use addons\WriteOff\common\models\WriteOffMember;
  4. use addons\WriteOff\common\models\WriteOffMemberLog;
  5. use addons\WriteOff\common\models\WriteOffSetting;
  6. use addons\WriteOff\common\models\WriteOffUser;
  7. use addons\WriteOff\common\models\WriteOffLevel;
  8. use addons\WriteOff\common\models\WriteOffPromoteOrderLog;
  9. use addons\WriteOff\common\models\WriteOffAwardLog;
  10. use addons\WriteOff\common\models\WriteOffCommissionJob;
  11. use addons\WriteOff\common\helpers\QrcodeHelper;
  12. use addons\WriteOff\common\enums\WriteOffEnum;
  13. use services\common\UserWalletService;
  14. use common\enums\AddonsEnum;
  15. use common\enums\RabbitMqEnum;
  16. use common\enums\StatusEnum;
  17. use common\helpers\TaskHelper;
  18. use common\models\mall\MallAddons;
  19. use common\models\order\Order;
  20. use common\models\order\OrderDetail;
  21. use common\traits\ErrorTrait;
  22. use PhpAmqpLib\Message\AMQPMessage;
  23. use common\helpers\LockHelper;
  24. use common\enums\RedisKeyEnum;
  25. use yii\helpers\Json;
  26. use yii\db\Exception;
  27. use Yii;
  28. class RewardLogic
  29. {
  30. use ErrorTrait;
  31. public static function reward($params){
  32. $order = Order::findOne($params['id']);
  33. $order_id = $order['id'];
  34. $mall_id = $order['mall_id'];
  35. $isInstall = MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_WRITE_Off);
  36. if(!$isInstall) return true;
  37. // 获取配置
  38. $config = Yii::$app->services->setting->addons->get($mall_id, WriteOffEnum::ADDONS_NAME, 'basic');
  39. if(empty($config['is_enable'])) return true;
  40. $select = "id,mall_id,goods_id,user_id,goods_price,order_id,num";
  41. $order_details = OrderDetail::find()->select($select)->where(['order_id' => $order_id])->asArray()->all();
  42. if (empty($order_details)) throw new \Exception("订单id={$order_id}的订单详情数据为空");
  43. $goods_ids = array_column($order_details, 'goods_id'); // 商品ids
  44. // 获取设置了奖励的商品
  45. $list = WriteOffSetting::find()->where(['goods_id' => $goods_ids, 'is_enable_promote_reward' => StatusEnum::ENABLED, 'status' => StatusEnum::ENABLED])->indexBy('goods_id')->asArray()->all();
  46. if (empty($list)) return true;
  47. $extra_info = Json::decode($order['extra_info']);
  48. if(empty($extra_info['write_off']['user_id'])) return true;;
  49. $user_id = $extra_info['write_off']['user_id'];
  50. $insert_wallet = [];
  51. $t = \Yii::$app->db->beginTransaction();
  52. try{
  53. if(!empty($config['is_enable_promote_reward'])){
  54. $insert_wallet = self::promoteReward($order,$user_id,$config,$list,$order_details);
  55. }
  56. if(!empty($insert_wallet)){
  57. $res = UserWalletService::batchHandleByQueue($insert_wallet);
  58. if (empty($res)) throw new \Exception(UserWalletService::getStaticError());
  59. foreach ($insert_wallet as $k => $user) {
  60. $promote_commission_arr = [];
  61. $writeOffUser = WriteOffUser::find()->where(['mall_id'=>$mall_id,'user_id'=> $user['user_id'],'status' => StatusEnum::ENABLED])->one();
  62. if(empty($writeOffUser)) continue;
  63. if($user['capital_type'] == WriteOffEnum::PROMOTE_PRIZE){
  64. $writeOffUser->promote_commission += $user['money'];
  65. $promote_commission_arr = [
  66. 'mall_id' => $mall_id,
  67. 'user_id' => $user['user_id'],
  68. 'order_id' => $order['id'],
  69. 'order_no' => $order['order_no'],
  70. 'order_detail_id' => $user['source_table_id'],
  71. 'pay_money' => $order['pay_money'],
  72. 'buy_user_id' => $order['user_id'],
  73. ];
  74. }
  75. if($user['capital_type'] == WriteOffEnum::MANAGE_PRIZE){
  76. $writeOffUser->manage_commission += $user['money'];
  77. }
  78. $writeOffUser->total_commission += $user['money'];
  79. $res = $writeOffUser->save();
  80. if (empty($res)) throw new \Exception(WriteOffUser::getStaticError());
  81. if(!empty($promote_commission_arr)){
  82. $res = WriteOffPromoteOrderLog::setData($promote_commission_arr);
  83. if (empty($res)) throw new \Exception(WriteOffPromoteOrderLog::getStaticError());
  84. }
  85. }
  86. }
  87. $t->commit();
  88. return true;
  89. }catch(\Exception $e){
  90. $t->rollBack();
  91. \Yii::error('触发核销员奖励'.$e->getMessage());
  92. return false;
  93. }
  94. }
  95. public static function promoteReward($order,$user_id,$config,$list,$order_details){
  96. $mall_id = $order['mall_id'];
  97. $money = $order['pay_money'];
  98. $writeOffUser = WriteOffUser::find()->where(['mall_id'=>$mall_id,'user_id'=> $user_id,'status' => StatusEnum::ENABLED])->one();
  99. if(empty($writeOffUser)) throw new \Exception('核销员不存在');
  100. $level = WriteOffLevel::findOne(['mall_id'=>$mall_id,'level'=>$writeOffUser['level'],'status' => StatusEnum::ENABLED]);
  101. if(empty($level) || empty($level['is_enable_promote_reward'])) throw new \Exception('该等级未开启促销奖励');
  102. //$reward_money = $money * $level['promote_reward_prize'] / 100;
  103. foreach ($order_details as $detail) {
  104. $goods_id = $detail['goods_id'];
  105. $setting = $list[$goods_id] ?? [];
  106. if (empty($setting)) continue;
  107. // $settlement_method = $setting['settlement_method'];
  108. // if ($settlement_method != $order_status) continue;
  109. $pay_money = $detail['goods_price'] + $detail['adjust_money'];
  110. $reward_money = bcmul($level['promote_reward_prize'] / 100, $pay_money);
  111. if ($reward_money <= 0) continue;
  112. $insert_wallet[] = [
  113. 'mall_id' => $mall_id,
  114. 'user_id' => $user_id,
  115. 'is_frozen' => false,
  116. 'wallet_type' => 'commission',
  117. 'money' => $reward_money,
  118. 'desc' => '获得订单('.$order['id'].')促销奖励',
  119. 'source_table' => OrderDetail::tableName(),
  120. 'source_table_id' => $detail['id'],
  121. 'from_type' => WriteOffEnum::ADDONS_NAME,
  122. 'capital_type' => WriteOffEnum::PROMOTE_PRIZE,
  123. 'order_no' =>$order['order_no'],
  124. 'contributor_id' =>$order['user_id'],
  125. ];
  126. //管理奖励
  127. if (!empty($config['is_enable_store_manage_reward']) && $config['manage_reward_rate'] > 0) {
  128. $store_id = $writeOffUser['store_id'];
  129. $writeOffUserList = WriteOffUser::find()->where(['mall_id'=>$mall_id,'status'=>StatusEnum::ENABLED,'store_id'=>$store_id,'is_enable_manage_reward'=>1])->asArray()->all();
  130. if(!empty($writeOffUserList)){
  131. $manage_reward = $pay_money * $config['manage_reward_rate'] / 100;
  132. if($manage_reward > 0){
  133. foreach($writeOffUserList as $item){
  134. $insert_wallet[] = [
  135. 'mall_id' => $mall_id,
  136. 'user_id' => $item['user_id'],
  137. 'is_frozen' => false,
  138. 'wallet_type' => 'commission',
  139. 'money' => $manage_reward,
  140. 'desc' => '获得订单('.$order['id'].')管理奖励',
  141. 'source_table' => OrderDetail::tableName(),
  142. 'source_table_id' => $detail['id'],
  143. 'from_type' => WriteOffEnum::ADDONS_NAME,
  144. 'capital_type' => WriteOffEnum::MANAGE_PRIZE,
  145. 'order_no' =>$order['order_no'],
  146. 'contributor_id' =>$order['user_id'],
  147. ];
  148. }
  149. }
  150. }
  151. }
  152. }
  153. return $insert_wallet;
  154. }
  155. public static function writeOffReward($params){
  156. try{
  157. $writeOffMemberLog = WriteOffMemberLog::findOne($params['id']);
  158. if(empty($writeOffMemberLog)) throw new \Exception('数据不存在');
  159. $writeOffUser = WriteOffUser::findOne(['id' => $writeOffMemberLog['source_table_id'],'status' => StatusEnum::ENABLED]);
  160. if(empty($writeOffUser)) throw new \Exception('核销员状态异常');
  161. $mall_id = $writeOffUser['mall_id'];
  162. $level = WriteOffLevel::findOne(['mall_id'=>$mall_id,'level'=>$writeOffUser['level'],'status' => StatusEnum::ENABLED]);
  163. if(empty($level) || empty($level['is_enable_write_off_reward'])) throw new \Exception('该等级未开启核销奖励');
  164. $write_off_reward_proportion = json_decode($level['write_off_reward_proportion'],true);
  165. if(empty($write_off_reward_proportion)) throw new \Exception('阶梯奖励设置异常');
  166. $write_off_reward_proportion = array_reverse($write_off_reward_proportion);
  167. $counts = count($write_off_reward_proportion);
  168. $money = 0;
  169. $today_start = strtotime(date('Y-m-d 00:00:00',time()));
  170. $today_end = strtotime(date('Y-m-d 23:59:59',time()));
  171. $log_today = WriteOffMemberLog::find()
  172. ->where(['source_table' => WriteOffUser::tableName(),'source_table_id' => $writeOffUser['id'],'change_type' => 'sub'])
  173. ->andWhere(['>=','created_at',$today_start])
  174. ->andWhere(['<=','created_at',$today_end])
  175. ->sum('change_num') ?? 0;
  176. if($log_today > $counts){
  177. $proportion_first = $write_off_reward_proportion[0];
  178. $money = $proportion_first['money'];
  179. }else{
  180. foreach($write_off_reward_proportion as $key => $proportion){
  181. if($log_today == $counts - $key){
  182. $money = $proportion['money'];
  183. break;
  184. }
  185. }
  186. }
  187. if($money > 0){
  188. $insert_wallet[] = [
  189. 'mall_id' => $mall_id,
  190. 'user_id' => $writeOffUser['user_id'],
  191. 'is_frozen' => false,
  192. 'wallet_type' => 'commission',
  193. 'money' => $money,
  194. 'desc' => '核销用户('.$writeOffMemberLog['user_id'].')获得核销奖励',
  195. 'source_table' => WriteOffMemberLog::tableName(),
  196. 'source_table_id' => $writeOffMemberLog['id'],
  197. 'from_type' => WriteOffEnum::ADDONS_NAME,
  198. 'capital_type' => WriteOffEnum::WRITE_OFF_PRIZE,
  199. 'order_no' =>$writeOffMemberLog['order_no'],
  200. 'contributor_id' =>$writeOffMemberLog['user_id'],
  201. ];
  202. $res = UserWalletService::batchHandleByQueue($insert_wallet);
  203. if (empty($res)) throw new \Exception(UserWalletService::getStaticError());
  204. $writeOffUser->commission += $money;
  205. $writeOffUser->total_commission += $money;
  206. if(!$writeOffUser->save()) throw new \Exception(WriteOffUser::getStaticError());
  207. }
  208. return true;
  209. }catch(\Exception $e){
  210. \Yii::error('核销奖励发放异常,params:'.json_encode($params).',error:'.$e->getMessage());
  211. return false;
  212. }
  213. }
  214. public static function achievementPromoteReward($mall_id){
  215. $isInstall = MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_WRITE_Off);
  216. if(!$isInstall) return true;
  217. // 获取配置
  218. $config = Yii::$app->services->setting->addons->get($mall_id, WriteOffEnum::ADDONS_NAME, 'basic');
  219. if(empty($config['is_enable']) || empty($config['is_enable_promote_reward'])) return true;
  220. $continue = false;
  221. $compute_period = $config['compute_period'];
  222. switch ($config['compute_period']) {
  223. case 0:
  224. if (date('d') != 1) $continue = true;// 非当月1号直接退出
  225. $start_day = date("Ym01", strtotime("-1 month"));
  226. $end_day = date('Ymd', strtotime(date('Y-m', time()) . '-01 00:00:00') - 86400);
  227. break;
  228. }
  229. if ($continue) return true;
  230. $date_limit = $start_day . '-' . $end_day;
  231. $job = WriteOffCommissionJob::findOne(['mall_id' => $mall_id, 'compute_period' => $compute_period, 'date_limit' => $date_limit, 'status' => StatusEnum::ENABLED]);
  232. if ($job) return true;
  233. // 生成执行记录
  234. $job = new WriteOffCommissionJob();
  235. $job->mall_id = $mall_id;
  236. $job->date_limit = $date_limit;
  237. $job->compute_period = $compute_period;
  238. if (!$job->save()) throw new Exception($job->getErrorMessage());
  239. try {
  240. self::addCommissionLog($mall_id,$start_day, $end_day);
  241. return true;
  242. } catch (Exception $e) {
  243. \Yii::error('促销业绩奖励结算异常:'.$e->getMessage());
  244. return false;
  245. }
  246. }
  247. public static function addCommissionLog($mall_id,$start_day, $end_day){
  248. $start_day = strtotime($start_day);
  249. $end_day = strtotime(date('Y-m-d 23:59:59',strtotime($end_day)));
  250. $level_list = WriteOffLevel::find()
  251. ->where(['mall_id'=>$mall_id,'status' => StatusEnum::ENABLED,'is_enable_promote_reward_achievement'=>1])
  252. ->indexBy('level')
  253. ->asArray()
  254. ->all();
  255. if(empty($level_list)) return true;
  256. $levels = array_column($level_list,'level');
  257. foreach($level_list as &$level){
  258. $level['promote_achievement_reward_proportion'] = json_decode($level['promote_achievement_reward_proportion'],true);
  259. if(empty($level['promote_achievement_reward_proportion'])){
  260. unset($level);
  261. }
  262. $level['promote_achievement_reward_proportion'] = array_reverse($level['promote_achievement_reward_proportion']);
  263. }
  264. $write_off_user_list = WriteOffUser::find()
  265. ->where(['mall_id' => $mall_id, 'status' => StatusEnum::ENABLED])
  266. ->andWhere(['in','level',$levels])
  267. ->select('id,user_id,level')
  268. ->asArray()
  269. ->all();
  270. if (empty($write_off_user_list)) return true;
  271. $total = WriteOffPromoteOrderLog::find()
  272. ->where(['mall_id'=>$mall_id,'status'=>StatusEnum::ENABLED])
  273. ->andWhere(['>=','created_at',$start_day])
  274. ->andWhere(['<=','created_at',$end_day])
  275. ->indexBy('user_id')
  276. ->groupBy('user_id')
  277. ->select('sum(pay_money) as money,user_id')
  278. ->asArray()
  279. ->all();
  280. if(empty($total)) return true;
  281. $insert_wallet = [];
  282. $trans = \Yii::$app->db->beginTransaction();
  283. try{
  284. foreach($write_off_user_list as $write_off_user){
  285. $achievement = 0;
  286. $rate = 0;
  287. if(empty($level_list[$write_off_user['level']])) continue;
  288. $proportion_list = $level_list[$write_off_user['level']]['promote_achievement_reward_proportion'];
  289. if(!empty($total[$write_off_user['user_id']]['money'])){
  290. $achievement = $total[$write_off_user['user_id']]['money'];
  291. }
  292. foreach($proportion_list as $proportion){
  293. if($achievement >= $proportion['money_start'] && $achievement <= $proportion['money_end']){
  294. $rate = $proportion['proportion'];
  295. }
  296. }
  297. $reward_money = $achievement * $rate / 100;
  298. if($reward_money > 0){
  299. $params = [
  300. 'mall_id' => $mall_id,
  301. 'user_id' => $write_off_user['user_id'],
  302. 'achievement_sum' => $achievement,
  303. 'award_money' => $reward_money,
  304. 'rate' => $rate,
  305. 'is_settlement' => 1,
  306. ];
  307. $res = WriteOffAwardLog::setData($params);
  308. if (empty($res)) throw new \Exception(WriteOffAwardLog::getStaticError());
  309. $writeOffUser = WriteOffUser::findOne($write_off_user['id']);
  310. $writeOffUser->promote_achievement_commission += $reward_money;
  311. $writeOffUser->total_commission += $reward_money;
  312. if(!$writeOffUser->save()) throw new \Exception(WriteOffUser::getStaticError());
  313. $insert_wallet[] = [
  314. 'mall_id' => $mall_id,
  315. 'user_id' => $write_off_user['user_id'],
  316. 'is_frozen' => false,
  317. 'wallet_type' => 'commission',
  318. 'money' => $reward_money,
  319. 'desc' => '促销阶梯奖励',
  320. 'source_table' => WriteOffAwardLog::tableName(),
  321. 'source_table_id' => $res->id,
  322. 'from_type' => WriteOffEnum::ADDONS_NAME,
  323. 'capital_type' => WriteOffEnum::ACHIEVEMENT_PROMOTE_PRIZE,
  324. ];
  325. }
  326. }
  327. if(!empty($insert_wallet)){
  328. $res = UserWalletService::batchHandleByQueue($insert_wallet);
  329. if (empty($res)) throw new \Exception(UserWalletService::getStaticError());
  330. }
  331. $trans->commit();
  332. return true;
  333. }catch(\Exception $e){
  334. $trans->rollBack();
  335. throw new \Exception($e->getMessage());
  336. }
  337. }
  338. }