219 lines
6.5 KiB
PHP
219 lines
6.5 KiB
PHP
<?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))) {
|
||
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
|
||
* @throws ErrException
|
||
*/
|
||
private function placeOrder(): void
|
||
{
|
||
try {
|
||
Db::beginTransaction();
|
||
|
||
$this->reduceStock();
|
||
|
||
$this->insertOrder();
|
||
|
||
$this->insertOrderGoods();
|
||
|
||
$this->couponLock();
|
||
|
||
Db::commit();
|
||
} catch (Exception $e){
|
||
echo $e->getMessage();
|
||
//回滚数据库 和 缓存
|
||
Db::rollBack();
|
||
$this->rollbackStock();
|
||
|
||
// $this->rollbackCouponLock();
|
||
//意外抛出
|
||
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['discount_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('下单失败-01');
|
||
|
||
$this->orderId = $orderInsertModel->id;
|
||
}
|
||
} |