feat(production): 優化生產單 BOM 原物料選取邏輯,支援商品 -> 倉庫 -> 批號連動與 API 分佈查詢
This commit is contained in:
@@ -36,7 +36,7 @@ class InventoryAdjustDoc extends Model
|
||||
static::creating(function ($model) {
|
||||
if (empty($model->doc_no)) {
|
||||
$today = date('Ymd');
|
||||
$prefix = 'ADJ' . $today;
|
||||
$prefix = 'ADJ-' . $today . '-';
|
||||
|
||||
$lastDoc = static::where('doc_no', 'like', $prefix . '%')
|
||||
->orderBy('doc_no', 'desc')
|
||||
|
||||
@@ -36,7 +36,7 @@ class InventoryCountDoc extends Model
|
||||
static::creating(function ($model) {
|
||||
if (empty($model->doc_no)) {
|
||||
$today = date('Ymd');
|
||||
$prefix = 'CNT' . $today;
|
||||
$prefix = 'CNT-' . $today . '-';
|
||||
|
||||
// 查詢當天編號最大的單據
|
||||
$lastDoc = static::where('doc_no', 'like', $prefix . '%')
|
||||
|
||||
@@ -35,7 +35,7 @@ class InventoryTransferOrder extends Model
|
||||
static::creating(function ($model) {
|
||||
if (empty($model->doc_no)) {
|
||||
$today = date('Ymd');
|
||||
$prefix = 'TRF' . $today;
|
||||
$prefix = 'TRF-' . $today . '-';
|
||||
|
||||
$lastDoc = static::where('doc_no', 'like', $prefix . '%')
|
||||
->orderBy('doc_no', 'desc')
|
||||
|
||||
@@ -90,8 +90,8 @@ class GoodsReceiptService
|
||||
|
||||
private function generateCode(string $date)
|
||||
{
|
||||
// Format: GR + YYYYMMDD + NNN
|
||||
$prefix = 'GR' . date('Ymd', strtotime($date));
|
||||
// Format: GR-YYYYMMDD-NN
|
||||
$prefix = 'GR-' . date('Ymd', strtotime($date)) . '-';
|
||||
|
||||
$last = GoodsReceipt::where('code', 'like', $prefix . '%')
|
||||
->orderBy('id', 'desc')
|
||||
@@ -99,11 +99,11 @@ class GoodsReceiptService
|
||||
->first();
|
||||
|
||||
if ($last) {
|
||||
$seq = intval(substr($last->code, -3)) + 1;
|
||||
$seq = intval(substr($last->code, -2)) + 1;
|
||||
} else {
|
||||
$seq = 1;
|
||||
}
|
||||
|
||||
return $prefix . str_pad($seq, 3, '0', STR_PAD_LEFT);
|
||||
return $prefix . str_pad($seq, 2, '0', STR_PAD_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,20 +187,20 @@ class PurchaseOrderController extends Controller
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
// 生成單號:POYYYYMMDD001
|
||||
// 生成單號:PO-YYYYMMDD-01
|
||||
$today = now()->format('Ymd');
|
||||
$prefix = 'PO' . $today;
|
||||
$prefix = 'PO-' . $today . '-';
|
||||
$lastOrder = PurchaseOrder::where('code', 'like', $prefix . '%')
|
||||
->lockForUpdate() // 鎖定以避免並發衝突
|
||||
->orderBy('code', 'desc')
|
||||
->first();
|
||||
|
||||
if ($lastOrder) {
|
||||
// 取得最後 3 碼序號並加 1
|
||||
$lastSequence = intval(substr($lastOrder->code, -3));
|
||||
$sequence = str_pad($lastSequence + 1, 3, '0', STR_PAD_LEFT);
|
||||
// 取得最後 2 碼序號並加 1
|
||||
$lastSequence = intval(substr($lastOrder->code, -2));
|
||||
$sequence = str_pad($lastSequence + 1, 2, '0', STR_PAD_LEFT);
|
||||
} else {
|
||||
$sequence = '001';
|
||||
$sequence = '01';
|
||||
}
|
||||
$code = $prefix . $sequence;
|
||||
|
||||
|
||||
@@ -269,6 +269,33 @@ class ProductionOrderController extends Controller
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得商品在各倉庫的庫存分佈
|
||||
*/
|
||||
public function getProductWarehouses($productId)
|
||||
{
|
||||
$inventories = \App\Modules\Inventory\Models\Inventory::with(['warehouse', 'product.baseUnit'])
|
||||
->where('product_id', $productId)
|
||||
->where('quantity', '>', 0)
|
||||
->get();
|
||||
|
||||
$data = $inventories->map(function ($inv) {
|
||||
return [
|
||||
'id' => $inv->id, // Inventory ID
|
||||
'warehouse_id' => $inv->warehouse_id,
|
||||
'warehouse_name' => $inv->warehouse->name ?? '未知倉庫',
|
||||
'batch_number' => $inv->batch_number,
|
||||
'quantity' => $inv->quantity,
|
||||
'expiry_date' => $inv->expiry_date ? $inv->expiry_date->format('Y-m-d') : null,
|
||||
'unit_name' => $inv->product->baseUnit->name ?? '',
|
||||
'base_unit_id' => $inv->product->base_unit_id ?? null,
|
||||
'conversion_rate' => $inv->product->conversion_rate ?? 1,
|
||||
];
|
||||
});
|
||||
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 編輯生產單
|
||||
*/
|
||||
|
||||
@@ -30,6 +30,10 @@ Route::middleware('auth')->group(function () {
|
||||
->middleware('permission:production_orders.create')
|
||||
->name('api.production.warehouses.inventories');
|
||||
|
||||
Route::get('/api/production/products/{product}/inventories', [ProductionOrderController::class, 'getProductWarehouses'])
|
||||
->middleware('permission:production_orders.create')
|
||||
->name('api.production.products.inventories');
|
||||
|
||||
Route::get('/api/production/recipes/latest-by-product/{productId}', [RecipeController::class, 'getLatestByProduct'])
|
||||
->name('api.production.recipes.latest-by-product');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user