<?php
|
|
namespace app\service;
|
|
|
|
use app\model\Order;
|
|
use app\model\OrderItem;
|
|
use app\model\Product;
|
|
use think\facade\Db;
|
|
|
|
class OrderService
|
|
{
|
|
// 下单事务 (BUG-04: 增加数量校验)
|
|
public function submit(string $cardNo, array $items, string $note = ''): array
|
|
{
|
|
return Db::transaction(function () use ($cardNo, $items, $note) {
|
|
$totalAmount = 0;
|
|
$orderItems = [];
|
|
|
|
foreach ($items as $item) {
|
|
// BUG-04: 校验 qty 为正整数
|
|
$qty = intval($item['qty'] ?? 1);
|
|
if ($qty < 1 || $qty > 99) {
|
|
throw new \Exception('商品数量不合法');
|
|
}
|
|
|
|
$product = Product::find($item['productId']);
|
|
if (!$product || $product->status != 1) {
|
|
throw new \Exception('商品不存在或已下架');
|
|
}
|
|
$subtotal = $product->price * $qty;
|
|
$totalAmount += $subtotal;
|
|
$orderItems[] = [
|
|
'product_id' => $product->id,
|
|
'product_name' => $product->name,
|
|
'emoji' => $product->emoji ?? '',
|
|
'price' => $product->price,
|
|
'quantity' => $qty,
|
|
];
|
|
}
|
|
|
|
if ($totalAmount <= 0) {
|
|
throw new \Exception('订单金额无效');
|
|
}
|
|
|
|
// BUG-03 (旧): 订单号增加秒级精度避免并发冲突
|
|
$orderNo = 'OD' . date('His') . substr($cardNo, -3) . rand(10, 99);
|
|
|
|
$order = Order::create([
|
|
'order_no' => $orderNo,
|
|
'card_no' => $cardNo,
|
|
'total_amount' => $totalAmount,
|
|
'status' => 0,
|
|
'note' => $note,
|
|
'submitted_at' => date('Y-m-d H:i:s'),
|
|
]);
|
|
|
|
foreach ($orderItems as &$oi) {
|
|
$oi['order_id'] = $order->id;
|
|
}
|
|
(new OrderItem())->saveAll($orderItems);
|
|
|
|
return ['orderNo' => $order->order_no];
|
|
});
|
|
}
|
|
|
|
// 顾客订单列表
|
|
public function listByCard(string $cardNo): array
|
|
{
|
|
$orders = Order::with('items')
|
|
->where('card_no', $cardNo)
|
|
->order('submitted_at', 'desc')
|
|
->select()
|
|
->toArray();
|
|
|
|
return array_map(function ($o) {
|
|
return [
|
|
'id' => $o['id'],
|
|
'orderNo' => $o['order_no'],
|
|
'cardNo' => $o['card_no'],
|
|
'status' => $o['status'],
|
|
'note' => $o['note'] ?? '',
|
|
'remindCount' => $o['remind_count'] ?? 0,
|
|
'submittedAt' => date('H:i', strtotime($o['submitted_at'])),
|
|
'items' => array_map(function ($i) {
|
|
return [
|
|
'name' => $i['product_name'],
|
|
'emoji' => $i['emoji'] ?? '',
|
|
'alc' => 0.0,
|
|
'qty' => $i['quantity'],
|
|
];
|
|
}, $o['items'] ?? []),
|
|
];
|
|
}, $orders);
|
|
}
|
|
|
|
// BUG-01: 催单增加归属校验 + 状态校验 + 频率限制
|
|
public function remind(int $orderId, string $cardNo): void
|
|
{
|
|
$order = Order::find($orderId);
|
|
if (!$order) {
|
|
throw new \Exception('订单不存在');
|
|
}
|
|
// 归属校验
|
|
if ($order->card_no !== $cardNo) {
|
|
throw new \Exception('无权操作此订单');
|
|
}
|
|
// 状态校验:仅新单可催
|
|
if ($order->status !== 0) {
|
|
throw new \Exception('当前订单状态不可催单');
|
|
}
|
|
// 频率限制:30秒冷却
|
|
$lastRemind = strtotime($order->updated_at ?? $order->submitted_at);
|
|
if (time() - $lastRemind < 30) {
|
|
throw new \Exception('催单太频繁,请30秒后再试');
|
|
}
|
|
// 上限:最多5次
|
|
if ($order->remind_count >= 5) {
|
|
throw new \Exception('催单次数已达上限');
|
|
}
|
|
|
|
Order::where('id', $orderId)->inc('remind_count', 1)->update();
|
|
}
|
|
}
|