@open-mercato/core 0.10.1-develop.7776.1.3032ea0741 → 0.10.1-develop.7781.1.079f42c863
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/catalog/components/products/ProductsDataTable.js +6 -5
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +5 -4
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +6 -5
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +5 -4
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/query_index/cli.js +9 -1
- package/dist/modules/query_index/cli.js.map +2 -2
- package/dist/modules/query_index/lib/coverage.js +13 -2
- package/dist/modules/query_index/lib/coverage.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +28 -9
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/indexer.js +5 -1
- package/dist/modules/query_index/lib/indexer.js.map +2 -2
- package/dist/modules/query_index/lib/reindexer.js +95 -32
- package/dist/modules/query_index/lib/reindexer.js.map +2 -2
- package/dist/modules/query_index/lib/search-scope.js +101 -0
- package/dist/modules/query_index/lib/search-scope.js.map +7 -0
- package/dist/modules/query_index/lib/stale.js +41 -1
- package/dist/modules/query_index/lib/stale.js.map +2 -2
- package/dist/modules/query_index/lib/subscriber-scope.js +30 -7
- package/dist/modules/query_index/lib/subscriber-scope.js.map +3 -3
- package/dist/modules/query_index/lib/tenant-global.js +41 -0
- package/dist/modules/query_index/lib/tenant-global.js.map +7 -0
- package/dist/modules/query_index/subscribers/reindex.js +9 -2
- package/dist/modules/query_index/subscribers/reindex.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +4 -3
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +6 -5
- package/src/modules/customers/backend/customers/companies/page.tsx +5 -4
- package/src/modules/customers/backend/customers/deals/page.tsx +6 -5
- package/src/modules/customers/backend/customers/people/page.tsx +5 -4
- package/src/modules/query_index/cli.ts +19 -1
- package/src/modules/query_index/lib/coverage.ts +29 -3
- package/src/modules/query_index/lib/engine.ts +34 -9
- package/src/modules/query_index/lib/indexer.ts +6 -1
- package/src/modules/query_index/lib/reindexer.ts +205 -36
- package/src/modules/query_index/lib/search-scope.ts +144 -0
- package/src/modules/query_index/lib/stale.ts +73 -0
- package/src/modules/query_index/lib/subscriber-scope.ts +38 -8
- package/src/modules/query_index/lib/tenant-global.ts +93 -0
- package/src/modules/query_index/subscribers/reindex.ts +24 -1
- package/src/modules/sales/components/documents/ItemsSection.tsx +6 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/sales/components/documents/ItemsSection.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\";\n\nimport * as React from \"react\";\nimport { extensionPoints } from \"@open-mercato/core/modules/sales/extension-points\";\nimport { apiCall, withScopedApiRequestHeaders } from \"@open-mercato/ui/backend/utils/apiCall\";\nimport { buildOptimisticLockHeader } from \"@open-mercato/ui/backend/utils/optimisticLock\";\nimport { deleteCrud } from \"@open-mercato/ui/backend/utils/crud\";\nimport { normalizeCrudServerError } from \"@open-mercato/ui/backend/utils/serverErrors\";\nimport { LoadingMessage, TabEmptyState } from \"@open-mercato/ui/backend/detail\";\nimport { Button } from \"@open-mercato/ui/primitives/button\";\nimport { flash } from \"@open-mercato/ui/backend/FlashMessages\";\nimport { Pencil, Trash2 } from \"lucide-react\";\nimport {\n DictionaryValue,\n type DictionaryMap,\n createDictionaryMap,\n normalizeDictionaryEntries,\n} from \"@open-mercato/core/modules/dictionaries/components/dictionaryAppearance\";\nimport { cn } from \"@open-mercato/shared/lib/utils\";\nimport { useT, useLocale } from \"@open-mercato/shared/lib/i18n/context\";\nimport { useOrganizationScopeDetail } from \"@open-mercato/shared/lib/frontend/useOrganizationScope\";\nimport { useConfirmDialog } from \"@open-mercato/ui/backend/confirm-dialog\";\nimport { emitSalesDocumentTotalsRefresh } from \"@open-mercato/core/modules/sales/lib/frontend/documentTotalsEvents\";\nimport { LineItemDialog } from \"./LineItemDialog\";\nimport { handleSectionMutationError } from \"./optimisticLock\";\nimport { useSalesDocumentMutation } from \"./useSalesDocumentMutation\";\nimport type { SalesLineRecord } from \"./lineItemTypes\";\nimport {\n formatMoney,\n normalizeNumber,\n resolveLineDiscountDisplay,\n} from \"./lineItemUtils\";\nimport type { SectionAction } from \"@open-mercato/ui/backend/detail\";\nimport { extractCustomFieldValues } from \"./customFieldHelpers\";\nimport { canonicalizeUnitCode } from \"@open-mercato/shared/lib/units/unitCodes\";\nimport type { SalesLineUomSnapshot } from \"../../lib/types\";\nimport { useInjectionDataWidgets } from \"@open-mercato/ui/backend/injection/useInjectionDataWidgets\";\nimport type { InjectionColumnDefinition } from \"@open-mercato/shared/modules/widgets/injection\";\nimport { OrderItemsInjectionContext } from \"../../widgets/injection/order-items-context\";\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\ntype ResolvedUnitPriceReference = {\n grossPerReference: number;\n referenceUnitCode: string;\n};\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isSalesLineUomSnapshot(\n value: unknown,\n): value is SalesLineUomSnapshot {\n if (!isPlainObject(value)) return false;\n return (\n value.version === 1 &&\n typeof value.enteredQuantity === \"string\" &&\n typeof value.toBaseFactor === \"string\" &&\n typeof value.normalizedQuantity === \"string\"\n );\n}\n\nfunction extractUomSnapshot(\n item: Record<string, unknown>,\n): SalesLineUomSnapshot | null {\n const raw = item.uom_snapshot ?? item.uomSnapshot;\n if (isSalesLineUomSnapshot(raw)) return raw;\n return null;\n}\n\nfunction resolveUnitPriceReference(\n snapshot: SalesLineUomSnapshot | Record<string, unknown> | null,\n): ResolvedUnitPriceReference | null {\n if (!snapshot) return null;\n\n const ref = isSalesLineUomSnapshot(snapshot)\n ? snapshot.unitPriceReference\n : isPlainObject(snapshot)\n ? isPlainObject(snapshot.unitPriceReference)\n ? snapshot.unitPriceReference\n : isPlainObject(snapshot.unit_price_reference)\n ? snapshot.unit_price_reference\n : null\n : null;\n\n if (!ref || !isPlainObject(ref)) return null;\n\n const refRecord = ref as Record<string, unknown>;\n const grossPerReference = normalizeNumber(\n refRecord.grossPerReference ?? refRecord.gross_per_reference,\n Number.NaN,\n );\n if (!Number.isFinite(grossPerReference)) return null;\n\n const referenceUnitCode =\n typeof refRecord.referenceUnitCode === \"string\"\n ? refRecord.referenceUnitCode\n : typeof refRecord.reference_unit_code === \"string\"\n ? refRecord.reference_unit_code\n : typeof refRecord.referenceUnit === \"string\"\n ? refRecord.referenceUnit\n : null;\n if (!referenceUnitCode) return null;\n\n return { grossPerReference, referenceUnitCode };\n}\n\nfunction getUomFields(item: Record<string, unknown>) {\n const uomSnapshot = extractUomSnapshot(item);\n return {\n normalizedQuantity: (item.normalized_quantity ?? item.normalizedQuantity ?? null) as\n | number\n | string\n | null,\n normalizedUnit: (item.normalized_unit ?? item.normalizedUnit ?? null) as string | null,\n quantityUnit: (item.quantity_unit ?? item.quantityUnit ?? null) as string | null,\n uomSnapshot,\n };\n}\n\nfunction resolveInjectedColumnValue(\n row: Record<string, unknown>,\n accessorKey: string,\n): unknown {\n const segments = accessorKey.split(\".\").filter(Boolean);\n let current: unknown = row;\n for (const segment of segments) {\n if (!current || typeof current !== \"object\") return undefined;\n current = (current as Record<string, unknown>)[segment];\n }\n return current;\n}\n\nconst LINES_PAGE_SIZE = 100;\n// Upper bound on line pages fetched for one document, so an API that ignores `page`\n// cannot spin the loader forever.\nconst LINES_MAX_PAGES = 200;\n\nconst SHIPMENTS_PAGE_SIZE = 100;\n// A single order beyond this many shipment pages is pathological; stopping there\n// keeps the shipped state explicitly unresolved rather than silently partial.\nconst SHIPMENTS_MAX_PAGES = 50;\n\ntype SalesDocumentItemsSectionProps = {\n documentId: string;\n kind: \"order\" | \"quote\";\n currencyCode: string | null | undefined;\n documentUpdatedAt?: string | null;\n organizationId?: string | null;\n tenantId?: string | null;\n onActionChange?: (action: SectionAction | null) => void;\n onItemsChange?: (items: SalesLineRecord[]) => void;\n /** Disables line writes: on an external order they would all be rejected. */\n amountsReadOnly?: boolean;\n};\n\nexport function SalesDocumentItemsSection({\n documentId,\n kind,\n currencyCode,\n documentUpdatedAt,\n organizationId: orgFromProps,\n tenantId: tenantFromProps,\n onActionChange,\n onItemsChange,\n amountsReadOnly = false,\n}: SalesDocumentItemsSectionProps) {\n const t = useT();\n const runDocumentMutation = useSalesDocumentMutation(kind, documentId);\n const locale = useLocale();\n const { organizationId, tenantId } = useOrganizationScopeDetail();\n const { confirm, ConfirmDialogElement } = useConfirmDialog();\n const resolvedOrganizationId = orgFromProps ?? organizationId ?? null;\n const resolvedTenantId = tenantFromProps ?? tenantId ?? null;\n const [items, setItems] = React.useState<SalesLineRecord[]>([]);\n const [loading, setLoading] = React.useState(false);\n const [error, setError] = React.useState<string | null>(null);\n const [dialogOpen, setDialogOpen] = React.useState(false);\n const [lineForEdit, setLineForEdit] = React.useState<SalesLineRecord | null>(\n null,\n );\n const [lineStatusMap, setLineStatusMap] = React.useState<DictionaryMap>({});\n const [shippedTotals, setShippedTotals] = React.useState<Map<string, number>>(\n new Map(),\n );\n // Quotes have no shipments at all, so their shipped state is known up front.\n // For orders it stays unknown until every shipment page has been read \u2014 an\n // empty map from a pending or failed load must never read as \"nothing shipped\".\n const [shippedTotalsResolved, setShippedTotalsResolved] = React.useState(\n kind !== \"order\",\n );\n\n const { widgets: allColumnWidgets } = useInjectionDataWidgets(\n extensionPoints.hosts.orderItemColumns.spotId,\n );\n const columnWidgets = kind === \"order\" ? allColumnWidgets : [];\n const injectedColumns = React.useMemo<InjectionColumnDefinition[]>(() => {\n const cols: InjectionColumnDefinition[] = [];\n for (const widget of columnWidgets) {\n if (!(\"columns\" in widget)) continue;\n for (const def of (widget as { columns?: InjectionColumnDefinition[] })\n .columns ?? []) {\n cols.push(def);\n }\n }\n return cols;\n }, [columnWidgets]);\n\n const resourcePath = React.useMemo(\n () => (kind === \"order\" ? \"sales/order-lines\" : \"sales/quote-lines\"),\n [kind],\n );\n const documentKey = kind === \"order\" ? \"orderId\" : \"quoteId\";\n const lineStatusesLoaded = React.useRef(false);\n const itemsLoadedForDocument = React.useRef<string | null>(null);\n const itemsLoadSeq = React.useRef(0);\n const shipmentsLoadedForDocument = React.useRef<string | null>(null);\n const loadLineStatuses = React.useCallback(async () => {\n try {\n const params = new URLSearchParams({ page: \"1\", pageSize: \"100\" });\n const response = await apiCall<{\n items?: Array<Record<string, unknown>>;\n }>(`/api/sales/order-line-statuses?${params.toString()}`, undefined, {\n fallback: { items: [] },\n });\n const entries = normalizeDictionaryEntries(response.result?.items ?? [], { sort: false });\n setLineStatusMap(createDictionaryMap(entries));\n } catch (err) {\n logger.error('sales.document.line-statuses.load', { err });\n setLineStatusMap({});\n }\n }, []);\n\n const loadItems = React.useCallback(async () => {\n const loadSeq = ++itemsLoadSeq.current;\n const isCurrentLoad = () => loadSeq === itemsLoadSeq.current;\n setLoading(true);\n setError(null);\n try {\n const collectedItems: Array<Record<string, unknown>> = [];\n const seenIds = new Set<string>();\n let loaded = false;\n let complete = false;\n let page = 1;\n while (page <= LINES_MAX_PAGES) {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(LINES_PAGE_SIZE),\n [documentKey]: documentId,\n });\n const response = await apiCall<{\n items?: Array<Record<string, unknown>>;\n total?: unknown;\n }>(`/api/${resourcePath}?${params.toString()}`, undefined, {\n fallback: { items: [] },\n });\n if (!response.ok || !Array.isArray(response.result?.items)) {\n if (page > 1) throw new Error(\"[internal] sales line page failed to load\");\n complete = true;\n break;\n }\n loaded = true;\n const pageItems = response.result.items;\n let added = 0;\n pageItems.forEach((item) => {\n const id = typeof item.id === \"string\" ? item.id : null;\n if (id && seenIds.has(id)) return;\n if (id) seenIds.add(id);\n collectedItems.push(item);\n added += 1;\n });\n const reportedTotal = normalizeNumber(response.result?.total, Number.NaN);\n const hasMore =\n added > 0 &&\n pageItems.length >= LINES_PAGE_SIZE &&\n (!Number.isFinite(reportedTotal) || collectedItems.length < reportedTotal);\n if (!hasMore) {\n complete = true;\n break;\n }\n page += 1;\n }\n if (!complete) throw new Error(\"[internal] sales line page limit reached\");\n if (!isCurrentLoad()) return;\n if (loaded) {\n const mapped = collectedItems.flatMap<SalesLineRecord>(\n (item) => {\n const id = typeof item.id === \"string\" ? item.id : null;\n if (!id) return [];\n const taxRate = normalizeNumber(\n item.tax_rate ?? item.taxRate,\n 0,\n );\n const customFields = extractCustomFieldValues(\n item as Record<string, unknown>,\n );\n const name =\n typeof item.name === \"string\"\n ? item.name\n : typeof item.catalog_snapshot === \"object\" &&\n item.catalog_snapshot &&\n typeof (item.catalog_snapshot as Record<string, unknown>).name === \"string\"\n ? (item.catalog_snapshot as Record<string, unknown>).name as string\n : null;\n const description =\n typeof item.description === \"string\" && item.description.trim()\n ? item.description\n : null;\n const quantity = normalizeNumber(item.quantity, 0);\n const uomFields = getUomFields(item);\n const quantityUnit = canonicalizeUnitCode(uomFields.quantityUnit);\n const normalizedQuantity = normalizeNumber(\n uomFields.normalizedQuantity,\n quantity,\n );\n const normalizedUnit =\n canonicalizeUnitCode(uomFields.normalizedUnit) ?? quantityUnit;\n const uomSnapshot = uomFields.uomSnapshot;\n const unitPriceNetRaw = normalizeNumber(\n item.unit_price_net ?? item.unitPriceNet,\n Number.NaN,\n );\n const unitPriceGrossRaw = normalizeNumber(\n item.unit_price_gross ?? item.unitPriceGross,\n Number.NaN,\n );\n const unitPriceNet = Number.isFinite(unitPriceNetRaw)\n ? unitPriceNetRaw\n : Number.isFinite(unitPriceGrossRaw)\n ? unitPriceGrossRaw / (1 + taxRate / 100)\n : 0;\n const unitPriceGross = Number.isFinite(unitPriceGrossRaw)\n ? unitPriceGrossRaw\n : Number.isFinite(unitPriceNetRaw)\n ? unitPriceNetRaw * (1 + taxRate / 100)\n : 0;\n const totalNetRaw = normalizeNumber(\n item.total_net_amount ?? item.totalNetAmount,\n Number.NaN,\n );\n const totalGrossRaw = normalizeNumber(\n item.total_gross_amount ?? item.totalGrossAmount,\n Number.NaN,\n );\n const totalNet = Number.isFinite(totalNetRaw)\n ? totalNetRaw\n : unitPriceNet * quantity;\n const totalGross = Number.isFinite(totalGrossRaw)\n ? totalGrossRaw\n : unitPriceGross * quantity;\n const priceModeRaw =\n item.metadata &&\n typeof item.metadata === \"object\"\n ? (item.metadata as Record<string, unknown>).priceMode\n : null;\n const priceMode = priceModeRaw === \"net\" ? \"net\" : \"gross\";\n const customFieldSetId =\n typeof item.custom_field_set_id === \"string\"\n ? item.custom_field_set_id\n : typeof item.customFieldSetId === \"string\"\n ? item.customFieldSetId\n : null;\n const statusEntryId =\n typeof item.status_entry_id === \"string\"\n ? item.status_entry_id\n : typeof item.statusEntryId === \"string\"\n ? item.statusEntryId\n : null;\n const status = typeof item.status === \"string\" ? item.status : null;\n const record: SalesLineRecord = {\n id,\n name,\n description,\n productId:\n typeof item.product_id === \"string\" ? item.product_id : null,\n productVariantId:\n typeof item.product_variant_id === \"string\"\n ? item.product_variant_id\n : null,\n quantity,\n quantityUnit,\n normalizedQuantity,\n normalizedUnit,\n currencyCode:\n typeof item.currency_code === \"string\"\n ? item.currency_code\n : typeof currencyCode === \"string\"\n ? currencyCode\n : null,\n unitPriceNet,\n unitPriceGross,\n discountAmount: normalizeNumber(\n item.discount_amount ?? item.discountAmount,\n 0,\n ),\n discountPercent: normalizeNumber(\n item.discount_percent ?? item.discountPercent,\n 0,\n ),\n taxRate,\n totalNet,\n totalGross,\n priceMode,\n uomSnapshot,\n metadata:\n (item.metadata as Record<string, unknown> | null | undefined) ??\n null,\n catalogSnapshot:\n (item.catalog_snapshot as\n | Record<string, unknown>\n | null\n | undefined) ?? null,\n customFieldSetId,\n customFields: Object.keys(customFields).length\n ? customFields\n : null,\n status,\n statusEntryId,\n };\n return [record];\n },\n );\n setItems(mapped);\n if (onItemsChange) onItemsChange(mapped);\n } else {\n setItems([]);\n if (onItemsChange) onItemsChange([]);\n }\n } catch (err) {\n if (!isCurrentLoad()) return;\n logger.error('sales.document.items.load', { err });\n setError(t(\"sales.documents.items.errorLoad\", \"Failed to load items.\"));\n setItems([]);\n if (onItemsChange) onItemsChange([]);\n } finally {\n if (isCurrentLoad()) setLoading(false);\n }\n }, [currencyCode, documentId, documentKey, onItemsChange, resourcePath, t]);\n\n const loadShippedTotals = React.useCallback(async () => {\n if (kind !== \"order\") {\n setShippedTotals(new Map());\n setShippedTotalsResolved(true);\n return;\n }\n setShippedTotals(new Map());\n setShippedTotalsResolved(false);\n try {\n const totals = new Map<string, number>();\n let page = 1;\n let collected = 0;\n let complete = false;\n while (page <= SHIPMENTS_MAX_PAGES) {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(SHIPMENTS_PAGE_SIZE),\n orderId: documentId,\n });\n const response = await apiCall<{\n items?: Array<Record<string, unknown>>;\n total?: unknown;\n }>(`/api/sales/shipments?${params.toString()}`, undefined, {\n fallback: { items: [] },\n });\n if (!response.ok || !Array.isArray(response.result?.items)) return;\n const shipments = response.result.items;\n shipments.forEach((shipment) => {\n const entries = Array.isArray(shipment.items)\n ? (shipment.items as Array<Record<string, unknown>>)\n : [];\n entries.forEach((entry) => {\n const lineId =\n typeof entry.orderLineId === \"string\"\n ? entry.orderLineId\n : typeof entry.order_line_id === \"string\"\n ? entry.order_line_id\n : null;\n if (!lineId) return;\n const quantity = normalizeNumber(entry.quantity, 0);\n if (!Number.isFinite(quantity) || quantity <= 0) return;\n const current = totals.get(lineId) ?? 0;\n totals.set(lineId, current + quantity);\n });\n });\n collected += shipments.length;\n const reportedTotal = normalizeNumber(response.result?.total, Number.NaN);\n const hasMore =\n shipments.length >= SHIPMENTS_PAGE_SIZE &&\n (!Number.isFinite(reportedTotal) || collected < reportedTotal);\n if (!hasMore) {\n complete = true;\n break;\n }\n page += 1;\n }\n if (!complete) return;\n setShippedTotals(totals);\n setShippedTotalsResolved(true);\n } catch (err) {\n logger.error('sales.document.shipments.load', { err });\n }\n }, [documentId, kind]);\n\n React.useEffect(() => {\n if (lineStatusesLoaded.current) return;\n lineStatusesLoaded.current = true;\n void loadLineStatuses();\n }, [loadLineStatuses]);\n\n React.useEffect(() => {\n if (!documentId) return;\n if (itemsLoadedForDocument.current === documentId) return;\n itemsLoadedForDocument.current = documentId;\n void loadItems();\n }, [documentId, loadItems]);\n\n React.useEffect(() => {\n if (kind !== \"order\") {\n shipmentsLoadedForDocument.current = null;\n setShippedTotals(new Map());\n setShippedTotalsResolved(true);\n return;\n }\n const key = `${kind}:${documentId}`;\n if (shipmentsLoadedForDocument.current === key) return;\n shipmentsLoadedForDocument.current = key;\n void loadShippedTotals();\n }, [documentId, kind, loadShippedTotals]);\n\n const openCreate = React.useCallback(() => {\n setLineForEdit(null);\n setDialogOpen(true);\n }, []);\n\n React.useEffect(() => {\n if (!onActionChange) return;\n onActionChange({\n label: t(\"sales.documents.items.add\", \"Add item\"),\n onClick: openCreate,\n disabled: amountsReadOnly,\n });\n return () => onActionChange(null);\n }, [amountsReadOnly, onActionChange, openCreate, t]);\n\n const handleEdit = React.useCallback(\n (line: SalesLineRecord) => {\n if (amountsReadOnly) return;\n setLineForEdit(line);\n setDialogOpen(true);\n },\n [amountsReadOnly],\n );\n\n const resolveVariantInfo = React.useCallback((record: SalesLineRecord) => {\n const meta =\n (record.metadata as Record<string, unknown> | null | undefined) ?? null;\n const snapshot =\n (record.catalogSnapshot as Record<string, unknown> | null | undefined) ??\n null;\n const variantSnapshot =\n snapshot &&\n typeof snapshot.variant === \"object\" &&\n snapshot.variant\n ? (snapshot.variant as Record<string, unknown>)\n : null;\n const variantTitle =\n meta && typeof meta.variantTitle === \"string\"\n ? meta.variantTitle\n : variantSnapshot && typeof variantSnapshot.name === \"string\"\n ? variantSnapshot.name\n : null;\n const variantSku =\n meta && typeof meta.variantSku === \"string\"\n ? meta.variantSku\n : variantSnapshot && typeof variantSnapshot.sku === \"string\"\n ? variantSnapshot.sku\n : null;\n\n return { variantTitle, variantSku };\n }, []);\n\n const handleDelete = React.useCallback(\n async (line: SalesLineRecord) => {\n const confirmed = await confirm({\n title: t(\n \"sales.documents.items.deleteConfirm\",\n \"Delete this line item?\",\n ),\n variant: \"destructive\",\n });\n if (!confirmed) return;\n try {\n const result = await runDocumentMutation(() => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(documentUpdatedAt),\n () =>\n deleteCrud(resourcePath, {\n body: {\n id: line.id,\n [documentKey]: documentId,\n organizationId: resolvedOrganizationId ?? undefined,\n tenantId: resolvedTenantId ?? undefined,\n },\n errorMessage: t(\n \"sales.documents.items.errorDelete\",\n \"Failed to delete line.\",\n ),\n }),\n ), { id: line.id, [documentKey]: documentId });\n if (result.ok) {\n flash(t(\"sales.documents.items.deleted\", \"Line removed.\"), \"success\");\n await loadItems();\n emitSalesDocumentTotalsRefresh({ documentId, kind });\n }\n } catch (err) {\n if (handleSectionMutationError(err, t, () => void loadItems())) return;\n logger.error('sales.document.items.delete', { err });\n const normalized = normalizeCrudServerError(err);\n const fallback = t(\n \"sales.documents.items.errorDelete\",\n \"Failed to delete line.\",\n );\n flash(normalized.message || fallback, \"error\");\n }\n },\n [\n confirm,\n documentId,\n documentKey,\n documentUpdatedAt,\n kind,\n loadItems,\n resolvedOrganizationId,\n resourcePath,\n t,\n resolvedTenantId,\n runDocumentMutation,\n ],\n );\n\n const renderStatus = React.useCallback(\n (line: SalesLineRecord) => {\n const value = line.status ?? null;\n if (!value) {\n return (\n <span className=\"text-xs text-muted-foreground\">\n {t(\"sales.documents.items.table.statusEmpty\", \"No status\")}\n </span>\n );\n }\n return (\n <DictionaryValue\n value={value}\n map={lineStatusMap}\n fallback={<span className=\"text-xs font-medium\">{value}</span>}\n className=\"text-xs font-medium\"\n iconWrapperClassName=\"inline-flex h-6 w-6 items-center justify-center rounded bg-muted text-muted-foreground\"\n iconClassName=\"h-3.5 w-3.5\"\n colorClassName=\"h-4 w-4 rounded-full border border-border/70\"\n />\n );\n },\n [lineStatusMap, t],\n );\n\n const showDiscountColumn = React.useMemo(\n () => items.some((item) => resolveLineDiscountDisplay(item) !== null),\n [items],\n );\n\n const renderImage = (record: SalesLineRecord) => {\n const meta =\n (record.metadata as Record<string, unknown> | null | undefined) ?? {};\n const snapshot =\n (record.catalogSnapshot as Record<string, unknown> | null | undefined) ??\n {};\n const productSnapshot: Record<string, unknown> =\n typeof snapshot === \"object\" && snapshot\n ? ((snapshot.product as Record<string, unknown>) ?? {})\n : {};\n const variantSnapshot: Record<string, unknown> =\n typeof snapshot === \"object\" && snapshot\n ? ((snapshot.variant as Record<string, unknown>) ?? {})\n : {};\n const productThumb =\n (meta &&\n typeof meta.productThumbnail === \"string\" &&\n meta.productThumbnail) ||\n (productSnapshot &&\n typeof productSnapshot.thumbnailUrl === \"string\" &&\n productSnapshot.thumbnailUrl) ||\n null;\n const variantThumb =\n (meta &&\n typeof meta.variantThumbnail === \"string\" &&\n meta.variantThumbnail) ||\n (variantSnapshot &&\n typeof variantSnapshot.thumbnailUrl === \"string\" &&\n variantSnapshot.thumbnailUrl) ||\n null;\n const thumbnail = variantThumb ?? productThumb;\n if (thumbnail) {\n return (\n <img\n src={thumbnail}\n alt={record.name ?? record.id}\n className=\"h-10 w-10 rounded border object-cover\"\n />\n );\n }\n return (\n <div className=\"flex h-10 w-10 items-center justify-center rounded border bg-muted text-xs text-muted-foreground\">\n N/A\n </div>\n );\n };\n\n return (\n <OrderItemsInjectionContext.Provider value={{ documentId, kind }}>\n <div className=\"space-y-4\">\n {loading ? (\n <LoadingMessage\n label={t(\"sales.documents.items.loading\", \"Loading items\u2026\")}\n className=\"border-0 bg-transparent p-0 py-8 justify-center\"\n />\n ) : error ? (\n <p className=\"text-sm text-destructive\">{error}</p>\n ) : items.length === 0 ? (\n <TabEmptyState\n title={t(\"sales.documents.items.empty\", \"No items yet.\")}\n description={t(\n \"sales.documents.items.subtitle\",\n \"Add products and configure pricing for this document.\",\n )}\n action={{\n label: t(\"sales.documents.items.add\", \"Add item\"),\n onClick: openCreate,\n disabled: amountsReadOnly,\n }}\n />\n ) : (\n <div className=\"relative overflow-x-auto rounded border\">\n <table className=\"w-full text-sm\">\n <thead className=\"bg-muted\">\n <tr className=\"text-left\">\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.product\", \"Product\")}\n </th>\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.status\", \"Status\")}\n </th>\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.quantity\", \"Qty\")}\n </th>\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.unit\", \"Unit price\")}\n </th>\n {showDiscountColumn ? (\n <th className=\"px-3 py-2 font-medium whitespace-nowrap\">\n {t(\"sales.documents.items.table.discount\", \"Discount\")}\n </th>\n ) : null}\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.total\", \"Total\")}\n </th>\n {injectedColumns.map((col) => (\n <th\n key={col.id}\n className=\"px-3 py-2 font-medium whitespace-nowrap\"\n >\n {col.headerKey ? t(col.headerKey, col.header) : col.header}\n </th>\n ))}\n <th className=\"px-3 py-2 font-medium sr-only\">\n {t(\"sales.documents.items.table.actions\", \"Actions\")}\n </th>\n </tr>\n </thead>\n <tbody>\n {items.map((item) => {\n const meta =\n (item.metadata as\n | Record<string, unknown>\n | null\n | undefined) ?? null;\n const { variantTitle, variantSku } = resolveVariantInfo(item);\n const productSku =\n meta && typeof meta.productSku === \"string\"\n ? meta.productSku\n : null;\n const variantLabel = variantTitle ?? variantSku;\n const variantSuffix =\n variantSku && variantLabel && variantSku !== variantLabel\n ? ` \u2022 ${variantSku}`\n : \"\";\n const showProductSku =\n productSku && productSku !== variantSku ? productSku : null;\n const shippedQuantity = Math.max(\n 0,\n shippedTotals.get(item.id) ?? 0,\n );\n const quantityLabel = item.quantityUnit\n ? `${item.quantity} ${item.quantityUnit}`\n : String(item.quantity);\n const showNormalized =\n Number.isFinite(item.normalizedQuantity) &&\n item.normalizedQuantity > 0 &&\n (item.normalizedUnit ?? null) &&\n (Math.abs(item.normalizedQuantity - item.quantity) >\n 0.000001 ||\n (item.normalizedUnit ?? null) !==\n (item.quantityUnit ?? null));\n const unitPriceReference = resolveUnitPriceReference(\n item.uomSnapshot,\n );\n const discount = resolveLineDiscountDisplay(item);\n\n return (\n <tr\n key={item.id}\n className={cn(\n \"border-t transition-colors\",\n amountsReadOnly ? \"\" : \"cursor-pointer hover:bg-muted/50\",\n )}\n onClick={() => handleEdit(item)}\n >\n <td className=\"px-3 py-3\">\n <div className=\"flex items-center gap-3\">\n {renderImage(item)}\n <div className=\"min-w-0\">\n <div className=\"truncate font-medium\">\n {item.name ??\n t(\"sales.documents.items.untitled\", \"Untitled\")}\n </div>\n {variantLabel ? (\n <div className=\"text-xs text-muted-foreground truncate\">\n {variantLabel}\n {variantSuffix}\n </div>\n ) : null}\n {showProductSku ? (\n <div className=\"text-xs text-muted-foreground truncate\">\n {showProductSku}\n </div>\n ) : null}\n {item.description ? (\n <div\n className=\"text-xs text-muted-foreground line-clamp-2\"\n title={item.description}\n >\n {item.description}\n </div>\n ) : null}\n </div>\n </div>\n </td>\n <td className=\"px-3 py-3\">\n <div className=\"flex items-center\">\n {renderStatus(item)}\n </div>\n </td>\n <td className=\"px-3 py-3\">\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"font-medium\">{quantityLabel}</span>\n {showNormalized ? (\n <span className=\"text-xs text-muted-foreground\">\n {item.normalizedQuantity} {item.normalizedUnit}\n </span>\n ) : null}\n {shippedQuantity > 0 ? (\n <span className=\"text-xs text-muted-foreground\">\n {t(\n \"sales.documents.items.table.shipped\",\n \"{{shipped}} / {{total}} shipped\",\n {\n shipped: shippedQuantity,\n total: item.quantity,\n },\n )}\n </span>\n ) : null}\n </div>\n </td>\n <td className=\"px-3 py-3\">\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"font-mono text-sm\">\n {formatMoney(\n item.unitPriceGross,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n <span className=\"text-xs text-muted-foreground\">\n {t(\"sales.documents.items.table.gross\", \"gross\")}\n </span>\n </span>\n <span className=\"font-mono text-xs text-muted-foreground\">\n {formatMoney(\n item.unitPriceNet,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n {t(\"sales.documents.items.table.net\", \"net\")}\n </span>\n {unitPriceReference ? (\n <span className=\"text-xs text-muted-foreground\">\n {t(\n \"sales.documents.items.table.unitPriceReference\",\n \"{{value}} per 1 {{unit}}\",\n {\n value: formatMoney(\n unitPriceReference.grossPerReference,\n item.currencyCode ??\n currencyCode ??\n undefined,\n locale,\n ),\n unit: unitPriceReference.referenceUnitCode,\n },\n )}\n </span>\n ) : null}\n </div>\n </td>\n {showDiscountColumn ? (\n <td className=\"px-3 py-3\">\n {discount ? (\n <div className=\"flex flex-col gap-0.5\">\n {discount.amount !== null ? (\n <span className=\"font-mono text-sm\">\n {t(\n \"sales.documents.items.table.discountAmount\",\n \"\u2212{{value}}\",\n {\n value: formatMoney(\n discount.amount,\n item.currencyCode ??\n currencyCode ??\n undefined,\n locale,\n ),\n },\n )}\n </span>\n ) : null}\n {discount.percent !== null ? (\n <span\n className={\n discount.amount !== null\n ? \"font-mono text-xs text-muted-foreground\"\n : \"font-mono text-sm\"\n }\n >\n {t(\n \"sales.documents.items.table.discountPercent\",\n \"{{value}}%\",\n { value: discount.percent },\n )}\n </span>\n ) : null}\n </div>\n ) : null}\n </td>\n ) : null}\n <td className=\"px-3 py-3 font-semibold\">\n <div className=\"flex flex-col gap-0.5\">\n <span>\n {formatMoney(\n item.totalGross,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n <span className=\"text-xs font-normal text-muted-foreground\">\n {t(\"sales.documents.items.table.gross\", \"gross\")}\n </span>\n </span>\n <span className=\"text-xs font-medium text-muted-foreground\">\n {formatMoney(\n item.totalNet,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n {t(\"sales.documents.items.table.net\", \"net\")}\n </span>\n </div>\n </td>\n {injectedColumns.map((col) => {\n const colValue = resolveInjectedColumnValue(\n item as unknown as Record<string, unknown>,\n col.accessorKey,\n );\n const Cell = col.cell;\n return (\n <td\n key={col.id}\n className=\"px-3 py-3\"\n onClick={(e) => e.stopPropagation()}\n >\n {Cell ? <Cell getValue={() => colValue} /> : null}\n </td>\n );\n })}\n <td className=\"px-3 py-3\">\n <div className=\"flex items-center gap-2 justify-end\">\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"h-8 w-8\"\n aria-label={t('ui.actions.edit', 'Edit')}\n disabled={amountsReadOnly}\n onClick={(event) => {\n event.stopPropagation();\n handleEdit(item);\n }}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <span\n title={amountsReadOnly\n ? t('sales.documents.amountsExternalHint', 'Totals on this document come from an external system and are stored as supplied.')\n : kind === 'order' && items.length === 1\n ? t('sales.documents.items.errorDeleteLast', 'An order must contain at least one line item.')\n : undefined}\n >\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"h-8 w-8 text-destructive\"\n aria-label={t('ui.actions.delete', 'Delete')}\n disabled={amountsReadOnly || (kind === 'order' && items.length === 1)}\n onClick={(event) => {\n event.stopPropagation();\n void handleDelete(item);\n }}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </span>\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n )}\n\n <LineItemDialog\n open={dialogOpen}\n onOpenChange={(next) => {\n setDialogOpen(next);\n if (!next) setLineForEdit(null);\n }}\n kind={kind}\n documentId={documentId}\n currencyCode={currencyCode}\n documentUpdatedAt={documentUpdatedAt}\n organizationId={resolvedOrganizationId}\n tenantId={resolvedTenantId}\n initialLine={lineForEdit}\n shippedQuantity={\n lineForEdit\n ? Math.max(0, shippedTotals.get(lineForEdit.id) ?? 0)\n : 0\n }\n shippedQuantityResolved={shippedTotalsResolved}\n onSaved={async () => {\n await loadItems();\n emitSalesDocumentTotalsRefresh({ documentId, kind });\n }}\n />\n {ConfirmDialogElement}\n </div>\n </OrderItemsInjectionContext.Provider>\n );\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\";\n\nimport * as React from \"react\";\nimport { extensionPoints } from \"@open-mercato/core/modules/sales/extension-points\";\nimport { apiCall, withScopedApiRequestHeaders } from \"@open-mercato/ui/backend/utils/apiCall\";\nimport { buildOptimisticLockHeader } from \"@open-mercato/ui/backend/utils/optimisticLock\";\nimport { deleteCrud } from \"@open-mercato/ui/backend/utils/crud\";\nimport { normalizeCrudServerError } from \"@open-mercato/ui/backend/utils/serverErrors\";\nimport { ErrorMessage, LoadingMessage, TabEmptyState } from \"@open-mercato/ui/backend/detail\";\nimport { Button } from \"@open-mercato/ui/primitives/button\";\nimport { flash } from \"@open-mercato/ui/backend/FlashMessages\";\nimport { Pencil, Trash2 } from \"lucide-react\";\nimport {\n DictionaryValue,\n type DictionaryMap,\n createDictionaryMap,\n normalizeDictionaryEntries,\n} from \"@open-mercato/core/modules/dictionaries/components/dictionaryAppearance\";\nimport { cn } from \"@open-mercato/shared/lib/utils\";\nimport { useT, useLocale } from \"@open-mercato/shared/lib/i18n/context\";\nimport { useOrganizationScopeDetail } from \"@open-mercato/shared/lib/frontend/useOrganizationScope\";\nimport { useConfirmDialog } from \"@open-mercato/ui/backend/confirm-dialog\";\nimport { emitSalesDocumentTotalsRefresh } from \"@open-mercato/core/modules/sales/lib/frontend/documentTotalsEvents\";\nimport { LineItemDialog } from \"./LineItemDialog\";\nimport { handleSectionMutationError } from \"./optimisticLock\";\nimport { useSalesDocumentMutation } from \"./useSalesDocumentMutation\";\nimport type { SalesLineRecord } from \"./lineItemTypes\";\nimport {\n formatMoney,\n normalizeNumber,\n resolveLineDiscountDisplay,\n} from \"./lineItemUtils\";\nimport type { SectionAction } from \"@open-mercato/ui/backend/detail\";\nimport { extractCustomFieldValues } from \"./customFieldHelpers\";\nimport { canonicalizeUnitCode } from \"@open-mercato/shared/lib/units/unitCodes\";\nimport type { SalesLineUomSnapshot } from \"../../lib/types\";\nimport { useInjectionDataWidgets } from \"@open-mercato/ui/backend/injection/useInjectionDataWidgets\";\nimport type { InjectionColumnDefinition } from \"@open-mercato/shared/modules/widgets/injection\";\nimport { OrderItemsInjectionContext } from \"../../widgets/injection/order-items-context\";\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\ntype ResolvedUnitPriceReference = {\n grossPerReference: number;\n referenceUnitCode: string;\n};\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isSalesLineUomSnapshot(\n value: unknown,\n): value is SalesLineUomSnapshot {\n if (!isPlainObject(value)) return false;\n return (\n value.version === 1 &&\n typeof value.enteredQuantity === \"string\" &&\n typeof value.toBaseFactor === \"string\" &&\n typeof value.normalizedQuantity === \"string\"\n );\n}\n\nfunction extractUomSnapshot(\n item: Record<string, unknown>,\n): SalesLineUomSnapshot | null {\n const raw = item.uom_snapshot ?? item.uomSnapshot;\n if (isSalesLineUomSnapshot(raw)) return raw;\n return null;\n}\n\nfunction resolveUnitPriceReference(\n snapshot: SalesLineUomSnapshot | Record<string, unknown> | null,\n): ResolvedUnitPriceReference | null {\n if (!snapshot) return null;\n\n const ref = isSalesLineUomSnapshot(snapshot)\n ? snapshot.unitPriceReference\n : isPlainObject(snapshot)\n ? isPlainObject(snapshot.unitPriceReference)\n ? snapshot.unitPriceReference\n : isPlainObject(snapshot.unit_price_reference)\n ? snapshot.unit_price_reference\n : null\n : null;\n\n if (!ref || !isPlainObject(ref)) return null;\n\n const refRecord = ref as Record<string, unknown>;\n const grossPerReference = normalizeNumber(\n refRecord.grossPerReference ?? refRecord.gross_per_reference,\n Number.NaN,\n );\n if (!Number.isFinite(grossPerReference)) return null;\n\n const referenceUnitCode =\n typeof refRecord.referenceUnitCode === \"string\"\n ? refRecord.referenceUnitCode\n : typeof refRecord.reference_unit_code === \"string\"\n ? refRecord.reference_unit_code\n : typeof refRecord.referenceUnit === \"string\"\n ? refRecord.referenceUnit\n : null;\n if (!referenceUnitCode) return null;\n\n return { grossPerReference, referenceUnitCode };\n}\n\nfunction getUomFields(item: Record<string, unknown>) {\n const uomSnapshot = extractUomSnapshot(item);\n return {\n normalizedQuantity: (item.normalized_quantity ?? item.normalizedQuantity ?? null) as\n | number\n | string\n | null,\n normalizedUnit: (item.normalized_unit ?? item.normalizedUnit ?? null) as string | null,\n quantityUnit: (item.quantity_unit ?? item.quantityUnit ?? null) as string | null,\n uomSnapshot,\n };\n}\n\nfunction resolveInjectedColumnValue(\n row: Record<string, unknown>,\n accessorKey: string,\n): unknown {\n const segments = accessorKey.split(\".\").filter(Boolean);\n let current: unknown = row;\n for (const segment of segments) {\n if (!current || typeof current !== \"object\") return undefined;\n current = (current as Record<string, unknown>)[segment];\n }\n return current;\n}\n\nconst LINES_PAGE_SIZE = 100;\n// Upper bound on line pages fetched for one document, so an API that ignores `page`\n// cannot spin the loader forever.\nconst LINES_MAX_PAGES = 200;\n\nconst SHIPMENTS_PAGE_SIZE = 100;\n// A single order beyond this many shipment pages is pathological; stopping there\n// keeps the shipped state explicitly unresolved rather than silently partial.\nconst SHIPMENTS_MAX_PAGES = 50;\n\ntype SalesDocumentItemsSectionProps = {\n documentId: string;\n kind: \"order\" | \"quote\";\n currencyCode: string | null | undefined;\n documentUpdatedAt?: string | null;\n organizationId?: string | null;\n tenantId?: string | null;\n onActionChange?: (action: SectionAction | null) => void;\n onItemsChange?: (items: SalesLineRecord[]) => void;\n /** Disables line writes: on an external order they would all be rejected. */\n amountsReadOnly?: boolean;\n};\n\nexport function SalesDocumentItemsSection({\n documentId,\n kind,\n currencyCode,\n documentUpdatedAt,\n organizationId: orgFromProps,\n tenantId: tenantFromProps,\n onActionChange,\n onItemsChange,\n amountsReadOnly = false,\n}: SalesDocumentItemsSectionProps) {\n const t = useT();\n const runDocumentMutation = useSalesDocumentMutation(kind, documentId);\n const locale = useLocale();\n const { organizationId, tenantId } = useOrganizationScopeDetail();\n const { confirm, ConfirmDialogElement } = useConfirmDialog();\n const resolvedOrganizationId = orgFromProps ?? organizationId ?? null;\n const resolvedTenantId = tenantFromProps ?? tenantId ?? null;\n const [items, setItems] = React.useState<SalesLineRecord[]>([]);\n const [loading, setLoading] = React.useState(false);\n const [error, setError] = React.useState<string | null>(null);\n const [dialogOpen, setDialogOpen] = React.useState(false);\n const [lineForEdit, setLineForEdit] = React.useState<SalesLineRecord | null>(\n null,\n );\n const [lineStatusMap, setLineStatusMap] = React.useState<DictionaryMap>({});\n const [shippedTotals, setShippedTotals] = React.useState<Map<string, number>>(\n new Map(),\n );\n // Quotes have no shipments at all, so their shipped state is known up front.\n // For orders it stays unknown until every shipment page has been read \u2014 an\n // empty map from a pending or failed load must never read as \"nothing shipped\".\n const [shippedTotalsResolved, setShippedTotalsResolved] = React.useState(\n kind !== \"order\",\n );\n\n const { widgets: allColumnWidgets, isLoading: injectedColumnsLoading, error: injectedColumnsError } = useInjectionDataWidgets(\n extensionPoints.hosts.orderItemColumns.spotId,\n );\n const columnWidgets = kind === \"order\" ? allColumnWidgets : [];\n const injectedColumns = React.useMemo<InjectionColumnDefinition[]>(() => {\n const cols: InjectionColumnDefinition[] = [];\n for (const widget of columnWidgets) {\n if (!(\"columns\" in widget)) continue;\n for (const def of (widget as { columns?: InjectionColumnDefinition[] })\n .columns ?? []) {\n cols.push(def);\n }\n }\n return cols;\n }, [columnWidgets]);\n\n const resourcePath = React.useMemo(\n () => (kind === \"order\" ? \"sales/order-lines\" : \"sales/quote-lines\"),\n [kind],\n );\n const documentKey = kind === \"order\" ? \"orderId\" : \"quoteId\";\n const lineStatusesLoaded = React.useRef(false);\n const itemsLoadedForDocument = React.useRef<string | null>(null);\n const itemsLoadSeq = React.useRef(0);\n const shipmentsLoadedForDocument = React.useRef<string | null>(null);\n const loadLineStatuses = React.useCallback(async () => {\n try {\n const params = new URLSearchParams({ page: \"1\", pageSize: \"100\" });\n const response = await apiCall<{\n items?: Array<Record<string, unknown>>;\n }>(`/api/sales/order-line-statuses?${params.toString()}`, undefined, {\n fallback: { items: [] },\n });\n const entries = normalizeDictionaryEntries(response.result?.items ?? [], { sort: false });\n setLineStatusMap(createDictionaryMap(entries));\n } catch (err) {\n logger.error('sales.document.line-statuses.load', { err });\n setLineStatusMap({});\n }\n }, []);\n\n const loadItems = React.useCallback(async () => {\n const loadSeq = ++itemsLoadSeq.current;\n const isCurrentLoad = () => loadSeq === itemsLoadSeq.current;\n setLoading(true);\n setError(null);\n try {\n const collectedItems: Array<Record<string, unknown>> = [];\n const seenIds = new Set<string>();\n let loaded = false;\n let complete = false;\n let page = 1;\n while (page <= LINES_MAX_PAGES) {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(LINES_PAGE_SIZE),\n [documentKey]: documentId,\n });\n const response = await apiCall<{\n items?: Array<Record<string, unknown>>;\n total?: unknown;\n }>(`/api/${resourcePath}?${params.toString()}`, undefined, {\n fallback: { items: [] },\n });\n if (!response.ok || !Array.isArray(response.result?.items)) {\n if (page > 1) throw new Error(\"[internal] sales line page failed to load\");\n complete = true;\n break;\n }\n loaded = true;\n const pageItems = response.result.items;\n let added = 0;\n pageItems.forEach((item) => {\n const id = typeof item.id === \"string\" ? item.id : null;\n if (id && seenIds.has(id)) return;\n if (id) seenIds.add(id);\n collectedItems.push(item);\n added += 1;\n });\n const reportedTotal = normalizeNumber(response.result?.total, Number.NaN);\n const hasMore =\n added > 0 &&\n pageItems.length >= LINES_PAGE_SIZE &&\n (!Number.isFinite(reportedTotal) || collectedItems.length < reportedTotal);\n if (!hasMore) {\n complete = true;\n break;\n }\n page += 1;\n }\n if (!complete) throw new Error(\"[internal] sales line page limit reached\");\n if (!isCurrentLoad()) return;\n if (loaded) {\n const mapped = collectedItems.flatMap<SalesLineRecord>(\n (item) => {\n const id = typeof item.id === \"string\" ? item.id : null;\n if (!id) return [];\n const taxRate = normalizeNumber(\n item.tax_rate ?? item.taxRate,\n 0,\n );\n const customFields = extractCustomFieldValues(\n item as Record<string, unknown>,\n );\n const name =\n typeof item.name === \"string\"\n ? item.name\n : typeof item.catalog_snapshot === \"object\" &&\n item.catalog_snapshot &&\n typeof (item.catalog_snapshot as Record<string, unknown>).name === \"string\"\n ? (item.catalog_snapshot as Record<string, unknown>).name as string\n : null;\n const description =\n typeof item.description === \"string\" && item.description.trim()\n ? item.description\n : null;\n const quantity = normalizeNumber(item.quantity, 0);\n const uomFields = getUomFields(item);\n const quantityUnit = canonicalizeUnitCode(uomFields.quantityUnit);\n const normalizedQuantity = normalizeNumber(\n uomFields.normalizedQuantity,\n quantity,\n );\n const normalizedUnit =\n canonicalizeUnitCode(uomFields.normalizedUnit) ?? quantityUnit;\n const uomSnapshot = uomFields.uomSnapshot;\n const unitPriceNetRaw = normalizeNumber(\n item.unit_price_net ?? item.unitPriceNet,\n Number.NaN,\n );\n const unitPriceGrossRaw = normalizeNumber(\n item.unit_price_gross ?? item.unitPriceGross,\n Number.NaN,\n );\n const unitPriceNet = Number.isFinite(unitPriceNetRaw)\n ? unitPriceNetRaw\n : Number.isFinite(unitPriceGrossRaw)\n ? unitPriceGrossRaw / (1 + taxRate / 100)\n : 0;\n const unitPriceGross = Number.isFinite(unitPriceGrossRaw)\n ? unitPriceGrossRaw\n : Number.isFinite(unitPriceNetRaw)\n ? unitPriceNetRaw * (1 + taxRate / 100)\n : 0;\n const totalNetRaw = normalizeNumber(\n item.total_net_amount ?? item.totalNetAmount,\n Number.NaN,\n );\n const totalGrossRaw = normalizeNumber(\n item.total_gross_amount ?? item.totalGrossAmount,\n Number.NaN,\n );\n const totalNet = Number.isFinite(totalNetRaw)\n ? totalNetRaw\n : unitPriceNet * quantity;\n const totalGross = Number.isFinite(totalGrossRaw)\n ? totalGrossRaw\n : unitPriceGross * quantity;\n const priceModeRaw =\n item.metadata &&\n typeof item.metadata === \"object\"\n ? (item.metadata as Record<string, unknown>).priceMode\n : null;\n const priceMode = priceModeRaw === \"net\" ? \"net\" : \"gross\";\n const customFieldSetId =\n typeof item.custom_field_set_id === \"string\"\n ? item.custom_field_set_id\n : typeof item.customFieldSetId === \"string\"\n ? item.customFieldSetId\n : null;\n const statusEntryId =\n typeof item.status_entry_id === \"string\"\n ? item.status_entry_id\n : typeof item.statusEntryId === \"string\"\n ? item.statusEntryId\n : null;\n const status = typeof item.status === \"string\" ? item.status : null;\n const record: SalesLineRecord = {\n id,\n name,\n description,\n productId:\n typeof item.product_id === \"string\" ? item.product_id : null,\n productVariantId:\n typeof item.product_variant_id === \"string\"\n ? item.product_variant_id\n : null,\n quantity,\n quantityUnit,\n normalizedQuantity,\n normalizedUnit,\n currencyCode:\n typeof item.currency_code === \"string\"\n ? item.currency_code\n : typeof currencyCode === \"string\"\n ? currencyCode\n : null,\n unitPriceNet,\n unitPriceGross,\n discountAmount: normalizeNumber(\n item.discount_amount ?? item.discountAmount,\n 0,\n ),\n discountPercent: normalizeNumber(\n item.discount_percent ?? item.discountPercent,\n 0,\n ),\n taxRate,\n totalNet,\n totalGross,\n priceMode,\n uomSnapshot,\n metadata:\n (item.metadata as Record<string, unknown> | null | undefined) ??\n null,\n catalogSnapshot:\n (item.catalog_snapshot as\n | Record<string, unknown>\n | null\n | undefined) ?? null,\n customFieldSetId,\n customFields: Object.keys(customFields).length\n ? customFields\n : null,\n status,\n statusEntryId,\n };\n return [record];\n },\n );\n setItems(mapped);\n if (onItemsChange) onItemsChange(mapped);\n } else {\n setItems([]);\n if (onItemsChange) onItemsChange([]);\n }\n } catch (err) {\n if (!isCurrentLoad()) return;\n logger.error('sales.document.items.load', { err });\n setError(t(\"sales.documents.items.errorLoad\", \"Failed to load items.\"));\n setItems([]);\n if (onItemsChange) onItemsChange([]);\n } finally {\n if (isCurrentLoad()) setLoading(false);\n }\n }, [currencyCode, documentId, documentKey, onItemsChange, resourcePath, t]);\n\n const loadShippedTotals = React.useCallback(async () => {\n if (kind !== \"order\") {\n setShippedTotals(new Map());\n setShippedTotalsResolved(true);\n return;\n }\n setShippedTotals(new Map());\n setShippedTotalsResolved(false);\n try {\n const totals = new Map<string, number>();\n let page = 1;\n let collected = 0;\n let complete = false;\n while (page <= SHIPMENTS_MAX_PAGES) {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(SHIPMENTS_PAGE_SIZE),\n orderId: documentId,\n });\n const response = await apiCall<{\n items?: Array<Record<string, unknown>>;\n total?: unknown;\n }>(`/api/sales/shipments?${params.toString()}`, undefined, {\n fallback: { items: [] },\n });\n if (!response.ok || !Array.isArray(response.result?.items)) return;\n const shipments = response.result.items;\n shipments.forEach((shipment) => {\n const entries = Array.isArray(shipment.items)\n ? (shipment.items as Array<Record<string, unknown>>)\n : [];\n entries.forEach((entry) => {\n const lineId =\n typeof entry.orderLineId === \"string\"\n ? entry.orderLineId\n : typeof entry.order_line_id === \"string\"\n ? entry.order_line_id\n : null;\n if (!lineId) return;\n const quantity = normalizeNumber(entry.quantity, 0);\n if (!Number.isFinite(quantity) || quantity <= 0) return;\n const current = totals.get(lineId) ?? 0;\n totals.set(lineId, current + quantity);\n });\n });\n collected += shipments.length;\n const reportedTotal = normalizeNumber(response.result?.total, Number.NaN);\n const hasMore =\n shipments.length >= SHIPMENTS_PAGE_SIZE &&\n (!Number.isFinite(reportedTotal) || collected < reportedTotal);\n if (!hasMore) {\n complete = true;\n break;\n }\n page += 1;\n }\n if (!complete) return;\n setShippedTotals(totals);\n setShippedTotalsResolved(true);\n } catch (err) {\n logger.error('sales.document.shipments.load', { err });\n }\n }, [documentId, kind]);\n\n React.useEffect(() => {\n if (lineStatusesLoaded.current) return;\n lineStatusesLoaded.current = true;\n void loadLineStatuses();\n }, [loadLineStatuses]);\n\n React.useEffect(() => {\n if (!documentId) return;\n if (itemsLoadedForDocument.current === documentId) return;\n itemsLoadedForDocument.current = documentId;\n void loadItems();\n }, [documentId, loadItems]);\n\n React.useEffect(() => {\n if (kind !== \"order\") {\n shipmentsLoadedForDocument.current = null;\n setShippedTotals(new Map());\n setShippedTotalsResolved(true);\n return;\n }\n const key = `${kind}:${documentId}`;\n if (shipmentsLoadedForDocument.current === key) return;\n shipmentsLoadedForDocument.current = key;\n void loadShippedTotals();\n }, [documentId, kind, loadShippedTotals]);\n\n const openCreate = React.useCallback(() => {\n setLineForEdit(null);\n setDialogOpen(true);\n }, []);\n\n React.useEffect(() => {\n if (!onActionChange) return;\n onActionChange({\n label: t(\"sales.documents.items.add\", \"Add item\"),\n onClick: openCreate,\n disabled: amountsReadOnly,\n });\n return () => onActionChange(null);\n }, [amountsReadOnly, onActionChange, openCreate, t]);\n\n const handleEdit = React.useCallback(\n (line: SalesLineRecord) => {\n if (amountsReadOnly) return;\n setLineForEdit(line);\n setDialogOpen(true);\n },\n [amountsReadOnly],\n );\n\n const resolveVariantInfo = React.useCallback((record: SalesLineRecord) => {\n const meta =\n (record.metadata as Record<string, unknown> | null | undefined) ?? null;\n const snapshot =\n (record.catalogSnapshot as Record<string, unknown> | null | undefined) ??\n null;\n const variantSnapshot =\n snapshot &&\n typeof snapshot.variant === \"object\" &&\n snapshot.variant\n ? (snapshot.variant as Record<string, unknown>)\n : null;\n const variantTitle =\n meta && typeof meta.variantTitle === \"string\"\n ? meta.variantTitle\n : variantSnapshot && typeof variantSnapshot.name === \"string\"\n ? variantSnapshot.name\n : null;\n const variantSku =\n meta && typeof meta.variantSku === \"string\"\n ? meta.variantSku\n : variantSnapshot && typeof variantSnapshot.sku === \"string\"\n ? variantSnapshot.sku\n : null;\n\n return { variantTitle, variantSku };\n }, []);\n\n const handleDelete = React.useCallback(\n async (line: SalesLineRecord) => {\n const confirmed = await confirm({\n title: t(\n \"sales.documents.items.deleteConfirm\",\n \"Delete this line item?\",\n ),\n variant: \"destructive\",\n });\n if (!confirmed) return;\n try {\n const result = await runDocumentMutation(() => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(documentUpdatedAt),\n () =>\n deleteCrud(resourcePath, {\n body: {\n id: line.id,\n [documentKey]: documentId,\n organizationId: resolvedOrganizationId ?? undefined,\n tenantId: resolvedTenantId ?? undefined,\n },\n errorMessage: t(\n \"sales.documents.items.errorDelete\",\n \"Failed to delete line.\",\n ),\n }),\n ), { id: line.id, [documentKey]: documentId });\n if (result.ok) {\n flash(t(\"sales.documents.items.deleted\", \"Line removed.\"), \"success\");\n await loadItems();\n emitSalesDocumentTotalsRefresh({ documentId, kind });\n }\n } catch (err) {\n if (handleSectionMutationError(err, t, () => void loadItems())) return;\n logger.error('sales.document.items.delete', { err });\n const normalized = normalizeCrudServerError(err);\n const fallback = t(\n \"sales.documents.items.errorDelete\",\n \"Failed to delete line.\",\n );\n flash(normalized.message || fallback, \"error\");\n }\n },\n [\n confirm,\n documentId,\n documentKey,\n documentUpdatedAt,\n kind,\n loadItems,\n resolvedOrganizationId,\n resourcePath,\n t,\n resolvedTenantId,\n runDocumentMutation,\n ],\n );\n\n const renderStatus = React.useCallback(\n (line: SalesLineRecord) => {\n const value = line.status ?? null;\n if (!value) {\n return (\n <span className=\"text-xs text-muted-foreground\">\n {t(\"sales.documents.items.table.statusEmpty\", \"No status\")}\n </span>\n );\n }\n return (\n <DictionaryValue\n value={value}\n map={lineStatusMap}\n fallback={<span className=\"text-xs font-medium\">{value}</span>}\n className=\"text-xs font-medium\"\n iconWrapperClassName=\"inline-flex h-6 w-6 items-center justify-center rounded bg-muted text-muted-foreground\"\n iconClassName=\"h-3.5 w-3.5\"\n colorClassName=\"h-4 w-4 rounded-full border border-border/70\"\n />\n );\n },\n [lineStatusMap, t],\n );\n\n const showDiscountColumn = React.useMemo(\n () => items.some((item) => resolveLineDiscountDisplay(item) !== null),\n [items],\n );\n\n const renderImage = (record: SalesLineRecord) => {\n const meta =\n (record.metadata as Record<string, unknown> | null | undefined) ?? {};\n const snapshot =\n (record.catalogSnapshot as Record<string, unknown> | null | undefined) ??\n {};\n const productSnapshot: Record<string, unknown> =\n typeof snapshot === \"object\" && snapshot\n ? ((snapshot.product as Record<string, unknown>) ?? {})\n : {};\n const variantSnapshot: Record<string, unknown> =\n typeof snapshot === \"object\" && snapshot\n ? ((snapshot.variant as Record<string, unknown>) ?? {})\n : {};\n const productThumb =\n (meta &&\n typeof meta.productThumbnail === \"string\" &&\n meta.productThumbnail) ||\n (productSnapshot &&\n typeof productSnapshot.thumbnailUrl === \"string\" &&\n productSnapshot.thumbnailUrl) ||\n null;\n const variantThumb =\n (meta &&\n typeof meta.variantThumbnail === \"string\" &&\n meta.variantThumbnail) ||\n (variantSnapshot &&\n typeof variantSnapshot.thumbnailUrl === \"string\" &&\n variantSnapshot.thumbnailUrl) ||\n null;\n const thumbnail = variantThumb ?? productThumb;\n if (thumbnail) {\n return (\n <img\n src={thumbnail}\n alt={record.name ?? record.id}\n className=\"h-10 w-10 rounded border object-cover\"\n />\n );\n }\n return (\n <div className=\"flex h-10 w-10 items-center justify-center rounded border bg-muted text-xs text-muted-foreground\">\n N/A\n </div>\n );\n };\n\n return (\n <OrderItemsInjectionContext.Provider value={{ documentId, kind }}>\n <div className=\"space-y-4\">\n {kind === \"order\" && injectedColumnsError ? (\n <ErrorMessage label={t('ui.dataTable.extensions.error', 'Some table extensions could not load. Reload the page to retry.')} />\n ) : null}\n {loading || (kind === \"order\" && injectedColumnsLoading) ? (\n <LoadingMessage\n label={t(\"sales.documents.items.loading\", \"Loading items\u2026\")}\n className=\"border-0 bg-transparent p-0 py-8 justify-center\"\n />\n ) : error ? (\n <p className=\"text-sm text-destructive\">{error}</p>\n ) : items.length === 0 ? (\n <TabEmptyState\n title={t(\"sales.documents.items.empty\", \"No items yet.\")}\n description={t(\n \"sales.documents.items.subtitle\",\n \"Add products and configure pricing for this document.\",\n )}\n action={{\n label: t(\"sales.documents.items.add\", \"Add item\"),\n onClick: openCreate,\n disabled: amountsReadOnly,\n }}\n />\n ) : (\n <div className=\"relative overflow-x-auto rounded border\">\n <table className=\"w-full text-sm\">\n <thead className=\"bg-muted\">\n <tr className=\"text-left\">\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.product\", \"Product\")}\n </th>\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.status\", \"Status\")}\n </th>\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.quantity\", \"Qty\")}\n </th>\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.unit\", \"Unit price\")}\n </th>\n {showDiscountColumn ? (\n <th className=\"px-3 py-2 font-medium whitespace-nowrap\">\n {t(\"sales.documents.items.table.discount\", \"Discount\")}\n </th>\n ) : null}\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.total\", \"Total\")}\n </th>\n {injectedColumns.map((col) => (\n <th\n key={col.id}\n className=\"px-3 py-2 font-medium whitespace-nowrap\"\n >\n {col.headerKey ? t(col.headerKey, col.header) : col.header}\n </th>\n ))}\n <th className=\"px-3 py-2 font-medium sr-only\">\n {t(\"sales.documents.items.table.actions\", \"Actions\")}\n </th>\n </tr>\n </thead>\n <tbody>\n {items.map((item) => {\n const meta =\n (item.metadata as\n | Record<string, unknown>\n | null\n | undefined) ?? null;\n const { variantTitle, variantSku } = resolveVariantInfo(item);\n const productSku =\n meta && typeof meta.productSku === \"string\"\n ? meta.productSku\n : null;\n const variantLabel = variantTitle ?? variantSku;\n const variantSuffix =\n variantSku && variantLabel && variantSku !== variantLabel\n ? ` \u2022 ${variantSku}`\n : \"\";\n const showProductSku =\n productSku && productSku !== variantSku ? productSku : null;\n const shippedQuantity = Math.max(\n 0,\n shippedTotals.get(item.id) ?? 0,\n );\n const quantityLabel = item.quantityUnit\n ? `${item.quantity} ${item.quantityUnit}`\n : String(item.quantity);\n const showNormalized =\n Number.isFinite(item.normalizedQuantity) &&\n item.normalizedQuantity > 0 &&\n (item.normalizedUnit ?? null) &&\n (Math.abs(item.normalizedQuantity - item.quantity) >\n 0.000001 ||\n (item.normalizedUnit ?? null) !==\n (item.quantityUnit ?? null));\n const unitPriceReference = resolveUnitPriceReference(\n item.uomSnapshot,\n );\n const discount = resolveLineDiscountDisplay(item);\n\n return (\n <tr\n key={item.id}\n className={cn(\n \"border-t transition-colors\",\n amountsReadOnly ? \"\" : \"cursor-pointer hover:bg-muted/50\",\n )}\n onClick={() => handleEdit(item)}\n >\n <td className=\"px-3 py-3\">\n <div className=\"flex items-center gap-3\">\n {renderImage(item)}\n <div className=\"min-w-0\">\n <div className=\"truncate font-medium\">\n {item.name ??\n t(\"sales.documents.items.untitled\", \"Untitled\")}\n </div>\n {variantLabel ? (\n <div className=\"text-xs text-muted-foreground truncate\">\n {variantLabel}\n {variantSuffix}\n </div>\n ) : null}\n {showProductSku ? (\n <div className=\"text-xs text-muted-foreground truncate\">\n {showProductSku}\n </div>\n ) : null}\n {item.description ? (\n <div\n className=\"text-xs text-muted-foreground line-clamp-2\"\n title={item.description}\n >\n {item.description}\n </div>\n ) : null}\n </div>\n </div>\n </td>\n <td className=\"px-3 py-3\">\n <div className=\"flex items-center\">\n {renderStatus(item)}\n </div>\n </td>\n <td className=\"px-3 py-3\">\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"font-medium\">{quantityLabel}</span>\n {showNormalized ? (\n <span className=\"text-xs text-muted-foreground\">\n {item.normalizedQuantity} {item.normalizedUnit}\n </span>\n ) : null}\n {shippedQuantity > 0 ? (\n <span className=\"text-xs text-muted-foreground\">\n {t(\n \"sales.documents.items.table.shipped\",\n \"{{shipped}} / {{total}} shipped\",\n {\n shipped: shippedQuantity,\n total: item.quantity,\n },\n )}\n </span>\n ) : null}\n </div>\n </td>\n <td className=\"px-3 py-3\">\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"font-mono text-sm\">\n {formatMoney(\n item.unitPriceGross,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n <span className=\"text-xs text-muted-foreground\">\n {t(\"sales.documents.items.table.gross\", \"gross\")}\n </span>\n </span>\n <span className=\"font-mono text-xs text-muted-foreground\">\n {formatMoney(\n item.unitPriceNet,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n {t(\"sales.documents.items.table.net\", \"net\")}\n </span>\n {unitPriceReference ? (\n <span className=\"text-xs text-muted-foreground\">\n {t(\n \"sales.documents.items.table.unitPriceReference\",\n \"{{value}} per 1 {{unit}}\",\n {\n value: formatMoney(\n unitPriceReference.grossPerReference,\n item.currencyCode ??\n currencyCode ??\n undefined,\n locale,\n ),\n unit: unitPriceReference.referenceUnitCode,\n },\n )}\n </span>\n ) : null}\n </div>\n </td>\n {showDiscountColumn ? (\n <td className=\"px-3 py-3\">\n {discount ? (\n <div className=\"flex flex-col gap-0.5\">\n {discount.amount !== null ? (\n <span className=\"font-mono text-sm\">\n {t(\n \"sales.documents.items.table.discountAmount\",\n \"\u2212{{value}}\",\n {\n value: formatMoney(\n discount.amount,\n item.currencyCode ??\n currencyCode ??\n undefined,\n locale,\n ),\n },\n )}\n </span>\n ) : null}\n {discount.percent !== null ? (\n <span\n className={\n discount.amount !== null\n ? \"font-mono text-xs text-muted-foreground\"\n : \"font-mono text-sm\"\n }\n >\n {t(\n \"sales.documents.items.table.discountPercent\",\n \"{{value}}%\",\n { value: discount.percent },\n )}\n </span>\n ) : null}\n </div>\n ) : null}\n </td>\n ) : null}\n <td className=\"px-3 py-3 font-semibold\">\n <div className=\"flex flex-col gap-0.5\">\n <span>\n {formatMoney(\n item.totalGross,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n <span className=\"text-xs font-normal text-muted-foreground\">\n {t(\"sales.documents.items.table.gross\", \"gross\")}\n </span>\n </span>\n <span className=\"text-xs font-medium text-muted-foreground\">\n {formatMoney(\n item.totalNet,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n {t(\"sales.documents.items.table.net\", \"net\")}\n </span>\n </div>\n </td>\n {injectedColumns.map((col) => {\n const colValue = resolveInjectedColumnValue(\n item as unknown as Record<string, unknown>,\n col.accessorKey,\n );\n const Cell = col.cell;\n return (\n <td\n key={col.id}\n className=\"px-3 py-3\"\n onClick={(e) => e.stopPropagation()}\n >\n {Cell ? <Cell getValue={() => colValue} /> : null}\n </td>\n );\n })}\n <td className=\"px-3 py-3\">\n <div className=\"flex items-center gap-2 justify-end\">\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"h-8 w-8\"\n aria-label={t('ui.actions.edit', 'Edit')}\n disabled={amountsReadOnly}\n onClick={(event) => {\n event.stopPropagation();\n handleEdit(item);\n }}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <span\n title={amountsReadOnly\n ? t('sales.documents.amountsExternalHint', 'Totals on this document come from an external system and are stored as supplied.')\n : kind === 'order' && items.length === 1\n ? t('sales.documents.items.errorDeleteLast', 'An order must contain at least one line item.')\n : undefined}\n >\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"h-8 w-8 text-destructive\"\n aria-label={t('ui.actions.delete', 'Delete')}\n disabled={amountsReadOnly || (kind === 'order' && items.length === 1)}\n onClick={(event) => {\n event.stopPropagation();\n void handleDelete(item);\n }}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </span>\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n )}\n\n <LineItemDialog\n open={dialogOpen}\n onOpenChange={(next) => {\n setDialogOpen(next);\n if (!next) setLineForEdit(null);\n }}\n kind={kind}\n documentId={documentId}\n currencyCode={currencyCode}\n documentUpdatedAt={documentUpdatedAt}\n organizationId={resolvedOrganizationId}\n tenantId={resolvedTenantId}\n initialLine={lineForEdit}\n shippedQuantity={\n lineForEdit\n ? Math.max(0, shippedTotals.get(lineForEdit.id) ?? 0)\n : 0\n }\n shippedQuantityResolved={shippedTotalsResolved}\n onSaved={async () => {\n await loadItems();\n emitSalesDocumentTotalsRefresh({ documentId, kind });\n }}\n />\n {ConfirmDialogElement}\n </div>\n </OrderItemsInjectionContext.Provider>\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.10.1-develop.
|
|
3
|
+
"version": "0.10.1-develop.7781.1.079f42c863",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -266,16 +266,16 @@
|
|
|
266
266
|
"zod": "^4.4.3"
|
|
267
267
|
},
|
|
268
268
|
"peerDependencies": {
|
|
269
|
-
"@open-mercato/ai-assistant": "0.10.1-develop.
|
|
270
|
-
"@open-mercato/shared": "0.10.1-develop.
|
|
271
|
-
"@open-mercato/ui": "0.10.1-develop.
|
|
269
|
+
"@open-mercato/ai-assistant": "0.10.1-develop.7781.1.079f42c863",
|
|
270
|
+
"@open-mercato/shared": "0.10.1-develop.7781.1.079f42c863",
|
|
271
|
+
"@open-mercato/ui": "0.10.1-develop.7781.1.079f42c863",
|
|
272
272
|
"react": "^19.0.0",
|
|
273
273
|
"react-dom": "^19.0.0"
|
|
274
274
|
},
|
|
275
275
|
"devDependencies": {
|
|
276
|
-
"@open-mercato/ai-assistant": "0.10.1-develop.
|
|
277
|
-
"@open-mercato/shared": "0.10.1-develop.
|
|
278
|
-
"@open-mercato/ui": "0.10.1-develop.
|
|
276
|
+
"@open-mercato/ai-assistant": "0.10.1-develop.7781.1.079f42c863",
|
|
277
|
+
"@open-mercato/shared": "0.10.1-develop.7781.1.079f42c863",
|
|
278
|
+
"@open-mercato/ui": "0.10.1-develop.7781.1.079f42c863",
|
|
279
279
|
"@testing-library/dom": "^10.4.1",
|
|
280
280
|
"@testing-library/jest-dom": "^7.0.1",
|
|
281
281
|
"@testing-library/react": "^16.3.3",
|
|
@@ -195,8 +195,8 @@ export default function ProductsDataTable({
|
|
|
195
195
|
setReloadToken((token) => token + 1)
|
|
196
196
|
})
|
|
197
197
|
const [customFieldsetFilter, setCustomFieldsetFilter] = React.useState<string | null>(null)
|
|
198
|
-
const { data: customFieldDefs = [] } = useCustomFieldDefs(ENTITY_ID, {
|
|
199
|
-
keyExtras: [scopeVersion
|
|
198
|
+
const { data: customFieldDefs = [], isLoading: customFieldDefsLoading, refetch: refetchCustomFieldDefs } = useCustomFieldDefs(ENTITY_ID, {
|
|
199
|
+
keyExtras: [scopeVersion],
|
|
200
200
|
})
|
|
201
201
|
const [channelOptionsCache, setChannelOptionsCache] = React.useState<Record<string, FilterOption>>({})
|
|
202
202
|
const [categoryOptionsCache, setCategoryOptionsCache] = React.useState<Record<string, FilterOption>>({})
|
|
@@ -507,8 +507,9 @@ export default function ProductsDataTable({
|
|
|
507
507
|
)
|
|
508
508
|
|
|
509
509
|
const handleRefresh = React.useCallback(() => {
|
|
510
|
+
void refetchCustomFieldDefs()
|
|
510
511
|
setReloadToken((token) => token + 1)
|
|
511
|
-
}, [])
|
|
512
|
+
}, [refetchCustomFieldDefs])
|
|
512
513
|
|
|
513
514
|
const queryParams = React.useMemo(() => {
|
|
514
515
|
const params = new URLSearchParams()
|
|
@@ -668,7 +669,7 @@ export default function ProductsDataTable({
|
|
|
668
669
|
title={t('catalog.products.page.title', 'Products & services')}
|
|
669
670
|
titleHeadingLevel={1}
|
|
670
671
|
entityId={ENTITY_ID}
|
|
671
|
-
customFieldFilterKeyExtras={[scopeVersion
|
|
672
|
+
customFieldFilterKeyExtras={[scopeVersion]}
|
|
672
673
|
refreshButton={{
|
|
673
674
|
label: t('catalog.products.actions.refresh', 'Refresh'),
|
|
674
675
|
onRefresh: handleRefresh,
|
|
@@ -730,7 +731,7 @@ export default function ProductsDataTable({
|
|
|
730
731
|
cacheStatus,
|
|
731
732
|
}}
|
|
732
733
|
exporter={exportConfig}
|
|
733
|
-
isLoading={isLoading}
|
|
734
|
+
isLoading={isLoading || customFieldDefsLoading}
|
|
734
735
|
perspective={{ tableId: extensionPoints.hosts.productsTable.tableId }}
|
|
735
736
|
stickyActionsColumn
|
|
736
737
|
rowActions={(row) => (
|
|
@@ -330,9 +330,9 @@ export default function CustomersCompaniesPage() {
|
|
|
330
330
|
}
|
|
331
331
|
}, [fetchDictionaryEntries, scopeVersion, reloadToken])
|
|
332
332
|
|
|
333
|
-
const { data: customFieldDefs = [] } = useCustomFieldDefs(
|
|
333
|
+
const { data: customFieldDefs = [], isLoading: customFieldDefsLoading, refetch: refetchCustomFieldDefs } = useCustomFieldDefs(
|
|
334
334
|
[E.customers.customer_entity, E.customers.customer_company_profile],
|
|
335
|
-
{ keyExtras: [scopeVersion
|
|
335
|
+
{ keyExtras: [scopeVersion] },
|
|
336
336
|
)
|
|
337
337
|
const currentUserId = useCurrentUserId()
|
|
338
338
|
const activeOrgId = useCurrentOrganization()?.id ?? null
|
|
@@ -449,8 +449,9 @@ export default function CustomersCompaniesPage() {
|
|
|
449
449
|
}, [queryParams, reloadToken, scopeVersion, t])
|
|
450
450
|
|
|
451
451
|
const handleRefresh = React.useCallback(() => {
|
|
452
|
+
void refetchCustomFieldDefs()
|
|
452
453
|
setReloadToken((token) => token + 1)
|
|
453
|
-
}, [])
|
|
454
|
+
}, [refetchCustomFieldDefs])
|
|
454
455
|
|
|
455
456
|
const handleDelete = React.useCallback(async (company: CompanyRow) => {
|
|
456
457
|
if (!company?.id) return
|
|
@@ -993,7 +994,7 @@ export default function CustomersCompaniesPage() {
|
|
|
993
994
|
)}
|
|
994
995
|
virtualized
|
|
995
996
|
pagination={{ page, pageSize, total, totalPages, totalIsCapped, onPageChange: setPage, pageSizeOptions: [10, 25, 50, 100], onPageSizeChange: handlePageSizeChange, cacheStatus }}
|
|
996
|
-
isLoading={isLoading}
|
|
997
|
+
isLoading={isLoading || customFieldDefsLoading}
|
|
997
998
|
/>
|
|
998
999
|
<AdvancedFilterPanel
|
|
999
1000
|
fields={advancedFilterFields}
|
|
@@ -219,6 +219,9 @@ export default function CustomersDealsPage() {
|
|
|
219
219
|
const pathname = usePathname()
|
|
220
220
|
const searchParams = useSearchParams()
|
|
221
221
|
const scopeVersion = useOrganizationScopeVersion()
|
|
222
|
+
const { data: customFieldDefs = [], isLoading: customFieldDefsLoading, refetch: refetchCustomFieldDefs } = useCustomFieldDefs([E.customers.customer_deal], {
|
|
223
|
+
keyExtras: [scopeVersion],
|
|
224
|
+
})
|
|
222
225
|
const queryClient = useQueryClient()
|
|
223
226
|
|
|
224
227
|
const [rows, setRows] = React.useState<DealRow[]>([])
|
|
@@ -466,8 +469,9 @@ export default function CustomersDealsPage() {
|
|
|
466
469
|
invalidateCustomerDictionary(queryClient, 'deal-statuses'),
|
|
467
470
|
invalidateCustomerDictionary(queryClient, 'pipeline-stages'),
|
|
468
471
|
])
|
|
472
|
+
void refetchCustomFieldDefs()
|
|
469
473
|
setReloadToken((token) => token + 1)
|
|
470
|
-
}, [queryClient])
|
|
474
|
+
}, [queryClient, refetchCustomFieldDefs])
|
|
471
475
|
|
|
472
476
|
const bulkMutationContextId = 'customers-deals-list:bulk-delete'
|
|
473
477
|
const { runMutation: runBulkMutation, retryLastMutation: retryBulkMutation } = useGuardedMutation<{
|
|
@@ -777,9 +781,6 @@ export default function CustomersDealsPage() {
|
|
|
777
781
|
return succeeded.length > 0
|
|
778
782
|
}, [bulkMutationContextId, confirm, retryBulkMutation, runBulkMutation, t])
|
|
779
783
|
|
|
780
|
-
const { data: customFieldDefs = [] } = useCustomFieldDefs([E.customers.customer_deal], {
|
|
781
|
-
keyExtras: [scopeVersion, reloadToken],
|
|
782
|
-
})
|
|
783
784
|
const currentUserId = useCurrentUserId()
|
|
784
785
|
const activeOrgId = useCurrentOrganization()?.id ?? null
|
|
785
786
|
const [ownerFilterOptions, setOwnerFilterOptions] = React.useState<AdvancedFilterOption[]>([])
|
|
@@ -1333,7 +1334,7 @@ export default function CustomersDealsPage() {
|
|
|
1333
1334
|
onPageSizeChange: handlePageSizeChange,
|
|
1334
1335
|
cacheStatus,
|
|
1335
1336
|
}}
|
|
1336
|
-
isLoading={isLoading}
|
|
1337
|
+
isLoading={isLoading || customFieldDefsLoading}
|
|
1337
1338
|
refreshButton={{
|
|
1338
1339
|
label: t('customers.deals.list.refresh'),
|
|
1339
1340
|
onRefresh: handleRefresh,
|
|
@@ -339,9 +339,9 @@ export default function CustomersPeoplePage() {
|
|
|
339
339
|
}
|
|
340
340
|
}, [fetchDictionaryEntries, scopeVersion, reloadToken])
|
|
341
341
|
|
|
342
|
-
const { data: customFieldDefs = [] } = useCustomFieldDefs(
|
|
342
|
+
const { data: customFieldDefs = [], isLoading: customFieldDefsLoading, refetch: refetchCustomFieldDefs } = useCustomFieldDefs(
|
|
343
343
|
[E.customers.customer_entity, E.customers.customer_person_profile],
|
|
344
|
-
{ keyExtras: [scopeVersion
|
|
344
|
+
{ keyExtras: [scopeVersion] },
|
|
345
345
|
)
|
|
346
346
|
const currentUserId = useCurrentUserId()
|
|
347
347
|
const activeOrgId = useCurrentOrganization()?.id ?? null
|
|
@@ -460,8 +460,9 @@ export default function CustomersPeoplePage() {
|
|
|
460
460
|
}, [queryParams, reloadToken, scopeVersion, t])
|
|
461
461
|
|
|
462
462
|
const handleRefresh = React.useCallback(() => {
|
|
463
|
+
void refetchCustomFieldDefs()
|
|
463
464
|
setReloadToken((token) => token + 1)
|
|
464
|
-
}, [])
|
|
465
|
+
}, [refetchCustomFieldDefs])
|
|
465
466
|
|
|
466
467
|
const handleDelete = React.useCallback(async (person: PersonRow) => {
|
|
467
468
|
if (!person?.id) return
|
|
@@ -1018,7 +1019,7 @@ export default function CustomersPeoplePage() {
|
|
|
1018
1019
|
)}
|
|
1019
1020
|
virtualized
|
|
1020
1021
|
pagination={{ page, pageSize, total, totalPages, totalIsCapped, onPageChange: setPage, cacheStatus, pageSizeOptions: [10, 25, 50, 100], onPageSizeChange: handlePageSizeChange }}
|
|
1021
|
-
isLoading={isLoading}
|
|
1022
|
+
isLoading={isLoading || customFieldDefsLoading}
|
|
1022
1023
|
/>
|
|
1023
1024
|
<AdvancedFilterPanel
|
|
1024
1025
|
fields={advancedFilterFields}
|
|
@@ -22,6 +22,21 @@ import {
|
|
|
22
22
|
type AnyRow,
|
|
23
23
|
} from './lib/batch'
|
|
24
24
|
import { reindexEntity, DEFAULT_REINDEX_PARTITIONS } from './lib/reindexer'
|
|
25
|
+
import type { ReindexJobResult } from './lib/reindexer'
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A refused sweep returns processed 0 / total 0, which the progress reporting below prints
|
|
29
|
+
* as `0 / 0 (0.00%)` - indistinguishable from a run that found nothing. Say why instead.
|
|
30
|
+
*/
|
|
31
|
+
function warnIfReindexRefused(entityType: string, result: ReindexJobResult): void {
|
|
32
|
+
if (!result.refused) return
|
|
33
|
+
const detail = result.refused === 'no-tenant-column'
|
|
34
|
+
? 'the source table has no tenant_id column and the entity type is not declared tenant-global'
|
|
35
|
+
: result.refused === 'declared-global-but-org-scoped'
|
|
36
|
+
? 'the entity type is declared tenant-global but its table carries an organization_id column'
|
|
37
|
+
: "the source table's columns could not be read, so no scope could be proven (usually transient)"
|
|
38
|
+
console.warn(` -> ${entityType}: reindex REFUSED, nothing was indexed - ${detail}`)
|
|
39
|
+
}
|
|
25
40
|
import { purgeIndexScope } from './lib/purge'
|
|
26
41
|
import { refreshCoverageSnapshot } from './lib/coverage'
|
|
27
42
|
import { flattenSystemEntityIds } from '@open-mercato/shared/lib/entities/system-entities'
|
|
@@ -476,7 +491,7 @@ async function verifyAndRepairIndexCoverage(
|
|
|
476
491
|
})
|
|
477
492
|
}
|
|
478
493
|
} else {
|
|
479
|
-
await reindexEntity(em, {
|
|
494
|
+
const repairResult = await reindexEntity(em, {
|
|
480
495
|
entityType: options.entityType,
|
|
481
496
|
tenantId: options.tenantId,
|
|
482
497
|
organizationId: options.organizationId,
|
|
@@ -485,6 +500,7 @@ async function verifyAndRepairIndexCoverage(
|
|
|
485
500
|
emitVectorizeEvents: false,
|
|
486
501
|
resetCoverage: false,
|
|
487
502
|
})
|
|
503
|
+
warnIfReindexRefused(options.entityType, repairResult)
|
|
488
504
|
}
|
|
489
505
|
} catch (error) {
|
|
490
506
|
console.warn(
|
|
@@ -853,6 +869,7 @@ const reindex: ModuleCli = {
|
|
|
853
869
|
if (progressBar) {
|
|
854
870
|
(progressBar as ProgressBarHandle).complete()
|
|
855
871
|
}
|
|
872
|
+
warnIfReindexRefused(entity, partitionStats)
|
|
856
873
|
if (!useBar && groupedProgress) {
|
|
857
874
|
groupedProgress.onProgress(part, { processed: partitionStats.processed, total: partitionStats.total })
|
|
858
875
|
} else if (!useBar) {
|
|
@@ -999,6 +1016,7 @@ const reindex: ModuleCli = {
|
|
|
999
1016
|
if (progressBar) {
|
|
1000
1017
|
(progressBar as ProgressBarHandle).complete()
|
|
1001
1018
|
}
|
|
1019
|
+
warnIfReindexRefused(id, result)
|
|
1002
1020
|
if (!useBar && groupedProgress) {
|
|
1003
1021
|
groupedProgress.onProgress(part, { processed: result.processed, total: result.total })
|
|
1004
1022
|
} else if (!useBar) {
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
import { resolveQueryIndexSourceTableMetadata } from './subscriber-scope'
|
|
1
2
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
3
|
import { type Kysely, type Transaction, sql } from 'kysely'
|
|
3
|
-
import { resolveEntityTableName } from '@open-mercato/shared/lib/query/engine'
|
|
4
|
+
import { resolveEntityTableName as resolveFallbackEntityTableName } from '@open-mercato/shared/lib/query/engine'
|
|
4
5
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
5
6
|
|
|
7
|
+
function resolveEntityTableName(em: EntityManager, entity: string): string {
|
|
8
|
+
return resolveQueryIndexSourceTableMetadata(em, entity)?.table ?? resolveFallbackEntityTableName(em, entity)
|
|
9
|
+
}
|
|
10
|
+
|
|
6
11
|
const logger = createLogger('query_index').child({ component: 'coverage' })
|
|
7
12
|
|
|
8
13
|
type CoverageExecutor = Kysely<any> | Transaction<any>
|
|
@@ -446,6 +451,25 @@ export async function deleteCoverageForEntity(db: Kysely<any>, entityType: strin
|
|
|
446
451
|
.execute()
|
|
447
452
|
}
|
|
448
453
|
|
|
454
|
+
type CatalogueCoverageDatabase = {
|
|
455
|
+
entity_index_coverage: { entity_type: string; tenant_id: string | null; organization_id: string | null }
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Drop every coverage row of `entityType` outside the global scope (no tenant, and the
|
|
460
|
+
* organization placeholder or no organization). A declared platform-wide catalogue keeps its
|
|
461
|
+
* coverage there only; rows an earlier sweep wrote under the caller's scope are never
|
|
462
|
+
* refreshed again and would keep reporting stale counts.
|
|
463
|
+
*/
|
|
464
|
+
export async function deleteScopedCoverageForEntity(db: Kysely<CatalogueCoverageDatabase>, entityType: string): Promise<void> {
|
|
465
|
+
if (!entityType) return
|
|
466
|
+
await db
|
|
467
|
+
.deleteFrom('entity_index_coverage')
|
|
468
|
+
.where('entity_type', '=', entityType)
|
|
469
|
+
.where(sql<boolean>`(tenant_id is not null or (organization_id is not null and organization_id <> ${GLOBAL_ORGANIZATION_PLACEHOLDER}))`)
|
|
470
|
+
.execute()
|
|
471
|
+
}
|
|
472
|
+
|
|
449
473
|
async function deleteCoverageScope(db: Kysely<any>, scope: CoverageScope): Promise<void> {
|
|
450
474
|
const { entityType, tenantId, organizationId, withDeleted } = scope
|
|
451
475
|
if (!entityType) return
|
|
@@ -468,8 +492,8 @@ async function tableHasColumn(db: Kysely<any>, table: string, column: string): P
|
|
|
468
492
|
const exists = await db
|
|
469
493
|
.selectFrom('information_schema.columns' as any)
|
|
470
494
|
.select(sql<number>`1`.as('present'))
|
|
471
|
-
.where(sql<boolean>`table_schema = current_schema()`)
|
|
472
|
-
.where('table_name' as any, '=', table)
|
|
495
|
+
.where(table.includes('.') ? sql<boolean>`table_schema = ${table.split('.')[0]}` : sql<boolean>`table_schema = current_schema()`)
|
|
496
|
+
.where('table_name' as any, '=', table.split('.').pop())
|
|
473
497
|
.where('column_name' as any, '=', column)
|
|
474
498
|
.executeTakeFirst()
|
|
475
499
|
const present = !!exists
|
|
@@ -493,6 +517,8 @@ export type ColumnCheck = { table: string; column: string }
|
|
|
493
517
|
// subscribers hit an already-primed (or in-flight) cache instead of each doing their own
|
|
494
518
|
// per-table introspection round trip.
|
|
495
519
|
export async function primeColumnCache(db: Kysely<any>, checks: ColumnCheck[]): Promise<void> {
|
|
520
|
+
for (const check of checks.filter((entry) => typeof entry?.table === 'string' && entry.table.includes('.'))) await tableHasColumn(db, check.table, check.column)
|
|
521
|
+
checks = checks.filter((entry) => !(typeof entry?.table === 'string' && entry.table.includes('.')))
|
|
496
522
|
const missing: Array<{ table: string; column: string; key: string }> = []
|
|
497
523
|
const seen = new Set<string>()
|
|
498
524
|
for (const check of checks) {
|