diff --git a/app/Http/Controllers/Purchase/PurchaseOrderController.php b/app/Http/Controllers/Purchase/PurchaseOrderController.php index 7f35a92..ab3d57b 100644 --- a/app/Http/Controllers/Purchase/PurchaseOrderController.php +++ b/app/Http/Controllers/Purchase/PurchaseOrderController.php @@ -20,6 +20,7 @@ use Modules\AnnoRoute\Attribute\PutRoute; use Modules\AnnoRoute\Attribute\RequestAttribute; use Modules\Common\Http\Controllers\BaseController; use Symfony\Component\HttpFoundation\Response; +use Throwable; /** * 采购单管理(C1 汇总生成 / C2-C3 导出 / C4 修改) @@ -213,33 +214,8 @@ class PurchaseOrderController extends BaseController } /** - * C4 门店单元格修改:数量/称重回写订货明细,金额重算并同步订单/采购单汇总 - */ - #[PutRoute(route: '/cell/{id}', authorize: 'update', where: ['id' => '[0-9]+'])] - public function updateCell(int $id, PurchaseCellUpdateRequest $request): JsonResponse - { - $item = StoreOrderItemModel::find($id); - if (empty($item)) { - throw new RepositoryException('订货明细不存在'); - } - $validated = $request->validated(); - - $item = app(PurchaseEditService::class)->updateCell( - $item, - (int) $validated['quantity'], - isset($validated['weight']) ? (float) $validated['weight'] : null, - ); - - return $this->success([ - 'quantity' => (int) $item->quantity, - 'weight' => (float) $item->weight, - 'amount' => (float) $item->amount, - ]); - } - - /** - * C4 商品行修改:品名/供应商/包规/单位/成本一键同步该商品全部订货明细; - * 实际称重按数量比例分摊(尾差修正守恒) + * 商品行修改:品名/供应商/包规/单位/成本一键同步该商品全部订货明细; + * @throws Throwable */ #[PutRoute(route: '/{id}/row/{productId}', authorize: 'update', where: ['id' => '[0-9]+', 'productId' => '[0-9]+'])] public function updateRow(int $id, int $productId, PurchaseRowUpdateRequest $request): JsonResponse @@ -256,16 +232,14 @@ class PurchaseOrderController extends BaseController $attrs[$field] = $validated[$field]; } } - $weight = isset($validated['weight']) ? (float) $validated['weight'] : null; - if ($attrs === [] && $weight === null) { - throw new RepositoryException('品名/供应商/包规/单位/成本/实际称重至少填写一项'); + if ($attrs === []) { + throw new RepositoryException('品名/供应商/包规/单位/成本至少填写一项'); } $count = app(PurchaseEditService::class)->updateRow( $purchase, $productId, $attrs, - $weight, (bool) ($validated['sync_product'] ?? false), ); diff --git a/app/Http/Requests/Purchase/PurchaseRowUpdateRequest.php b/app/Http/Requests/Purchase/PurchaseRowUpdateRequest.php index 4a6a534..6abf7e9 100644 --- a/app/Http/Requests/Purchase/PurchaseRowUpdateRequest.php +++ b/app/Http/Requests/Purchase/PurchaseRowUpdateRequest.php @@ -20,7 +20,6 @@ class PurchaseRowUpdateRequest extends BaseFormRequest 'product_spec' => 'nullable|string|max:100', 'unit' => 'nullable|string|max:20', 'cost_price' => 'nullable|numeric|min:0', - 'weight' => 'nullable|numeric|min:0', 'sync_product' => 'nullable|boolean', ]; } @@ -34,8 +33,6 @@ class PurchaseRowUpdateRequest extends BaseFormRequest 'unit.max' => '单位不能超过 20 字', 'cost_price.numeric' => '采购成本必须为数字', 'cost_price.min' => '采购成本不能小于 0', - 'weight.numeric' => '实际称重必须为数字', - 'weight.min' => '实际称重不能小于 0', ]; } } diff --git a/app/Models/PurchaseOrderModel.php b/app/Models/PurchaseOrderModel.php index d00cce2..5a9f289 100644 --- a/app/Models/PurchaseOrderModel.php +++ b/app/Models/PurchaseOrderModel.php @@ -16,9 +16,9 @@ class PurchaseOrderModel extends Model use HasFactory; /** 状态:进行中(已生成,待完成) */ - public const STATUS_PENDING = 0; + public const int STATUS_PENDING = 0; /** 状态:已完成 */ - public const STATUS_COMPLETED = 3; + public const int STATUS_COMPLETED = 3; protected $table = 'purchase_order'; protected $primaryKey = 'id'; diff --git a/app/Services/PurchaseEditService.php b/app/Services/PurchaseEditService.php index 170d7d7..c6b8df2 100644 --- a/app/Services/PurchaseEditService.php +++ b/app/Services/PurchaseEditService.php @@ -8,55 +8,28 @@ use App\Models\PurchaseOrderModel; use App\Models\StoreOrderItemModel; use App\Models\StoreOrderModel; use Illuminate\Support\Facades\DB; +use Throwable; /** - * C4 采购单数据修改(明细矩阵:门店单元格 / 商品行) - * - * 采购单无独立明细表,修改直接回写订货明细(store_order_item),并重算: - * 1. 受影响订单汇总(recalculateOrderTotals 同口径:商品金额 + 附加金额) - * 2. 采购单头汇总:estimate_amount = Σ订货金额;actual_amount = Σ(称重>0 ? 称重×成本 : 数量×成本) + * 采购单数据修改 */ class PurchaseEditService { - /** - * 门店单元格修改:数量(必填)/ 称重(可空),金额按 数量×单价 重算 - */ - public function updateCell(StoreOrderItemModel $item, int $quantity, ?float $weight): StoreOrderItemModel - { - return DB::transaction(function () use ($item, $quantity, $weight) { - $item->quantity = $quantity; - if ($weight !== null) { - $item->weight = bcadd((string) $weight, '0', 3); - } - $item->amount = bcmul((string) $quantity, (string) $item->price, 2); - $item->save(); - - $order = StoreOrderModel::find($item->order_id); - if ($order !== null) { - $this->recalculateOrderTotals($order); - } - if ($item->purchase_id > 0) { - $purchase = PurchaseOrderModel::find($item->purchase_id); - if ($purchase !== null) { - $this->recalculatePurchaseTotals($purchase); - } - } - - return $item->refresh(); - }); - } /** * 商品行修改:品名/供应商/包规/单位/成本一键同步该商品全部订货明细; - * 实际称重按数量比例分摊(尾差修正守恒); * syncProduct = true 时同步更新商品档案(product 表) * + * @param PurchaseOrderModel $purchase + * @param int $productId * @param array{product_name?: string, supplier_id?: int, product_spec?: string, unit?: string, cost_price?: float} $attrs 行属性(仅同步传入键) - * @param float|null $weight 行实际称重合计,NULL 不修改 + * @param bool $syncProduct + * @return int + * @throws Throwable */ - public function updateRow(PurchaseOrderModel $purchase, int $productId, array $attrs, ?float $weight, bool $syncProduct = false): int + public function updateRow(PurchaseOrderModel $purchase, int $productId, array $attrs, bool $syncProduct = false): int { - return DB::transaction(function () use ($purchase, $productId, $attrs, $weight, $syncProduct) { + return DB::transaction(function () use ($purchase, $productId, $attrs, $syncProduct) { $items = StoreOrderItemModel::query() ->where('purchase_id', $purchase->id) ->where('product_id', $productId) @@ -87,7 +60,7 @@ class PurchaseEditService $item->fill($sync)->save(); } - // 同步至商品档案(软删除商品不同步,直接报错回滚) + // 同步至商品档案 if ($syncProduct) { $product = ProductModel::withTrashed()->find($productId); if ($product === null || $product->trashed()) { @@ -113,33 +86,6 @@ class PurchaseEditService } } - if ($weight !== null) { - $totalQty = $items->reduce( - static fn (string $carry, $item): string => bcadd($carry, (string) $item->quantity, 2), - '0' - ); - $target = bcadd((string) $weight, '0', 3); - $allocated = '0'; - $lastIndex = $items->count() - 1; - foreach ($items->values() as $index => $item) { - if ($index === $lastIndex) { - // 尾差修正:最后一行 = 总称重 − 已分摊,保证守恒 - $rowWeight = bcsub($target, $allocated, 3); - } elseif ((float) $totalQty > 0) { - $ratio = bcdiv((string) $item->quantity, $totalQty, 6); - $rowWeight = bcmul($target, $ratio, 3); - $allocated = bcadd($allocated, $rowWeight, 3); - } else { - $rowWeight = '0'; - } - $item->weight = $rowWeight; - $item->save(); - } - } - - $orderIds = $items->pluck('order_id')->unique()->all(); - StoreOrderModel::whereIn('id', $orderIds)->get() - ->each(fn (StoreOrderModel $order) => $this->recalculateOrderTotals($order)); $this->recalculatePurchaseTotals($purchase); return $items->count(); @@ -147,51 +93,24 @@ class PurchaseEditService } /** - * 重算订单汇总(与 StoreOrderController::recalculateOrderTotals 同口径) - */ - public function recalculateOrderTotals(StoreOrderModel $order): void - { - $totals = StoreOrderItemModel::query() - ->where('order_id', $order->id) - ->selectRaw('COALESCE(SUM(quantity), 0) as total_quantity') - ->selectRaw('COALESCE(SUM(weight), 0) as total_weight') - ->selectRaw('COALESCE(SUM(amount), 0) as product_amount') - ->first(); - - $productAmount = bcadd((string) $totals->product_amount, '0', 2); - $order->total_quantity = (int) $totals->total_quantity; - $order->total_weight = bcadd((string) $totals->total_weight, '0', 3); - $order->product_amount = $productAmount; - $order->total_amount = bcadd($productAmount, (string) $order->added_amount, 2); - $order->save(); - } - - /** - * 重算采购单头汇总:estimate_amount = Σ订货金额(销售口径); - * actual_amount = Σ(称重>0 ? 称重×成本 : 数量×成本)(采购成本口径) + * 重算采购金额汇总 */ public function recalculatePurchaseTotals(PurchaseOrderModel $purchase): void { $items = StoreOrderItemModel::query() ->where('purchase_id', $purchase->id) - ->get(['quantity', 'weight', 'amount', 'cost_price', 'product_spec']); + ->get(['quantity', 'cost_price']); - $totalQuantity = '0'; - $totalWeight = '0'; + $totalQuantity = 0; $estimate = '0'; - $actual = '0'; foreach ($items as $item) { - $unitCost = self::unitCost((string) ($item->cost_price ?? '0'), (string) $item->product_spec); - $totalQuantity = bcadd($totalQuantity, (string) $item->quantity, 2); - $totalWeight = bcadd($totalWeight, (string) $item->weight, 3); - $estimate = bcadd($estimate, (string) $item->amount, 2); - $actual = bcadd($actual, self::costAmount((string) $item->quantity, (string) $item->weight, $unitCost), 2); + $totalQuantity += $item->quantity; + $item_estimate = bcmul($item->cost_price, $item->quantity, 2); + $estimate = bcadd($estimate, $item_estimate, 2); } $purchase->total_quantity = $totalQuantity; - $purchase->total_weight = $totalWeight; $purchase->estimate_amount = $estimate; - $purchase->actual_amount = $actual; $purchase->save(); }