DeductionLogic.php 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. <?php
  2. namespace addons\CloudStockTwo\common\logic\deduction;
  3. use addons\CloudStockTwo\common\enums\CloudStockTwoEnum;
  4. use addons\CloudStockTwo\common\events\order\FillEvent;
  5. use addons\CloudStockTwo\common\logic\reward\EqualReward;
  6. use addons\CloudStockTwo\common\logic\reward\OverReward;
  7. use addons\CloudStockTwo\common\models\CloudStockTwoAgent;
  8. use addons\CloudStockTwo\common\models\CloudStockTwoAgentGoods;
  9. use addons\CloudStockTwo\common\models\CloudStockTwoDeductionDetail;
  10. use addons\CloudStockTwo\common\models\CloudStockTwoFillOrder;
  11. use addons\CloudStockTwo\common\models\CloudStockGoods;
  12. use addons\CloudStockTwo\common\models\CloudStockTwoGoods;
  13. use addons\CloudStockTwo\common\models\CloudStockTwoLevel;
  14. use addons\CloudStockTwo\common\sms\SmsConfig;
  15. use addons\CloudStockTwo\common\sms\TimeLimitFillMessage;
  16. use common\enums\AddonsEnum;
  17. use common\enums\OrderStatusEnum;
  18. use common\enums\StatusEnum;
  19. use common\enums\UserWalletEnum;
  20. use common\helpers\BcHelper;
  21. use common\helpers\sms\Sms;
  22. use common\models\goods\Goods;
  23. use common\models\mall\MallAddons;
  24. use common\models\order\Order;
  25. use common\models\order\OrderDetail;
  26. use common\models\user\User;
  27. use Overtrue\EasySms\EasySms;
  28. use Overtrue\EasySms\Exceptions\NoGatewayAvailableException;
  29. use yii\db\Exception;
  30. use addons\CloudStockTwo\common\events\order\SalesCompanyEvent;
  31. use addons\SalesCompany\common\models\SalesCompanyAgent;
  32. abstract class DeductionLogic
  33. {
  34. public $order_type;//会员订单还是补货订单
  35. protected $user_id; //买货会员用户id,补货用户id
  36. protected $goods_id; //商品id
  37. protected $parent_agent; //上级代理商对象 类型:StockAgent
  38. protected $mall_id; //商城id
  39. protected $not_yet_num;//剩余未扣库存数量;
  40. protected $stock_log_id;//库存变动记录表id
  41. protected $unit_goods_price; //货款单价
  42. protected $stock_goods;//库存商品
  43. protected $order;//订单模型model
  44. protected $changes_desc;//资金变动描述
  45. protected $changes_type;//资金变动类型
  46. protected $bonus_over_changes_type; //平级奖资金变动类型
  47. protected $bonus_over_changes_desc; //平级奖资金变动描述
  48. protected $bonus_equal_changes_type; //越级奖资金变动类型
  49. protected $bonus_equal_changes_desc; //越级奖资金变动描述
  50. protected $is_frozen = 0; //收益是否结算;
  51. protected $is_time_limit_fill; //是否开启限时补货
  52. protected $fill_hour = 0; //限时补货小时数
  53. protected $time_limit_fill_user_ids = []; //执行过限时补货的代理商用户id,防止重复
  54. protected $is_job;
  55. protected $user;
  56. protected $stock_log;
  57. protected $reward_list;//奖励数组
  58. protected $parent_agent_list;//上级代理数组
  59. protected $team_desc;//团队奖变动描述
  60. protected $diff_desc;//极差奖变动描述
  61. protected $wait_deduct_equal_money;
  62. public function __construct($user, $user_parent_agent, $stock_log, $order, $not_yet_num,$reward_list, $parent_agent_list,$wait_deduct_equal_money,$order_type,$time_limit_fill_user_ids = [], $is_job = 0)
  63. {
  64. $this->user_id = $user->id;
  65. $this->parent_agent = $user_parent_agent;
  66. $this->order = $order;
  67. $this->goods_id = $order['goods_id'];
  68. $this->not_yet_num = $not_yet_num;
  69. $this->mall_id = $order['mall_id'];
  70. $this->stock_log_id = $stock_log['id'];
  71. $this->stock_log = $stock_log;
  72. $this->time_limit_fill_user_ids = $time_limit_fill_user_ids;
  73. $this->is_job = $is_job;
  74. $this->user = $user;
  75. $this->reward_list = $reward_list;
  76. $this->parent_agent_list = $parent_agent_list;
  77. $this->order_type = $order_type;
  78. $this->wait_deduct_equal_money = $wait_deduct_equal_money;
  79. //库存商品模型对象
  80. $this->getStockGoods();
  81. //定义资金变动类型和描述
  82. $this->getChangesType();
  83. //获取限时补货配置
  84. $this->getIsTimeLimitFill();
  85. //获取会员买货扣分润后货款商品单价
  86. $this->getUnitGoodsPrice();
  87. }
  88. /**
  89. * 获取商品货款单价
  90. * @return mixed
  91. */
  92. protected abstract function getUnitGoodsPrice();
  93. /**
  94. * 获取库存商品
  95. */
  96. protected function getStockGoods()
  97. {
  98. //库存商品奖励配置
  99. $this->stock_goods = CloudStockTwoGoods::findOne(['goods_id' => $this->goods_id, 'mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED]);
  100. }
  101. /**
  102. * 定义资金变动类型和描述
  103. */
  104. protected function getChangesType()
  105. {
  106. if ($this->order_type == 'buying') {
  107. $this->changes_type = CloudStockTwoEnum::STOCK_CHANGE_TYPE102;
  108. $this->changes_desc = "会员买货货款收益";
  109. $this->bonus_over_changes_type = CloudStockTwoEnum::CHANGE_TYPE_INCREASE_GOODS_BUY_OVER_BONUS;
  110. $this->bonus_over_changes_desc = "会员买货越级奖发放";
  111. $this->bonus_equal_changes_type = CloudStockTwoEnum::CHANGE_TYPE_INCREASE_GOODS_BUY_EQUAL_BONUS;
  112. $this->bonus_equal_changes_desc = "会员买货平级奖发放";
  113. $this->team_desc = "会员买货团队奖发放";
  114. $this->diff_desc = "会员买货极差奖发放";
  115. } elseif ($this->order_type == 'fill') {
  116. $this->changes_type = CloudStockTwoEnum::CHANGE_TYPE_INCREASE_FILL_PAYMENT;
  117. $this->changes_desc = "下级补货货款收益";
  118. $this->bonus_over_changes_type = CloudStockTwoEnum::CHANGE_TYPE_INCREASE_FILL_OVER_BONUS;
  119. $this->bonus_over_changes_desc = "下级补货越级奖发放";
  120. $this->bonus_equal_changes_type = CloudStockTwoEnum::CHANGE_TYPE_INCREASE_FILL_EQUAL_BONUS;
  121. $this->bonus_equal_changes_desc = "下级补货平级奖发放";
  122. $this->team_desc = "下级补货团队奖发放";
  123. $this->diff_desc = "下级补货极差奖发放";
  124. }
  125. }
  126. /**
  127. * 获取限时补货配置
  128. * @return int|mixed
  129. */
  130. protected function getIsTimeLimitFill()
  131. {
  132. $configs = \Yii::$app->services->setting->addons->get($this->mall_id, AddonsEnum::ADDONS_NAME_CLOUD_STOCK_TWO, 'basic');
  133. $this->is_time_limit_fill = isset($configs['is_time_limit_fill']) ? $configs['is_time_limit_fill'] : 0;
  134. $this->fill_hour = isset($configs['fill_hour']) ? $configs['fill_hour'] : 0;
  135. }
  136. ///平一级
  137. public function equalOne($agent, $direct_agent, $stock_level, $over_desc, $equal_desc, $num)
  138. {
  139. switch (true) {
  140. case $agent['level'] > $direct_agent['level']:
  141. //越级奖
  142. $this->sendOverReward($direct_agent, $stock_level, 1, $over_desc, $num);
  143. break;
  144. case $agent['level'] == $direct_agent['level']:
  145. //平级奖
  146. $this->sendEqualReward($direct_agent, $stock_level, 1, $equal_desc, $num);
  147. break;
  148. default:
  149. }
  150. }
  151. //发放平级奖励
  152. public function sendEqualReward($parent_user_agent, $stock_level, $equal_level, $equal_desc, $num)
  153. {
  154. //该代理商等级是否开启平级奖
  155. if (empty($stock_level['is_equal'])) return $this->unit_goods_price;
  156. $obj = new EqualReward(
  157. $parent_user_agent,
  158. $this->stock_goods,
  159. $this->unit_goods_price,
  160. $this->order['id'],
  161. $num,
  162. $this->is_frozen,
  163. $this->bonus_equal_changes_type,
  164. $equal_desc,
  165. $this->is_job
  166. );
  167. $obj->equal_level = $equal_level;
  168. $count_bonus_money = $obj->sendReward();
  169. $this->unit_goods_price = 0;
  170. if ($count_bonus_money > 0) $this->unit_goods_price = BcHelper::floorFloat($count_bonus_money / $num);
  171. }
  172. //发放越级奖励
  173. public function sendOverReward($parent_user_agent, $stock_level, $over_level, $over_desc, $num)
  174. {
  175. if (empty($stock_level['is_over'])) return $this->unit_goods_price;
  176. $obj = new OverReward(
  177. $parent_user_agent,
  178. $this->stock_goods,
  179. $this->unit_goods_price,
  180. $this->order['id'],
  181. $num,
  182. $this->is_frozen,
  183. $this->order,
  184. $over_desc,
  185. $this->is_job
  186. );
  187. $obj->over_level = $over_level;
  188. $count_bonus_money = $obj->sendReward();
  189. $this->unit_goods_price = 0;
  190. if ($count_bonus_money > 0) $this->unit_goods_price = BcHelper::floorFloat($count_bonus_money / $this->order['num']);
  191. }
  192. public function deduct()
  193. {
  194. //销售公司成员
  195. $sales_company_arr = [];
  196. if(MallAddons::isInstall($this->mall_id,AddonsEnum::ADDONS_NAME_SALES_COMPANY)){
  197. $salesCompanyAgent = SalesCompanyAgent::lists(['where' => [['mall_id' => $this->mall_id] ,['status'=>StatusEnum::ENABLED]], 'index' => 'user_id'], true);
  198. if($salesCompanyAgent){
  199. $sales_company_arr = $salesCompanyAgent;
  200. }
  201. }
  202. //没有上级代理商,直接扣平台的;
  203. if (empty($this->parent_agent)) {
  204. $params = [
  205. 'stock_log_id' => $this->stock_log_id,
  206. 'user_id' => 0,
  207. 'num' => $this->not_yet_num,
  208. 'not_yet_num' => 0,
  209. 'changes_type' => $this->stock_log['changes_type'],
  210. 'order_type' => $this->stock_log['order_type'],
  211. 'order_id' => $this->stock_log['order_id'],
  212. 'goods_id' => $this->goods_id,
  213. 'mall_id' => $this->mall_id,
  214. 'is_sales' => 0,
  215. ];
  216. //会员补货
  217. $company_user_id = 0;
  218. if(isset($sales_company_arr[$this->user_id]) && $this->order_type == 'fill'){
  219. $params['is_sales'] = 1;
  220. $params['company_id'] = $sales_company_arr[$this->user_id]['company_id'];
  221. $company_user_id = $this->user_id;
  222. }
  223. //下单用户为最高等级,上级代理有绑定销售公司
  224. $agent = CloudStockTwoAgent::findOne(['user_id'=>$this->user_id,'status'=>StatusEnum::ENABLED]);
  225. $user_level = $agent ? $agent->level : 0;
  226. $user_arr = [];
  227. if(!empty($this->parent_agent_list)){
  228. foreach($this->parent_agent_list as $parent_agent){
  229. if($parent_agent['level'] >= $user_level){
  230. $user_arr[] = $parent_agent->user_id;
  231. }
  232. }
  233. }
  234. if(!empty($user_arr) && !$params['is_sales']){
  235. foreach($user_arr as $user_id){
  236. if(isset($sales_company_arr[$user_id])){
  237. $params['is_sales'] = 1;
  238. $params['company_id'] = $sales_company_arr[$user_id]['company_id'];
  239. $company_user_id = $user_id;
  240. break;
  241. }
  242. }
  243. }
  244. $res = CloudStockTwoDeductionDetail::setData($params);
  245. if ($res == false) throw new \Exception(CloudStockTwoDeductionDetail::getStaticError());
  246. $is_install = MallAddons::isInstall($this->mall_id, AddonsEnum::ADDONS_NAME_ACHIEVEMENT);
  247. if ($is_install) $this->triggerAchievement($params);
  248. if(!empty($this->parent_agent_list) && $this->user_id != $company_user_id){
  249. foreach($this->parent_agent_list as $key => $agent){
  250. if(isset($this->reward_list[$agent['user_id']][UserWalletEnum::DIFF])){
  251. $this->reward_list[$agent['user_id']][UserWalletEnum::DIFF]['num'] = $this->not_yet_num;
  252. }
  253. if(isset($this->reward_list[$agent['user_id']][UserWalletEnum::EQUAL])){
  254. $this->reward_list[$agent['user_id']][UserWalletEnum::EQUAL]['num'] = $this->not_yet_num;
  255. }
  256. if(isset($this->reward_list[$agent['user_id']][UserWalletEnum::OVER])){
  257. $this->reward_list[$agent['user_id']][UserWalletEnum::OVER]['num'] = $this->not_yet_num;
  258. }
  259. }
  260. $this->rewardTeamPrice(UserWalletEnum::DIFF);
  261. $this->rewardTeamPrice(UserWalletEnum::OVER);
  262. $this->rewardTeamPrice(UserWalletEnum::EQUAL);
  263. }
  264. if($params['is_sales']==1){
  265. $this->salesCompany($company_user_id);
  266. }
  267. $this->not_yet_num = 0;
  268. $this->wait_deduct_equal_money = 0;
  269. return true;
  270. }
  271. $parent_agent_goods = CloudStockTwoAgentGoods::findOne(['mall_id' => $this->mall_id, 'user_id' => $this->parent_agent->user_id, 'goods_id' => $this->goods_id, 'status' => StatusEnum::ENABLED]);
  272. //代理商没有库存商品或者商品库存为0,递归找有库存的上级供应商扣减;
  273. if (empty($parent_agent_goods) || $parent_agent_goods->num == 0){
  274. if(empty($this->is_time_limit_fill) || (!empty($this->is_time_limit_fill) && in_array($this->parent_agent->user_id, $this->time_limit_fill_user_ids))){
  275. //当前会员无货 拿极差奖
  276. //获取最高代理商等级,当代理商等级为最高且没有库存时,直接扣平台库存(销售公司)
  277. $level_arr = array_column($this->parent_agent_list,'level');
  278. $max_level = max($level_arr);
  279. // $max_level = CloudStockTwoLevel::getMaxLevel($this->mall_id,$this->user_id);
  280. if(MallAddons::isInstall($this->mall_id,AddonsEnum::ADDONS_NAME_SALES_COMPANY) && $this->parent_agent->level == $max_level){
  281. $params = [
  282. 'stock_log_id' => $this->stock_log_id,
  283. 'user_id' => 0,
  284. 'num' => $this->not_yet_num,
  285. 'not_yet_num' => 0,
  286. 'changes_type' => $this->stock_log['changes_type'],
  287. 'order_type' => $this->stock_log['order_type'],
  288. 'order_id' => $this->stock_log['order_id'],
  289. 'goods_id' => $this->goods_id,
  290. 'mall_id' => $this->mall_id,
  291. 'is_sales' => 0,
  292. ];
  293. $company_user_id = 0;
  294. if(isset($sales_company_arr[$this->parent_agent->user_id])){
  295. $params['is_sales'] = 1;
  296. $params['company_id'] = $sales_company_arr[$this->parent_agent->user_id]['company_id'];
  297. $company_user_id = $this->parent_agent->user_id;
  298. }
  299. $user_arr = [];
  300. if(!empty($this->parent_agent_list)){
  301. foreach($this->parent_agent_list as $key => $agent){
  302. if($agent['level'] >= $this->parent_agent->level){
  303. $user_arr[] = $agent['user_id'];
  304. }
  305. }
  306. }
  307. if(!empty($user_arr) && !$params['is_sales']){
  308. foreach($user_arr as $user_id){
  309. if(isset($sales_company_arr[$user_id])){
  310. $params['is_sales'] = 1;
  311. $params['company_id'] = $sales_company_arr[$user_id]['company_id'];
  312. $company_user_id = $user_id;
  313. break;
  314. }
  315. }
  316. }
  317. $res = CloudStockTwoDeductionDetail::setData($params);
  318. if ($res == false) throw new \Exception(CloudStockTwoDeductionDetail::getStaticError());
  319. $is_install = MallAddons::isInstall($this->mall_id, AddonsEnum::ADDONS_NAME_ACHIEVEMENT);
  320. if ($is_install) $this->triggerAchievement($params);
  321. //销售公司途径 所有代理发放极差
  322. if(!empty($this->parent_agent_list)){
  323. foreach($this->parent_agent_list as $key => $agent){
  324. if(isset($this->reward_list[$agent['user_id']][UserWalletEnum::DIFF])){
  325. $this->reward_list[$agent['user_id']][UserWalletEnum::DIFF]['num'] = $this->not_yet_num;
  326. }
  327. if(isset($this->reward_list[$agent['user_id']][UserWalletEnum::EQUAL])){
  328. $this->reward_list[$agent['user_id']][UserWalletEnum::EQUAL]['num'] = $this->not_yet_num;
  329. }
  330. if(isset($this->reward_list[$agent['user_id']][UserWalletEnum::OVER])){
  331. $this->reward_list[$agent['user_id']][UserWalletEnum::OVER]['num'] = $this->not_yet_num;
  332. }
  333. //当前代理绑定了销售公司情况下,找到下一个极差结束
  334. if($this->parent_agent->level == $agent['level'] && $company_user_id == $this->parent_agent->user_id){
  335. $this->wait_deduct_equal_money = 0;
  336. break;
  337. }elseif($this->parent_agent->level < $agent['level']){
  338. break;
  339. }
  340. }
  341. $this->rewardTeamPrice(UserWalletEnum::DIFF);
  342. $this->rewardTeamPrice(UserWalletEnum::OVER);
  343. $this->rewardTeamPrice(UserWalletEnum::EQUAL);
  344. }
  345. if($params['is_sales']==1){
  346. $this->salesCompany($company_user_id);
  347. }
  348. $this->not_yet_num = 0;
  349. $this->wait_deduct_equal_money = 0;
  350. return true;
  351. }else{
  352. return $this->deductOrJob();
  353. }
  354. }else{
  355. return $this->deductOrJob();
  356. }
  357. }
  358. //代理商扣减库存,返回未扣库存数
  359. $agent_goods_deduct_not_yet_num = $this->agentGoodsDeduct($parent_agent_goods, $this->stock_log_id, $this->not_yet_num);
  360. if (empty($agent_goods_deduct_not_yet_num)) {
  361. //代理商上级够库存给下级扣减
  362. return true;
  363. } else {
  364. //代理商上级不够库存,给下级扣减
  365. $this->not_yet_num = $agent_goods_deduct_not_yet_num;
  366. }
  367. //未扣库存数大于0,递归找有库存的上级供应商扣减;
  368. if ($this->not_yet_num > 0) return $this->deductOrJob();
  369. return true;
  370. }
  371. protected function triggerAchievement($params){
  372. if ($this->order_type == 'fill') {
  373. try {
  374. \Yii::warning('触发业绩');
  375. $event = new FillEvent($this->mall_id);
  376. $order_detail_list[] = [
  377. 'id'=>$this->order['id'],
  378. 'goods_id'=>$this->order['goods_id'],
  379. 'goods_price'=>$this->order['pay_money']/$this->order['num']*$params['num'],
  380. 'num'=>$params['num'],
  381. 'user_id'=>$this->user_id,
  382. ];
  383. $data = [
  384. 'id' => $this->order['id'],
  385. 'user_id' => $this->user_id,
  386. 'mall_id' => $this->mall_id,
  387. 'created_at' => $this->order['created_at'],
  388. 'is_cloud' => 1,
  389. 'goods_id_arr' => [$this->goods_id],
  390. 'order_no' => $this->order['order_no'],
  391. 'order_detail_list'=>$order_detail_list
  392. ];
  393. \Yii::$app->services->events->dispatch($event, $data, $event->listeners);
  394. // AchievementOrderLogic::addData($this->mall_id,
  395. // $this->order['order_no'], $this->user_id, $grant['id'], $this->order['created_at'],
  396. // 1, [$this->goods_id], $order_detail_list);
  397. } catch (\Exception $e) {
  398. \Yii::error('云库存补货订单业绩' . PHP_EOL . $e->getFile() . '(' . $e->getLine() . ')' . PHP_EOL . "message:" . $e->getMessage());
  399. }
  400. }
  401. if ($this->order_type == 'buying') {
  402. //触发业绩
  403. try {
  404. $statistical_methods = \Yii::$app->services->setting->addons->get($this->mall_id, AddonsEnum::ADDONS_NAME_ACHIEVEMENT, 'basic.statistical_methods', true);
  405. // if(!empty($statistical_methods)){
  406. // 触发云库存订单支付事件
  407. $event = new FillEvent($this->mall_id);
  408. $order_detail_list[] = [
  409. 'id'=>$this->order['id'],
  410. 'goods_id'=>$this->order['goods_id'],
  411. 'goods_price'=>$this->order['after_distribution_price'],
  412. 'num'=>$params['num'],
  413. 'user_id'=>$this->user_id,
  414. ];
  415. $data = [
  416. 'id' => $this->order['id'],
  417. 'user_id' => $this->user_id,
  418. 'mall_id' => $this->mall_id,
  419. 'created_at' => $this->order['created_at'],
  420. 'is_cloud' => 1,
  421. 'goods_id_arr' => [$this->goods_id],
  422. 'order_no' => $this->order->order['order_no'],
  423. 'order_detail_list'=>$order_detail_list
  424. ];
  425. \Yii::$app->services->events->dispatch($event, $data, $event->listeners);
  426. // AchievementOrderLogic::addData($this->mall_id,
  427. // $this->order->order['order_no'], $this->user_id, $grant['id'], $this->order['created_at'],
  428. // 1, [$this->goods_id], $order_detail_list);
  429. // }
  430. } catch (\Exception $e) {
  431. \Yii::error('会员前端购买订单业绩' . PHP_EOL . $e->getFile() . '(' . $e->getLine() . ')' . PHP_EOL . "message:" . $e->getMessage());
  432. }
  433. }
  434. }
  435. /**
  436. * 代理商库存足够扣,扣减相应库存数,代理商库存不够扣,有多少扣多少,返回未扣库存数
  437. * 扣谁的库存,谁拿货款收益,扣多少数量库存,拿多少数量货款收益;
  438. * @param $parent_agent_goods //库存商品
  439. * @param $stock_log_id //库存变动日志id
  440. * @param $not_yet_num //剩余未扣数量
  441. * @return false|int
  442. */
  443. protected function agentGoodsDeduct($parent_agent_goods, $stock_log_id, $not_yet_num)
  444. {
  445. if ($parent_agent_goods->num >= $not_yet_num) {
  446. $parent_agent_goods->num -= $not_yet_num;//代理商库存足够扣,扣减扣库存数
  447. $num = $not_yet_num;
  448. $not_yet_num = 0;
  449. } else {
  450. $parent_agent_deduction_num = $parent_agent_goods->num;//代理商库存不足够扣,有多少扣多少
  451. $parent_agent_goods->num = 0;//代理商库存归0
  452. $not_yet_num -= $parent_agent_deduction_num; //记录此次扣的库存数剩余数量
  453. $num = $parent_agent_deduction_num;
  454. }
  455. $params = [
  456. 'stock_log_id' => $stock_log_id,
  457. 'not_yet_num' => $not_yet_num,
  458. 'num' => $num,
  459. 'user_id' => $parent_agent_goods->user_id,
  460. 'changes_type' => $this->stock_log['changes_type'],
  461. 'order_id' => $this->stock_log['order_id'],
  462. 'goods_id' => $parent_agent_goods['goods_id'],
  463. 'mall_id' => $parent_agent_goods['mall_id'],
  464. 'order_type' => $this->stock_log['order_type'],
  465. ];
  466. if (!$parent_agent_goods->save()) throw new Exception($parent_agent_goods->getErrorMessage());
  467. $res = CloudStockTwoDeductionDetail::setData($params);
  468. if (!$res) throw new Exception(CloudStockTwoDeductionDetail::getStaticError());
  469. $unit_goods_price = $this->unit_goods_price;
  470. //发放极差奖
  471. if(!empty($this->parent_agent_list)){
  472. $diff_price = 0;//未结算平级/越级奖励
  473. foreach($this->parent_agent_list as $key => $agent){
  474. if($agent['user_id'] == $this->parent_agent->user_id){
  475. if($diff_price > 0){
  476. $unit_goods_price -= $diff_price;
  477. }
  478. break;
  479. }
  480. if(isset($this->reward_list[$agent['user_id']][UserWalletEnum::DIFF])){
  481. $this->reward_list[$agent['user_id']][UserWalletEnum::DIFF]['num'] = $num;
  482. $unit_goods_price -= $this->reward_list[$agent['user_id']][UserWalletEnum::DIFF]['diff_price'];
  483. $diff_price = 0;//找到下一个拿极差的代理
  484. }
  485. if(isset($this->reward_list[$agent['user_id']][UserWalletEnum::EQUAL])){
  486. $this->reward_list[$agent['user_id']][UserWalletEnum::EQUAL]['num'] = $num;
  487. $diff_price += $this->reward_list[$agent['user_id']][UserWalletEnum::EQUAL]['unit_goods_price'];
  488. }
  489. if(isset($this->reward_list[$agent['user_id']][UserWalletEnum::OVER])){
  490. $this->reward_list[$agent['user_id']][UserWalletEnum::OVER]['num'] = $num;
  491. $diff_price += $this->reward_list[$agent['user_id']][UserWalletEnum::OVER]['unit_goods_price'];
  492. }
  493. }
  494. }
  495. $this->rewardTeamPrice(UserWalletEnum::DIFF);
  496. $this->rewardTeamPrice(UserWalletEnum::OVER);
  497. $this->rewardTeamPrice(UserWalletEnum::EQUAL);
  498. $payment_for_goods = $unit_goods_price * $num;
  499. //货款收益大于0,新增货款收益记录;
  500. if ($payment_for_goods > 0) {
  501. if ($this->parent_agent) {
  502. if ($this->order_type == 'buying') {
  503. $order = Order::findOne(['id'=>$this->order['order_id']]);
  504. //订单完成后才结算货款
  505. if($order['order_status']!=OrderStatusEnum::ACCOMPLISH)$this->is_frozen = true;
  506. $source_table = OrderDetail::tableName();
  507. $capital_type = UserWalletEnum::PAYMENT_FOR_GOODS_BUY;
  508. $source_table_id = $this->order['order_detail_id'];
  509. $desc ='';
  510. if(is_string(UserWalletEnum::getCapitalTypeMapByCommission( UserWalletEnum::PAYMENT_FOR_GOODS_BUY))){
  511. $desc = UserWalletEnum::getCapitalTypeMapByCommission( UserWalletEnum::PAYMENT_FOR_GOODS_BUY);
  512. }
  513. } else {
  514. $source_table = CloudStockTwoFillOrder::tableName();
  515. $source_table_id = $this->order['id'];
  516. $capital_type = UserWalletEnum::PAYMENT_FOR_GOODS_FILL;
  517. $desc ='';
  518. if(is_string(UserWalletEnum::getCapitalTypeMapByCommission( UserWalletEnum::PAYMENT_FOR_GOODS_FILL))){
  519. $desc = UserWalletEnum::getCapitalTypeMapByCommission( UserWalletEnum::PAYMENT_FOR_GOODS_FILL);
  520. }
  521. }
  522. //货款平台管理费
  523. $configs = \Yii::$app->services->setting->addons->get($this->mall_id, AddonsEnum::ADDONS_NAME_CLOUD_STOCK_TWO, 'basic');
  524. if($configs['platform_fee']){
  525. $agent_order_price = CloudStockTwoGoods::getReplenshPrice($this->mall_id,$this->parent_agent->level,[$this->goods_id]) ?? 0;
  526. $agent_order_price = $agent_order_price * $num;
  527. $service_charge = 0;
  528. if($payment_for_goods > $agent_order_price){
  529. $service_charge = ($payment_for_goods-$agent_order_price) * $configs['platform_fee'] / 100;
  530. $service_charge = bcmul($service_charge,1,2);
  531. $payment_for_goods = bcsub($payment_for_goods,$service_charge,2);
  532. $desc .= ',平台管理费扣除:'.$service_charge.'元';
  533. }
  534. }
  535. $insert_wallet [] = [
  536. 'mall_id' => $this->mall_id,
  537. 'user_id' => $this->parent_agent->user_id,
  538. 'is_frozen' => $this->is_frozen,
  539. 'wallet_type' => 'commission',
  540. 'money' => $payment_for_goods,
  541. 'desc' => $desc,
  542. 'source_table' => $source_table,
  543. 'source_table_id' => $source_table_id,
  544. 'from_type' => AddonsEnum::ADDONS_NAME_CLOUD_STOCK_TWO,
  545. 'capital_type' => $capital_type,
  546. 'service_charge' => $service_charge,
  547. ];
  548. //投递到资产队列
  549. if ($insert_wallet) {
  550. CloudStockTwoAgent::sendUserWalletQueue($insert_wallet);
  551. }
  552. }
  553. }
  554. return $not_yet_num;
  555. }
  556. public function deductOrJob()
  557. {
  558. //当前扣库存代理商
  559. $agent_user_id = 0;
  560. $level = 0;
  561. if (isset($this->parent_agent)) {
  562. $agent_user_id = $this->parent_agent->user_id;
  563. $level = $this->parent_agent->level;
  564. }
  565. if (!empty($this->is_time_limit_fill) && !empty($agent_user_id)) {
  566. //当前代理商加入过队列
  567. if (in_array($agent_user_id, $this->time_limit_fill_user_ids)) {
  568. //过了限时补货,而不补货,再往上找符合条件的代理商扣库存
  569. $parent_agent = CloudStockTwoAgent::getUserParentAgent($agent_user_id, $level);
  570. $this->parent_agent = $parent_agent;
  571. return $this->deduct();
  572. } else {
  573. //当前代理商没有加入过队列
  574. //记录执行限时补货的代理商用户id
  575. array_push($this->time_limit_fill_user_ids, $agent_user_id);
  576. $data = [
  577. 'user_id' => $this->user_id,
  578. 'agent_user_id' => $agent_user_id,
  579. 'stock_log_id' => $this->stock_log_id,
  580. 'order_id' => $this->order['id'],
  581. 'not_yet_num' => $this->not_yet_num,
  582. 'order_type' => $this->order_type,
  583. 'mall_id' => $this->mall_id,
  584. 'time_limit_fill_user_ids' => $this->time_limit_fill_user_ids,
  585. 'parent_agent_list' => $this->parent_agent_list,
  586. 'reward_list' => $this->reward_list,
  587. 'wait_deduct_equal_money' => $this->wait_deduct_equal_money,
  588. ];
  589. \Yii::error('订单id:'.$this->order['id'].'触发限时补货,时间是:'.$this->fill_hour);
  590. \Yii::$app->services->rabbitMq->delay($this->fill_hour * 3600, $data, DeductionJob::class, 'handleSync');
  591. //补货通知
  592. try{
  593. $SmsConfig = new Sms($this->mall_id);
  594. $easy_sms = $SmsConfig->easySms;
  595. $goods = Goods::findOne(['id' => $this->goods_id]);
  596. $goods_name = $goods['goods_name'];
  597. mb_substr($goods_name,0,24);
  598. $message = new TimeLimitFillMessage($this->mall_id, $this->fill_hour, $goods_name, $this->not_yet_num);
  599. $user = User::findOne(['id' => $agent_user_id]);
  600. // $easy_sms->send($user['mobile'], $message);
  601. try{
  602. $easy_sms->send($user['mobile'], $message);
  603. }catch (NoGatewayAvailableException $e){
  604. $res = $e->getExceptions();
  605. if(!empty($res)){
  606. foreach ($res as $exception){
  607. if(is_string($exception->getMessage())){
  608. \Yii::error('云库存补货通知短信发送失败:' .$exception->getMessage());
  609. }
  610. }
  611. }
  612. }
  613. }catch (\Exception $e){
  614. \Yii::error('云库存补货通知短信发送失败:' .$e->getMessage());
  615. }
  616. return true;
  617. }
  618. } else {
  619. //没有开启限时补货或者下单人的上级代理商不存在,递归往上找,直到找平台扣库存
  620. $this->parent_agent = CloudStockTwoAgent::getUserParentAgent($agent_user_id, $level);
  621. return $this->deduct();
  622. }
  623. }
  624. /**
  625. * 团队奖
  626. */
  627. public function rewardTeamPrice($capital_type)
  628. {
  629. if(empty($this->reward_list)){
  630. return true;
  631. }
  632. $insert_wallet = [];
  633. $is_frozen = false;
  634. if ($this->order_type == 'buying') {
  635. $source_table = OrderDetail::tableName();
  636. $source_table_id = $this->order['order_detail_id'];
  637. $order = Order::findOne(['id'=>$this->order['order_id']]);
  638. //订单完成后才结算货款
  639. if($order['order_status']!=OrderStatusEnum::ACCOMPLISH)$is_frozen = true;
  640. } else {
  641. $source_table = CloudStockTwoFillOrder::tableName();
  642. $source_table_id = $this->order['id'];
  643. }
  644. $desc = '';
  645. if($capital_type == UserWalletEnum::TEAM){
  646. $desc = $this->team_desc;
  647. }elseif($capital_type == UserWalletEnum::EQUAL){
  648. $desc = $this->bonus_equal_changes_desc;
  649. }elseif($capital_type == UserWalletEnum::OVER){
  650. $desc = $this->bonus_over_changes_desc;
  651. }elseif($capital_type == UserWalletEnum::DIFF){
  652. $desc = $this->diff_desc;
  653. }
  654. $configs = \Yii::$app->services->setting->addons->get($this->mall_id, AddonsEnum::ADDONS_NAME_CLOUD_STOCK_TWO, 'basic');
  655. foreach($this->parent_agent_list as $agent){
  656. if(isset($this->reward_list[$agent['user_id']][$capital_type]) && $this->reward_list[$agent['user_id']][$capital_type]['num']){
  657. $commission_num = $this->reward_list[$agent['user_id']][$capital_type]['unit_goods_price'] * $this->reward_list[$agent['user_id']][$capital_type]['num'];
  658. $service_charge = 0;
  659. if($configs['platform_fee']){
  660. $service_charge = $commission_num * $configs['platform_fee'] / 100;
  661. $service_charge = bcmul($service_charge,1,2);
  662. $commission_num = bcsub($commission_num,$service_charge,2);
  663. if(empty($commission_num)) return $insert_wallet;
  664. }
  665. $insert_wallet[] = [
  666. 'mall_id' => $this->mall_id,
  667. 'user_id' => $agent['user_id'],
  668. 'is_frozen' => $is_frozen,
  669. 'wallet_type' => 'commission',
  670. 'money' => $commission_num,
  671. 'desc' => $desc.',平台管理费扣除:'.$service_charge.'元',
  672. 'source_table' => $source_table,
  673. 'source_table_id' => $source_table_id,
  674. 'from_type' => AddonsEnum::ADDONS_NAME_CLOUD_STOCK_TWO,
  675. 'capital_type' => $capital_type,
  676. 'service_charge' => $service_charge,
  677. ];
  678. $this->reward_list[$agent['user_id']][$capital_type]['num'] = 0;
  679. }
  680. }
  681. //投递到资产队列
  682. if ($insert_wallet) {
  683. CloudStockTwoAgent::sendUserWalletQueue($insert_wallet);
  684. }
  685. }
  686. /**
  687. * 销售公司
  688. */
  689. public function salesCompany($user_id=0){
  690. if($this->parent_agent){
  691. // $user_id = $this->parent_agent->user_id;
  692. $order_price = CloudStockTwoGoods::getReplenshPrice($this->mall_id,$this->parent_agent->level,[$this->goods_id]) ?? 0;
  693. }else{
  694. // $user_id = $this->user_id;
  695. $order_price = $this->unit_goods_price;
  696. }
  697. $agent_order_price = CloudStockTwoGoods::getReplenshPrice($this->mall_id,0,[$this->goods_id]) ?? 0;
  698. $sales_price = bcsub($order_price,$agent_order_price,2);
  699. //销售公司承担未结算平级/越级奖
  700. if($this->wait_deduct_equal_money){
  701. $sales_price = bcsub($sales_price,$this->wait_deduct_equal_money,2);
  702. }
  703. //销售公司拿货价 = 代理拿货价
  704. if(!$sales_price || $sales_price <= 0){
  705. return true;
  706. }
  707. $is_frozen = 0;
  708. if ($this->order_type == 'buying') {
  709. $source_table = OrderDetail::tableName();
  710. $source_table_id = $this->order['order_detail_id'];
  711. $desc ='会员买货货款,旗下成员(ID:'.$user_id.')收益后结算奖励';
  712. $order = Order::findOne(['id'=>$this->order['order_id']]);
  713. //订单完成后才结算货款
  714. if($order['order_status']!=OrderStatusEnum::ACCOMPLISH)$is_frozen = 1;
  715. } else {
  716. $source_table = CloudStockTwoFillOrder::tableName();
  717. $source_table_id = $this->order['id'];
  718. $desc ='补货货款,旗下成员(ID:'.$user_id.')收益后结算奖励';
  719. }
  720. \Yii::error('销售公司触发,order_id:'.$this->stock_log['order_id'].',user_id:'.$user_id);
  721. $event = new SalesCompanyEvent($this->mall_id);
  722. $data = [
  723. 'source_table' => $source_table,
  724. 'source_table_id' => $source_table_id,
  725. 'num' => $this->not_yet_num,
  726. 'user_id' => $user_id,
  727. 'price' => $sales_price,
  728. 'desc' => $desc,
  729. 'is_frozen' => $is_frozen,
  730. ];
  731. \Yii::$app->services->events->dispatch($event, $data, $event->listeners);
  732. }
  733. }