feat: 標準化全系統數值輸入欄位與擴充商品價格功能
1. UI 標準化: - 針對全系統數值輸入欄位統一加上 step='any' 以支援小數點。 - 表格形式 (Table) 的數值輸入欄位統一加上 text-right 靠右對齊。 - 修正 Components 與 Pages 中所有涉及金額與數量的輸入框。 2. 功能擴充與修正: - 擴充 Product 模型與相關 Dialog 以支援多種價格設定。 - 修正 Inventory/GoodsReceipt/Create.tsx 未使用的變數錯誤。 - 優化庫存相關頁面的 UI 一致性。 3. 其他: - 更新相關的 Type 定義與 Controller 邏輯。
This commit is contained in:
@@ -181,6 +181,16 @@ class AdjustDocController extends Controller
|
||||
{
|
||||
$doc->load(['items.product.baseUnit', 'createdBy', 'postedBy', 'warehouse', 'countDoc']);
|
||||
|
||||
// Pre-fetch relevant Inventory information (mainly for expiry date)
|
||||
$inventoryMap = \App\Modules\Inventory\Models\Inventory::withTrashed()
|
||||
->where('warehouse_id', $doc->warehouse_id)
|
||||
->whereIn('product_id', $doc->items->pluck('product_id'))
|
||||
->whereIn('batch_number', $doc->items->pluck('batch_number'))
|
||||
->get()
|
||||
->mapWithKeys(function ($inv) {
|
||||
return [$inv->product_id . '-' . $inv->batch_number => $inv];
|
||||
});
|
||||
|
||||
$docData = [
|
||||
'id' => (string) $doc->id,
|
||||
'doc_no' => $doc->doc_no,
|
||||
@@ -193,13 +203,15 @@ class AdjustDocController extends Controller
|
||||
'created_by' => $doc->createdBy?->name,
|
||||
'count_doc_id' => $doc->count_doc_id ? (string)$doc->count_doc_id : null,
|
||||
'count_doc_no' => $doc->countDoc?->doc_no,
|
||||
'items' => $doc->items->map(function ($item) {
|
||||
'items' => $doc->items->map(function ($item) use ($inventoryMap) {
|
||||
$inv = $inventoryMap->get($item->product_id . '-' . $item->batch_number);
|
||||
return [
|
||||
'id' => (string) $item->id,
|
||||
'product_id' => (string) $item->product_id,
|
||||
'product_name' => $item->product->name,
|
||||
'product_code' => $item->product->code,
|
||||
'batch_number' => $item->batch_number,
|
||||
'expiry_date' => $inv && $inv->expiry_date ? $inv->expiry_date->format('Y-m-d') : null,
|
||||
'unit' => $item->product->baseUnit?->name,
|
||||
'qty_before' => (float) $item->qty_before,
|
||||
'adjust_qty' => (float) $item->adjust_qty,
|
||||
|
||||
@@ -94,6 +94,16 @@ class CountDocController extends Controller
|
||||
{
|
||||
$doc->load(['items.product.baseUnit', 'createdBy', 'completedBy', 'warehouse']);
|
||||
|
||||
// 預先抓取相關的 Inventory 資訊 (主要為了取得效期)
|
||||
$inventoryMap = \App\Modules\Inventory\Models\Inventory::withTrashed()
|
||||
->where('warehouse_id', $doc->warehouse_id)
|
||||
->whereIn('product_id', $doc->items->pluck('product_id'))
|
||||
->whereIn('batch_number', $doc->items->pluck('batch_number'))
|
||||
->get()
|
||||
->mapWithKeys(function ($inv) {
|
||||
return [$inv->product_id . '-' . $inv->batch_number => $inv];
|
||||
});
|
||||
|
||||
$docData = [
|
||||
'id' => (string) $doc->id,
|
||||
'doc_no' => $doc->doc_no,
|
||||
@@ -103,12 +113,16 @@ class CountDocController extends Controller
|
||||
'remarks' => $doc->remarks,
|
||||
'snapshot_date' => $doc->snapshot_date ? $doc->snapshot_date->format('Y-m-d H:i') : null,
|
||||
'created_by' => $doc->createdBy?->name,
|
||||
'items' => $doc->items->map(function ($item) {
|
||||
'items' => $doc->items->map(function ($item) use ($inventoryMap) {
|
||||
$key = $item->product_id . '-' . $item->batch_number;
|
||||
$inv = $inventoryMap->get($key);
|
||||
|
||||
return [
|
||||
'id' => (string) $item->id,
|
||||
'product_name' => $item->product->name,
|
||||
'product_code' => $item->product->code,
|
||||
'batch_number' => $item->batch_number,
|
||||
'expiry_date' => $inv && $inv->expiry_date ? $inv->expiry_date->format('Y-m-d') : null, // 新增效期
|
||||
'unit' => $item->product->baseUnit?->name,
|
||||
'system_qty' => (float) $item->system_qty,
|
||||
'counted_qty' => is_null($item->counted_qty) ? '' : (float) $item->counted_qty,
|
||||
|
||||
@@ -131,16 +131,18 @@ class InventoryController extends Controller
|
||||
{
|
||||
// ... (unchanged) ...
|
||||
$products = Product::with(['baseUnit', 'largeUnit'])
|
||||
->select('id', 'name', 'code', 'base_unit_id', 'large_unit_id', 'conversion_rate')
|
||||
->select('id', 'name', 'code', 'barcode', 'base_unit_id', 'large_unit_id', 'conversion_rate', 'cost_price')
|
||||
->get()
|
||||
->map(function ($product) {
|
||||
return [
|
||||
'id' => (string) $product->id,
|
||||
'name' => $product->name,
|
||||
'code' => $product->code,
|
||||
'barcode' => $product->barcode,
|
||||
'baseUnit' => $product->baseUnit?->name ?? '個',
|
||||
'largeUnit' => $product->largeUnit?->name, // 可能為 null
|
||||
'conversionRate' => (float) $product->conversion_rate,
|
||||
'costPrice' => (float) $product->cost_price,
|
||||
];
|
||||
});
|
||||
|
||||
|
||||
@@ -96,6 +96,10 @@ class ProductController extends Controller
|
||||
] : null,
|
||||
'conversionRate' => (float) $product->conversion_rate,
|
||||
'location' => $product->location,
|
||||
'cost_price' => (float) $product->cost_price,
|
||||
'price' => (float) $product->price,
|
||||
'member_price' => (float) $product->member_price,
|
||||
'wholesale_price' => (float) $product->wholesale_price,
|
||||
];
|
||||
});
|
||||
|
||||
@@ -126,7 +130,12 @@ class ProductController extends Controller
|
||||
'large_unit_id' => 'nullable|exists:units,id',
|
||||
'conversion_rate' => 'required_with:large_unit_id|nullable|numeric|min:0.0001',
|
||||
'purchase_unit_id' => 'nullable|exists:units,id',
|
||||
'purchase_unit_id' => 'nullable|exists:units,id',
|
||||
'location' => 'nullable|string|max:255',
|
||||
'cost_price' => 'nullable|numeric|min:0',
|
||||
'price' => 'nullable|numeric|min:0',
|
||||
'member_price' => 'nullable|numeric|min:0',
|
||||
'wholesale_price' => 'nullable|numeric|min:0',
|
||||
], [
|
||||
'code.required' => '商品代號為必填',
|
||||
'code.max' => '商品代號最多 8 碼',
|
||||
@@ -142,6 +151,14 @@ class ProductController extends Controller
|
||||
'conversion_rate.required_with' => '填寫大單位時,換算率為必填',
|
||||
'conversion_rate.numeric' => '換算率必須為數字',
|
||||
'conversion_rate.min' => '換算率最小為 0.0001',
|
||||
'cost_price.numeric' => '成本價必須為數字',
|
||||
'cost_price.min' => '成本價不能小於 0',
|
||||
'price.numeric' => '售價必須為數字',
|
||||
'price.min' => '售價不能小於 0',
|
||||
'member_price.numeric' => '會員價必須為數字',
|
||||
'member_price.min' => '會員價不能小於 0',
|
||||
'wholesale_price.numeric' => '批發價必須為數字',
|
||||
'wholesale_price.min' => '批發價不能小於 0',
|
||||
]);
|
||||
|
||||
$product = Product::create($validated);
|
||||
@@ -165,7 +182,12 @@ class ProductController extends Controller
|
||||
'large_unit_id' => 'nullable|exists:units,id',
|
||||
'conversion_rate' => 'required_with:large_unit_id|nullable|numeric|min:0.0001',
|
||||
'purchase_unit_id' => 'nullable|exists:units,id',
|
||||
'purchase_unit_id' => 'nullable|exists:units,id',
|
||||
'location' => 'nullable|string|max:255',
|
||||
'cost_price' => 'nullable|numeric|min:0',
|
||||
'price' => 'nullable|numeric|min:0',
|
||||
'member_price' => 'nullable|numeric|min:0',
|
||||
'wholesale_price' => 'nullable|numeric|min:0',
|
||||
], [
|
||||
'code.required' => '商品代號為必填',
|
||||
'code.max' => '商品代號最多 8 碼',
|
||||
@@ -181,6 +203,14 @@ class ProductController extends Controller
|
||||
'conversion_rate.required_with' => '填寫大單位時,換算率為必填',
|
||||
'conversion_rate.numeric' => '換算率必須為數字',
|
||||
'conversion_rate.min' => '換算率最小為 0.0001',
|
||||
'cost_price.numeric' => '成本價必須為數字',
|
||||
'cost_price.min' => '成本價不能小於 0',
|
||||
'price.numeric' => '售價必須為數字',
|
||||
'price.min' => '售價不能小於 0',
|
||||
'member_price.numeric' => '會員價必須為數字',
|
||||
'member_price.min' => '會員價不能小於 0',
|
||||
'wholesale_price.numeric' => '批發價必須為數字',
|
||||
'wholesale_price.min' => '批發價不能小於 0',
|
||||
]);
|
||||
|
||||
$product->update($validated);
|
||||
|
||||
@@ -125,6 +125,7 @@ class TransferOrderController extends Controller
|
||||
'product_name' => $item->product->name,
|
||||
'product_code' => $item->product->code,
|
||||
'batch_number' => $item->batch_number,
|
||||
'expiry_date' => $stock && $stock->expiry_date ? $stock->expiry_date->format('Y-m-d') : null,
|
||||
'unit' => $item->product->baseUnit?->name,
|
||||
'quantity' => (float) $item->quantity,
|
||||
'max_quantity' => $item->snapshot_quantity ? (float) $item->snapshot_quantity : ($stock ? (float) $stock->quantity : 0.0),
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace App\Modules\Inventory\Exports;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
|
||||
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
// use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
|
||||
|
||||
class ProductTemplateExport implements WithHeadings, WithColumnFormatting
|
||||
@@ -22,6 +22,10 @@ class ProductTemplateExport implements WithHeadings, WithColumnFormatting
|
||||
'基本單位',
|
||||
'大單位',
|
||||
'換算率',
|
||||
'成本價',
|
||||
'售價',
|
||||
'會員價',
|
||||
'批發價',
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
@@ -74,6 +74,10 @@ class ProductImport implements ToModel, WithHeadingRow, WithValidation, WithMapp
|
||||
'large_unit_id' => $largeUnitId,
|
||||
'conversion_rate' => $row['換算率'] ?? null,
|
||||
'purchase_unit_id' => null,
|
||||
'cost_price' => $row['成本價'] ?? null,
|
||||
'price' => $row['售價'] ?? null,
|
||||
'member_price' => $row['會員價'] ?? null,
|
||||
'wholesale_price' => $row['批發價'] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -100,6 +104,10 @@ class ProductImport implements ToModel, WithHeadingRow, WithValidation, WithMapp
|
||||
}],
|
||||
|
||||
'換算率' => ['nullable', 'numeric', 'min:0.0001', 'required_with:大單位'],
|
||||
'成本價' => ['nullable', 'numeric', 'min:0'],
|
||||
'售價' => ['nullable', 'numeric', 'min:0'],
|
||||
'會員價' => ['nullable', 'numeric', 'min:0'],
|
||||
'批發價' => ['nullable', 'numeric', 'min:0'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@ class Product extends Model
|
||||
'conversion_rate',
|
||||
'purchase_unit_id',
|
||||
'location',
|
||||
'cost_price',
|
||||
'price',
|
||||
'member_price',
|
||||
'wholesale_price',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
|
||||
Reference in New Issue
Block a user