Ver a proveniência

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 há 1 semana
ascendente
cometimento
7b8135dd2d
11 ficheiros alterados com 197 adições e 175 eliminações
  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 Ver ficheiro

@@ -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 Ver ficheiro

@@ -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 Ver ficheiro

@@ -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 Ver ficheiro

@@ -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 Ver ficheiro

@@ -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 Ver ficheiro

@@ -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 Ver ficheiro

@@ -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 Ver ficheiro

@@ -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 Ver ficheiro

@@ -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 Ver ficheiro

@@ -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 Ver ficheiro

@@ -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}} 失敗",


Carregando…
Cancelar
Guardar