소스 검색

remove bar from round card lsit

lot expiry after create round before appove
tonigh lot will expiry can not do expiry handle ,block while stock taking relate
stockTakeUpdate
CANCERYS\kw093 1 주 전
부모
커밋
7b8135dd2d
11개의 변경된 파일과 197개의 추가작업 그리고 175개의 파일을 삭제
  1. +3
    -1
      src/app/api/stockIssue/actions.ts
  2. +8
    -1
      src/components/StockIssue/ExpiryHandleTab.tsx
  3. +8
    -3
      src/components/StockTakeManagement/ApproverStockTakeAll.tsx
  4. +28
    -15
      src/components/StockTakeManagement/PickerCardList.tsx
  5. +24
    -27
      src/components/StockTakeManagement/StockTakeRoundCardList.tsx
  6. +4
    -0
      src/components/StockTakeManagement/StockTakeTab.tsx
  7. +116
    -124
      src/components/WarehouseHandle/WarehouseHandle.tsx
  8. +1
    -0
      src/i18n/en/stockIssue.json
  9. +2
    -2
      src/i18n/en/stockTake.json
  10. +1
    -0
      src/i18n/zh/stockIssue.json
  11. +2
    -2
      src/i18n/zh/stockTake.json

+ 3
- 1
src/app/api/stockIssue/actions.ts 파일 보기

@@ -18,8 +18,10 @@ export interface ExpiryItemResult {
expiryDate: string | null;
remainingQty: number;
uomDesc?: string | null;
/** True when expiryDate is today or earlier. */
/** True when expiryDate is today or earlier (and not blocked by open stock take for today-expiry). */
canHandle?: boolean;
/** When canHandle is false: FUTURE | STOCK_TAKE_OPEN */
canHandleBlockKey?: string | null;
}

