lockForUpdate(); if ($orderIds !== []) { $orders = $query->whereIn('id', $orderIds)->get(); $invalid = $orders->where('status', '<>', StoreOrderModel::STATUS_SUMMARIZED); if ($orders->isEmpty() || $invalid->isNotEmpty()) { throw new RepositoryException( '所选订单包含非「已接单」状态,无法生成采购单:' . $invalid->pluck('order_no')->implode('、') ); } } else { $orders = $query->where('status', StoreOrderModel::STATUS_SUMMARIZED)->get(); } if ($orders->isEmpty()) { throw new RepositoryException('无已接单订单,无法生成采购单'); } $sourceOrderIds = $orders->pluck('id')->all(); // 2. 订货明细汇总(采购单头数据) $items = StoreOrderItemModel::query()->whereIn('order_id', $sourceOrderIds)->get(); if ($items->isEmpty()) { throw new RepositoryException('已接单订单均无明细,无法生成采购单'); } $totalQuantity = $items->reduce( static fn (string $carry, $item): string => bcadd($carry, (string) $item->quantity, 2), '0' ); // 预估成本 $estimateAmount = $items->reduce( static fn (string $carry, $item): string => bcadd($carry, bcmul($item->quantity, $item->cost_price, 2), 2), '0' ); // 参考总重量 = Σ 明细参考重量(下单时按订货量 × 规格预填) $totalWeight = $items->reduce( static fn (string $carry, $item): string => bcadd($carry, (string) $item->weight, 3), '0' ); $purchase = PurchaseOrderModel::create([ 'purchase_no' => $this->billNumberService->make('PO'), 'purchase_date' => $date, 'status' => PurchaseOrderModel::STATUS_PENDING, 'total_quantity' => $totalQuantity, 'total_weight' => $totalWeight, 'estimate_amount' => $estimateAmount, 'actual_amount' => 0, 'operator_id' => $operatorId, ]); // 3. 源订单回写「采购中」并关联采购单;订货明细同步回写 purchase_id StoreOrderModel::whereIn('id', $sourceOrderIds) ->update([ 'status' => StoreOrderModel::STATUS_DELIVERING, 'purchase_id' => $purchase->id, ]); StoreOrderItemModel::whereIn('order_id', $sourceOrderIds) ->update(['purchase_id' => $purchase->id]); return $purchase; }); } }