From e80e57cdcfff19d955889a12dee68963881ac831 Mon Sep 17 00:00:00 2001 From: Yatu Date: Wed, 1 Apr 2026 19:05:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20B-001=20=E9=A9=B3=E5=9B=9E=E5=BA=93?= =?UTF-8?q?=E5=AD=98=E9=87=8A=E6=94=BE=20+=20B-002=20=E7=BC=BA=E5=A4=B1?= =?UTF-8?q?=E8=B7=AF=E7=94=B1=20+=20B-003=20delivery=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E7=BB=9F=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - StockService: 添加unlockStock()方法 - OrderController: 驳回时自动解锁库存 - routes/api.php: 添加warehouse/bindings、operation-logs、delivery统一路由 --- app/Http/Controllers/OrderController.php | 26 ++++++++++++++++++++ app/Services/StockService.php | 31 ++++++++++++++++++++++++ routes/api.php | 22 ++++++++++++++++- 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/OrderController.php b/app/Http/Controllers/OrderController.php index 572ffe1..f7f7d5f 100644 --- a/app/Http/Controllers/OrderController.php +++ b/app/Http/Controllers/OrderController.php @@ -229,6 +229,19 @@ public function batchAudit(Request $request) continue; } + // 驳回时解锁库存 + if ($request->action === 'reject') { + $stockService = app(\App\Services\StockService::class); + foreach ($order->items as $item) { + $stockService->unlockStock( + $item->sku_code ?? $item->erp_sku_id, + $order->warehouse_id, + $item->quantity, + $order->id + ); + } + } + $order->update([ 'audit_status' => $request->action === 'approve' ? 'approved' : 'rejected', 'audit_comment' => $request->comment, @@ -284,6 +297,19 @@ public function auditOrder(Request $request, string $id) ], 400); } + // 驳回时解锁库存 + if ($request->action === 'reject') { + $stockService = app(\App\Services\StockService::class); + foreach ($order->items as $item) { + $stockService->unlockStock( + $item->sku_code ?? $item->erp_sku_id, + $order->warehouse_id, + $item->quantity, + $order->id + ); + } + } + $order->update([ 'audit_status' => $request->action === 'approve' ? 'approved' : 'rejected', 'audit_comment' => $request->comment, diff --git a/app/Services/StockService.php b/app/Services/StockService.php index 883a383..4e72b62 100644 --- a/app/Services/StockService.php +++ b/app/Services/StockService.php @@ -38,6 +38,37 @@ public function lock($skuCode, $warehouseId, $quantity, $orderId) }); } + /** + * 解锁库存(驳回订单时调用) + */ + public function unlockStock($skuCode, $warehouseId, $quantity, $orderId) + { + if ($quantity <= 0) { + throw new \InvalidArgumentException('解锁数量必须为正数'); + } + + return DB::transaction(function () use ($skuCode, $warehouseId, $quantity, $orderId) { + $stock = $this->getStock($skuCode, $warehouseId); + + if ($stock->locked_quantity < $quantity) { + throw new \Exception("商品 {$skuCode} 锁定库存不足,当前锁定{$stock->locked_quantity},需解锁{$quantity}"); + } + + $stock->decrement('locked_quantity', $quantity); + + StockLog::create([ + 'sku_code' => $skuCode, + 'warehouse_id' => $warehouseId, + 'change_quantity' => -$quantity, + 'type' => 'unlock', + 'order_id' => $orderId, + 'remark' => "解锁库存,订单ID {$orderId}", + ]); + + return $stock; + }); + } + /** * 获取指定SKU在仓库的可用库存 */ diff --git a/routes/api.php b/routes/api.php index 7f4a7d1..e8dd9e2 100644 --- a/routes/api.php +++ b/routes/api.php @@ -95,5 +95,25 @@ Route::delete('/{id}', [GoodsController::class, 'destroy']); }); -// 商品模块(ERP SKU) +// 仓库模板绑定 +Route::middleware('auth:sanctum')->prefix('warehouse')->group(function () { + Route::get('/bindings', [WarehouseTemplateBindingController::class, 'index']); + Route::post('/bindings', [WarehouseTemplateBindingController::class, 'store']); + Route::put('/bindings/{id}', [WarehouseTemplateBindingController::class, 'update']); + Route::delete('/bindings/{id}', [WarehouseTemplateBindingController::class, 'destroy']); +}); + +// 操作日志 +Route::middleware('auth:sanctum')->prefix('operation-logs')->group(function () { + Route::get('/', [OperationLogController::class, 'index']); + Route::get('/export', [OperationLogController::class, 'export']); +}); + +// 发货管理 - 统一路径 +Route::middleware('auth:sanctum')->prefix('delivery')->group(function () { + Route::get('/pending', [DeliveryController::class, 'pending']); + Route::get('/pending-delivery', [DeliveryController::class, 'pending']); // 兼容旧路径 + Route::get('/reprint/{id}', [DeliveryController::class, 'reprint']); + Route::post('/reprint', [DeliveryController::class, 'reprintBatch']); // 批量重打 +});