Files
hyperf_service/app/Service/Api/Order/PlaceOrderService.php
2025-03-24 11:43:15 +08:00

215 lines
6.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
*/
declare(strict_types=1);
namespace App\Service\Api\Order;
use App\Amqp\Producer\CancelOrderProducer;
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 App\Service\ServiceTrait\Common\OrderChangeStatusTrait;
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
{
use OrderChangeStatusTrait;
public function __construct()
{
parent::__construct();
$this->isAutoSelectCoupon = 2;
}
/**
* @var array
*/
private array $rollbackStockCache = [];
/**
* 统一下单逻辑
* @return array
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function handle(): array
{
//todo 加防抖
$this->siteId = (int)$this->request->input('site_id');
$this->couponId = (int)$this->request->input('coupon_id',0);
$this->orderType = (int)$this->request->input('order_type');
// 生成购物车信息 检测商品和库存等
$this->check();
// 如果传递了优惠券的值 则进行检测
$this->getCouponInfo();
// 计算
$this->compute();
// 如果有优惠券的情况下 重载计算
$this->reloadCompute();
// 下单 减少库存 写入数据库
$this->placeOrder();
// 加入取消延迟队列
$this->joinCancelDelayQueue(
$this->orderId,
OrderCode::ORDER_TYPE_GOOD,
(int)$this->configCache->getConfigValueByKey(ConfigCode::ORDER_CANCEL_TIME_KEY) * DateUtil::MINUTE * DateUtil::MS
);
$this->sendStockMq($this->orderId,OrderCode::WAIT_PAY);
$this->orderRes['order_id'] = $this->orderId;
return $this->return->success('success',$this->orderRes);
}
/**
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception
*/
private function reduceStock(): void
{
$this->rollbackStockCache = [];
// var_dump($this->cartFirstData);
foreach ($this->cartFirstData as $goodId => $stock) {
$this->rollbackStockCache[$goodId] = $stock;
if (!($this->redis->zIncrBy($this->stockKey,-$stock,$goodId))) {
echo '123';
throw new Exception('cache error');
}
}
}
/**
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function rollbackStock(): void
{
if (empty($this->rollbackStockCache)) return;
foreach ($this->rollbackStockCache as $goodId => $stock) {
$this->redis->zIncrBy($this->stockKey,$stock,$goodId);
}
}
/**
* 下单
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function placeOrder(): void
{
try {
Db::beginTransaction();
$this->reduceStock();
$this->insertOrder();
$this->insertOrderGoods();
Db::commit();
} catch (Exception $e){
echo $e->getMessage();
//回滚数据库 和 缓存
Db::rollBack();
$this->rollbackStock();
//意外抛出
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,
'kitchen_id' => $this->orderRes['site_info']['kitchen_id'],
'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'],
'status' => OrderCode::WAIT_PAY,
'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 = $this->generateOrderNo(OrderCode::ORDER_TYPE_GOOD, $this->userId);
$orderInsertModel->user_id = $this->userId;
$orderInsertModel->cycle_id = $this->cycleId;
$orderInsertModel->site_id = $this->siteId;
$orderInsertModel->city_id = $this->orderRes['site_info']['city_id'];
$orderInsertModel->kitchen_id = $this->orderRes['site_info']['kitchen_id'];
$orderInsertModel->coupon_id = $this->couponId;
$orderInsertModel->copies = $this->orderRes['copies'];
$orderInsertModel->type = $this->orderType;
$orderInsertModel->total_price = $this->orderRes['total_price'];
$orderInsertModel->actual_price = max($this->orderRes['actual_price'], 0);
$orderInsertModel->discount_price = $this->orderRes['favorable_sundry_price'] + $this->orderRes['favorable_good_price'];
$orderInsertModel->append_price = $this->orderRes['sundry_price'];
$orderInsertModel->append_copies = $this->orderRes['sundry_num'];
$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;
}
}