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.

122 lines
4.2 KiB

<?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('Y-m-d H:i:s', 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();
}
}