currentUser($request); $store = $this->ensureStoreBound($user); if ($store->level_id <= 0) { throw new RepositoryException('门店未设置客户等级,无法下单,请联系客服'); } $items = $request->validated('items'); $remark = (string) ($request->validated('remark') ?? ''); $order = DB::transaction(function () use ($store, $items, $remark) { $productIds = array_map(static fn ($row) => (int) $row['product_id'], $items); $products = ProductModel::query() ->where('status', ProductModel::STATUS_ON) ->whereIn('id', $productIds) ->get() ->keyBy('id'); $prices = ProductPriceModel::query() ->where('level_id', $store->level_id) ->whereIn('product_id', $productIds) ->pluck('price', 'product_id'); $totalQuantity = '0'; $totalAmount = '0'; $now = now(); $rows = []; foreach ($items as $row) { $productId = (int) $row['product_id']; $product = $products->get($productId); if ($product === null) { throw new RepositoryException('存在已下架或不存在的商品,请刷新后重试'); } if (! isset($prices[$productId])) { throw new RepositoryException('商品「' . $product->name . '」未设置您所在等级的价格,无法下单'); } $price = (string) $prices[$productId]; $quantity = (string) $row['quantity']; $amount = bcmul($price, $quantity, 2); $totalQuantity = bcadd($totalQuantity, $quantity, 2); $totalAmount = bcadd($totalAmount, $amount, 2); $rows[] = [ 'store_id' => $store->id, 'product_id' => $productId, 'product_name' => $product->name, 'product_spec' => $product->spec, 'price' => $price, 'quantity' => $quantity, 'weight' => 0, 'amount' => $amount, 'remark' => '', 'created_at' => $now, 'updated_at' => $now, ]; } $order = StoreOrderModel::create([ 'order_no' => app(BillNumberService::class)->make('SO'), 'store_id' => $store->id, 'order_date' => $now->toDateString(), 'total_quantity' => $totalQuantity, 'total_weight' => 0, 'total_amount' => $totalAmount, 'status' => StoreOrderModel::STATUS_PENDING, 'remark' => $remark, ]); foreach ($rows as &$itemRow) { $itemRow['order_id'] = $order->id; } StoreOrderItemModel::insert($rows); return $order; }); return $this->success([ 'id' => $order->id, 'order_no' => $order->order_no, 'total_amount' => $order->total_amount, ], '下单成功'); } /** 历史订单:当前门店强制过滤,?status=&page=&pageSize= */ #[GetRoute('/order', authorize: true)] public function index(Request $request): JsonResponse { $user = $this->currentUser($request); $store = $this->ensureStoreBound($user); $query = StoreOrderModel::query()->where('store_id', $store->id); if ($request->filled('status')) { $query->where('status', (int) $request->input('status')); } $data = $query->orderBy('order_date', 'desc') ->orderBy('id', 'desc') ->paginate((int) $request->input('pageSize', 10)) ->toArray(); return $this->success($data); } /** * 按周期聚合金额/数量:?period=day|week|month(分组列表,period_label 可作下钻查询参数) */ #[GetRoute('/order/summary', authorize: true)] public function summary(Request $request): JsonResponse { $period = (string) $request->query('period', 'month'); if (! in_array($period, ['day', 'week', 'month'], true)) { throw new RepositoryException('period 参数只能是 day/week/month'); } $user = $this->currentUser($request); $store = $this->ensureStoreBound($user); // 按数据库方言选择周期分组表达式(生产 MySQL / 测试 SQLite) $driver = DB::connection()->getDriverName(); if ($driver === 'sqlite') { $format = match ($period) { 'day' => '%Y-%m-%d', 'week' => '%Y-W%W', default => '%Y-%m', }; $labelExpr = "strftime('{$format}', order_date)"; } else { $format = match ($period) { 'day' => '%Y-%m-%d', 'week' => '%x-W%v', default => '%Y-%m', }; $labelExpr = "DATE_FORMAT(order_date, '{$format}')"; } $rows = StoreOrderModel::query() ->where('store_id', $store->id) ->where('status', '<>', StoreOrderModel::STATUS_CANCELLED) ->selectRaw("{$labelExpr} as period_label") ->selectRaw('SUM(total_amount) as total_amount, SUM(total_quantity) as total_quantity, COUNT(*) as order_count') ->groupBy('period_label') ->orderByDesc('period_label') ->limit(50) ->get() ->toArray(); return $this->success(['period' => $period, 'groups' => $rows]); } /** 订单详情(校验归属:仅能查看本店订单) */ #[GetRoute('/order/{id}', authorize: true, where: ['id' => '[0-9]+'])] public function detail(int $id, Request $request): JsonResponse { $user = $this->currentUser($request); $store = $this->ensureStoreBound($user); $order = StoreOrderModel::with('items') ->where('store_id', $store->id) ->find($id); if ($order === null) { throw new RepositoryException('订单不存在'); } return $this->success($order->toArray()); } /** 取消订单(仅待汇总可取消) */ #[PutRoute('/order/{id}/cancel', authorize: true, where: ['id' => '[0-9]+'])] public function cancel(int $id, Request $request): JsonResponse { $user = $this->currentUser($request); $store = $this->ensureStoreBound($user); $order = StoreOrderModel::where('store_id', $store->id)->find($id); if ($order === null) { throw new RepositoryException('订单不存在'); } if ($order->status !== StoreOrderModel::STATUS_PENDING) { throw new RepositoryException('仅待汇总的订单可以取消'); } $order->status = StoreOrderModel::STATUS_CANCELLED; $order->save(); return $this->success([], '订单已取消'); } }