RewardLogLogic.php 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. <?php
  2. namespace addons\ServeBonus\common\logic;
  3. use addons\ServeBonus\common\enums\ServeBonusEnum;
  4. use addons\ServeBonus\common\models\ServeBonus;
  5. use addons\ServeBonus\common\models\ServeBonusCommissionItemSetting;
  6. use addons\ServeBonus\common\models\ServeBonusAchievement;
  7. use addons\ServeBonus\common\models\ServeBonusLevelSetting;
  8. use addons\ServeBonus\common\models\ServeBonusRewardLog;
  9. use addons\ServeBonus\common\models\ServeBonusOrderLog;
  10. use addons\ServeBonus\common\models\ServeBonusAchievementSettleLog;
  11. use addons\ServeBonus\common\models\ServeBonusCloudStockPeriod;
  12. use addons\CloudStock\common\enums\CloudStockEnum;
  13. use addons\CloudStock\common\models\CloudStockBuyingOrder;
  14. use addons\CloudStock\common\models\CloudStockFillOrder;
  15. use addons\CloudStock\common\models\CloudStockAgent;
  16. use addons\CloudStock\common\models\CloudStockGoods;
  17. use addons\CloudStock\common\models\CloudStockUpgradeBag;
  18. use addons\ServeBonus\common\models\ServeBonusLevel;
  19. use common\models\goods\Goods;
  20. use common\models\order\Order;
  21. use common\enums\StatusEnum;
  22. use common\helpers\ArrayHelper;
  23. use common\helpers\FormatHelper;
  24. use common\models\common\CapitalLog;
  25. use common\models\common\CommissionLog;
  26. use common\models\mall\MallAddons;
  27. use common\models\user\User;
  28. use yii\helpers\Json;
  29. use common\models\order\OrderDetail;
  30. use common\models\user\UserTeamMonthStatistics;
  31. use common\traits\ErrorTrait;
  32. use Exception;
  33. use yii;
  34. /**
  35. * Class RewardLog
  36. * @Author: ltm
  37. * @DateTime: 2021/10/25 9:39
  38. * @Copyright: copyright (c) 2021 广东七件事集团
  39. * @package addons\ServeBonus\common\logic
  40. */
  41. class RewardLogLogic
  42. {
  43. use ErrorTrait;
  44. /**
  45. * @Author: hua
  46. * @DateTime: 2021/10/18 9:57
  47. * @Copyright: copyright (c) 2021 广东七件事集团
  48. * @param $data
  49. * @return bool
  50. */
  51. public function execute($order, $settlement_method)
  52. {
  53. try {
  54. // 查询订单信息
  55. $where['where'] = [['=', 'order_id', $order['id']], ['=', 'status', StatusEnum::ENABLED]];
  56. $order_detail = OrderDetail::lists($where, true);
  57. if (empty($order_detail)) return true;
  58. // 初始化数据
  59. $mallId = $order['mall_id'];
  60. $user_id = $order['user_id'];
  61. $calculate = [];// 佣金计算
  62. $amounts = 0;// 结算的总金额
  63. $date = date('Ymd', time());
  64. $time = time();
  65. // 判断用户插件是否安装
  66. if (MallAddons::isInstall($mallId, ServeBonusEnum::ADDONS_NAME) == false) return true;
  67. // 获取基础配置
  68. $config = Yii::$app->services->setting->addons->get($mallId, 'ServeBonus', 'basic');
  69. // 判断是否开启插件分润
  70. if ($config['is_enable'] == StatusEnum::DISABLED) return true;
  71. // 判断结算方式,0=支付完成,1=订单完成
  72. if ($config['settlement_method'] != $settlement_method) return true;
  73. // 获取用户信息
  74. $user = User::find()->select("parent_id")->where(['id' => $user_id, 'status' => StatusEnum::ENABLED])->asArray()->one();
  75. $parent_level = ServeBonus::find()->select("level")->where(['mall_id' => $mallId,'user_id' => $user['parent_id'], 'status' => StatusEnum::ENABLED])->asArray()->scalar();
  76. // 获取服务商等级列表
  77. $field = 'level,prize,is_percent_prize,extra_prize,is_percent_extra,is_extra,extra_type,extra_is_limit,extra_limit_price,is_accumulation,is_cloud_stock_open,accumulation_condition,accumulation_condition_money';
  78. $level_arr = ServeBonusLevelSetting::find()->select($field)->where(['mall_id' => $mallId, 'status' => StatusEnum::ENABLED])->orderBy('level asc')->asArray()->all();
  79. if (empty($level_arr)) return true;
  80. $level_arr = array_column($level_arr, null, 'level');
  81. // 获取所有服务商列表
  82. $servebonus_list = ServeBonus::find()->where(['mall_id' => $mallId, 'status' => StatusEnum::ENABLED])->all();
  83. if (empty($servebonus_list)) return true;
  84. // 服务商是否开启加权平均分限制条件
  85. $last_month = date('Y-m', strtotime('-1 month'));
  86. $unachievement_list = [];
  87. $achievement_field = $config['achievement_count_method'] == 1 ? 'finish_price' : 'price';
  88. //排除已经达到佣金上限的服务商
  89. $level_list = [];
  90. $diff_num = [];
  91. foreach ($servebonus_list as $lv => $slb) {
  92. $level = null;
  93. if (!isset($level_list[$slb->level])) {
  94. $level = ServeBonusLevel::find()->where(['mall_id' => $mallId, 'status' => StatusEnum::ENABLED, 'level' => $slb->level])->one();
  95. if ($level) {
  96. $level_list[$slb->level] = $level;
  97. } else {
  98. $level_list[$slb->level] = null;
  99. }
  100. } else {
  101. $level = $level_list[$slb->level];
  102. }
  103. if (!$level) unset($servebonus_list[$lv]);
  104. //计算金额
  105. if ($level->is_to_bonus && $level->to_bonus_price > 0) {
  106. CapitalLog::$capitalType = 'commission';
  107. $total_settled = CapitalLog::find()->where(['user_id' => $slb->user_id, 'change_type' => 'add'])->sum('change_num') ?? 0;
  108. CapitalLog::$capitalType = 'commission_frozen';
  109. $total_nosettled = CapitalLog::find()->where(['user_id' => $slb->user_id, 'change_type' => 'add'])->sum('change_num') ?? 0;
  110. $total = bcadd($total_nosettled + $total_settled, 2);
  111. if ($total >= $level->to_bonus_price) {
  112. unset($servebonus_list[$lv]);
  113. $diff_num[$slb->level] += 1;
  114. }
  115. }
  116. // 加权平均分限制条件
  117. if ($level_arr[$slb->level]['accumulation_condition'] == 1) {
  118. $achievement_price = UserTeamMonthStatistics::find()->where(['mall_id' => $mallId, 'user_id' => $slb->user_id, 'month' => $last_month, 'status' => StatusEnum::ENABLED])->select($achievement_field)->scalar();
  119. // 加权平均分限制条件,上月团队总业绩需达标
  120. if ($achievement_price < $level_arr[$slb->level]['accumulation_condition_money']) {
  121. $diff_num[$slb->level] += 1;
  122. $unachievement_list[] = $slb->id;
  123. }
  124. }
  125. }
  126. // 统计各个服务商等级的总人数
  127. $level_count = ServeBonus::find()
  128. ->select("count(id) num,level")
  129. ->where(['mall_id' => $mallId, 'status' => StatusEnum::ENABLED])
  130. ->groupBy("level")
  131. ->indexBy("level")
  132. ->orderBy("level asc")
  133. ->asArray()
  134. ->all();
  135. //减去相应的人头
  136. if ($level_count) {
  137. foreach ($level_count as &$lv_item) {
  138. if (isset($diff_num[$lv_item['level']])) {
  139. $lv_item['num'] = $lv_item['num'] - $diff_num[$lv_item['level']];
  140. if ($lv_item['num'] < 0) $lv_item['num'] = 0;
  141. }
  142. }
  143. }
  144. $temp_level_count = $level_count;
  145. $settlement_data = [];
  146. $total_commonisson = 0;// 出单奖励总奖励金额初始化
  147. // 循环订单详情,对不同商品进行对应的佣金结算
  148. foreach ($order_detail as $index => $detail) {
  149. $accumulation_num = $prev_commission = 0;// 叠加数量,叠加奖励;
  150. // 查询服务商商品
  151. $goods_setting = ServeBonusCommissionItemSetting::getOne([['mall_id' => $mallId,'item_id' => $detail['goods_id'], 'is_enable' => StatusEnum::ENABLED]], true, ['detail']);
  152. if (empty($goods_setting)) continue;
  153. //新增:云库存商品判断
  154. if(!empty($config['is_cloud_stock_open'])){
  155. $cloud_stock_goods = CloudStockGoods::findOne(['mall_id'=>$mallId,'goods_id'=>$detail['goods_id'],'status' => StatusEnum::ENABLED]);
  156. $upgrade_bag_list = CloudStockUpgradeBag::lists(['where'=>['mall_id'=>$mallId,'status' => StatusEnum::ENABLED]]);
  157. $is_upgrade_bag_goods = false;
  158. foreach($upgrade_bag_list as $upgrade_bag){
  159. $upgrade_bag_goods = is_numeric($upgrade_bag['goods_id']) ? [$upgrade_bag['goods_id']] : json_decode($upgrade_bag['goods_id'],true);
  160. if(in_array($detail['goods_id'],$upgrade_bag_goods)){
  161. $is_upgrade_bag_goods = true;
  162. break;
  163. }
  164. }
  165. if(!empty($cloud_stock_goods) || $is_upgrade_bag_goods) continue;
  166. }
  167. // 获取结算的金额
  168. if ($config['compute_type'] == 0) $order_money = $detail['goods_price'];// 支付金额
  169. if ($config['compute_type'] == 1) $order_money = $detail['goods_price'] - ($detail['cost_price'] * $detail['num']) + $detail['adjust_money'];// 商品利润
  170. if ($config['compute_type'] == 2) $order_money = $detail['price'] * $detail['num'];// 商品售价
  171. if ($order_money <= 0) continue;// 分红金额过小则没必要分红
  172. //添加订单记录
  173. $order_log = ServeBonusOrderLog::findOne(['order_no'=>$order['order_no'],'order_detail_id'=>$detail['id']]);
  174. if(empty($order_log)){
  175. $order_log_params = [
  176. 'mall_id'=> $mallId,
  177. 'order_id' => $order['id'],
  178. 'order_detail_id' => $detail['id'],
  179. 'order_no' => $order['order_no'],
  180. 'order_type' => 0,
  181. 'money' => $order_money,
  182. 'date' => $date,
  183. 'goods_id' => $detail['goods_id'],
  184. 'num' => (int)$detail['num'],
  185. ];
  186. $res = ServeBonusOrderLog::setData($order_log_params);
  187. if ($res == false) throw new Exception(ServeBonusOrderLog::getStaticError());
  188. }
  189. $amounts = $amounts + $order_money;
  190. // 判断是否开启独立设置
  191. $is_gooods_alone = false;
  192. if (!empty($goods_setting['is_alone']) && $goods_setting['is_alone'] == 1) {
  193. // 商品独立分佣配置
  194. $level_calculate = $goods_setting['detail'];
  195. $is_gooods_alone = true;
  196. } else {
  197. // 等级分佣配置
  198. $level_calculate = $level_arr;
  199. }
  200. // 将等级设计倒叙,最高等级为排第一,计算各个等级开启叠加分红后的数量
  201. $level_count = $temp_level_count;
  202. $desc_level_calculate = ArrayHelper::arraySort($level_calculate, 'level', 'desc');
  203. foreach ($desc_level_calculate as $level) {
  204. $level_num = $level_count[$level['level']]['num'];// 该等级的人数
  205. $level_count[$level['level']]['num'] += $accumulation_num;// 统计的人数 = 等级人数 + 开启叠加分红等级人数
  206. // 判断是否开启叠加分红,开启叠加分红则增加对应的等级人数
  207. if ($level['is_accumulation'] == StatusEnum::ENABLED) {
  208. $accumulation_num += $level_num;
  209. }
  210. }
  211. // 对应的等级的出单奖励/加权分红计算
  212. foreach ($level_calculate as &$level) {
  213. $level_num = $level_count[$level['level']]['num'];// 统计的人数
  214. if ($level_num <= 0) {
  215. $extra_commonisson = 0;
  216. } else {
  217. if ($is_gooods_alone) {// 商品独立设置
  218. $level['is_percent_extra'] = $goods_setting['is_percent_extra'];
  219. $level['is_percent_prize'] = $goods_setting['is_percent_prize'];
  220. }
  221. if ($level['is_percent_extra'] == 0) {// 百分比
  222. $extra_commonisson = $level['extra_prize'] ? bcdiv($order_money * $level['extra_prize'] / $level_num, 100, 2) : 0;// 加权分红,单位:元
  223. $amounts = $order_money;
  224. } else {// 固定金额
  225. $extra_commonisson = $level['extra_prize'] ? bcdiv(($detail['num'] * $level['extra_prize']), $level_num, 2) : 0;// 加权分红,单位:元
  226. $amounts = ($detail['num'] * $level['extra_prize']);
  227. }
  228. // 出单奖励金额计算
  229. if ($level['level'] == $parent_level) {
  230. if ($level['is_percent_prize'] == 0) {// 百分比
  231. $total_commonisson += $level['prize'] ? bcdiv($order_money * $level['prize'], 100, 2) : 0;// 加权分红,单位:元
  232. } else {// 固定金额
  233. $total_commonisson += ($detail['num'] * $level['prize']);// 出单奖励,单位:元
  234. }
  235. }
  236. }
  237. $total_extra_commonisson = $level['is_accumulation'] == StatusEnum::ENABLED ? $extra_commonisson + $prev_commission : $extra_commonisson;
  238. // 单个商品的结算明细
  239. $settlement_data[$level['level']][] = [
  240. 'detail_id' => $detail['id'],
  241. 'goods_id' => $detail['goods_id'],
  242. 'goods_name' => $detail['goods_name'],
  243. 'amounts' => $amounts,
  244. 'prize' => 0,
  245. 'commonisson' => 0,
  246. 'is_accumulation' => $level['is_accumulation'],
  247. 'average_count' => $level_num,
  248. 'accumulation_prize' => $prev_commission,
  249. 'is_percent_extra' => $level['is_percent_extra'],
  250. 'extra_prize' => $level['extra_prize'],
  251. 'extra_commonisson' => $total_extra_commonisson,
  252. ];
  253. // 分红佣金计算
  254. $calculate[$level['level']] = [
  255. 'commission' => 0,
  256. 'extra_commission' => empty($calculate[$level['level']]['extra_commission']) ? $total_extra_commonisson : $calculate[$level['level']]['extra_commission'] + $total_extra_commonisson,
  257. 'settlement_data' => $settlement_data[$level['level']],
  258. ];
  259. $prev_commission += $extra_commonisson;// 低层级叠加的佣金
  260. }
  261. }
  262. // 结算的配置
  263. $settlement_config = [
  264. 'compute_type' => $config['compute_type'],// 佣金计算方式
  265. 'settlement_method' => $config['settlement_method'],// 结算方式
  266. ];
  267. // 分红计算
  268. foreach ($servebonus_list as $servebonus) {
  269. if (empty($calculate[$servebonus->level])) continue;
  270. // 判断用户是否符合额外分红条件
  271. if ($level[$servebonus->level]['extra_type'] == 1 && $servebonus->upgrade_status != 1) continue;
  272. if ($level[$servebonus->level]['extra_type'] == 2 && $servebonus->upgrade_status != 2) continue;
  273. // 不达标则跳过
  274. if (!in_array($servebonus->id, $unachievement_list)) {
  275. $extra_settlement_config = $settlement_config;
  276. $extra_commission = $calculate[$servebonus->level]['extra_commission'];
  277. // 判断是否设置额外分红上限并且用户是否达到额外分红上限
  278. if ($level_arr[$servebonus->level]['extra_is_limit'] == 1) {
  279. // 已超额则直接退出
  280. if ($servebonus->temp_extra_commission > $level_arr[$servebonus->level]['extra_limit_price']) continue;
  281. // 没超额,但是加上奖励金额则超额,额外分红 = 限制金额 - 已有额外金额;
  282. if ($servebonus->temp_extra_commission + $calculate[$servebonus->level]['extra_commission'] > $level_arr[$servebonus->level]['extra_limit_price']) {
  283. $extra_commission = $level_arr[$servebonus->level]['extra_limit_price'] - $servebonus->temp_extra_commission;
  284. $extra_settlement_config['extra_msg'] = '额外分红金额已达到上限,应得额外分红:¥' . $calculate[$servebonus->level]['extra_commission'] . ',实得额外分红:¥' . $extra_commission;
  285. }
  286. }
  287. // 额外分红
  288. $extra_commission > 0 && $rows[] = [
  289. 'mall_id' => $servebonus->mall_id,
  290. 'order_id' => $order['id'],
  291. 'order_no' => $order['order_no'],
  292. 'user_id' => $servebonus->user_id,
  293. 'type' => 2,
  294. 'level' => $servebonus->level,// 服务商等级
  295. 'amounts' => $calculate[$servebonus->level]['settlement_data'][0]['amounts'],
  296. 'commission' => $extra_commission,
  297. 'settlement_config' => Json::encode($extra_settlement_config),
  298. 'settlement_data' => Json::encode($calculate[$servebonus->level]['settlement_data']),
  299. 'date' => $date,
  300. 'created_at' => $time,
  301. 'updated_at' => $time,
  302. ];
  303. // 增加额外分红的临时额度
  304. $servebonus->temp_extra_commission += $calculate[$servebonus->level]['extra_commission'];
  305. $servebonus->save();
  306. }
  307. // 计算出单奖励金额
  308. if (!empty($user['parent_id']) && $user['parent_id'] == $servebonus->user_id) {
  309. $parent_level = $servebonus->level;
  310. $commonisson = $total_commonisson;// 出单奖励,单位:元
  311. }
  312. }
  313. // 保存数据
  314. if (!empty($rows)) {
  315. $trans = Yii::$app->db->beginTransaction();
  316. try {
  317. // 今日出单记录
  318. if (!empty($user['parent_id']) && !empty($commonisson)) {
  319. $achievement = ['mall_id' => $mallId, 'user_id' => $user['parent_id'], 'buy_uid' => $user_id, 'level' => $parent_level, 'order_id' => $order['id'], 'order_no' => $order['order_no'], 'prize' => $commonisson, 'date' => $date];
  320. $res = ServeBonusAchievement::setData($achievement);
  321. if ($res == false) throw new Exception(ServeBonusAchievement::getStaticError());
  322. }
  323. // 生成数据
  324. $field = ['mall_id','order_id','order_no','user_id','type','level','amounts','commission','settlement_config','settlement_data','date','created_at','updated_at'];
  325. $res = Yii::$app->db->createCommand()->batchInsert(ServeBonusRewardLog::tableName(), $field, $rows)->execute();
  326. if ($res == false) throw new Exception(ServeBonusRewardLog::getStaticError());
  327. $trans->commit();
  328. } catch (Exception $e) {
  329. $trans->rollBack();
  330. $this->setError($e->getMessage());
  331. return false;
  332. }
  333. }
  334. return true;
  335. } catch (Exception $e) {
  336. $exception = FormatHelper::exception($e, '订单触发服务商分红计算错误');
  337. echo $exception;
  338. $this->setError($exception);
  339. return false;
  340. }
  341. }
  342. public function executeByCloudStock($order){
  343. try{
  344. // 初始化数据
  345. $mallId = $order['mall_id'];
  346. $user_id = 0;
  347. $order_id = 0;
  348. $order_no = '';
  349. $calculate = [];// 佣金计算
  350. $amounts = 0;// 结算的总金额
  351. $date = date('Ymd', time());
  352. $time = time();
  353. // 获取基础配置
  354. $config = Yii::$app->services->setting->addons->get($mallId, 'ServeBonus', 'basic');
  355. // 判断是否开启插件分润
  356. if ($config['is_enable'] == StatusEnum::DISABLED) return true;
  357. //新增:云库存商品判断
  358. if(empty($config['is_cloud_stock_open'])) return false;
  359. $order_detail = [];
  360. $from_order = [];
  361. //升级礼包
  362. if($order['changes_type'] == CloudStockEnum::CHANGE_TYPE_INCREASE_UPGRADE_BAG_GIVE){
  363. // 查询订单信息
  364. $configs = \Yii::$app->services->setting->addons->get($mallId, \common\enums\AddonsEnum::ADDONS_NAME_CLOUD_STOCK, 'basic');
  365. $level_up_give_stock_by_parent_type = $configs['level_up_give_stock_by_parent_type'] ?? 0;
  366. if($level_up_give_stock_by_parent_type == 1){
  367. $cloud_stock_fill_order_relation = \addons\CloudStock\common\models\CloudStockFillOrderRelation::findOne(['fill_order_id'=>$order['order_id']]);
  368. if(empty($cloud_stock_fill_order_relation)) return true;
  369. $order['order_id'] = $cloud_stock_fill_order_relation['order_id'];
  370. }
  371. $where['where'] = [['=', 'order_id', $order['order_id']], ['=', 'status', StatusEnum::ENABLED]];
  372. $order_detail = OrderDetail::lists($where, true);
  373. if (empty($order_detail)) return true;
  374. // $goods = Goods::findOne($order['goods_id']);
  375. // $order_detail[] = [
  376. // 'goods_price' => $goods['price'] * $order['num'],
  377. // 'goods_id' => $order['goods_id'],
  378. // 'num' => $order['num'],
  379. // 'cost_price' => $goods['cost_price'],
  380. // 'adjust_money' => 0,
  381. // 'price' => $goods['price'],
  382. // ];
  383. $user_id = $order_detail[0]['user_id'];
  384. $from_order = Order::findOne($order['order_id']);
  385. if(empty($from_order)) return true;
  386. }elseif($order['order_type'] == CloudStockEnum::STOCK_ORDER_TYPE_USER){
  387. $buying_order = CloudStockBuyingOrder::findOne($order['order_id']);
  388. // 查询订单信息
  389. $where['where'] = [['=', 'id', $buying_order['order_detail_id']]];
  390. $order_detail = OrderDetail::lists($where, true);
  391. if (empty($order_detail)) return true;
  392. $user_id = $buying_order['user_id'];
  393. $from_order = Order::findOne($buying_order['order_id']);
  394. if(empty($from_order)) return true;
  395. }elseif($order['order_type'] == CloudStockEnum::STOCK_ORDER_TYPE_REPLENISH){
  396. $fill_order = CloudStockFillOrder::findOne($order['order_id']);
  397. if (empty($fill_order)) return true;
  398. $goods = Goods::findOne($fill_order['goods_id']);
  399. $order_detail[] = [
  400. 'goods_price' => $fill_order['pay_money'],
  401. 'goods_id' => $fill_order['goods_id'],
  402. 'num' => $fill_order['num'],
  403. 'cost_price' => $goods['cost_price'],
  404. 'adjust_money' => 0,
  405. 'price' => $goods['price'],
  406. ];
  407. $user_id = $fill_order['user_id'];
  408. $from_order = $fill_order;
  409. if(empty($from_order)) return true;
  410. }else{
  411. return true;
  412. }
  413. //不是升级礼包商品 根据扣除平台数量计算
  414. if($order['changes_type'] != CloudStockEnum::CHANGE_TYPE_INCREASE_UPGRADE_BAG_GIVE){
  415. foreach($order_detail as &$detail){
  416. $detail['num'] = $order['num'];
  417. }
  418. }
  419. // 获取用户信息
  420. $user = User::find()->select("parent_id")->where(['id' => $user_id, 'status' => StatusEnum::ENABLED])->asArray()->one();
  421. $parent_level = ServeBonus::find()->select("level")->where(['mall_id' => $mallId,'user_id' => $user['parent_id'], 'status' => StatusEnum::ENABLED])->asArray()->scalar();
  422. // 获取服务商等级列表
  423. $field = 'level,prize,is_percent_prize,extra_prize,is_percent_extra,is_extra,extra_type,extra_is_limit,extra_limit_price,is_accumulation,is_cloud_stock_open,cloud_stock_achievement_percent,cloud_stock_achievement_prize,accumulation_condition,accumulation_condition_money';
  424. $level_arr = ServeBonusLevelSetting::find()->select($field)->where(['mall_id' => $mallId, 'status' => StatusEnum::ENABLED])->orderBy('level asc')->asArray()->all();
  425. if (empty($level_arr)) return true;
  426. $level_arr = array_column($level_arr, null, 'level');
  427. // 获取所有服务商列表
  428. $servebonus_list = ServeBonus::find()->where(['mall_id' => $mallId, 'status' => StatusEnum::ENABLED])->all();
  429. if (empty($servebonus_list)) return true;
  430. //排除已经达到佣金上限的服务商
  431. $level_list = [];
  432. $diff_num = [];
  433. foreach ($servebonus_list as $lv => $slb) {
  434. $level = null;
  435. if (!isset($level_list[$slb->level])) {
  436. $level = ServeBonusLevel::find()->where(['mall_id' => $mallId, 'status' => StatusEnum::ENABLED, 'level' => $slb->level])->one();
  437. if ($level) {
  438. $level_list[$slb->level] = $level;
  439. } else {
  440. $level_list[$slb->level] = null;
  441. }
  442. } else {
  443. $level = $level_list[$slb->level];
  444. }
  445. if (!$level) unset($servebonus_list[$lv]);
  446. //计算金额
  447. if ($level->is_to_bonus && $level->to_bonus_price > 0) {
  448. CapitalLog::$capitalType = 'commission';
  449. $total_settled = CapitalLog::find()->where(['user_id' => $slb->user_id, 'change_type' => 'add'])->sum('change_num') ?? 0;
  450. CapitalLog::$capitalType = 'commission_frozen';
  451. $total_nosettled = CapitalLog::find()->where(['user_id' => $slb->user_id, 'change_type' => 'add'])->sum('change_num') ?? 0;
  452. $total = bcadd($total_nosettled + $total_settled, 2);
  453. if ($total >= $level->to_bonus_price) {
  454. unset($servebonus_list[$lv]);
  455. $diff_num[$slb->level] += 1;
  456. }
  457. }
  458. }
  459. // 统计各个服务商等级的总人数
  460. $level_count = ServeBonus::find()
  461. ->select("count(id) num,level")
  462. ->where(['mall_id' => $mallId, 'status' => StatusEnum::ENABLED])
  463. ->groupBy("level")
  464. ->indexBy("level")
  465. ->orderBy("level asc")
  466. ->asArray()
  467. ->all();
  468. //减去相应的人头
  469. if ($level_count) {
  470. foreach ($level_count as &$lv_item) {
  471. if (isset($diff_num[$lv_item['level']])) {
  472. $lv_item['num'] = $lv_item['num'] - $diff_num[$lv_item['level']];
  473. if ($lv_item['num'] < 0) $lv_item['num'] = 0;
  474. }
  475. }
  476. }
  477. $temp_level_count = $level_count;
  478. $settlement_data = [];
  479. $total_commonisson = 0;// 出单奖励总奖励金额初始化
  480. // 循环订单详情,对不同商品进行对应的佣金结算
  481. foreach ($order_detail as $index => $detail) {
  482. $accumulation_num = $prev_commission = 0;// 叠加数量,叠加奖励;
  483. // 查询服务商商品
  484. $goods_setting = ServeBonusCommissionItemSetting::getOne([['mall_id' => $mallId,'item_id' => $detail['goods_id'], 'is_enable' => StatusEnum::ENABLED]], true, ['detail']);
  485. if (empty($goods_setting)) continue;
  486. //新增:云库存商品判断
  487. //if(empty($config['is_cloud_stock_open'])) continue;
  488. // $cloud_stock_goods = CloudStockGoods::findOne(['mall_id'=>$mallId,'goods_id'=>$detail['goods_id'],'status' => StatusEnum::ENABLED]);
  489. // $upgrade_bag_list = CloudStockUpgradeBag::findOne(['mall_id'=>$mallId,'goods_id'=>$detail['goods_id'],'status' => StatusEnum::ENABLED]);
  490. // if(empty($cloud_stock_goods) && empty($upgrade_bag_list)) continue;
  491. // 获取结算的金额
  492. if ($config['compute_type'] == 0) $order_money = $detail['goods_price'] / $order['total_num'] * $order['num'];// 支付金额
  493. if ($config['compute_type'] == 1) $order_money = $detail['goods_price'] - ($detail['cost_price'] * $detail['num']) + $detail['adjust_money'];// 商品利润
  494. if ($config['compute_type'] == 2) $order_money = $detail['price'] * $detail['num'];// 商品售价
  495. if ($order_money <= 0) continue;// 分红金额过小则没必要分红
  496. //添加订单记录
  497. $order_detail_id = !empty($detail['id']) ? $detail['id'] : 0;
  498. $order_log = ServeBonusOrderLog::findOne(['order_no'=>$from_order['order_no'],'order_detail_id'=>$order_detail_id]);
  499. if(empty($order_log)){
  500. $order_log_params = [
  501. 'mall_id'=> $mallId,
  502. 'order_id' => $from_order['id'],
  503. 'order_detail_id' => $order_detail_id,
  504. 'order_no' => $from_order['order_no'],
  505. 'order_type' => $order['order_type'],
  506. 'money' => $order_money,
  507. 'date' => $date,
  508. 'goods_id' => $detail['goods_id'],
  509. 'num' => $detail['num'],
  510. ];
  511. $res = ServeBonusOrderLog::setData($order_log_params);
  512. if ($res == false) throw new Exception(ServeBonusOrderLog::getStaticError());
  513. }
  514. $amounts = $amounts + $order_money;
  515. // 判断是否开启独立设置
  516. $is_gooods_alone = false;
  517. if (!empty($goods_setting['is_alone']) && $goods_setting['is_alone'] == 1) {
  518. // 商品独立分佣配置
  519. $level_calculate = $goods_setting['detail'];
  520. $is_gooods_alone = true;
  521. } else {
  522. // 等级分佣配置
  523. $level_calculate = $level_arr;
  524. }
  525. // 将等级设计倒叙,最高等级为排第一,计算各个等级开启叠加分红后的数量
  526. $level_count = $temp_level_count;
  527. $desc_level_calculate = ArrayHelper::arraySort($level_calculate, 'level', 'desc');
  528. foreach ($desc_level_calculate as $level) {
  529. $level_num = $level_count[$level['level']]['num'];// 该等级的人数
  530. $level_count[$level['level']]['num'] += $accumulation_num;// 统计的人数 = 等级人数 + 开启叠加分红等级人数
  531. // 判断是否开启叠加分红,开启叠加分红则增加对应的等级人数
  532. if ($level['is_accumulation'] == StatusEnum::ENABLED) {
  533. $accumulation_num += $level_num;
  534. }
  535. }
  536. // 对应的等级的出单奖励/加权分红计算
  537. foreach ($level_calculate as &$level) {
  538. $level_num = $level_count[$level['level']]['num'];// 统计的人数
  539. if ($level_num <= 0) {
  540. $extra_commonisson = 0;
  541. } else {
  542. if ($is_gooods_alone) {// 商品独立设置
  543. $level['is_percent_extra'] = $goods_setting['is_percent_extra'];
  544. $level['is_percent_prize'] = $goods_setting['is_percent_prize'];
  545. }
  546. if ($level['is_percent_extra'] == 0) {// 百分比
  547. $extra_commonisson = $level['extra_prize'] ? bcdiv($order_money * $level['extra_prize'] / $level_num, 100, 2) : 0;// 加权分红,单位:元
  548. $amounts = $order_money;
  549. } else {// 固定金额
  550. $extra_commonisson = $level['extra_prize'] ? bcdiv(($detail['num'] * $level['extra_prize']), $level_num, 2) : 0;// 加权分红,单位:元
  551. $amounts = ($detail['num'] * $level['extra_prize']);
  552. }
  553. // 出单奖励金额计算
  554. if ($level['level'] == $parent_level) {
  555. if ($level['is_percent_prize'] == 0) {// 百分比
  556. $total_commonisson += $level['prize'] ? bcdiv($order_money * $level['prize'], 100, 2) : 0;// 加权分红,单位:元
  557. } else {// 固定金额
  558. $total_commonisson += ($detail['num'] * $level['prize']);// 出单奖励,单位:元
  559. }
  560. }
  561. }
  562. $total_extra_commonisson = $level['is_accumulation'] == StatusEnum::ENABLED ? $extra_commonisson + $prev_commission : $extra_commonisson;
  563. // 单个商品的结算明细
  564. $settlement_data[$level['level']][] = [
  565. 'detail_id' => $detail['id'],
  566. 'goods_id' => $detail['goods_id'],
  567. 'goods_name' => $detail['goods_name'],
  568. 'amounts' => $amounts,
  569. 'prize' => 0,
  570. 'commonisson' => 0,
  571. 'is_accumulation' => $level['is_accumulation'],
  572. 'average_count' => $level_num,
  573. 'accumulation_prize' => $prev_commission,
  574. 'is_percent_extra' => $level['is_percent_extra'],
  575. 'extra_prize' => $level['extra_prize'],
  576. 'extra_commonisson' => $total_extra_commonisson,
  577. ];
  578. // 分红佣金计算
  579. $calculate[$level['level']] = [
  580. 'commission' => 0,
  581. 'extra_commission' => empty($calculate[$level['level']]['extra_commission']) ? $total_extra_commonisson : $calculate[$level['level']]['extra_commission'] + $total_extra_commonisson,
  582. 'settlement_data' => $settlement_data[$level['level']],
  583. ];
  584. $prev_commission += $extra_commonisson;// 低层级叠加的佣金
  585. }
  586. }
  587. // 结算的配置
  588. $settlement_config = [
  589. 'compute_type' => $config['compute_type'],// 佣金计算方式
  590. 'settlement_method' => $config['settlement_method'],// 结算方式
  591. ];
  592. // 分红计算
  593. foreach ($servebonus_list as $servebonus) {
  594. if (empty($calculate[$servebonus->level])) continue;
  595. // 判断用户是否符合额外分红条件
  596. if ($level[$servebonus->level]['extra_type'] == 1 && $servebonus->upgrade_status != 1) continue;
  597. if ($level[$servebonus->level]['extra_type'] == 2 && $servebonus->upgrade_status != 2) continue;
  598. $extra_settlement_config = $settlement_config;
  599. $extra_commission = $calculate[$servebonus->level]['extra_commission'];
  600. // 判断是否设置额外分红上限并且用户是否达到额外分红上限
  601. if ($level_arr[$servebonus->level]['extra_is_limit'] == 1) {
  602. // 已超额则直接退出
  603. if ($servebonus->temp_extra_commission > $level_arr[$servebonus->level]['extra_limit_price']) continue;
  604. // 没超额,但是加上奖励金额则超额,额外分红 = 限制金额 - 已有额外金额;
  605. if ($servebonus->temp_extra_commission + $calculate[$servebonus->level]['extra_commission'] > $level_arr[$servebonus->level]['extra_limit_price']) {
  606. $extra_commission = $level_arr[$servebonus->level]['extra_limit_price'] - $servebonus->temp_extra_commission;
  607. $extra_settlement_config['extra_msg'] = '额外分红金额已达到上限,应得额外分红:¥' . $calculate[$servebonus->level]['extra_commission'] . ',实得额外分红:¥' . $extra_commission;
  608. }
  609. }
  610. // 额外分红
  611. $rows[] = [
  612. 'mall_id' => $servebonus->mall_id,
  613. 'order_id' => $from_order['id'],
  614. 'order_no' => $from_order['order_no'],
  615. 'user_id' => $servebonus->user_id,
  616. 'type' => 2,
  617. 'level' => $servebonus->level,// 服务商等级
  618. 'amounts' => $calculate[$servebonus->level]['settlement_data'][0]['amounts'],
  619. 'commission' => $extra_commission,
  620. 'settlement_config' => Json::encode($extra_settlement_config),
  621. 'settlement_data' => Json::encode($calculate[$servebonus->level]['settlement_data']),
  622. 'date' => $date,
  623. 'created_at' => $time,
  624. 'updated_at' => $time,
  625. 'is_cloud_stock' => 1,
  626. ];
  627. // 增加额外分红的临时额度
  628. $servebonus->temp_extra_commission += $calculate[$servebonus->level]['extra_commission'];
  629. $servebonus->save();
  630. // 计算出单奖励金额
  631. if (!empty($user['parent_id']) && $user['parent_id'] == $servebonus->user_id) {
  632. $parent_level = $servebonus->level;
  633. $commonisson = $total_commonisson;// 出单奖励,单位:元
  634. }
  635. }
  636. // 保存数据
  637. if (!empty($rows)) {
  638. $trans = Yii::$app->db->beginTransaction();
  639. try {
  640. // 今日出单记录
  641. if (!empty($user['parent_id']) && !empty($commonisson)) {
  642. //该笔订单是否已出单
  643. $is_add = ServeBonusAchievement::findOne(['user_id' => $user['parent_id'], 'buy_uid' => $user_id,'order_id' => $from_order['id'], 'order_no' => $from_order['order_no']]);
  644. if(empty($is_add)){
  645. $achievement = ['mall_id' => $mallId, 'user_id' => $user['parent_id'], 'buy_uid' => $user_id, 'level' => $parent_level, 'order_id' => $from_order['id'], 'order_no' => $from_order['order_no'], 'prize' => $commonisson, 'date' => $date];
  646. $res = ServeBonusAchievement::setData($achievement);
  647. if ($res == false) throw new Exception(ServeBonusAchievement::getStaticError());
  648. }
  649. }
  650. // 生成数据
  651. $field = ['mall_id','order_id','order_no','user_id','type','level','amounts','commission','settlement_config','settlement_data','date','created_at','updated_at','is_cloud_stock'];
  652. $res = Yii::$app->db->createCommand()->batchInsert(ServeBonusRewardLog::tableName(), $field, $rows)->execute();
  653. if ($res == false) throw new Exception(ServeBonusRewardLog::getStaticError());
  654. $trans->commit();
  655. } catch (Exception $e) {
  656. $trans->rollBack();
  657. $this->setError($e->getMessage());
  658. return false;
  659. }
  660. }
  661. if(!empty($order['settle_log_id'])){
  662. $log = ServeBonusAchievementSettleLog::findOne($order['settle_log_id']);
  663. if($log){
  664. $log->not_yet_num = bcsub($log->not_yet_num,$order['num']);
  665. $log->save();
  666. }
  667. }
  668. $serveBonus = ServeBonus::findOne(['user_id'=>$user_id,'status'=>StatusEnum::ENABLED]);
  669. if(empty($serveBonus)) return true;
  670. if(in_array($order['changes_type'],[CloudStockEnum::CHANGE_TYPE_INCREASE_FILL,CloudStockEnum::CHANGE_TYPE_INCREASE_UPGRADE_BAG_GIVE])){
  671. // 获取结算周期,0=天,1=周,2=月
  672. $compute_period = $config['compute_period'];
  673. switch ($compute_period) {
  674. case 1:
  675. $start_day = date("Ymd", time());
  676. $end_day = $start_day;
  677. break;
  678. case 2:
  679. $start_day = date('Ymd', (time() - ((date('w') == 0 ? 7 : date('w')) - 1) * 24 * 3600));
  680. $end_day = date('Ymd', (time() + (7 - (date('w') == 0 ? 7 : date('w'))) * 24 * 3600));
  681. break;
  682. case 3:
  683. $start_day = date("Ym01", time());
  684. $end_day = date('Ymd', strtotime(date('Y-m-01', time()). ' 1 month -1 day'));
  685. break;
  686. }
  687. //当前期数是否已有记录
  688. $period_log = ServeBonusCloudStockPeriod::findOne(['user_id'=>$user_id,'compute_period'=>$compute_period,'start_time' => $start_day,'end_time' => $end_day]);
  689. if(empty($period_log)){
  690. $period_log = new ServeBonusCloudStockPeriod();
  691. $period_log->user_id = $user_id;
  692. $period_log->mall_id = $mallId;
  693. $period_log->period_num = ServeBonusCloudStockPeriod::getPrevPeriodNum($mallId,$user_id);
  694. $period_log->compute_period = $compute_period;
  695. $period_log->start_time = $start_day;
  696. $period_log->end_time = $end_day;
  697. }
  698. //个人补货业绩
  699. $amounts = 0;
  700. if($order['changes_type'] == CloudStockEnum::CHANGE_TYPE_INCREASE_UPGRADE_BAG_GIVE){
  701. // $cloud_stock_goods = CloudStockGoods::findOne(['mall_id'=>$mallId,'goods_id'=>$order['goods_id'],'status' => StatusEnum::ENABLED]);
  702. // if(!empty($cloud_stock_goods)){
  703. // $agent = CloudStockAgent::findOne(['mall_id' => $mallId, 'user_id' => $user_id, 'status' => StatusEnum::ENABLED]);
  704. // $agent_price_arr = json_decode($cloud_stock_goods['agent_price'],true);
  705. // $price_arr = array_column($agent_price_arr,'price','level');
  706. // $amounts = $price_arr[$agent->level]? $price_arr[$agent->level] * $order['num'] : 0;
  707. // }
  708. $amounts = $from_order['pay_money'];
  709. }else{
  710. $amounts = $from_order['pay_money'] / $order['total_num'] * $order['num'];
  711. }
  712. if(empty($amounts)) return true;
  713. //等级补货业绩 实时计算
  714. $amounts_num = 0;
  715. //等级分红金额 实时计算
  716. //$total_amounts_num = 0;
  717. //分红结算金额
  718. //$commission = 0;
  719. $period_log->amounts += $amounts;
  720. //$period_log->amounts_num = $amounts_num;
  721. //$period_log->total_amounts_num = $total_amounts_num;
  722. //$period_log->commission = $commission;
  723. if(!$period_log->save()) throw new Exception(ServeBonusCloudStockPeriod::getStaticError());
  724. }
  725. return true;
  726. }catch(\Exception $e){
  727. $exception = FormatHelper::exception($e, '云库存订单触发服务商分红计算错误');
  728. echo $exception;
  729. $this->setError($exception);
  730. return false;
  731. }
  732. }
  733. }