CartController.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. <?php
  2. namespace addons\Store\api\modules\v1\controllers;
  3. use addons\Store\common\models\Store;
  4. use addons\Store\common\models\StoreCart;
  5. use addons\Store\common\models\StoreGoods;
  6. use addons\Store\common\models\StoreGoodsAttr;
  7. use addons\Store\common\models\StoreOrderDetail;
  8. use addons\Store\common\services\StoreService;
  9. use api\controllers\OnAuthController;
  10. use common\enums\StatusEnum;
  11. use common\models\user\UserLevel;
  12. use function Clue\StreamFilter\fun;
  13. /**
  14. * Class CartController
  15. * @package api\modules\goods\controllers
  16. */
  17. class CartController extends OnAuthController
  18. {
  19. public $modelClass = '';
  20. /**
  21. * 不用进行登录验证的方法
  22. * 例如: ['index', 'update', 'create', 'view', 'delete']
  23. * 默认全部需要验证
  24. *
  25. * @var array
  26. */
  27. protected $authOptional = ['index'];
  28. /**
  29. * 添加购物车
  30. * @return mixed|void
  31. */
  32. public function actionAdd()
  33. {
  34. try {
  35. $params = \Yii::$app->request->post();
  36. $res = \Yii::$app->services->validate->validate($params, [
  37. [['goods_id','attr_id', 'num'], 'required'],
  38. ]);
  39. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  40. $goods = StoreGoods::getOne([
  41. ['id'=>$params['goods_id']],
  42. ['status'=>StatusEnum::ENABLED],
  43. [ 'is_on_sale'=>1],
  44. ['check_status'=>1],
  45. ],true,['extra']);
  46. if (empty($params['num'])) return $this->error("请输入数量");
  47. if (empty($goods)) return $this->error("商品不存在");
  48. if(!empty($goods['goods_source'])) return $this->error('该商品不允许加入购物车');
  49. // 没有规格id则查找默认规格【寻找价格最低的规格】
  50. $where = ['goods_id' => $params['goods_id'], 'status' => StatusEnum::ENABLED];
  51. !empty($params['attr_id']) && $where['id'] = $params['attr_id'];
  52. $goods_attr = StoreGoodsAttr::find()->where($where)->orderBy('price asc')->one();
  53. if($goods_attr->goods_id!=$params['goods_id']) return $this->error("goods_id与attr_id不配对");
  54. $cart_goods_nums = StoreCart::getCartGoodsNums($this->user_id,$params['attr_id']);
  55. $goods['num'] = $params['num']+$cart_goods_nums;
  56. $this->userLimit($this->user,$goods);
  57. if (empty($goods['is_attr'])) {
  58. if (empty($goods['stock'])) return $this->error('库存不足');
  59. if($goods['num']>$goods['stock'])return $this->error('超库存');
  60. } else {
  61. //多规格
  62. if (empty($goods_attr)) return $this->error("所选的规格不存在");
  63. if (empty($goods_attr['stock'])) return $this->error("所选的规格库存不足");
  64. if($goods['num']>$goods_attr['stock'])return $this->error('超库存');
  65. }
  66. $params['store_id'] = $goods['store_id'];
  67. $params['mall_id'] = $this->mall_id;
  68. $params['user_id'] = $this->user_id;
  69. StoreCart::addCart($params);
  70. return $this->success('加入购物车成功', []);
  71. }catch (\Exception $e){
  72. return $this->error($e->getMessage(), []);
  73. }
  74. }
  75. public function actionUpdateCart()
  76. {
  77. try {
  78. $params = \Yii::$app->request->post();
  79. $res = \Yii::$app->services->validate->validate($params, [
  80. [['goods_id','attr_id', 'num'], 'required'],
  81. ]);
  82. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  83. $goods = StoreGoods::getOne([
  84. ['id'=>$params['goods_id']],
  85. ['status'=>StatusEnum::ENABLED],
  86. [ 'is_on_sale'=>1],
  87. ['check_status'=>1],
  88. ],true,['extra']);
  89. if (empty($params['num'])) return $this->error("请输入数量");
  90. if (empty($goods)) return $this->error("商品不存在");
  91. if(!empty($goods['goods_source'])) return $this->error('该商品不允许加入购物车');
  92. // 没有规格id则查找默认规格【寻找价格最低的规格】
  93. $where = ['goods_id' => $params['goods_id'], 'status' => StatusEnum::ENABLED];
  94. !empty($params['attr_id']) && $where['id'] = $params['attr_id'];
  95. $goods_attr = StoreGoodsAttr::find()->where($where)->orderBy('price asc')->one();
  96. if($goods_attr->goods_id!=$params['goods_id']) return $this->error("goods_id与attr_id不配对");
  97. $goods['num'] = $params['num'];
  98. $this->userLimit($this->user,$goods);
  99. if (empty($goods['is_attr'])) {
  100. if (empty($goods['stock'])) return $this->error('库存不足');
  101. if($goods['num']>$goods['stock'])return $this->error('超库存');
  102. } else {
  103. //多规格
  104. if (empty($goods_attr)) return $this->error("所选的规格不存在");
  105. if (empty($goods_attr['stock'])) return $this->error("所选的规格库存不足");
  106. if($goods['num']>$goods_attr['stock'])return $this->error('超库存');
  107. }
  108. $params['store_id'] = $goods['store_id'];
  109. $params['mall_id'] = $this->mall_id;
  110. $params['user_id'] = $this->user_id;
  111. StoreCart::updateCart($params);
  112. return $this->success('修改购物车成功', []);
  113. }catch (\Exception $e){
  114. return $this->error($e->getMessage(), []);
  115. }
  116. }
  117. protected function userLimit($user,$goods){
  118. $extra = $goods['extra'];
  119. if(!empty($extra)){
  120. $member_buy_limit_setting = json_decode($extra['member_buy_limit_setting'],true);
  121. if (!empty($member_buy_limit_setting['member_level'])) {
  122. if (!in_array($user->level, $member_buy_limit_setting['member_level'])) {
  123. throw new \Exception('该商品为指定会员购买请升级购买');
  124. }
  125. }
  126. if ($member_buy_limit_setting['nums'] > $goods['num']) {
  127. throw new \Exception('该商品起购数量为' . $member_buy_limit_setting['nums']);
  128. }
  129. if ($member_buy_limit_setting['every_num'] < $goods['num'] && $member_buy_limit_setting['every_num'] != 0) {
  130. throw new \Exception('该商品每次限购' . $member_buy_limit_setting['every_num']);
  131. }
  132. $already_buy = $this->statisticsBuyGoodsId($goods['goods_id'] ?? 0, $user['id']);
  133. if ($member_buy_limit_setting['total_num'] < $goods['num'] + $already_buy['all'] && $member_buy_limit_setting['total_num'] != 0) {
  134. throw new \Exception('该商品限购' . $member_buy_limit_setting['total_num']);
  135. }
  136. if ($member_buy_limit_setting['every_day_num'] < $goods['num'] + $already_buy['day'] && $member_buy_limit_setting['every_day_num'] != 0) {
  137. throw new \Exception('该商品每日限购' . $member_buy_limit_setting['every_day_num']);
  138. }
  139. if ($member_buy_limit_setting['every_week_num'] < $goods['num'] + $already_buy['week'] && $member_buy_limit_setting['every_week_num'] != 0) {
  140. throw new \Exception('该商品每周限购' . $member_buy_limit_setting['every_week_num']);
  141. }
  142. if ($member_buy_limit_setting['every_month_num'] < $goods['num'] + $already_buy['month'] && $member_buy_limit_setting['every_month_num'] != 0) {
  143. throw new \Exception('该商品每月限购' . $member_buy_limit_setting['every_month_num']);
  144. }
  145. }
  146. }
  147. protected function statisticsBuyGoodsId($goods_id, $user_id): array
  148. {
  149. $params['where'] = [
  150. [ 'user_id'=>$user_id],
  151. ['goods_id'=> $goods_id],
  152. // ['is_feedback'=> OrderStatusEnum::NOT_FEEDBACK],
  153. ['>=', 'order_status', 0]
  154. ];
  155. $params['select'] = 'created_at,num';
  156. $already_buy = StoreOrderDetail::lists($params);
  157. $res_data = [
  158. 'day' => 0,
  159. 'week' => 0,
  160. 'month' => 0,
  161. 'all' => 0,
  162. ];
  163. if (!empty($already_buy)) {
  164. $time = time();
  165. $date = date('Y-m-d', $time);
  166. $day_start = strtotime($date . ' 00:00:00');
  167. $day_end = strtotime($date . ' 23:59:59');
  168. $w = date('w', strtotime($date));
  169. $week_start = strtotime(date('Y-m-d', strtotime($date . '-' . ($w ? $w - 1 : 6) . 'days')) . ' 00:00:00');
  170. $week_end = $week_start + (86400 * 6) - 1;
  171. $date = date('Y-m', $time);
  172. $month_start = strtotime(date('Y-m-01', strtotime(date($date))) . ' 00:00:00');
  173. $month_end = $month_start + (86400 * date('t')) - 1;
  174. foreach ($already_buy as $k) {
  175. $date = $k['created_at'];
  176. $num = $k['num'];
  177. if ($date > $day_start && $date < $day_end) {
  178. $res_data['day'] += $num;
  179. }
  180. if ($date > $week_start && $date < $week_end) {
  181. $res_data['week'] += $num;
  182. }
  183. if ($date > $month_start && $date < $month_end) {
  184. $res_data['month'] += $num;
  185. }
  186. $res_data['all'] += $num;
  187. }
  188. }
  189. return $res_data;
  190. }
  191. /**
  192. * 删除购物车
  193. * @return mixed|void
  194. */
  195. public function actionDel()
  196. {
  197. $params = \Yii::$app->request->post();
  198. $res = \Yii::$app->services->validate->validate($params, [
  199. [['list'], 'required'],
  200. ]);
  201. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  202. $params['mall_id'] = $this->mall_id;
  203. $params['user_id'] = $this->user_id;
  204. StoreCart::delCart($params);
  205. return $this->success('操作成功', []);
  206. }
  207. /**
  208. * 购物车列表
  209. * @return mixed|void
  210. */
  211. public function actionIndex()
  212. {
  213. $params = \Yii::$app->request->get();
  214. $res = \Yii::$app->services->validate->validate($params, [
  215. [['store_id'], 'safe'],
  216. ]);
  217. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  218. $list = StoreCart::getCartList($this->user_id);
  219. $store_list = [];
  220. $store_id_arr = [];
  221. if (!empty($list)) {
  222. $attr_id_arr = [];
  223. $num_arr =[];
  224. foreach ($list as $v) {
  225. $row = json_decode($v, true);
  226. if (is_array($row)) {
  227. $attr_id_arr[] = $row['attr_id'];
  228. $store_id_arr[] = $row['store_id'];
  229. $num_arr[$row['attr_id']] = $row['num'];
  230. }
  231. }
  232. $params['where'] = [['id' => $attr_id_arr],['>','stock',0],['status'=>StatusEnum::ENABLED]];
  233. $params['with'] = ['goods' => function ($query) {
  234. $query->select('id,store_id,goods_name,is_on_sale,freight_type,cover_pic')->with(['extra']);
  235. }];
  236. $params['select'] = 'id,goods_id,pic_url,price,name,stock';
  237. $list = StoreGoodsAttr::lists($params);
  238. if(!empty($params['store_id'])){
  239. $store_id_arr = $params['store_id'];
  240. }
  241. $store_list = Store::lists(['where'=>[['id'=>$store_id_arr]],'select'=>'id,store_name,logo_img,business_time_start,business_time_end']);
  242. $rows = [];
  243. $user = $this->user;
  244. $user_level = UserLevel::findOne(['mall_id' => $this->mall_id, 'level' => $user['level'], 'status' => StatusEnum::ENABLED]);
  245. $discount = 10;
  246. if (isset($user_level)) $discount = $user_level['discount'];
  247. if (!empty($list)) {
  248. foreach ($list as $v) {
  249. if($v['goods']['is_on_sale']){
  250. $v['member_price'] = StoreGoods::computeMemberPrice($v['price'],$v['sign_id'] ?? 0,$user['level'],$v['goods']['is_attr'] ?? 0,
  251. $v['goods']['extra']['is_member_price'],$member_price_setting ?? [],$discount);
  252. if (!empty($v['goods']['extra']['is_member_price']) && !empty($v['extra']['member_price_setting'])) {
  253. $member_price_setting = $v['extra']['member_price_setting'];
  254. if ($v['goods']['is_attr']) {
  255. if (!empty($member_price_setting['level' . $user['level']][$v['sign_id']])) $v['price'] = $member_price_setting['level' . $user['level']][$v['sign_id']];
  256. } else {
  257. if (!empty($member_price_setting[$user['level']])) $v['price'] = $member_price_setting[$user['level']];
  258. }
  259. }
  260. if(!empty($v['goods']['extra']['member_buy_limit_setting'])){
  261. $member_buy_limit_setting = json_decode($v['goods']['extra']['member_buy_limit_setting'],true);
  262. }
  263. $freight_type = explode(',',$v['goods']['freight_type']);
  264. sort($freight_type);
  265. $rows[$v['goods']['store_id']][] = [
  266. 'goods_id' => $v['goods_id'],
  267. 'num' => $num_arr[$v['id']],
  268. 'attr_id' => $v['id'],
  269. 'price' => $v['price'],
  270. 'member_price' => $v['member_price'],
  271. 'cover_pic' =>$v['pic_url']?$v['pic_url']:$v['goods']['cover_pic'],
  272. 'attr' => $v['name'],
  273. 'stock' => $v['stock'],
  274. 'goods_name' => $v['goods']['goods_name'],
  275. 'is_on_sale' => $v['goods']['is_on_sale'],
  276. 'freight_type' => $freight_type,
  277. 'member_buy_limit_setting' => $member_buy_limit_setting??[],
  278. ];
  279. }
  280. }
  281. }
  282. foreach ($store_list as &$val) {
  283. $total_price =$total_num = 0;
  284. $list = [];
  285. if(isset($rows[$val['id']])){
  286. foreach ($rows[$val['id']] as $rk => $rv) {
  287. $price_sum = 0;
  288. $total_num += $rv['num'];
  289. $price_sum = bcmul($rv['price'], $rv['num'], 2);
  290. $total_price = bcadd($total_price, $price_sum, 2);
  291. }
  292. $list=$rows[$val['id']];
  293. }
  294. $val['list'] = $list;
  295. $val['total_price'] = $total_price;
  296. $val['total_num'] = $total_num;
  297. $val['business_status'] = StoreService::checkBusinessTime($val, 'front') ?? '';
  298. }
  299. }
  300. return $this->success('操作成功', $store_list);
  301. }
  302. public function actionClear()
  303. {
  304. $get = \Yii::$app->request->get();
  305. $params = [];
  306. $params['mall_id'] = $this->mall_id;
  307. $params['user_id'] = $this->user_id;
  308. $params['del_type'] = $get['del_type'] ?? 'del';
  309. $params['select'] = $get['select'] ?? '';
  310. if ($params['del_type'] == 'select') {
  311. $attr_ids = explode(',', $params['select']);
  312. $params['list'] = [];
  313. foreach ($attr_ids as $id) {
  314. $params['list'][]['attr_id'] = $id;
  315. }
  316. StoreCart::delCart($params);
  317. } else {
  318. StoreCart::clearCart($params);
  319. }
  320. return $this->success('操作成功', []);
  321. }
  322. }