Przeglądaj źródła

update stock in line

reset-do-picking-order
CANCERYS\kw093 1 tydzień temu
rodzic
commit
2548b7a007
6 zmienionych plików z 86 dodań i 68 usunięć
  1. +5
    -0
      src/app/api/stockIn/index.ts
  2. +33
    -12
      src/components/PoDetail/PoDetail.tsx
  3. +5
    -4
      src/components/PoDetail/PoInputGrid.tsx
  4. +2
    -2
      src/components/PoDetail/QcStockInModal.tsx
  5. +8
    -4
      src/components/PutAwayScan/PutAwayModal.tsx
  6. +33
    -46
      src/components/StockIn/StockInForm.tsx

+ 5
- 0
src/app/api/stockIn/index.ts Wyświetl plik

@@ -109,6 +109,8 @@ export interface StockInLine {
itemType: string; itemType: string;
demandQty: number; demandQty: number;
acceptedQty: number; acceptedQty: number;
purchaseDemandQty?: number;
purchaseAcceptedQty?: number;
qty?: number; qty?: number;
receivedQty?: number; receivedQty?: number;
processed?: number; processed?: number;
@@ -124,6 +126,8 @@ export interface StockInLine {
lotNo?: string; lotNo?: string;
poCode?: string; poCode?: string;
uom?: Uom; uom?: Uom;
purchaseUomDesc?: string;
stockUomDesc?: string;
joCode?: string; joCode?: string;
warehouseCode?: string; warehouseCode?: string;
defaultWarehouseId: number; // id for now defaultWarehouseId: number; // id for now
@@ -150,6 +154,7 @@ export interface EscalationInput {
export interface PutAwayLine { export interface PutAwayLine {
id?: number id?: number
qty: number qty: number
stockQty?: number
warehouseId: number; warehouseId: number;
warehouse: string; warehouse: string;
printQty: number; printQty: number;


+ 33
- 12
src/components/PoDetail/PoDetail.tsx Wyświetl plik

@@ -451,7 +451,10 @@ const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => {
const oldId = row.id; const oldId = row.id;
const acceptedQty = Number(polInputList[rowIndex].dnQty); const acceptedQty = Number(polInputList[rowIndex].dnQty);
if (isNaN(acceptedQty) || acceptedQty <= 0) { alert("來貨數量必須大於0!"); return; } // Temp check, need update if (isNaN(acceptedQty) || acceptedQty <= 0) { alert("來貨數量必須大於0!"); return; } // Temp check, need update

if (!Number.isInteger(acceptedQty)) {
alert("來貨數量必須是整數(不能有小數)!");
return;
}
const postData = { const postData = {
dnNo: dnFormProps.watch("dnNo"), dnNo: dnFormProps.watch("dnNo"),
receiptDate: outputDateStringToInputDateString(dnFormProps.watch("receiptDate")), receiptDate: outputDateStringToInputDateString(dnFormProps.watch("receiptDate")),
@@ -491,22 +494,30 @@ const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => {
break; break;
case "dnQty": case "dnQty":
// Allow empty input // Allow empty input
if (raw.trim() === '') {
polInputList[rowIndex].dnQty = 0;
break;
}
const trimmed = raw.trim();


if (trimmed === "") {
polInputList[rowIndex].dnQty = 0;
break;
}
/*
// Keep digits only // Keep digits only
const cleaned = raw.replace(/[^\d]/g, ''); const cleaned = raw.replace(/[^\d]/g, '');
if (cleaned === '') { if (cleaned === '') {
// If the user typed only non-digits, keep previous value // If the user typed only non-digits, keep previous value
break; break;
} }
*/
const parsed = Number(trimmed);


// Parse and clamp to non-negative integer
const next = Math.max(0, Math.floor(Number(cleaned)));
polInputList[rowIndex].dnQty = next;
// 不是合法數字(例如 "abc")
if (!Number.isFinite(parsed)) {
polInputList[rowIndex].dnQty = 0; // 或保留舊值,看你需求
break; break;
}

polInputList[rowIndex].dnQty = parsed; // 這裡允許小數,先存起來
break;
default: default:
break; break;
} }
@@ -515,9 +526,16 @@ const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => {


// const [focusField, setFocusField] = useState<HTMLInputElement>(); // const [focusField, setFocusField] = useState<HTMLInputElement>();


const purchaseToStockRatio = (row.stockUom.purchaseRatioN ?? 1) / (row.stockUom.purchaseRatioD ?? 1) * (row.stockUom.stockRatioD ?? 1) / (row.stockUom.stockRatioN ?? 1)
const receivedTotal = decimalFormatter.format(row.stockInLine.filter((sil) => sil.purchaseOrderLineId === row.id).reduce((acc, cur) => acc + (cur.acceptedQty ?? 0),0) * purchaseToStockRatio);
const highlightColor = (Number(receivedTotal.replace(/,/g, '')) <= 0) ? "red" : "inherit";
// 本批收貨數量(訂單單位): 使用者在該行輸入的 dnQty
const batchPurchaseQty = polInputList[rowIndex]?.dnQty ?? 0;

// 已來貨總數(庫存單位): 同一 POL 底下所有 stock_in_line.acceptedQty 的合計
const totalStockReceived = row.stockInLine
.filter((sil) => sil.purchaseOrderLineId === row.id)
.reduce((acc, cur) => acc + (cur.acceptedQty ?? 0), 0);
const receivedTotalText = decimalFormatter.format(totalStockReceived);
const highlightColor =
Number(receivedTotalText.replace(/,/g, "")) <= 0 ? "red" : "inherit";
return ( return (
<> <>
@@ -552,7 +570,10 @@ const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => {
<TableCell align="right">{integerFormatter.format(row.processed)}</TableCell> <TableCell align="right">{integerFormatter.format(row.processed)}</TableCell>
<TableCell align="left">{row.uom?.udfudesc}</TableCell> <TableCell align="left">{row.uom?.udfudesc}</TableCell>
{/* <TableCell align="right">{decimalFormatter.format(row.stockUom.stockQty)}</TableCell> */} {/* <TableCell align="right">{decimalFormatter.format(row.stockUom.stockQty)}</TableCell> */}
<TableCell sx={{ color: highlightColor}} align="right">{receivedTotal}</TableCell>
{/* <TableCell sx={{ color: highlightColor}} align="right">{receivedTotal}</TableCell> */}
<TableCell sx={{ color: highlightColor }} align="right">
{decimalFormatter.format(totalStockReceived)}
</TableCell>
<TableCell sx={{ color: highlightColor}} align="left">{row.stockUom.stockUomDesc}</TableCell> <TableCell sx={{ color: highlightColor}} align="left">{row.stockUom.stockUomDesc}</TableCell>
{/* <TableCell align="right"> {/* <TableCell align="right">
{decimalFormatter.format(totalWeight)} {weightUnit} {decimalFormatter.format(totalWeight)} {weightUnit}


+ 5
- 4
src/components/PoDetail/PoInputGrid.tsx Wyświetl plik

@@ -524,7 +524,8 @@ function PoInputGrid({
// editable: true, // editable: true,
// replace with tooltip + content // replace with tooltip + content
renderCell: (params) => { renderCell: (params) => {
return integerFormatter.format(params.value)
const qty = params.row.purchaseAcceptedQty ?? params.row.acceptedQty ?? 0;
return integerFormatter.format(qty);
} }
}, },
{ {
@@ -545,9 +546,9 @@ function PoInputGrid({
// editable: true, // editable: true,
// replace with tooltip + content // replace with tooltip + content
renderCell: (params) => { renderCell: (params) => {
const baseQty = (params.row.acceptedQty ?? 0) * (itemDetail.stockUom.purchaseRatioN ?? 1) / (itemDetail.stockUom.purchaseRatioD ?? 1)
const stockQty = baseQty * (itemDetail.stockUom.stockRatioD ?? 1) / (itemDetail.stockUom.stockRatioN ?? 1)
return decimalFormatter.format(stockQty)
// acceptedQty 現在就是庫存單位數量
const stockQty = params.row.acceptedQty ?? 0;
return decimalFormatter.format(stockQty);
} }
}, },
{ {


+ 2
- 2
src/components/PoDetail/QcStockInModal.tsx Wyświetl plik

@@ -198,7 +198,7 @@ const PoQcStockInModalVer2: React.FC<Props> = ({
expiryDate: d.expiryDate ? arrayToDateString(d.expiryDate, "input") : undefined, expiryDate: d.expiryDate ? arrayToDateString(d.expiryDate, "input") : undefined,
receiptDate: d.receiptDate ? arrayToDateString(d.receiptDate, "input") receiptDate: d.receiptDate ? arrayToDateString(d.receiptDate, "input")
: dayjs().add(0, "month").format(INPUT_DATE_FORMAT), : dayjs().add(0, "month").format(INPUT_DATE_FORMAT),
acceptQty: d.demandQty?? d.acceptedQty,
acceptQty: d.acceptedQty ?? d.demandQty,
// escResult: (d.escResult && d.escResult?.length > 0) ? d.escResult : [], // escResult: (d.escResult && d.escResult?.length > 0) ? d.escResult : [],
// qcResult: (d.qcResult && d.qcResult?.length > 0) ? d.qcResult : [],//[...dummyQCData], // qcResult: (d.qcResult && d.qcResult?.length > 0) ? d.qcResult : [],//[...dummyQCData],
warehouseId: d.defaultWarehouseId ?? 1, warehouseId: d.defaultWarehouseId ?? 1,
@@ -451,7 +451,7 @@ const PoQcStockInModalVer2: React.FC<Props> = ({
async (data, event) => { async (data, event) => {
// Extract only putaway related fields // Extract only putaway related fields
const putawayData = { const putawayData = {
acceptQty: Number(data.acceptQty?? (stockInLineInfo?.demandQty?? (stockInLineInfo?.acceptedQty))), //TODO improve
acceptQty: Number(data.acceptQty ?? (stockInLineInfo?.acceptedQty ?? stockInLineInfo?.demandQty)), //TODO improve
warehouseId: data.warehouseId, warehouseId: data.warehouseId,
status: data.status, //TODO Fix it! status: data.status, //TODO Fix it!
// ...data, // ...data,


+ 8
- 4
src/components/PutAwayScan/PutAwayModal.tsx Wyświetl plik

@@ -251,7 +251,7 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId
formProps.reset({ formProps.reset({
...defaultNewValue ...defaultNewValue
}) })
const total = itemDetail.putAwayLines?.reduce((sum, p) => sum + p.qty, 0) ?? 0;
const total = itemDetail.putAwayLines?.reduce((sum, p) => sum + (p.stockQty ?? p.qty ?? 0), 0) ?? 0;
setPutQty(itemDetail?.acceptedQty - total); setPutQty(itemDetail?.acceptedQty - total);
// ✅ Get first warehouse from existing put away lines // ✅ Get first warehouse from existing put away lines
@@ -294,7 +294,7 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId
const res = await fetchStockInLineInfo(stockInLineId); const res = await fetchStockInLineInfo(stockInLineId);
console.log("%c Fetched Stock In Line Info:", "color:gold", res); console.log("%c Fetched Stock In Line Info:", "color:gold", res);


const total = res.putAwayLines?.reduce((sum, p) => sum + p.qty, 0) ?? 0;
const total = res.putAwayLines?.reduce((sum, p) => sum + (p.stockQty ?? p.qty ?? 0), 0) ?? 0;
setTotalPutAwayQty(total); setTotalPutAwayQty(total);
setItemDetail(res); setItemDetail(res);
} catch (e) { } catch (e) {
@@ -346,6 +346,10 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId
// qty: acceptQty; // qty: acceptQty;
// } // }
try { try {
if (!itemDetail?.id || itemDetail.acceptedQty === undefined || itemDetail.acceptedQty === null) {
alert("找不到收貨數量(acceptedQty),請重新掃碼再試。");
return;
}
// 确定最终使用的 warehouseId // 确定最终使用的 warehouseId
const effectiveWarehouseId = warehouseId > 0 const effectiveWarehouseId = warehouseId > 0
? warehouseId ? warehouseId
@@ -361,8 +365,8 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId
purchaseOrderId: itemDetail?.purchaseOrderId, purchaseOrderId: itemDetail?.purchaseOrderId,
purchaseOrderLineId: itemDetail?.purchaseOrderLineId, purchaseOrderLineId: itemDetail?.purchaseOrderLineId,
itemId: itemDetail?.itemId, itemId: itemDetail?.itemId,
acceptedQty: itemDetail?.acceptedQty,
acceptQty: itemDetail?.acceptedQty,
acceptedQty: Number(itemDetail.acceptedQty),
acceptQty: Number(itemDetail.acceptedQty),
status: "received", status: "received",
// purchaseOrderId: parseInt(params.get("id")!), // purchaseOrderId: parseInt(params.get("id")!),
// purchaseOrderLineId: itemDetail?.purchaseOrderLineId, // purchaseOrderLineId: itemDetail?.purchaseOrderLineId,


+ 33
- 46
src/components/StockIn/StockInForm.tsx Wyświetl plik

@@ -370,47 +370,38 @@ const StockInForm: React.FC<Props> = ({
/> />
</Grid></> </Grid></>
)} )}
{putawayMode && (
{putawayMode ? (
<>
<Grid item xs={6}>
<TextField
label={"本批次庫存收貨數量"}
fullWidth
sx={compactFields ? undefined : textfieldSx}
disabled={true}
value={`${itemDetail.acceptedQty ?? 0} (${itemDetail.stockUomDesc ?? ""})`}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={"本批次採購收貨數量"}
fullWidth
sx={compactFields ? undefined : textfieldSx}
disabled={true}
value={`${itemDetail.purchaseAcceptedQty ?? 0} (${itemDetail.purchaseUomDesc ?? ""})`}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={"已上架數量"}
fullWidth
sx={compactFields ? undefined : textfieldSx}
disabled={true}
value={`${itemDetail.putAwayLines?.reduce((sum, p) => sum + (p.stockQty ?? 0), 0) ?? 0} (${itemDetail.stockUomDesc ?? ""})`}
/>
</Grid>
</>
) : (
<Grid item xs={6}> <Grid item xs={6}>
<TextField
label={t("acceptedQty")}
fullWidth
sx={compactFields ? undefined : textfieldSx}
disabled={true}
value={itemDetail.acceptedQty}
// disabled={true}
// disabled={disabled}
// error={Boolean(errors.acceptedQty)}
// helperText={errors.acceptedQty?.message}
/>
</Grid>
)}
<Grid item xs={6}>
<TextField
label={t("uom")}
fullWidth
{...register("uom.udfudesc", {
required: "uom required!",
})}
// value={uom?.code}
sx={compactFields ? undefined : textfieldSx}
disabled={true}
/>
</Grid>
<Grid item xs={6}>
{putawayMode ? (
<TextField
label={t("processedQty")}
fullWidth
sx={compactFields ? undefined : textfieldSx}
disabled={true}
value={itemDetail.putAwayLines?.reduce((sum, p) => sum + p.qty, 0) ?? 0}
// disabled={true}
// disabled={disabled}
// error={Boolean(errors.acceptedQty)}
// helperText={errors.acceptedQty?.message}
/>
) : (
<TextField <TextField
label={t("acceptedQty")} label={t("acceptedQty")}
fullWidth fullWidth
@@ -419,13 +410,9 @@ const StockInForm: React.FC<Props> = ({
{...register("acceptedQty", { {...register("acceptedQty", {
required: "acceptedQty required!", required: "acceptedQty required!",
})} })}
// disabled={true}
// disabled={disabled}
// error={Boolean(errors.acceptedQty)}
// helperText={errors.acceptedQty?.message}
/> />
)}
</Grid>
</Grid>
)}
{/* <Grid item xs={4}> {/* <Grid item xs={4}>
<TextField <TextField
label={t("acceptedWeight")} label={t("acceptedWeight")}


Ładowanie…
Anuluj
Zapisz