@open-mercato/core 0.7.1-develop.7195.1.b5efd1d51a → 0.7.1-develop.7201.1.9bd6c88e3d

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.
Files changed (43) hide show
  1. package/dist/modules/auth/lib/setup-app.js +1 -0
  2. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  3. package/dist/modules/catalog/components/products/ProductUomSection.js +27 -22
  4. package/dist/modules/catalog/components/products/ProductUomSection.js.map +2 -2
  5. package/dist/modules/entities/lib/field-definitions.js +9 -0
  6. package/dist/modules/entities/lib/field-definitions.js.map +2 -2
  7. package/dist/modules/entities/lib/install-from-ce.js +1 -0
  8. package/dist/modules/entities/lib/install-from-ce.js.map +2 -2
  9. package/dist/modules/eudr/search.js +3 -5
  10. package/dist/modules/eudr/search.js.map +2 -2
  11. package/dist/modules/sales/components/documents/PaymentDialog.js +14 -11
  12. package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
  13. package/dist/modules/sales/lib/lineSnapshots.js +3 -0
  14. package/dist/modules/sales/lib/lineSnapshots.js.map +2 -2
  15. package/dist/modules/wms/components/backend/AdjustInventoryDialog.js +8 -6
  16. package/dist/modules/wms/components/backend/AdjustInventoryDialog.js.map +2 -2
  17. package/dist/modules/wms/search.js +4 -4
  18. package/dist/modules/wms/search.js.map +2 -2
  19. package/package.json +7 -7
  20. package/src/modules/auth/lib/setup-app.ts +6 -0
  21. package/src/modules/catalog/components/products/ProductUomSection.tsx +31 -21
  22. package/src/modules/entities/lib/field-definitions.ts +15 -0
  23. package/src/modules/entities/lib/install-from-ce.ts +1 -0
  24. package/src/modules/eudr/i18n/de.json +4 -1
  25. package/src/modules/eudr/i18n/en.json +4 -1
  26. package/src/modules/eudr/i18n/es.json +4 -1
  27. package/src/modules/eudr/i18n/ko.json +4 -1
  28. package/src/modules/eudr/i18n/pl.json +4 -1
  29. package/src/modules/eudr/search.ts +3 -5
  30. package/src/modules/sales/components/documents/PaymentDialog.tsx +18 -11
  31. package/src/modules/sales/i18n/de.json +1 -0
  32. package/src/modules/sales/i18n/en.json +1 -0
  33. package/src/modules/sales/i18n/es.json +1 -0
  34. package/src/modules/sales/i18n/ko.json +1 -0
  35. package/src/modules/sales/i18n/pl.json +1 -0
  36. package/src/modules/sales/lib/lineSnapshots.ts +22 -3
  37. package/src/modules/wms/components/backend/AdjustInventoryDialog.tsx +6 -5
  38. package/src/modules/wms/i18n/de.json +4 -0
  39. package/src/modules/wms/i18n/en.json +4 -0
  40. package/src/modules/wms/i18n/es.json +4 -0
  41. package/src/modules/wms/i18n/ko.json +4 -0
  42. package/src/modules/wms/i18n/pl.json +4 -0
  43. package/src/modules/wms/search.ts +4 -4
@@ -32,7 +32,8 @@ import {
32
32
  } from "@open-mercato/ui/primitives/select";
33
33
  import { StatusBadge } from "@open-mercato/ui/primitives/status-badge";
34
34
  import { Textarea } from "@open-mercato/ui/primitives/textarea";
35
- import { useT } from "@open-mercato/shared/lib/i18n/context";
35
+ import { useT, useLocale } from "@open-mercato/shared/lib/i18n/context";
36
+ import { parseLocaleNumber } from "@open-mercato/shared/lib/number";
36
37
  import { createLogger } from "@open-mercato/shared/lib/logger";
37
38
  import { buildInventoryMutationReferenceId } from "../../lib/inventoryMutationUi.js";
