diff --git a/src/components/ProductionProcess/DrinkProductionQtyDashboard.tsx b/src/components/ProductionProcess/DrinkProductionQtyDashboard.tsx index 3a73b4c2..a99d3607 100644 --- a/src/components/ProductionProcess/DrinkProductionQtyDashboard.tsx +++ b/src/components/ProductionProcess/DrinkProductionQtyDashboard.tsx @@ -44,7 +44,10 @@ import { DrinkShipmentQtyDeliveryDetail, } from "@/app/api/jo/actions"; import { arrayToDayjs } from "@/app/utils/formatUtil"; -import { exportDrinkProductionQtyXlsx } from "@/components/ProductionProcess/exportDrinkProductionQtyXlsx"; +import { + exportDrinkProductionQtyXlsx, + type DrinkViewMode, +} from "@/components/ProductionProcess/exportDrinkProductionQtyXlsx"; const REFRESH_INTERVAL = 10 * 60 * 1000; // 10 分鐘 @@ -58,8 +61,6 @@ const JO_STATUS_FILTER_VALUES = [ "completed", ] as const; -type DrinkViewMode = "actual" | "planned" | "shipment"; - const formatQty = (qty: number | null | undefined): string => { if (qty === null || qty === undefined || Number.isNaN(qty)) return "-"; return qty.toLocaleString(undefined, { maximumFractionDigits: 2 }); @@ -332,6 +333,7 @@ const DrinkProductionQtyDashboard: React.FC = () => { onClick={() => { exportDrinkProductionQtyXlsx({ data, + shipmentData, viewMode, selectedDate: selectedDate.format("YYYY-MM-DD"), statusFilter: joStatusFilter, diff --git a/src/components/ProductionProcess/exportDrinkProductionQtyXlsx.ts b/src/components/ProductionProcess/exportDrinkProductionQtyXlsx.ts index 8584a884..4a3abeca 100644 --- a/src/components/ProductionProcess/exportDrinkProductionQtyXlsx.ts +++ b/src/components/ProductionProcess/exportDrinkProductionQtyXlsx.ts @@ -4,9 +4,10 @@ import { exportMultiSheetToXlsx } from "@/app/(main)/chart/_components/exportCha import type { DrinkProductionQtyJobOrderDetail, DrinkProductionQtyResponse, + DrinkShipmentQtyResponse, } from "@/app/api/jo/actions"; -type DrinkViewMode = "actual" | "planned"; +export type DrinkViewMode = "actual" | "planned" | "shipment"; const formatDateTime = (value: unknown): string => { if (value == null || value === "") return ""; @@ -27,28 +28,102 @@ const formatDate = (value: string | null | undefined): string => { export type ExportDrinkProductionQtyParams = { data: DrinkProductionQtyResponse[]; + shipmentData?: DrinkShipmentQtyResponse[]; viewMode: DrinkViewMode; selectedDate: string; statusFilter: string; t: TFunction; }; +const viewModeLabel = (viewMode: DrinkViewMode, t: TFunction): string => { + switch (viewMode) { + case "planned": + return t("Drink detail mode: planned"); + case "shipment": + return t("Drink detail mode: shipment"); + case "actual": + return t("Drink detail mode: actual"); + default: { + const _exhaustive: never = viewMode; + return _exhaustive; + } + } +}; + +const formatDoStatus = (status: string | null | undefined, t: TFunction): string => { + if (!status) return ""; + switch (status.toLowerCase()) { + case "pending": + return t("Drink do status pending"); + case "receiving": + return t("Drink do status receiving"); + case "completed": + return t("Drink do status completed"); + default: + return t(status, { ns: "do", defaultValue: status }); + } +}; + export function exportDrinkProductionQtyXlsx({ data, + shipmentData = [], viewMode, selectedDate, statusFilter, t, }: ExportDrinkProductionQtyParams): void { - const viewLabel = - viewMode === "planned" - ? t("Drink detail mode: planned") - : t("Drink detail mode: actual"); + const viewLabel = viewModeLabel(viewMode, t); const statusFilterLabel = statusFilter ? t(statusFilter, { ns: "jo", defaultValue: statusFilter }) : t("All"); const exportedAt = dayjs().format("YYYY-MM-DD HH:mm:ss"); + if (viewMode === "shipment") { + const doRows: Record[] = []; + const itemRows = shipmentData.map((item) => { + for (const delivery of item.deliveries ?? []) { + doRows.push({ + [t("Export meta: exported at")]: exportedAt, + [t("Drink detail mode label")]: viewLabel, + [t("Date")]: selectedDate, + [t("Item Code")]: item.itemCode ?? "", + [t("Goods Name")]: item.itemName ?? "", + [t("Unit")]: item.uom ?? "", + [t("Delivery Order Code", { ns: "do" })]: delivery.deliveryOrderCode ?? "", + [t("Delivery Order Status", { ns: "do" })]: formatDoStatus( + delivery.deliveryOrderStatus, + t, + ), + [t("Shop Name", { ns: "do" })]: + delivery.shopName || delivery.shopCode || "", + [t("Delivery Date", { ns: "do" })]: formatDate(delivery.deliveryDate), + [t("Shipment Order Qty")]: delivery.orderQty ?? 0, + [t("Shipped Qty")]: delivery.shippedQty ?? 0, + }); + } + return { + [t("Export meta: exported at")]: exportedAt, + [t("Drink detail mode label")]: viewLabel, + [t("Date")]: selectedDate, + [t("Item Code")]: item.itemCode ?? "", + [t("Goods Name")]: item.itemName ?? "", + [t("Unit")]: item.uom ?? "", + [t("Shipment Order Qty")]: item.totalOrderQty ?? 0, + [t("Shipped Qty")]: item.totalShippedQty ?? 0, + [t("DO count")]: (item.deliveries ?? []).length, + }; + }); + const filename = `DrinkProductionQty_shipment_${selectedDate}_${dayjs().format("HHmm")}`; + exportMultiSheetToXlsx( + [ + { name: t("Excel sheet: DO detail"), rows: doRows }, + { name: t("Excel sheet: item summary"), rows: itemRows }, + ], + filename, + ); + return; + } + const filterJos = ( jobOrders: DrinkProductionQtyJobOrderDetail[], ): DrinkProductionQtyJobOrderDetail[] => { diff --git a/src/i18n/en/productionProcess.json b/src/i18n/en/productionProcess.json index 446d7bec..efdff3e8 100644 --- a/src/i18n/en/productionProcess.json +++ b/src/i18n/en/productionProcess.json @@ -119,9 +119,11 @@ "QC users": "QC users", "Put away users": "Put-away users", "Excel sheet: JO detail": "JO detail", + "Excel sheet: DO detail": "DO detail", "Excel sheet: process people": "Process people", "Excel sheet: item summary": "Item summary", "JO count": "JO count", + "DO count": "DO count", "Process seq": "Process seq", "Handler": "Handler", "Goods Name": "Goods Name", diff --git a/src/i18n/zh/productionProcess.json b/src/i18n/zh/productionProcess.json index c70d4a5b..814ff3fc 100644 --- a/src/i18n/zh/productionProcess.json +++ b/src/i18n/zh/productionProcess.json @@ -119,9 +119,11 @@ "QC users": "QC人員", "Put away users": "上架人員", "Excel sheet: JO detail": "JO明細", + "Excel sheet: DO detail": "DO明細", "Excel sheet: process people": "工序人員", "Excel sheet: item summary": "貨品彙總", "JO count": "工單筆數", + "DO count": "送貨單筆數", "Process seq": "工序序號", "Handler": "處理人", "Goods Name": "貨品名稱",