diff --git a/src/app/(main)/layout.tsx b/src/app/(main)/layout.tsx
index dc236bc..4144526 100644
--- a/src/app/(main)/layout.tsx
+++ b/src/app/(main)/layout.tsx
@@ -37,7 +37,7 @@ export default async function MainLayout({
return (
-
+ {/* */}
<>
@@ -62,7 +62,7 @@ export default async function MainLayout({
>
-
+ {/* */}
);
diff --git a/src/app/api/dashboard/actions.ts b/src/app/api/dashboard/actions.ts
index da6d72d..bd0d240 100644
--- a/src/app/api/dashboard/actions.ts
+++ b/src/app/api/dashboard/actions.ts
@@ -30,9 +30,6 @@ export interface StockInLineEntry {
acceptedQty: number;
status?: string;
expiryDate?: string;
- productLotNo?: string;
- receiptDate?: string;
- dnDate?: string;
}
export interface PurchaseQcResult {
diff --git a/src/app/api/po/actions.ts b/src/app/api/po/actions.ts
index 92f1b7f..a013ab4 100644
--- a/src/app/api/po/actions.ts
+++ b/src/app/api/po/actions.ts
@@ -31,11 +31,14 @@ export interface StockInLineEntry {
acceptedQty: number;
status?: string;
expiryDate?: string;
+ productLotNo?: string;
+ receiptDate?: string;
+ dnDate?: string;
}
export interface PurchaseQcResult{
qcItemId: number;
- isPassed: boolean;
+ qcPassed: boolean;
failQty: number;
remarks?: string;
@@ -111,7 +114,7 @@ export const fetchStockInLineInfo = cache(async (stockInLineId: number) => {
export const createStockInLine = async (data: StockInLineEntry) => {
const stockInLine = await serverFetchJson<
- PostStockInLineResponse
+ PostStockInLineResponse
>(`${BASE_API_URL}/stockInLine/create`, {
method: "POST",
body: JSON.stringify(data),
@@ -125,7 +128,7 @@ export const updateStockInLine = async (
data: StockInLineEntry & ModalFormInput,
) => {
const stockInLine = await serverFetchJson<
- PostStockInLineResponse
+ PostStockInLineResponse
>(`${BASE_API_URL}/stockInLine/update`, {
method: "POST",
body: JSON.stringify(data),
diff --git a/src/app/api/po/index.ts b/src/app/api/po/index.ts
index 55678b1..8cff8fc 100644
--- a/src/app/api/po/index.ts
+++ b/src/app/api/po/index.ts
@@ -54,7 +54,7 @@ export interface StockUomForPoLine {
export interface StockInLine {
id: number;
- stockInId: number;
+ stockInId?: number;
purchaseOrderId?: number;
purchaseOrderLineId: number;
itemId: number;
@@ -63,23 +63,24 @@ export interface StockInLine {
itemType: string;
demandQty: number;
acceptedQty: number;
- qty: number;
- processed: number;
- price: number;
- priceUnit: string;
+ qty?: number;
+ processed?: number;
+ price?: number;
+ priceUnit?: string;
shelfLife?: number;
receiptDate?: string;
productionDate?: string;
+ productLotNo?: string;
expiryDate?: string;
status: string;
- supplier: string;
- lotNo: string;
- poCode: string;
- uom: Uom;
+ supplier?: string;
+ lotNo?: string;
+ poCode?: string;
+ uom?: Uom;
defaultWarehouseId: number; // id for now
- dnNo: string;
- dnDate: number[];
- stockQty: number;
+ dnNo?: string;
+ dnDate?: number[];
+ stockQty?: number;
}
export const fetchPoList = cache(async (queryParams?: Record) => {
diff --git a/src/app/api/qc/index.ts b/src/app/api/qc/index.ts
index 6c65043..a99d457 100644
--- a/src/app/api/qc/index.ts
+++ b/src/app/api/qc/index.ts
@@ -20,7 +20,7 @@ export interface QcData {
code: string,
name: string,
qcDescription: string,
- isPassed: boolean | undefined
+ qcPassed: boolean | undefined
failQty: number | undefined
remarks: string | undefined
}
diff --git a/src/components/PickOrderSearch/QcFormVer2.tsx b/src/components/PickOrderSearch/QcFormVer2.tsx
index 9c615a2..ebea29d 100644
--- a/src/components/PickOrderSearch/QcFormVer2.tsx
+++ b/src/components/PickOrderSearch/QcFormVer2.tsx
@@ -49,7 +49,7 @@ import EscalationComponent from "./EscalationComponent";
import QcDataGrid from "./QCDatagrid";
import StockInFormVer2 from "./StockInFormVer2";
import { dummyEscalationHistory, dummyQCData, QcData } from "./dummyQcTemplate";
-import { ModalFormInput } from "@/app/api/dashboard/actions";
+import { ModalFormInput } from "@/app/api/po/actions";
import { escape } from "lodash";
interface Props {
diff --git a/src/components/PoDetail/PoDetail.tsx b/src/components/PoDetail/PoDetail.tsx
index 6b39623..1715d8b 100644
--- a/src/components/PoDetail/PoDetail.tsx
+++ b/src/components/PoDetail/PoDetail.tsx
@@ -43,9 +43,11 @@ import {
import {
checkPolAndCompletePo,
fetchPoInClient,
+ fetchPoListClient,
fetchStockInLineInfo,
PurchaseQcResult,
startPo,
+ createStockInLine
} from "@/app/api/po/actions";
import {
useCallback,
@@ -69,9 +71,7 @@ import DoneIcon from "@mui/icons-material/Done";
import { getCustomWidth } from "@/app/utils/commonUtil";
import PoInfoCard from "./PoInfoCard";
import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil";
-import { fetchPoListClient } from "@/app/api/po/actions";
import { List, ListItem, ListItemButton, ListItemText, Divider } from "@mui/material";
-import { createStockInLine } from "@/app/api/dashboard/actions";
import { Controller, FormProvider, useForm } from "react-hook-form";
import dayjs, { Dayjs } from "dayjs";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
@@ -81,7 +81,6 @@ import LoadingComponent from "../General/LoadingComponent";
//import { useRouter } from "next/navigation";
-
type Props = {
po: PoResult;
qc: QcItemWithChecks[];
@@ -397,6 +396,9 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => {
setTimeout(async () => {
// post stock in line
const oldId = row.id;
+ const acceptedQty = Number(polInputList[rowIndex].dnQty);
+ if (isNaN(acceptedQty) || acceptedQty <= 0) { alert("來貨數量必須大於0!"); return; } // Temp check, need update
+
const postData = {
dnNo: dnFormProps.watch("dnNo"),
dnDate: outputDateStringToInputDateString(dnFormProps.watch("dnDate")),
@@ -405,7 +407,7 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => {
itemName: row.itemName,
purchaseOrderId: row.purchaseOrderId,
purchaseOrderLineId: row.id,
- acceptedQty: polInputList[rowIndex].dnQty || 0,
+ acceptedQty: acceptedQty,
productLotNo: polInputList[rowIndex].lotNo || '',
// acceptedQty: secondReceiveQty || 0,
// acceptedQty: row.acceptedQty,
@@ -535,7 +537,7 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => {
handleStart()
}
>
- 提交
+ {t("submit")}
diff --git a/src/components/PoDetail/QcFormVer2.tsx b/src/components/PoDetail/QcFormVer2.tsx
index 09e2ee0..37667a9 100644
--- a/src/components/PoDetail/QcFormVer2.tsx
+++ b/src/components/PoDetail/QcFormVer2.tsx
@@ -49,7 +49,7 @@ import EscalationComponent from "./EscalationComponent";
import QcDataGrid from "./QCDatagrid";
import StockInFormVer2 from "./StockInFormVer2";
import { dummyEscalationHistory, dummyQCData } from "./dummyQcTemplate";
-import { ModalFormInput } from "@/app/api/dashboard/actions";
+import { ModalFormInput } from "@/app/api/po/actions";
import { escape } from "lodash";
import { PanoramaSharp } from "@mui/icons-material";
@@ -197,7 +197,7 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI
),
},
{
- field: 'qcResult',
+ field: 'qcPassed',
headerName: t("qcResult"),
flex: 1.5,
renderCell: (params) => {
@@ -208,14 +208,15 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI
{
const value = e.target.value;
setQcItems((prev) =>
- prev.map((r): QcData => (r.id === params.id ? { ...r, isPassed: value === "true" } : r))
+ prev.map((r): QcData => (r.id === params.id ? { ...r, qcPassed: value === "true" } : r))
);
}}
- name={`isPassed-${params.id}`}
+ name={`qcPassed-${params.id}`}
>
= ({ qc, itemDetail, disabled, qcItems, setQcI
label="合格"
disabled={disabled}
sx={{
- color: currentValue.isPassed === true ? "green" : "inherit",
+ color: currentValue.qcPassed === true ? "green" : "inherit",
"& .Mui-checked": {color: "green"}
}}
/>
@@ -233,7 +234,7 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI
label="不合格"
disabled={disabled}
sx={{
- color: currentValue.isPassed === false ? "red" : "inherit",
+ color: currentValue.qcPassed === false ? "red" : "inherit",
"& .Mui-checked": {color: "red"}
}}
/>
@@ -251,8 +252,8 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI
{
const v = e.target.value;
const next = v === '' ? undefined : Number(v);
@@ -313,7 +314,7 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI
const [isCollapsed, setIsCollapsed] = useState(true);
const onFailedOpenCollapse = useCallback((qcItems: PurchaseQcResult[]) => {
- const isFailed = qcItems.some((qc) => !qc.isPassed)
+ const isFailed = qcItems.some((qc) => !qc.qcPassed)
console.log(isFailed)
if (isFailed) {
setIsCollapsed(true)
@@ -439,7 +440,11 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI
}
sx={{"& .Mui-checked": {color: "red"}}}
- label="不接受及上報" />
+ label="不接受" />
+ }
+ sx={{"& .Mui-checked": {color: "blue"}}}
+ label="上報品檢結果" />
)}
/>
diff --git a/src/components/PoDetail/QcStockInModalVer2.tsx b/src/components/PoDetail/QcStockInModalVer2.tsx
index 879f4cf..79997c9 100644
--- a/src/components/PoDetail/QcStockInModalVer2.tsx
+++ b/src/components/PoDetail/QcStockInModalVer2.tsx
@@ -1,6 +1,6 @@
"use client";
import { StockInLine } from "@/app/api/po";
-import { ModalFormInput, PurchaseQcResult, StockInLineEntry, updateStockInLine } from "@/app/api/po/actions";
+import { ModalFormInput, PurchaseQcResult, StockInLineEntry, updateStockInLine, PurchaseQCInput } from "@/app/api/po/actions";
import { QcItemWithChecks, QcData } from "@/app/api/qc";
import {
Box,
@@ -22,7 +22,6 @@ import PutawayForm from "./PutawayForm";
import { dummyPutawayLine, dummyQCData } from "./dummyQcTemplate";
import { useGridApiRef } from "@mui/x-data-grid";
import {submitDialogWithWarning} from "../Swal/CustomAlerts";
-import { PurchaseQCInput, PutawayInput } from "@/app/api/dashboard/actions";
import { arrayToDateString, arrayToInputDateString, dayjsToInputDateString } from "@/app/utils/formatUtil";
import dayjs from "dayjs";
@@ -114,10 +113,11 @@ const [qcItems, setQcItems] = useState(dummyQCData)
}, [open])
- const [isCompleted, setIsCompleted] = useState(false);
+ const [viewOnly, setViewOnly] = useState(false);
useEffect(() => {
- setIsCompleted(itemDetail.status.toLowerCase() == "completed")
+ const isViewOnly = itemDetail.status.toLowerCase() == "completed" || itemDetail.status.toLowerCase() == "rejected"
+ setViewOnly(isViewOnly)
}, [itemDetail]);
const [openPutaway, setOpenPutaway] = useState(false);
@@ -162,12 +162,12 @@ const [qcItems, setQcItems] = useState(dummyQCData)
const qcAccept = data.qcAccept;
const acceptQty = data.acceptQty as number;
const qcResults = qcItems;
- // const qcResults = isCompleted? data.qcResult as PurchaseQcResult[] : qcItems;
+ // const qcResults = viewOnly? data.qcResult as PurchaseQcResult[] : qcItems;
// Validate QC data
const validationErrors : string[] = [];
// Check if all QC items have results
- const itemsWithoutResult = qcResults.filter(item => item.isPassed === undefined);
+ const itemsWithoutResult = qcResults.filter(item => item.qcPassed === undefined);
if (itemsWithoutResult.length > 0) {
validationErrors.push(`${t("QC items without result")}`);
// validationErrors.push(`${t("QC items without result")}: ${itemsWithoutResult.map(item => item.code).join(', ')}`);
@@ -175,7 +175,7 @@ const [qcItems, setQcItems] = useState(dummyQCData)
// Check if failed items have failed quantity
const failedItemsWithoutQty = qcResults.filter(item =>
- item.isPassed === false && (!item.failQty || item.failQty <= 0)
+ item.qcPassed === false && (!item.failQty || item.failQty <= 0)
);
if (failedItemsWithoutQty.length > 0) {
validationErrors.push(`${t("Failed items must have failed quantity")}`);
@@ -194,10 +194,16 @@ const [qcItems, setQcItems] = useState(dummyQCData)
// Check if dates are input
if (data.productionDate === undefined || data.productionDate == null) {
- validationErrors.push("Production Date cannot be null!");
+ validationErrors.push("請輸入生產日期!");
}
if (data.expiryDate === undefined || data.expiryDate == null) {
- validationErrors.push("Expiry Date cannot be null!");
+ validationErrors.push("請輸入到期日!");
+ }
+ if (!qcResults.every((qc) => qc.qcPassed) && qcAccept) {
+ validationErrors.push("有不合格檢查項目,無法收貨!");
+ // submitDialogWithWarning(() => postStockInLineWithQc(qcData), t, {title:"有不合格檢查項目,確認接受收貨?",
+ // confirmButtonText: t("confirm putaway"), html: ""});
+ // return;
}
if (validationErrors.length > 0) {
@@ -219,8 +225,8 @@ const [qcItems, setQcItems] = useState(dummyQCData)
qcItemId: item.id,
// code: item.code,
// qcDescription: item.qcDescription,
- isPassed: item.isPassed? item.isPassed : false,
- failQty: (item.failQty && !item.isPassed) ? item.failQty : 0,
+ qcPassed: item.qcPassed? item.qcPassed : false,
+ failQty: (item.failQty && !item.qcPassed) ? item.failQty : 0,
// failedQty: (typeof item.failedQty === "number" && !item.isPassed) ? item.failedQty : 0,
remarks: item.remarks || ''
}))
@@ -228,42 +234,21 @@ const [qcItems, setQcItems] = useState(dummyQCData)
// const qcData = data;
console.log("QC Data for submission:", qcData);
+
+ await postStockInLine(qcData);
- if (!qcData.qcResult.every((qc) => qc.isPassed) && qcData.qcAccept) {
- submitDialogWithWarning(() => postStockInLineWithQc(qcData), t, {title:"有不合格檢查項目,確認接受收貨?",
- confirmButtonText: t("confirm putaway"), html: ""});
- return;
+ if (qcData.qcAccept) {
+ // submitDialogWithWarning(onOpenPutaway, t, {title:"Save success, confirm to proceed?",
+ // confirmButtonText: t("confirm putaway"), html: ""});
+ onOpenPutaway();
+ } else {
+ closeHandler({}, "backdropClick");
}
- await postStockInLineWithQc(qcData);
- // return;
+ return ;
+
},
[onOpenPutaway, qcItems],
);
-
- const postStockInLineWithQc = useCallback(async (qcData: PurchaseQCInput) => {
- const args = {
- ...qcData
- // id: itemDetail.id,
- // purchaseOrderId: itemDetail.purchaseOrderId,
- // purchaseOrderLineId: itemDetail.purchaseOrderLineId,
- // itemId: itemDetail.itemId,
- // ...data,
- // productionDate: productionDate,
- // expiryDate: expiryDate,
- // receiptDate: receiptDate,
- } as ModalFormInput;
-
- await postStockInLine(args);
-
- if (qcData.qcAccept) {
- // submitDialogWithWarning(onOpenPutaway, t, {title:"Save success, confirm to proceed?",
- // confirmButtonText: t("confirm putaway"), html: ""});
- onOpenPutaway();
- } else {
- closeHandler({}, "backdropClick");
- }
- return ;
- },[onOpenPutaway,closeHandler]);
const postStockInLine = useCallback(async (args: ModalFormInput) => {
const submitData = {
@@ -340,7 +325,7 @@ const [qcItems, setQcItems] = useState(dummyQCData)
const acceptQty = formProps.watch("acceptedQty")
const checkQcIsPassed = useCallback((qcItems: PurchaseQcResult[]) => {
- const isPassed = qcItems.every((qc) => qc.isPassed);
+ const isPassed = qcItems.every((qc) => qc.qcPassed);
console.log(isPassed)
if (isPassed) {
formProps.setValue("passingQty", acceptQty)
@@ -378,7 +363,7 @@ const [qcItems, setQcItems] = useState(dummyQCData)