庫存明細報告 improve speed 送貨訂單與倉存單位不符 excel 預計到貨→預計送貨fix負數倉
| @@ -8,10 +8,10 @@ import { | |||||
| TextField, | TextField, | ||||
| } from "@mui/material"; | } from "@mui/material"; | ||||
| export type QcItemFilter = "measurable" | "non_measurable"; | |||||
| export type QcItemFilter = "all" | "measurable"; | |||||
| export const REP010_DEFAULT_CRITERIA: Record<string, string> = { | export const REP010_DEFAULT_CRITERIA: Record<string, string> = { | ||||
| qcItemFilter: "measurable", | |||||
| qcItemScope: "all", | |||||
| }; | }; | ||||
| interface ItemQcReportFiltersProps { | interface ItemQcReportFiltersProps { | ||||
| @@ -21,18 +21,19 @@ interface ItemQcReportFiltersProps { | |||||
| const gridSize = { xs: 12, sm: 6 }; | const gridSize = { xs: 12, sm: 6 }; | ||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 64 | v1.0.0 | 2026-08-11 */ | |||||
| export default function ItemQcReportFilters({ | export default function ItemQcReportFilters({ | ||||
| criteria, | criteria, | ||||
| onFieldChange, | onFieldChange, | ||||
| }: ItemQcReportFiltersProps) { | }: ItemQcReportFiltersProps) { | ||||
| const qcItemFilter = (criteria.qcItemFilter || "measurable") as QcItemFilter; | |||||
| const qcItemFilter = (criteria.qcItemScope || "all") as QcItemFilter; | |||||
| return ( | return ( | ||||
| <Grid container spacing={3}> | <Grid container spacing={3}> | ||||
| <Grid item {...gridSize}> | <Grid item {...gridSize}> | ||||
| <TextField | <TextField | ||||
| fullWidth | fullWidth | ||||
| label="QC 檢測日期:由 Last In Date Start" | |||||
| label="QC 檢測日期:由 QC Date Start" | |||||
| type="date" | type="date" | ||||
| value={criteria.lastInDateStart || ""} | value={criteria.lastInDateStart || ""} | ||||
| onChange={(e) => onFieldChange("lastInDateStart", e.target.value)} | onChange={(e) => onFieldChange("lastInDateStart", e.target.value)} | ||||
| @@ -42,7 +43,7 @@ export default function ItemQcReportFilters({ | |||||
| <Grid item {...gridSize}> | <Grid item {...gridSize}> | ||||
| <TextField | <TextField | ||||
| fullWidth | fullWidth | ||||
| label="QC 檢測日期:至 Last In Date End" | |||||
| label="QC 檢測日期:至 QC Date End" | |||||
| type="date" | type="date" | ||||
| value={criteria.lastInDateEnd || ""} | value={criteria.lastInDateEnd || ""} | ||||
| onChange={(e) => onFieldChange("lastInDateEnd", e.target.value)} | onChange={(e) => onFieldChange("lastInDateEnd", e.target.value)} | ||||
| @@ -54,10 +55,10 @@ export default function ItemQcReportFilters({ | |||||
| fullWidth | fullWidth | ||||
| select | select | ||||
| label="QC 類型" | label="QC 類型" | ||||
| value={criteria.qcType || ""} | |||||
| value={criteria.qcType || "all"} | |||||
| onChange={(e) => onFieldChange("qcType", e.target.value)} | onChange={(e) => onFieldChange("qcType", e.target.value)} | ||||
| > | > | ||||
| <MenuItem value="">全部</MenuItem> | |||||
| <MenuItem value="all">全部</MenuItem> | |||||
| <MenuItem value="IQC">IQC</MenuItem> | <MenuItem value="IQC">IQC</MenuItem> | ||||
| <MenuItem value="EPQC">EPQC</MenuItem> | <MenuItem value="EPQC">EPQC</MenuItem> | ||||
| </TextField> | </TextField> | ||||
| @@ -75,17 +76,17 @@ export default function ItemQcReportFilters({ | |||||
| <TextField | <TextField | ||||
| fullWidth | fullWidth | ||||
| select | select | ||||
| label="溫濕度數據篩選" | |||||
| value={qcItemFilter} | |||||
| onChange={(e) => onFieldChange("qcItemFilter", e.target.value)} | |||||
| label="QC 項目範圍" | |||||
| value={qcItemFilter === "measurable" ? "measurable" : "all"} | |||||
| onChange={(e) => onFieldChange("qcItemScope", e.target.value)} | |||||
| > | > | ||||
| <MenuItem value="all">全部 QC 項目</MenuItem> | |||||
| <MenuItem value="measurable">只包含溫度濕度</MenuItem> | <MenuItem value="measurable">只包含溫度濕度</MenuItem> | ||||
| <MenuItem value="non_measurable">不包含溫度濕度</MenuItem> | |||||
| </TextField> | </TextField> | ||||
| <FormHelperText> | <FormHelperText> | ||||
| {qcItemFilter === "measurable" | {qcItemFilter === "measurable" | ||||
| ? "僅匯出已填寫實測值的溫度/濕度 QC 項目。" | |||||
| : "僅匯出非溫度/濕度之其他 QC 檢驗項目。"} | |||||
| ? "僅匯出溫度/濕度 QC 項目(與 production 舊預設相同)。" | |||||
| : "匯出全部 QC 檢驗項目(含溫度/濕度)。"} | |||||
| </FormHelperText> | </FormHelperText> | ||||
| </Grid> | </Grid> | ||||
| </Grid> | </Grid> | ||||
| @@ -44,7 +44,7 @@ interface ItemCodeWithName { | |||||
| } | } | ||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 39 | v1.0.0 | 2026-08-03 */ | /** FP-MTMS Version Checklist | Functions Ref. No. 39 | v1.0.0 | 2026-08-03 */ | ||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 60 | v1.0.0 | 2026-08-10 */ | |||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 60 | v1.0.1 | 2026-08-11 */ | |||||
| export default function ReportPage() { | export default function ReportPage() { | ||||
| const { data: session } = useSession() as { data: SessionWithTokens | null }; | const { data: session } = useSession() as { data: SessionWithTokens | null }; | ||||
| const includeGrnFinancialColumns = | const includeGrnFinancialColumns = | ||||
| @@ -74,7 +74,8 @@ export default function ReportPage() { | |||||
| const handleSelectReport = (reportId: string) => { | const handleSelectReport = (reportId: string) => { | ||||
| if (reportId === selectedReportId) return; | if (reportId === selectedReportId) return; | ||||
| setSelectedReportId(reportId); | setSelectedReportId(reportId); | ||||
| setCriteria({}); | |||||
| // rep-010: default QC item scope to all (show label, not empty select) | |||||
| setCriteria(reportId === 'rep-010' ? { qcType: 'all', qcItemScope: 'all' } : {}); | |||||
| }; | }; | ||||
| const handleFieldChange = (name: string, value: string | string[]) => { | const handleFieldChange = (name: string, value: string | string[]) => { | ||||
| @@ -252,6 +253,28 @@ export default function ReportPage() { | |||||
| return p.toString(); | return p.toString(); | ||||
| }; | }; | ||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 64 | v1.0.0 | 2026-08-11 */ | |||||
| /** rep-010:qcItemScope → includeMeasurable / includeOther;qcType=all 不傳篩選 */ | |||||
| const buildRep010QueryString = (): string => { | |||||
| const p = new URLSearchParams(); | |||||
| Object.entries(criteria).forEach(([key, value]) => { | |||||
| if (key === 'qcItemScope') return; | |||||
| if (key === 'qcType' && String(value).trim().toLowerCase() === 'all') return; | |||||
| if (value != null && String(value).trim() !== '') { | |||||
| p.set(key, String(value)); | |||||
| } | |||||
| }); | |||||
| const scope = (criteria.qcItemScope || 'all').trim().toLowerCase(); | |||||
| if (scope === 'measurable') { | |||||
| p.set('includeMeasurable', 'true'); | |||||
| p.set('includeOther', 'false'); | |||||
| } else { | |||||
| p.set('includeMeasurable', 'true'); | |||||
| p.set('includeOther', 'true'); | |||||
| } | |||||
| return p.toString(); | |||||
| }; | |||||
| const handlePrint = async () => { | const handlePrint = async () => { | ||||
| if (!currentReport) return; | if (!currentReport) return; | ||||
| if (!validateRequiredFields()) return; | if (!validateRequiredFields()) return; | ||||
| @@ -293,6 +316,8 @@ export default function ReportPage() { | |||||
| let queryParams = | let queryParams = | ||||
| currentReport.id === 'rep-012' | currentReport.id === 'rep-012' | ||||
| ? buildRep012QueryString() | ? buildRep012QueryString() | ||||
| : currentReport.id === 'rep-010' | |||||
| ? buildRep010QueryString() | |||||
| : new URLSearchParams(criteria).toString(); | : new URLSearchParams(criteria).toString(); | ||||
| // rep-016: single-day UI — mirror dateStart to dateEnd for backend API. | // rep-016: single-day UI — mirror dateStart to dateEnd for backend API. | ||||
| if (currentReport.id === 'rep-016') { | if (currentReport.id === 'rep-016') { | ||||
| @@ -359,6 +384,8 @@ export default function ReportPage() { | |||||
| const queryParams = | const queryParams = | ||||
| currentReport.id === 'rep-012' | currentReport.id === 'rep-012' | ||||
| ? buildRep012QueryString() | ? buildRep012QueryString() | ||||
| : currentReport.id === 'rep-010' | |||||
| ? buildRep010QueryString() | |||||
| : new URLSearchParams(criteria).toString(); | : new URLSearchParams(criteria).toString(); | ||||
| const url = `${currentReport.apiEndpoint}?${queryParams}`; | const url = `${currentReport.apiEndpoint}?${queryParams}`; | ||||
| @@ -207,6 +207,7 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, | { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, | ||||
| ] | ] | ||||
| }, | }, | ||||
| { | { | ||||
| id: "rep-014", | id: "rep-014", | ||||
| @@ -236,18 +237,29 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| }, | }, | ||||
| { id: "rep-010", | { id: "rep-010", | ||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 64 | v1.0.0 | 2026-08-11 */ | |||||
| title: "庫存品質檢測報告", | title: "庫存品質檢測報告", | ||||
| apiEndpoint: `${NEXT_PUBLIC_API_URL}/report/print-item-qc-fail`, | apiEndpoint: `${NEXT_PUBLIC_API_URL}/report/print-item-qc-fail`, | ||||
| fields: [ | fields: [ | ||||
| { label: "QC 檢測日期:由 Last In Date Start", name: "lastInDateStart", type: "date", required: false }, | |||||
| { label: "QC 檢測日期:至 Last In Date End", name: "lastInDateEnd", type: "date", required: false }, | |||||
| { label: "QC 檢測日期:由 QC Date Start", name: "lastInDateStart", type: "date", required: false }, | |||||
| { label: "QC 檢測日期:至 QC Date End", name: "lastInDateEnd", type: "date", required: false }, | |||||
| { label: "QC 類型", name: "qcType", type: "select", required: false, | { label: "QC 類型", name: "qcType", type: "select", required: false, | ||||
| options: [ | options: [ | ||||
| { label: "全部", value: "" }, | |||||
| { label: "IQC", value: "IQC" }, | |||||
| { label: "EPQC", value: "EPQC" }, | |||||
| { label: "全部", value: "all" }, | |||||
| { label: "IQC(採購)", value: "IQC" }, | |||||
| { label: "EPQC(工單)", value: "EPQC" }, | |||||
| ] }, | ] }, | ||||
| { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, | { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, | ||||
| { | |||||
| label: "QC 項目範圍", | |||||
| name: "qcItemScope", | |||||
| type: "select", | |||||
| required: false, | |||||
| options: [ | |||||
| { label: "全部 QC 項目", value: "all" }, | |||||
| { label: "只包含溫度濕度", value: "measurable" }, | |||||
| ], | |||||
| }, | |||||
| ] | ] | ||||
| }, | }, | ||||
| { id: "rep-013", | { id: "rep-013", | ||||
| @@ -386,14 +398,14 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| ], | ], | ||||
| }, | }, | ||||
| { | { | ||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 60 | v1.0.0 | 2026-08-10 */ | |||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 60 | v1.0.1 | 2026-08-11 */ | |||||
| id: "rep-018", | id: "rep-018", | ||||
| title: "送貨訂單與倉存單位不符報告", | title: "送貨訂單與倉存單位不符報告", | ||||
| apiEndpoint: `${NEXT_PUBLIC_API_URL}/report/print-do-inventory-uom-mismatch`, | apiEndpoint: `${NEXT_PUBLIC_API_URL}/report/print-do-inventory-uom-mismatch`, | ||||
| responseType: "excel", | responseType: "excel", | ||||
| fields: [ | fields: [ | ||||
| { | { | ||||
| label: "預計到貨日期 Estimated Arrival Date", | |||||
| label: "預計送貨日期 Estimated Arrival Date", | |||||
| name: "deliveryDate", | name: "deliveryDate", | ||||
| type: "date", | type: "date", | ||||
| required: true, | required: true, | ||||
| @@ -405,7 +417,7 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| type: "select", | type: "select", | ||||
| required: false, | required: false, | ||||
| options: [ | options: [ | ||||
| { label: "全部 All (2F+4F)", value: "All" }, | |||||
| { label: "全部", value: "All" }, | |||||
| { label: "2F", value: "2F" }, | { label: "2F", value: "2F" }, | ||||
| { label: "4F", value: "4F" }, | { label: "4F", value: "4F" }, | ||||
| ], | ], | ||||