@open-mercato/core 0.7.1-develop.7200.1.8ba2d93d3f → 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.
- package/dist/modules/catalog/components/products/ProductUomSection.js +27 -22
- package/dist/modules/catalog/components/products/ProductUomSection.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentDialog.js +14 -11
- package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
- package/dist/modules/wms/components/backend/AdjustInventoryDialog.js +8 -6
- package/dist/modules/wms/components/backend/AdjustInventoryDialog.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/catalog/components/products/ProductUomSection.tsx +31 -21
- package/src/modules/sales/components/documents/PaymentDialog.tsx +18 -11
- package/src/modules/sales/i18n/de.json +1 -0
- package/src/modules/sales/i18n/en.json +1 -0
- package/src/modules/sales/i18n/es.json +1 -0
- package/src/modules/sales/i18n/ko.json +1 -0
- package/src/modules/sales/i18n/pl.json +1 -0
- package/src/modules/wms/components/backend/AdjustInventoryDialog.tsx +6 -5
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
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";
|
|
@@ -32,18 +33,19 @@ const REFERENCE_UNIT_OPTIONS = REFERENCE_UNIT_CODES.map((code) => ({
|
|
|
32
33
|
i18nKey: `catalog.products.unitPrice.options.${code}`,
|
|
33
34
|
fallback: REFERENCE_UNIT_DISPLAY[code] ?? code
|
|
34
35
|
}));
|
|
35
|
-
function normalizeDecimalInput(value) {
|
|
36
|
-
|
|
36
|
+
function normalizeDecimalInput(value, locale) {
|
|
37
|
+
const parsed = parseLocaleNumber(value, locale);
|
|
38
|
+
return parsed === null ? value : String(parsed);
|
|
37
39
|
}
|
|
38
|
-
function toPositiveNumber(value) {
|
|
40
|
+
function toPositiveNumber(value, locale) {
|
|
39
41
|
if (typeof value === "number") {
|
|
40
42
|
return Number.isFinite(value) && value > 0 ? value : null;
|
|
41
43
|
}
|
|
42
44
|
if (typeof value !== "string") return null;
|
|
43
45
|
const normalized = toTrimmedOrNull(value);
|
|
44
46
|
if (!normalized) return null;
|
|
45
|
-
const numeric =
|
|
46
|
-
return
|
|
47
|
+
const numeric = parseLocaleNumber(normalized, locale);
|
|
48
|
+
return numeric !== null && numeric > 0 ? numeric : null;
|
|
47
49
|
}
|
|
48
50
|
function toSortValue(value) {
|
|
49
51
|
const numeric = Number(value);
|
|
@@ -54,7 +56,7 @@ function formatPreviewNumber(value) {
|
|
|
54
56
|
const rounded = Math.round(value * 1e6) / 1e6;
|
|
55
57
|
return Number.isInteger(rounded) ? String(rounded) : rounded.toString();
|
|
56
58
|
}
|
|
57
|
-
function normalizeConversions(value) {
|
|
59
|
+
function normalizeConversions(value, locale) {
|
|
58
60
|
if (!Array.isArray(value)) return [];
|
|
59
61
|
const normalized = value.map((entry) => {
|
|
60
62
|
if (!entry || typeof entry !== "object") return null;
|
|
@@ -62,7 +64,7 @@ function normalizeConversions(value) {
|
|
|
62
64
|
return {
|
|
63
65
|
id: toTrimmedOrNull(row.id) ?? null,
|
|
64
66
|
unitCode: toTrimmedOrNull(row.unitCode) ?? "",
|
|
65
|
-
toBaseFactor: toTrimmedOrNull(row.toBaseFactor) ? normalizeDecimalInput(toTrimmedOrNull(row.toBaseFactor)) : "",
|
|
67
|
+
toBaseFactor: toTrimmedOrNull(row.toBaseFactor) ? normalizeDecimalInput(toTrimmedOrNull(row.toBaseFactor), locale) : "",
|
|
66
68
|
sortOrder: toTrimmedOrNull(row.sortOrder) ?? "",
|
|
67
69
|
isActive: row.isActive !== false
|
|
68
70
|
};
|
|
@@ -97,13 +99,14 @@ function ProductUomSection({
|
|
|
97
99
|
embedded = false
|
|
98
100
|
}) {
|
|
99
101
|
const t = useT();
|
|
102
|
+
const locale = useLocale();
|
|
100
103
|
const { enabled: unitPriceDisplayEnabled } = useUnitPriceDisplayEnabled();
|
|
101
104
|
const [unitOptions, setUnitOptions] = React.useState([]);
|
|
102
105
|
const [loadingUnits, setLoadingUnits] = React.useState(false);
|
|
103
106
|
const [errorLoadingUnits, setErrorLoadingUnits] = React.useState(false);
|
|
104
107
|
const conversions = React.useMemo(
|
|
105
|
-
() => normalizeConversions(values.unitConversions),
|
|
106
|
-
[values.unitConversions]
|
|
108
|
+
() => normalizeConversions(values.unitConversions, locale),
|
|
109
|
+
[values.unitConversions, locale]
|
|
107
110
|
);
|
|
108
111
|
React.useEffect(() => {
|
|
109
112
|
let cancelled = false;
|
|
@@ -191,11 +194,11 @@ function ProductUomSection({
|
|
|
191
194
|
const defaultUnit = toTrimmedOrNull(values.defaultUnit) ?? "";
|
|
192
195
|
const defaultSalesUnit = toTrimmedOrNull(values.defaultSalesUnit) ?? "";
|
|
193
196
|
const defaultSalesQuantityRaw = toTrimmedOrNull(values.defaultSalesUnitQuantity) ?? "1";
|
|
194
|
-
const defaultSalesQuantity = normalizeDecimalInput(defaultSalesQuantityRaw);
|
|
197
|
+
const defaultSalesQuantity = normalizeDecimalInput(defaultSalesQuantityRaw, locale);
|
|
195
198
|
const unitPriceEnabled = Boolean(values.unitPriceEnabled);
|
|
196
199
|
const unitPriceReferenceUnit = toTrimmedOrNull(values.unitPriceReferenceUnit) ?? "";
|
|
197
200
|
const unitPriceBaseQuantityRaw = toTrimmedOrNull(values.unitPriceBaseQuantity) ?? "";
|
|
198
|
-
const unitPriceBaseQuantity = normalizeDecimalInput(unitPriceBaseQuantityRaw);
|
|
201
|
+
const unitPriceBaseQuantity = normalizeDecimalInput(unitPriceBaseQuantityRaw, locale);
|
|
199
202
|
const baseUnitLabel = findUnitLabel(defaultUnit) ?? defaultUnit;
|
|
200
203
|
const salesUnitLabel = findUnitLabel(defaultSalesUnit || defaultUnit) ?? defaultSalesUnit ?? defaultUnit;
|
|
201
204
|
const defaultSalesFactor = React.useMemo(() => {
|
|
@@ -204,13 +207,13 @@ function ProductUomSection({
|
|
|
204
207
|
if (!defaultUnitKey || !defaultSalesKey) return null;
|
|
205
208
|
if (defaultSalesKey === defaultUnitKey) return 1;
|
|
206
209
|
const row = conversions.find(
|
|
207
|
-
(entry) => entry.isActive && entry.unitCode.toLowerCase() === defaultSalesKey && toPositiveNumber(entry.toBaseFactor) !== null
|
|
210
|
+
(entry) => entry.isActive && entry.unitCode.toLowerCase() === defaultSalesKey && toPositiveNumber(entry.toBaseFactor, locale) !== null
|
|
208
211
|
);
|
|
209
|
-
return row ? toPositiveNumber(row.toBaseFactor) : null;
|
|
210
|
-
}, [conversions, defaultSalesUnit, defaultUnit]);
|
|
211
|
-
const defaultSalesQuantityNumber = toPositiveNumber(defaultSalesQuantity);
|
|
212
|
+
return row ? toPositiveNumber(row.toBaseFactor, locale) : null;
|
|
213
|
+
}, [conversions, defaultSalesUnit, defaultUnit, locale]);
|
|
214
|
+
const defaultSalesQuantityNumber = toPositiveNumber(defaultSalesQuantity, locale);
|
|
212
215
|
const defaultSalesQuantityNormalized = defaultSalesQuantityNumber && defaultSalesFactor ? defaultSalesQuantityNumber * defaultSalesFactor : null;
|
|
213
|
-
const unitPriceBaseQuantityNumber = toPositiveNumber(unitPriceBaseQuantity);
|
|
216
|
+
const unitPriceBaseQuantityNumber = toPositiveNumber(unitPriceBaseQuantity, locale);
|
|
214
217
|
const validConversions = conversions.filter(
|
|
215
218
|
(entry) => toTrimmedOrNull(entry.unitCode) && toTrimmedOrNull(entry.toBaseFactor)
|
|
216
219
|
);
|
|
@@ -288,7 +291,7 @@ function ProductUomSection({
|
|
|
288
291
|
value: defaultSalesQuantity,
|
|
289
292
|
onChange: (event) => setValue(
|
|
290
293
|
"defaultSalesUnitQuantity",
|
|
291
|
-
normalizeDecimalInput(event.target.value)
|
|
294
|
+
normalizeDecimalInput(event.target.value, locale)
|
|
292
295
|
),
|
|
293
296
|
placeholder: "1"
|
|
294
297
|
}
|
|
@@ -418,7 +421,7 @@ function ProductUomSection({
|
|
|
418
421
|
value: unitPriceBaseQuantity,
|
|
419
422
|
onChange: (event) => setValue(
|
|
420
423
|
"unitPriceBaseQuantity",
|
|
421
|
-
normalizeDecimalInput(event.target.value)
|
|
424
|
+
normalizeDecimalInput(event.target.value, locale)
|
|
422
425
|
),
|
|
423
426
|
placeholder: "1"
|
|
424
427
|
}
|
|
@@ -458,7 +461,7 @@ function ProductUomSection({
|
|
|
458
461
|
"catalog.products.uom.emptyConversions",
|
|
459
462
|
"No conversions configured yet."
|
|
460
463
|
) }) : /* @__PURE__ */ jsx("div", { className: "space-y-2", children: conversions.map((entry, index) => {
|
|
461
|
-
const conversionFactor = toPositiveNumber(entry.toBaseFactor);
|
|
464
|
+
const conversionFactor = toPositiveNumber(entry.toBaseFactor, locale);
|
|
462
465
|
const conversionPreviewText = entry.unitCode && conversionFactor !== null ? t(
|
|
463
466
|
"catalog.products.uom.conversionPreview",
|
|
464
467
|
"1 {{fromUnit}} = {{factor}} {{baseUnit}}",
|
|
@@ -501,7 +504,7 @@ function ProductUomSection({
|
|
|
501
504
|
inputMode: "decimal",
|
|
502
505
|
value: entry.toBaseFactor,
|
|
503
506
|
onChange: (event) => updateConversion(index, {
|
|
504
|
-
toBaseFactor: normalizeDecimalInput(event.target.value)
|
|
507
|
+
toBaseFactor: normalizeDecimalInput(event.target.value, locale)
|
|
505
508
|
}),
|
|
506
509
|
placeholder: "1"
|
|
507
510
|
}
|
|
@@ -593,6 +596,8 @@ function ProductUomSection({
|
|
|
593
596
|
);
|
|
594
597
|
}
|
|
595
598
|
export {
|
|
596
|
-
ProductUomSection
|
|
599
|
+
ProductUomSection,
|
|
600
|
+
normalizeDecimalInput,
|
|
601
|
+
toPositiveNumber
|
|
597
602
|
};
|
|
598
603
|
//# sourceMappingURL=ProductUomSection.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/catalog/components/products/ProductUomSection.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\";\n\nimport * as React from \"react\";\nimport { useT } from \"@open-mercato/shared/lib/i18n/context\";\nimport { apiCall } from \"@open-mercato/ui/backend/utils/apiCall\";\nimport { Button } from \"@open-mercato/ui/primitives/button\";\nimport { Checkbox } from \"@open-mercato/ui/primitives/checkbox\";\nimport { Input } from \"@open-mercato/ui/primitives/input\";\nimport { Label } from \"@open-mercato/ui/primitives/label\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@open-mercato/ui/primitives/select\";\nimport { Spinner } from \"@open-mercato/ui/primitives/spinner\";\nimport { ArrowDown, ArrowUp, Plus, Trash2 } from \"lucide-react\";\nimport type {\n ProductFormValues,\n ProductUnitConversionDraft,\n} from \"./productForm\";\nimport { createProductUnitConversionDraft } from \"./productForm\";\nimport { REFERENCE_UNIT_CODES } from \"@open-mercato/shared/lib/units/unitCodes\";\nimport { toTrimmedOrNull } from \"./productFormUtils\";\nimport { useUnitPriceDisplayEnabled } from \"./hooks/useUnitPriceDisplayEnabled\";\n\ntype UnitDictionaryEntry = {\n id?: string;\n value?: string;\n label?: string;\n};\n\ntype UnitDictionaryResponse = {\n entries?: UnitDictionaryEntry[];\n};\n\ntype UnitOption = {\n value: string;\n label: string;\n};\n\ntype ProductUomSectionProps = {\n values: ProductFormValues;\n errors: Record<string, string>;\n setValue: (id: string, value: unknown) => void;\n embedded?: boolean;\n};\n\nconst REFERENCE_UNIT_DISPLAY: Record<string, string> = {\n kg: \"1 kg\", l: \"1 l\", m2: \"1 m\\u00B2\", m3: \"1 m\\u00B3\", pc: \"1 pc\",\n};\nconst REFERENCE_UNIT_OPTIONS = REFERENCE_UNIT_CODES.map((code) => ({\n value: code,\n i18nKey: `catalog.products.unitPrice.options.${code}` as const,\n fallback: REFERENCE_UNIT_DISPLAY[code] ?? code,\n}));\n\nfunction normalizeDecimalInput(value: string): string {\n return value.replace(/,/g, \".\");\n}\n\nfunction toPositiveNumber(value: unknown): number | null {\n if (typeof value === \"number\") {\n return Number.isFinite(value) && value > 0 ? value : null;\n }\n if (typeof value !== \"string\") return null;\n const normalized = toTrimmedOrNull(value);\n if (!normalized) return null;\n const numeric = Number(normalized.replace(\",\", \".\"));\n return Number.isFinite(numeric) && numeric > 0 ? numeric : null;\n}\n\nfunction toSortValue(value: string): number {\n const numeric = Number(value);\n return Number.isFinite(numeric) ? numeric : Number.MAX_SAFE_INTEGER;\n}\n\nfunction formatPreviewNumber(value: number): string {\n if (!Number.isFinite(value)) return \"0\";\n const rounded = Math.round(value * 1_000_000) / 1_000_000;\n return Number.isInteger(rounded) ? String(rounded) : rounded.toString();\n}\n\nfunction normalizeConversions(value: unknown): ProductUnitConversionDraft[] {\n if (!Array.isArray(value)) return [];\n const normalized = value\n .map((entry) => {\n if (!entry || typeof entry !== \"object\") return null;\n const row = entry as ProductUnitConversionDraft;\n return {\n id: toTrimmedOrNull(row.id) ?? null,\n unitCode: toTrimmedOrNull(row.unitCode) ?? \"\",\n toBaseFactor: toTrimmedOrNull(row.toBaseFactor)\n ? normalizeDecimalInput(toTrimmedOrNull(row.toBaseFactor) as string)\n : \"\",\n sortOrder: toTrimmedOrNull(row.sortOrder) ?? \"\",\n isActive: row.isActive !== false,\n } satisfies ProductUnitConversionDraft;\n })\n .filter((entry): entry is ProductUnitConversionDraft => Boolean(entry));\n normalized.sort((left, right) => {\n const leftOrder = toSortValue(left.sortOrder);\n const rightOrder = toSortValue(right.sortOrder);\n if (leftOrder === rightOrder) return left.unitCode.localeCompare(right.unitCode);\n return leftOrder - rightOrder;\n });\n return normalized.map((entry, index) => ({\n ...entry,\n sortOrder: String((index + 1) * 10),\n }));\n}\n\nfunction buildUnitOptions(\n entries: UnitDictionaryEntry[] | undefined,\n): UnitOption[] {\n const list = Array.isArray(entries) ? entries : [];\n const options = list\n .map((entry) => {\n const value = toTrimmedOrNull(entry.value);\n if (!value) return null;\n return {\n value,\n label: toTrimmedOrNull(entry.label) ?? value,\n } satisfies UnitOption;\n })\n .filter((entry): entry is UnitOption => Boolean(entry));\n return options.sort((left, right) => left.label.localeCompare(right.label));\n}\n\nexport function ProductUomSection({\n values,\n errors,\n setValue,\n embedded = false,\n}: ProductUomSectionProps) {\n const t = useT();\n const { enabled: unitPriceDisplayEnabled } = useUnitPriceDisplayEnabled();\n const [unitOptions, setUnitOptions] = React.useState<UnitOption[]>([]);\n const [loadingUnits, setLoadingUnits] = React.useState(false);\n const [errorLoadingUnits, setErrorLoadingUnits] = React.useState(false);\n const conversions = React.useMemo(\n () => normalizeConversions(values.unitConversions),\n [values.unitConversions],\n );\n\n React.useEffect(() => {\n let cancelled = false;\n async function loadUnits() {\n setLoadingUnits(true);\n setErrorLoadingUnits(false);\n try {\n const response = await apiCall<UnitDictionaryResponse>(\n \"/api/catalog/dictionaries/unit\",\n undefined,\n { fallback: { entries: [] } },\n );\n if (cancelled) return;\n setUnitOptions(buildUnitOptions(response.result?.entries));\n } catch {\n if (!cancelled) {\n setUnitOptions([]);\n setErrorLoadingUnits(true);\n }\n } finally {\n if (!cancelled) setLoadingUnits(false);\n }\n }\n void loadUnits();\n return () => {\n cancelled = true;\n };\n }, []);\n\n const findUnitLabel = React.useCallback(\n (value: string | null | undefined) => {\n const code = toTrimmedOrNull(value);\n if (!code) return null;\n const option = unitOptions.find((entry) => entry.value === code);\n return option?.label ?? code;\n },\n [unitOptions],\n );\n\n const setConversions = React.useCallback(\n (next: ProductUnitConversionDraft[]) => {\n const normalized = next.map((entry, index) => ({\n ...entry,\n sortOrder: String((index + 1) * 10),\n }));\n setValue(\"unitConversions\", normalized);\n },\n [setValue],\n );\n\n const addConversion = React.useCallback(() => {\n const next = [\n ...conversions,\n createProductUnitConversionDraft({\n sortOrder: String((conversions.length + 1) * 10),\n }),\n ];\n setConversions(next);\n }, [conversions, setConversions]);\n\n const updateConversion = React.useCallback(\n (index: number, patch: Partial<ProductUnitConversionDraft>) => {\n const next = conversions.map((entry, rowIndex) =>\n rowIndex === index ? { ...entry, ...patch } : entry,\n );\n setConversions(next);\n },\n [conversions, setConversions],\n );\n\n const removeConversion = React.useCallback(\n (index: number) => {\n const next = conversions.filter((_entry, rowIndex) => rowIndex !== index);\n setConversions(next);\n },\n [conversions, setConversions],\n );\n\n const moveConversion = React.useCallback(\n (index: number, direction: \"up\" | \"down\") => {\n const targetIndex = direction === \"up\" ? index - 1 : index + 1;\n if (targetIndex < 0 || targetIndex >= conversions.length) return;\n const next = [...conversions];\n const source = next[index];\n next[index] = next[targetIndex];\n next[targetIndex] = source;\n setConversions(next);\n },\n [conversions, setConversions],\n );\n\n const defaultUnit = toTrimmedOrNull(values.defaultUnit) ?? \"\";\n const defaultSalesUnit = toTrimmedOrNull(values.defaultSalesUnit) ?? \"\";\n const defaultSalesQuantityRaw =\n toTrimmedOrNull(values.defaultSalesUnitQuantity) ?? \"1\";\n const defaultSalesQuantity = normalizeDecimalInput(defaultSalesQuantityRaw);\n const unitPriceEnabled = Boolean(values.unitPriceEnabled);\n const unitPriceReferenceUnit =\n toTrimmedOrNull(values.unitPriceReferenceUnit) ?? \"\";\n const unitPriceBaseQuantityRaw =\n toTrimmedOrNull(values.unitPriceBaseQuantity) ?? \"\";\n const unitPriceBaseQuantity = normalizeDecimalInput(unitPriceBaseQuantityRaw);\n\n const baseUnitLabel = findUnitLabel(defaultUnit) ?? defaultUnit;\n const salesUnitLabel =\n findUnitLabel(defaultSalesUnit || defaultUnit) ??\n defaultSalesUnit ??\n defaultUnit;\n\n const defaultSalesFactor = React.useMemo(() => {\n const defaultUnitKey = defaultUnit.toLowerCase();\n const defaultSalesKey = (defaultSalesUnit || defaultUnit).toLowerCase();\n if (!defaultUnitKey || !defaultSalesKey) return null;\n if (defaultSalesKey === defaultUnitKey) return 1;\n const row = conversions.find(\n (entry) =>\n entry.isActive &&\n entry.unitCode.toLowerCase() === defaultSalesKey &&\n toPositiveNumber(entry.toBaseFactor) !== null,\n );\n return row ? toPositiveNumber(row.toBaseFactor) : null;\n }, [conversions, defaultSalesUnit, defaultUnit]);\n\n const defaultSalesQuantityNumber = toPositiveNumber(defaultSalesQuantity);\n const defaultSalesQuantityNormalized =\n defaultSalesQuantityNumber && defaultSalesFactor\n ? defaultSalesQuantityNumber * defaultSalesFactor\n : null;\n const unitPriceBaseQuantityNumber = toPositiveNumber(unitPriceBaseQuantity);\n\n const validConversions = conversions.filter(\n (entry) =>\n toTrimmedOrNull(entry.unitCode) && toTrimmedOrNull(entry.toBaseFactor),\n );\n const conversionPreviewItems = validConversions\n .slice(0, 3)\n .map((entry) => {\n const label = findUnitLabel(entry.unitCode) ?? entry.unitCode;\n const baseLabel = findUnitLabel(defaultUnit) ?? defaultUnit;\n const factor = toTrimmedOrNull(entry.toBaseFactor) ?? \"1\";\n return `1 ${label} = ${factor} ${baseLabel || t(\"catalog.products.uom.baseUnit\", \"base unit\")}`;\n });\n const conversionPreview =\n validConversions.length > 3\n ? `${conversionPreviewItems.join(\" \u2022 \")} (+${validConversions.length - 3})`\n : conversionPreviewItems.join(\" \u2022 \");\n\n return (\n <div\n className={\n embedded ? \"space-y-5\" : \"space-y-5 rounded-lg border bg-card p-4\"\n }\n >\n <div className=\"space-y-1\">\n <h3 className=\"text-sm font-semibold\">\n {t(\"catalog.products.uom.title\", \"Units of measure\")}\n </h3>\n <p className=\"text-xs text-muted-foreground\">\n {t(\n \"catalog.products.uom.description\",\n \"Set base unit, sales unit, and packaging conversions.\",\n )}\n </p>\n </div>\n\n {loadingUnits ? (\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <Spinner className=\"h-3 w-3\" />\n {t(\"catalog.products.uom.loadingUnits\", \"Loading units...\")}\n </div>\n ) : null}\n\n {errorLoadingUnits ? (\n <p className=\"text-xs text-destructive\">\n {t(\n \"catalog.products.uom.errors.loadUnits\",\n \"Failed to load units. Please try refreshing the page.\",\n )}\n </p>\n ) : null}\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-product-uom-base-unit\">{t(\"catalog.products.uom.baseUnit\", \"Base unit\")}</Label>\n <Select\n value={defaultUnit || undefined}\n onValueChange={(value) => setValue(\"defaultUnit\", value || null)}\n disabled={loadingUnits}\n >\n <SelectTrigger id=\"catalog-product-uom-base-unit\">\n <SelectValue placeholder={t(\"catalog.products.uom.selectUnit\", \"Select unit\")} />\n </SelectTrigger>\n <SelectContent>\n {unitOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {errors.defaultUnit ? (\n <p className=\"text-xs text-destructive\">{errors.defaultUnit}</p>\n ) : null}\n </div>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-product-uom-sales-unit\">\n {t(\"catalog.products.uom.defaultSalesUnit\", \"Default sales unit\")}\n </Label>\n <Select\n value={defaultSalesUnit || undefined}\n onValueChange={(value) => setValue(\"defaultSalesUnit\", value || null)}\n disabled={loadingUnits}\n >\n <SelectTrigger id=\"catalog-product-uom-sales-unit\">\n <SelectValue placeholder={t(\"catalog.products.uom.selectUnit\", \"Select unit\")} />\n </SelectTrigger>\n <SelectContent>\n {unitOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {errors.defaultSalesUnit ? (\n <p className=\"text-xs text-destructive\">{errors.defaultSalesUnit}</p>\n ) : null}\n </div>\n\n <div className=\"space-y-2 md:col-span-2\">\n <Label htmlFor=\"catalog-product-uom-default-sales-quantity\">\n {t(\n \"catalog.products.uom.defaultSalesQuantityLabel\",\n \"Default line quantity (in sales unit)\",\n )}\n </Label>\n <Input\n id=\"catalog-product-uom-default-sales-quantity\"\n type=\"text\"\n inputMode=\"decimal\"\n value={defaultSalesQuantity}\n onChange={(event) =>\n setValue(\n \"defaultSalesUnitQuantity\",\n normalizeDecimalInput(event.target.value),\n )\n }\n placeholder=\"1\"\n />\n <p className=\"text-xs text-muted-foreground\">\n {t(\n \"catalog.products.uom.defaultSalesQuantityHint\",\n \"Used to prefill quantity in quote/order lines. Value is interpreted in Default sales unit.\",\n )}\n </p>\n {defaultSalesQuantityNumber && salesUnitLabel ? (\n <p className=\"text-xs text-muted-foreground\">\n {defaultSalesQuantityNormalized && baseUnitLabel\n ? t(\n \"catalog.products.uom.defaultSalesQuantityPreviewWithNormalization\",\n \"Default line: {{quantity}} {{salesUnit}} (= {{normalized}} {{baseUnit}}).\",\n {\n quantity: formatPreviewNumber(defaultSalesQuantityNumber),\n salesUnit: salesUnitLabel,\n normalized: formatPreviewNumber(\n defaultSalesQuantityNormalized,\n ),\n baseUnit: baseUnitLabel,\n },\n )\n : t(\n \"catalog.products.uom.defaultSalesQuantityPreview\",\n \"Default line: {{quantity}} {{salesUnit}}.\",\n {\n quantity: formatPreviewNumber(defaultSalesQuantityNumber),\n salesUnit: salesUnitLabel,\n },\n )}\n </p>\n ) : null}\n {errors.defaultSalesUnitQuantity ? (\n <p className=\"text-xs text-destructive\">\n {errors.defaultSalesUnitQuantity}\n </p>\n ) : null}\n </div>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-product-uom-rounding-mode\">\n {t(\"catalog.products.uom.roundingMode\", \"Rounding mode\")}\n </Label>\n <Select\n value={values.uomRoundingMode ?? \"half_up\"}\n onValueChange={(value) => setValue(\"uomRoundingMode\", value)}\n >\n <SelectTrigger id=\"catalog-product-uom-rounding-mode\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"half_up\">\n {t(\"catalog.products.uom.roundingModeHalfUp\", \"Half up (default)\")}\n </SelectItem>\n <SelectItem value=\"down\">\n {t(\"catalog.products.uom.roundingModeDown\", \"Round down\")}\n </SelectItem>\n <SelectItem value=\"up\">\n {t(\"catalog.products.uom.roundingModeUp\", \"Round up\")}\n </SelectItem>\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-product-uom-rounding-scale\">\n {t(\"catalog.products.uom.roundingScale\", \"Rounding scale (decimal places)\")}\n </Label>\n <Input\n id=\"catalog-product-uom-rounding-scale\"\n type=\"number\"\n min={0}\n max={6}\n value={values.uomRoundingScale ?? 4}\n onChange={(event) => {\n const parsed = Number.parseInt(event.target.value, 10);\n setValue(\"uomRoundingScale\", Number.isFinite(parsed) ? Math.max(0, Math.min(6, parsed)) : 4);\n }}\n />\n </div>\n </div>\n\n {unitPriceDisplayEnabled ? (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Checkbox\n id=\"catalog-product-unit-price-enabled\"\n checked={unitPriceEnabled}\n onCheckedChange={(checked) =>\n setValue(\"unitPriceEnabled\", checked === true)\n }\n />\n <Label\n htmlFor=\"catalog-product-unit-price-enabled\"\n className=\"text-sm\"\n >\n {t(\n \"catalog.products.unitPrice.enable\",\n \"Enable EU unit price display\",\n )}\n </Label>\n </div>\n\n {unitPriceEnabled ? (\n <div className=\"grid gap-3 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-product-uom-reference-unit\">\n {t(\n \"catalog.products.unitPrice.referenceUnit\",\n \"Reference unit\",\n )}\n </Label>\n <Select\n value={unitPriceReferenceUnit || undefined}\n onValueChange={(value) => setValue(\"unitPriceReferenceUnit\", value || null)}\n >\n <SelectTrigger id=\"catalog-product-uom-reference-unit\">\n <SelectValue\n placeholder={t(\n \"catalog.products.unitPrice.selectReferenceUnit\",\n \"Select reference unit\",\n )}\n />\n </SelectTrigger>\n <SelectContent>\n {REFERENCE_UNIT_OPTIONS.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {t(option.i18nKey, option.fallback)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-product-uom-unit-price-base-quantity\">\n {t(\n \"catalog.products.unitPrice.baseQuantity\",\n \"Reference quantity (in base unit)\",\n )}\n </Label>\n <Input\n id=\"catalog-product-uom-unit-price-base-quantity\"\n type=\"text\"\n inputMode=\"decimal\"\n value={unitPriceBaseQuantity}\n onChange={(event) =>\n setValue(\n \"unitPriceBaseQuantity\",\n normalizeDecimalInput(event.target.value),\n )\n }\n placeholder=\"1\"\n />\n </div>\n </div>\n ) : null}\n {unitPriceEnabled ? (\n <p className=\"text-xs text-muted-foreground\">\n {unitPriceReferenceUnit && unitPriceBaseQuantityNumber\n ? t(\n \"catalog.products.unitPrice.hintWithPreview\",\n \"Show calculated price per {{quantity}} {{unit}}. For most products use 1 (for example: 1 kg, 1 l, 1 m\u00B2).\",\n {\n quantity: formatPreviewNumber(unitPriceBaseQuantityNumber),\n unit: unitPriceReferenceUnit,\n },\n )\n : t(\n \"catalog.products.unitPrice.hint\",\n \"Show calculated price per selected reference unit. In most cases set quantity to 1.\",\n )}\n </p>\n ) : null}\n </div>\n ) : null}\n\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-2\">\n <Label className=\"text-sm\">\n {t(\"catalog.products.uom.conversions\", \"Product conversions\")}\n </Label>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={addConversion}\n >\n <Plus className=\"mr-1.5 h-4 w-4\" />\n {t(\"catalog.products.uom.addConversion\", \"Add conversion\")}\n </Button>\n </div>\n\n {conversions.length === 0 ? (\n <p className=\"text-xs text-muted-foreground\">\n {t(\n \"catalog.products.uom.emptyConversions\",\n \"No conversions configured yet.\",\n )}\n </p>\n ) : (\n <div className=\"space-y-2\">\n {conversions.map((entry, index) => {\n const conversionFactor = toPositiveNumber(entry.toBaseFactor);\n const conversionPreviewText =\n entry.unitCode && conversionFactor !== null\n ? t(\n \"catalog.products.uom.conversionPreview\",\n \"1 {{fromUnit}} = {{factor}} {{baseUnit}}\",\n {\n fromUnit: findUnitLabel(entry.unitCode) ?? entry.unitCode,\n factor: formatPreviewNumber(conversionFactor),\n baseUnit:\n findUnitLabel(defaultUnit) ??\n defaultUnit ??\n t(\"catalog.products.uom.baseUnit\", \"base unit\"),\n },\n )\n : null;\n\n return (\n <div\n key={entry.id ?? `uom-conversion-${index}`}\n className=\"grid gap-3 rounded-md border p-3 md:grid-cols-12\"\n >\n <div className=\"space-y-1 md:col-span-4\">\n <Label htmlFor={`catalog-product-uom-conversion-unit-${index}`} className=\"text-xs text-muted-foreground\">\n {t(\"catalog.products.uom.conversionUnit\", \"Sales unit\")}\n </Label>\n <Select\n value={entry.unitCode || undefined}\n onValueChange={(value) => updateConversion(index, { unitCode: value ?? '' })}\n disabled={loadingUnits}\n >\n <SelectTrigger id={`catalog-product-uom-conversion-unit-${index}`}>\n <SelectValue placeholder={t(\"catalog.products.uom.selectUnit\", \"Select unit\")} />\n </SelectTrigger>\n <SelectContent>\n {unitOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"space-y-1 md:col-span-3\">\n <Label htmlFor={`catalog-product-uom-conversion-factor-${index}`} className=\"text-xs text-muted-foreground\">\n {t(\n \"catalog.products.uom.toBaseFactor\",\n \"Base units per 1 sales unit\",\n )}\n </Label>\n <Input\n id={`catalog-product-uom-conversion-factor-${index}`}\n type=\"text\"\n inputMode=\"decimal\"\n value={entry.toBaseFactor}\n onChange={(event) =>\n updateConversion(index, {\n toBaseFactor: normalizeDecimalInput(event.target.value),\n })\n }\n placeholder=\"1\"\n />\n </div>\n\n <div className=\"flex items-end gap-2 md:col-span-3\">\n <div className=\"inline-flex h-9 rounded-md border\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-9 w-9 rounded-none border-r\"\n onClick={() => moveConversion(index, \"up\")}\n disabled={index === 0}\n aria-label={t(\n \"catalog.products.uom.moveUp\",\n \"Move conversion up\",\n )}\n >\n <ArrowUp className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-9 w-9 rounded-none\"\n onClick={() => moveConversion(index, \"down\")}\n disabled={index === conversions.length - 1}\n aria-label={t(\n \"catalog.products.uom.moveDown\",\n \"Move conversion down\",\n )}\n >\n <ArrowDown className=\"h-4 w-4\" />\n </Button>\n </div>\n <label\n htmlFor={`catalog-product-uom-conversion-active-${index}`}\n className=\"flex items-center gap-2 px-1 text-xs text-muted-foreground\"\n >\n <Checkbox\n id={`catalog-product-uom-conversion-active-${index}`}\n checked={entry.isActive}\n onCheckedChange={(checked) =>\n updateConversion(index, { isActive: checked === true })\n }\n />\n {t(\"catalog.products.uom.active\", \"Active\")}\n </label>\n </div>\n\n <div className=\"flex items-end justify-end md:col-span-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"text-destructive\"\n onClick={() => removeConversion(index)}\n aria-label={t(\n \"catalog.products.uom.removeConversion\",\n \"Remove conversion\",\n )}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n\n {conversionPreviewText && (\n <p className=\"text-xs text-muted-foreground md:col-span-12\">\n {conversionPreviewText}\n </p>\n )}\n </div>\n );\n })}\n </div>\n )}\n\n {conversions.length > 1 ? (\n <p className=\"text-xs text-muted-foreground\">\n {t(\n \"catalog.products.uom.conversionOrderHint\",\n \"Use arrows to reorder conversion priority.\",\n )}\n </p>\n ) : null}\n\n {conversionPreview ? (\n <p className=\"text-xs text-muted-foreground\">{conversionPreview}</p>\n ) : null}\n </div>\n </div>\n );\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\";\n\nimport * as React from \"react\";\nimport { useT, useLocale } from \"@open-mercato/shared/lib/i18n/context\";\nimport { parseLocaleNumber } from \"@open-mercato/shared/lib/number\";\nimport { apiCall } from \"@open-mercato/ui/backend/utils/apiCall\";\nimport { Button } from \"@open-mercato/ui/primitives/button\";\nimport { Checkbox } from \"@open-mercato/ui/primitives/checkbox\";\nimport { Input } from \"@open-mercato/ui/primitives/input\";\nimport { Label } from \"@open-mercato/ui/primitives/label\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@open-mercato/ui/primitives/select\";\nimport { Spinner } from \"@open-mercato/ui/primitives/spinner\";\nimport { ArrowDown, ArrowUp, Plus, Trash2 } from \"lucide-react\";\nimport type {\n ProductFormValues,\n ProductUnitConversionDraft,\n} from \"./productForm\";\nimport { createProductUnitConversionDraft } from \"./productForm\";\nimport { REFERENCE_UNIT_CODES } from \"@open-mercato/shared/lib/units/unitCodes\";\nimport { toTrimmedOrNull } from \"./productFormUtils\";\nimport { useUnitPriceDisplayEnabled } from \"./hooks/useUnitPriceDisplayEnabled\";\n\ntype UnitDictionaryEntry = {\n id?: string;\n value?: string;\n label?: string;\n};\n\ntype UnitDictionaryResponse = {\n entries?: UnitDictionaryEntry[];\n};\n\ntype UnitOption = {\n value: string;\n label: string;\n};\n\ntype ProductUomSectionProps = {\n values: ProductFormValues;\n errors: Record<string, string>;\n setValue: (id: string, value: unknown) => void;\n embedded?: boolean;\n};\n\nconst REFERENCE_UNIT_DISPLAY: Record<string, string> = {\n kg: \"1 kg\", l: \"1 l\", m2: \"1 m\\u00B2\", m3: \"1 m\\u00B3\", pc: \"1 pc\",\n};\nconst REFERENCE_UNIT_OPTIONS = REFERENCE_UNIT_CODES.map((code) => ({\n value: code,\n i18nKey: `catalog.products.unitPrice.options.${code}` as const,\n fallback: REFERENCE_UNIT_DISPLAY[code] ?? code,\n}));\n\n// Keeps the field submit-ready (dot-decimal, no grouping characters) while the user is\n// still typing. Falls back to the raw value when it isn't parseable yet (empty, a lone\n// sign) so the field stays editable. Delegates to `parseLocaleNumber` instead of a\n// hard-coded `,` -> `.` swap, which broke on grouped input such as `1 234,56` (#5828).\nexport function normalizeDecimalInput(value: string, locale?: string): string {\n const parsed = parseLocaleNumber(value, locale);\n return parsed === null ? value : String(parsed);\n}\n\nexport function toPositiveNumber(value: unknown, locale?: string): number | null {\n if (typeof value === \"number\") {\n return Number.isFinite(value) && value > 0 ? value : null;\n }\n if (typeof value !== \"string\") return null;\n const normalized = toTrimmedOrNull(value);\n if (!normalized) return null;\n const numeric = parseLocaleNumber(normalized, locale);\n return numeric !== null && numeric > 0 ? numeric : null;\n}\n\nfunction toSortValue(value: string): number {\n const numeric = Number(value);\n return Number.isFinite(numeric) ? numeric : Number.MAX_SAFE_INTEGER;\n}\n\nfunction formatPreviewNumber(value: number): string {\n if (!Number.isFinite(value)) return \"0\";\n const rounded = Math.round(value * 1_000_000) / 1_000_000;\n return Number.isInteger(rounded) ? String(rounded) : rounded.toString();\n}\n\nfunction normalizeConversions(\n value: unknown,\n locale?: string,\n): ProductUnitConversionDraft[] {\n if (!Array.isArray(value)) return [];\n const normalized = value\n .map((entry) => {\n if (!entry || typeof entry !== \"object\") return null;\n const row = entry as ProductUnitConversionDraft;\n return {\n id: toTrimmedOrNull(row.id) ?? null,\n unitCode: toTrimmedOrNull(row.unitCode) ?? \"\",\n toBaseFactor: toTrimmedOrNull(row.toBaseFactor)\n ? normalizeDecimalInput(toTrimmedOrNull(row.toBaseFactor) as string, locale)\n : \"\",\n sortOrder: toTrimmedOrNull(row.sortOrder) ?? \"\",\n isActive: row.isActive !== false,\n } satisfies ProductUnitConversionDraft;\n })\n .filter((entry): entry is ProductUnitConversionDraft => Boolean(entry));\n normalized.sort((left, right) => {\n const leftOrder = toSortValue(left.sortOrder);\n const rightOrder = toSortValue(right.sortOrder);\n if (leftOrder === rightOrder) return left.unitCode.localeCompare(right.unitCode);\n return leftOrder - rightOrder;\n });\n return normalized.map((entry, index) => ({\n ...entry,\n sortOrder: String((index + 1) * 10),\n }));\n}\n\nfunction buildUnitOptions(\n entries: UnitDictionaryEntry[] | undefined,\n): UnitOption[] {\n const list = Array.isArray(entries) ? entries : [];\n const options = list\n .map((entry) => {\n const value = toTrimmedOrNull(entry.value);\n if (!value) return null;\n return {\n value,\n label: toTrimmedOrNull(entry.label) ?? value,\n } satisfies UnitOption;\n })\n .filter((entry): entry is UnitOption => Boolean(entry));\n return options.sort((left, right) => left.label.localeCompare(right.label));\n}\n\nexport function ProductUomSection({\n values,\n errors,\n setValue,\n embedded = false,\n}: ProductUomSectionProps) {\n const t = useT();\n const locale = useLocale();\n const { enabled: unitPriceDisplayEnabled } = useUnitPriceDisplayEnabled();\n const [unitOptions, setUnitOptions] = React.useState<UnitOption[]>([]);\n const [loadingUnits, setLoadingUnits] = React.useState(false);\n const [errorLoadingUnits, setErrorLoadingUnits] = React.useState(false);\n const conversions = React.useMemo(\n () => normalizeConversions(values.unitConversions, locale),\n [values.unitConversions, locale],\n );\n\n React.useEffect(() => {\n let cancelled = false;\n async function loadUnits() {\n setLoadingUnits(true);\n setErrorLoadingUnits(false);\n try {\n const response = await apiCall<UnitDictionaryResponse>(\n \"/api/catalog/dictionaries/unit\",\n undefined,\n { fallback: { entries: [] } },\n );\n if (cancelled) return;\n setUnitOptions(buildUnitOptions(response.result?.entries));\n } catch {\n if (!cancelled) {\n setUnitOptions([]);\n setErrorLoadingUnits(true);\n }\n } finally {\n if (!cancelled) setLoadingUnits(false);\n }\n }\n void loadUnits();\n return () => {\n cancelled = true;\n };\n }, []);\n\n const findUnitLabel = React.useCallback(\n (value: string | null | undefined) => {\n const code = toTrimmedOrNull(value);\n if (!code) return null;\n const option = unitOptions.find((entry) => entry.value === code);\n return option?.label ?? code;\n },\n [unitOptions],\n );\n\n const setConversions = React.useCallback(\n (next: ProductUnitConversionDraft[]) => {\n const normalized = next.map((entry, index) => ({\n ...entry,\n sortOrder: String((index + 1) * 10),\n }));\n setValue(\"unitConversions\", normalized);\n },\n [setValue],\n );\n\n const addConversion = React.useCallback(() => {\n const next = [\n ...conversions,\n createProductUnitConversionDraft({\n sortOrder: String((conversions.length + 1) * 10),\n }),\n ];\n setConversions(next);\n }, [conversions, setConversions]);\n\n const updateConversion = React.useCallback(\n (index: number, patch: Partial<ProductUnitConversionDraft>) => {\n const next = conversions.map((entry, rowIndex) =>\n rowIndex === index ? { ...entry, ...patch } : entry,\n );\n setConversions(next);\n },\n [conversions, setConversions],\n );\n\n const removeConversion = React.useCallback(\n (index: number) => {\n const next = conversions.filter((_entry, rowIndex) => rowIndex !== index);\n setConversions(next);\n },\n [conversions, setConversions],\n );\n\n const moveConversion = React.useCallback(\n (index: number, direction: \"up\" | \"down\") => {\n const targetIndex = direction === \"up\" ? index - 1 : index + 1;\n if (targetIndex < 0 || targetIndex >= conversions.length) return;\n const next = [...conversions];\n const source = next[index];\n next[index] = next[targetIndex];\n next[targetIndex] = source;\n setConversions(next);\n },\n [conversions, setConversions],\n );\n\n const defaultUnit = toTrimmedOrNull(values.defaultUnit) ?? \"\";\n const defaultSalesUnit = toTrimmedOrNull(values.defaultSalesUnit) ?? \"\";\n const defaultSalesQuantityRaw =\n toTrimmedOrNull(values.defaultSalesUnitQuantity) ?? \"1\";\n const defaultSalesQuantity = normalizeDecimalInput(defaultSalesQuantityRaw, locale);\n const unitPriceEnabled = Boolean(values.unitPriceEnabled);\n const unitPriceReferenceUnit =\n toTrimmedOrNull(values.unitPriceReferenceUnit) ?? \"\";\n const unitPriceBaseQuantityRaw =\n toTrimmedOrNull(values.unitPriceBaseQuantity) ?? \"\";\n const unitPriceBaseQuantity = normalizeDecimalInput(unitPriceBaseQuantityRaw, locale);\n\n const baseUnitLabel = findUnitLabel(defaultUnit) ?? defaultUnit;\n const salesUnitLabel =\n findUnitLabel(defaultSalesUnit || defaultUnit) ??\n defaultSalesUnit ??\n defaultUnit;\n\n const defaultSalesFactor = React.useMemo(() => {\n const defaultUnitKey = defaultUnit.toLowerCase();\n const defaultSalesKey = (defaultSalesUnit || defaultUnit).toLowerCase();\n if (!defaultUnitKey || !defaultSalesKey) return null;\n if (defaultSalesKey === defaultUnitKey) return 1;\n const row = conversions.find(\n (entry) =>\n entry.isActive &&\n entry.unitCode.toLowerCase() === defaultSalesKey &&\n toPositiveNumber(entry.toBaseFactor, locale) !== null,\n );\n return row ? toPositiveNumber(row.toBaseFactor, locale) : null;\n }, [conversions, defaultSalesUnit, defaultUnit, locale]);\n\n const defaultSalesQuantityNumber = toPositiveNumber(defaultSalesQuantity, locale);\n const defaultSalesQuantityNormalized =\n defaultSalesQuantityNumber && defaultSalesFactor\n ? defaultSalesQuantityNumber * defaultSalesFactor\n : null;\n const unitPriceBaseQuantityNumber = toPositiveNumber(unitPriceBaseQuantity, locale);\n\n const validConversions = conversions.filter(\n (entry) =>\n toTrimmedOrNull(entry.unitCode) && toTrimmedOrNull(entry.toBaseFactor),\n );\n const conversionPreviewItems = validConversions\n .slice(0, 3)\n .map((entry) => {\n const label = findUnitLabel(entry.unitCode) ?? entry.unitCode;\n const baseLabel = findUnitLabel(defaultUnit) ?? defaultUnit;\n const factor = toTrimmedOrNull(entry.toBaseFactor) ?? \"1\";\n return `1 ${label} = ${factor} ${baseLabel || t(\"catalog.products.uom.baseUnit\", \"base unit\")}`;\n });\n const conversionPreview =\n validConversions.length > 3\n ? `${conversionPreviewItems.join(\" \u2022 \")} (+${validConversions.length - 3})`\n : conversionPreviewItems.join(\" \u2022 \");\n\n return (\n <div\n className={\n embedded ? \"space-y-5\" : \"space-y-5 rounded-lg border bg-card p-4\"\n }\n >\n <div className=\"space-y-1\">\n <h3 className=\"text-sm font-semibold\">\n {t(\"catalog.products.uom.title\", \"Units of measure\")}\n </h3>\n <p className=\"text-xs text-muted-foreground\">\n {t(\n \"catalog.products.uom.description\",\n \"Set base unit, sales unit, and packaging conversions.\",\n )}\n </p>\n </div>\n\n {loadingUnits ? (\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <Spinner className=\"h-3 w-3\" />\n {t(\"catalog.products.uom.loadingUnits\", \"Loading units...\")}\n </div>\n ) : null}\n\n {errorLoadingUnits ? (\n <p className=\"text-xs text-destructive\">\n {t(\n \"catalog.products.uom.errors.loadUnits\",\n \"Failed to load units. Please try refreshing the page.\",\n )}\n </p>\n ) : null}\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-product-uom-base-unit\">{t(\"catalog.products.uom.baseUnit\", \"Base unit\")}</Label>\n <Select\n value={defaultUnit || undefined}\n onValueChange={(value) => setValue(\"defaultUnit\", value || null)}\n disabled={loadingUnits}\n >\n <SelectTrigger id=\"catalog-product-uom-base-unit\">\n <SelectValue placeholder={t(\"catalog.products.uom.selectUnit\", \"Select unit\")} />\n </SelectTrigger>\n <SelectContent>\n {unitOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {errors.defaultUnit ? (\n <p className=\"text-xs text-destructive\">{errors.defaultUnit}</p>\n ) : null}\n </div>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-product-uom-sales-unit\">\n {t(\"catalog.products.uom.defaultSalesUnit\", \"Default sales unit\")}\n </Label>\n <Select\n value={defaultSalesUnit || undefined}\n onValueChange={(value) => setValue(\"defaultSalesUnit\", value || null)}\n disabled={loadingUnits}\n >\n <SelectTrigger id=\"catalog-product-uom-sales-unit\">\n <SelectValue placeholder={t(\"catalog.products.uom.selectUnit\", \"Select unit\")} />\n </SelectTrigger>\n <SelectContent>\n {unitOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {errors.defaultSalesUnit ? (\n <p className=\"text-xs text-destructive\">{errors.defaultSalesUnit}</p>\n ) : null}\n </div>\n\n <div className=\"space-y-2 md:col-span-2\">\n <Label htmlFor=\"catalog-product-uom-default-sales-quantity\">\n {t(\n \"catalog.products.uom.defaultSalesQuantityLabel\",\n \"Default line quantity (in sales unit)\",\n )}\n </Label>\n <Input\n id=\"catalog-product-uom-default-sales-quantity\"\n type=\"text\"\n inputMode=\"decimal\"\n value={defaultSalesQuantity}\n onChange={(event) =>\n setValue(\n \"defaultSalesUnitQuantity\",\n normalizeDecimalInput(event.target.value, locale),\n )\n }\n placeholder=\"1\"\n />\n <p className=\"text-xs text-muted-foreground\">\n {t(\n \"catalog.products.uom.defaultSalesQuantityHint\",\n \"Used to prefill quantity in quote/order lines. Value is interpreted in Default sales unit.\",\n )}\n </p>\n {defaultSalesQuantityNumber && salesUnitLabel ? (\n <p className=\"text-xs text-muted-foreground\">\n {defaultSalesQuantityNormalized && baseUnitLabel\n ? t(\n \"catalog.products.uom.defaultSalesQuantityPreviewWithNormalization\",\n \"Default line: {{quantity}} {{salesUnit}} (= {{normalized}} {{baseUnit}}).\",\n {\n quantity: formatPreviewNumber(defaultSalesQuantityNumber),\n salesUnit: salesUnitLabel,\n normalized: formatPreviewNumber(\n defaultSalesQuantityNormalized,\n ),\n baseUnit: baseUnitLabel,\n },\n )\n : t(\n \"catalog.products.uom.defaultSalesQuantityPreview\",\n \"Default line: {{quantity}} {{salesUnit}}.\",\n {\n quantity: formatPreviewNumber(defaultSalesQuantityNumber),\n salesUnit: salesUnitLabel,\n },\n )}\n </p>\n ) : null}\n {errors.defaultSalesUnitQuantity ? (\n <p className=\"text-xs text-destructive\">\n {errors.defaultSalesUnitQuantity}\n </p>\n ) : null}\n </div>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-product-uom-rounding-mode\">\n {t(\"catalog.products.uom.roundingMode\", \"Rounding mode\")}\n </Label>\n <Select\n value={values.uomRoundingMode ?? \"half_up\"}\n onValueChange={(value) => setValue(\"uomRoundingMode\", value)}\n >\n <SelectTrigger id=\"catalog-product-uom-rounding-mode\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"half_up\">\n {t(\"catalog.products.uom.roundingModeHalfUp\", \"Half up (default)\")}\n </SelectItem>\n <SelectItem value=\"down\">\n {t(\"catalog.products.uom.roundingModeDown\", \"Round down\")}\n </SelectItem>\n <SelectItem value=\"up\">\n {t(\"catalog.products.uom.roundingModeUp\", \"Round up\")}\n </SelectItem>\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-product-uom-rounding-scale\">\n {t(\"catalog.products.uom.roundingScale\", \"Rounding scale (decimal places)\")}\n </Label>\n <Input\n id=\"catalog-product-uom-rounding-scale\"\n type=\"number\"\n min={0}\n max={6}\n value={values.uomRoundingScale ?? 4}\n onChange={(event) => {\n const parsed = Number.parseInt(event.target.value, 10);\n setValue(\"uomRoundingScale\", Number.isFinite(parsed) ? Math.max(0, Math.min(6, parsed)) : 4);\n }}\n />\n </div>\n </div>\n\n {unitPriceDisplayEnabled ? (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Checkbox\n id=\"catalog-product-unit-price-enabled\"\n checked={unitPriceEnabled}\n onCheckedChange={(checked) =>\n setValue(\"unitPriceEnabled\", checked === true)\n }\n />\n <Label\n htmlFor=\"catalog-product-unit-price-enabled\"\n className=\"text-sm\"\n >\n {t(\n \"catalog.products.unitPrice.enable\",\n \"Enable EU unit price display\",\n )}\n </Label>\n </div>\n\n {unitPriceEnabled ? (\n <div className=\"grid gap-3 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-product-uom-reference-unit\">\n {t(\n \"catalog.products.unitPrice.referenceUnit\",\n \"Reference unit\",\n )}\n </Label>\n <Select\n value={unitPriceReferenceUnit || undefined}\n onValueChange={(value) => setValue(\"unitPriceReferenceUnit\", value || null)}\n >\n <SelectTrigger id=\"catalog-product-uom-reference-unit\">\n <SelectValue\n placeholder={t(\n \"catalog.products.unitPrice.selectReferenceUnit\",\n \"Select reference unit\",\n )}\n />\n </SelectTrigger>\n <SelectContent>\n {REFERENCE_UNIT_OPTIONS.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {t(option.i18nKey, option.fallback)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-product-uom-unit-price-base-quantity\">\n {t(\n \"catalog.products.unitPrice.baseQuantity\",\n \"Reference quantity (in base unit)\",\n )}\n </Label>\n <Input\n id=\"catalog-product-uom-unit-price-base-quantity\"\n type=\"text\"\n inputMode=\"decimal\"\n value={unitPriceBaseQuantity}\n onChange={(event) =>\n setValue(\n \"unitPriceBaseQuantity\",\n normalizeDecimalInput(event.target.value, locale),\n )\n }\n placeholder=\"1\"\n />\n </div>\n </div>\n ) : null}\n {unitPriceEnabled ? (\n <p className=\"text-xs text-muted-foreground\">\n {unitPriceReferenceUnit && unitPriceBaseQuantityNumber\n ? t(\n \"catalog.products.unitPrice.hintWithPreview\",\n \"Show calculated price per {{quantity}} {{unit}}. For most products use 1 (for example: 1 kg, 1 l, 1 m\u00B2).\",\n {\n quantity: formatPreviewNumber(unitPriceBaseQuantityNumber),\n unit: unitPriceReferenceUnit,\n },\n )\n : t(\n \"catalog.products.unitPrice.hint\",\n \"Show calculated price per selected reference unit. In most cases set quantity to 1.\",\n )}\n </p>\n ) : null}\n </div>\n ) : null}\n\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-2\">\n <Label className=\"text-sm\">\n {t(\"catalog.products.uom.conversions\", \"Product conversions\")}\n </Label>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={addConversion}\n >\n <Plus className=\"mr-1.5 h-4 w-4\" />\n {t(\"catalog.products.uom.addConversion\", \"Add conversion\")}\n </Button>\n </div>\n\n {conversions.length === 0 ? (\n <p className=\"text-xs text-muted-foreground\">\n {t(\n \"catalog.products.uom.emptyConversions\",\n \"No conversions configured yet.\",\n )}\n </p>\n ) : (\n <div className=\"space-y-2\">\n {conversions.map((entry, index) => {\n const conversionFactor = toPositiveNumber(entry.toBaseFactor, locale);\n const conversionPreviewText =\n entry.unitCode && conversionFactor !== null\n ? t(\n \"catalog.products.uom.conversionPreview\",\n \"1 {{fromUnit}} = {{factor}} {{baseUnit}}\",\n {\n fromUnit: findUnitLabel(entry.unitCode) ?? entry.unitCode,\n factor: formatPreviewNumber(conversionFactor),\n baseUnit:\n findUnitLabel(defaultUnit) ??\n defaultUnit ??\n t(\"catalog.products.uom.baseUnit\", \"base unit\"),\n },\n )\n : null;\n\n return (\n <div\n key={entry.id ?? `uom-conversion-${index}`}\n className=\"grid gap-3 rounded-md border p-3 md:grid-cols-12\"\n >\n <div className=\"space-y-1 md:col-span-4\">\n <Label htmlFor={`catalog-product-uom-conversion-unit-${index}`} className=\"text-xs text-muted-foreground\">\n {t(\"catalog.products.uom.conversionUnit\", \"Sales unit\")}\n </Label>\n <Select\n value={entry.unitCode || undefined}\n onValueChange={(value) => updateConversion(index, { unitCode: value ?? '' })}\n disabled={loadingUnits}\n >\n <SelectTrigger id={`catalog-product-uom-conversion-unit-${index}`}>\n <SelectValue placeholder={t(\"catalog.products.uom.selectUnit\", \"Select unit\")} />\n </SelectTrigger>\n <SelectContent>\n {unitOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"space-y-1 md:col-span-3\">\n <Label htmlFor={`catalog-product-uom-conversion-factor-${index}`} className=\"text-xs text-muted-foreground\">\n {t(\n \"catalog.products.uom.toBaseFactor\",\n \"Base units per 1 sales unit\",\n )}\n </Label>\n <Input\n id={`catalog-product-uom-conversion-factor-${index}`}\n type=\"text\"\n inputMode=\"decimal\"\n value={entry.toBaseFactor}\n onChange={(event) =>\n updateConversion(index, {\n toBaseFactor: normalizeDecimalInput(event.target.value, locale),\n })\n }\n placeholder=\"1\"\n />\n </div>\n\n <div className=\"flex items-end gap-2 md:col-span-3\">\n <div className=\"inline-flex h-9 rounded-md border\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-9 w-9 rounded-none border-r\"\n onClick={() => moveConversion(index, \"up\")}\n disabled={index === 0}\n aria-label={t(\n \"catalog.products.uom.moveUp\",\n \"Move conversion up\",\n )}\n >\n <ArrowUp className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-9 w-9 rounded-none\"\n onClick={() => moveConversion(index, \"down\")}\n disabled={index === conversions.length - 1}\n aria-label={t(\n \"catalog.products.uom.moveDown\",\n \"Move conversion down\",\n )}\n >\n <ArrowDown className=\"h-4 w-4\" />\n </Button>\n </div>\n <label\n htmlFor={`catalog-product-uom-conversion-active-${index}`}\n className=\"flex items-center gap-2 px-1 text-xs text-muted-foreground\"\n >\n <Checkbox\n id={`catalog-product-uom-conversion-active-${index}`}\n checked={entry.isActive}\n onCheckedChange={(checked) =>\n updateConversion(index, { isActive: checked === true })\n }\n />\n {t(\"catalog.products.uom.active\", \"Active\")}\n </label>\n </div>\n\n <div className=\"flex items-end justify-end md:col-span-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"text-destructive\"\n onClick={() => removeConversion(index)}\n aria-label={t(\n \"catalog.products.uom.removeConversion\",\n \"Remove conversion\",\n )}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n\n {conversionPreviewText && (\n <p className=\"text-xs text-muted-foreground md:col-span-12\">\n {conversionPreviewText}\n </p>\n )}\n </div>\n );\n })}\n </div>\n )}\n\n {conversions.length > 1 ? (\n <p className=\"text-xs text-muted-foreground\">\n {t(\n \"catalog.products.uom.conversionOrderHint\",\n \"Use arrows to reorder conversion priority.\",\n )}\n </p>\n ) : null}\n\n {conversionPreview ? (\n <p className=\"text-xs text-muted-foreground\">{conversionPreview}</p>\n ) : null}\n </div>\n </div>\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -15,17 +15,16 @@ import { useDialogKeyHandler } from "@open-mercato/ui/hooks/useDialogKeyHandler"
|
|
|
15
15
|
import { Input } from "@open-mercato/ui/primitives/input";
|
|
16
16
|
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
17
17
|
import { E } from "../../../../generated/entities.ids.generated.js";
|
|
18
|
-
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
18
|
+
import { useT, useLocale } from "@open-mercato/shared/lib/i18n/context";
|
|
19
|
+
import { parseLocaleNumber } from "@open-mercato/shared/lib/number";
|
|
19
20
|
import { normalizeCustomFieldSubmitValue, extractCustomFieldValues } from "./customFieldHelpers.js";
|
|
20
21
|
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
21
22
|
const logger = createLogger("sales");
|
|
22
|
-
const
|
|
23
|
-
if (typeof value === "number"
|
|
24
|
-
if (typeof value
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
return 0;
|
|
23
|
+
const parseAmountInput = (value, locale) => {
|
|
24
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
25
|
+
if (typeof value !== "string") return 0;
|
|
26
|
+
if (!value.trim()) return 0;
|
|
27
|
+
return parseLocaleNumber(value, locale);
|
|
29
28
|
};
|
|
30
29
|
function PaymentDialog({
|
|
31
30
|
open,
|
|
@@ -40,6 +39,7 @@ function PaymentDialog({
|
|
|
40
39
|
onSaved
|
|
41
40
|
}) {
|
|
42
41
|
const t = useT();
|
|
42
|
+
const locale = useLocale();
|
|
43
43
|
const dialogContentRef = React.useRef(null);
|
|
44
44
|
const [formResetKey, setFormResetKey] = React.useState(0);
|
|
45
45
|
const [paymentMethods, setPaymentMethods] = React.useState([]);
|
|
@@ -261,9 +261,8 @@ function PaymentDialog({
|
|
|
261
261
|
/* @__PURE__ */ jsx(
|
|
262
262
|
Input,
|
|
263
263
|
{
|
|
264
|
-
type: "
|
|
264
|
+
type: "text",
|
|
265
265
|
inputMode: "decimal",
|
|
266
|
-
step: "0.01",
|
|
267
266
|
value: normalized,
|
|
268
267
|
onChange: (event) => setValue(event.target.value),
|
|
269
268
|
placeholder: "0.00"
|
|
@@ -397,10 +396,14 @@ function PaymentDialog({
|
|
|
397
396
|
const handleSubmit = React.useCallback(
|
|
398
397
|
async (values) => {
|
|
399
398
|
const resolvedCurrency = currencyCode ? currencyCode.toUpperCase() : "";
|
|
400
|
-
const amountValue =
|
|
399
|
+
const amountValue = parseAmountInput(values.amount, locale);
|
|
401
400
|
if (!resolvedCurrency.trim()) {
|
|
402
401
|
throw createCrudFormError(t("sales.documents.payments.currencyRequired", "Currency is required."));
|
|
403
402
|
}
|
|
403
|
+
if (amountValue === null) {
|
|
404
|
+
const message = t("sales.documents.payments.amountInvalid", "Enter the amount as a number.");
|
|
405
|
+
throw createCrudFormError(message, { amount: message });
|
|
406
|
+
}
|
|
404
407
|
if (amountValue <= 0) {
|
|
405
408
|
throw createCrudFormError(t("sales.documents.payments.amountRequired", "Enter a positive amount."), {
|
|
406
409
|
amount: t("sales.documents.payments.amountRequired", "Enter a positive amount.")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/sales/components/documents/PaymentDialog.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { CreditCard } from 'lucide-react'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { LookupSelect, type LookupSelectItem } from '@open-mercato/ui/backend/inputs'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { createCrud, updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { handleSectionMutationError } from './optimisticLock'\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { E } from '#generated/entities.ids.generated'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { normalizeCustomFieldSubmitValue, extractCustomFieldValues } from './customFieldHelpers'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\nexport type PaymentTotals = {\n paidTotalAmount?: number | null\n refundedTotalAmount?: number | null\n outstandingAmount?: number | null\n}\n\nexport type PaymentFormData = {\n id?: string | null\n updatedAt?: string | null\n amount?: number | string | null\n paymentMethodId?: string | null\n paymentReference?: string | null\n receivedAt?: string | null\n currencyCode?: string | null\n statusEntryId?: string | null\n customValues?: Record<string, unknown> | null\n customFieldSetId?: string | null\n}\n\ntype PaymentMethodOption = {\n id: string\n name: string\n code: string\n}\n\ntype StatusOption = {\n id: string\n value: string\n label: string\n color: string | null\n}\n\ntype PaymentDialogProps = {\n open: boolean\n mode: 'create' | 'edit'\n payment?: PaymentFormData | null\n currencyCode: string | null | undefined\n orderId: string\n organizationId: string | null\n tenantId: string | null\n documentUpdatedAt?: string | null\n onOpenChange: (open: boolean) => void\n onSaved?: (totals?: PaymentTotals | null) => void | Promise<void>\n}\n\nconst normalizeNumber = (value: unknown): number => {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n if (!Number.isNaN(parsed)) return parsed\n }\n return 0\n}\n\nexport function PaymentDialog({\n open,\n mode,\n payment,\n currencyCode,\n orderId,\n organizationId,\n tenantId,\n documentUpdatedAt,\n onOpenChange,\n onSaved,\n}: PaymentDialogProps) {\n const t = useT()\n const dialogContentRef = React.useRef<HTMLDivElement | null>(null)\n const [formResetKey, setFormResetKey] = React.useState(0)\n const [paymentMethods, setPaymentMethods] = React.useState<PaymentMethodOption[]>([])\n const [methodsLoading, setMethodsLoading] = React.useState(false)\n const [paymentStatuses, setPaymentStatuses] = React.useState<StatusOption[]>([])\n const [paymentStatusLoading, setPaymentStatusLoading] = React.useState(false)\n const [documentStatuses, setDocumentStatuses] = React.useState<StatusOption[]>([])\n const [documentStatusLoading, setDocumentStatusLoading] = React.useState(false)\n\n const currencyLabel = React.useMemo(() => {\n const code = currencyCode ? currencyCode.toUpperCase() : ''\n if (!code) return t('sales.documents.detail.empty', 'Not set')\n return code\n }, [currencyCode, t])\n\n const initialValues = React.useMemo(\n () => ({\n amount: payment?.amount ?? '',\n paymentMethodId: payment?.paymentMethodId ?? '',\n paymentReference: payment?.paymentReference ?? '',\n receivedAt: payment?.receivedAt ? payment.receivedAt.slice(0, 10) : '',\n statusEntryId: payment?.statusEntryId ?? '',\n documentStatusEntryId: '',\n customFieldSetId: payment?.customFieldSetId ?? '',\n ...extractCustomFieldValues(payment),\n }),\n [\n payment?.amount,\n payment?.customFieldSetId,\n payment?.customValues,\n payment?.paymentMethodId,\n payment?.paymentReference,\n payment?.receivedAt,\n payment?.statusEntryId,\n ],\n )\n\n const loadPaymentMethods = React.useCallback(\n async (query?: string): Promise<PaymentMethodOption[]> => {\n setMethodsLoading(true)\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '100', isActive: 'true' })\n if (query && query.trim().length) params.set('search', query.trim())\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/payment-methods?${params.toString()}`,\n undefined,\n { fallback: { items: [] } }\n )\n if (response.ok && Array.isArray(response.result?.items)) {\n const options = response.result.items\n .map((item) => {\n const id = typeof item.id === 'string' ? item.id : null\n if (!id) return null\n const name = typeof item.name === 'string' ? item.name : null\n const code = typeof item.code === 'string' ? item.code : null\n return {\n id,\n name: name ?? code ?? id,\n code: code ?? id,\n }\n })\n .filter((entry): entry is PaymentMethodOption => !!entry)\n if (!query) setPaymentMethods(options)\n return options\n }\n if (!query) setPaymentMethods([])\n return []\n } catch (err) {\n logger.error('sales.payments.methods.load', { err })\n return []\n } finally {\n setMethodsLoading(false)\n }\n },\n []\n )\n\n const fetchPaymentMethodItems = React.useCallback(\n async (query?: string): Promise<LookupSelectItem[]> => {\n const options =\n paymentMethods.length && !query\n ? paymentMethods\n : await loadPaymentMethods(query)\n const term = query?.trim().toLowerCase() ?? ''\n return options\n .filter(\n (option) =>\n !term.length ||\n option.name.toLowerCase().includes(term) ||\n option.code.toLowerCase().includes(term)\n )\n .map<LookupSelectItem>((option) => ({\n id: option.id,\n title: option.name,\n subtitle: option.code,\n icon: <CreditCard className=\"h-4 w-4 text-muted-foreground\" />,\n }))\n },\n [loadPaymentMethods, paymentMethods]\n )\n\n const shortcutLabel = t('sales.documents.payments.saveShortcut', 'Save \u2318\u23CE / Ctrl+Enter')\n const renderStatusIcon = React.useCallback(\n (color?: string | null) => (\n <span\n className=\"h-2.5 w-2.5 rounded-full border border-border/70\"\n style={color ? { backgroundColor: color, borderColor: color } : undefined}\n />\n ),\n [],\n )\n\n const loadDocumentStatuses = React.useCallback(async (): Promise<StatusOption[]> => {\n setDocumentStatusLoading(true)\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '100' })\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/order-statuses?${params.toString()}`,\n undefined,\n { fallback: { items: [] } },\n )\n const items = Array.isArray(response.result?.items) ? response.result.items : []\n const mapped = items\n .map((entry) => {\n const id = typeof entry.id === 'string' ? entry.id : null\n const value = typeof entry.value === 'string' ? entry.value : null\n if (!id || !value) return null\n const label =\n typeof entry.label === 'string' && entry.label.trim().length\n ? entry.label\n : value\n const color =\n typeof entry.color === 'string' && entry.color.trim().length ? entry.color : null\n return { id, value, label, color }\n })\n .filter((entry): entry is StatusOption => Boolean(entry))\n setDocumentStatuses(mapped)\n return mapped\n } catch (err) {\n logger.error('sales.payments.statuses.load', { err })\n setDocumentStatuses([])\n return []\n } finally {\n setDocumentStatusLoading(false)\n }\n }, [])\n\n const loadPaymentStatuses = React.useCallback(async (): Promise<StatusOption[]> => {\n setPaymentStatusLoading(true)\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '100' })\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/payment-statuses?${params.toString()}`,\n undefined,\n { fallback: { items: [] } },\n )\n const items = Array.isArray(response.result?.items) ? response.result.items : []\n const mapped = items\n .map((entry) => {\n const id = typeof entry.id === 'string' ? entry.id : null\n const value = typeof entry.value === 'string' ? entry.value : null\n if (!id || !value) return null\n const label =\n typeof entry.label === 'string' && entry.label.trim().length\n ? entry.label\n : value\n const color =\n typeof entry.color === 'string' && entry.color.trim().length ? entry.color : null\n return { id, value, label, color }\n })\n .filter((entry): entry is StatusOption => Boolean(entry))\n setPaymentStatuses(mapped)\n return mapped\n } catch (err) {\n logger.error('sales.payments.statuses.load', { err })\n setPaymentStatuses([])\n return []\n } finally {\n setPaymentStatusLoading(false)\n }\n }, [])\n\n React.useEffect(() => {\n if (!open) return\n setFormResetKey((prev) => prev + 1)\n if (!paymentMethods.length) {\n void loadPaymentMethods()\n }\n if (!paymentStatuses.length) {\n void loadPaymentStatuses()\n }\n if (mode === 'create') {\n if (!documentStatuses.length) {\n void loadDocumentStatuses()\n }\n }\n }, [\n documentStatuses.length,\n loadDocumentStatuses,\n loadPaymentStatuses,\n loadPaymentMethods,\n mode,\n open,\n payment?.id,\n paymentStatuses.length,\n paymentMethods.length,\n ])\n\n const fetchDocumentStatusItems = React.useCallback(\n async (query?: string): Promise<LookupSelectItem[]> => {\n const options =\n documentStatuses.length && !query ? documentStatuses : await loadDocumentStatuses()\n const term = query?.trim().toLowerCase() ?? ''\n return options\n .filter(\n (option) =>\n !term.length ||\n option.label.toLowerCase().includes(term) ||\n option.value.toLowerCase().includes(term),\n )\n .map<LookupSelectItem>((option) => ({\n id: option.id,\n title: option.label,\n subtitle: option.value,\n icon: renderStatusIcon(option.color),\n }))\n },\n [documentStatuses, loadDocumentStatuses, renderStatusIcon],\n )\n\n const fetchPaymentStatusItems = React.useCallback(\n async (query?: string): Promise<LookupSelectItem[]> => {\n const options =\n paymentStatuses.length && !query ? paymentStatuses : await loadPaymentStatuses()\n const term = query?.trim().toLowerCase() ?? ''\n return options\n .filter(\n (option) =>\n !term.length ||\n option.label.toLowerCase().includes(term) ||\n option.value.toLowerCase().includes(term),\n )\n .map<LookupSelectItem>((option) => ({\n id: option.id,\n title: option.label,\n subtitle: option.value,\n icon: renderStatusIcon(option.color),\n }))\n },\n [loadPaymentStatuses, paymentStatuses, renderStatusIcon],\n )\n\n const fields = React.useMemo<CrudField[]>(\n () => [\n {\n id: 'amount',\n label: t('sales.documents.payments.amount', 'Amount'),\n type: 'custom',\n required: true,\n component: ({ value, setValue }) => {\n const normalized = typeof value === 'number' ? value : typeof value === 'string' ? value : ''\n return (\n <div className=\"flex items-center gap-2\">\n <Input\n type=\"number\"\n inputMode=\"decimal\"\n step=\"0.01\"\n value={normalized as string | number}\n onChange={(event) => setValue(event.target.value)}\n placeholder=\"0.00\"\n />\n <span className=\"rounded-full border border-border/70 bg-muted/50 px-3 py-1 text-xs font-semibold uppercase text-foreground\">\n {currencyLabel}\n </span>\n </div>\n )\n },\n },\n {\n id: 'paymentMethodId',\n label: t('sales.documents.payments.method', 'Method'),\n type: 'custom',\n component: ({ value, setValue }) => {\n const currentValue = typeof value === 'string' && value.length ? value : null\n return (\n <LookupSelect\n value={currentValue}\n onChange={(next) => setValue(next ?? '')}\n fetchItems={fetchPaymentMethodItems}\n searchPlaceholder={t('sales.documents.payments.methodPlaceholder', 'Search payment method')}\n emptyLabel={t('sales.documents.payments.methodsEmpty', 'No payment methods')}\n loadingLabel={t('sales.documents.payments.loadingMethods', 'Loading payment methods\u2026')}\n selectedHintLabel={(id) =>\n t('sales.documents.payments.methodSelected', 'Selected method: {{id}}', { id })\n }\n minQuery={0}\n />\n )\n },\n },\n {\n id: 'statusEntryId',\n label: t('sales.documents.payments.status', 'Status'),\n type: 'custom',\n component: ({ value, setValue }) => {\n const currentValue = typeof value === 'string' && value.length ? value : null\n return (\n <LookupSelect\n value={currentValue}\n onChange={(next) => setValue(next ?? '')}\n fetchItems={fetchPaymentStatusItems}\n placeholder={t('sales.documents.payments.statusPlaceholder', 'Select status')}\n loading={paymentStatusLoading}\n minQuery={0}\n />\n )\n },\n },\n ...(mode === 'create'\n ? ([\n {\n id: 'documentStatusEntryId',\n label: t('sales.documents.status.changeDocument', 'Change order/quote status'),\n type: 'custom',\n component: ({ value, setValue }) => {\n const currentValue = typeof value === 'string' && value.length ? value : null\n return (\n <LookupSelect\n value={currentValue}\n onChange={(next) => setValue(next ?? '')}\n fetchItems={fetchDocumentStatusItems}\n placeholder={t(\n 'sales.documents.status.documentPlaceholder',\n 'Select new order/quote status',\n )}\n loading={documentStatusLoading}\n minQuery={0}\n />\n )\n },\n },\n ] as CrudField[])\n : []),\n {\n id: 'paymentReference',\n label: t('sales.documents.payments.reference', 'Reference'),\n type: 'text',\n placeholder: t('sales.documents.payments.referencePlaceholder', 'External reference or note'),\n },\n {\n id: 'receivedAt',\n label: t('sales.documents.payments.receivedAt', 'Received at'),\n type: 'date',\n },\n ],\n [\n currencyLabel,\n documentStatusLoading,\n fetchPaymentStatusItems,\n fetchDocumentStatusItems,\n fetchPaymentMethodItems,\n paymentStatusLoading,\n mode,\n t,\n ],\n )\n\n const groups = React.useMemo<CrudFormGroup[]>(\n () => {\n const base: CrudFormGroup[] = [\n {\n id: 'paymentDetails',\n title: t('sales.documents.payments.form.title', 'Payment details'),\n column: 1,\n fields: ['amount', 'paymentMethodId', 'statusEntryId'],\n },\n ]\n if (mode === 'create') {\n base.push({\n id: 'statusChanges',\n title: t('sales.documents.status.sectionTitle', 'Status changes'),\n column: 1,\n fields: ['documentStatusEntryId'],\n })\n }\n base.push({\n id: 'paymentReference',\n title: t('sales.documents.payments.reference', 'Reference'),\n column: 2,\n fields: ['paymentReference', 'receivedAt'],\n })\n base.push({\n id: 'paymentCustomFields',\n title: t('entities.customFields.title', 'Custom fields'),\n column: 2,\n kind: 'customFields',\n })\n return base\n },\n [mode, t],\n )\n\n const handleSubmit = React.useCallback(\n async (values: Record<string, unknown>) => {\n const resolvedCurrency = currencyCode ? currencyCode.toUpperCase() : ''\n const amountValue = normalizeNumber(values.amount)\n if (!resolvedCurrency.trim()) {\n throw createCrudFormError(t('sales.documents.payments.currencyRequired', 'Currency is required.'))\n }\n if (amountValue <= 0) {\n throw createCrudFormError(t('sales.documents.payments.amountRequired', 'Enter a positive amount.'), {\n amount: t('sales.documents.payments.amountRequired', 'Enter a positive amount.'),\n })\n }\n\n const payload: Record<string, unknown> = {\n orderId,\n amount: amountValue,\n currencyCode: resolvedCurrency,\n paymentReference:\n typeof values.paymentReference === 'string' && values.paymentReference.trim().length\n ? values.paymentReference.trim()\n : undefined,\n paymentMethodId:\n typeof values.paymentMethodId === 'string' && values.paymentMethodId.trim().length\n ? values.paymentMethodId\n : undefined,\n statusEntryId:\n typeof values.statusEntryId === 'string' && values.statusEntryId.trim().length\n ? values.statusEntryId\n : undefined,\n customFieldSetId:\n typeof values.customFieldSetId === 'string' && values.customFieldSetId.trim().length\n ? values.customFieldSetId.trim()\n : undefined,\n organizationId: organizationId ?? undefined,\n tenantId: tenantId ?? undefined,\n }\n const documentStatusEntryId =\n typeof values.documentStatusEntryId === 'string' && values.documentStatusEntryId.trim().length\n ? values.documentStatusEntryId\n : null\n if (documentStatusEntryId) {\n payload.documentStatusEntryId = documentStatusEntryId\n }\n if (typeof values.receivedAt === 'string' && values.receivedAt.trim().length) {\n payload.receivedAt = new Date(values.receivedAt)\n }\n const customFields = collectCustomFieldValues(values, {\n transform: normalizeCustomFieldSubmitValue,\n })\n if (Object.keys(customFields).length) payload.customFields = customFields\n\n const action = payment?.id ? updateCrud : createCrud\n try {\n const result = await withScopedApiRequestHeaders(\n // The server guards the PARENT order's aggregate version (Gap A) for\n // both create and update, so send the order's `updated_at`.\n buildOptimisticLockHeader(documentUpdatedAt ?? undefined),\n () =>\n action(\n 'sales/payments',\n payment?.id ? { id: payment.id, ...payload } : payload,\n {\n errorMessage: t('sales.documents.payments.errorSave', 'Failed to save payment.'),\n }\n )\n )\n if (result.ok) {\n const totals = (result.result as any)?.orderTotals as PaymentTotals | undefined\n if (onSaved) {\n await onSaved(totals ?? null)\n }\n setFormResetKey((prev) => prev + 1)\n onOpenChange(false)\n }\n } catch (err) {\n if (\n handleSectionMutationError(err, t, () => {\n if (onSaved) void onSaved()\n })\n ) {\n onOpenChange(false)\n return\n }\n throw err\n }\n },\n [currencyCode, documentUpdatedAt, mode, onOpenChange, onSaved, orderId, organizationId, payment?.id, t, tenantId]\n )\n\n const handleSubmitForm = React.useCallback(\n () => dialogContentRef.current?.querySelector('form')?.requestSubmit(),\n [],\n )\n const handleKeyDown = useDialogKeyHandler({\n onConfirm: handleSubmitForm,\n onCancel: () => onOpenChange(false),\n })\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent\n ref={dialogContentRef}\n className=\"sm:max-w-5xl\"\n onKeyDown={handleKeyDown}\n >\n <DialogHeader>\n <DialogTitle>\n {mode === 'edit'\n ? t('sales.documents.payments.edit', 'Edit payment')\n : t('sales.documents.payments.add', 'Add payment')}\n </DialogTitle>\n </DialogHeader>\n <CrudForm\n key={formResetKey}\n embedded\n entityId={E.sales.sales_payment}\n fields={fields}\n groups={groups}\n initialValues={initialValues}\n customFieldsetBindings={{ [E.sales.sales_payment]: { valueKey: 'customFieldSetId' } }}\n submitLabel={shortcutLabel}\n onSubmit={handleSubmit}\n loadingMessage={t('sales.documents.payments.loading', 'Loading payments\u2026')}\n customFieldsLoadingMessage={t('ui.forms.loading', 'Loading data...')}\n contentHeader={\n methodsLoading ? (\n <p className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <Spinner className=\"h-3.5 w-3.5 animate-spin\" />\n {t('sales.documents.payments.loadingMethods', 'Loading payment methods\u2026')}\n </p>\n ) : null\n }\n />\n </DialogContent>\n </Dialog>\n )\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { CreditCard } from 'lucide-react'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { LookupSelect, type LookupSelectItem } from '@open-mercato/ui/backend/inputs'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { createCrud, updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { handleSectionMutationError } from './optimisticLock'\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { E } from '#generated/entities.ids.generated'\nimport { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'\nimport { parseLocaleNumber } from '@open-mercato/shared/lib/number'\nimport { normalizeCustomFieldSubmitValue, extractCustomFieldValues } from './customFieldHelpers'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\nexport type PaymentTotals = {\n paidTotalAmount?: number | null\n refundedTotalAmount?: number | null\n outstandingAmount?: number | null\n}\n\nexport type PaymentFormData = {\n id?: string | null\n updatedAt?: string | null\n amount?: number | string | null\n paymentMethodId?: string | null\n paymentReference?: string | null\n receivedAt?: string | null\n currencyCode?: string | null\n statusEntryId?: string | null\n customValues?: Record<string, unknown> | null\n customFieldSetId?: string | null\n}\n\ntype PaymentMethodOption = {\n id: string\n name: string\n code: string\n}\n\ntype StatusOption = {\n id: string\n value: string\n label: string\n color: string | null\n}\n\ntype PaymentDialogProps = {\n open: boolean\n mode: 'create' | 'edit'\n payment?: PaymentFormData | null\n currencyCode: string | null | undefined\n orderId: string\n organizationId: string | null\n tenantId: string | null\n documentUpdatedAt?: string | null\n onOpenChange: (open: boolean) => void\n onSaved?: (totals?: PaymentTotals | null) => void | Promise<void>\n}\n\n// The amount field is a hand-rolled text input, so the raw string a user typed reaches\n// the submit handler carrying the separator the surrounding UI displays \u2014 `110,70` under\n// Polish (issue #5828, same defect class as #5552). A blank/absent value keeps the old\n// \"must be a positive amount\" message; only genuinely unparseable input returns null.\nconst parseAmountInput = (value: unknown, locale?: string): number | null => {\n if (typeof value === 'number') return Number.isFinite(value) ? value : null\n if (typeof value !== 'string') return 0\n if (!value.trim()) return 0\n return parseLocaleNumber(value, locale)\n}\n\nexport function PaymentDialog({\n open,\n mode,\n payment,\n currencyCode,\n orderId,\n organizationId,\n tenantId,\n documentUpdatedAt,\n onOpenChange,\n onSaved,\n}: PaymentDialogProps) {\n const t = useT()\n const locale = useLocale()\n const dialogContentRef = React.useRef<HTMLDivElement | null>(null)\n const [formResetKey, setFormResetKey] = React.useState(0)\n const [paymentMethods, setPaymentMethods] = React.useState<PaymentMethodOption[]>([])\n const [methodsLoading, setMethodsLoading] = React.useState(false)\n const [paymentStatuses, setPaymentStatuses] = React.useState<StatusOption[]>([])\n const [paymentStatusLoading, setPaymentStatusLoading] = React.useState(false)\n const [documentStatuses, setDocumentStatuses] = React.useState<StatusOption[]>([])\n const [documentStatusLoading, setDocumentStatusLoading] = React.useState(false)\n\n const currencyLabel = React.useMemo(() => {\n const code = currencyCode ? currencyCode.toUpperCase() : ''\n if (!code) return t('sales.documents.detail.empty', 'Not set')\n return code\n }, [currencyCode, t])\n\n const initialValues = React.useMemo(\n () => ({\n amount: payment?.amount ?? '',\n paymentMethodId: payment?.paymentMethodId ?? '',\n paymentReference: payment?.paymentReference ?? '',\n receivedAt: payment?.receivedAt ? payment.receivedAt.slice(0, 10) : '',\n statusEntryId: payment?.statusEntryId ?? '',\n documentStatusEntryId: '',\n customFieldSetId: payment?.customFieldSetId ?? '',\n ...extractCustomFieldValues(payment),\n }),\n [\n payment?.amount,\n payment?.customFieldSetId,\n payment?.customValues,\n payment?.paymentMethodId,\n payment?.paymentReference,\n payment?.receivedAt,\n payment?.statusEntryId,\n ],\n )\n\n const loadPaymentMethods = React.useCallback(\n async (query?: string): Promise<PaymentMethodOption[]> => {\n setMethodsLoading(true)\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '100', isActive: 'true' })\n if (query && query.trim().length) params.set('search', query.trim())\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/payment-methods?${params.toString()}`,\n undefined,\n { fallback: { items: [] } }\n )\n if (response.ok && Array.isArray(response.result?.items)) {\n const options = response.result.items\n .map((item) => {\n const id = typeof item.id === 'string' ? item.id : null\n if (!id) return null\n const name = typeof item.name === 'string' ? item.name : null\n const code = typeof item.code === 'string' ? item.code : null\n return {\n id,\n name: name ?? code ?? id,\n code: code ?? id,\n }\n })\n .filter((entry): entry is PaymentMethodOption => !!entry)\n if (!query) setPaymentMethods(options)\n return options\n }\n if (!query) setPaymentMethods([])\n return []\n } catch (err) {\n logger.error('sales.payments.methods.load', { err })\n return []\n } finally {\n setMethodsLoading(false)\n }\n },\n []\n )\n\n const fetchPaymentMethodItems = React.useCallback(\n async (query?: string): Promise<LookupSelectItem[]> => {\n const options =\n paymentMethods.length && !query\n ? paymentMethods\n : await loadPaymentMethods(query)\n const term = query?.trim().toLowerCase() ?? ''\n return options\n .filter(\n (option) =>\n !term.length ||\n option.name.toLowerCase().includes(term) ||\n option.code.toLowerCase().includes(term)\n )\n .map<LookupSelectItem>((option) => ({\n id: option.id,\n title: option.name,\n subtitle: option.code,\n icon: <CreditCard className=\"h-4 w-4 text-muted-foreground\" />,\n }))\n },\n [loadPaymentMethods, paymentMethods]\n )\n\n const shortcutLabel = t('sales.documents.payments.saveShortcut', 'Save \u2318\u23CE / Ctrl+Enter')\n const renderStatusIcon = React.useCallback(\n (color?: string | null) => (\n <span\n className=\"h-2.5 w-2.5 rounded-full border border-border/70\"\n style={color ? { backgroundColor: color, borderColor: color } : undefined}\n />\n ),\n [],\n )\n\n const loadDocumentStatuses = React.useCallback(async (): Promise<StatusOption[]> => {\n setDocumentStatusLoading(true)\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '100' })\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/order-statuses?${params.toString()}`,\n undefined,\n { fallback: { items: [] } },\n )\n const items = Array.isArray(response.result?.items) ? response.result.items : []\n const mapped = items\n .map((entry) => {\n const id = typeof entry.id === 'string' ? entry.id : null\n const value = typeof entry.value === 'string' ? entry.value : null\n if (!id || !value) return null\n const label =\n typeof entry.label === 'string' && entry.label.trim().length\n ? entry.label\n : value\n const color =\n typeof entry.color === 'string' && entry.color.trim().length ? entry.color : null\n return { id, value, label, color }\n })\n .filter((entry): entry is StatusOption => Boolean(entry))\n setDocumentStatuses(mapped)\n return mapped\n } catch (err) {\n logger.error('sales.payments.statuses.load', { err })\n setDocumentStatuses([])\n return []\n } finally {\n setDocumentStatusLoading(false)\n }\n }, [])\n\n const loadPaymentStatuses = React.useCallback(async (): Promise<StatusOption[]> => {\n setPaymentStatusLoading(true)\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '100' })\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/payment-statuses?${params.toString()}`,\n undefined,\n { fallback: { items: [] } },\n )\n const items = Array.isArray(response.result?.items) ? response.result.items : []\n const mapped = items\n .map((entry) => {\n const id = typeof entry.id === 'string' ? entry.id : null\n const value = typeof entry.value === 'string' ? entry.value : null\n if (!id || !value) return null\n const label =\n typeof entry.label === 'string' && entry.label.trim().length\n ? entry.label\n : value\n const color =\n typeof entry.color === 'string' && entry.color.trim().length ? entry.color : null\n return { id, value, label, color }\n })\n .filter((entry): entry is StatusOption => Boolean(entry))\n setPaymentStatuses(mapped)\n return mapped\n } catch (err) {\n logger.error('sales.payments.statuses.load', { err })\n setPaymentStatuses([])\n return []\n } finally {\n setPaymentStatusLoading(false)\n }\n }, [])\n\n React.useEffect(() => {\n if (!open) return\n setFormResetKey((prev) => prev + 1)\n if (!paymentMethods.length) {\n void loadPaymentMethods()\n }\n if (!paymentStatuses.length) {\n void loadPaymentStatuses()\n }\n if (mode === 'create') {\n if (!documentStatuses.length) {\n void loadDocumentStatuses()\n }\n }\n }, [\n documentStatuses.length,\n loadDocumentStatuses,\n loadPaymentStatuses,\n loadPaymentMethods,\n mode,\n open,\n payment?.id,\n paymentStatuses.length,\n paymentMethods.length,\n ])\n\n const fetchDocumentStatusItems = React.useCallback(\n async (query?: string): Promise<LookupSelectItem[]> => {\n const options =\n documentStatuses.length && !query ? documentStatuses : await loadDocumentStatuses()\n const term = query?.trim().toLowerCase() ?? ''\n return options\n .filter(\n (option) =>\n !term.length ||\n option.label.toLowerCase().includes(term) ||\n option.value.toLowerCase().includes(term),\n )\n .map<LookupSelectItem>((option) => ({\n id: option.id,\n title: option.label,\n subtitle: option.value,\n icon: renderStatusIcon(option.color),\n }))\n },\n [documentStatuses, loadDocumentStatuses, renderStatusIcon],\n )\n\n const fetchPaymentStatusItems = React.useCallback(\n async (query?: string): Promise<LookupSelectItem[]> => {\n const options =\n paymentStatuses.length && !query ? paymentStatuses : await loadPaymentStatuses()\n const term = query?.trim().toLowerCase() ?? ''\n return options\n .filter(\n (option) =>\n !term.length ||\n option.label.toLowerCase().includes(term) ||\n option.value.toLowerCase().includes(term),\n )\n .map<LookupSelectItem>((option) => ({\n id: option.id,\n title: option.label,\n subtitle: option.value,\n icon: renderStatusIcon(option.color),\n }))\n },\n [loadPaymentStatuses, paymentStatuses, renderStatusIcon],\n )\n\n const fields = React.useMemo<CrudField[]>(\n () => [\n {\n id: 'amount',\n label: t('sales.documents.payments.amount', 'Amount'),\n type: 'custom',\n required: true,\n component: ({ value, setValue }) => {\n const normalized = typeof value === 'number' ? value : typeof value === 'string' ? value : ''\n return (\n <div className=\"flex items-center gap-2\">\n <Input\n type=\"text\"\n inputMode=\"decimal\"\n value={normalized as string | number}\n onChange={(event) => setValue(event.target.value)}\n placeholder=\"0.00\"\n />\n <span className=\"rounded-full border border-border/70 bg-muted/50 px-3 py-1 text-xs font-semibold uppercase text-foreground\">\n {currencyLabel}\n </span>\n </div>\n )\n },\n },\n {\n id: 'paymentMethodId',\n label: t('sales.documents.payments.method', 'Method'),\n type: 'custom',\n component: ({ value, setValue }) => {\n const currentValue = typeof value === 'string' && value.length ? value : null\n return (\n <LookupSelect\n value={currentValue}\n onChange={(next) => setValue(next ?? '')}\n fetchItems={fetchPaymentMethodItems}\n searchPlaceholder={t('sales.documents.payments.methodPlaceholder', 'Search payment method')}\n emptyLabel={t('sales.documents.payments.methodsEmpty', 'No payment methods')}\n loadingLabel={t('sales.documents.payments.loadingMethods', 'Loading payment methods\u2026')}\n selectedHintLabel={(id) =>\n t('sales.documents.payments.methodSelected', 'Selected method: {{id}}', { id })\n }\n minQuery={0}\n />\n )\n },\n },\n {\n id: 'statusEntryId',\n label: t('sales.documents.payments.status', 'Status'),\n type: 'custom',\n component: ({ value, setValue }) => {\n const currentValue = typeof value === 'string' && value.length ? value : null\n return (\n <LookupSelect\n value={currentValue}\n onChange={(next) => setValue(next ?? '')}\n fetchItems={fetchPaymentStatusItems}\n placeholder={t('sales.documents.payments.statusPlaceholder', 'Select status')}\n loading={paymentStatusLoading}\n minQuery={0}\n />\n )\n },\n },\n ...(mode === 'create'\n ? ([\n {\n id: 'documentStatusEntryId',\n label: t('sales.documents.status.changeDocument', 'Change order/quote status'),\n type: 'custom',\n component: ({ value, setValue }) => {\n const currentValue = typeof value === 'string' && value.length ? value : null\n return (\n <LookupSelect\n value={currentValue}\n onChange={(next) => setValue(next ?? '')}\n fetchItems={fetchDocumentStatusItems}\n placeholder={t(\n 'sales.documents.status.documentPlaceholder',\n 'Select new order/quote status',\n )}\n loading={documentStatusLoading}\n minQuery={0}\n />\n )\n },\n },\n ] as CrudField[])\n : []),\n {\n id: 'paymentReference',\n label: t('sales.documents.payments.reference', 'Reference'),\n type: 'text',\n placeholder: t('sales.documents.payments.referencePlaceholder', 'External reference or note'),\n },\n {\n id: 'receivedAt',\n label: t('sales.documents.payments.receivedAt', 'Received at'),\n type: 'date',\n },\n ],\n [\n currencyLabel,\n documentStatusLoading,\n fetchPaymentStatusItems,\n fetchDocumentStatusItems,\n fetchPaymentMethodItems,\n paymentStatusLoading,\n mode,\n t,\n ],\n )\n\n const groups = React.useMemo<CrudFormGroup[]>(\n () => {\n const base: CrudFormGroup[] = [\n {\n id: 'paymentDetails',\n title: t('sales.documents.payments.form.title', 'Payment details'),\n column: 1,\n fields: ['amount', 'paymentMethodId', 'statusEntryId'],\n },\n ]\n if (mode === 'create') {\n base.push({\n id: 'statusChanges',\n title: t('sales.documents.status.sectionTitle', 'Status changes'),\n column: 1,\n fields: ['documentStatusEntryId'],\n })\n }\n base.push({\n id: 'paymentReference',\n title: t('sales.documents.payments.reference', 'Reference'),\n column: 2,\n fields: ['paymentReference', 'receivedAt'],\n })\n base.push({\n id: 'paymentCustomFields',\n title: t('entities.customFields.title', 'Custom fields'),\n column: 2,\n kind: 'customFields',\n })\n return base\n },\n [mode, t],\n )\n\n const handleSubmit = React.useCallback(\n async (values: Record<string, unknown>) => {\n const resolvedCurrency = currencyCode ? currencyCode.toUpperCase() : ''\n const amountValue = parseAmountInput(values.amount, locale)\n if (!resolvedCurrency.trim()) {\n throw createCrudFormError(t('sales.documents.payments.currencyRequired', 'Currency is required.'))\n }\n if (amountValue === null) {\n const message = t('sales.documents.payments.amountInvalid', 'Enter the amount as a number.')\n throw createCrudFormError(message, { amount: message })\n }\n if (amountValue <= 0) {\n throw createCrudFormError(t('sales.documents.payments.amountRequired', 'Enter a positive amount.'), {\n amount: t('sales.documents.payments.amountRequired', 'Enter a positive amount.'),\n })\n }\n\n const payload: Record<string, unknown> = {\n orderId,\n amount: amountValue,\n currencyCode: resolvedCurrency,\n paymentReference:\n typeof values.paymentReference === 'string' && values.paymentReference.trim().length\n ? values.paymentReference.trim()\n : undefined,\n paymentMethodId:\n typeof values.paymentMethodId === 'string' && values.paymentMethodId.trim().length\n ? values.paymentMethodId\n : undefined,\n statusEntryId:\n typeof values.statusEntryId === 'string' && values.statusEntryId.trim().length\n ? values.statusEntryId\n : undefined,\n customFieldSetId:\n typeof values.customFieldSetId === 'string' && values.customFieldSetId.trim().length\n ? values.customFieldSetId.trim()\n : undefined,\n organizationId: organizationId ?? undefined,\n tenantId: tenantId ?? undefined,\n }\n const documentStatusEntryId =\n typeof values.documentStatusEntryId === 'string' && values.documentStatusEntryId.trim().length\n ? values.documentStatusEntryId\n : null\n if (documentStatusEntryId) {\n payload.documentStatusEntryId = documentStatusEntryId\n }\n if (typeof values.receivedAt === 'string' && values.receivedAt.trim().length) {\n payload.receivedAt = new Date(values.receivedAt)\n }\n const customFields = collectCustomFieldValues(values, {\n transform: normalizeCustomFieldSubmitValue,\n })\n if (Object.keys(customFields).length) payload.customFields = customFields\n\n const action = payment?.id ? updateCrud : createCrud\n try {\n const result = await withScopedApiRequestHeaders(\n // The server guards the PARENT order's aggregate version (Gap A) for\n // both create and update, so send the order's `updated_at`.\n buildOptimisticLockHeader(documentUpdatedAt ?? undefined),\n () =>\n action(\n 'sales/payments',\n payment?.id ? { id: payment.id, ...payload } : payload,\n {\n errorMessage: t('sales.documents.payments.errorSave', 'Failed to save payment.'),\n }\n )\n )\n if (result.ok) {\n const totals = (result.result as any)?.orderTotals as PaymentTotals | undefined\n if (onSaved) {\n await onSaved(totals ?? null)\n }\n setFormResetKey((prev) => prev + 1)\n onOpenChange(false)\n }\n } catch (err) {\n if (\n handleSectionMutationError(err, t, () => {\n if (onSaved) void onSaved()\n })\n ) {\n onOpenChange(false)\n return\n }\n throw err\n }\n },\n [currencyCode, documentUpdatedAt, mode, onOpenChange, onSaved, orderId, organizationId, payment?.id, t, tenantId]\n )\n\n const handleSubmitForm = React.useCallback(\n () => dialogContentRef.current?.querySelector('form')?.requestSubmit(),\n [],\n )\n const handleKeyDown = useDialogKeyHandler({\n onConfirm: handleSubmitForm,\n onCancel: () => onOpenChange(false),\n })\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent\n ref={dialogContentRef}\n className=\"sm:max-w-5xl\"\n onKeyDown={handleKeyDown}\n >\n <DialogHeader>\n <DialogTitle>\n {mode === 'edit'\n ? t('sales.documents.payments.edit', 'Edit payment')\n : t('sales.documents.payments.add', 'Add payment')}\n </DialogTitle>\n </DialogHeader>\n <CrudForm\n key={formResetKey}\n embedded\n entityId={E.sales.sales_payment}\n fields={fields}\n groups={groups}\n initialValues={initialValues}\n customFieldsetBindings={{ [E.sales.sales_payment]: { valueKey: 'customFieldSetId' } }}\n submitLabel={shortcutLabel}\n onSubmit={handleSubmit}\n loadingMessage={t('sales.documents.payments.loading', 'Loading payments\u2026')}\n customFieldsLoadingMessage={t('ui.forms.loading', 'Loading data...')}\n contentHeader={\n methodsLoading ? (\n <p className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <Spinner className=\"h-3.5 w-3.5 animate-spin\" />\n {t('sales.documents.payments.loadingMethods', 'Loading payment methods\u2026')}\n </p>\n ) : null\n }\n />\n </DialogContent>\n </Dialog>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|