From 524bf4269082f4e510a63058c6c8bf482664e8b5 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Mon, 7 Sep 2026 16:23:36 +0800 Subject: [PATCH] fix inventory adj button --- src/app/api/inventory/actions.ts | 2 +- .../InventorySearch/InventoryLotLineTable.tsx | 8 +- .../InventorySearch/InventorySearch.tsx | 210 ++---------------- 3 files changed, 22 insertions(+), 198 deletions(-) diff --git a/src/app/api/inventory/actions.ts b/src/app/api/inventory/actions.ts index b03440c9..fb7d8643 100644 --- a/src/app/api/inventory/actions.ts +++ b/src/app/api/inventory/actions.ts @@ -172,7 +172,7 @@ async function fetchInventoriesLatestImpl(data: SearchInventory) { export const fetchInventories = cache(fetchInventoriesImpl); /** - * FP-MTMS Version Checklist | Functions Ref. No. 18 | v1.0.1 | 2026-09-07 + * FP-MTMS Version Checklist | Functions Ref. No. 18 | v1.0.3 | 2026-09-07 * Inventory search page: latest inventory row per item (no baseUnit/uomId filter). */ export const fetchInventoriesLatest = cache(fetchInventoriesLatestImpl); diff --git a/src/components/InventorySearch/InventoryLotLineTable.tsx b/src/components/InventorySearch/InventoryLotLineTable.tsx index d9a2f448..fd6165d1 100644 --- a/src/components/InventorySearch/InventoryLotLineTable.tsx +++ b/src/components/InventorySearch/InventoryLotLineTable.tsx @@ -34,7 +34,7 @@ import dayjs from "dayjs"; import CheckIcon from "@mui/icons-material/Check"; import { submitStockAdjustment, StockAdjustmentLineRequest } from "@/app/api/stockAdjustment/actions"; import { useSession } from "next-auth/react"; -import { AUTH } from "@/authorities"; +import { AUTH, hasAbility } from "@/authorities"; type AdjustmentEntry = InventoryLotLineResult & { adjustedQty: number; @@ -59,7 +59,7 @@ interface Props { onStockAdjustmentSuccess?: () => void | Promise; } -/** FP-MTMS Version Checklist | Functions Ref. No. 3 | v1.0.5 | 2026-08-05 */ +/** FP-MTMS Version Checklist | Functions Ref. No. 3 | v1.0.6 | 2026-09-07 */ const InventoryLotLineTable: React.FC = ({ inventoryLotLines, pagingController, setPagingController, totalCount, inventory, filterLotNo, @@ -68,8 +68,8 @@ const InventoryLotLineTable: React.FC = ({ }) => { const { t } = useTranslation(["inventory"]); const { data: session } = useSession(); - const abilities = session?.user?.abilities ?? []; - const canStockAdjust = abilities.includes(AUTH.INVENTORY_ADJUST); + const abilities = session?.abilities ?? session?.user?.abilities ?? []; + const canStockAdjust = hasAbility(abilities, AUTH.INVENTORY_ADJUST); const PRINT_PRINTER_ID_KEY = 'inventoryLotLinePrintPrinterId'; const { setIsUploading } = useUploadContext(); const [stockTransferModalOpen, setStockTransferModalOpen] = useState(false); diff --git a/src/components/InventorySearch/InventorySearch.tsx b/src/components/InventorySearch/InventorySearch.tsx index 6586ea10..a59ff224 100644 --- a/src/components/InventorySearch/InventorySearch.tsx +++ b/src/components/InventorySearch/InventorySearch.tsx @@ -16,23 +16,10 @@ import { fetchInventoryLotLines, } from '@/app/api/inventory/actions'; import { PrinterCombo } from '@/app/api/settings/printer'; -import { ItemCombo, fetchItemsByPage } from '@/app/api/settings/item/actions'; -import { - Button, - Dialog, - DialogActions, - DialogContent, - DialogTitle, - TextField, - Box, - CircularProgress, - Table, - TableBody, - TableCell, - TableHead, - TableRow, - Radio, -} from '@mui/material'; +import { fetchItemsByPage } from '@/app/api/settings/item/actions'; +import { useSession } from 'next-auth/react'; +import { AUTH, hasAbility } from '@/authorities'; +import { Button, Box } from '@mui/material'; interface Props { inventories: InventoryResult[]; @@ -66,8 +53,6 @@ type ItemLookupRow = { purchaseUnit?: string; }; -type OpeningItemRow = ItemCombo & { code: string; name: string; type?: string }; - const extractItemRecords = (res: unknown): ItemLookupRow[] => { if (!res) return []; if (Array.isArray(res)) return res as ItemLookupRow[]; @@ -77,11 +62,13 @@ const extractItemRecords = (res: unknown): ItemLookupRow[] => { return []; }; -/** FP-MTMS Version Checklist | Functions Ref. No. 18 | v1.0.1 | 2026-09-07 */ +/** FP-MTMS Version Checklist | Functions Ref. No. 18 | v1.0.3 | 2026-09-07 */ const InventorySearch: React.FC = ({ inventories, printerCombo }) => { const { t } = useTranslation(['inventory', 'common', 'item']); + const { data: session } = useSession(); + const abilities = session?.abilities ?? session?.user?.abilities ?? []; + const canStockAdjust = hasAbility(abilities, AUTH.INVENTORY_ADJUST); const searchInFlightRef = useRef(false); - const openingSearchInFlightRef = useRef(false); const buildSyntheticInventory = useCallback((item: ItemLookupRow): InventoryResult => { const uom = item.uomDesc || item.uom || item.purchaseUnit || ''; @@ -153,13 +140,6 @@ const InventorySearch: React.FC = ({ inventories, printerCombo }) => { const [lotNoFilter, setLotNoFilter] = useState(''); const [scannedItemId, setScannedItemId] = useState(null); - // Opening inventory (pure opening stock for items without existing inventory) - const [openingItems, setOpeningItems] = useState([]); - const [openingModalOpen, setOpeningModalOpen] = useState(false); - const [openingSelectedItem, setOpeningSelectedItem] = useState(null); - const [openingLoading, setOpeningLoading] = useState(false); - const [openingSearchText, setOpeningSearchText] = useState(''); - const defaultInputs = useMemo( () => ({ itemId: '', @@ -354,7 +334,7 @@ const InventorySearch: React.FC = ({ inventories, printerCombo }) => { setInventoryLotLinesPagingController(() => defaultPagingController); // No inventory rows: look up item master so 0-qty rows can be selected for stock adjustment. - if (invRes?.records?.length === 0) { + if (canStockAdjust && invRes?.records?.length === 0) { try { const items = await lookupItemsByCodeOrName(query.itemCode, query.itemName); const typeFilter = query.itemType?.trim(); @@ -385,6 +365,7 @@ const InventorySearch: React.FC = ({ inventories, printerCombo }) => { refetchInventoryLotLineData, lookupItemsByCodeOrName, applyItemsAsSyntheticInventories, + canStockAdjust, ], ); @@ -430,8 +411,12 @@ const InventorySearch: React.FC = ({ inventories, printerCombo }) => { onInventoryRowClick(target); } else { refetchInventoryLotLineData(null, 'search', defaultPagingController); - const items = await lookupItemsByCodeOrName(res?.itemCode); - if (!applyItemsAsSyntheticInventories(items)) { + if (canStockAdjust) { + const items = await lookupItemsByCodeOrName(res?.itemCode); + if (!applyItemsAsSyntheticInventories(items)) { + setSelectedInventory(null); + } + } else { setSelectedInventory(null); } } @@ -454,73 +439,10 @@ const InventorySearch: React.FC = ({ inventories, printerCombo }) => { refetchInventoryLotLineData, lookupItemsByCodeOrName, applyItemsAsSyntheticInventories, + canStockAdjust, scanUiMode, ]); - //console.log('', 'color: #666', inventoriesPagingController); - - const handleOpenOpeningInventoryModal = useCallback(() => { - setOpeningSelectedItem(null); - setOpeningItems([]); - setOpeningSearchText(''); - setOpeningModalOpen(true); - }, []); - - const handleOpeningSearch = useCallback(async () => { - const trimmed = openingSearchText.trim(); - if (!trimmed) { - setOpeningItems([]); - return; - } - if (openingSearchInFlightRef.current) return; - openingSearchInFlightRef.current = true; - setOpeningLoading(true); - try { - const items = trimmed.includes(' ') - ? await lookupItemsByCodeOrName(undefined, trimmed) - : await lookupItemsByCodeOrName(trimmed); - const combos: OpeningItemRow[] = items.map((item) => { - const uom = item.uomDesc || item.uom || item.purchaseUnit || ''; - return { - id: item.id, - label: `${item.code} - ${item.name}`, - uomId: 0, - uom, - uomDesc: uom, - code: item.code, - name: item.name, - type: item.type, - }; - }); - setOpeningItems(combos); - } catch (e) { - console.error('Failed to search items for opening inventory:', e); - setOpeningItems([]); - } finally { - setOpeningLoading(false); - openingSearchInFlightRef.current = false; - } - }, [openingSearchText, lookupItemsByCodeOrName]); - - const handleConfirmOpeningInventory = useCallback(() => { - if (!openingSelectedItem) { - setOpeningModalOpen(false); - return; - } - - applyItemsAsSyntheticInventories([ - { - id: Number(openingSelectedItem.id), - code: openingSelectedItem.code, - name: openingSelectedItem.name, - type: openingSelectedItem.type, - uom: openingSelectedItem.uom, - uomDesc: openingSelectedItem.uomDesc, - }, - ]); - setOpeningModalOpen(false); - }, [openingSelectedItem, applyItemsAsSyntheticInventories]); - return ( <> = ({ inventories, printerCombo }) => { )} - - } /> @@ -604,96 +518,6 @@ const InventorySearch: React.FC = ({ inventories, printerCombo }) => { } }} /> - - setOpeningModalOpen(false)} - fullWidth - maxWidth="md" - > - {t('Add entry for items without inventory')} - - - setOpeningSearchText(e.target.value)} - onKeyDown={(e) => { - if (e.key === 'Enter') { - e.preventDefault(); - handleOpeningSearch(); - } - }} - sx={{ flex: 2 }} - /> - - - - {openingItems.length === 0 && !openingLoading ? ( - - {openingSearchText - ? t('No data') - : t('Enter item code or name to search')} - - ) : ( - - - - - {t('Code')} - {t('Name')} - {t('UoM')} - {t('Current Stock')} - - - - {openingItems.map((it) => { - const selected = openingSelectedItem?.id === it.id; - return ( - setOpeningSelectedItem(it)} - sx={{ cursor: 'pointer' }} - > - - - - {it.code} - {it.name} - {it.uomDesc || it.uom} - - {it.currentStockBalance != null ? it.currentStockBalance : '-'} - - - ); - })} - -
- )} -
- - - - -
); };