CommissionLogLogic.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. <?php
  2. namespace addons\ServeBonus\common\logic;
  3. use addons\ServeBonus\common\enums\ServeBonusEnum;
  4. use addons\ServeBonus\common\models\ServeBonusRewardLog;
  5. use addons\ServeBonus\common\models\ServeBonus;
  6. use addons\ServeBonus\common\models\ServeBonusAchievement;
  7. use addons\ServeBonus\common\models\ServeBonusCommissionJob;
  8. use addons\ServeBonus\common\models\ServeBonusCommissionLog;
  9. use addons\ServeBonus\common\models\ServeBonusPeriod;
  10. use addons\ServeBonus\common\models\ServeBonusCloudStockPeriod;
  11. use addons\ServeBonus\common\models\ServeBonusOrderLog;
  12. use common\enums\AddonsEnum;
  13. use common\enums\StatusEnum;
  14. use common\enums\UserWalletEnum;
  15. use common\helpers\FormatHelper;
  16. use common\models\mall\Mall;
  17. use common\models\mall\MallAddons;
  18. use common\traits\ErrorTrait;
  19. use Exception;
  20. use services\common\UserWalletService;
  21. use Yii;
  22. use yii\helpers\Json;
  23. class CommissionLogLogic{
  24. use ErrorTrait;
  25. /**
  26. * 执行分红操作
  27. * @Author: ltm
  28. * @DateTime: 2021/11/5 0005 14:27
  29. * @Copyright: copyright (c) 2021 广东七件事集团
  30. * @return bool
  31. */
  32. public function execute($mallId = 0, $isManual = false)
  33. {
  34. $where = [];
  35. !empty($mallId) && $isManual && $where['where'] = ['=', 'id' ,$mallId];// 手动执行单个商城分红操作
  36. $mall_list = Mall::getEnableMallList(true, $where);
  37. if(!empty($mall_list)){
  38. foreach ($mall_list as $mall){
  39. $mallId = $mall['id'];
  40. // 判断是否有安装该插件
  41. if (MallAddons::isInstall($mallId, AddonsEnum::ADDONS_NAME_SERVEBONUS) == false) continue;
  42. // 出单奖励记录
  43. $trans = Yii::$app->db->beginTransaction();
  44. try {
  45. $res = $this->calculate($mallId, $isManual);
  46. if($res === false) throw new Exception($this->getError());
  47. $trans->commit();
  48. } catch (Exception $e) {
  49. $trans->rollBack();
  50. }
  51. // 获取基础配置
  52. $config = Yii::$app->services->setting->addons->get($mallId, 'ServeBonus', 'basic');
  53. if ($config['is_enable'] == StatusEnum::ENABLED) {
  54. $continue = false;
  55. // 获取结算周期,0=天,1=周,2=月
  56. $compute_period = $config['compute_period'];
  57. if ($isManual == false) {
  58. switch ($compute_period) {
  59. case 1:
  60. $start_day = date("Ymd", strtotime("-1 day"));
  61. $end_day = $start_day;
  62. break;
  63. case 2:
  64. if (date('w') != 1) $continue = true;// 非周一直接退出
  65. $start_day = date("Ymd", strtotime("last Monday"));
  66. $end_day = date('Ymd', strtotime('-1 sunday', time()));;
  67. break;
  68. case 3:
  69. if (date('d') != 1) $continue = true;// 非当月1号直接退出
  70. $start_day = date("Ym01", strtotime("-1 month"));
  71. $end_day = date('Ymd', strtotime(date('Y-m', time()) . '-01 00:00:00') - 86400);
  72. break;
  73. }
  74. } else {
  75. $start_day = $end_day = date("Ymd", time());// 手动执行当日的订单分红
  76. }
  77. if ($continue) continue;
  78. $date_limit = $start_day . '-' . $end_day;
  79. $job = ServeBonusCommissionJob::findOne(['mall_id' => $mallId, 'compute_period' => $compute_period, 'date_limit' => $date_limit, 'status' => StatusEnum::ENABLED]);
  80. if ($job && $isManual == false) continue;
  81. // 生成执行记录
  82. if (empty($job)) {
  83. $job = new ServeBonusCommissionJob();
  84. $job->mall_id = $mallId;
  85. $job->date_limit = $date_limit;
  86. $job->compute_period = $compute_period;
  87. if (!$job->save()) throw new Exception($job->getErrorMessage());
  88. }
  89. $trans = Yii::$app->db->beginTransaction();
  90. try {
  91. $res = $this->addCommissionLog($mallId, $config, $start_day, $end_day);
  92. if($res === false) throw new Exception($this->getError());
  93. $trans->commit();
  94. } catch (Exception $e) {
  95. $trans->rollBack();
  96. }
  97. }
  98. }
  99. return true;
  100. }
  101. }
  102. //修复用
  103. public function fix($mallId = 0,$date=''){
  104. $where = [];
  105. $where['where'] = ['=', 'id' ,$mallId];// 手动执行单个商城分红操作
  106. $mall_list = Mall::getEnableMallList(true, $where);
  107. if(!empty($mall_list)){
  108. foreach ($mall_list as $mall){
  109. $mallId = $mall['id'];
  110. // 判断是否有安装该插件
  111. if (MallAddons::isInstall($mallId, AddonsEnum::ADDONS_NAME_SERVEBONUS) == false) continue;
  112. // 获取基础配置
  113. $config = Yii::$app->services->setting->addons->get($mallId, 'ServeBonus', 'basic');
  114. if ($config['is_enable'] == StatusEnum::ENABLED) {
  115. $compute_period = $config['compute_period'];
  116. if(empty($date))$date = date("Ymd", time());
  117. $start_day = $end_day = $date;// 手动执行当日的订单分红
  118. $date_limit = $start_day . '-' . $end_day;
  119. // 生成执行记录
  120. $job = new ServeBonusCommissionJob();
  121. $job->mall_id = $mallId;
  122. $job->date_limit = $date_limit;
  123. $job->compute_period = $compute_period;
  124. if (!$job->save()) throw new Exception($job->getErrorMessage());
  125. $trans = Yii::$app->db->beginTransaction();
  126. try {
  127. $res = $this->addCommissionLog($mallId, $config, $start_day, $end_day);
  128. if($res === false) throw new Exception($this->getError());
  129. $trans->commit();
  130. } catch (Exception $e) {
  131. $trans->rollBack();
  132. }
  133. }
  134. }
  135. return true;
  136. }
  137. }
  138. /**
  139. * 计算出单奖励
  140. * @Author: lun
  141. * @DateTime: 2022/1/25 0025 18:55
  142. * @Copyright: copyright (c) 2021 广东七件事集团
  143. * @param $mallId
  144. * @param $isManual
  145. */
  146. private function calculate($mallId, $isManual)
  147. {
  148. try {
  149. $time = time();
  150. $yesterday = date("Ymd", $time);
  151. $yesterday = $isManual ? $yesterday : date("Ymd", strtotime("-1 day"));
  152. // 获取出单奖励列表
  153. $list = ServeBonusAchievement::getServeBonusAchievement([['mall_id' => $mallId, 'date' => $yesterday, 'is_settlement' => StatusEnum::DISABLED, 'status' => StatusEnum::ENABLED]]);
  154. if (empty($list)) return true;
  155. // 将同级别的用户组合为数组
  156. foreach ($list as $item) {
  157. $bonus_uids[$item['level']][] = $item['user_id'];
  158. }
  159. // 循环操作
  160. foreach ($list as $item) {
  161. $num = count(array_unique($bonus_uids[$item['level']]));// 该等级的人数
  162. $commission = sprintf("%.2f",substr(sprintf("%.3f", $item['prize'] / $num), 0, -1));// 佣金
  163. $new_uids = array_unique($bonus_uids[$item['level']]);// 移除重复的元素
  164. foreach ($new_uids as $uid) {
  165. $rows[] = [
  166. 'mall_id' => $mallId,
  167. 'order_id' => $item['order_id'],
  168. 'order_no' => $item['order_no'],
  169. 'user_id' => $uid,
  170. 'type' => 1,
  171. 'level' => $item['level'],// 服务商等级
  172. 'amounts' => $item['prize'],
  173. 'commission' => $commission,
  174. 'settlement_data' => Json::encode([
  175. 'amounts' => $item['prize'],
  176. 'commonisson' => $commission,
  177. 'average_count' => $num,
  178. ]),
  179. 'date' => $yesterday,
  180. 'created_at' => $time,
  181. 'updated_at' => $time,
  182. ];
  183. }
  184. // 修改统计人数,将此条数据改为已结算
  185. ServeBonusAchievement::updateAll(['average_count' => $num, 'is_settlement' => StatusEnum::ENABLED], ['id' => $item['id']]);
  186. }
  187. // 生成数据
  188. if (!empty($rows)) {
  189. $field = ['mall_id','order_id','order_no','user_id','type','level','amounts','commission','settlement_data','date','created_at','updated_at'];
  190. $res = Yii::$app->db->createCommand()->batchInsert(ServeBonusRewardLog::tableName(), $field, $rows)->execute();
  191. if ($res == false) throw new \yii\db\Exception(ServeBonusRewardLog::getStaticError());
  192. }
  193. return true;
  194. } catch (Exception $e) {
  195. return false;
  196. }
  197. }
  198. /**
  199. * 增加ServeBonus分红佣金
  200. * @Author: ltm
  201. * @DateTime: 2021/11/5 0005 14:27
  202. * @Copyright: copyright (c) 2021 广东七件事集团
  203. * @param $mallId
  204. * @param $config
  205. * @param $start_day
  206. * @param $end_time
  207. * @return bool
  208. */
  209. private function addCommissionLog($mallId, $config, $start_day, $end_day)
  210. {
  211. if ($config['is_enable'] == StatusEnum::DISABLED) {
  212. Yii::error('系统没有开启服务商提成');
  213. return true;
  214. }
  215. try {
  216. // 初始化数据
  217. $time = time();
  218. $table_name = ServeBonusCommissionLog::tableName();
  219. // 获取所有服务商列表
  220. $servebonus_list = ServeBonus::find()->where(['mall_id' => $mallId, 'status' => StatusEnum::ENABLED])->asArray()->all();
  221. if (empty($servebonus_list)) return true;
  222. $servebonus_arr = array_column($servebonus_list,'user_id');
  223. // 获取分红奖励列表
  224. $reward_list = ServeBonusRewardLog::find()
  225. ->select('user_id,sum(amounts) amounts,sum(commission) commission,type')
  226. ->where(['mall_id' => $mallId, 'is_settlement' => StatusEnum::DISABLED])
  227. ->andFilterWhere(['between', 'date', $start_day, $end_day])
  228. ->groupBy('user_id,type')
  229. ->orderBy("user_id desc,type asc")
  230. ->asArray()
  231. ->all();
  232. //获取业绩分红奖励列表
  233. $achievement_reward_list = ServeBonusCloudStockPeriod::find()
  234. ->select('max(id) as id,user_id,amounts,amounts_num,total_amounts_num,commission,start_time,end_time')
  235. ->where(['mall_id' => $mallId, 'is_settlement' => StatusEnum::DISABLED])
  236. ->andWhere(['=', 'start_time', $start_day])
  237. ->andWhere(['=', 'end_time', $end_day])
  238. ->groupBy('user_id')
  239. ->orderBy("id desc")
  240. ->asArray()
  241. ->all();
  242. $level_arr = array_unique(array_column($servebonus_list,'level'));
  243. $servebonus_list = array_column($servebonus_list,null,'user_id');
  244. $total = [];
  245. foreach($level_arr as $level){
  246. $total[$level]['amounts_num'] = ServeBonusCloudStockPeriod::getAmountsNum($mallId,$level,$start_day,$end_day);
  247. $total[$level]['total_amounts_num'] = ServeBonusOrderLog::getTotalAmountsNum($mallId,$level,$start_day,$end_day);
  248. }
  249. if(!empty($achievement_reward_list)){
  250. foreach($achievement_reward_list as &$achievement_reward){
  251. $achievement_reward['type'] = ServeBonusEnum::BOUNS_TYPE_ACHIEVEMENT;
  252. if(empty($total[$servebonus_list[$achievement_reward['user_id']]['level']])) continue;
  253. $achievement_reward['amounts_num'] = $total[$servebonus_list[$achievement_reward['user_id']]['level']]['amounts_num'];
  254. $achievement_reward['total_amounts_num'] = $total[$servebonus_list[$achievement_reward['user_id']]['level']]['total_amounts_num'];
  255. $achievement_reward['commission'] = $achievement_reward['amounts'] / $achievement_reward['amounts_num'] * $achievement_reward['total_amounts_num'];
  256. }
  257. }
  258. $reward_list = array_merge($reward_list,$achievement_reward_list);
  259. if (empty($reward_list)) return true;
  260. // 获取本期期数id
  261. $period_id = ServeBonusPeriod::setData($mallId);
  262. $servebonus_commission = $forever_uids = [];// 用户佣金、记录加权分红、出单奖励用户初始化
  263. $total_commission = $total_extra_commission = $total_achievement_commission = 0;// 统计加权分红跟出单奖励总额
  264. $total_settlement_uids = [];
  265. // 生成计算好的结算数据
  266. foreach ($reward_list as $item) {
  267. if (in_array($item['user_id'], $servebonus_arr)) {
  268. // 加权分红跟出单奖励数据处理
  269. if(!$servebonus_commission[$item['user_id']]['commission']){
  270. $servebonus_commission[$item['user_id']]['commission'] = 0;
  271. }
  272. if(!$servebonus_commission[$item['user_id']]['extra_commission']){
  273. $servebonus_commission[$item['user_id']]['extra_commission'] = 0;
  274. }
  275. if(!$servebonus_commission[$item['user_id']]['achievement_commission']){
  276. $servebonus_commission[$item['user_id']]['achievement_commission'] = 0;
  277. }
  278. if ($item['type'] == ServeBonusEnum::BOUNS_TYPE_FOREVER) {
  279. $forever_uids[] = $item['user_id'];// 出单奖励用户id
  280. $servebonus_commission[$item['user_id']]['commission'] = $item['commission'];
  281. $total_commission += $item['commission'];
  282. } elseif($item['type'] == ServeBonusEnum::BOUNS_TYPE_ACHIEVEMENT){
  283. $servebonus_commission[$item['user_id']]['achievement_commission'] = $item['commission'];
  284. $total_achievement_commission += $item['commission'];
  285. $log = ServeBonusCloudStockPeriod::findOne($item['id']);
  286. $log->is_settlement = StatusEnum::ENABLED;
  287. $log->period_id = $period_id;
  288. $log->updated_at = $time;
  289. $log->amounts_num = $item['amounts_num'];
  290. $log->total_amounts_num = $item['total_amounts_num'];
  291. $log->commission = $item['commission'];
  292. if(!$log->save()) throw new \Exception(ServeBonusCloudStockPeriod::getStaticError());
  293. }else {
  294. $servebonus_commission[$item['user_id']]['commission'] = $servebonus_commission[$item['user_id']]['commission'] ?? 0;
  295. $servebonus_commission[$item['user_id']]['extra_commission'] = $item['commission'];
  296. $total_extra_commission += $item['commission'];
  297. }
  298. $rows[$item['user_id']] = [
  299. 'mall_id' => $mallId,
  300. 'user_id' => $item['user_id'],
  301. 'period_id' => $period_id,
  302. 'commission' => empty($rows[$item['user_id']]['commission']) ? $servebonus_commission[$item['user_id']]['commission'] : $rows[$item['user_id']]['commission'],
  303. 'extra_commission' => empty($rows[$item['user_id']]['extra_commission']) ? $servebonus_commission[$item['user_id']]['extra_commission'] : $rows[$item['user_id']]['extra_commission'],
  304. 'compute_period' => $config['compute_period'],
  305. 'start_time' => $start_day,
  306. 'end_time' => $end_day,
  307. 'created_at' => $time,
  308. 'updated_at' => $time,
  309. 'achievement_commission' => empty($rows[$item['user_id']]['achievement_commission']) ? $servebonus_commission[$item['user_id']]['achievement_commission'] : $rows[$item['user_id']]['achievement_commission'],
  310. ];
  311. $total_settlement_uids[] = $item['user_id'];
  312. }
  313. }
  314. if (empty($rows)) return true;
  315. // 生成数据
  316. $field = ['mall_id','user_id','period_id','commission','extra_commission','compute_period','start_time','end_time','created_at','updated_at','achievement_commission'];
  317. Yii::$app->db->createCommand()->batchInsert($table_name, $field, $rows)->execute();
  318. // 数据生成完成记录表修改结算状态
  319. ServeBonusRewardLog::updateAll(
  320. [
  321. 'is_settlement' => StatusEnum::ENABLED,
  322. 'period_id' => $period_id,
  323. 'updated_at' => $time
  324. ],
  325. ['and', ['mall_id' => $mallId, 'is_settlement' => StatusEnum::DISABLED],['between', 'date', $start_day, $end_day]]
  326. );
  327. // 增加对应服务商分佣金额
  328. $log_list = ServeBonusCommissionLog::getServeBonusCommissionLog([['mall_id' => $mallId,'period_id' => $period_id,'start_time' => $start_day,'end_time' => $end_day]]);
  329. foreach ($log_list as $item) {
  330. $wallet_money = $item['commission'] + $item['extra_commission'] + $item['achievement_commission'];
  331. if (empty($wallet_money)) continue;
  332. $insert_wallet[] = [
  333. 'mall_id' => $mallId,
  334. 'user_id' => $item['user_id'],
  335. 'is_frozen' => false,
  336. 'wallet_type' => 'commission',
  337. 'money' => $wallet_money,
  338. 'desc' => '服务商分红佣金',
  339. 'source_table' => $table_name,
  340. 'source_table_id' => $item['id'],
  341. 'from_type' => ServeBonusEnum::ADDONS_NAME,
  342. 'capital_type' => UserWalletEnum::BOUNS,
  343. ];
  344. }
  345. if (!empty($insert_wallet)) {
  346. $res = UserWalletService::batchHandleByQueue($insert_wallet);
  347. if (empty($res)) throw new \Exception(UserWalletService::getStaticError());
  348. }
  349. // 增加用户服务商金额
  350. $commission_logs = ServeBonusCommissionLog::find()->where(['period_id' => $period_id, 'status' => StatusEnum::ENABLED])->asArray()->all();
  351. foreach ($commission_logs as $commission_log) {
  352. $ServeBonus = ServeBonus::findOne(['mall_id' => $mallId, 'user_id' => $commission_log['user_id'], 'status' => StatusEnum::ENABLED]);
  353. if (empty($ServeBonus)) continue;
  354. if (!empty($commission_log['commission'])) {// 出单奖励
  355. $ServeBonus->commission += $commission_log['commission'];// 增加出单奖励
  356. $ServeBonus->total_commission += $commission_log['commission'];// 增加总累计
  357. }
  358. if (!empty($commission_log['extra_commission'])) {// 加权分红
  359. $ServeBonus->extra_commission += $commission_log['extra_commission'];// 增加加权分红奖励
  360. $ServeBonus->total_commission += $commission_log['extra_commission'];// 增加总累计
  361. }
  362. if (!empty($commission_log['achievement_commission'])) {// 加权分红
  363. $ServeBonus->achievement_commission += $commission_log['achievement_commission'];// 增加加权分红奖励
  364. $ServeBonus->total_commission += $commission_log['achievement_commission'];// 增加总累计
  365. }
  366. $ServeBonus->temp_extra_commission = $ServeBonus->extra_commission;// 重置加权平分计算金额
  367. $ServeBonus->period_num = $ServeBonus->period_num + 1;// 增加结算期数
  368. if (!$ServeBonus->save()) throw new \Exception($ServeBonus->getErrorMessage());
  369. }
  370. // 修改商城本期分红数据
  371. ServeBonusPeriod::setData($mallId,[
  372. 'id' => $period_id,
  373. 'amounts' => $total_commission,
  374. 'amounts_num' => count(array_unique($forever_uids)),
  375. 'extra_amounts' => $total_extra_commission,
  376. 'total_amounts_num' => count(array_unique($total_settlement_uids)),
  377. 'compute_period' => $config['compute_period'],
  378. 'start_time' => $start_day,
  379. 'end_time' => $end_day,
  380. 'achievement_commission' => $total_achievement_commission,
  381. ]);
  382. return true;
  383. } catch (Exception $e) {
  384. $exception = FormatHelper::exception($e, "mall_id={$mallId} 服务商定时分红任务失败");
  385. echo $exception;
  386. Yii::error($exception);
  387. $this->setError($exception);
  388. return false;
  389. }
  390. }
  391. }