CsGoodsController.php 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917
  1. <?php
  2. namespace addons\CloudStock\api\modules\v1\controllers;
  3. use addons\CloudStock\common\enums\CloudStockEnum;
  4. use addons\CloudStock\common\events\order\DispenseEvent;
  5. use addons\CloudStock\common\logic\order\RestrictPurchases;
  6. use addons\CloudStock\common\models\CloudStockAgent;
  7. use addons\CloudStock\common\models\CloudStockAgentGoods;
  8. use addons\CloudStock\common\models\CloudStockAgentOrder;
  9. use addons\CloudStock\common\models\CloudStockDeductionDetail;
  10. use addons\CloudStock\common\models\CloudStockDispenseOrder;
  11. use addons\CloudStock\common\models\CloudStockGoods;
  12. use addons\CloudStock\common\models\CloudStockGoodsStockLog;
  13. use addons\CloudStock\common\models\CloudStockIncreaseDetail;
  14. use addons\CloudStock\common\models\CloudStockLevel;
  15. use addons\CloudStock\common\logic\order\PickOfflinePayNotify;
  16. use addons\CloudStock\common\models\CloudStockUpgradeBag;
  17. use addons\CloudStock\common\models\CouponSetting;
  18. use addons\CloudStock\common\services\CloudStockAgentCartService;
  19. use addons\CloudStock\common\services\CloudStockAgentGoodsService;
  20. use addons\CloudStock\common\services\CloudStockAgentOrderService;
  21. use common\enums\StatusEnum;
  22. use common\helpers\ArrayHelper;
  23. use common\models\goods\Goods;
  24. use common\models\goods\GoodsAttr;
  25. use common\models\user\User;
  26. use common\models\user\UserPartitionRelationship;
  27. use common\enums\AddonsEnum;
  28. use common\logic\order\OrderFormLogic;
  29. use common\enums\AppEnum;
  30. use common\enums\ShippingTypeEnum;
  31. use common\logic\order\OrderInitDataLogic;
  32. use common\models\user\UserAddress;
  33. use common\logic\order\OrderMarketingLogic;
  34. use common\enums\PreviewTypeEnum;
  35. class CsGoodsController extends BaseController
  36. {
  37. public $modelClass = '';
  38. /**
  39. * 不用进行登录验证的方法
  40. *
  41. * 例如: ['index', 'update', 'create', 'view', 'delete']
  42. * 默认全部需要验证
  43. *
  44. * @var array
  45. */
  46. protected $authOptional = ['upgrade-goods-list'];
  47. /**
  48. * @name:
  49. * @msg: 我的库存列表
  50. * @param {*}
  51. * @return {*}
  52. */
  53. public function actionList()
  54. {
  55. if (!\Yii::$app->request->isGet) {
  56. return $this->error('请求方式错误');
  57. }
  58. $page = \Yii::$app->request->get('page', 1);
  59. $limit = \Yii::$app->request->get('limit', $this->pageSize);
  60. $wheres[] = ['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED];
  61. $get = \Yii::$app->request->get();
  62. if(!empty($get['type']) && $get['type']==2){
  63. //升级礼包商品
  64. $wheres[] = ['goods_id' => CloudStockUpgradeBag::getGoodsIds($this->mall_id)];
  65. } else {
  66. $configs = \Yii::$app->services->setting->addons->get($this->mall_id, AddonsEnum::ADDONS_NAME_CLOUD_STOCK, 'basic');
  67. if (!empty($configs['is_show_cloud_stock_partition'])) {
  68. $wheres[] = ['not in', 'goods_id', CloudStockUpgradeBag::getGoodsIds($this->mall_id)];
  69. }
  70. }
  71. $params = [
  72. 'select' => 'id,mall_id,goods_id,agent_price,created_at,agent_price,sort,min_replenish,restrict_permissions',
  73. 'where' => $wheres,
  74. 'order' => 'sort asc,created_at desc',
  75. 'page' => 1,
  76. 'limit' => 1000,
  77. ];
  78. $list = CloudStockGoods::listPage($params);
  79. if (empty($list['list'])) {
  80. if (!is_array($list['list'])) return $this->error(CloudStockAgentGoods::getStaticError());
  81. }
  82. $cloud_stock_agent = CloudStockAgent::find()->where(['user_id'=>$this->user_id,'status'=>StatusEnum::ENABLED,'mall_id'=>$this->mall_id])->one();
  83. $good_ids = array_column($list['list'], 'goods_id');
  84. $agent_goods = CloudStockAgentGoods::find()
  85. ->select('user_id,goods_id,num as agent_stock')
  86. ->where(['mall_id' => $this->mall_id, 'user_id' => $this->user_id, 'status' => StatusEnum::ENABLED, 'goods_id' => $good_ids])
  87. ->asArray()
  88. ->indexBy('goods_id')
  89. ->all();
  90. $mall_goods = Goods::find()
  91. ->select('id,goods_name,price,cover_pic')
  92. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'id' => $good_ids, 'is_on_sale' => 1, 'is_attr' => 0])
  93. ->asArray()
  94. ->indexBy('id')
  95. ->all();
  96. $goodsWeight = GoodsAttr::find()
  97. ->select('weight')
  98. ->where(['status' => StatusEnum::ENABLED, 'goods_id' => $good_ids])
  99. ->asArray()
  100. ->indexBy('goods_id')
  101. ->column();
  102. // dd($list['list'], $mall_goods);
  103. $limit_data = RestrictPurchases::getLimitData($this->mall_id,$this->user_id,$good_ids);
  104. $cloud_stock_agent_guota_list = \addons\CloudStock\common\models\CloudStockAgentGuota::find()
  105. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'goods_id' => $good_ids,'user_id'=>$this->user_id])
  106. ->indexBy('goods_id')
  107. ->all();
  108. foreach ($list['list'] as $index => &$lv) {
  109. if (!empty($mall_goods[$lv['goods_id']])) {
  110. $mall_good = $mall_goods[$lv['goods_id']];
  111. } else {
  112. unset($list['list'][$index]);
  113. continue;
  114. }
  115. $restrict_permissions = json_decode($lv['restrict_permissions'],true);
  116. if(empty($restrict_permissions)){
  117. $restrict_permissions = [];
  118. }
  119. if(in_array($cloud_stock_agent['level'],$restrict_permissions) && isset($list['list'][$index])){
  120. unset($list['list'][$index]);
  121. continue;
  122. }
  123. // 当前会员是否可以补货当前商品
  124. $rr = CloudStockGoods::canFillGood($this->mall_id, $lv['goods_id'], $this->stock_agent->level, $this->user_id);
  125. if (false === $rr) {
  126. unset($list['list'][$index]);
  127. continue;
  128. }
  129. $price = $mall_good['price'] ?? 0;
  130. $agent_price = json_decode($lv['agent_price'],true);
  131. $agent_price = array_column($agent_price,null,'level');
  132. $replenish_price = 0;
  133. if(!empty($agent_price[$this->stock_agent->level])){
  134. $replenish_price = $agent_price[$this->stock_agent->level]['price'];
  135. }
  136. // 如果补货价格为0,前端不显示,不可以补货
  137. if ($replenish_price <= 0) {
  138. unset($list['list'][$index]);
  139. continue;
  140. }
  141. $lv['replenish_price'] = $replenish_price;
  142. $lv['goods_name'] = $mall_good['goods_name'] ?? '';
  143. $lv['cover_pic'] = $mall_good['cover_pic'] ?? '';
  144. // 平台价格,零售价
  145. $lv['pirce'] = $price;
  146. $lv['profit'] = bcsub($price, $replenish_price, 2);
  147. $lv['user_id'] = $this->user_id;
  148. if (!empty($agent_goods[$lv['goods_id']])) {
  149. $lv = array_merge($lv, $agent_goods[$lv['goods_id']]);
  150. }
  151. $lv['is_mine'] = 0;
  152. $lv['agent_stock'] = 0;
  153. if (isset($agent_goods[$lv['goods_id']])) {
  154. $lv['agent_stock'] = $agent_goods[$lv['goods_id']]['agent_stock'];
  155. if ($lv['agent_stock'] > 0) $lv['is_mine'] = 1;
  156. }
  157. unset($lv['agent_price']);
  158. //todo
  159. $lv['month_quota'] = null;
  160. $lv['remaining_quantity'] = null;
  161. $lv['pre_sale_quantity'] = null;
  162. if(isset($limit_data[$lv['goods_id']])){
  163. $lv['month_quota'] = $limit_data[$lv['goods_id']]['month_quota'];
  164. $lv['remaining_quantity'] = $limit_data[$lv['goods_id']]['remaining_quantity'];
  165. }
  166. if(isset($cloud_stock_agent_guota_list[$lv['goods_id']])){
  167. $lv['pre_sale_quantity'] = $cloud_stock_agent_guota_list[$lv['goods_id']]['pre_sale_quantity'];
  168. }
  169. $lv['weight'] = bcdiv($goodsWeight[$lv['goods_id']] ?? 0, 1000, 3); // 转为kg
  170. }
  171. $list['count'] = count($list['list']);
  172. $list['list'] = array_values($list['list']);
  173. $cloudStockGoodsList = CloudStockGoods::lists(['where'=>[['mall_id'=>$this->mall_id],['status'=>StatusEnum::ENABLED]]]);
  174. $goods_ids = array_column($cloudStockGoodsList,'goods_id');
  175. $total_num = CloudStockAgentGoods::find()->where(['mall_id' => $this->mall_id, 'user_id' => $this->user_id,'goods_id'=>$goods_ids, 'status' => StatusEnum::ENABLED])->sum('num');
  176. $all_stock = $total_num??0;
  177. $is_stock_assignment = \Yii::$app->services->setting->addons->get($this->mall_id, AddonsEnum::ADDONS_NAME_CLOUD_STOCK, 'basic')['is_stock_assignment'] ?? 1;
  178. return $this->success('success', compact('list', 'all_stock', 'is_stock_assignment'));
  179. }
  180. /**
  181. * @name:
  182. * @msg: 库存明细
  183. * @param {integer} $goods_id 商品id
  184. * @param {string} $date 搜索日期
  185. * @param {string} $record_type 搜索的记录类型,add:库存增加明细;sub:库存减少明细
  186. * @return {*}
  187. */
  188. public function actionStockDetails()
  189. {
  190. if (!\Yii::$app->request->isGet) {
  191. return $this->error('请求方式错误');
  192. }
  193. $page = \Yii::$app->request->get('page', 1);
  194. $limit = \Yii::$app->request->get('limit', $this->pageSize);
  195. $goods_id = \Yii::$app->request->get('goods_id');
  196. $date = \Yii::$app->request->get('date');
  197. // 记录类型,add:库存增加;sub:库存减少
  198. $record_type = \Yii::$app->request->get('record_type');
  199. if (empty($record_type) || !in_array($record_type, ['add', 'sub'])) return $this->error('参数错误');
  200. $wheres[] = ['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED];
  201. if (!empty($good_ids)) {
  202. $wheres[] = ['goods_id' => $goods_id];
  203. $goods = Goods::find()
  204. ->select('id,goods_name,price,cover_pic')
  205. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'id' => $good_ids, 'is_on_sale' => 1, 'is_attr' => 0])
  206. ->asArray()
  207. ->indexBy('id')
  208. ->all();
  209. }
  210. if (!empty($date)) {
  211. $start_time = strtotime($date . ' 00:00:00');
  212. $end_time = strtotime($date . ' 23:59:59');
  213. $wheres[] = ['and', ['>=', 'created_at', $start_time], ['<=', 'created_at', $end_time]];
  214. }
  215. if ('add' == $record_type) {
  216. $details = CloudStockIncreaseDetail::find()
  217. ->select('stock_log_id,num')
  218. ->where(['user_id' => $this->user_id, 'status' => StatusEnum::ENABLED])
  219. ->asArray()
  220. ->indexBy('stock_log_id')
  221. ->all();
  222. $log_ids = array_column($details, 'stock_log_id');
  223. } else {
  224. $details = CloudStockDeductionDetail::find()
  225. ->select('stock_log_id,num')
  226. ->where(['user_id' => $this->user_id, 'status' => StatusEnum::ENABLED])
  227. ->asArray()
  228. ->indexBy('stock_log_id')
  229. ->all();
  230. $log_ids = array_column($details, 'stock_log_id');
  231. }
  232. $wheres[] = ['id' => $log_ids];
  233. $params = [
  234. 'select' => 'id,mall_id,goods_id,changes_dir,order_id,order_type,changes_type,num,created_at',
  235. 'where' => $wheres,
  236. 'order' => 'created_at desc',
  237. 'page' => $page,
  238. 'limit' => $limit
  239. ];
  240. $detail_list = CloudStockGoodsStockLog::listPage($params);
  241. if (empty($detail_list['list'])) {
  242. if (!is_array($detail_list['list'])) return $this->error(CloudStockAgentGoods::getStaticError());
  243. return $this->success('success', $detail_list);
  244. }
  245. if (empty($goods)) {
  246. $good_ids = array_column($detail_list['list'], 'goods_id');
  247. $goods = Goods::find()
  248. ->select('id,goods_name,price,cover_pic')
  249. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'id' => $good_ids, 'is_on_sale' => 1, 'is_attr' => 0])
  250. ->asArray()
  251. ->indexBy('id')
  252. ->all();
  253. }
  254. foreach ($detail_list['list'] as &$list) {
  255. $good = $goods[$list['goods_id']] ?? [];
  256. $detail = $details[$list['id']] ?? [];
  257. $list['goods_name'] = $good['goods_name'] ?? '';
  258. $list['cover_pic'] = $good['cover_pic'] ?? '';
  259. $list['price'] = $good['price'] ?? 0;
  260. switch ($list['changes_type']) {
  261. // 上级补货数量
  262. case CloudStockEnum::STOCK_CHANGE_TYPE100:
  263. if (!isset($list['replenish_num'])) $list['replenish_num'] = 0;
  264. $list['replenish_num'] += $detail['num'] ?? 0;
  265. break;
  266. // 上级配货数量
  267. case CloudStockEnum::STOCK_CHANGE_TYPE101:
  268. if (!isset($list['prepare_num'])) $list['prepare_num'] = 0;
  269. $list['prepare_num'] += $detail['num'] ?? 0;
  270. break;
  271. // 退货退库存数量
  272. case CloudStockEnum::STOCK_CHANGE_TYPE102:
  273. if (!isset($list['refund_num'])) $list['refund_num'] = 0;
  274. $list['refund_num'] += $detail['num'] ?? 0;
  275. break;
  276. // 系统添加数量
  277. case CloudStockEnum::STOCK_CHANGE_TYPE103:
  278. if (!isset($list['sys_add_num'])) $list['sys_add_num'] = 0;
  279. $list['sys_add_num'] += $detail['num'] ?? 0;
  280. break;
  281. // 平台补货赠送数量
  282. case CloudStockEnum::STOCK_CHANGE_TYPE104:
  283. if (!isset($list['platfrom_give_num'])) $list['platfrom_give_num'] = 0;
  284. $list['platfrom_give_num'] += $detail['num'] ?? 0;
  285. break;
  286. // 购买礼包赠送数量
  287. case CloudStockEnum::STOCK_CHANGE_TYPE105:
  288. if (!isset($list['buy_gift_give_num'])) $list['buy_gift_give_num'] = 0;
  289. $list['buy_gift_give_num'] += $detail['num'] ?? 0;
  290. break;
  291. // 会员买货数量
  292. case CloudStockEnum::STOCK_CHANGE_TYPE200:
  293. if (!isset($list['member_buy_num'])) $list['member_buy_num'] = 0;
  294. $list['member_buy_num'] += $detail['num'] ?? 0;
  295. break;
  296. // 给下级配货数量
  297. case CloudStockEnum::STOCK_CHANGE_TYPE201:
  298. if (!isset($list['issue_num'])) $list['issue_num'] = 0;
  299. $list['issue_num'] += $detail['num'] ?? 0;
  300. break;
  301. // 下级向自己补货数量
  302. case CloudStockEnum::STOCK_CHANGE_TYPE202:
  303. if (!isset($list['sub_user_replenish_num'])) $list['sub_user_replenish_num'] = 0;
  304. $list['sub_user_replenish_num'] += $detail['num'] ?? 0;
  305. break;
  306. // 自提货到线下数量
  307. case CloudStockEnum::STOCK_CHANGE_TYPE203:
  308. if (!isset($list['pick_to_offline_num'])) $list['pick_to_offline_num'] = 0;
  309. $list['pick_to_offline_num'] += $detail['num'] ?? 0;
  310. break;
  311. // 系统扣减数量
  312. case CloudStockEnum::STOCK_CHANGE_TYPE204:
  313. if (!isset($list['sys_sub_num'])) $list['sys_sub_num'] = 0;
  314. $list['sys_sub_num'] += $detail['num'] ?? 0;
  315. break;
  316. default:
  317. break;
  318. }
  319. }
  320. $user = ArrayHelper::toArray($this->stock_agent->user);
  321. $stock_change_type_map = CloudStockEnum::getStockChangeTypeMap();
  322. $stock_change_dir_map = CloudStockEnum::getStockChangeDirMap();
  323. return $this->success('success', compact('detail_list', 'user', 'stock_change_type_map', 'stock_change_dir_map'));
  324. }
  325. public function actionStockDetail()
  326. {
  327. if (!\Yii::$app->request->isGet) {
  328. return $this->error('请求方式错误');
  329. }
  330. $page = \Yii::$app->request->get('page', 1);
  331. $limit = \Yii::$app->request->get('limit', $this->pageSize);
  332. $date = \Yii::$app->request->get('date');
  333. $goods_id = \Yii::$app->request->get('goods_id');
  334. // 记录类型,add:库存增加;sub:库存减少
  335. $record_type = \Yii::$app->request->get('record_type');
  336. if (empty($record_type) || !in_array($record_type, ['add', 'sub'])) return $this->error('参数错误');
  337. $wheres[] = ['user_id' => $this->user_id];
  338. $wheres[] = ['user_id' => $this->user_id];
  339. if (!empty($date)) {
  340. $date = date($date . '-01');
  341. } else {
  342. $date = date('Y-m-01');
  343. }
  344. $start_time = strtotime($date);
  345. $end_time = strtotime($date . '+1 month -1 day 23:59:59');
  346. $wheres[] = ['and', ['>=', 'created_at', $start_time], ['<=', 'created_at', $end_time]];
  347. !empty($goods_id) && $wheres[] = ['goods_id' => $goods_id];
  348. if ('add' == $record_type) {
  349. $params = [
  350. 'where' => $wheres,
  351. 'order' => 'created_at desc',
  352. 'page' => $page,
  353. 'limit' => $limit
  354. ];
  355. $detail_list = CloudStockIncreaseDetail::listPage($params);
  356. } else {
  357. $params = [
  358. 'where' => $wheres,
  359. 'order' => 'created_at desc',
  360. 'page' => $page,
  361. 'limit' => $limit
  362. ];
  363. $detail_list = CloudStockDeductionDetail::listPage($params);
  364. }
  365. if (!empty($detail_list['list'])) {
  366. $goods_id_arr = array_column($detail_list['list'], 'goods_id');
  367. $goods_list = Goods::find()
  368. ->select('id,goods_name,price,cover_pic')
  369. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'id' => $goods_id_arr])
  370. ->asArray()
  371. ->indexBy('id')
  372. ->all();
  373. foreach ($detail_list['list'] as &$item) {
  374. $item['goods_name'] = $item['cover_pic'] = '';
  375. $item['price'] = 0;
  376. $item['changes_dir'] = 'add' == $record_type ? 1 : 2;
  377. if (isset($goods_list[$item['goods_id']])) {
  378. $item['goods_name'] = $goods_list[$item['goods_id']]['goods_name'];
  379. $item['cover_pic'] = $goods_list[$item['goods_id']]['cover_pic'];
  380. $item['price'] = $goods_list[$item['goods_id']]['price'];
  381. }
  382. }
  383. }
  384. $user = ArrayHelper::toArray($this->stock_agent->user);
  385. $stock_change_type_map = CloudStockEnum::getStockChangeTypeMap();
  386. $stock_change_dir_map = CloudStockEnum::getStockChangeDirMap();
  387. return $this->success('success', compact('detail_list', 'user', 'stock_change_type_map', 'stock_change_dir_map'));
  388. }
  389. /**
  390. * @name:
  391. * @msg: 给下级配货
  392. * @param {*}
  393. * @return {*}
  394. */
  395. public function actionIssueGive()
  396. {
  397. try {
  398. if (!\Yii::$app->request->isPost) {
  399. return $this->error('请求方式错误');
  400. }
  401. $post = \Yii::$app->request->post();
  402. $rules = [
  403. [['goods_id', 'number', 'target_user_id'], 'required'],
  404. [['goods_id', 'number', 'target_user_id'], 'integer'],
  405. ];
  406. $res = \Yii::$app->services->validate->validate($post, $rules);
  407. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  408. $post['user_id'] = $this->user_id;
  409. $post['type'] = 1;
  410. $post['mall_id'] = $this->mall_id;
  411. $model = CloudStockDispenseOrder::addData($post);
  412. $res = CloudStockGoodsStockLog::stockHandle($this->mall_id, $post, CloudStockEnum::STOCK_CHANGE_TYPE201);
  413. if (false === $res) return $this->error(CloudStockGoodsStockLog::getStaticError());
  414. $data = [];
  415. $event = new DispenseEvent($model['mall_id']);
  416. $data['id'] = $model['id'];
  417. \Yii::$app->services->events->dispatch($event, $data, $event->listeners);
  418. return $this->success('操作成功');
  419. } catch (\Exception $e) {
  420. return $this->error($e->getMessage());
  421. }
  422. }
  423. /**
  424. * @name:
  425. * @msg: 提货到线下
  426. * @param {integer} $goods_id 商品id
  427. * @return {*}
  428. */
  429. public function actionGoodDetail()
  430. {
  431. if (!\Yii::$app->request->isGet) {
  432. return $this->error('请求方式错误');
  433. }
  434. $goods_id = \Yii::$app->request->get('goods_id');
  435. if (empty($goods_id)) return $this->error('参数错误');
  436. $good = Goods::find()
  437. ->select('id,mall_id,goods_name,cover_pic,price,stock')
  438. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'id' => $goods_id, 'is_on_sale' => 1, 'is_attr' => 0])
  439. ->limit(1)
  440. ->asArray()
  441. ->one();
  442. $stock_good = CloudStockGoods::findOne(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'goods_id' => $goods_id]);
  443. if (empty($good)) return $this->error('商品数据异常');
  444. $good['weight'] = bcdiv(GoodsAttr::find()
  445. ->where([
  446. 'goods_id' => $goods_id,
  447. 'status' => StatusEnum::ENABLED,
  448. ])
  449. ->select('weight')
  450. ->scalar() ?: 0, 1000, 3);
  451. $configs = \Yii::$app->services->setting->addons->get($this->mall_id, AddonsEnum::ADDONS_NAME_CLOUD_STOCK, 'basic');
  452. $unitArr = [1 => 'kg', 2 => '件'];
  453. $good['config'] = [
  454. 'is_enable_order_num_limit' => $configs['is_enable_order_num_limit'] ?? 0,
  455. 'unit' => $configs['order_limit_type'] ?? 2,
  456. 'limit_num' => $configs['order_limit_num'] ?? 0,
  457. ];
  458. $good['config']['unit_text'] = $unitArr[$good['config']['unit']] ?? '-';
  459. $agent_price = json_decode($stock_good['agent_price'],true);
  460. $agent_price = array_column($agent_price,null,'level');
  461. $replenish_price = 0;
  462. $replenish_price_list = [];
  463. if(!empty($agent_price[$this->stock_agent->level])){
  464. $replenish_price = $agent_price[$this->stock_agent->level]['price'];
  465. $replenish_price_list = $agent_price[$this->stock_agent->level]['price_list'];
  466. }
  467. $all_stocks = CloudStockGoods::allPerantAgentGoodStocks($goods_id, $this->user_id, $this->mall_id);
  468. if (false === $all_stocks) {
  469. return $this->error(CloudStockGoods::getStaticError());
  470. }
  471. $good['replenish_price'] = $replenish_price;
  472. $good['profit'] = bcsub($good['price'], $replenish_price, 2);
  473. $good['pick_number_limit'] = $all_stocks;
  474. $good['is_allow_fill'] = $stock_good->is_allow_fill;
  475. $good['remind_text'] = '';
  476. $cloud_stock_level = CloudStockLevel::findOne(['mall_id'=>$this->mall_id,'status'=>StatusEnum::ENABLED,'level'=>$this->stock_agent->level]);
  477. if(!empty($cloud_stock_level) && !empty($cloud_stock_level['is_open_fill_min_once'])){
  478. $good['remind_text'] = '一次性提货最低需提'.$cloud_stock_level['fill_min_once'].'件,最高可提'.$cloud_stock_level['fill_max_once'].'件';
  479. }
  480. $good['is_take_by_range'] = $stock_good['is_take_by_range'];
  481. $good['replenish_price_list'] = $replenish_price_list;
  482. // 获取设置
  483. $configs = \Yii::$app->services->setting->addons->get($this->mall_id, AddonsEnum::ADDONS_NAME_CLOUD_STOCK, 'basic');
  484. $good['is_enable_rand_fee'] = $configs['is_enable_rand_fee'] ?? 0;
  485. $good['condition'] = json_decode($configs['rand_condition'],true);
  486. $good['is_enable_freight_charges'] = $configs['is_enable_freight_charges'] ?? 0;
  487. $good['min_replenish'] = $stock_good['min_replenish'];
  488. $good['give_text'] = '';
  489. if(isset($stock_good['is_buhuo']) && $stock_good['is_buhuo'] == 1){
  490. $coupon = CouponSetting::getGiveCoupon($this->mall_id,[['goods_id'=>$good['id'],'num'=>0]],$this->stock_agent->level);
  491. if(empty($coupon) == false){
  492. $good['give_text'] = '当前商品一次性补货每满'.$coupon[$good['id']]['rule_num'].'件('.$coupon[$good['id']]['rule_num'].'的整数倍),可获得';
  493. $coupon_text = [];
  494. foreach ($coupon[$good['id']]['coupon_arr'] as $arr){
  495. $coupon_text[] = $arr['num'].'张“'.$arr['name'].'”';
  496. }
  497. $good['give_text'] .= implode('、',$coupon_text).'优惠券';
  498. }
  499. }
  500. return $this->success('success', $good);
  501. }
  502. /**
  503. * @name:
  504. * @msg: 提货到线下
  505. * @param {integer} addr_id 地址 id
  506. * @param {integer} goods_id 商品 id
  507. * @param {integer} number 提货数量
  508. * @param {string} password 交易密码
  509. * @return {*}
  510. */
  511. public function actionPickOffline()
  512. {
  513. if (!\Yii::$app->request->isPost) {
  514. return $this->error('请求方式错误');
  515. }
  516. $post = \Yii::$app->request->post();
  517. $rules = [
  518. [['addr_id'], 'required'],
  519. [['addr_id', 'goods_id', 'number'], 'integer'],
  520. [['password','remark'], 'string'],
  521. [['pay_money'], 'number'],
  522. ];
  523. $res = \Yii::$app->services->validate->validate($post, $rules);
  524. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  525. $balance_pay_setting = json_decode(\Yii::$app->services->setting->mall->get($this->mall_id, 'pay.balance'), 'true');
  526. if (!empty($balance_pay_setting['pay_password_status'])) {
  527. $user = User::findOne(['id' => $this->user_id]);
  528. if (empty($user->transaction_password)) {
  529. return $this->error('您未设置支付密码');
  530. }
  531. if (empty($post['password'])) {
  532. return $this->error('请输入交易密码');
  533. }
  534. if (!\Yii::$app->security->validatePassword(trim($post['password']), $user->transaction_password)) {
  535. return $this->error('支付密码错误');
  536. }
  537. }
  538. $post['user_id'] = $this->user_id;
  539. $post['mall_id'] = $this->mall_id;
  540. $post['stock_agent'] = $this->stock_agent;
  541. // dd($post);
  542. // 提货到线下
  543. $res = CloudStockAgentOrder::pickOffline($this->mall_id, $post);
  544. if (false === $res) return $this->error('提货失败:' . CloudStockAgentOrder::getStaticError());
  545. //生成运费订单流水
  546. if($res->send_status == CloudStockEnum::PICK_ORDER_STATUS3){
  547. //生成支付流水
  548. $order_trade_info[] = [
  549. 'order_no' => $res->order_no,
  550. 'amount' => $res->pay_money,
  551. 'title' => '云库存自提订单',
  552. 'notify_class' => PickOfflinePayNotify::class,
  553. 'order_type' => AddonsEnum::ADDONS_NAME_CLOUD_STOCK,
  554. ];
  555. $res_trade = \Yii::$app->services->pay->createTrade($this->mall_id, $this->user_id, $order_trade_info);
  556. if ($res_trade == false) return $this->error('生成支付流水失败');
  557. $res->trade_id = $res_trade['trade_id'];
  558. $res->trade_no = $res_trade['trade_no'];
  559. if(!$res->save()) return $this->error('数据保存失败');
  560. return $this->success('提货成功',['trade_no' => $res_trade['trade_no'], 'trade_id' => $res_trade['trade_id'], 'order_ids' => $res->id]);
  561. }
  562. return $this->success('提货成功');
  563. }
  564. /**
  565. * 重新支付
  566. *
  567. * @return void
  568. */
  569. public function actionRePay()
  570. {
  571. $params = \Yii::$app->request->post();
  572. $res = \Yii::$app->services->validate->validate($params, [
  573. [['order_id'], 'required'],
  574. [['order_id'], 'integer'],
  575. ]);
  576. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  577. $res = CloudStockAgentOrder::getOne(
  578. [
  579. [
  580. 'id' => $params['order_id'],
  581. 'mall_id' => $this->mall_id,
  582. 'user_id' => $this->user_id,
  583. 'send_status' => CloudStockEnum::PICK_ORDER_STATUS3,
  584. ]
  585. ]
  586. );
  587. if (empty($res)) {
  588. return $this->error('未查询到待支付订单');
  589. }
  590. //生成支付流水
  591. $order_trade_info[] = [
  592. 'order_no' => $res->order_no,
  593. 'amount' => $res->pay_money,
  594. 'title' => '云库存自提订单',
  595. 'notify_class' => PickOfflinePayNotify::class,
  596. 'order_type' => AddonsEnum::ADDONS_NAME_CLOUD_STOCK,
  597. ];
  598. $res_trade = \Yii::$app->services->pay->createTrade($this->mall_id, $this->user_id, $order_trade_info);
  599. if ($res_trade == false) return $this->error('生成支付流水失败');
  600. $res->trade_id = $res_trade['trade_id'];
  601. $res->trade_no = $res_trade['trade_no'];
  602. if(!$res->save()) return $this->error('数据保存失败');
  603. return $this->success('success', ['trade_no' => $res_trade['trade_no'], 'trade_id' => $res_trade['trade_id'], 'order_ids' => $res->id]);
  604. }
  605. public function actionUpgradeGoodsList(){
  606. $params = \Yii::$app->request->get();
  607. $res = \Yii::$app->services->validate->validate($params, [
  608. [['limit', 'page','keyword'], 'safe']
  609. ]);
  610. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  611. $where[] = ['g.mall_id' => $this->mall_id];
  612. $where[] = ['g.status' => [StatusEnum::ENABLED]];
  613. $where[] = ['g.is_on_sale' => 1];
  614. $where[] = ['g.is_show' => 1];
  615. if (isset($params['keyword'])) {
  616. $where[] = ['like', 'g.goods_name', trim($params['keyword'])];
  617. }
  618. $goods_ids = [];
  619. $level_list = CloudStockLevel::lists(['where'=>[['mall_id'=>$this->mall_id],['status'=>StatusEnum::ENABLED],['upgrade_type_condition'=>1]]]);
  620. if(!empty($level_list)){
  621. foreach($level_list as $level){
  622. $checked_condition_values = json_decode($level['checked_condition_values'], true);
  623. $checked_condition_keys = json_decode($level['checked_condition_keys'], true);
  624. if(in_array(0,$checked_condition_keys) && !empty($checked_condition_values)){
  625. if(isset($checked_condition_values[0]['value'])){
  626. $goods_ids = array_merge($goods_ids,array_column($checked_condition_values[0]['value'],'goods_id'));
  627. }
  628. }
  629. }
  630. }
  631. $where[] = ['g.id'=>$goods_ids];
  632. $params['where'] = $where;
  633. $params['alias'] = 'g';
  634. $params['select'] = 'g.id,g.goods_name,g.cover_pic,g.price,g.original_price';
  635. $goods_list = Goods::listPage($params);
  636. return $this->success('操作成功', $goods_list);
  637. }
  638. /**
  639. * 订单预览
  640. * @Author bing
  641. * @DateTime 2021-09-24 19:46:46
  642. * @return void
  643. * @copyright: Copyright (c) 2020 广东七件事集团
  644. */
  645. public function actionPreview()
  646. {
  647. try {
  648. if (!\Yii::$app->request->isPost) {
  649. return $this->error('请求方式错误');
  650. }
  651. $post = \Yii::$app->request->post();
  652. $rules = [
  653. [['addr_id'], 'required'],
  654. [['addr_id', 'goods_id', 'number'], 'integer'],
  655. ];
  656. $res = \Yii::$app->services->validate->validate($post, $rules);
  657. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  658. // 获取收货地址
  659. $address_info = UserAddress::getUserAddress($this->user_id, $post['addr_id']);
  660. if (empty($address_info)) {
  661. $this->error('收货地址不存在');
  662. return;
  663. }
  664. $baseParams = ['mall_id' => $this->mall_id, 'user_id' => $this->user_id, 'stock_agent' => $this->stock_agent];
  665. $goodsService = new CloudStockAgentGoodsService($baseParams);
  666. $orderService = new CloudStockAgentOrderService($baseParams);
  667. $cartService = new CloudStockAgentCartService($baseParams);
  668. if (!empty($post['goods_id']) && !empty($post['number'])) {
  669. $freightAttr[] = ['goods_id' => $post['goods_id'], 'num' => $post['number']];
  670. } else {
  671. $cartList = $cartService->getCartList();
  672. // 购物车
  673. foreach ($cartList as $cartItem) {
  674. if (empty($cartItem['goods_id']) || empty($cartItem['num'])) {
  675. continue;
  676. }
  677. $freightAttr[] = [
  678. 'goods_id' => $cartItem['goods_id'],
  679. 'num' => $cartItem['num']
  680. ];
  681. }
  682. }
  683. if (empty($freightAttr)) {
  684. $this->error('未选择提货商品');
  685. return;
  686. }
  687. $form = $orderService->getForm($goodsService, $this->mall_id, $this->user_id, $post['addr_id'], $freightAttr);
  688. $form->attributes = [
  689. 'type' => PreviewTypeEnum::FREIGHT,
  690. 'data' => [
  691. 'shipping_type' => ShippingTypeEnum::LOGISTICS,
  692. 'freight_attr' => $freightAttr,
  693. 'address_id' => $post['addr_id']
  694. ]
  695. ];
  696. $group_order_goods = $form['group_order_goods'];
  697. $group_order_goods_list = [];
  698. foreach ($group_order_goods as $val){
  699. $group_order_goods_list[]=$val;
  700. }
  701. $marketing = $form['marketing']??[];
  702. $pay_type_list = \Yii::$app->services->pay->getEnablePayment($this->mall_id, $this->platform);
  703. if($form['total_pay_money']<=0){
  704. $tmp = [];
  705. foreach ($pay_type_list as $item){
  706. if($item['trade_type']=='default'){
  707. $tmp[]=$item;
  708. break;
  709. }
  710. }
  711. $pay_type_list = $tmp;
  712. }
  713. $shipping_type_list = $form->type == PreviewTypeEnum::RESERVE_NOW ? ShippingTypeEnum::getReserveMap() : ShippingTypeEnum::getMap();
  714. $option_list = [];
  715. $group_order_goods = $group_order_goods_list;
  716. $extends_fields = [];
  717. $info = compact('group_order_goods', 'marketing', 'address_info', 'pay_type_list', 'shipping_type_list', 'option_list', 'extends_fields');
  718. if($form['total_pay_money'] < 0) $form['total_pay_money'] = 0;
  719. $info['total_pay_money'] = '¥' . $form['total_pay_money'];
  720. $info['is_address'] = $form['is_address'] ?? 0;
  721. $info['is_virtual'] = $form['is_virtual'] ?? 0;
  722. $info['is_sign_agreement'] = $form['is_sign_agreement'] ?? 0;
  723. $info['shipping_type'] = $form->data['shipping_type'] ?? null;
  724. $info['pay_money'] = 0;
  725. if(!empty($info['marketing']['deduct'])){
  726. foreach($info['marketing']['deduct'] as $key => $item){
  727. if($key != 'shipping_fee'){
  728. unset($info['marketing']['deduct'][$key]);
  729. }else{
  730. $info['total_pay_money'] = '¥' . $item['money'];
  731. $info['pay_money'] = $item['money'];
  732. }
  733. }
  734. }
  735. return $this->success('操作成功', $info);
  736. }catch (\Exception $e){
  737. return $this->error($e->getMessage());
  738. }
  739. }
  740. public function actionAgentStock(){
  741. $is_mycat = \Yii::$app->params['is_mycat'];
  742. $params = \Yii::$app->request->get();
  743. if(isset($is_mycat)&&$is_mycat==true){
  744. $child_user_ids = UserPartitionRelationship::getChildIdArr($this->user_id);
  745. $where[] = ['=', 'mall_id', $this->mall_id];
  746. $where[] = ['in', 'status', [StatusEnum::DISABLED, StatusEnum::ENABLED]];
  747. $where[] = ['in', 'user_id', $child_user_ids];
  748. $params['order'] = 'stock desc';
  749. $params['where'] = $where;
  750. $params['select'] = 'id,user_id,stock,level';
  751. $params['with'] = 'user';
  752. $page_data = CloudStockAgent::listPage($params, false);
  753. }else{
  754. // 联表查询
  755. $joins = [
  756. ['LEFT JOIN', UserPartitionRelationship::tableName() . 'upr', 'upr.user_id = csa.user_id'],
  757. ];
  758. $user_ship = UserPartitionRelationship::findOne(['user_id'=>$this->user_id]);
  759. $tree = $user_ship['tree'];
  760. $where[] = ['<>', 'upr.user_id', $this->user_id];
  761. $where[] = ['like', 'upr.tree', "{$tree},%", false];
  762. $where[] = ['in', 'csa.status', [StatusEnum::DISABLED, StatusEnum::ENABLED]];
  763. $select = 'csa.id,csa.user_id,csa.stock,csa.level';
  764. $order = 'csa.stock desc';
  765. $params['alias'] = 'csa';
  766. $params['select'] = $select;
  767. $params['where'] = $where;
  768. $params['with'] = 'user';
  769. $params['join'] = $joins;
  770. $params['order'] = $order;
  771. $page_data = CloudStockAgent::listPage($params, false, true);
  772. }
  773. if (!empty($page_data['list'])) {
  774. $level_arr = array_column($page_data['list'], 'level');
  775. $user_ids = array_column($page_data['list'], 'user_id');
  776. $level_list = CloudStockLevel::lists(['where' => [['mall_id' => $this->mall_id], ['level' => $level_arr], ['status' => StatusEnum::ENABLED]], 'index' => 'level']);
  777. $cloudStockGoodsList = CloudStockGoods::lists(['where'=>[['mall_id'=>$this->mall_id],['status'=>StatusEnum::ENABLED]]]);
  778. $goods_ids = array_column($cloudStockGoodsList,'goods_id');
  779. $agent_goods_list = CloudStockAgentGoods::lists(['where' => [['user_id' => $user_ids],['goods_id'=>$goods_ids],['status'=>StatusEnum::ENABLED]], 'select' => 'sum(num) num ,user_id', 'group' => 'user_id', 'index' => 'user_id']);
  780. foreach ($page_data['list'] as &$item) {
  781. $item['level_name'] = $level_list[$item['level']]['name'] ?? '';
  782. $item['total_stock_num'] = 0;
  783. if (isset($agent_goods_list[$item['user_id']])) $item['total_stock_num'] = $agent_goods_list[$item['user_id']]['num'];
  784. unset($item['stock']);
  785. }
  786. }
  787. return $this->success('操作成功', $page_data);
  788. }
  789. public function actionAgentStockSum(){
  790. $is_mycat = \Yii::$app->params['is_mycat'];
  791. $cloudStockGoodsList = CloudStockGoods::lists(['where'=>[['mall_id'=>$this->mall_id],['status'=>StatusEnum::ENABLED]]]);
  792. $goods_ids = array_column($cloudStockGoodsList,'goods_id');
  793. if(isset($is_mycat)&&$is_mycat==true){
  794. $child_user_ids = UserPartitionRelationship::getChildIdArr($this->user_id);
  795. $stock = CloudStockAgentGoods::find()->where(['mall_id'=> $this->mall_id,'user_id'=>$child_user_ids,'goods_id'=>$goods_ids,'status'=>StatusEnum::ENABLED])->sum('num');
  796. }else{
  797. $user_ship = UserPartitionRelationship::findOne(['user_id'=>$this->user_id]);
  798. $tree = $user_ship['tree'];
  799. $stock = CloudStockAgentGoods::find()->alias('csa')
  800. ->leftJoin( UserPartitionRelationship::tableName() . 'upr','upr.user_id = csa.user_id')
  801. ->where(['csa.mall_id'=> $this->mall_id,'csa.goods_id'=>$goods_ids,'csa.status'=>StatusEnum::ENABLED])
  802. ->andWhere(['<>', 'upr.user_id', $this->user_id])
  803. ->andWhere(['like', 'upr.tree', "{$tree},%", false])
  804. ->sum('csa.num');
  805. }
  806. return $this->success('操作成功', ['stock'=>$stock??0,'goods_num'=>count($goods_ids)]);
  807. }
  808. public function actionAgentStockDetail(){
  809. $params = \Yii::$app->request->get();
  810. $rules = [
  811. [['user_id',], 'required'],
  812. ];
  813. $res = \Yii::$app->services->validate->validate($params, $rules);
  814. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  815. $user_id = $params['user_id'];
  816. $parent_user_ids = UserPartitionRelationship::getParentIdArr($user_id);
  817. if(!in_array($this->user_id,$parent_user_ids)) return $this->error('该会员不属于你的团队');
  818. $params['where'] = [['mall_id'=>$this->mall_id],['status'=>StatusEnum::ENABLED]];
  819. $params['select'] = 'goods_id';
  820. $cloudStockGoodsList = CloudStockGoods::listPage($params);
  821. if (!empty($cloudStockGoodsList['list'])) {
  822. $goods_ids = array_column($cloudStockGoodsList['list'],'goods_id');
  823. $agent_goods_list = CloudStockAgentGoods::lists([
  824. 'where'=>[['user_id' => $user_id],['goods_id'=>$goods_ids],['status'=>StatusEnum::ENABLED]],
  825. 'select'=>'goods_id,num as stock',
  826. 'index'=>'goods_id'
  827. ]);
  828. $goods_list = Goods::lists(['where' => [['id'=>$goods_ids],['status'=>StatusEnum::ENABLED]],'index'=>'id']);
  829. foreach ($cloudStockGoodsList['list'] as &$item) {
  830. $item['goods_name'] = '';
  831. $item['cover_pic'] = '';
  832. $item['stock'] = 0;
  833. if (isset($goods_list[$item['goods_id']])) {
  834. $item['goods_name'] = $goods_list[$item['goods_id']]['goods_name'];
  835. $item['cover_pic'] = $goods_list[$item['goods_id']]['cover_pic'];
  836. }
  837. if (isset($agent_goods_list[$item['goods_id']])) {
  838. $item['stock'] = $agent_goods_list[$item['goods_id']]['stock'];
  839. }
  840. }
  841. }
  842. return $this->success('操作成功',$cloudStockGoodsList);
  843. }
  844. public function actionAgentStockDetailSum(){
  845. $params = \Yii::$app->request->get();
  846. $rules = [
  847. [['user_id',], 'required'],
  848. ];
  849. $res = \Yii::$app->services->validate->validate($params, $rules);
  850. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  851. $user_id = $params['user_id'];
  852. $parent_user_ids = UserPartitionRelationship::getParentIdArr($user_id);
  853. if(!in_array($this->user_id,$parent_user_ids)) return $this->error('该会员不属于你的团队');
  854. $cloud_stock_agent = CloudStockAgent::findOne(['user_id'=>$user_id,'status'=>StatusEnum::ENABLED]);
  855. if(empty($cloud_stock_agent)) return $this->error('代理部存在');
  856. $cloudStockGoodsList = CloudStockGoods::lists(['where'=>[['mall_id'=>$this->mall_id],['status'=>StatusEnum::ENABLED]]]);
  857. $goods_ids = array_column($cloudStockGoodsList,'goods_id');
  858. $stock = CloudStockAgentGoods::find()->where(['mall_id'=> $this->mall_id,'user_id'=>$user_id,'goods_id'=>$goods_ids,'status'=>StatusEnum::ENABLED])->sum('num');
  859. $user = User::getOne([['id' =>$user_id]],true,[],false,['id', 'nickname', 'avatar_url', 'mobile', 'parent_id']);
  860. $level_arr = CloudStockLevel::getOne( [['mall_id' => $this->mall_id], ['level' => $cloud_stock_agent['level']], ['status' => StatusEnum::ENABLED]]);
  861. $user['level'] = $cloud_stock_agent['level']??'';
  862. $user['level_name'] = $level_arr['name']??'';
  863. return $this->success('操作成功', ['stock'=>$stock??0,'goods_num'=>count($goods_ids),'user'=>$user]);
  864. }
  865. }