diff --git a/app/Amqp/Consumer/CancelOrderConsumer.php b/app/Amqp/Consumer/CancelOrderConsumer.php new file mode 100644 index 0000000..f2eb712 --- /dev/null +++ b/app/Amqp/Consumer/CancelOrderConsumer.php @@ -0,0 +1,86 @@ +log->error('CancelOrderConsumer:error:NoData:'.json_encode($data)); + return Result::ACK; + } + + $this->orderId = (int)$data['order_id']; + $this->orderType = (int)$data['type']; + + $orderInfo = match ($this->orderType) { + OrderCode::ORDER_TYPE_GOOD => $this->orderModel->getInfoById($this->orderId), + default => null, + }; + + if (empty($orderInfo)) { + $this->log->debug('CancelOrderConsumer:error:NoOrderData:'.json_encode($data)); + return Result::ACK; + } + + if ($orderInfo->status != OrderCode::WAIT_PAY) { + $this->log->debug('CancelOrderConsumer:error:orderStatusError:'.json_encode($orderInfo->toArray())); + return Result::ACK; + } + + $orderInfo->status = OrderCode::CANCEL; + if (!$orderInfo->save()) { + $this->log->debug('CancelOrderConsumer:error:orderStatusSaveError:'.json_encode($orderInfo->toArray())); + return Result::ACK; + } + + + return Result::ACK; + } +} diff --git a/app/Amqp/Consumer/OrderGoodStockConsumer.php b/app/Amqp/Consumer/OrderGoodStockConsumer.php new file mode 100644 index 0000000..9bd9abe --- /dev/null +++ b/app/Amqp/Consumer/OrderGoodStockConsumer.php @@ -0,0 +1,26 @@ + {"order_id":"orderId","type":"OrderCode::ORDER_TYPE_GOOD"} + */ + $this->payload = $data; + } +} diff --git a/app/Amqp/Producer/OrderGoodStockProducer.php b/app/Amqp/Producer/OrderGoodStockProducer.php new file mode 100644 index 0000000..98f8e6f --- /dev/null +++ b/app/Amqp/Producer/OrderGoodStockProducer.php @@ -0,0 +1,27 @@ + {"order_id":"orderId","type":"OrderCode::WAIT_PAY"} + */ + $this->payload = $data; + } +} diff --git a/app/Amqp/Producer/RefundOrderProducer.php b/app/Amqp/Producer/RefundOrderProducer.php new file mode 100644 index 0000000..6ae304f --- /dev/null +++ b/app/Amqp/Producer/RefundOrderProducer.php @@ -0,0 +1,24 @@ +payload = $data; + } +} diff --git a/app/Constants/Common/OrderCode.php b/app/Constants/Common/OrderCode.php new file mode 100644 index 0000000..6f575df --- /dev/null +++ b/app/Constants/Common/OrderCode.php @@ -0,0 +1,45 @@ + '15:00:00' + self::TODAY_CUT_OFF_TIME_KEY => '15:00:00', + self::ORDER_CANCEL_TIME_KEY => 5, ]; } \ No newline at end of file diff --git a/app/Extend/DateUtil.php b/app/Extend/DateUtil.php index cccafc1..6d9c2a1 100644 --- a/app/Extend/DateUtil.php +++ b/app/Extend/DateUtil.php @@ -11,6 +11,8 @@ class DateUtil public const MONTH = 2592000; // 月 public const YEAR = 311040000; // 年 + public const MS = 1000; + /** * 获取当前时间到今日结束的秒数 * @return int diff --git a/app/Model/Order.php b/app/Model/Order.php new file mode 100644 index 0000000..1647137 --- /dev/null +++ b/app/Model/Order.php @@ -0,0 +1,66 @@ + 'integer', 'user_id' => 'integer', 'cycle_id' => 'integer', 'site_id' => 'integer', 'city_id' => 'integer', 'coupon_id' => 'integer', 'meal_copies' => 'integer', 'optional_copies' => 'integer', 'status' => 'integer', 'is_refund_all' => 'integer']; + + const string CREATED_AT = 'create_time'; + + const string UPDATED_AT = 'update_time'; + + /** + * @param int $id + * @return Order|Order[]|Collection|\Hyperf\Database\Model\Model|null + */ + public function getInfoById(int $id): array|Order|Collection|\Hyperf\Database\Model\Model|null + { + return $this->find($id); + } +} diff --git a/app/Model/OrderGood.php b/app/Model/OrderGood.php new file mode 100644 index 0000000..8ec0469 --- /dev/null +++ b/app/Model/OrderGood.php @@ -0,0 +1,45 @@ + 'integer', 'order_id' => 'integer', 'cycle_id' => 'integer', 'sku_id' => 'integer', 'spu_id' => 'integer', 'user_id' => 'integer', 'quantity' => 'integer', 'is_comment' => 'integer', 'copies' => 'integer', 'type' => 'integer']; + + const string CREATED_AT = 'create_time'; + + const string UPDATED_AT = 'update_time'; +} diff --git a/app/Service/Api/Order/BaseOrderService.php b/app/Service/Api/Order/BaseOrderService.php index 082132b..3abf547 100644 --- a/app/Service/Api/Order/BaseOrderService.php +++ b/app/Service/Api/Order/BaseOrderService.php @@ -81,6 +81,11 @@ abstract class BaseOrderService extends BaseService */ protected int $siteId; + /** + * @var int + */ + protected int $orderId; + /** * 构造方法 * @throws ContainerExceptionInterface diff --git a/app/Service/Api/Order/PlaceOrderService.php b/app/Service/Api/Order/PlaceOrderService.php index 8595775..d67384c 100644 --- a/app/Service/Api/Order/PlaceOrderService.php +++ b/app/Service/Api/Order/PlaceOrderService.php @@ -10,12 +10,25 @@ declare(strict_types=1); namespace App\Service\Api\Order; +use App\Amqp\Producer\CancelOrderProducer; +use App\Constants\Common\GoodCode; +use App\Constants\Common\OrderCode; +use App\Constants\ConfigCode; +use App\Exception\ErrException; +use App\Extend\DateUtil; +use App\Model\Order; +use App\Model\OrderGood; +use Exception; +use Hyperf\Amqp\Producer; +use Hyperf\Context\ApplicationContext; +use Hyperf\DbConnection\Db; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; class PlaceOrderService extends BaseOrderService { /** + * 统一下单逻辑 * @return array * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface @@ -31,17 +44,108 @@ class PlaceOrderService extends BaseOrderService $this->placeOrder(); + $this->joinCancelDelayQueue(); + return $this->return->success('success',$this->orderRes); } - private function placeOrder() + /** + * 加入取消队列 + * @return void + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + private function joinCancelDelayQueue(): void { - foreach ($this->orderRes['good'] as $oneCopies) - { - foreach ($oneCopies['good_info'] as $one) - { + $message = new CancelOrderProducer([ + 'order_id' => $this->orderId, + 'type' => OrderCode::ORDER_TYPE_GOOD + ]); + $message->setDelayMs((int)$this->configCache->getConfigValue(ConfigCode::ORDER_CANCEL_TIME_KEY) * DateUtil::MINUTE * DateUtil::MS); + $producer = ApplicationContext::getContainer()->get(Producer::class); + $producer->produce($message); + } - } + /** + * 下单 + * @return void + */ + private function placeOrder(): void + { + try { + Db::beginTransaction(); + + $this->insertOrder(); + + $this->insertOrderGoods(); + + Db::commit(); + } catch (Exception $e){ + Db::rollBack(); + throw new ErrException($e->getMessage()); } } + + /** + * 插入订单商品 + * @return void + * @throws Exception + */ + private function insertOrderGoods(): void + { + $copiesNum = 0; + $orderGoodInsertArr = []; + foreach ($this->orderRes['good'] as $oneCopies) + { + $copiesNum++; + foreach ($oneCopies['good_info'] as $one) + { + $orderGoodInsertArr[] = [ + 'order_id' => $this->orderId, + 'cycle_id' => $this->cycleId, + 'sku_id' => $one['id'], + 'spu_id' => $one['spu_id'], + 'user_id' => $this->userId, + 'quantity' => $one['num'], + 'unit_price' => $one['unit_price'], + 'is_comment' => OrderCode::GOOD_COMMENT_NULL, + 'copies' => $copiesNum, + 'type' => $one['type'], + 'create_time' => date('Y-m-d H:i:s'), + 'update_time' => date('Y-m-d H:i:s'), + ]; + } + } + + if (!(new OrderGood)->insert($orderGoodInsertArr)) throw new Exception('写入订单商品失败'); + } + + /** + * 插入订单 + * @return void + * @throws Exception + */ + private function insertOrder(): void + { + $orderInsertModel = new Order(); + + $orderInsertModel->order_sno = '123'; + $orderInsertModel->user_id = $this->userId; + $orderInsertModel->cycle_id = $this->cycleId; + $orderInsertModel->site_id = $this->siteId; + $orderInsertModel->city_id = $this->orderRes['site']['city_id']; + $orderInsertModel->coupon_id = $this->couponId; + $orderInsertModel->meal_copies = $this->orderRes['meal_copies']; + $orderInsertModel->optional_copies = $this->orderRes['optional_copies']; + $orderInsertModel->total_price = $this->orderRes['total_price']; + $orderInsertModel->actual_price = $this->orderRes['actual_price']; + $orderInsertModel->discount_price = $this->orderRes['favorable_sundry_price'] + $this->orderRes['favorable_good_price']; + $orderInsertModel->status = OrderCode::WAIT_PAY; + $orderInsertModel->is_refund_all = OrderCode::REFUND_NULL; + $orderInsertModel->order_json = json_encode($this->orderRes); + + if (!$orderInsertModel->save()) throw new Exception('下单失败'); + + $this->orderId = $orderInsertModel->id; + } } \ No newline at end of file diff --git a/app/Service/ServiceTrait/Api/OrderTrait.php b/app/Service/ServiceTrait/Api/OrderTrait.php index 23d8595..84c2e5d 100644 --- a/app/Service/ServiceTrait/Api/OrderTrait.php +++ b/app/Service/ServiceTrait/Api/OrderTrait.php @@ -14,6 +14,7 @@ use App\Cache\Redis\Api\ApiRedisKey; use App\Cache\Redis\Api\SiteCache; use App\Cache\Redis\RedisCache; use App\Constants\ApiCode; +use App\Constants\Common\GoodCode; use App\Exception\ErrException; use Hyperf\Di\Annotation\Inject; use Psr\Container\ContainerExceptionInterface; @@ -165,19 +166,21 @@ trait OrderTrait $oneCopiesGoodInfo = []; foreach ($oneCopies as $oneGood) { - if (empty($oneCopiesGoodInfo[$oneGood])) - { + if (empty($oneCopiesGoodInfo[$oneGood])) { $oneCopiesGoodInfo[$oneGood] = [ 'num' => 1, 'good_name' => '1', 'good_url' => '1', - 'unit_price' => $this->skuArr[$oneGood]['price'] + 'unit_price' => $this->skuArr[$oneGood]['price'], + 'type' => $this->skuArr[$oneGood]['type'], ]; + } else { + $oneCopiesGoodInfo[$oneGood]['num'] += 1; } $oneCopiesTotalPrice = bcadd($oneCopiesTotalPrice, $this->skuArr[$oneGood]['price'],2); - if ($copiesType == 1 && $this->skuArr[$oneGood]['type'] == 2) { + if ($copiesType == 1 && $this->skuArr[$oneGood]['type'] == GoodCode::SPU_TYPE_MEAL) { $copiesType = 2; } }