38
39
  import {
@@ -63,11 +64,10 @@ const EMPTY_FORM = {
63
64
  notes: "",
64
65
  serialNumber: ""
65
66
  };
66
- function parseDeltaInput(value) {
67
+ function parseDeltaInput(value, locale) {
67
68
  const trimmed = value.trim();
68
69
  if (!trimmed || trimmed === "-" || trimmed === "+") return null;
69
- const parsed = Number(trimmed);
70
- return Number.isFinite(parsed) ? parsed : null;
70
+ return parseLocaleNumber(trimmed, locale);
71
71
  }
72
72
  function AdjustInventoryDialog({
73
73
  open,
@@ -79,6 +79,7 @@ function AdjustInventoryDialog({
79
79
  initialLotId
80
80
  }) {
81
81
  const t = useT();
82
+ const locale = useLocale();
82
83
  const queryClient = useQueryClient();
83
84
  const formRef = React.useRef(null);
84
85
  const { runMutation, retryLastMutation } = useGuardedMutation({
@@ -645,7 +646,7 @@ function AdjustInventoryDialog({
645
646
  inputMode: "decimal",
646
647
  value: String(form.delta),
647
648
  onChange: (event) => {
648
- const parsed = parseDeltaInput(event.target.value);
649
+ const parsed = parseDeltaInput(event.target.value, locale);
649
650
  if (parsed == null) return;
650
651
  patchForm({ delta: parsed });
651
652
  },
@@ -750,6 +751,7 @@ function AdjustInventoryDialog({
750
751
  ) });
751
752
  }
752
753
  export {
753
- AdjustInventoryDialog
754
+ AdjustInventoryDialog,
755
+ parseDeltaInput
754
756
  };
755
757
  //# sourceMappingURL=AdjustInventoryDialog.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/wms/components/backend/AdjustInventoryDialog.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { Minus, Package, Plus } from 'lucide-react'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { flashMutationError } from '../../lib/flashMutationError'\nimport { ComboboxInput } from '@open-mercato/ui/backend/inputs/ComboboxInput'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { FormField } from '@open-mercato/ui/primitives/form-field'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { KbdShortcut } from '@open-mercato/ui/primitives/kbd'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { StatusBadge } from '@open-mercato/ui/primitives/status-badge'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { buildInventoryMutationReferenceId } from '../../lib/inventoryMutationUi'\nimport {\n BalanceLookupError,\n ensureLotIdForInventoryMutation,\n fetchBalanceOnHand,\n fetchVariantReorderPoint,\n findLotIdByNumber,\n InventoryLotMutationError,\n loadCatalogVariantOptions,\n loadLocationOptions,\n loadLotNumberOptions,\n loadWarehouseOptions,\n resolveCatalogVariantLabel,\n resolveLocationLabel,\n resolveLotNumberFromId,\n resolveWarehouseLabel,\n} from './inventoryMutationLoaders'\nimport type { useWmsInventoryMutationAccess } from './useWmsInventoryMutationAccess'\n\nconst logger = createLogger('wms')\n\nconst ADJUST_REASON_CODES = ['damaged', 'shrinkage', 'found', 'correction', 'other'] as const\n\ntype AdjustReasonCode = (typeof ADJUST_REASON_CODES)[number]\n\ntype AdjustFormValues = {\n catalogVariantId: string\n warehouseId: string\n locationId: string\n lotNumber: string\n delta: number\n reasonCode: AdjustReasonCode | ''\n notes: string\n serialNumber: string\n}\n\ntype AdjustInventoryDialogProps = {\n open: boolean\n onOpenChange: (open: boolean) => void\n access: ReturnType<typeof useWmsInventoryMutationAccess>\n initialCatalogVariantId?: string\n initialWarehouseId?: string\n initialLocationId?: string\n initialLotId?: string\n}\n\nconst EMPTY_FORM: AdjustFormValues = {\n catalogVariantId: '',\n warehouseId: '',\n locationId: '',\n lotNumber: '',\n delta: 1,\n reasonCode: '',\n notes: '',\n serialNumber: '',\n}\n\nfunction parseDeltaInput(value: string): number | null {\n const trimmed = value.trim()\n if (!trimmed || trimmed === '-' || trimmed === '+') return null\n const parsed = Number(trimmed)\n return Number.isFinite(parsed) ? parsed : null\n}\n\nexport function AdjustInventoryDialog({\n open,\n onOpenChange,\n access,\n initialCatalogVariantId,\n initialWarehouseId,\n initialLocationId,\n initialLotId,\n}: AdjustInventoryDialogProps) {\n const t = useT()\n const queryClient = useQueryClient()\n const formRef = React.useRef<HTMLFormElement>(null)\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: 'wms-inventory-adjust',\n })\n const mutationContext = React.useMemo(\n () => ({ retryLastMutation }),\n [retryLastMutation],\n )\n const adjustFormSchema = React.useMemo(\n () =>\n z.object({\n catalogVariantId: z.string().uuid(),\n warehouseId: z.string().uuid(),\n locationId: z.string().uuid(),\n lotNumber: z.string().trim().max(120).optional(),\n delta: z.coerce.number().refine((value) => value !== 0, {\n message: t(\n 'wms.backend.inventory.adjust.errors.deltaZero',\n 'Inventory delta must be non-zero.',\n ),\n }),\n reasonCode: z.enum(ADJUST_REASON_CODES),\n notes: z.string().trim().max(500).optional(),\n serialNumber: z.string().trim().max(120).optional(),\n }),\n [t],\n )\n const [submitting, setSubmitting] = React.useState(false)\n const [form, setForm] = React.useState<AdjustFormValues>(EMPTY_FORM)\n const [fieldErrors, setFieldErrors] = React.useState<Record<string, string>>({})\n const [onHand, setOnHand] = React.useState<number | null>(null)\n const [previewError, setPreviewError] = React.useState<string | null>(null)\n const [reorderPoint, setReorderPoint] = React.useState(0)\n const [loadingPreview, setLoadingPreview] = React.useState(false)\n const [optionLabelByValue, setOptionLabelByValue] = React.useState<Record<string, string>>({})\n\n const registerOptionLabels = React.useCallback(\n (options: Array<{ value: string; label: string }>) => {\n setOptionLabelByValue((current) => {\n let changed = false\n const next = { ...current }\n for (const option of options) {\n const value = option.value.trim()\n const label = option.label.trim()\n if (!value || !label || next[value] === label) continue\n next[value] = label\n changed = true\n }\n return changed ? next : current\n })\n },\n [],\n )\n\n const resolveOptionLabel = React.useCallback(\n (value: string) => optionLabelByValue[value] ?? value,\n [optionLabelByValue],\n )\n const optionLabelByValueRef = React.useRef(optionLabelByValue)\n optionLabelByValueRef.current = optionLabelByValue\n\n const reasonLabel = React.useCallback(\n (code: AdjustReasonCode) => {\n const fallbacks: Record<AdjustReasonCode, string> = {\n damaged: 'Damaged',\n shrinkage: 'Shrinkage',\n found: 'Found stock',\n correction: 'Correction',\n other: 'Other',\n }\n return t(`wms.backend.inventory.adjust.reasons.${code}`, fallbacks[code])\n },\n [t],\n )\n\n const resetDialog = React.useCallback(() => {\n setForm(EMPTY_FORM)\n setFieldErrors({})\n setOnHand(null)\n setPreviewError(null)\n setReorderPoint(0)\n setLoadingPreview(false)\n setSubmitting(false)\n setOptionLabelByValue({})\n }, [])\n\n const closeDialog = React.useCallback(() => {\n onOpenChange(false)\n resetDialog()\n }, [onOpenChange, resetDialog])\n\n const patchForm = React.useCallback((patch: Partial<AdjustFormValues>) => {\n setForm((current) => ({ ...current, ...patch }))\n setFieldErrors({})\n }, [])\n\n React.useEffect(() => {\n if (!open) return\n const catalogVariantId = initialCatalogVariantId?.trim()\n const warehouseId = initialWarehouseId?.trim()\n const locationId = initialLocationId?.trim()\n const lotId = initialLotId?.trim()\n if (!catalogVariantId && !warehouseId && !locationId && !lotId) return\n setForm((current) => ({\n ...current,\n ...(catalogVariantId ? { catalogVariantId } : {}),\n ...(warehouseId ? { warehouseId, locationId: locationId ?? '' } : {}),\n ...(locationId ? { locationId } : {}),\n }))\n if (!lotId) return\n let cancelled = false\n void resolveLotNumberFromId(lotId).then((lotNumber) => {\n if (cancelled || !lotNumber) return\n setForm((current) => ({ ...current, lotNumber }))\n registerOptionLabels([{ value: lotNumber, label: lotNumber }])\n })\n return () => {\n cancelled = true\n }\n }, [\n initialCatalogVariantId,\n initialLocationId,\n initialLotId,\n initialWarehouseId,\n open,\n registerOptionLabels,\n ])\n\n React.useEffect(() => {\n if (!open) return\n let cancelled = false\n\n const ensureLabel = async (value: string, resolve: (id: string) => Promise<string | null>) => {\n const id = value.trim()\n if (!id || optionLabelByValueRef.current[id]) return\n const label = await resolve(id)\n if (cancelled || !label) return\n registerOptionLabels([{ value: id, label }])\n }\n\n void Promise.all([\n ensureLabel(form.catalogVariantId, resolveCatalogVariantLabel),\n ensureLabel(form.warehouseId, resolveWarehouseLabel),\n ensureLabel(form.locationId, resolveLocationLabel),\n ])\n\n return () => {\n cancelled = true\n }\n }, [\n form.catalogVariantId,\n form.locationId,\n form.warehouseId,\n open,\n registerOptionLabels,\n ])\n\n React.useEffect(() => {\n if (!open) return\n const variantId = form.catalogVariantId.trim()\n if (!variantId) {\n setReorderPoint(0)\n return\n }\n let cancelled = false\n void fetchVariantReorderPoint(variantId).then((value) => {\n if (!cancelled) setReorderPoint(value)\n })\n return () => {\n cancelled = true\n }\n }, [form.catalogVariantId, open])\n\n const previewContextReady = Boolean(\n form.catalogVariantId.trim() &&\n form.warehouseId.trim() &&\n form.locationId.trim(),\n )\n\n React.useEffect(() => {\n if (!open) return\n const warehouseId = form.warehouseId.trim()\n const locationId = form.locationId.trim()\n const catalogVariantId = form.catalogVariantId.trim()\n const lotNumber = form.lotNumber.trim()\n if (!warehouseId || !locationId || !catalogVariantId) {\n setOnHand(null)\n setPreviewError(null)\n setLoadingPreview(false)\n return\n }\n let cancelled = false\n setLoadingPreview(true)\n setPreviewError(null)\n void (async () => {\n try {\n const lotId = lotNumber\n ? await findLotIdByNumber(catalogVariantId, lotNumber)\n : null\n if (cancelled) return\n const value = await fetchBalanceOnHand({\n warehouseId,\n locationId,\n catalogVariantId,\n lotId,\n })\n if (!cancelled) {\n setOnHand(value)\n setPreviewError(null)\n }\n } catch (error: unknown) {\n if (cancelled) return\n setOnHand(null)\n if (error instanceof BalanceLookupError) {\n setPreviewError(\n t(\n 'wms.backend.inventory.adjust.errors.previewBalance',\n 'Failed to load balance preview.',\n ),\n )\n return\n }\n logger.error('fetchBalanceOnHand failed', { component: 'AdjustInventoryDialog', err: error })\n setPreviewError(\n t(\n 'wms.backend.inventory.adjust.errors.previewBalance',\n 'Failed to load balance preview.',\n ),\n )\n } finally {\n if (!cancelled) setLoadingPreview(false)\n }\n })()\n return () => {\n cancelled = true\n }\n }, [\n form.catalogVariantId,\n form.locationId,\n form.lotNumber,\n form.warehouseId,\n open,\n t,\n ])\n\n const projectedOnHand =\n onHand != null && form.delta !== 0 ? onHand + form.delta : null\n const showBelowReorder =\n projectedOnHand != null && reorderPoint > 0 && projectedOnHand <= reorderPoint\n\n const handleSubmit = React.useCallback(\n async (event?: React.FormEvent) => {\n event?.preventDefault()\n const parsed = adjustFormSchema.safeParse({\n ...form,\n lotNumber: form.lotNumber.trim() || undefined,\n notes: form.notes.trim() || undefined,\n serialNumber: form.serialNumber.trim() || undefined,\n })\n if (!parsed.success) {\n const nextErrors: Record<string, string> = {}\n for (const issue of parsed.error.issues) {\n const key = String(issue.path[0] ?? 'form')\n if (!nextErrors[key]) nextErrors[key] = issue.message\n }\n setFieldErrors(nextErrors)\n return\n }\n\n if (!access.scopeReady || !access.organizationId || !access.tenantId || !access.userId) {\n flash(\n t(\n 'wms.backend.inventory.mutations.errors.scope',\n 'Select an organization and sign in before posting inventory changes.',\n ),\n 'error',\n )\n return\n }\n\n setSubmitting(true)\n try {\n // Persist the stable reason code (not a locale-rendered label) so activity\n // feeds can re-translate for the viewer's language later.\n const reason = parsed.data.reasonCode\n const notes = parsed.data.notes?.trim()\n const lotNumber = parsed.data.lotNumber?.trim()\n let lotId: string | undefined\n if (lotNumber) {\n try {\n lotId = await ensureLotIdForInventoryMutation({\n catalogVariantId: parsed.data.catalogVariantId,\n lotNumber,\n organizationId: access.organizationId,\n tenantId: access.tenantId,\n })\n } catch (error: unknown) {\n const message =\n error instanceof InventoryLotMutationError\n ? error.message\n : t(\n 'wms.backend.inventory.adjust.errors.lot',\n 'Failed to resolve inventory lot.',\n )\n setFieldErrors({ lotNumber: message })\n return\n }\n }\n const payload: Record<string, unknown> = {\n organizationId: access.organizationId,\n tenantId: access.tenantId,\n warehouseId: parsed.data.warehouseId,\n locationId: parsed.data.locationId,\n catalogVariantId: parsed.data.catalogVariantId,\n delta: parsed.data.delta,\n reason,\n reasonCode: parsed.data.reasonCode,\n referenceType: 'manual',\n referenceId: buildInventoryMutationReferenceId(),\n performedBy: access.userId,\n }\n if (lotId) payload.lotId = lotId\n const serial = parsed.data.serialNumber?.trim()\n if (serial) payload.serialNumber = serial\n if (notes) payload.metadata = { notes }\n\n await runMutation({\n operation: async () => {\n const call = await apiCall<{ ok?: boolean; movementId?: string }>(\n '/api/wms/inventory/adjust',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n )\n if (!call.ok) {\n await raiseCrudError(\n call.response,\n t('wms.backend.inventory.adjust.errors.submit', 'Failed to adjust inventory.'),\n )\n }\n return call.result ?? {}\n },\n context: mutationContext,\n mutationPayload: payload,\n })\n\n flash(t('wms.backend.inventory.adjust.flash.success', 'Inventory adjusted'), 'success')\n await queryClient.invalidateQueries({ queryKey: ['wms-inventory-console'] })\n await queryClient.invalidateQueries({ queryKey: ['wms-sku-detail'] })\n closeDialog()\n } catch (error) {\n flashMutationError(error, t('wms.backend.inventory.adjust.errors.submit', 'Failed to adjust inventory.'), t)\n } finally {\n setSubmitting(false)\n }\n },\n [\n access,\n adjustFormSchema,\n closeDialog,\n form,\n mutationContext,\n queryClient,\n runMutation,\n t,\n ],\n )\n\n const handleDialogKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n closeDialog()\n return\n }\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n if (!submitting) void handleSubmit()\n }\n },\n [closeDialog, handleSubmit, submitting],\n )\n\n const adjustDelta = React.useCallback((step: -1 | 1) => {\n setForm((current) => {\n const next = current.delta + step\n return { ...current, delta: next === 0 ? step : next }\n })\n setFieldErrors({})\n }, [])\n\n return (\n <Dialog open={open} onOpenChange={(next) => (next ? onOpenChange(true) : closeDialog())}>\n <DialogContent\n className=\"max-w-lg gap-0 overflow-hidden p-0\"\n onKeyDown={handleDialogKeyDown}\n >\n <div className=\"border-b px-6 py-4 pr-12\">\n <DialogHeader className=\"space-y-1 text-left\">\n <DialogTitle>\n {t('wms.backend.inventory.adjust.dialog.title', 'Adjust inventory')}\n </DialogTitle>\n <DialogDescription>\n {t(\n 'wms.backend.inventory.adjust.dialog.description',\n 'Append a signed delta to the ledger',\n )}\n </DialogDescription>\n </DialogHeader>\n </div>\n\n <form ref={formRef} onSubmit={handleSubmit} className=\"flex min-h-0 flex-1 flex-col\">\n <div className=\"flex flex-col gap-5 overflow-y-auto px-6 py-6\">\n <FormField\n label={t('wms.backend.inventory.adjust.form.variant', 'Variant')}\n required\n error={fieldErrors.catalogVariantId}\n >\n <div className=\"relative [&_input]:pl-9\">\n <Package\n className=\"pointer-events-none absolute left-3 top-1/2 z-10 size-4 -translate-y-1/2 text-muted-foreground\"\n aria-hidden=\"true\"\n />\n <ComboboxInput\n value={form.catalogVariantId}\n onChange={(next) => {\n patchForm({\n catalogVariantId: next.trim(),\n lotNumber: '',\n })\n }}\n loadSuggestions={async (query) => {\n const options = await loadCatalogVariantOptions(query)\n registerOptionLabels(options)\n return options.map((option) => ({\n value: option.value,\n label: option.label,\n description: option.description,\n }))\n }}\n resolveLabel={resolveOptionLabel}\n placeholder={t(\n 'wms.backend.inventory.adjust.form.variantPlaceholder',\n 'Search variant or SKU',\n )}\n allowCustomValues={false}\n disabled={submitting}\n />\n </div>\n </FormField>\n\n <div className=\"grid gap-5 sm:grid-cols-2\">\n <FormField\n label={t('wms.backend.inventory.adjust.form.warehouse', 'Warehouse')}\n required\n error={fieldErrors.warehouseId}\n >\n <ComboboxInput\n value={form.warehouseId}\n onChange={(next) => {\n patchForm({\n warehouseId: next.trim(),\n locationId: '',\n })\n }}\n loadSuggestions={async (query) => {\n const options = await loadWarehouseOptions(query)\n registerOptionLabels(options)\n return options.map((option) => ({\n value: option.value,\n label: option.label,\n }))\n }}\n resolveLabel={resolveOptionLabel}\n placeholder={t(\n 'wms.backend.inventory.adjust.form.warehousePlaceholder',\n 'Select warehouse',\n )}\n allowCustomValues={false}\n disabled={submitting}\n />\n </FormField>\n\n <FormField\n label={t('wms.backend.inventory.adjust.form.location', 'Location')}\n required\n error={fieldErrors.locationId}\n >\n <ComboboxInput\n value={form.locationId}\n onChange={(next) => patchForm({ locationId: next.trim() })}\n loadSuggestions={async (query) => {\n const options = await loadLocationOptions(form.warehouseId, query)\n registerOptionLabels(options)\n return options.map((option) => ({\n value: option.value,\n label: option.label,\n }))\n }}\n resolveLabel={resolveOptionLabel}\n placeholder={t(\n 'wms.backend.inventory.adjust.form.locationPlaceholder',\n 'Select location',\n )}\n allowCustomValues={false}\n disabled={submitting || !form.warehouseId}\n />\n </FormField>\n </div>\n\n <FormField\n label={t('wms.backend.inventory.adjust.form.lot', 'Lot')}\n error={fieldErrors.lotNumber}\n >\n <ComboboxInput\n value={form.lotNumber}\n onChange={(next) => patchForm({ lotNumber: next.trim() })}\n loadSuggestions={async (query) => {\n const options = await loadLotNumberOptions(form.catalogVariantId, query)\n registerOptionLabels(options)\n return options.map((option) => ({\n value: option.value,\n label: option.label,\n }))\n }}\n resolveLabel={resolveOptionLabel}\n placeholder={t(\n 'wms.backend.inventory.adjust.form.lotPlaceholder',\n 'Select lot (optional)',\n )}\n allowCustomValues\n disabled={submitting || !form.catalogVariantId}\n />\n </FormField>\n\n <FormField\n label={t('wms.backend.inventory.adjust.form.serial', 'Serial number')}\n error={fieldErrors.serialNumber}\n >\n <Input\n value={form.serialNumber}\n onChange={(event) => patchForm({ serialNumber: event.target.value })}\n placeholder={t(\n 'wms.backend.inventory.adjust.form.serialPlaceholder',\n 'Optional \u2014 for serial-tracked variants',\n )}\n disabled={submitting}\n />\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {t(\n 'wms.backend.inventory.adjust.form.serialHelp',\n 'Use when the variant profile tracks serials.',\n )}\n </p>\n </FormField>\n\n <FormField\n label={t('wms.backend.inventory.adjust.form.delta', 'Adjustment')}\n required\n error={fieldErrors.delta}\n >\n <div className=\"flex w-32 items-center gap-2 rounded-md border bg-background p-2 shadow-xs\">\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={t('wms.backend.inventory.adjust.form.decrease', 'Decrease quantity')}\n onClick={() => adjustDelta(-1)}\n disabled={submitting}\n >\n <Minus className=\"size-4\" />\n </IconButton>\n <Input\n type=\"text\"\n inputMode=\"decimal\"\n value={String(form.delta)}\n onChange={(event) => {\n const parsed = parseDeltaInput(event.target.value)\n if (parsed == null) return\n patchForm({ delta: parsed })\n }}\n className=\"h-8 w-auto min-w-0 flex-1 border-0 bg-transparent p-0 shadow-none focus-visible:ring-0\"\n inputClassName=\"text-center [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none\"\n disabled={submitting}\n />\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={t('wms.backend.inventory.adjust.form.increase', 'Increase quantity')}\n onClick={() => adjustDelta(1)}\n disabled={submitting}\n >\n <Plus className=\"size-4\" />\n </IconButton>\n </div>\n </FormField>\n\n <FormField\n label={t('wms.backend.inventory.adjust.form.reason', 'Reason')}\n required\n error={fieldErrors.reasonCode}\n >\n <Select\n value={form.reasonCode || undefined}\n onValueChange={(next) =>\n patchForm({ reasonCode: next as AdjustReasonCode })\n }\n disabled={submitting}\n >\n <SelectTrigger>\n <SelectValue\n placeholder={t(\n 'wms.backend.inventory.adjust.form.reasonPlaceholder',\n 'Select reason',\n )}\n />\n </SelectTrigger>\n <SelectContent>\n {ADJUST_REASON_CODES.map((code) => (\n <SelectItem key={code} value={code}>\n {reasonLabel(code)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </FormField>\n\n <FormField label={t('wms.backend.inventory.adjust.form.notes', 'Notes')}>\n <Textarea\n value={form.notes}\n onChange={(event) => patchForm({ notes: event.target.value })}\n placeholder={t(\n 'wms.backend.inventory.adjust.form.notesPlaceholder',\n 'Optional \u2014 context for auditors',\n )}\n rows={3}\n disabled={submitting}\n />\n </FormField>\n\n {previewContextReady ? (\n <div className=\"rounded-lg border bg-muted/40 px-4 py-3.5\">\n <p className=\"text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {t('wms.backend.inventory.adjust.preview.title', 'Balance preview')}\n </p>\n <div className=\"mt-2 flex items-center justify-between gap-3\">\n {previewError ? (\n <p className=\"text-sm text-status-warning-fg\">{previewError}</p>\n ) : loadingPreview && onHand == null ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('wms.backend.inventory.adjust.preview.loading', 'Refreshing balance\u2026')}\n </p>\n ) : onHand != null && projectedOnHand != null ? (\n <p className=\"text-sm font-semibold tabular-nums text-foreground\">\n {t('wms.backend.inventory.adjust.preview.onHandLabel', 'On hand')}{' '}\n {onHand}\n {' \u2192 '}\n {projectedOnHand}\n </p>\n ) : onHand != null ? (\n <p className=\"text-sm font-semibold tabular-nums text-foreground\">\n {t('wms.backend.inventory.adjust.preview.onHandLabel', 'On hand')}{' '}\n {onHand}\n </p>\n ) : null}\n {showBelowReorder ? (\n <StatusBadge variant=\"warning\">\n {t(\n 'wms.backend.inventory.adjust.preview.belowReorder',\n 'Below reorder',\n )}\n </StatusBadge>\n ) : null}\n </div>\n {loadingPreview && onHand != null ? (\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {t('wms.backend.inventory.adjust.preview.loading', 'Refreshing balance\u2026')}\n </p>\n ) : null}\n </div>\n ) : null}\n </div>\n\n <DialogFooter bordered={false} className=\"border-t px-6 py-4 sm:justify-between\">\n <p className=\"hidden text-xs text-muted-foreground sm:inline-flex sm:items-center sm:gap-1.5\">\n <KbdShortcut keys={['\u2318', 'Enter']} />\n <span>/</span>\n <KbdShortcut keys={['Ctrl', 'Enter']} />\n <span>{t('wms.backend.inventory.adjust.dialog.shortcutSave', 'to save')}</span>\n </p>\n <div className=\"flex w-full flex-col-reverse gap-2 sm:w-auto sm:flex-row\">\n <Button type=\"button\" variant=\"outline\" onClick={closeDialog} disabled={submitting}>\n {t('common.cancel', 'Cancel')}\n </Button>\n <Button type=\"submit\" disabled={submitting}>\n {t('wms.backend.inventory.adjust.dialog.submit', 'Save adjustment')}\n </Button>\n </div>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { Minus, Package, Plus } from 'lucide-react'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { flashMutationError } from '../../lib/flashMutationError'\nimport { ComboboxInput } from '@open-mercato/ui/backend/inputs/ComboboxInput'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { FormField } from '@open-mercato/ui/primitives/form-field'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { KbdShortcut } from '@open-mercato/ui/primitives/kbd'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { StatusBadge } from '@open-mercato/ui/primitives/status-badge'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'\nimport { parseLocaleNumber } from '@open-mercato/shared/lib/number'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { buildInventoryMutationReferenceId } from '../../lib/inventoryMutationUi'\nimport {\n BalanceLookupError,\n ensureLotIdForInventoryMutation,\n fetchBalanceOnHand,\n fetchVariantReorderPoint,\n findLotIdByNumber,\n InventoryLotMutationError,\n loadCatalogVariantOptions,\n loadLocationOptions,\n loadLotNumberOptions,\n loadWarehouseOptions,\n resolveCatalogVariantLabel,\n resolveLocationLabel,\n resolveLotNumberFromId,\n resolveWarehouseLabel,\n} from './inventoryMutationLoaders'\nimport type { useWmsInventoryMutationAccess } from './useWmsInventoryMutationAccess'\n\nconst logger = createLogger('wms')\n\nconst ADJUST_REASON_CODES = ['damaged', 'shrinkage', 'found', 'correction', 'other'] as const\n\ntype AdjustReasonCode = (typeof ADJUST_REASON_CODES)[number]\n\ntype AdjustFormValues = {\n catalogVariantId: string\n warehouseId: string\n locationId: string\n lotNumber: string\n delta: number\n reasonCode: AdjustReasonCode | ''\n notes: string\n serialNumber: string\n}\n\ntype AdjustInventoryDialogProps = {\n open: boolean\n onOpenChange: (open: boolean) => void\n access: ReturnType<typeof useWmsInventoryMutationAccess>\n initialCatalogVariantId?: string\n initialWarehouseId?: string\n initialLocationId?: string\n initialLotId?: string\n}\n\nconst EMPTY_FORM: AdjustFormValues = {\n catalogVariantId: '',\n warehouseId: '',\n locationId: '',\n lotNumber: '',\n delta: 1,\n reasonCode: '',\n notes: '',\n serialNumber: '',\n}\n\nexport function parseDeltaInput(value: string, locale?: string): number | null {\n const trimmed = value.trim()\n if (!trimmed || trimmed === '-' || trimmed === '+') return null\n return parseLocaleNumber(trimmed, locale)\n}\n\nexport function AdjustInventoryDialog({\n open,\n onOpenChange,\n access,\n initialCatalogVariantId,\n initialWarehouseId,\n initialLocationId,\n initialLotId,\n}: AdjustInventoryDialogProps) {\n const t = useT()\n const locale = useLocale()\n const queryClient = useQueryClient()\n const formRef = React.useRef<HTMLFormElement>(null)\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: 'wms-inventory-adjust',\n })\n const mutationContext = React.useMemo(\n () => ({ retryLastMutation }),\n [retryLastMutation],\n )\n const adjustFormSchema = React.useMemo(\n () =>\n z.object({\n catalogVariantId: z.string().uuid(),\n warehouseId: z.string().uuid(),\n locationId: z.string().uuid(),\n lotNumber: z.string().trim().max(120).optional(),\n delta: z.coerce.number().refine((value) => value !== 0, {\n message: t(\n 'wms.backend.inventory.adjust.errors.deltaZero',\n 'Inventory delta must be non-zero.',\n ),\n }),\n reasonCode: z.enum(ADJUST_REASON_CODES),\n notes: z.string().trim().max(500).optional(),\n serialNumber: z.string().trim().max(120).optional(),\n }),\n [t],\n )\n const [submitting, setSubmitting] = React.useState(false)\n const [form, setForm] = React.useState<AdjustFormValues>(EMPTY_FORM)\n const [fieldErrors, setFieldErrors] = React.useState<Record<string, string>>({})\n const [onHand, setOnHand] = React.useState<number | null>(null)\n const [previewError, setPreviewError] = React.useState<string | null>(null)\n const [reorderPoint, setReorderPoint] = React.useState(0)\n const [loadingPreview, setLoadingPreview] = React.useState(false)\n const [optionLabelByValue, setOptionLabelByValue] = React.useState<Record<string, string>>({})\n\n const registerOptionLabels = React.useCallback(\n (options: Array<{ value: string; label: string }>) => {\n setOptionLabelByValue((current) => {\n let changed = false\n const next = { ...current }\n for (const option of options) {\n const value = option.value.trim()\n const label = option.label.trim()\n if (!value || !label || next[value] === label) continue\n next[value] = label\n changed = true\n }\n return changed ? next : current\n })\n },\n [],\n )\n\n const resolveOptionLabel = React.useCallback(\n (value: string) => optionLabelByValue[value] ?? value,\n [optionLabelByValue],\n )\n const optionLabelByValueRef = React.useRef(optionLabelByValue)\n optionLabelByValueRef.current = optionLabelByValue\n\n const reasonLabel = React.useCallback(\n (code: AdjustReasonCode) => {\n const fallbacks: Record<AdjustReasonCode, string> = {\n damaged: 'Damaged',\n shrinkage: 'Shrinkage',\n found: 'Found stock',\n correction: 'Correction',\n other: 'Other',\n }\n return t(`wms.backend.inventory.adjust.reasons.${code}`, fallbacks[code])\n },\n [t],\n )\n\n const resetDialog = React.useCallback(() => {\n setForm(EMPTY_FORM)\n setFieldErrors({})\n setOnHand(null)\n setPreviewError(null)\n setReorderPoint(0)\n setLoadingPreview(false)\n setSubmitting(false)\n setOptionLabelByValue({})\n }, [])\n\n const closeDialog = React.useCallback(() => {\n onOpenChange(false)\n resetDialog()\n }, [onOpenChange, resetDialog])\n\n const patchForm = React.useCallback((patch: Partial<AdjustFormValues>) => {\n setForm((current) => ({ ...current, ...patch }))\n setFieldErrors({})\n }, [])\n\n React.useEffect(() => {\n if (!open) return\n const catalogVariantId = initialCatalogVariantId?.trim()\n const warehouseId = initialWarehouseId?.trim()\n const locationId = initialLocationId?.trim()\n const lotId = initialLotId?.trim()\n if (!catalogVariantId && !warehouseId && !locationId && !lotId) return\n setForm((current) => ({\n ...current,\n ...(catalogVariantId ? { catalogVariantId } : {}),\n ...(warehouseId ? { warehouseId, locationId: locationId ?? '' } : {}),\n ...(locationId ? { locationId } : {}),\n }))\n if (!lotId) return\n let cancelled = false\n void resolveLotNumberFromId(lotId).then((lotNumber) => {\n if (cancelled || !lotNumber) return\n setForm((current) => ({ ...current, lotNumber }))\n registerOptionLabels([{ value: lotNumber, label: lotNumber }])\n })\n return () => {\n cancelled = true\n }\n }, [\n initialCatalogVariantId,\n initialLocationId,\n initialLotId,\n initialWarehouseId,\n open,\n registerOptionLabels,\n ])\n\n React.useEffect(() => {\n if (!open) return\n let cancelled = false\n\n const ensureLabel = async (value: string, resolve: (id: string) => Promise<string | null>) => {\n const id = value.trim()\n if (!id || optionLabelByValueRef.current[id]) return\n const label = await resolve(id)\n if (cancelled || !label) return\n registerOptionLabels([{ value: id, label }])\n }\n\n void Promise.all([\n ensureLabel(form.catalogVariantId, resolveCatalogVariantLabel),\n ensureLabel(form.warehouseId, resolveWarehouseLabel),\n ensureLabel(form.locationId, resolveLocationLabel),\n ])\n\n return () => {\n cancelled = true\n }\n }, [\n form.catalogVariantId,\n form.locationId,\n form.warehouseId,\n open,\n registerOptionLabels,\n ])\n\n React.useEffect(() => {\n if (!open) return\n const variantId = form.catalogVariantId.trim()\n if (!variantId) {\n setReorderPoint(0)\n return\n }\n let cancelled = false\n void fetchVariantReorderPoint(variantId).then((value) => {\n if (!cancelled) setReorderPoint(value)\n })\n return () => {\n cancelled = true\n }\n }, [form.catalogVariantId, open])\n\n const previewContextReady = Boolean(\n form.catalogVariantId.trim() &&\n form.warehouseId.trim() &&\n form.locationId.trim(),\n )\n\n React.useEffect(() => {\n if (!open) return\n const warehouseId = form.warehouseId.trim()\n const locationId = form.locationId.trim()\n const catalogVariantId = form.catalogVariantId.trim()\n const lotNumber = form.lotNumber.trim()\n if (!warehouseId || !locationId || !catalogVariantId) {\n setOnHand(null)\n setPreviewError(null)\n setLoadingPreview(false)\n return\n }\n let cancelled = false\n setLoadingPreview(true)\n setPreviewError(null)\n void (async () => {\n try {\n const lotId = lotNumber\n ? await findLotIdByNumber(catalogVariantId, lotNumber)\n : null\n if (cancelled) return\n const value = await fetchBalanceOnHand({\n warehouseId,\n locationId,\n catalogVariantId,\n lotId,\n })\n if (!cancelled) {\n setOnHand(value)\n setPreviewError(null)\n }\n } catch (error: unknown) {\n if (cancelled) return\n setOnHand(null)\n if (error instanceof BalanceLookupError) {\n setPreviewError(\n t(\n 'wms.backend.inventory.adjust.errors.previewBalance',\n 'Failed to load balance preview.',\n ),\n )\n return\n }\n logger.error('fetchBalanceOnHand failed', { component: 'AdjustInventoryDialog', err: error })\n setPreviewError(\n t(\n 'wms.backend.inventory.adjust.errors.previewBalance',\n 'Failed to load balance preview.',\n ),\n )\n } finally {\n if (!cancelled) setLoadingPreview(false)\n }\n })()\n return () => {\n cancelled = true\n }\n }, [\n form.catalogVariantId,\n form.locationId,\n form.lotNumber,\n form.warehouseId,\n open,\n t,\n ])\n\n const projectedOnHand =\n onHand != null && form.delta !== 0 ? onHand + form.delta : null\n const showBelowReorder =\n projectedOnHand != null && reorderPoint > 0 && projectedOnHand <= reorderPoint\n\n const handleSubmit = React.useCallback(\n async (event?: React.FormEvent) => {\n event?.preventDefault()\n const parsed = adjustFormSchema.safeParse({\n ...form,\n lotNumber: form.lotNumber.trim() || undefined,\n notes: form.notes.trim() || undefined,\n serialNumber: form.serialNumber.trim() || undefined,\n })\n if (!parsed.success) {\n const nextErrors: Record<string, string> = {}\n for (const issue of parsed.error.issues) {\n const key = String(issue.path[0] ?? 'form')\n if (!nextErrors[key]) nextErrors[key] = issue.message\n }\n setFieldErrors(nextErrors)\n return\n }\n\n if (!access.scopeReady || !access.organizationId || !access.tenantId || !access.userId) {\n flash(\n t(\n 'wms.backend.inventory.mutations.errors.scope',\n 'Select an organization and sign in before posting inventory changes.',\n ),\n 'error',\n )\n return\n }\n\n setSubmitting(true)\n try {\n // Persist the stable reason code (not a locale-rendered label) so activity\n // feeds can re-translate for the viewer's language later.\n const reason = parsed.data.reasonCode\n const notes = parsed.data.notes?.trim()\n const lotNumber = parsed.data.lotNumber?.trim()\n let lotId: string | undefined\n if (lotNumber) {\n try {\n lotId = await ensureLotIdForInventoryMutation({\n catalogVariantId: parsed.data.catalogVariantId,\n lotNumber,\n organizationId: access.organizationId,\n tenantId: access.tenantId,\n })\n } catch (error: unknown) {\n const message =\n error instanceof InventoryLotMutationError\n ? error.message\n : t(\n 'wms.backend.inventory.adjust.errors.lot',\n 'Failed to resolve inventory lot.',\n )\n setFieldErrors({ lotNumber: message })\n return\n }\n }\n const payload: Record<string, unknown> = {\n organizationId: access.organizationId,\n tenantId: access.tenantId,\n warehouseId: parsed.data.warehouseId,\n locationId: parsed.data.locationId,\n catalogVariantId: parsed.data.catalogVariantId,\n delta: parsed.data.delta,\n reason,\n reasonCode: parsed.data.reasonCode,\n referenceType: 'manual',\n referenceId: buildInventoryMutationReferenceId(),\n performedBy: access.userId,\n }\n if (lotId) payload.lotId = lotId\n const serial = parsed.data.serialNumber?.trim()\n if (serial) payload.serialNumber = serial\n if (notes) payload.metadata = { notes }\n\n await runMutation({\n operation: async () => {\n const call = await apiCall<{ ok?: boolean; movementId?: string }>(\n '/api/wms/inventory/adjust',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n )\n if (!call.ok) {\n await raiseCrudError(\n call.response,\n t('wms.backend.inventory.adjust.errors.submit', 'Failed to adjust inventory.'),\n )\n }\n return call.result ?? {}\n },\n context: mutationContext,\n mutationPayload: payload,\n })\n\n flash(t('wms.backend.inventory.adjust.flash.success', 'Inventory adjusted'), 'success')\n await queryClient.invalidateQueries({ queryKey: ['wms-inventory-console'] })\n await queryClient.invalidateQueries({ queryKey: ['wms-sku-detail'] })\n closeDialog()\n } catch (error) {\n flashMutationError(error, t('wms.backend.inventory.adjust.errors.submit', 'Failed to adjust inventory.'), t)\n } finally {\n setSubmitting(false)\n }\n },\n [\n access,\n adjustFormSchema,\n closeDialog,\n form,\n mutationContext,\n queryClient,\n runMutation,\n t,\n ],\n )\n\n const handleDialogKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n closeDialog()\n return\n }\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n if (!submitting) void handleSubmit()\n }\n },\n [closeDialog, handleSubmit, submitting],\n )\n\n const adjustDelta = React.useCallback((step: -1 | 1) => {\n setForm((current) => {\n const next = current.delta + step\n return { ...current, delta: next === 0 ? step : next }\n })\n setFieldErrors({})\n }, [])\n\n return (\n <Dialog open={open} onOpenChange={(next) => (next ? onOpenChange(true) : closeDialog())}>\n <DialogContent\n className=\"max-w-lg gap-0 overflow-hidden p-0\"\n onKeyDown={handleDialogKeyDown}\n >\n <div className=\"border-b px-6 py-4 pr-12\">\n <DialogHeader className=\"space-y-1 text-left\">\n <DialogTitle>\n {t('wms.backend.inventory.adjust.dialog.title', 'Adjust inventory')}\n </DialogTitle>\n <DialogDescription>\n {t(\n 'wms.backend.inventory.adjust.dialog.description',\n 'Append a signed delta to the ledger',\n )}\n </DialogDescription>\n </DialogHeader>\n </div>\n\n <form ref={formRef} onSubmit={handleSubmit} className=\"flex min-h-0 flex-1 flex-col\">\n <div className=\"flex flex-col gap-5 overflow-y-auto px-6 py-6\">\n <FormField\n label={t('wms.backend.inventory.adjust.form.variant', 'Variant')}\n required\n error={fieldErrors.catalogVariantId}\n >\n <div className=\"relative [&_input]:pl-9\">\n <Package\n className=\"pointer-events-none absolute left-3 top-1/2 z-10 size-4 -translate-y-1/2 text-muted-foreground\"\n aria-hidden=\"true\"\n />\n <ComboboxInput\n value={form.catalogVariantId}\n onChange={(next) => {\n patchForm({\n catalogVariantId: next.trim(),\n lotNumber: '',\n })\n }}\n loadSuggestions={async (query) => {\n const options = await loadCatalogVariantOptions(query)\n registerOptionLabels(options)\n return options.map((option) => ({\n value: option.value,\n label: option.label,\n description: option.description,\n }))\n }}\n resolveLabel={resolveOptionLabel}\n placeholder={t(\n 'wms.backend.inventory.adjust.form.variantPlaceholder',\n 'Search variant or SKU',\n )}\n allowCustomValues={false}\n disabled={submitting}\n />\n </div>\n </FormField>\n\n <div className=\"grid gap-5 sm:grid-cols-2\">\n <FormField\n label={t('wms.backend.inventory.adjust.form.warehouse', 'Warehouse')}\n required\n error={fieldErrors.warehouseId}\n >\n <ComboboxInput\n value={form.warehouseId}\n onChange={(next) => {\n patchForm({\n warehouseId: next.trim(),\n locationId: '',\n })\n }}\n loadSuggestions={async (query) => {\n const options = await loadWarehouseOptions(query)\n registerOptionLabels(options)\n return options.map((option) => ({\n value: option.value,\n label: option.label,\n }))\n }}\n resolveLabel={resolveOptionLabel}\n placeholder={t(\n 'wms.backend.inventory.adjust.form.warehousePlaceholder',\n 'Select warehouse',\n )}\n allowCustomValues={false}\n disabled={submitting}\n />\n </FormField>\n\n <FormField\n label={t('wms.backend.inventory.adjust.form.location', 'Location')}\n required\n error={fieldErrors.locationId}\n >\n <ComboboxInput\n value={form.locationId}\n onChange={(next) => patchForm({ locationId: next.trim() })}\n loadSuggestions={async (query) => {\n const options = await loadLocationOptions(form.warehouseId, query)\n registerOptionLabels(options)\n return options.map((option) => ({\n value: option.value,\n label: option.label,\n }))\n }}\n resolveLabel={resolveOptionLabel}\n placeholder={t(\n 'wms.backend.inventory.adjust.form.locationPlaceholder',\n 'Select location',\n )}\n allowCustomValues={false}\n disabled={submitting || !form.warehouseId}\n />\n </FormField>\n </div>\n\n <FormField\n label={t('wms.backend.inventory.adjust.form.lot', 'Lot')}\n error={fieldErrors.lotNumber}\n >\n <ComboboxInput\n value={form.lotNumber}\n onChange={(next) => patchForm({ lotNumber: next.trim() })}\n loadSuggestions={async (query) => {\n const options = await loadLotNumberOptions(form.catalogVariantId, query)\n registerOptionLabels(options)\n return options.map((option) => ({\n value: option.value,\n label: option.label,\n }))\n }}\n resolveLabel={resolveOptionLabel}\n placeholder={t(\n 'wms.backend.inventory.adjust.form.lotPlaceholder',\n 'Select lot (optional)',\n )}\n allowCustomValues\n disabled={submitting || !form.catalogVariantId}\n />\n </FormField>\n\n <FormField\n label={t('wms.backend.inventory.adjust.form.serial', 'Serial number')}\n error={fieldErrors.serialNumber}\n >\n <Input\n value={form.serialNumber}\n onChange={(event) => patchForm({ serialNumber: event.target.value })}\n placeholder={t(\n 'wms.backend.inventory.adjust.form.serialPlaceholder',\n 'Optional \u2014 for serial-tracked variants',\n )}\n disabled={submitting}\n />\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {t(\n 'wms.backend.inventory.adjust.form.serialHelp',\n 'Use when the variant profile tracks serials.',\n )}\n </p>\n </FormField>\n\n <FormField\n label={t('wms.backend.inventory.adjust.form.delta', 'Adjustment')}\n required\n error={fieldErrors.delta}\n >\n <div className=\"flex w-32 items-center gap-2 rounded-md border bg-background p-2 shadow-xs\">\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={t('wms.backend.inventory.adjust.form.decrease', 'Decrease quantity')}\n onClick={() => adjustDelta(-1)}\n disabled={submitting}\n >\n <Minus className=\"size-4\" />\n </IconButton>\n <Input\n type=\"text\"\n inputMode=\"decimal\"\n value={String(form.delta)}\n onChange={(event) => {\n const parsed = parseDeltaInput(event.target.value, locale)\n if (parsed == null) return\n patchForm({ delta: parsed })\n }}\n className=\"h-8 w-auto min-w-0 flex-1 border-0 bg-transparent p-0 shadow-none focus-visible:ring-0\"\n inputClassName=\"text-center [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none\"\n disabled={submitting}\n />\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={t('wms.backend.inventory.adjust.form.increase', 'Increase quantity')}\n onClick={() => adjustDelta(1)}\n disabled={submitting}\n >\n <Plus className=\"size-4\" />\n </IconButton>\n </div>\n </FormField>\n\n <FormField\n label={t('wms.backend.inventory.adjust.form.reason', 'Reason')}\n required\n error={fieldErrors.reasonCode}\n >\n <Select\n value={form.reasonCode || undefined}\n onValueChange={(next) =>\n patchForm({ reasonCode: next as AdjustReasonCode })\n }\n disabled={submitting}\n >\n <SelectTrigger>\n <SelectValue\n placeholder={t(\n 'wms.backend.inventory.adjust.form.reasonPlaceholder',\n 'Select reason',\n )}\n />\n </SelectTrigger>\n <SelectContent>\n {ADJUST_REASON_CODES.map((code) => (\n <SelectItem key={code} value={code}>\n {reasonLabel(code)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </FormField>\n\n <FormField label={t('wms.backend.inventory.adjust.form.notes', 'Notes')}>\n <Textarea\n value={form.notes}\n onChange={(event) => patchForm({ notes: event.target.value })}\n placeholder={t(\n 'wms.backend.inventory.adjust.form.notesPlaceholder',\n 'Optional \u2014 context for auditors',\n )}\n rows={3}\n disabled={submitting}\n />\n </FormField>\n\n {previewContextReady ? (\n <div className=\"rounded-lg border bg-muted/40 px-4 py-3.5\">\n <p className=\"text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {t('wms.backend.inventory.adjust.preview.title', 'Balance preview')}\n </p>\n <div className=\"mt-2 flex items-center justify-between gap-3\">\n {previewError ? (\n <p className=\"text-sm text-status-warning-fg\">{previewError}</p>\n ) : loadingPreview && onHand == null ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('wms.backend.inventory.adjust.preview.loading', 'Refreshing balance\u2026')}\n </p>\n ) : onHand != null && projectedOnHand != null ? (\n <p className=\"text-sm font-semibold tabular-nums text-foreground\">\n {t('wms.backend.inventory.adjust.preview.onHandLabel', 'On hand')}{' '}\n {onHand}\n {' \u2192 '}\n {projectedOnHand}\n </p>\n ) : onHand != null ? (\n <p className=\"text-sm font-semibold tabular-nums text-foreground\">\n {t('wms.backend.inventory.adjust.preview.onHandLabel', 'On hand')}{' '}\n {onHand}\n </p>\n ) : null}\n {showBelowReorder ? (\n <StatusBadge variant=\"warning\">\n {t(\n 'wms.backend.inventory.adjust.preview.belowReorder',\n 'Below reorder',\n )}\n </StatusBadge>\n ) : null}\n </div>\n {loadingPreview && onHand != null ? (\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {t('wms.backend.inventory.adjust.preview.loading', 'Refreshing balance\u2026')}\n </p>\n ) : null}\n </div>\n ) : null}\n </div>\n\n <DialogFooter bordered={false} className=\"border-t px-6 py-4 sm:justify-between\">\n <p className=\"hidden text-xs text-muted-foreground sm:inline-flex sm:items-center sm:gap-1.5\">\n <KbdShortcut keys={['\u2318', 'Enter']} />\n <span>/</span>\n <KbdShortcut keys={['Ctrl', 'Enter']} />\n <span>{t('wms.backend.inventory.adjust.dialog.shortcutSave', 'to save')}</span>\n </p>\n <div className=\"flex w-full flex-col-reverse gap-2 sm:w-auto sm:flex-row\">\n <Button type=\"button\" variant=\"outline\" onClick={closeDialog} disabled={submitting}>\n {t('common.cancel', 'Cancel')}\n </Button>\n <Button type=\"submit\" disabled={submitting}>\n {t('wms.backend.inventory.adjust.dialog.submit', 'Save adjustment')}\n </Button>\n </div>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n )\n}\n"],
5
+ "mappings": ";AAkgBU,SACE,KADF;AAhgBV,YAAY,WAAW;AACvB,SAAS,SAAS;AAClB,SAAS,sBAAsB;AAC/B,SAAS,OAAO,SAAS,YAAY;AACrC,SAAS,aAAa;AACtB,SAAS,0BAA0B;AACnC,SAAS,0BAA0B;AACnC,SAAS,qBAAqB;AAC9B,SAAS,eAAe;AACxB,SAAS,sBAAsB;AAC/B,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB;AACzB,SAAS,MAAM,iBAAiB;AAChC,SAAS,yBAAyB;AAClC,SAAS,oBAAoB;AAC7B,SAAS,yCAAyC;AAClD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,MAAM,SAAS,aAAa,KAAK;AAEjC,MAAM,sBAAsB,CAAC,WAAW,aAAa,SAAS,cAAc,OAAO;AAyBnF,MAAM,aAA+B;AAAA,EACnC,kBAAkB;AAAA,EAClB,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,cAAc;AAChB;AAEO,SAAS,gBAAgB,OAAe,QAAgC;AAC7E,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,WAAW,YAAY,OAAO,YAAY,IAAK,QAAO;AAC3D,SAAO,kBAAkB,SAAS,MAAM;AAC1C;AAEO,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA+B;AAC7B,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,cAAc,eAAe;AACnC,QAAM,UAAU,MAAM,OAAwB,IAAI;AAClD,QAAM,EAAE,aAAa,kBAAkB,IAAI,mBAExC;AAAA,IACD,WAAW;AAAA,EACb,CAAC;AACD,QAAM,kBAAkB,MAAM;AAAA,IAC5B,OAAO,EAAE,kBAAkB;AAAA,IAC3B,CAAC,iBAAiB;AAAA,EACpB;AACA,QAAM,mBAAmB,MAAM;AAAA,IAC7B,MACE,EAAE,OAAO;AAAA,MACP,kBAAkB,EAAE,OAAO,EAAE,KAAK;AAAA,MAClC,aAAa,EAAE,OAAO,EAAE,KAAK;AAAA,MAC7B,YAAY,EAAE,OAAO,EAAE,KAAK;AAAA,MAC5B,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,MAC/C,OAAO,EAAE,OAAO,OAAO,EAAE,OAAO,CAAC,UAAU,UAAU,GAAG;AAAA,QACtD,SAAS;AAAA,UACP;AAAA,UACA;AAAA,QACF;AAAA,MACF,CAAC;AAAA,MACD,YAAY,EAAE,KAAK,mBAAmB;AAAA,MACtC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,MAC3C,cAAc,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,IACpD,CAAC;AAAA,IACH,CAAC,CAAC;AAAA,EACJ;AACA,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,KAAK;AACxD,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAA2B,UAAU;AACnE,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAiC,CAAC,CAAC;AAC/E,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAAwB,IAAI;AAC9D,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAwB,IAAI;AAC1E,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAS,CAAC;AACxD,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAS,KAAK;AAChE,QAAM,CAAC,oBAAoB,qBAAqB,IAAI,MAAM,SAAiC,CAAC,CAAC;AAE7F,QAAM,uBAAuB,MAAM;AAAA,IACjC,CAAC,YAAqD;AACpD,4BAAsB,CAAC,YAAY;AACjC,YAAI,UAAU;AACd,cAAM,OAAO,EAAE,GAAG,QAAQ;AAC1B,mBAAW,UAAU,SAAS;AAC5B,gBAAM,QAAQ,OAAO,MAAM,KAAK;AAChC,gBAAM,QAAQ,OAAO,MAAM,KAAK;AAChC,cAAI,CAAC,SAAS,CAAC,SAAS,KAAK,KAAK,MAAM,MAAO;AAC/C,eAAK,KAAK,IAAI;AACd,oBAAU;AAAA,QACZ;AACA,eAAO,UAAU,OAAO;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,qBAAqB,MAAM;AAAA,IAC/B,CAAC,UAAkB,mBAAmB,KAAK,KAAK;AAAA,IAChD,CAAC,kBAAkB;AAAA,EACrB;AACA,QAAM,wBAAwB,MAAM,OAAO,kBAAkB;AAC7D,wBAAsB,UAAU;AAEhC,QAAM,cAAc,MAAM;AAAA,IACxB,CAAC,SAA2B;AAC1B,YAAM,YAA8C;AAAA,QAClD,SAAS;AAAA,QACT,WAAW;AAAA,QACX,OAAO;AAAA,QACP,YAAY;AAAA,QACZ,OAAO;AAAA,MACT;AACA,aAAO,EAAE,wCAAwC,IAAI,IAAI,UAAU,IAAI,CAAC;AAAA,IAC1E;AAAA,IACA,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,cAAc,MAAM,YAAY,MAAM;AAC1C,YAAQ,UAAU;AAClB,mBAAe,CAAC,CAAC;AACjB,cAAU,IAAI;AACd,oBAAgB,IAAI;AACpB,oBAAgB,CAAC;AACjB,sBAAkB,KAAK;AACvB,kBAAc,KAAK;AACnB,0BAAsB,CAAC,CAAC;AAAA,EAC1B,GAAG,CAAC,CAAC;AAEL,QAAM,cAAc,MAAM,YAAY,MAAM;AAC1C,iBAAa,KAAK;AAClB,gBAAY;AAAA,EACd,GAAG,CAAC,cAAc,WAAW,CAAC;AAE9B,QAAM,YAAY,MAAM,YAAY,CAAC,UAAqC;AACxE,YAAQ,CAAC,aAAa,EAAE,GAAG,SAAS,GAAG,MAAM,EAAE;AAC/C,mBAAe,CAAC,CAAC;AAAA,EACnB,GAAG,CAAC,CAAC;AAEL,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,KAAM;AACX,UAAM,mBAAmB,yBAAyB,KAAK;AACvD,UAAM,cAAc,oBAAoB,KAAK;AAC7C,UAAM,aAAa,mBAAmB,KAAK;AAC3C,UAAM,QAAQ,cAAc,KAAK;AACjC,QAAI,CAAC,oBAAoB,CAAC,eAAe,CAAC,cAAc,CAAC,MAAO;AAChE,YAAQ,CAAC,aAAa;AAAA,MACpB,GAAG;AAAA,MACH,GAAI,mBAAmB,EAAE,iBAAiB,IAAI,CAAC;AAAA,MAC/C,GAAI,cAAc,EAAE,aAAa,YAAY,cAAc,GAAG,IAAI,CAAC;AAAA,MACnE,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,IACrC,EAAE;AACF,QAAI,CAAC,MAAO;AACZ,QAAI,YAAY;AAChB,SAAK,uBAAuB,KAAK,EAAE,KAAK,CAAC,cAAc;AACrD,UAAI,aAAa,CAAC,UAAW;AAC7B,cAAQ,CAAC,aAAa,EAAE,GAAG,SAAS,UAAU,EAAE;AAChD,2BAAqB,CAAC,EAAE,OAAO,WAAW,OAAO,UAAU,CAAC,CAAC;AAAA,IAC/D,CAAC;AACD,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,KAAM;AACX,QAAI,YAAY;AAEhB,UAAM,cAAc,OAAO,OAAe,YAAoD;AAC5F,YAAM,KAAK,MAAM,KAAK;AACtB,UAAI,CAAC,MAAM,sBAAsB,QAAQ,EAAE,EAAG;AAC9C,YAAM,QAAQ,MAAM,QAAQ,EAAE;AAC9B,UAAI,aAAa,CAAC,MAAO;AACzB,2BAAqB,CAAC,EAAE,OAAO,IAAI,MAAM,CAAC,CAAC;AAAA,IAC7C;AAEA,SAAK,QAAQ,IAAI;AAAA,MACf,YAAY,KAAK,kBAAkB,0BAA0B;AAAA,MAC7D,YAAY,KAAK,aAAa,qBAAqB;AAAA,MACnD,YAAY,KAAK,YAAY,oBAAoB;AAAA,IACnD,CAAC;AAED,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG;AAAA,IACD,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,KAAM;AACX,UAAM,YAAY,KAAK,iBAAiB,KAAK;AAC7C,QAAI,CAAC,WAAW;AACd,sBAAgB,CAAC;AACjB;AAAA,IACF;AACA,QAAI,YAAY;AAChB,SAAK,yBAAyB,SAAS,EAAE,KAAK,CAAC,UAAU;AACvD,UAAI,CAAC,UAAW,iBAAgB,KAAK;AAAA,IACvC,CAAC;AACD,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,KAAK,kBAAkB,IAAI,CAAC;AAEhC,QAAM,sBAAsB;AAAA,IAC1B,KAAK,iBAAiB,KAAK,KACzB,KAAK,YAAY,KAAK,KACtB,KAAK,WAAW,KAAK;AAAA,EACzB;AAEA,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,KAAM;AACX,UAAM,cAAc,KAAK,YAAY,KAAK;AAC1C,UAAM,aAAa,KAAK,WAAW,KAAK;AACxC,UAAM,mBAAmB,KAAK,iBAAiB,KAAK;AACpD,UAAM,YAAY,KAAK,UAAU,KAAK;AACtC,QAAI,CAAC,eAAe,CAAC,cAAc,CAAC,kBAAkB;AACpD,gBAAU,IAAI;AACd,sBAAgB,IAAI;AACpB,wBAAkB,KAAK;AACvB;AAAA,IACF;AACA,QAAI,YAAY;AAChB,sBAAkB,IAAI;AACtB,oBAAgB,IAAI;AACpB,UAAM,YAAY;AAChB,UAAI;AACF,cAAM,QAAQ,YACV,MAAM,kBAAkB,kBAAkB,SAAS,IACnD;AACJ,YAAI,UAAW;AACf,cAAM,QAAQ,MAAM,mBAAmB;AAAA,UACrC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AACD,YAAI,CAAC,WAAW;AACd,oBAAU,KAAK;AACf,0BAAgB,IAAI;AAAA,QACtB;AAAA,MACF,SAAS,OAAgB;AACvB,YAAI,UAAW;AACf,kBAAU,IAAI;AACd,YAAI,iBAAiB,oBAAoB;AACvC;AAAA,YACE;AAAA,cACE;AAAA,cACA;AAAA,YACF;AAAA,UACF;AACA;AAAA,QACF;AACA,eAAO,MAAM,6BAA6B,EAAE,WAAW,yBAAyB,KAAK,MAAM,CAAC;AAC5F;AAAA,UACE;AAAA,YACE;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF,UAAE;AACA,YAAI,CAAC,UAAW,mBAAkB,KAAK;AAAA,MACzC;AAAA,IACF,GAAG;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG;AAAA,IACD,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,kBACJ,UAAU,QAAQ,KAAK,UAAU,IAAI,SAAS,KAAK,QAAQ;AAC7D,QAAM,mBACJ,mBAAmB,QAAQ,eAAe,KAAK,mBAAmB;AAEpE,QAAM,eAAe,MAAM;AAAA,IACzB,OAAO,UAA4B;AACjC,aAAO,eAAe;AACtB,YAAM,SAAS,iBAAiB,UAAU;AAAA,QACxC,GAAG;AAAA,QACH,WAAW,KAAK,UAAU,KAAK,KAAK;AAAA,QACpC,OAAO,KAAK,MAAM,KAAK,KAAK;AAAA,QAC5B,cAAc,KAAK,aAAa,KAAK,KAAK;AAAA,MAC5C,CAAC;AACD,UAAI,CAAC,OAAO,SAAS;AACnB,cAAM,aAAqC,CAAC;AAC5C,mBAAW,SAAS,OAAO,MAAM,QAAQ;AACvC,gBAAM,MAAM,OAAO,MAAM,KAAK,CAAC,KAAK,MAAM;AAC1C,cAAI,CAAC,WAAW,GAAG,EAAG,YAAW,GAAG,IAAI,MAAM;AAAA,QAChD;AACA,uBAAe,UAAU;AACzB;AAAA,MACF;AAEA,UAAI,CAAC,OAAO,cAAc,CAAC,OAAO,kBAAkB,CAAC,OAAO,YAAY,CAAC,OAAO,QAAQ;AACtF;AAAA,UACE;AAAA,YACE;AAAA,YACA;AAAA,UACF;AAAA,UACA;AAAA,QACF;AACA;AAAA,MACF;AAEA,oBAAc,IAAI;AAClB,UAAI;AAGJ,cAAM,SAAS,OAAO,KAAK;AAC3B,cAAM,QAAQ,OAAO,KAAK,OAAO,KAAK;AACtC,cAAM,YAAY,OAAO,KAAK,WAAW,KAAK;AAC9C,YAAI;AACJ,YAAI,WAAW;AACb,cAAI;AACF,oBAAQ,MAAM,gCAAgC;AAAA,cAC5C,kBAAkB,OAAO,KAAK;AAAA,cAC9B;AAAA,cACA,gBAAgB,OAAO;AAAA,cACvB,UAAU,OAAO;AAAA,YACnB,CAAC;AAAA,UACH,SAAS,OAAgB;AACvB,kBAAM,UACJ,iBAAiB,4BACb,MAAM,UACN;AAAA,cACE;AAAA,cACA;AAAA,YACF;AACN,2BAAe,EAAE,WAAW,QAAQ,CAAC;AACrC;AAAA,UACF;AAAA,QACF;AACA,cAAM,UAAmC;AAAA,UACvC,gBAAgB,OAAO;AAAA,UACvB,UAAU,OAAO;AAAA,UACjB,aAAa,OAAO,KAAK;AAAA,UACzB,YAAY,OAAO,KAAK;AAAA,UACxB,kBAAkB,OAAO,KAAK;AAAA,UAC9B,OAAO,OAAO,KAAK;AAAA,UACnB;AAAA,UACA,YAAY,OAAO,KAAK;AAAA,UACxB,eAAe;AAAA,UACf,aAAa,kCAAkC;AAAA,UAC/C,aAAa,OAAO;AAAA,QACtB;AACE,YAAI,MAAO,SAAQ,QAAQ;AAC3B,cAAM,SAAS,OAAO,KAAK,cAAc,KAAK;AAC9C,YAAI,OAAQ,SAAQ,eAAe;AACnC,YAAI,MAAO,SAAQ,WAAW,EAAE,MAAM;AAEtC,cAAM,YAAY;AAAA,UAChB,WAAW,YAAY;AACrB,kBAAM,OAAO,MAAM;AAAA,cACjB;AAAA,cACA;AAAA,gBACE,QAAQ;AAAA,gBACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,gBAC9C,MAAM,KAAK,UAAU,OAAO;AAAA,cAC9B;AAAA,YACF;AACA,gBAAI,CAAC,KAAK,IAAI;AACZ,oBAAM;AAAA,gBACJ,KAAK;AAAA,gBACL,EAAE,8CAA8C,6BAA6B;AAAA,cAC/E;AAAA,YACF;AACA,mBAAO,KAAK,UAAU,CAAC;AAAA,UACzB;AAAA,UACA,SAAS;AAAA,UACT,iBAAiB;AAAA,QACnB,CAAC;AAED,cAAM,EAAE,8CAA8C,oBAAoB,GAAG,SAAS;AACtF,cAAM,YAAY,kBAAkB,EAAE,UAAU,CAAC,uBAAuB,EAAE,CAAC;AAC3E,cAAM,YAAY,kBAAkB,EAAE,UAAU,CAAC,gBAAgB,EAAE,CAAC;AACpE,oBAAY;AAAA,MACd,SAAS,OAAO;AACd,2BAAmB,OAAO,EAAE,8CAA8C,6BAA6B,GAAG,CAAC;AAAA,MAC7G,UAAE;AACA,sBAAc,KAAK;AAAA,MACrB;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,sBAAsB,MAAM;AAAA,IAChC,CAAC,UAA+C;AAC9C,UAAI,MAAM,QAAQ,UAAU;AAC1B,cAAM,eAAe;AACrB,oBAAY;AACZ;AAAA,MACF;AACA,WAAK,MAAM,WAAW,MAAM,YAAY,MAAM,QAAQ,SAAS;AAC7D,cAAM,eAAe;AACrB,YAAI,CAAC,WAAY,MAAK,aAAa;AAAA,MACrC;AAAA,IACF;AAAA,IACA,CAAC,aAAa,cAAc,UAAU;AAAA,EACxC;AAEA,QAAM,cAAc,MAAM,YAAY,CAAC,SAAiB;AACtD,YAAQ,CAAC,YAAY;AACnB,YAAM,OAAO,QAAQ,QAAQ;AAC7B,aAAO,EAAE,GAAG,SAAS,OAAO,SAAS,IAAI,OAAO,KAAK;AAAA,IACvD,CAAC;AACD,mBAAe,CAAC,CAAC;AAAA,EACnB,GAAG,CAAC,CAAC;AAEL,SACE,oBAAC,UAAO,MAAY,cAAc,CAAC,SAAU,OAAO,aAAa,IAAI,IAAI,YAAY,GACnF;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,WAAW;AAAA,MAEX;AAAA,4BAAC,SAAI,WAAU,4BACb,+BAAC,gBAAa,WAAU,uBACtB;AAAA,8BAAC,eACE,YAAE,6CAA6C,kBAAkB,GACpE;AAAA,UACA,oBAAC,qBACE;AAAA,YACC;AAAA,YACA;AAAA,UACF,GACF;AAAA,WACF,GACF;AAAA,QAEA,qBAAC,UAAK,KAAK,SAAS,UAAU,cAAc,WAAU,gCACpD;AAAA,+BAAC,SAAI,WAAU,iDACb;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO,EAAE,6CAA6C,SAAS;AAAA,gBAC/D,UAAQ;AAAA,gBACR,OAAO,YAAY;AAAA,gBAEnB,+BAAC,SAAI,WAAU,2BACb;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAU;AAAA,sBACV,eAAY;AAAA;AAAA,kBACd;AAAA,kBACA;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO,KAAK;AAAA,sBACZ,UAAU,CAAC,SAAS;AAClB,kCAAU;AAAA,0BACR,kBAAkB,KAAK,KAAK;AAAA,0BAC5B,WAAW;AAAA,wBACb,CAAC;AAAA,sBACH;AAAA,sBACA,iBAAiB,OAAO,UAAU;AAChC,8BAAM,UAAU,MAAM,0BAA0B,KAAK;AACrD,6CAAqB,OAAO;AAC5B,+BAAO,QAAQ,IAAI,CAAC,YAAY;AAAA,0BAC9B,OAAO,OAAO;AAAA,0BACd,OAAO,OAAO;AAAA,0BACd,aAAa,OAAO;AAAA,wBACtB,EAAE;AAAA,sBACJ;AAAA,sBACA,cAAc;AAAA,sBACd,aAAa;AAAA,wBACX;AAAA,wBACA;AAAA,sBACF;AAAA,sBACA,mBAAmB;AAAA,sBACnB,UAAU;AAAA;AAAA,kBACZ;AAAA,mBACF;AAAA;AAAA,YACF;AAAA,YAEA,qBAAC,SAAI,WAAU,6BACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO,EAAE,+CAA+C,WAAW;AAAA,kBACnE,UAAQ;AAAA,kBACR,OAAO,YAAY;AAAA,kBAEnB;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO,KAAK;AAAA,sBACZ,UAAU,CAAC,SAAS;AAClB,kCAAU;AAAA,0BACR,aAAa,KAAK,KAAK;AAAA,0BACvB,YAAY;AAAA,wBACd,CAAC;AAAA,sBACH;AAAA,sBACA,iBAAiB,OAAO,UAAU;AAChC,8BAAM,UAAU,MAAM,qBAAqB,KAAK;AAChD,6CAAqB,OAAO;AAC5B,+BAAO,QAAQ,IAAI,CAAC,YAAY;AAAA,0BAC9B,OAAO,OAAO;AAAA,0BACd,OAAO,OAAO;AAAA,wBAChB,EAAE;AAAA,sBACJ;AAAA,sBACA,cAAc;AAAA,sBACd,aAAa;AAAA,wBACX;AAAA,wBACA;AAAA,sBACF;AAAA,sBACA,mBAAmB;AAAA,sBACnB,UAAU;AAAA;AAAA,kBACZ;AAAA;AAAA,cACF;AAAA,cAEA;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO,EAAE,8CAA8C,UAAU;AAAA,kBACjE,UAAQ;AAAA,kBACR,OAAO,YAAY;AAAA,kBAEnB;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO,KAAK;AAAA,sBACZ,UAAU,CAAC,SAAS,UAAU,EAAE,YAAY,KAAK,KAAK,EAAE,CAAC;AAAA,sBACzD,iBAAiB,OAAO,UAAU;AAChC,8BAAM,UAAU,MAAM,oBAAoB,KAAK,aAAa,KAAK;AACjE,6CAAqB,OAAO;AAC5B,+BAAO,QAAQ,IAAI,CAAC,YAAY;AAAA,0BAC9B,OAAO,OAAO;AAAA,0BACd,OAAO,OAAO;AAAA,wBAChB,EAAE;AAAA,sBACJ;AAAA,sBACA,cAAc;AAAA,sBACd,aAAa;AAAA,wBACX;AAAA,wBACA;AAAA,sBACF;AAAA,sBACA,mBAAmB;AAAA,sBACnB,UAAU,cAAc,CAAC,KAAK;AAAA;AAAA,kBAChC;AAAA;AAAA,cACF;AAAA,eACF;AAAA,YAEA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO,EAAE,yCAAyC,KAAK;AAAA,gBACvD,OAAO,YAAY;AAAA,gBAEnB;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAO,KAAK;AAAA,oBACZ,UAAU,CAAC,SAAS,UAAU,EAAE,WAAW,KAAK,KAAK,EAAE,CAAC;AAAA,oBACxD,iBAAiB,OAAO,UAAU;AAChC,4BAAM,UAAU,MAAM,qBAAqB,KAAK,kBAAkB,KAAK;AACvE,2CAAqB,OAAO;AAC5B,6BAAO,QAAQ,IAAI,CAAC,YAAY;AAAA,wBAC9B,OAAO,OAAO;AAAA,wBACd,OAAO,OAAO;AAAA,sBAChB,EAAE;AAAA,oBACJ;AAAA,oBACA,cAAc;AAAA,oBACd,aAAa;AAAA,sBACX;AAAA,sBACA;AAAA,oBACF;AAAA,oBACA,mBAAiB;AAAA,oBACjB,UAAU,cAAc,CAAC,KAAK;AAAA;AAAA,gBAChC;AAAA;AAAA,YACF;AAAA,YAEA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO,EAAE,4CAA4C,eAAe;AAAA,gBACpE,OAAO,YAAY;AAAA,gBAEnB;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO,KAAK;AAAA,sBACZ,UAAU,CAAC,UAAU,UAAU,EAAE,cAAc,MAAM,OAAO,MAAM,CAAC;AAAA,sBACnE,aAAa;AAAA,wBACX;AAAA,wBACA;AAAA,sBACF;AAAA,sBACA,UAAU;AAAA;AAAA,kBACZ;AAAA,kBACA,oBAAC,OAAE,WAAU,sCACV;AAAA,oBACC;AAAA,oBACA;AAAA,kBACF,GACF;AAAA;AAAA;AAAA,YACF;AAAA,YAEA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO,EAAE,2CAA2C,YAAY;AAAA,gBAChE,UAAQ;AAAA,gBACR,OAAO,YAAY;AAAA,gBAEnB,+BAAC,SAAI,WAAU,8EACb;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,SAAQ;AAAA,sBACR,MAAK;AAAA,sBACL,cAAY,EAAE,8CAA8C,mBAAmB;AAAA,sBAC/E,SAAS,MAAM,YAAY,EAAE;AAAA,sBAC7B,UAAU;AAAA,sBAEV,8BAAC,SAAM,WAAU,UAAS;AAAA;AAAA,kBAC5B;AAAA,kBACA;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,OAAO,OAAO,KAAK,KAAK;AAAA,sBACxB,UAAU,CAAC,UAAU;AACnB,8BAAM,SAAS,gBAAgB,MAAM,OAAO,OAAO,MAAM;AACzD,4BAAI,UAAU,KAAM;AACpB,kCAAU,EAAE,OAAO,OAAO,CAAC;AAAA,sBAC7B;AAAA,sBACA,WAAU;AAAA,sBACV,gBAAe;AAAA,sBACf,UAAU;AAAA;AAAA,kBACZ;AAAA,kBACA;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,SAAQ;AAAA,sBACR,MAAK;AAAA,sBACL,cAAY,EAAE,8CAA8C,mBAAmB;AAAA,sBAC/E,SAAS,MAAM,YAAY,CAAC;AAAA,sBAC5B,UAAU;AAAA,sBAEV,8BAAC,QAAK,WAAU,UAAS;AAAA;AAAA,kBAC3B;AAAA,mBACF;AAAA;AAAA,YACF;AAAA,YAEA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO,EAAE,4CAA4C,QAAQ;AAAA,gBAC7D,UAAQ;AAAA,gBACR,OAAO,YAAY;AAAA,gBAEnB;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAO,KAAK,cAAc;AAAA,oBAC1B,eAAe,CAAC,SACd,UAAU,EAAE,YAAY,KAAyB,CAAC;AAAA,oBAEpD,UAAU;AAAA,oBAEV;AAAA,0CAAC,iBACC;AAAA,wBAAC;AAAA;AAAA,0BACC,aAAa;AAAA,4BACX;AAAA,4BACA;AAAA,0BACF;AAAA;AAAA,sBACF,GACF;AAAA,sBACA,oBAAC,iBACE,8BAAoB,IAAI,CAAC,SACxB,oBAAC,cAAsB,OAAO,MAC3B,sBAAY,IAAI,KADF,IAEjB,CACD,GACH;AAAA;AAAA;AAAA,gBACF;AAAA;AAAA,YACF;AAAA,YAEA,oBAAC,aAAU,OAAO,EAAE,2CAA2C,OAAO,GACpE;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO,KAAK;AAAA,gBACZ,UAAU,CAAC,UAAU,UAAU,EAAE,OAAO,MAAM,OAAO,MAAM,CAAC;AAAA,gBAC5D,aAAa;AAAA,kBACX;AAAA,kBACA;AAAA,gBACF;AAAA,gBACA,MAAM;AAAA,gBACN,UAAU;AAAA;AAAA,YACZ,GACF;AAAA,YAEC,sBACC,qBAAC,SAAI,WAAU,6CACb;AAAA,kCAAC,OAAE,WAAU,uEACV,YAAE,8CAA8C,iBAAiB,GACpE;AAAA,cACA,qBAAC,SAAI,WAAU,gDACZ;AAAA,+BACC,oBAAC,OAAE,WAAU,kCAAkC,wBAAa,IAC1D,kBAAkB,UAAU,OAC9B,oBAAC,OAAE,WAAU,iCACV,YAAE,gDAAgD,0BAAqB,GAC1E,IACE,UAAU,QAAQ,mBAAmB,OACvC,qBAAC,OAAE,WAAU,sDACV;AAAA,oBAAE,oDAAoD,SAAS;AAAA,kBAAG;AAAA,kBAClE;AAAA,kBACA;AAAA,kBACA;AAAA,mBACH,IACE,UAAU,OACZ,qBAAC,OAAE,WAAU,sDACV;AAAA,oBAAE,oDAAoD,SAAS;AAAA,kBAAG;AAAA,kBAClE;AAAA,mBACH,IACE;AAAA,gBACH,mBACC,oBAAC,eAAY,SAAQ,WAClB;AAAA,kBACC;AAAA,kBACA;AAAA,gBACF,GACF,IACE;AAAA,iBACN;AAAA,cACC,kBAAkB,UAAU,OAC3B,oBAAC,OAAE,WAAU,sCACV,YAAE,gDAAgD,0BAAqB,GAC1E,IACE;AAAA,eACN,IACE;AAAA,aACN;AAAA,UAEA,qBAAC,gBAAa,UAAU,OAAO,WAAU,yCACvC;AAAA,iCAAC,OAAE,WAAU,kFACX;AAAA,kCAAC,eAAY,MAAM,CAAC,UAAK,OAAO,GAAG;AAAA,cACnC,oBAAC,UAAK,eAAC;AAAA,cACP,oBAAC,eAAY,MAAM,CAAC,QAAQ,OAAO,GAAG;AAAA,cACtC,oBAAC,UAAM,YAAE,oDAAoD,SAAS,GAAE;AAAA,eAC1E;AAAA,YACA,qBAAC,SAAI,WAAU,4DACb;AAAA,kCAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,SAAS,aAAa,UAAU,YACrE,YAAE,iBAAiB,QAAQ,GAC9B;AAAA,cACA,oBAAC,UAAO,MAAK,UAAS,UAAU,YAC7B,YAAE,8CAA8C,iBAAiB,GACpE;AAAA,eACF;AAAA,aACF;AAAA,WACF;AAAA;AAAA;AAAA,EACF,GACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -37,13 +37,13 @@ function buildWarehousePresenter(t, record) {
37
37
  const label = t("wms.search.badge.warehouse", "Warehouse");
38
38
  const title = pickString(record.name, record.code, record.id) ?? label;
39
39
  const subtitle = formatSubtitle(record.code, record.city, record.country);
40
- return { title, subtitle, icon: "warehouse", badge: label };
40
+ return { title, subtitle, icon: "warehouse" };
41
41
  }
42
42
  function buildLocationPresenter(t, record) {
43
43
  const label = t("wms.search.badge.location", "Location");
44
44
  const title = pickString(record.code, record.id) ?? label;
45
45
  const subtitle = formatSubtitle(record.type, record.warehouse_id ?? record.warehouseId);
46
- return { title, subtitle, icon: "map-pinned", badge: label };
46
+ return { title, subtitle, icon: "map-pinned" };
47
47
  }
48
48
  function buildInventoryProfilePresenter(t, record) {
49
49
  const label = t("wms.search.badge.inventoryProfile", "Inventory profile");
@@ -55,13 +55,13 @@ function buildInventoryProfilePresenter(t, record) {
55
55
  record.default_uom ?? record.defaultUom,
56
56
  variantId ? t("wms.search.profile.variantScoped", "Variant-scoped") : t("wms.search.profile.productScoped", "Product-scoped")
57
57
  );
58
- return { title, subtitle, icon: "boxes", badge: label };
58
+ return { title, subtitle, icon: "boxes" };
59
59
  }
60
60
  function buildLotPresenter(t, record) {
61
61
  const label = t("wms.search.badge.lot", "Inventory lot");
62
62
  const title = pickString(record.lot_number, record.lotNumber, record.batch_number, record.batchNumber, record.id) ?? label;
63
63
  const subtitle = formatSubtitle(record.catalog_variant_id ?? record.catalogVariantId, record.status, record.expires_at ?? record.expiresAt);
64
- return { title, subtitle, icon: "package-search", badge: label };
64
+ return { title, subtitle, icon: "package-search" };
65
65
  }
66
66
  const searchConfig = {
67
67
  entities: [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/wms/search.ts"],
4
- "sourcesContent": ["import type {\n SearchBuildContext,\n SearchIndexSource,\n SearchModuleConfig,\n SearchResultPresenter,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { E } from '#generated/entities.ids.generated'\n\nconst WMS_ROOT_URL = '/backend/wms'\nconst WMS_INVENTORY_URL = '/backend/wms/inventory'\nconst WMS_CONFIG_URL = '/backend/config/wms'\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item == null ? '' : String(item))).filter(Boolean).join(', ')\n : typeof value === 'object'\n ? JSON.stringify(value)\n : String(value)\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const values = parts\n .map((part) => (part == null ? '' : String(part)).trim())\n .filter(Boolean)\n if (!values.length) return undefined\n return values.join(' \u00B7 ')\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n for (const [key, value] of Object.entries(ctx.customFields)) {\n appendLine(lines, key.replace(/^cf:/, ''), value)\n }\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nfunction buildWarehousePresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = t('wms.search.badge.warehouse', 'Warehouse')\n const title = pickString(record.name, record.code, record.id) ?? label\n const subtitle = formatSubtitle(record.code, record.city, record.country)\n return { title, subtitle, icon: 'warehouse', badge: label }\n}\n\nfunction buildLocationPresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = t('wms.search.badge.location', 'Location')\n const title = pickString(record.code, record.id) ?? label\n const subtitle = formatSubtitle(record.type, record.warehouse_id ?? record.warehouseId)\n return { title, subtitle, icon: 'map-pinned', badge: label }\n}\n\nfunction buildInventoryProfilePresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = t('wms.search.badge.inventoryProfile', 'Inventory profile')\n const productId = pickString(record.catalog_product_id, record.catalogProductId)\n const variantId = pickString(record.catalog_variant_id, record.catalogVariantId)\n const title = variantId || productId || pickString(record.id) || label\n const subtitle = formatSubtitle(\n record.default_strategy ?? record.defaultStrategy,\n record.default_uom ?? record.defaultUom,\n variantId ? t('wms.search.profile.variantScoped', 'Variant-scoped') : t('wms.search.profile.productScoped', 'Product-scoped'),\n )\n return { title, subtitle, icon: 'boxes', badge: label }\n}\n\nfunction buildLotPresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = t('wms.search.badge.lot', 'Inventory lot')\n const title = pickString(record.lot_number, record.lotNumber, record.batch_number, record.batchNumber, record.id) ?? label\n const subtitle = formatSubtitle(record.catalog_variant_id ?? record.catalogVariantId, record.status, record.expires_at ?? record.expiresAt)\n return { title, subtitle, icon: 'package-search', badge: label }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: E.wms.warehouse,\n aclFeatures: ['wms.view'],\n enabled: true,\n priority: 8,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name)\n appendLine(lines, 'Code', record.code)\n appendLine(lines, 'City', record.city)\n appendLine(lines, 'Country', record.country)\n appendLine(lines, 'Timezone', record.timezone)\n return buildIndexSource(ctx, buildWarehousePresenter(t, record), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildWarehousePresenter(t, ctx.record)\n },\n resolveUrl: async () => WMS_CONFIG_URL,\n fieldPolicy: {\n searchable: ['name', 'code', 'city', 'country', 'timezone'],\n },\n },\n {\n entityId: E.wms.warehouse_location,\n aclFeatures: ['wms.view'],\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Code', record.code)\n appendLine(lines, 'Type', record.type)\n appendLine(lines, 'Warehouse', record.warehouse_id ?? record.warehouseId)\n appendLine(lines, 'Parent', record.parent_id ?? record.parentId)\n appendLine(lines, 'Capacity units', record.capacity_units ?? record.capacityUnits)\n appendLine(lines, 'Capacity weight', record.capacity_weight ?? record.capacityWeight)\n return buildIndexSource(ctx, buildLocationPresenter(t, record), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildLocationPresenter(t, ctx.record)\n },\n resolveUrl: async () => WMS_CONFIG_URL,\n fieldPolicy: {\n searchable: ['code', 'type', 'warehouse_id', 'parent_id', 'capacity_units', 'capacity_weight'],\n },\n },\n {\n entityId: E.wms.product_inventory_profile,\n aclFeatures: ['wms.view'],\n enabled: true,\n priority: 8,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Product', record.catalog_product_id ?? record.catalogProductId)\n appendLine(lines, 'Variant', record.catalog_variant_id ?? record.catalogVariantId)\n appendLine(lines, 'Default UOM', record.default_uom ?? record.defaultUom)\n appendLine(lines, 'Strategy', record.default_strategy ?? record.defaultStrategy)\n appendLine(lines, 'Reorder point', record.reorder_point ?? record.reorderPoint)\n appendLine(lines, 'Safety stock', record.safety_stock ?? record.safetyStock)\n appendLine(lines, 'Track lot', record.track_lot ?? record.trackLot)\n appendLine(lines, 'Track serial', record.track_serial ?? record.trackSerial)\n appendLine(lines, 'Track expiration', record.track_expiration ?? record.trackExpiration)\n return buildIndexSource(ctx, buildInventoryProfilePresenter(t, record), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildInventoryProfilePresenter(t, ctx.record)\n },\n resolveUrl: async (ctx) => {\n const variantId = pickString(ctx.record.catalog_variant_id, ctx.record.catalogVariantId)\n if (variantId) return `${WMS_ROOT_URL}/sku/${variantId}`\n return WMS_CONFIG_URL\n },\n resolveLinks: async () => [{ href: WMS_INVENTORY_URL, label: 'Inventory console', kind: 'secondary' }],\n fieldPolicy: {\n searchable: [\n 'catalog_product_id',\n 'catalog_variant_id',\n 'default_uom',\n 'default_strategy',\n 'reorder_point',\n 'safety_stock',\n ],\n },\n },\n {\n entityId: E.wms.inventory_lot,\n aclFeatures: ['wms.view'],\n enabled: true,\n priority: 6,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Lot number', record.lot_number ?? record.lotNumber)\n appendLine(lines, 'Batch number', record.batch_number ?? record.batchNumber)\n appendLine(lines, 'SKU', record.sku)\n appendLine(lines, 'Variant', record.catalog_variant_id ?? record.catalogVariantId)\n appendLine(lines, 'Status', record.status)\n appendLine(lines, 'Expires at', record.expires_at ?? record.expiresAt)\n return buildIndexSource(ctx, buildLotPresenter(t, record), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildLotPresenter(t, ctx.record)\n },\n resolveUrl: async (ctx) => {\n const id = pickString(ctx.record.id)\n if (id) return `${WMS_ROOT_URL}/lot/${id}`\n return WMS_ROOT_URL\n },\n resolveLinks: async () => [{ href: WMS_CONFIG_URL, label: 'WMS configuration', kind: 'secondary' }],\n fieldPolicy: {\n searchable: ['lot_number', 'batch_number', 'sku', 'catalog_variant_id', 'status', 'expires_at'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type {\n SearchBuildContext,\n SearchIndexSource,\n SearchModuleConfig,\n SearchResultPresenter,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { E } from '#generated/entities.ids.generated'\n\nconst WMS_ROOT_URL = '/backend/wms'\nconst WMS_INVENTORY_URL = '/backend/wms/inventory'\nconst WMS_CONFIG_URL = '/backend/config/wms'\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item == null ? '' : String(item))).filter(Boolean).join(', ')\n : typeof value === 'object'\n ? JSON.stringify(value)\n : String(value)\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const values = parts\n .map((part) => (part == null ? '' : String(part)).trim())\n .filter(Boolean)\n if (!values.length) return undefined\n return values.join(' \u00B7 ')\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n for (const [key, value] of Object.entries(ctx.customFields)) {\n appendLine(lines, key.replace(/^cf:/, ''), value)\n }\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nfunction buildWarehousePresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = t('wms.search.badge.warehouse', 'Warehouse')\n const title = pickString(record.name, record.code, record.id) ?? label\n const subtitle = formatSubtitle(record.code, record.city, record.country)\n return { title, subtitle, icon: 'warehouse' }\n}\n\nfunction buildLocationPresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = t('wms.search.badge.location', 'Location')\n const title = pickString(record.code, record.id) ?? label\n const subtitle = formatSubtitle(record.type, record.warehouse_id ?? record.warehouseId)\n return { title, subtitle, icon: 'map-pinned' }\n}\n\nfunction buildInventoryProfilePresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = t('wms.search.badge.inventoryProfile', 'Inventory profile')\n const productId = pickString(record.catalog_product_id, record.catalogProductId)\n const variantId = pickString(record.catalog_variant_id, record.catalogVariantId)\n const title = variantId || productId || pickString(record.id) || label\n const subtitle = formatSubtitle(\n record.default_strategy ?? record.defaultStrategy,\n record.default_uom ?? record.defaultUom,\n variantId ? t('wms.search.profile.variantScoped', 'Variant-scoped') : t('wms.search.profile.productScoped', 'Product-scoped'),\n )\n return { title, subtitle, icon: 'boxes' }\n}\n\nfunction buildLotPresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = t('wms.search.badge.lot', 'Inventory lot')\n const title = pickString(record.lot_number, record.lotNumber, record.batch_number, record.batchNumber, record.id) ?? label\n const subtitle = formatSubtitle(record.catalog_variant_id ?? record.catalogVariantId, record.status, record.expires_at ?? record.expiresAt)\n return { title, subtitle, icon: 'package-search' }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: E.wms.warehouse,\n aclFeatures: ['wms.view'],\n enabled: true,\n priority: 8,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name)\n appendLine(lines, 'Code', record.code)\n appendLine(lines, 'City', record.city)\n appendLine(lines, 'Country', record.country)\n appendLine(lines, 'Timezone', record.timezone)\n return buildIndexSource(ctx, buildWarehousePresenter(t, record), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildWarehousePresenter(t, ctx.record)\n },\n resolveUrl: async () => WMS_CONFIG_URL,\n fieldPolicy: {\n searchable: ['name', 'code', 'city', 'country', 'timezone'],\n },\n },\n {\n entityId: E.wms.warehouse_location,\n aclFeatures: ['wms.view'],\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Code', record.code)\n appendLine(lines, 'Type', record.type)\n appendLine(lines, 'Warehouse', record.warehouse_id ?? record.warehouseId)\n appendLine(lines, 'Parent', record.parent_id ?? record.parentId)\n appendLine(lines, 'Capacity units', record.capacity_units ?? record.capacityUnits)\n appendLine(lines, 'Capacity weight', record.capacity_weight ?? record.capacityWeight)\n return buildIndexSource(ctx, buildLocationPresenter(t, record), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildLocationPresenter(t, ctx.record)\n },\n resolveUrl: async () => WMS_CONFIG_URL,\n fieldPolicy: {\n searchable: ['code', 'type', 'warehouse_id', 'parent_id', 'capacity_units', 'capacity_weight'],\n },\n },\n {\n entityId: E.wms.product_inventory_profile,\n aclFeatures: ['wms.view'],\n enabled: true,\n priority: 8,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Product', record.catalog_product_id ?? record.catalogProductId)\n appendLine(lines, 'Variant', record.catalog_variant_id ?? record.catalogVariantId)\n appendLine(lines, 'Default UOM', record.default_uom ?? record.defaultUom)\n appendLine(lines, 'Strategy', record.default_strategy ?? record.defaultStrategy)\n appendLine(lines, 'Reorder point', record.reorder_point ?? record.reorderPoint)\n appendLine(lines, 'Safety stock', record.safety_stock ?? record.safetyStock)\n appendLine(lines, 'Track lot', record.track_lot ?? record.trackLot)\n appendLine(lines, 'Track serial', record.track_serial ?? record.trackSerial)\n appendLine(lines, 'Track expiration', record.track_expiration ?? record.trackExpiration)\n return buildIndexSource(ctx, buildInventoryProfilePresenter(t, record), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildInventoryProfilePresenter(t, ctx.record)\n },\n resolveUrl: async (ctx) => {\n const variantId = pickString(ctx.record.catalog_variant_id, ctx.record.catalogVariantId)\n if (variantId) return `${WMS_ROOT_URL}/sku/${variantId}`\n return WMS_CONFIG_URL\n },\n resolveLinks: async () => [{ href: WMS_INVENTORY_URL, label: 'Inventory console', kind: 'secondary' }],\n fieldPolicy: {\n searchable: [\n 'catalog_product_id',\n 'catalog_variant_id',\n 'default_uom',\n 'default_strategy',\n 'reorder_point',\n 'safety_stock',\n ],\n },\n },\n {\n entityId: E.wms.inventory_lot,\n aclFeatures: ['wms.view'],\n enabled: true,\n priority: 6,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Lot number', record.lot_number ?? record.lotNumber)\n appendLine(lines, 'Batch number', record.batch_number ?? record.batchNumber)\n appendLine(lines, 'SKU', record.sku)\n appendLine(lines, 'Variant', record.catalog_variant_id ?? record.catalogVariantId)\n appendLine(lines, 'Status', record.status)\n appendLine(lines, 'Expires at', record.expires_at ?? record.expiresAt)\n return buildIndexSource(ctx, buildLotPresenter(t, record), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildLotPresenter(t, ctx.record)\n },\n resolveUrl: async (ctx) => {\n const id = pickString(ctx.record.id)\n if (id) return `${WMS_ROOT_URL}/lot/${id}`\n return WMS_ROOT_URL\n },\n resolveLinks: async () => [{ href: WMS_CONFIG_URL, label: 'WMS configuration', kind: 'secondary' }],\n fieldPolicy: {\n searchable: ['lot_number', 'batch_number', 'sku', 'catalog_variant_id', 'status', 'expires_at'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\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.7.1-develop.7195.1.b5efd1d51a",
3
+ "version": "0.7.1-develop.7201.1.9bd6c88e3d",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -253,16 +253,16 @@
253
253
  "zod": "^4.4.3"
254
254
  },
255
255
  "peerDependencies": {
256
- "@open-mercato/ai-assistant": "0.7.1-develop.7195.1.b5efd1d51a",
257
- "@open-mercato/shared": "0.7.1-develop.7195.1.b5efd1d51a",
258
- "@open-mercato/ui": "0.7.1-develop.7195.1.b5efd1d51a",
256
+ "@open-mercato/ai-assistant": "0.7.1-develop.7201.1.9bd6c88e3d",
257
+ "@open-mercato/shared": "0.7.1-develop.7201.1.9bd6c88e3d",
258
+ "@open-mercato/ui": "0.7.1-develop.7201.1.9bd6c88e3d",
259
259
  "react": "^19.0.0",
260
260
  "react-dom": "^19.0.0"
261
261
  },
262
262
  "devDependencies": {
263
- "@open-mercato/ai-assistant": "0.7.1-develop.7195.1.b5efd1d51a",
264
- "@open-mercato/shared": "0.7.1-develop.7195.1.b5efd1d51a",
265
- "@open-mercato/ui": "0.7.1-develop.7195.1.b5efd1d51a",
263
+ "@open-mercato/ai-assistant": "0.7.1-develop.7201.1.9bd6c88e3d",
264
+ "@open-mercato/shared": "0.7.1-develop.7201.1.9bd6c88e3d",
265
+ "@open-mercato/ui": "0.7.1-develop.7201.1.9bd6c88e3d",
266
266
  "@testing-library/dom": "^10.4.1",
267
267
  "@testing-library/jest-dom": "^7.0.1",
268
268
  "@testing-library/react": "^16.3.3",
@@ -470,6 +470,12 @@ export async function setupInitialTenant(
470
470
  }
471
471
  }
472
472
 
473
+ // Custom roles are often created inside onTenantCreated hooks, so they did not
474
+ // exist yet when ensureDefaultRoleAcls ran above and were skipped there. Sync
475
+ // again now that the hooks have had a chance to create them — idempotent, same
476
+ // pattern as the `mercato auth sync-role-acls` CLI command.
477
+ await ensureCustomRoleAcls(em, tenantId, resolvedModules)
478
+
473
479
  return {
474
480
  tenantId,
475
481
  organizationId,
@@ -1,7 +1,8 @@
1
1
  "use client";
2
2
 
3
3
  import * as React from "react";
4
- import { useT } from "@open-mercato/shared/lib/i18n/context";
4
+ import { useT, useLocale } from "@open-mercato/shared/lib/i18n/context";
5
+ import { parseLocaleNumber } from "@open-mercato/shared/lib/number";
5
6
  import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
6
7
  import { Button } from "@open-mercato/ui/primitives/button";
7
8
  import { Checkbox } from "@open-mercato/ui/primitives/checkbox";
@@ -56,19 +57,24 @@ const REFERENCE_UNIT_OPTIONS = REFERENCE_UNIT_CODES.map((code) => ({
56
57
  fallback: REFERENCE_UNIT_DISPLAY[code] ?? code,
57
58
  }));
58
59
 
59
- function normalizeDecimalInput(value: string): string {
60
- return value.replace(/,/g, ".");
60
+ // Keeps the field submit-ready (dot-decimal, no grouping characters) while the user is
61
+ // still typing. Falls back to the raw value when it isn't parseable yet (empty, a lone
62
+ // sign) so the field stays editable. Delegates to `parseLocaleNumber` instead of a
63
+ // hard-coded `,` -> `.` swap, which broke on grouped input such as `1 234,56` (#5828).
64
+ export function normalizeDecimalInput(value: string, locale?: string): string {
65
+ const parsed = parseLocaleNumber(value, locale);
66
+ return parsed === null ? value : String(parsed);
61
67
  }
62
68
 
63
- function toPositiveNumber(value: unknown): number | null {
69
+ export function toPositiveNumber(value: unknown, locale?: string): number | null {
64
70
  if (typeof value === "number") {
65
71
  return Number.isFinite(value) && value > 0 ? value : null;
66
72
  }
67
73
  if (typeof value !== "string") return null;
68
74
  const normalized = toTrimmedOrNull(value);
69
75
  if (!normalized) return null;
70
- const numeric = Number(normalized.replace(",", "."));
71
- return Number.isFinite(numeric) && numeric > 0 ? numeric : null;
76
+ const numeric = parseLocaleNumber(normalized, locale);
77
+ return numeric !== null && numeric > 0 ? numeric : null;
72
78
  }
73
79
 
74
80
  function toSortValue(value: string): number {
@@ -82,7 +88,10 @@ function formatPreviewNumber(value: number): string {
82
88
  return Number.isInteger(rounded) ? String(rounded) : rounded.toString();
83
89
  }
84
90
 
85
- function normalizeConversions(value: unknown): ProductUnitConversionDraft[] {
91
+ function normalizeConversions(
92
+ value: unknown,
93
+ locale?: string,
94
+ ): ProductUnitConversionDraft[] {
86
95
  if (!Array.isArray(value)) return [];
87
96
  const normalized = value
88
97
  .map((entry) => {
@@ -92,7 +101,7 @@ function normalizeConversions(value: unknown): ProductUnitConversionDraft[] {
92
101
  id: toTrimmedOrNull(row.id) ?? null,
93
102
  unitCode: toTrimmedOrNull(row.unitCode) ?? "",
94
103
  toBaseFactor: toTrimmedOrNull(row.toBaseFactor)
95
- ? normalizeDecimalInput(toTrimmedOrNull(row.toBaseFactor) as string)
104
+ ? normalizeDecimalInput(toTrimmedOrNull(row.toBaseFactor) as string, locale)
96
105
  : "",
97
106
  sortOrder: toTrimmedOrNull(row.sortOrder) ?? "",
98
107
  isActive: row.isActive !== false,
@@ -135,13 +144,14 @@ export function ProductUomSection({
135
144
  embedded = false,
136
145
  }: ProductUomSectionProps) {
137
146
  const t = useT();
147
+ const locale = useLocale();
138
148
  const { enabled: unitPriceDisplayEnabled } = useUnitPriceDisplayEnabled();
139
149
  const [unitOptions, setUnitOptions] = React.useState<UnitOption[]>([]);
140
150
  const [loadingUnits, setLoadingUnits] = React.useState(false);
141
151
  const [errorLoadingUnits, setErrorLoadingUnits] = React.useState(false);
142
152
  const conversions = React.useMemo(
143
- () => normalizeConversions(values.unitConversions),
144
- [values.unitConversions],
153
+ () => normalizeConversions(values.unitConversions, locale),
154
+ [values.unitConversions, locale],
145
155
  );
146
156
 
147
157
  React.useEffect(() => {
@@ -238,13 +248,13 @@ export function ProductUomSection({
238
248
  const defaultSalesUnit = toTrimmedOrNull(values.defaultSalesUnit) ?? "";
239
249
  const defaultSalesQuantityRaw =
240
250
  toTrimmedOrNull(values.defaultSalesUnitQuantity) ?? "1";
241
- const defaultSalesQuantity = normalizeDecimalInput(defaultSalesQuantityRaw);
251
+ const defaultSalesQuantity = normalizeDecimalInput(defaultSalesQuantityRaw, locale);
242
252
  const unitPriceEnabled = Boolean(values.unitPriceEnabled);
243
253
  const unitPriceReferenceUnit =
244
254
  toTrimmedOrNull(values.unitPriceReferenceUnit) ?? "";
245
255
  const unitPriceBaseQuantityRaw =
246
256
  toTrimmedOrNull(values.unitPriceBaseQuantity) ?? "";
247
- const unitPriceBaseQuantity = normalizeDecimalInput(unitPriceBaseQuantityRaw);
257
+ const unitPriceBaseQuantity = normalizeDecimalInput(unitPriceBaseQuantityRaw, locale);
248
258
 
249
259
  const baseUnitLabel = findUnitLabel(defaultUnit) ?? defaultUnit;
250
260
  const salesUnitLabel =
@@ -261,17 +271,17 @@ export function ProductUomSection({
261
271
  (entry) =>
262
272
  entry.isActive &&
263
273
  entry.unitCode.toLowerCase() === defaultSalesKey &&
264
- toPositiveNumber(entry.toBaseFactor) !== null,
274
+ toPositiveNumber(entry.toBaseFactor, locale) !== null,
265
275
  );
266
- return row ? toPositiveNumber(row.toBaseFactor) : null;
267
- }, [conversions, defaultSalesUnit, defaultUnit]);
276
+ return row ? toPositiveNumber(row.toBaseFactor, locale) : null;
277
+ }, [conversions, defaultSalesUnit, defaultUnit, locale]);
268
278
 
269
- const defaultSalesQuantityNumber = toPositiveNumber(defaultSalesQuantity);
279
+ const defaultSalesQuantityNumber = toPositiveNumber(defaultSalesQuantity, locale);
270
280
  const defaultSalesQuantityNormalized =
271
281
  defaultSalesQuantityNumber && defaultSalesFactor
272
282
  ? defaultSalesQuantityNumber * defaultSalesFactor
273
283
  : null;
274
- const unitPriceBaseQuantityNumber = toPositiveNumber(unitPriceBaseQuantity);
284
+ const unitPriceBaseQuantityNumber = toPositiveNumber(unitPriceBaseQuantity, locale);
275
285
 
276
286
  const validConversions = conversions.filter(
277
287
  (entry) =>
@@ -388,7 +398,7 @@ export function ProductUomSection({
388
398
  onChange={(event) =>
389
399
  setValue(
390
400
  "defaultSalesUnitQuantity",
391
- normalizeDecimalInput(event.target.value),
401
+ normalizeDecimalInput(event.target.value, locale),
392
402
  )
393
403
  }
394
404
  placeholder="1"
@@ -541,7 +551,7 @@ export function ProductUomSection({
541
551
  onChange={(event) =>
542
552
  setValue(
543
553
  "unitPriceBaseQuantity",
544
- normalizeDecimalInput(event.target.value),
554
+ normalizeDecimalInput(event.target.value, locale),
545
555
  )
546
556
  }
547
557
  placeholder="1"
@@ -595,7 +605,7 @@ export function ProductUomSection({
595
605
  ) : (
596
606
  <div className="space-y-2">
597
607
  {conversions.map((entry, index) => {
598
- const conversionFactor = toPositiveNumber(entry.toBaseFactor);
608
+ const conversionFactor = toPositiveNumber(entry.toBaseFactor, locale);
599
609
  const conversionPreviewText =
600
610
  entry.unitCode && conversionFactor !== null
601
611
  ? t(
@@ -653,7 +663,7 @@ export function ProductUomSection({
653
663
  value={entry.toBaseFactor}
654
664
  onChange={(event) =>
655
665
  updateConversion(index, {
656
- toBaseFactor: normalizeDecimalInput(event.target.value),
666
+ toBaseFactor: normalizeDecimalInput(event.target.value, locale),
657
667
  })
658
668
  }
659
669
  placeholder="1"