export interface ExpiryItemFilter {


+ 8
- 1
src/components/StockIssue/ExpiryHandleTab.tsx 파일 보기

@@ -114,6 +114,13 @@ function canHandleExpiryItem(item: ExpiryItemResult): boolean {
return d != null && !d.isAfter(dayjs(), "day");
}

function cannotHandleTooltipKey(item: ExpiryItemResult): string {
if (item.canHandleBlockKey === "STOCK_TAKE_OPEN") {
return "Expires today but in open stock take; cannot dispose";
}
return "Not yet due; cannot dispose until the expiry date";
}

/** FP-MTMS Version Checklist | Functions Ref. No. 74 | v1.0.3 | 2026-09-08 */
const ExpiryHandleTab: React.FC = () => {
const BATCH_CHUNK_SIZE = 20;
@@ -285,7 +292,7 @@ const ExpiryHandleTab: React.FC = () => {
);
if (canHandle) return button;
return (
<Tooltip title={t("Not yet due; cannot dispose until the expiry date")}>
<Tooltip title={t(cannotHandleTooltipKey(item))}>
<span>{button}</span>
</Tooltip>
);


+ 8
- 3
src/components/StockTakeManagement/ApproverStockTakeAll.tsx 파일 보기

@@ -62,6 +62,7 @@ import { stockTakeHiddenOnHand, stockTakeQtyGapWarnText } from "./stockTakeQtyGa
import { useStockTakeQtyGapWarnPercent } from "./useStockTakeQtyGapWarnPercent";
import { useSession } from "next-auth/react";
import { SessionWithTokens } from "@/config/authConfig";
import { AUTH } from "@/authorities";
import dayjs from "dayjs";
import { OUTPUT_DATE_FORMAT, roundDownPercent } from "@/app/utils/formatUtil";
import { DataGrid, GridColDef, GridRenderCellParams } from '@mui/x-data-grid';
@@ -373,6 +374,9 @@ const ApproverStockTakeAll: React.FC<ApproverStockTakeAllProps> = ({
const { t } = useTranslation(["stockTake", "common"]);
const qtyGapWarnPercent = useStockTakeQtyGapWarnPercent();
const { data: session } = useSession() as { data: SessionWithTokens | null };
const isAdmin = (session?.abilities ?? session?.user?.abilities ?? []).some(
(ability) => String(ability).trim() === AUTH.ADMIN,
);

const [inventoryLotDetails, setInventoryLotDetails] = useState<InventoryLotDetailResponse[]>([]);
const [loadingDetails, setLoadingDetails] = useState(false);
@@ -1575,7 +1579,7 @@ const ApproverStockTakeAll: React.FC<ApproverStockTakeAllProps> = ({
size="small"
variant="contained"
onClick={() => handleSaveApproverStockTake(detail)}
disabled={saving}
disabled={!isAdmin || saving}
>
{t("Save")}
</Button>
@@ -1586,7 +1590,7 @@ const ApproverStockTakeAll: React.FC<ApproverStockTakeAllProps> = ({
variant="outlined"
color="warning"
onClick={() => handleUpdateStatusToNotMatch(detail)}
disabled={updatingStatus||hasSecond}
disabled={!isAdmin || updatingStatus || hasSecond}
>
{t("Not Match")}
</Button>
@@ -1618,6 +1622,7 @@ const ApproverStockTakeAll: React.FC<ApproverStockTakeAllProps> = ({
approverBadQty,
saving,
updatingStatus,
isAdmin,
blockNonIntegerKeys,
sanitizeIntegerInput,
handleSaveApproverStockTake,
@@ -1632,7 +1637,7 @@ const ApproverStockTakeAll: React.FC<ApproverStockTakeAllProps> = ({
variant="contained"
color="primary"
onClick={handleOpenBatchSaveConfirm}
disabled={batchSaving}
disabled={!isAdmin || batchSaving}
>
{t("Batch Save All")}
</Button>


+ 28
- 15
src/components/StockTakeManagement/PickerCardList.tsx 파일 보기

@@ -223,6 +223,8 @@ interface PickerCardListProps {
locationPick: PickerLocationPick;
onLocationPickChange: (next: PickerLocationPick) => void;
stockTakeRoundId?: number | null;
/** 父層遞增:從明細返回時重抓區域卡片狀態 */
refreshNonce?: number;
hideSectionList?: boolean;
autoOpenCreate?: boolean;
onCreateDialogClose?: () => void;
@@ -312,6 +314,7 @@ const PickerCardList: React.FC<PickerCardListProps> = ({
locationPick,
onLocationPickChange,
stockTakeRoundId = null,
refreshNonce = 0,
hideSectionList = false,
autoOpenCreate = false,
onCreateDialogClose,
@@ -496,7 +499,7 @@ const PickerCardList: React.FC<PickerCardListProps> = ({
return () => {
cancelled = true;
};
}, [hideSectionList, listRefreshNonce, stockTakeRoundId]);
}, [hideSectionList, listRefreshNonce, refreshNonce, stockTakeRoundId]);

const roundSectionCodes = useMemo(
() =>
@@ -705,7 +708,7 @@ const PickerCardList: React.FC<PickerCardListProps> = ({
return () => {
cancelled = true;
};
}, [listRefreshNonce]);
}, [listRefreshNonce, refreshNonce]);

//const startIdx = page * PER_PAGE;
//const paged = stockTakeSessions.slice(startIdx, startIdx + PER_PAGE);
@@ -762,11 +765,21 @@ const PickerCardList: React.FC<PickerCardListProps> = ({
};
}, [openConfirmDialog]);

const handleGoWarehouseSettings = useCallback(() => {
setMissingSectionWarnDrawerOpen(false);
setOpenConfirmDialog(false);
router.push("/settings/warehouse");
}, [router]);
const handleGoWarehouseSettingsForIssue = useCallback(
(row: MissingStockTakeSectionIssueItem) => {
const params = new URLSearchParams();
if (row.storeId?.trim()) params.set("store_id", row.storeId.trim());
if (row.warehouse?.trim()) params.set("warehouse", row.warehouse.trim());
if (row.area?.trim()) params.set("area", row.area.trim());
if (row.slot?.trim()) params.set("slot", row.slot.trim());
if (row.code?.trim()) params.set("code", row.code.trim());
setMissingSectionWarnDrawerOpen(false);
setOpenConfirmDialog(false);
const qs = params.toString();
router.push(qs ? `/settings/warehouse?${qs}` : "/settings/warehouse");
},
[router],
);

const createStockTakeSummarySections = useMemo(() => {
return [...createDialogSelectedSections].sort((a, b) => a.localeCompare(b));
@@ -2485,6 +2498,14 @@ const PickerCardList: React.FC<PickerCardListProps> = ({
{row.order}
</Typography>
) : null}
<Button
size="small"
variant="contained"
sx={{ mt: 1 }}
onClick={() => handleGoWarehouseSettingsForIssue(row)}
>
{t("Warehouse missing stock take section go settings")}
</Button>
</Box>
))}
</Stack>
@@ -2503,14 +2524,6 @@ const PickerCardList: React.FC<PickerCardListProps> = ({
<Button variant="outlined" onClick={() => setMissingSectionWarnDrawerOpen(false)}>
{t("Cancel")}
</Button>
<Button
variant="contained"
color="primary"
onClick={handleGoWarehouseSettings}
disabled={missingSectionCount === 0}
>
{t("Warehouse missing stock take section go settings")}
</Button>
</Box>
</Drawer>
</Box>


+ 24
- 27
src/components/StockTakeManagement/StockTakeRoundCardList.tsx 파일 보기

@@ -16,7 +16,6 @@ import {
DialogContent,
DialogTitle,
Grid,
LinearProgress,
Stack,
Typography,
} from "@mui/material";
@@ -55,11 +54,6 @@ export function roundCardToSession(card: StockTakeRoundCard): AllPickedStockTake
};
}

function progressPercent(done: number, total: number): number {
if (total <= 0) return 0;
return Math.min(100, Math.round((done / total) * 100));
}

interface StockTakeRoundCardListProps {
isAdmin: boolean;
onEnterRound: (card: StockTakeRoundCard, rounds: StockTakeRoundCard[]) => void;
@@ -277,35 +271,38 @@ const StockTakeRoundCardList: React.FC<StockTakeRoundCardListProps> = ({
<Typography variant="body2" color="text.secondary">
{t("Main floor")}: {card.mainFloor?.trim() || "-"}
</Typography>
<Box sx={{ mt: 1.5 }}>
<Stack direction="row" justifyContent="space-between" sx={{ mb: 0.25 }}>
<Typography variant="caption" color="text.secondary">
<Stack
direction="row"
spacing={2}
sx={{ mt: 1.5 }}
alignItems="flex-start"
justifyContent="space-between"
>
<Stack spacing={0.25} sx={{ flex: 1, minWidth: 0 }}>
<Typography variant="caption" color="text.secondary" noWrap>
{isItemRound ? t("Stock taken lots") : t("Stock taken")}
</Typography>
<Typography variant="caption" color="text.secondary">
{taken}/{total}
<Typography
fontWeight={700}
color="primary.main"
sx={{ fontSize: "1.5rem", lineHeight: 1.2, fontVariantNumeric: "tabular-nums" }}
>
{taken} / {total}
</Typography>
</Stack>
<LinearProgress
variant="determinate"
value={progressPercent(taken, total)}
sx={{ height: 8, borderRadius: 1, mb: 1 }}
/>
<Stack direction="row" justifyContent="space-between" sx={{ mb: 0.25 }}>
<Typography variant="caption" color="text.secondary">
<Stack spacing={0.25} sx={{ flex: 1, minWidth: 0 }}>
<Typography variant="caption" color="text.secondary" noWrap>
{isItemRound ? t("Approved lots") : t("Approved progress")}
</Typography>
<Typography variant="caption" color="text.secondary">
{approved}/{total}
<Typography
fontWeight={700}
color="success.main"
sx={{ fontSize: "1.5rem", lineHeight: 1.2, fontVariantNumeric: "tabular-nums" }}
>
{approved} / {total}
</Typography>
</Stack>
<LinearProgress
variant="determinate"
color="success"
value={progressPercent(approved, total)}
sx={{ height: 8, borderRadius: 1 }}
/>
</Box>
</Stack>
</CardContent>
<CardActions sx={{ pt: 0.5, justifyContent: "space-between", flexWrap: "wrap", gap: 1 }}>
<Stack direction="row" spacing={1}>


+ 4
- 0
src/components/StockTakeManagement/StockTakeTab.tsx 파일 보기

@@ -74,6 +74,7 @@ const StockTakeTab: React.FC = () => {
const [approverLoading, setApproverLoading] = useState(false);
const [pickerListPage, setPickerListPage] = useState(0);
const [pickerListPageSize] = useState(6);
const [pickerListRefreshNonce, setPickerListRefreshNonce] = useState(0);
const [pickerSearchFilters, setPickerSearchFilters] = useState<PickerCardListFilters>(DEFAULT_PICKER_CARD_LIST_FILTERS);
const [pickerAppliedFilters, setPickerAppliedFilters] = useState<PickerCardListFilters>(DEFAULT_PICKER_CARD_LIST_FILTERS);
const [pickerLocationPick, setPickerLocationPick] = useState<PickerLocationPick>(EMPTY_PICKER_LOCATION);
@@ -110,6 +111,8 @@ const StockTakeTab: React.FC = () => {
const handleBackToList = useCallback(() => {
setSelectedSession(null);
setViewMode("details");
// 明細/重新盤點可能已改單頭狀態;列表是 display:none 未卸載,需重抓
setPickerListRefreshNonce((n) => n + 1);
}, []);

const handleSnackbar = useCallback((message: string, severity: "success" | "error" | "warning") => {
@@ -385,6 +388,7 @@ const StockTakeTab: React.FC = () => {
locationPick={pickerLocationPick}
onLocationPickChange={setPickerLocationPick}
stockTakeRoundId={roundId}
refreshNonce={pickerListRefreshNonce}
onCardClick={(session) => {
setViewScope("picker");
handleCardClick(session);


+ 116
- 124
src/components/WarehouseHandle/WarehouseHandle.tsx 파일 보기

@@ -1,11 +1,11 @@
"use client";

import { useCallback, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import SearchResults, { Column } from "../SearchResults/SearchResults";
import DeleteIcon from "@mui/icons-material/Delete";
import EditIcon from "@mui/icons-material/Edit";
import { useRouter } from "next/navigation";
import { useRouter, useSearchParams } from "next/navigation";
import { deleteDialog, successDialog } from "../Swal/CustomAlerts";
import { WarehouseResult } from "@/app/api/warehouse";
import { deleteWarehouse, editWarehouse } from "@/app/api/warehouse/actions";
@@ -31,8 +31,99 @@ interface Props {
type SearchQuery = Partial<Omit<WarehouseResult, "id">>;
type SearchParamNames = keyof SearchQuery;

type WarehouseSearchInputs = {
store_id: string;
warehouse: string;
area: string;
slot: string;
stockTakeSection: string;
stockTakeSectionDescription: string;
};

const EMPTY_WAREHOUSE_SEARCH: WarehouseSearchInputs = {
store_id: "",
warehouse: "",
area: "",
slot: "",
stockTakeSection: "",
stockTakeSectionDescription: "",
};

function parseWarehouseSearchFromParams(params: URLSearchParams): WarehouseSearchInputs {
const next: WarehouseSearchInputs = {
store_id: (params.get("store_id") || "").trim(),
warehouse: (params.get("warehouse") || "").trim(),
area: (params.get("area") || "").trim(),
slot: (params.get("slot") || "").trim(),
stockTakeSection: (params.get("stockTakeSection") || "").trim(),
stockTakeSectionDescription: (params.get("stockTakeSectionDescription") || "").trim(),
};
const code = (params.get("code") || "").trim();
if (code && !next.store_id && !next.warehouse && !next.area && !next.slot) {
const parts = code.split("-");
if (parts.length >= 4) {
next.store_id = parts[0] || "";
next.warehouse = parts[1] || "";
next.area = parts[2] || "";
next.slot = parts.slice(3).join("-") || "";
}
}
return next;
}

function filterWarehousesBySearch(
list: WarehouseResult[],
inputs: WarehouseSearchInputs,
): WarehouseResult[] {
const storeId = inputs.store_id?.trim() || "";
const warehouse = inputs.warehouse?.trim() || "";
const area = inputs.area?.trim() || "";
const slot = inputs.slot?.trim() || "";
const stockTakeSection = inputs.stockTakeSection?.trim() || "";
const stockTakeSectionDescription = inputs.stockTakeSectionDescription?.trim() || "";
if (!storeId && !warehouse && !area && !slot && !stockTakeSection && !stockTakeSectionDescription) {
return list;
}
return list.filter((warehouseItem) => {
if (stockTakeSection) {
const itemStockTakeSection = String(warehouseItem.stockTakeSection || "").toLowerCase();
if (!itemStockTakeSection.includes(stockTakeSection.toLowerCase())) return false;
}
if (stockTakeSectionDescription) {
const itemStockTakeSectionDescription = String(
warehouseItem.stockTakeSectionDescription || "",
).toLowerCase();
if (!itemStockTakeSectionDescription.includes(stockTakeSectionDescription.toLowerCase())) {
return false;
}
}
if (storeId || warehouse || area || slot) {
if (!warehouseItem.code) return false;
const codeValue = String(warehouseItem.code).toLowerCase();
const codeParts = codeValue.split("-");
if (codeParts.length >= 4) {
const slotPart = codeParts.slice(3).join("-");
return (
(!storeId || codeParts[0].includes(storeId.toLowerCase())) &&
(!warehouse || codeParts[1].includes(warehouse.toLowerCase())) &&
(!area || codeParts[2].includes(area.toLowerCase())) &&
(!slot || slotPart.includes(slot.toLowerCase()))
);
}
return (
(!storeId || codeValue.includes(storeId.toLowerCase())) &&
(!warehouse || codeValue.includes(warehouse.toLowerCase())) &&
(!area || codeValue.includes(area.toLowerCase())) &&
(!slot || codeValue.includes(slot.toLowerCase()))
);
}
return true;
});
}

const WarehouseHandle: React.FC<Props> = ({ warehouses }) => {
const { t } = useTranslation(["warehouse", "common"]);
const searchParams = useSearchParams();
const [filteredWarehouse, setFilteredWarehouse] = useState(warehouses);
const [pagingController, setPagingController] = useState({
pageNum: 1,
@@ -51,14 +142,22 @@ const WarehouseHandle: React.FC<Props> = ({ warehouses }) => {
const [isSavingEdit, setIsSavingEdit] = useState(false);
const [editError, setEditError] = useState("");

const [searchInputs, setSearchInputs] = useState({
store_id: "",
warehouse: "",
area: "",
slot: "",
stockTakeSection: "",
stockTakeSectionDescription: "",
});
const [searchInputs, setSearchInputs] = useState<WarehouseSearchInputs>(EMPTY_WAREHOUSE_SEARCH);

useEffect(() => {
const fromUrl = parseWarehouseSearchFromParams(searchParams);
const hasFilter =
Boolean(fromUrl.store_id) ||
Boolean(fromUrl.warehouse) ||
Boolean(fromUrl.area) ||
Boolean(fromUrl.slot) ||
Boolean(fromUrl.stockTakeSection) ||
Boolean(fromUrl.stockTakeSectionDescription);
if (!hasFilter) return;
setSearchInputs(fromUrl);
setFilteredWarehouse(filterWarehousesBySearch(warehouses, fromUrl));
setPagingController((prev) => ({ pageNum: 1, pageSize: prev.pageSize }));
}, [searchParams, warehouses]);

const onDeleteClick = useCallback((warehouse: WarehouseResult) => {
deleteDialog(async () => {
@@ -74,17 +173,13 @@ const WarehouseHandle: React.FC<Props> = ({ warehouses }) => {
}, [t, router]);

const handleReset = useCallback(() => {
setSearchInputs({
store_id: "",
warehouse: "",
area: "",
slot: "",
stockTakeSection: "",
stockTakeSectionDescription: "",
});
setSearchInputs(EMPTY_WAREHOUSE_SEARCH);
setFilteredWarehouse(warehouses);
setPagingController({ pageNum: 1, pageSize: pagingController.pageSize });
}, [warehouses, pagingController.pageSize]);
if (searchParams.toString()) {
router.replace("/settings/warehouse");
}
}, [warehouses, pagingController.pageSize, searchParams, router]);

const onEditClick = useCallback((warehouse: WarehouseResult) => {
setEditingWarehouse(warehouse);
@@ -154,114 +249,11 @@ const WarehouseHandle: React.FC<Props> = ({ warehouses }) => {
const handleSearch = useCallback(() => {
setIsSearching(true);
try {
let results: WarehouseResult[] = warehouses;

const storeId = searchInputs.store_id?.trim() || "";
const warehouse = searchInputs.warehouse?.trim() || "";
const area = searchInputs.area?.trim() || "";
const slot = searchInputs.slot?.trim() || "";
const stockTakeSection = searchInputs.stockTakeSection?.trim() || "";
const stockTakeSectionDescription = searchInputs.stockTakeSectionDescription?.trim() || "";
if (storeId || warehouse || area || slot || stockTakeSection || stockTakeSectionDescription) {
results = warehouses.filter((warehouseItem) => {
if (stockTakeSection) {
const itemStockTakeSection = String(warehouseItem.stockTakeSection || "").toLowerCase();
if (!itemStockTakeSection.includes(stockTakeSection.toLowerCase())) {
return false;
}
}
if (stockTakeSectionDescription) {
const itemStockTakeSectionDescription = String(warehouseItem.stockTakeSectionDescription || "").toLowerCase();
if (!itemStockTakeSectionDescription.includes(stockTakeSectionDescription.toLowerCase())) {
return false;
}
}
if (storeId || warehouse || area || slot) {
if (!warehouseItem.code) {
return false;
}
const codeValue = String(warehouseItem.code).toLowerCase();
const codeParts = codeValue.split("-");
if (codeParts.length >= 4) {
const codeStoreId = codeParts[0] || "";
const codeWarehouse = codeParts[1] || "";
const codeArea = codeParts[2] || "";
const codeSlot = codeParts[3] || "";
const storeIdMatch = !storeId || codeStoreId.includes(storeId.toLowerCase());
const warehouseMatch = !warehouse || codeWarehouse.includes(warehouse.toLowerCase());
const areaMatch = !area || codeArea.includes(area.toLowerCase());
const slotMatch = !slot || codeSlot.includes(slot.toLowerCase());
return storeIdMatch && warehouseMatch && areaMatch && slotMatch;
}
const storeIdMatch = !storeId || codeValue.includes(storeId.toLowerCase());
const warehouseMatch = !warehouse || codeValue.includes(warehouse.toLowerCase());
const areaMatch = !area || codeValue.includes(area.toLowerCase());
const slotMatch = !slot || codeValue.includes(slot.toLowerCase());
return storeIdMatch && warehouseMatch && areaMatch && slotMatch;
}
return true;
});
} else {
results = warehouses;
}

setFilteredWarehouse(results);
setFilteredWarehouse(filterWarehousesBySearch(warehouses, searchInputs));
setPagingController({ pageNum: 1, pageSize: pagingController.pageSize });
} catch (error) {
console.error("Error searching warehouses:", error);
const storeId = searchInputs.store_id?.trim().toLowerCase() || "";
const warehouse = searchInputs.warehouse?.trim().toLowerCase() || "";
const area = searchInputs.area?.trim().toLowerCase() || "";
const slot = searchInputs.slot?.trim().toLowerCase() || "";
const stockTakeSection = searchInputs.stockTakeSection?.trim().toLowerCase() || "";
const stockTakeSectionDescription = searchInputs.stockTakeSectionDescription?.trim().toLowerCase() || "";
setFilteredWarehouse(
warehouses.filter((warehouseItem) => {
if (stockTakeSection) {
const itemStockTakeSection = String(warehouseItem.stockTakeSection || "").toLowerCase();
if (!itemStockTakeSection.includes(stockTakeSection)) {
return false;
}
}
if (stockTakeSectionDescription) {
const itemStockTakeSectionDescription = String(warehouseItem.stockTakeSectionDescription || "").toLowerCase();
if (!itemStockTakeSectionDescription.includes(stockTakeSectionDescription)) {
return false;
}
}
if (storeId || warehouse || area || slot) {
if (!warehouseItem.code) {
return false;
}
const codeValue = String(warehouseItem.code).toLowerCase();
const codeParts = codeValue.split("-");
if (codeParts.length >= 4) {
const storeIdMatch = !storeId || codeParts[0].includes(storeId);
const warehouseMatch = !warehouse || codeParts[1].includes(warehouse);
const areaMatch = !area || codeParts[2].includes(area);
const slotMatch = !slot || codeParts[3].includes(slot);
return storeIdMatch && warehouseMatch && areaMatch && slotMatch;
}
return (!storeId || codeValue.includes(storeId)) &&
(!warehouse || codeValue.includes(warehouse)) &&
(!area || codeValue.includes(area)) &&
(!slot || codeValue.includes(slot));
}
return true;
})
);
setFilteredWarehouse(filterWarehousesBySearch(warehouses, searchInputs));
} finally {
setIsSearching(false);
}


+ 1
- 0
src/i18n/en/stockIssue.json 파일 보기

@@ -39,6 +39,7 @@
"Failed to submit": "Failed to submit",
"Failed to submit expiry item": "Failed to submit expiry item",
"Not yet due; cannot dispose until the expiry date": "Not yet due; cannot dispose until the expiry date",
"Expires today but in open stock take; cannot dispose": "Expires today but this lot is in an open stock take; dispose after the round finishes or the lot leaves the round",
"Handled Date": "Handled Date",
"Handled Start Date": "Handled Start Date",
"Handled End Date": "Handled End Date",


+ 2
- 2
src/i18n/en/stockTake.json 파일 보기

@@ -181,9 +181,9 @@
"Warehouse": "Warehouse",
"Warehouse code": "Warehouse code",
"Warehouse Location": "Warehouse Location",
"Warehouse missing stock take section drawer hint": "These locations have no stock take section (ST-xxx) and cannot be included in stock take. Fix in warehouse settings.",
"Warehouse missing stock take section drawer hint": "These locations have no stock take section (ST-xxx) and cannot be included in stock take. Use “Go to this warehouse” on each row to open settings with that location searched.",
"Warehouse missing stock take section empty": "No warehouses missing stock take section",
"Warehouse missing stock take section go settings": "Go to warehouse settings",
"Warehouse missing stock take section go settings": "Go to this warehouse",
"Warehouse missing stock take section showing": "Showing {{shown}} of {{count}}",
"Warehouse missing stock take section tooltip has": "{{count}} warehouse location(s) missing stock take section — click to view",
"Warehouse missing stock take section tooltip none": "All warehouses have a stock take section",


+ 1
- 0
src/i18n/zh/stockIssue.json 파일 보기

@@ -39,6 +39,7 @@
"Failed to submit": "提交失敗",
"Failed to submit expiry item": "提交過期品失敗",
"Not yet due; cannot dispose until the expiry date": "尚未到期,到期日當日才可處置",
"Expires today but in open stock take; cannot dispose": "今日到期但盤點進行中,請待盤點結束或該批退出盤點後再處置",
"Handled Date": "處理日期",
"Handled Start Date": "處理日期(開始)",
"Handled End Date": "處理日期(結束)",


+ 2
- 2
src/i18n/zh/stockTake.json 파일 보기

@@ -162,10 +162,10 @@
"No sections match search": "沒有符合搜索條件的區域",
"Confirm create stock take": "確認建立盤點",
"Not filled": "(未填寫)",
"Warehouse missing stock take section drawer hint": "以下倉庫位置尚未設定盤點區域(ST-xxx),無法納入盤點區域選擇。請至倉庫設定補上。",
"Warehouse missing stock take section drawer hint": "以下倉庫位置尚未設定盤點區域(ST-xxx),無法納入盤點區域選擇。請點各筆「前往此倉庫設定」補上。",
"Warehouse missing stock take section showing": "顯示前 {{shown}} 筆,共 {{count}} 筆",
"Warehouse missing stock take section empty": "沒有未設定盤點區域的倉庫",
"Warehouse missing stock take section go settings": "前往倉庫設定",
"Warehouse missing stock take section go settings": "前往此倉庫設定",
"Available QTY cannot be negative": "可用數量不能為負數",
"Stock take record saved successfully": "盤點記錄保存成功",
"Batch save completed: {{success}} success, {{errors}} errors": "批量保存完成:{{success}} 成功,{{errors}} 失敗",


불러오는 중...
취소
저장