You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

458 lines
14 KiB

  1. <?php
  2. namespace api\logic;
  3. use backend\modules\goods\models\ars\Goods;
  4. use backend\modules\goods\models\ars\GoodsSku;
  5. use backend\modules\shop\models\ars\Address;
  6. use backend\modules\shop\models\ars\Cart;
  7. use backend\modules\shop\models\ars\Order;
  8. use backend\modules\shop\models\ars\OrderGoods;
  9. use backend\modules\shop\models\ars\TakingSite;
  10. use yii\base\Component;
  11. use Throwable;
  12. use Yii;
  13. use yii\db\ActiveRecord;
  14. use yii\base\Exception;
  15. use yii\web\BadRequestHttpException;
  16. use yii\web\NotFoundHttpException;
  17. use yii\web\ServerErrorHttpException;
  18. /**
  19. * @author iron
  20. * @email weiriron@gmail.com
  21. * @package api\logic
  22. */
  23. class OrderLogic extends Component
  24. {
  25. public $viewAction = 'view';
  26. /*订单操作类型*/
  27. const TYPE_CONFIRM = 1;
  28. const TYPE_CANCEL = 2;
  29. const TYPE_TAKE = 3;
  30. const TYPE_CHANGE_SHIPPING_TYPE = 4;
  31. const TYPE_CHANGE_ADDRESS = 5;
  32. const TYPE_CHANGE_TAKING_SITE = 6;
  33. /*仓库类型*/
  34. const TYPE_ADD_STOCK = 1;
  35. const TYPE_SUB_STOCK = -1;
  36. /**
  37. * @return Order
  38. * @throws BadRequestHttpException
  39. * @throws Exception
  40. * 创建订单
  41. */
  42. public function create()
  43. {
  44. //立即购物需传参数
  45. $goodsId = Yii::$app->request->getBodyParam('goodsId');/*int 商品id*/
  46. $count = Yii::$app->request->getBodyParam('count');/*int 数量*/
  47. $skuId = Yii::$app->request->getBodyParam('skuId');/*int 商品sku id*/
  48. //购物车提交订单需传参数
  49. $cartIds = Yii::$app->request->getBodyParam('cartIds');/*array 购物车商品id*/
  50. if ((empty($cartIds) && empty($goodsId)) || ($goodsId && empty($count))) {
  51. throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS);
  52. }
  53. $tra = Yii::$app->db->beginTransaction();
  54. try {
  55. $order = new Order();
  56. $order->user_id = Yii::$app->user->getId();
  57. $order->type = Order::TYPE_SHOPPING;
  58. $order->order_sn = Helper::timeRandomNum(3, 'W');
  59. if (!$order->save()) {
  60. throw new ServerErrorHttpException('服务器创建订单失败');
  61. }
  62. if ($goodsId && $count) {
  63. $this->addGoods($order->id, $goodsId, $skuId, $count);/*添加订单商品*/
  64. } else {
  65. $this->addGoodsByCart($cartIds, $order->id);/*通过购物车添加订单商品*/
  66. }
  67. $this->getShippingType($order);
  68. $this->saveGoodsInfo($order);/*保存订单商品信息*/
  69. if (!$order->save()) {
  70. throw new Exception('服务器创建订单失败');
  71. }
  72. $tra->commit();
  73. Helper::createdResponse($order, $this->viewAction);
  74. return $order;
  75. } catch (Exception $e) {
  76. $tra->rollBack();
  77. throw $e;
  78. }
  79. }
  80. /**
  81. * @return bool
  82. * @throws Exception
  83. * @throws Throwable
  84. * @throws yii\base\InvalidConfigException
  85. * 根据操作类型更新订单
  86. */
  87. public function update()
  88. {
  89. $data = Yii::$app->request->getBodyParams();
  90. $type = Yii::$app->request->getBodyParam('type');
  91. $order = $this->findOrder();
  92. $tra = Yii::$app->db->beginTransaction();
  93. try {
  94. switch ($type) {
  95. case self::TYPE_CONFIRM :
  96. $this->confirm($order, $data);
  97. break;
  98. case self::TYPE_CANCEL:
  99. $this->cancel($order);
  100. break;
  101. case self::TYPE_TAKE:
  102. $this->take($order);
  103. break;
  104. case self::TYPE_CHANGE_SHIPPING_TYPE:
  105. $this->switchShippingType($order, $data);
  106. break;
  107. case self::TYPE_CHANGE_ADDRESS:
  108. $this->changeAddress($order, $data);
  109. break;
  110. case self::TYPE_CHANGE_TAKING_SITE:
  111. $this->changeTakingSite($order, $data);
  112. break;
  113. default:
  114. throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS);
  115. }
  116. if (!$order->save()) {
  117. throw new ServerErrorHttpException('服务器更新订单失败');
  118. }
  119. $tra->commit();
  120. return true;
  121. } catch (Exception $e) {
  122. $tra->rollBack();
  123. throw $e;
  124. }
  125. }
  126. /*----------------------------------------- 华丽的分割线 -----------------------------------------*/
  127. /**
  128. * @param $order
  129. * @return int
  130. * @throws BadRequestHttpException
  131. * @throws NotFoundHttpException
  132. */
  133. private function getShippingType($order)
  134. {
  135. $allOrderGoods = $this->findOrderGoods($order->id);
  136. $goods = $this->findGoods($allOrderGoods[0]->goods_id);
  137. if ($goods->is_express) {
  138. return Order::SHIPPING_TYPE_EXPRESS;
  139. }
  140. if ($goods->is_taking) {
  141. return Order::SHIPPING_TYPE_PICKED_UP;
  142. }
  143. throw new BadRequestHttpException('配送方式异常');
  144. }
  145. /**
  146. * @param Order $order
  147. * @param array $data
  148. * @throws BadRequestHttpException
  149. * @throws NotFoundHttpException
  150. * 添加地址到订单
  151. */
  152. private function changeAddress($order, $data)
  153. {
  154. if (!isset($data['address_id'])) {
  155. throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS);
  156. }
  157. if ($order->shipping_type !== Order::SHIPPING_TYPE_EXPRESS) {
  158. throw new BadRequestHttpException('配送方式异常');
  159. }
  160. if ($order->status !== Order::STATUS_UNCONFIRMED) {
  161. throw new BadRequestHttpException('该状态下不允许更改配送方式');
  162. }
  163. $address = Address::findOne(['id' => $data['address_id'], 'user_id' => Yii::$app->user->getId()]);
  164. if (!$address) {
  165. throw new NotFoundHttpException('收货地址未找到');
  166. }
  167. $order->consignee = $address->consignee;
  168. $order->phone = $address->phone;
  169. $order->city = $address->city;
  170. $order->area = $address->area;
  171. $order->province = $address->province;
  172. $order->address = $address->address;
  173. }
  174. /**
  175. * @param Order $order
  176. * @param array $data
  177. * @throws BadRequestHttpException
  178. * @throws NotFoundHttpException
  179. * 修改自提点
  180. */
  181. private function changeTakingSite($order, $data)
  182. {
  183. if (!isset($data['taking_site_id']) || empty($data['taking_site_id'])) {
  184. throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS);
  185. }
  186. if ($order->shipping_type !== Order::SHIPPING_TYPE_PICKED_UP) {
  187. throw new BadRequestHttpException('配送方式异常');
  188. }
  189. if ($order->status !== Order::STATUS_UNCONFIRMED) {
  190. throw new BadRequestHttpException('该状态下不允许更改提货地址方式');
  191. }
  192. $site = TakingSite::findOne($data['taking_site_id']);
  193. if (!$site) {
  194. throw new NotFoundHttpException('自提点未找到');
  195. }
  196. $order->taking_site = $data['taking_site_id'];
  197. }
  198. /**
  199. * @param Order $order
  200. * @param array $data
  201. * @throws BadRequestHttpException
  202. * 切换配送方式
  203. */
  204. private function switchShippingType($order, $data)
  205. {
  206. if (!isset($data['shipping_type']) ||
  207. !in_array($data['shipping_type'], [Order::SHIPPING_TYPE_PICKED_UP, Order::SHIPPING_TYPE_EXPRESS])) {
  208. throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS);
  209. }
  210. if ($order->status !== Order::STATUS_UNCONFIRMED) {
  211. throw new BadRequestHttpException('该状态下不允许更改配送方式');
  212. }
  213. $order->shipping_type = $data['shipping_type'];
  214. }
  215. /**
  216. * @param Order $order
  217. * @param array $data
  218. * @throws BadRequestHttpException
  219. * @throws NotFoundHttpException
  220. * @throws ServerErrorHttpException
  221. * @throws Throwable
  222. * @throws yii\db\StaleObjectException
  223. * 确定订单
  224. */
  225. private function confirm($order, $data)
  226. {
  227. if ($order->status !== Order::STATUS_UNCONFIRMED) {
  228. throw new BadRequestHttpException('订单状态异常');
  229. }
  230. if ($order->shipping_type === Order::SHIPPING_TYPE_PICKED_UP) {
  231. if ($data['consignee'] ?? false || $data['phone'] ?? false) {
  232. throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS);
  233. }
  234. $order->consignee = $data['consignee'];
  235. $order->phone = $data['phone'];
  236. }
  237. if (empty($order->consignee)) {
  238. throw new BadRequestHttpException('需先填写收件人信息');
  239. }
  240. if (isset($data['remarks'])) {
  241. $order->remarks = $data['remarks'];
  242. }
  243. Helper::delCarts($this->getCartsIds($order)); //删除购物车对应商品
  244. $order->status = Order::STATUS_NONPAYMENT;
  245. $this->updateStock($order, self::TYPE_SUB_STOCK);
  246. }
  247. /**
  248. * @param $order
  249. * @return array
  250. * 获取订单商品对应购物车商品id
  251. */
  252. private function getCartsIds($order)
  253. {
  254. $allGoods = $this->findOrderGoods($order->id);
  255. $ids = [];
  256. foreach ($allGoods as $goods) {
  257. $cart = Cart::findOne(['goods_id' => $goods->goods_id, 'user_id' => Yii::$app->user->getId()]);
  258. if ($cart) {
  259. $ids[] = $cart->id;
  260. }
  261. }
  262. return $ids;
  263. }
  264. /**
  265. * @param Order $order
  266. * @throws BadRequestHttpException
  267. * @throws NotFoundHttpException
  268. * @throws ServerErrorHttpException
  269. * 取消订单
  270. */
  271. private function cancel($order)
  272. {
  273. if ($order->status !== Order::STATUS_NONPAYMENT) {
  274. throw new BadRequestHttpException('该状态下无法取消订单');
  275. }
  276. $order->status = Order::STATUS_CANCEL;
  277. $this->updateStock($order, self::TYPE_ADD_STOCK);/*更新库存*/
  278. }
  279. /**
  280. * @param Order $order
  281. * @throws BadRequestHttpException
  282. * 确认收货
  283. */
  284. private function take($order)
  285. {
  286. if ($order->status !== Order::STATUS_SHIPMENT_ALL) {
  287. throw new BadRequestHttpException('该状态下无法确认收货');
  288. }
  289. $order->status = Order::STATUS_FINISH;
  290. }
  291. /**
  292. * @param $id
  293. * @param $type
  294. * @throws BadRequestHttpException
  295. * @throws NotFoundHttpException
  296. * @throws ServerErrorHttpException
  297. * 更新库存
  298. */
  299. private function updateStock($id, $type)
  300. {
  301. $allOrderGoods = $this->findOrderGoods($id);
  302. foreach ($allOrderGoods as $orderGoods) {
  303. /*检查库存*/
  304. if (Helper::checkStock($orderGoods->goods_id, $orderGoods->goods_count, $orderGoods->sku_id)) {
  305. return;
  306. }
  307. if ($orderGoods->sku_id) {
  308. $goods = GoodsSku::findOne($orderGoods->sku_id);
  309. } else {
  310. $goods = $this->findGoods($orderGoods->goods_id);
  311. }
  312. if ($type) {
  313. $count = $orderGoods->goods_count;
  314. } else {
  315. $count = -$orderGoods->goods_count;
  316. }
  317. if (!$goods->updateCounters(['stock' => $count])) {
  318. throw new ServerErrorHttpException('更新库存失败');
  319. }
  320. }
  321. }
  322. /**
  323. * @param array $cartIds 购物车商品id
  324. * @param int $id 订单id
  325. * @throws Exception
  326. * @throws NotFoundHttpException
  327. * 通过购物车添加商品
  328. */
  329. private function addGoodsByCart($cartIds, $id)
  330. {
  331. foreach ($cartIds as $cartId) {
  332. $cart = Cart::findOne($cartId);
  333. if (!$cart) {
  334. throw new NotFoundHttpException('购物车未找到');
  335. }
  336. $this->addGoods($id, $cart->goods_id, $cart->sku_id, $cart->goods_count);
  337. }
  338. }
  339. /**
  340. * @param Order $order
  341. * 保存商品总价格和总数量信息到
  342. */
  343. private function saveGoodsInfo($order)
  344. {
  345. $orderGoods = $this->findOrderGoods($order->id);
  346. foreach ($orderGoods as $goods) {
  347. $order->goods_amount += $goods->price;
  348. $order->goods_count += $goods->goods_count;
  349. }
  350. }
  351. /**
  352. * @param $id
  353. * @param int $goodsId
  354. * @param $skuId
  355. * @param $count
  356. * @throws Exception
  357. * @throws NotFoundHttpException
  358. * 添加商品到订单
  359. */
  360. private function addGoods($id, $goodsId, $skuId, $count)
  361. {
  362. $goods = $this->findGoods($goodsId);
  363. $orderGoods = new OrderGoods();
  364. $orderGoods->order_id = $id;
  365. $orderGoods->goods_id = $goodsId;
  366. $orderGoods->sku_id = $skuId ?: 0;
  367. $orderGoods->sku_value = Helper::skuValue($skuId);
  368. $orderGoods->weight = $skuId ? $this->skuWeight($skuId) : $goods->weight;
  369. $orderGoods->goods_count = $count;
  370. $orderGoods->goods_img = $goods->image;
  371. $orderGoods->goods_name = $goods->name;
  372. $orderGoods->price = Helper::goodsPrice($goodsId, $skuId);
  373. Helper::checkStock($goodsId, $count, $skuId); /*检查库存*/
  374. if (!$orderGoods->save()) {
  375. throw new Exception('服务器添加订单商品失败');
  376. }
  377. }
  378. /**
  379. * @param $skuId
  380. * @return int
  381. * @throws NotFoundHttpException
  382. * 获取sku重量
  383. */
  384. private function skuWeight($skuId)
  385. {
  386. $sku = GoodsSku::findOne($skuId);
  387. if (!$sku) {
  388. throw new NotFoundHttpException('sku未找到');
  389. }
  390. return $sku->weight;
  391. }
  392. /**
  393. * @return array|Order|null
  394. * 根据id获取订单
  395. */
  396. private function findOrder()
  397. {
  398. $id = Yii::$app->request->getQueryParam('id');
  399. return Order::find()
  400. ->where(['id' => $id])
  401. ->andWhere(['user_id' => Yii::$app->user->getId()])
  402. ->one();
  403. }
  404. /**
  405. * @param $id
  406. * @return array|ActiveRecord[]|OrderGoods[]
  407. * 根据订单 id 获取所有订单商品
  408. */
  409. private function findOrderGoods($id)
  410. {
  411. return OrderGoods::find()
  412. ->where(['order_id' => $id])
  413. ->all();
  414. }
  415. /**
  416. * @param $goodsId
  417. * @return array|Goods|null
  418. * @throws NotFoundHttpException
  419. */
  420. private function findGoods($goodsId)
  421. {
  422. $goods = Goods::find()
  423. ->where(['id' => $goodsId])
  424. ->andWhere(['is_delete' => Goods::IS_DELETE_NO])
  425. ->andWhere(['is_sale' => Goods::IS_SALE_YES])
  426. ->one();
  427. if (!$goods) {
  428. throw new NotFoundHttpException("商品[{$goodsId}]未找到");
  429. }
  430. return $goods;
  431. }
  432. }