GiftBagLogic.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. <?php
  2. namespace addons\CloudStock\common\logic\gift_bag;
  3. use addons\CloudStock\common\enums\CloudStockEnum;
  4. use addons\CloudStock\common\logic\deduction\DeductionJob;
  5. use addons\CloudStock\common\logic\level_up\LevelUp;
  6. use addons\CloudStock\common\models\CloudStockAgent;
  7. use addons\CloudStock\common\models\CloudStockAgentGoods;
  8. use addons\CloudStock\common\models\CloudStockDeductionDetail;
  9. use addons\CloudStock\common\models\CloudStockLevel;
  10. use addons\CloudStock\common\models\CloudStockGoodsStockLog;
  11. use addons\CloudStock\common\sms\SmsConfig;
  12. use addons\CloudStock\common\sms\TimeLimitFillMessage;
  13. use addons\CloudStock\common\events\order\CloudStockChangeEvent;
  14. use common\enums\AddonsEnum;
  15. use common\enums\StatusEnum;
  16. use common\helpers\sms\Sms;
  17. use common\models\order\Order;
  18. use common\models\user\User;
  19. use common\models\user\UserPartitionRelationship;
  20. use Overtrue\EasySms\EasySms;
  21. use Overtrue\EasySms\Exceptions\NoGatewayAvailableException;
  22. class GiftBagLogic
  23. {
  24. //升级礼包支持多商品,多赠送库存
  25. public static function upgradeBagUpNew($mall_id, $user_id, $order_id, $buy_goods_id_arr, $upgrade_bag_list, $cloud_stock_agent, $time, $before_level, $level_up_give_stock_by_parent, $goods_price_arr,$bag_commission=0)
  26. {
  27. $level = 0;
  28. $give_arr = [];
  29. foreach ($upgrade_bag_list as $item) {
  30. $goods_ids = [];
  31. if(!empty($item['goods_id'])){
  32. if (!empty(intval($item['goods_id']))) {
  33. $goods_ids[] = intval($item['goods_id']);
  34. } else {
  35. $goods_ids = json_decode($item['goods_id'], true);
  36. }
  37. }
  38. $intersect_goods_ids = array_intersect($buy_goods_id_arr, $goods_ids);//升级商品id
  39. if (!empty($intersect_goods_ids)) {
  40. $level = $item['level'];
  41. break;
  42. }
  43. }
  44. $cloud_stock_level_model = CloudStockLevel::findOne(['mall_id' => $mall_id, 'level' => $level, 'status' => StatusEnum::ENABLED]);
  45. if (empty($cloud_stock_level_model)) return false;
  46. if ($cloud_stock_agent->level >= $level) return true;
  47. $cloud_stock_agent->level = $level;
  48. $cloud_stock_agent->upgrade_status = CloudStockEnum::UPGRADE_STATUS_GOODS;
  49. $cloud_stock_agent->upgrade_at = $time;
  50. $cloud_stock_agent->before_level = $before_level;
  51. $res = $cloud_stock_agent->save();
  52. if ($res) {
  53. LevelUp::updateQuota($cloud_stock_agent);
  54. LevelUp::sendMessage($mall_id, $cloud_stock_level_model['name'], $cloud_stock_agent['user_id']);
  55. LevelUp::addUpgradeAgentToArr($mall_id, $user_id);
  56. }
  57. foreach ($upgrade_bag_list as $item) {
  58. $goods_ids = [];
  59. if (!empty(intval($item['goods_id']))) {
  60. $goods_ids[] = intval($item['goods_id']);
  61. } else {
  62. $goods_ids = json_decode($item['goods_id'], true);
  63. }
  64. if (array_intersect($buy_goods_id_arr, $goods_ids)) {
  65. if(!empty($item['give_goods_num'])){
  66. if (!empty(intval($item['give_goods_num']))) {
  67. $give_goods_num[] = intval($item['give_goods_num']);
  68. if (!empty($item['give_goods_id'])) {
  69. if (isset($give_arr[$item['give_goods_id']])) {
  70. $give_arr[$item['give_goods_id']] += $item['give_goods_num'];
  71. } else {
  72. $give_arr[$item['give_goods_id']] = $item['give_goods_num'];
  73. }
  74. }
  75. } else {
  76. $give_goods_num = json_decode($item['give_goods_num'], true);
  77. foreach ($give_goods_num as $give_goods) {
  78. if (isset($give_arr[$give_goods['goods_id']])) {
  79. $give_arr[$give_goods['goods_id']] += $give_goods['num'];
  80. } else {
  81. $give_arr[$give_goods['goods_id']] = $give_goods['num'];
  82. }
  83. }
  84. }
  85. }
  86. break;
  87. }
  88. }
  89. //赠送库存
  90. try {
  91. self::giveCloudStockGoods($mall_id, $user_id, $order_id, $level, $upgrade_bag_list, $buy_goods_id_arr, $goods_price_arr,$level_up_give_stock_by_parent,$bag_commission);
  92. }catch (\Exception $e){
  93. var_dump('addons\CloudStock\common\logic\level_up:upgradeBagUpNew:'.$e->getMessage().$e->getFile().$e->getLine());
  94. }
  95. }
  96. //送库存,送奖励
  97. public static function giveCloudStockGoods($mall_id, $buy_user_id, $order_id, $level, $upgrade_bag_list, $buy_goods_id_arr, $goods_price_arr,$level_up_give_stock_by_parent,$bag_commission)
  98. {
  99. $user = User::findOne(['id' => $buy_user_id]);
  100. $parent_id = $user['parent_id'];
  101. $second_parent_id = $user['second_parent_id'];
  102. $direct_reward = 0;
  103. $indirect_reward = 0;
  104. $is_percent = 0;//默认固定金额
  105. $total_goods_price = 0;
  106. $direct_reward_capital_type = '';
  107. $indirect_reward_capital_type = '';
  108. $p_cloud_stock_agent_list = CloudStockAgent::lists([
  109. 'where' => [
  110. ['user_id' => [$parent_id, $second_parent_id]],
  111. ['status' => StatusEnum::ENABLED],
  112. ['<=', 'level', $level],
  113. ],
  114. 'index' => 'user_id',
  115. ]);
  116. foreach ($upgrade_bag_list as $item) {
  117. $goods_ids = [];
  118. if(!empty($item['goods_id'])){
  119. if (!empty(intval($item['goods_id']))) {
  120. $goods_ids[] = intval($item['goods_id']);
  121. } else {
  122. $goods_ids = json_decode($item['goods_id'], true);
  123. }
  124. }
  125. $intersect_goods_ids = array_intersect($buy_goods_id_arr, $goods_ids);//升级商品id
  126. if (!empty($intersect_goods_ids)) {
  127. $level_reward = json_decode($item['level_reward'], true);
  128. if(is_array($level_reward)){
  129. $level_reward = array_column($level_reward,null,'level');
  130. }
  131. if(!empty($item['give_goods_num'])){
  132. if (!empty(intval($item['give_goods_num']))) {
  133. $give_goods_num[] = intval($item['give_goods_num']);
  134. if (!empty($item['give_goods_id'])) {
  135. if (isset($give_arr[$item['give_goods_id']])) {
  136. $give_arr[$item['give_goods_id']] += $item['give_goods_num'];
  137. } else {
  138. $give_arr[$item['give_goods_id']] = $item['give_goods_num'];
  139. }
  140. }
  141. } else {
  142. $give_goods_num = json_decode($item['give_goods_num'], true);
  143. foreach ($give_goods_num as $give_goods) {
  144. if (isset($give_arr[$give_goods['goods_id']])) {
  145. $give_arr[$give_goods['goods_id']] += $give_goods['num'];
  146. } else {
  147. $give_arr[$give_goods['goods_id']] = $give_goods['num'];
  148. }
  149. }
  150. }
  151. }
  152. if (!isset($p_cloud_stock_agent_list[$parent_id])) {
  153. $parent_id = 0;
  154. } else {
  155. if ($p_cloud_stock_agent_list[$parent_id]['level'] == $level) {
  156. $direct_reward = $level_reward[$p_cloud_stock_agent_list[$parent_id]['level']]['direct_equal_reward'] ?? 0;
  157. $direct_reward_capital_type = 'first_equal';
  158. } else {
  159. $direct_reward = $level_reward[$p_cloud_stock_agent_list[$parent_id]['level']]['direct_over_reward'] ?? 0;
  160. $direct_reward_capital_type = 'first_over';
  161. }
  162. }
  163. if (!isset($p_cloud_stock_agent_list[$second_parent_id])) {
  164. $second_parent_id = 0;
  165. } else {
  166. if ($p_cloud_stock_agent_list[$second_parent_id]['level'] == $level) {
  167. $indirect_reward = $level_reward[$p_cloud_stock_agent_list[$second_parent_id]['level']]['indirect_equal_reward'] ?? 0;
  168. $indirect_reward_capital_type = 'second_equal';
  169. } else {
  170. $indirect_reward = $level_reward[$p_cloud_stock_agent_list[$second_parent_id]['level']]['indirect_over_reward'] ?? 0;
  171. $indirect_reward_capital_type = 'second_over';
  172. }
  173. }
  174. $is_percent = $item['is_percent'] ?? 0;
  175. break;
  176. }
  177. }
  178. if (!empty($intersect_goods_ids)) {
  179. foreach ($intersect_goods_ids as $goods_id) {
  180. if (isset($goods_price_arr[$goods_id])) {
  181. $total_goods_price = bcadd($total_goods_price, $goods_price_arr[$goods_id], 2);
  182. }
  183. }
  184. }
  185. $payment_for_goods = $total_goods_price;
  186. if ($is_percent == 1) {
  187. //百分比
  188. if ($total_goods_price > 0) {
  189. $direct_reward = bcdiv($direct_reward * $total_goods_price, 100, 2);
  190. $indirect_reward = bcdiv($indirect_reward * $total_goods_price, 100, 2);
  191. } else {
  192. $direct_reward = 0;
  193. $indirect_reward = 0;
  194. }
  195. }
  196. if ($payment_for_goods > $direct_reward) {
  197. $payment_for_goods = bcsub($payment_for_goods, $direct_reward, 2);
  198. } else {
  199. $payment_for_goods = 0;
  200. $direct_reward = $payment_for_goods;
  201. }
  202. if ($payment_for_goods > $indirect_reward) {
  203. $payment_for_goods = bcsub($payment_for_goods, $indirect_reward, 2);
  204. } else {
  205. $payment_for_goods = 0;
  206. $indirect_reward = $payment_for_goods;
  207. }
  208. //扣除分佣
  209. if(!empty($bag_commission)){
  210. $payment_for_goods = bcsub($payment_for_goods, $bag_commission, 2);
  211. }
  212. if ($parent_id > 0 && $direct_reward > 0) {
  213. $insert_wallet[] = [
  214. 'mall_id' => $mall_id,
  215. 'user_id' => $parent_id,
  216. 'is_frozen' => false,
  217. 'wallet_type' => 'commission',
  218. 'money' => $direct_reward,
  219. 'desc' => '云库存直推奖励',
  220. 'source_table' => Order::tableName(),
  221. 'source_table_id' => $order_id,
  222. 'from_type' => AddonsEnum::ADDONS_NAME_CLOUD_STOCK,
  223. 'capital_type' => $direct_reward_capital_type,
  224. ];
  225. }
  226. if ($second_parent_id > 0 && $indirect_reward > 0) {
  227. $insert_wallet[] = [
  228. 'mall_id' => $mall_id,
  229. 'user_id' => $second_parent_id,
  230. 'is_frozen' => false,
  231. 'wallet_type' => 'commission',
  232. 'money' => $indirect_reward,
  233. 'desc' => '云库存间推奖励',
  234. 'source_table' => Order::tableName(),
  235. 'source_table_id' => $order_id,
  236. 'from_type' => AddonsEnum::ADDONS_NAME_CLOUD_STOCK,
  237. 'capital_type' => $indirect_reward_capital_type,
  238. ];
  239. }
  240. if (!empty($insert_wallet)) CloudStockAgent::sendUserWalletQueue($insert_wallet);
  241. if (!empty($give_arr)) {
  242. //库存变动表
  243. $stock_log_arr = [];
  244. foreach ($give_arr as $goods_id => $num) {
  245. if (empty($num)) continue;
  246. $params = [
  247. 'mall_id' => $mall_id,
  248. 'user_id' => $buy_user_id,
  249. 'goods_id' => $goods_id,
  250. 'num' => $num,
  251. 'order_id' => $order_id,
  252. 'changes_type' => CloudStockEnum::STOCK_CHANGE_TYPE105,
  253. 'changes_dir' => CloudStockEnum::STOCK_CHANGE_ADD,
  254. 'order_type' => CloudStockEnum::STOCK_ORDER_TYPE_USER,
  255. ];
  256. $res = CloudStockAgentGoods::addData($params, $increase_detail);
  257. if (!$res) throw new \Exception(CloudStockAgentGoods::getStaticError());
  258. CloudStockAgent::fixStock($mall_id,$buy_user_id);
  259. //库存变化记录
  260. $stock_log_params = [
  261. 'mall_id' => $mall_id,
  262. 'goods_id' => $goods_id,
  263. 'user_id' => 0,
  264. 'changes_dir' => CloudStockEnum::STOCK_CHANGE_SUB,
  265. 'order_id' => $order_id,
  266. 'num' => $num,
  267. 'order_type' => CloudStockEnum::STOCK_ORDER_TYPE_USER,
  268. 'changes_type' => CloudStockEnum::STOCK_CHANGE_TYPE105,
  269. ];
  270. $stock_log = CloudStockGoodsStockLog::setData($mall_id,$stock_log_params);
  271. if (!$stock_log) throw new \Exception(CloudStockGoodsStockLog::getStaticError());
  272. $stock_log_arr[$goods_id] = $stock_log->id;
  273. }
  274. if(!empty($level_up_give_stock_by_parent)){
  275. $res = self::checkDeductionStock($mall_id,$order_id, $buy_user_id, $level, $give_arr, $payment_for_goods,$stock_log_arr);
  276. var_dump($res);
  277. if(!empty($res['is_sub_stock'])){
  278. self::deductionStock($mall_id, $res['sub_user_id']??0, $order_id, $give_arr, $payment_for_goods,$stock_log_arr,$bag_commission);
  279. }
  280. }else{
  281. self::deductionStock($mall_id, 0, $order_id, $give_arr, $payment_for_goods,$stock_log_arr);
  282. }
  283. }
  284. }
  285. public static function checkDeductionStock($mall_id,$order_id, $buy_user_id, $level, $give_arr, $payment_for_goods,$stock_log_arr = [])
  286. {
  287. $give_goods_ids = array_keys($give_arr);
  288. $p_cloud_stock_agent_arr = self::getParentCloudStockAgent($mall_id,$level,$buy_user_id);
  289. $is_sub_stock = 1;
  290. $sub_user_id = 0;
  291. if (!empty($p_cloud_stock_agent_arr)) {
  292. $configs = \Yii::$app->services->setting->addons->get($mall_id, AddonsEnum::ADDONS_NAME_CLOUD_STOCK, 'basic');
  293. if (!empty($configs['is_time_limit_fill'])) {
  294. //开启延时补货
  295. $first_parent = $p_cloud_stock_agent_arr[0];
  296. $agent_goods_list = CloudStockAgentGoods::lists([
  297. 'where' => [
  298. ['mall_id' => $mall_id],
  299. ['user_id' => $first_parent['user_id']],
  300. ['goods_id' => $give_goods_ids],
  301. ],
  302. 'index' => 'goods_id',
  303. ]);
  304. $goods_ids = '';
  305. $num_s = '';
  306. foreach ($give_arr as $g_id => $num) {
  307. if (!isset($agent_goods_list[$g_id]) || $agent_goods_list[$g_id]['num'] < $num) {
  308. //延时补货
  309. $goods_ids.=$g_id.',';
  310. $num_s.=$num.',';
  311. $is_sub_stock = 0;
  312. $send_user_id = $first_parent['user_id'];
  313. }
  314. }
  315. if ($is_sub_stock == 1) {
  316. $sub_user_id = $first_parent['user_id'];
  317. }
  318. if($is_sub_stock==0){
  319. //投入延时队列
  320. $post_data = [
  321. 'mall_id' => $mall_id,
  322. 'order_id' => $order_id,
  323. 'give_arr' => $give_arr,
  324. 'payment_for_goods' => $payment_for_goods,
  325. 'buy_user_id' => $buy_user_id,
  326. 'level' => $level,
  327. 'stock_log_arr' => $stock_log_arr,
  328. ];
  329. var_dump('投入延时队列数据:'.json_encode($post_data));
  330. $fill_hour = $configs['fill_hour']??0;
  331. \Yii::$app->services->rabbitMq->delay($fill_hour * 3600, $post_data, DeductionJob::class, 'delayDeductionStock');
  332. if(!empty($send_user_id)){
  333. //补货通知
  334. try{
  335. $SmsConfig = new Sms($mall_id);
  336. $easy_sms = $SmsConfig->easySms;
  337. $message = new TimeLimitFillMessage($mall_id, $fill_hour, trim($goods_ids,','), trim($num_s,','));
  338. $user = User::findOne(['id' => $send_user_id]);
  339. $easy_sms->send($user['mobile'], $message);
  340. }catch (NoGatewayAvailableException $e){
  341. $res = $e->getExceptions();
  342. if(!empty($res)){
  343. foreach ($res as $exception){
  344. if(is_string($exception->getMessage())){
  345. var_dump('云库存购买升级礼包补货通知短信发送失败:' .$exception->getMessage());
  346. }
  347. }
  348. }
  349. }catch (\Exception $e){
  350. var_dump('云库存购买升级礼包补货通知短信发送失败:' .$e->getMessage());
  351. }
  352. }
  353. }
  354. } else {
  355. $sub_user_id = self::checkDeductionStockNoDelay($mall_id,$buy_user_id,$level,$give_arr);
  356. }
  357. }
  358. return ['is_sub_stock' => $is_sub_stock, 'sub_user_id' => $sub_user_id];
  359. }
  360. public static function checkDeductionStockNoDelay($mall_id,$buy_user_id,$level,$give_arr){
  361. $p_cloud_stock_agent_arr = self::getParentCloudStockAgent($mall_id,$level,$buy_user_id);
  362. $give_goods_ids = array_keys($give_arr);
  363. $u_pids = array_column($p_cloud_stock_agent_arr, 'user_id');
  364. $agent_goods_list = CloudStockAgentGoods::lists([
  365. 'where' => [
  366. ['mall_id' => $mall_id],
  367. ['user_id' => $u_pids],
  368. ['goods_id' => $give_goods_ids],
  369. ]
  370. ]);
  371. $agent_goods_arr = [];
  372. foreach ($agent_goods_list as $val) {
  373. $agent_goods_arr[$val['user_id']][$val['goods_id']] = $val;
  374. }
  375. $sub_user_id = 0;
  376. if (!empty($agent_goods_arr)) {
  377. foreach ($p_cloud_stock_agent_arr as $agent){
  378. if(isset($agent_goods_arr[$agent['user_id']])){
  379. $agent_goods = $agent_goods_arr[$agent['user_id']];
  380. $sub_user_id = $agent['user_id'];
  381. foreach ($give_arr as $g_id => $num) {
  382. if (!isset($agent_goods[$g_id]) || $agent_goods[$g_id]['num'] < $num) {
  383. $sub_user_id = 0;
  384. break;
  385. }
  386. }
  387. if ($sub_user_id > 0) {
  388. break;
  389. }
  390. }
  391. }
  392. }
  393. return $sub_user_id;
  394. }
  395. //获取上级代理
  396. public static function getParentCloudStockAgent($mall_id,$level,$buy_user_id){
  397. $parent_id_arr = UserPartitionRelationship::getParentIdArr($buy_user_id);
  398. $parent_id_arr = array_reverse($parent_id_arr);
  399. $p_cloud_stock_agent_list = CloudStockAgent::lists([
  400. 'where' => [
  401. ['mall_id' => $mall_id],
  402. ['user_id' => $parent_id_arr],
  403. ['status' => StatusEnum::ENABLED],
  404. ['>', 'level', $level],
  405. ],
  406. 'index' => 'user_id',
  407. ]);
  408. $p_cloud_stock_agent_arr = [];
  409. foreach ($parent_id_arr as $u_id) {
  410. if (isset($p_cloud_stock_agent_list[$u_id])) {
  411. $p_cloud_stock_agent_arr[] = $p_cloud_stock_agent_list[$u_id];
  412. }
  413. }
  414. return $p_cloud_stock_agent_arr;
  415. }
  416. //扣库存
  417. public static function deductionStock($mall_id, $sub_user_id, $order_id, $give_arr, $payment_for_goods,$stock_log_arr = [])
  418. {
  419. if (!empty($give_arr)) {
  420. if($sub_user_id>0){
  421. foreach ($give_arr as $goods_id => $num) {
  422. if (empty($num)) continue;
  423. $params = [
  424. 'mall_id' => $mall_id,
  425. 'user_id' => $sub_user_id,
  426. 'goods_id' => $goods_id,
  427. 'num' => $num,
  428. 'order_id' => $order_id,
  429. 'changes_type' => CloudStockEnum::STOCK_CHANGE_TYPE105,
  430. 'changes_dir' => CloudStockEnum::STOCK_CHANGE_SUB,
  431. 'order_type' => CloudStockEnum::STOCK_ORDER_TYPE_USER,
  432. 'stock_log_id' => !empty($stock_log_arr[$goods_id]) ? $stock_log_arr[$goods_id] : 0,
  433. ];
  434. $res = CloudStockAgentGoods::subData($params);
  435. if (!$res) throw new \Exception(CloudStockAgentGoods::getStaticError());
  436. CloudStockAgent::fixStock($mall_id,$sub_user_id);
  437. var_dump('扣减库存成功');
  438. }
  439. var_dump('货款'.$payment_for_goods);
  440. if($payment_for_goods>0){
  441. $source_table = Order::tableName();
  442. $source_table_id = $order_id;
  443. $insert_wallet[] = [
  444. 'mall_id' => $mall_id,
  445. 'user_id' => $sub_user_id,
  446. 'is_frozen' => false,
  447. 'wallet_type' => 'commission',
  448. 'money' => $payment_for_goods,
  449. 'desc' => '会员购买升级礼包赠送库存货款',
  450. 'source_table' => $source_table,
  451. 'source_table_id' => $source_table_id,
  452. 'from_type' => AddonsEnum::ADDONS_NAME_CLOUD_STOCK,
  453. 'capital_type' => 'payment_for_level_goods_buy',
  454. ];
  455. if (!empty($insert_wallet)) CloudStockAgent::sendUserWalletQueue($insert_wallet);
  456. }
  457. }else{
  458. foreach ($give_arr as $goods_id => $num) {
  459. $params = [
  460. 'stock_log_id' => !empty($stock_log_arr[$goods_id]) ? $stock_log_arr[$goods_id] : 0,
  461. 'user_id' => 0,
  462. 'num' =>$num,
  463. 'not_yet_num' => 0,
  464. 'changes_type' => CloudStockEnum::STOCK_CHANGE_TYPE105,
  465. 'order_id' => $order_id,
  466. 'goods_id' => $goods_id,
  467. 'mall_id' => $mall_id,
  468. ];
  469. $res = CloudStockDeductionDetail::setData($params);
  470. if($res){
  471. //触发库存变动事件
  472. $event = new CloudStockChangeEvent($mall_id);
  473. $event_data = [
  474. 'id' => $res->id,
  475. 'type' => CloudStockEnum::STOCK_CHANGE_SUB,
  476. 'mall_id' => $mall_id,
  477. ];
  478. \Yii::$app->services->events->dispatch($event, $event_data, $event->listeners);
  479. }
  480. }
  481. }
  482. }
  483. }
  484. }