feat: API調整訂單與販賣機訂單同步強制使用warehouse_code,更新API對接文件,及優化生產與配方模組UI顯示
All checks were successful
ERP-Deploy-Demo / deploy-demo (push) Successful in 55s
All checks were successful
ERP-Deploy-Demo / deploy-demo (push) Successful in 55s
This commit is contained in:
@@ -20,6 +20,9 @@ interface Product {
|
||||
code: string;
|
||||
base_unit_id?: number;
|
||||
large_unit_id?: number;
|
||||
purchase_unit_id?: number;
|
||||
cost_price?: number;
|
||||
conversion_rate?: number;
|
||||
}
|
||||
|
||||
interface Unit {
|
||||
@@ -73,10 +76,10 @@ export default function RecipeEdit({ recipe, products, units }: Props) {
|
||||
code: recipe.code,
|
||||
name: recipe.name,
|
||||
description: recipe.description || "",
|
||||
yield_quantity: String(recipe.yield_quantity),
|
||||
yield_quantity: String(Number(recipe.yield_quantity || 0)),
|
||||
items: recipe.items.map(item => ({
|
||||
product_id: String(item.product_id),
|
||||
quantity: String(item.quantity),
|
||||
quantity: String(Number(item.quantity || 0)),
|
||||
unit_id: String(item.unit_id),
|
||||
remark: item.remark || "",
|
||||
ui_product_name: item.product?.name,
|
||||
@@ -133,6 +136,25 @@ export default function RecipeEdit({ recipe, products, units }: Props) {
|
||||
put(route('recipes.update', recipe.id));
|
||||
};
|
||||
|
||||
const getUnitCost = (productId: string, unitId: string) => {
|
||||
const product = products.find(p => String(p.id) === productId);
|
||||
if (!product || !product.cost_price) return 0;
|
||||
let cost = Number(product.cost_price);
|
||||
|
||||
// Check if selected unit is large_unit or purchase_unit
|
||||
if (unitId && (String(unitId) === String(product.large_unit_id) || String(unitId) === String(product.purchase_unit_id))) {
|
||||
cost = cost * Number(product.conversion_rate || 1);
|
||||
}
|
||||
return cost;
|
||||
};
|
||||
|
||||
const totalCost = data.items.reduce((sum, item) => {
|
||||
const unitCost = getUnitCost(item.product_id, item.unit_id);
|
||||
return sum + (unitCost * Number(item.quantity || 0));
|
||||
}, 0);
|
||||
|
||||
const unitCost = Number(data.yield_quantity) > 0 ? totalCost / Number(data.yield_quantity) : 0;
|
||||
|
||||
return (
|
||||
<AuthenticatedLayout breadcrumbs={getBreadcrumbs("recipes", [{ label: "編輯", isPage: true }])}>
|
||||
<Head title="編輯配方" />
|
||||
@@ -258,10 +280,12 @@ export default function RecipeEdit({ recipe, products, units }: Props) {
|
||||
<Table>
|
||||
<TableHeader className="bg-gray-50">
|
||||
<TableRow>
|
||||
<TableHead className="w-[35%]">原物料商品</TableHead>
|
||||
<TableHead className="w-[20%]">標準用量</TableHead>
|
||||
<TableHead className="w-[20%]">單位</TableHead>
|
||||
<TableHead className="w-[20%]">備註</TableHead>
|
||||
<TableHead className="w-[30%]">原物料商品</TableHead>
|
||||
<TableHead className="w-[15%]">標準用量</TableHead>
|
||||
<TableHead className="w-[15%]">單位</TableHead>
|
||||
<TableHead className="w-[10%] text-right">預估單價</TableHead>
|
||||
<TableHead className="w-[10%] text-right">成本小計</TableHead>
|
||||
<TableHead className="w-[15%]">備註</TableHead>
|
||||
<TableHead className="w-[5%]"></TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
@@ -297,10 +321,23 @@ export default function RecipeEdit({ recipe, products, units }: Props) {
|
||||
className="text-right"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="align-middle">
|
||||
<div className="text-sm text-gray-700 bg-gray-50 px-3 py-2 rounded-md border border-gray-100 min-h-[38px] flex items-center">
|
||||
{item.ui_unit_name || (units.find(u => String(u.id) === item.unit_id)?.name) || '-'}
|
||||
</div>
|
||||
<TableCell className="align-top">
|
||||
<SearchableSelect
|
||||
value={item.unit_id}
|
||||
onValueChange={(v) => updateItem(index, 'unit_id', v)}
|
||||
options={units.map(u => ({
|
||||
label: u.name,
|
||||
value: String(u.id)
|
||||
}))}
|
||||
placeholder="單位"
|
||||
className="w-full"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="align-middle text-right text-sm text-gray-600">
|
||||
{getUnitCost(item.product_id, item.unit_id).toLocaleString(undefined, { maximumFractionDigits: 2 })} 元
|
||||
</TableCell>
|
||||
<TableCell className="align-middle text-right font-medium text-gray-900">
|
||||
{(getUnitCost(item.product_id, item.unit_id) * Number(item.quantity || 0)).toLocaleString(undefined, { maximumFractionDigits: 2 })} 元
|
||||
</TableCell>
|
||||
<TableCell className="align-top">
|
||||
<Input
|
||||
@@ -325,6 +362,23 @@ export default function RecipeEdit({ recipe, products, units }: Props) {
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
|
||||
{/* 配方成本總計區塊 */}
|
||||
<div className="mt-6 flex justify-end">
|
||||
<div className="bg-gray-50 p-4 rounded-lg border border-gray-200 min-w-[300px]">
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<span className="text-sm text-gray-600">配方預估總成本</span>
|
||||
<span className="text-lg font-bold text-gray-900">{totalCost.toLocaleString(undefined, { maximumFractionDigits: 2 })} 元</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center pt-2 border-t border-gray-200">
|
||||
<span className="text-sm font-medium text-gray-700">單位生產成本
|
||||
<span className="text-xs text-gray-500 ml-1">(共 {Number(data.yield_quantity || 0).toLocaleString(undefined, { maximumFractionDigits: 4 })} 份)</span>
|
||||
</span>
|
||||
<span className="text-md font-bold text-primary-main">{unitCost.toLocaleString(undefined, { maximumFractionDigits: 2 })} 元</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{errors.items && <p className="text-red-500 text-sm mt-2">{errors.items}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user