@open-mercato/core 0.10.1-develop.7833.1.d6cbf0e3ab → 0.10.1-develop.7841.1.af87ac614d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/cart/api/current/lines/bulk/route.js +1 -1
  3. package/dist/modules/cart/api/current/lines/bulk/route.js.map +2 -2
  4. package/dist/modules/cart/api/current/lines/route.js +1 -1
  5. package/dist/modules/cart/api/current/lines/route.js.map +2 -2
  6. package/dist/modules/cart/commands/lines.js +5 -10
  7. package/dist/modules/cart/commands/lines.js.map +2 -2
  8. package/dist/modules/cart/lib/currentCartRoute.js +8 -0
  9. package/dist/modules/cart/lib/currentCartRoute.js.map +3 -3
  10. package/dist/modules/cart/lib/lineMutationLock.js +52 -0
  11. package/dist/modules/cart/lib/lineMutationLock.js.map +7 -0
  12. package/dist/modules/customer_accounts/api/admin/roles.js +25 -2
  13. package/dist/modules/customer_accounts/api/admin/roles.js.map +2 -2
  14. package/dist/modules/customer_accounts/api/admin/users.js +24 -7
  15. package/dist/modules/customer_accounts/api/admin/users.js.map +2 -2
  16. package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js +77 -15
  17. package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js.map +2 -2
  18. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +12 -1
  19. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
  20. package/dist/modules/customer_accounts/data/validators.js +2 -1
  21. package/dist/modules/customer_accounts/data/validators.js.map +2 -2
  22. package/dist/modules/customer_accounts/lib/adminOrganizationScope.js +46 -0
  23. package/dist/modules/customer_accounts/lib/adminOrganizationScope.js.map +7 -0
  24. package/dist/modules/customers/api/customer-dictionary-entries/route.js +86 -0
  25. package/dist/modules/customers/api/customer-dictionary-entries/route.js.map +7 -0
  26. package/dist/modules/customers/api/dictionaries/[kind]/route.js +29 -7
  27. package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
  28. package/dist/modules/customers/cli.js +28 -110
  29. package/dist/modules/customers/cli.js.map +3 -3
  30. package/dist/modules/customers/components/DictionarySettings.js +1 -1
  31. package/dist/modules/customers/components/DictionarySettings.js.map +1 -1
  32. package/dist/modules/customers/components/detail/ManageTagsDialog.js +1 -1
  33. package/dist/modules/customers/components/detail/ManageTagsDialog.js.map +2 -2
  34. package/dist/modules/customers/components/detail/TaskDialog.js +14 -1
  35. package/dist/modules/customers/components/detail/TaskDialog.js.map +2 -2
  36. package/dist/modules/customers/components/detail/TaskForm.js +1 -16
  37. package/dist/modules/customers/components/detail/TaskForm.js.map +2 -2
  38. package/dist/modules/customers/components/detail/TasksSection.js +38 -10
  39. package/dist/modules/customers/components/detail/TasksSection.js.map +2 -2
  40. package/dist/modules/customers/components/detail/hooks/useCustomerDictionary.js +12 -5
  41. package/dist/modules/customers/components/detail/hooks/useCustomerDictionary.js.map +2 -2
  42. package/dist/modules/customers/components/detail/hooks/useInteractions.js +3 -13
  43. package/dist/modules/customers/components/detail/hooks/useInteractions.js.map +2 -2
  44. package/dist/modules/customers/lib/dictionaryDefaults.js +134 -0
  45. package/dist/modules/customers/lib/dictionaryDefaults.js.map +7 -0
  46. package/dist/modules/customers/lib/dictionaryLabels.js +59 -0
  47. package/dist/modules/customers/lib/dictionaryLabels.js.map +7 -0
  48. package/dist/modules/customers/lib/interactionCompatibility.js +1 -0
  49. package/dist/modules/customers/lib/interactionCompatibility.js.map +2 -2
  50. package/dist/modules/customers/translations.js +9 -0
  51. package/dist/modules/customers/translations.js.map +7 -0
  52. package/dist/modules/eudr/index.js +13 -0
  53. package/dist/modules/eudr/index.js.map +2 -2
  54. package/dist/modules/sales/commands/documents.js +3 -3
  55. package/dist/modules/sales/commands/documents.js.map +2 -2
  56. package/dist/modules/sales/components/documents/ItemsSection.js +75 -21
  57. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  58. package/dist/modules/sales/components/documents/lineItemUtils.js +2 -2
  59. package/dist/modules/sales/components/documents/lineItemUtils.js.map +2 -2
  60. package/dist/modules/staff/api/timesheets/access-requests/route.js +11 -5
  61. package/dist/modules/staff/api/timesheets/access-requests/route.js.map +2 -2
  62. package/dist/modules/staff/api/timesheets/time-projects/route.js +19 -12
  63. package/dist/modules/staff/api/timesheets/time-projects/route.js.map +2 -2
  64. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js +21 -12
  65. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js.map +2 -2
  66. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +14 -9
  67. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +2 -2
  68. package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js +31 -10
  69. package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js.map +2 -2
  70. package/dist/modules/staff/lib/time-tracking-ui/projectAccessScope.js +64 -0
  71. package/dist/modules/staff/lib/time-tracking-ui/projectAccessScope.js.map +7 -0
  72. package/dist/modules/staff/lib/time-tracking-ui/projectAccessScopeHeaders.js +13 -0
  73. package/dist/modules/staff/lib/time-tracking-ui/projectAccessScopeHeaders.js.map +7 -0
  74. package/dist/modules/sync_excel/index.js +11 -1
  75. package/dist/modules/sync_excel/index.js.map +2 -2
  76. package/dist/modules/translations/di.js +2 -0
  77. package/dist/modules/translations/di.js.map +2 -2
  78. package/package.json +7 -7
  79. package/src/modules/cart/api/current/lines/bulk/route.ts +1 -1
  80. package/src/modules/cart/api/current/lines/route.ts +1 -1
  81. package/src/modules/cart/commands/lines.ts +5 -10
  82. package/src/modules/cart/i18n/de.json +1 -0
  83. package/src/modules/cart/i18n/en.json +1 -0
  84. package/src/modules/cart/i18n/es.json +1 -0
  85. package/src/modules/cart/i18n/ko.json +1 -0
  86. package/src/modules/cart/i18n/pl.json +1 -0
  87. package/src/modules/cart/lib/currentCartRoute.ts +8 -0
  88. package/src/modules/cart/lib/lineMutationLock.ts +59 -0
  89. package/src/modules/customer_accounts/api/admin/roles.ts +26 -2
  90. package/src/modules/customer_accounts/api/admin/users.ts +26 -7
  91. package/src/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.tsx +96 -13
  92. package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +9 -1
  93. package/src/modules/customer_accounts/data/validators.ts +1 -0
  94. package/src/modules/customer_accounts/i18n/de.json +10 -0
  95. package/src/modules/customer_accounts/i18n/en.json +10 -0
  96. package/src/modules/customer_accounts/i18n/es.json +10 -0
  97. package/src/modules/customer_accounts/i18n/ko.json +10 -0
  98. package/src/modules/customer_accounts/i18n/pl.json +10 -0
  99. package/src/modules/customer_accounts/lib/adminOrganizationScope.ts +71 -0
  100. package/src/modules/customers/api/customer-dictionary-entries/route.ts +82 -0
  101. package/src/modules/customers/api/dictionaries/[kind]/route.ts +29 -6
  102. package/src/modules/customers/cli.ts +23 -124
  103. package/src/modules/customers/components/DictionarySettings.tsx +1 -1
  104. package/src/modules/customers/components/detail/ManageTagsDialog.tsx +1 -1
  105. package/src/modules/customers/components/detail/TaskDialog.tsx +15 -1
  106. package/src/modules/customers/components/detail/TaskForm.tsx +1 -17
  107. package/src/modules/customers/components/detail/TasksSection.tsx +44 -14
  108. package/src/modules/customers/components/detail/hooks/useCustomerDictionary.ts +14 -8
  109. package/src/modules/customers/components/detail/hooks/useInteractions.ts +3 -4
  110. package/src/modules/customers/i18n/de.json +81 -0
  111. package/src/modules/customers/i18n/en.json +81 -0
  112. package/src/modules/customers/i18n/es.json +81 -0
  113. package/src/modules/customers/i18n/ko.json +81 -0
  114. package/src/modules/customers/i18n/pl.json +81 -0
  115. package/src/modules/customers/lib/dictionaryDefaults.ts +137 -0
  116. package/src/modules/customers/lib/dictionaryLabels.ts +73 -0
  117. package/src/modules/customers/lib/interactionCompatibility.ts +1 -0
  118. package/src/modules/customers/translations.ts +5 -0
  119. package/src/modules/eudr/index.ts +13 -0
  120. package/src/modules/sales/commands/documents.ts +3 -3
  121. package/src/modules/sales/components/documents/ItemsSection.tsx +82 -23
  122. package/src/modules/sales/components/documents/lineItemUtils.ts +2 -2
  123. package/src/modules/sales/i18n/de.json +1 -0
  124. package/src/modules/sales/i18n/en.json +1 -0
  125. package/src/modules/sales/i18n/es.json +1 -0
  126. package/src/modules/sales/i18n/ko.json +1 -0
  127. package/src/modules/sales/i18n/pl.json +1 -0
  128. package/src/modules/staff/api/timesheets/access-requests/route.ts +13 -14
  129. package/src/modules/staff/api/timesheets/time-projects/route.ts +22 -13
  130. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.tsx +25 -14
  131. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +14 -13
  132. package/src/modules/staff/lib/time-tracking-ui/NoProjectAccess.tsx +30 -8
  133. package/src/modules/staff/lib/time-tracking-ui/projectAccessScope.ts +102 -0
  134. package/src/modules/staff/lib/time-tracking-ui/projectAccessScopeHeaders.ts +15 -0
  135. package/src/modules/sync_excel/index.ts +10 -0
  136. package/src/modules/translations/di.ts +2 -0
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { extensionPoints } from "@open-mercato/core/modules/sales/extension-points";
5
5
  import { apiCall, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
@@ -7,7 +7,8 @@ import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimi
7
7
  import { deleteCrud } from "@open-mercato/ui/backend/utils/crud";
8
8
  import { normalizeCrudServerError } from "@open-mercato/ui/backend/utils/serverErrors";
9
9
  import { ErrorMessage, LoadingMessage, TabEmptyState } from "@open-mercato/ui/backend/detail";
10
- import { Button } from "@open-mercato/ui/primitives/button";
10
+ import { IconButton } from "@open-mercato/ui/primitives/icon-button";
11
+ import { SimpleTooltip } from "@open-mercato/ui/primitives/tooltip";
11
12
  import { flash } from "@open-mercato/ui/backend/FlashMessages";
12
13
  import { Pencil, Trash2 } from "lucide-react";
13
14
  import {
@@ -34,6 +35,50 @@ import { useInjectionDataWidgets } from "@open-mercato/ui/backend/injection/useI
34
35
  import { OrderItemsInjectionContext } from "../../widgets/injection/order-items-context.js";
35
36
  import { createLogger } from "@open-mercato/shared/lib/logger";
36
37
  const logger = createLogger("sales");
38
+ function DisabledActionHint({
39
+ label,
40
+ reason,
41
+ children
42
+ }) {
43
+ const [open, setOpen] = React.useState(false);
44
+ const touchOpenRef = React.useRef(false);
45
+ if (!reason) return /* @__PURE__ */ jsx(Fragment, { children });
46
+ return /* @__PURE__ */ jsx(
47
+ SimpleTooltip,
48
+ {
49
+ content: reason,
50
+ open,
51
+ onOpenChange: (nextOpen) => {
52
+ if (nextOpen || !touchOpenRef.current) setOpen(nextOpen);
53
+ },
54
+ children: /* @__PURE__ */ jsx(
55
+ "span",
56
+ {
57
+ className: "inline-flex rounded-md focus-visible:outline-none focus-visible:shadow-focus",
58
+ tabIndex: 0,
59
+ "aria-label": `${label}: ${reason}`,
60
+ onClick: (event) => event.stopPropagation(),
61
+ onPointerDown: (event) => {
62
+ if (event.pointerType !== "touch") return;
63
+ touchOpenRef.current = true;
64
+ setOpen(true);
65
+ event.currentTarget.focus();
66
+ },
67
+ onBlur: () => {
68
+ touchOpenRef.current = false;
69
+ setOpen(false);
70
+ },
71
+ onKeyDown: (event) => {
72
+ if (event.key !== "Escape") return;
73
+ touchOpenRef.current = false;
74
+ setOpen(false);
75
+ },
76
+ children
77
+ }
78
+ )
79
+ }
80
+ );
81
+ }
37
82
  function isPlainObject(value) {
38
83
  return typeof value === "object" && value !== null && !Array.isArray(value);
39
84
  }
@@ -635,11 +680,11 @@ function SalesDocumentItemsSection({
635
680
  ] }) }),
636
681
  showDiscountColumn ? /* @__PURE__ */ jsx("td", { className: "px-3 py-3", children: discount ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
637
682
  discount.amount !== null ? /* @__PURE__ */ jsx("span", { className: "font-mono text-sm", children: t(
638
- "sales.documents.items.table.discountAmount",
639
- "\u2212{{value}}",
683
+ discount.amount < 0 ? "sales.documents.items.table.markupAmount" : "sales.documents.items.table.discountAmount",
684
+ discount.amount < 0 ? "+{{value}}" : "\u2212{{value}}",
640
685
  {
641
686
  value: formatMoney(
642
- discount.amount,
687
+ Math.abs(discount.amount),
643
688
  item.currencyCode ?? currencyCode ?? void 0,
644
689
  locale
645
690
  )
@@ -695,30 +740,39 @@ function SalesDocumentItemsSection({
695
740
  }),
696
741
  /* @__PURE__ */ jsx("td", { className: "px-3 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 justify-end", children: [
697
742
  /* @__PURE__ */ jsx(
698
- Button,
743
+ DisabledActionHint,
699
744
  {
700
- size: "icon",
701
- variant: "ghost",
702
- className: "h-8 w-8",
703
- "aria-label": t("ui.actions.edit", "Edit"),
704
- disabled: amountsReadOnly,
705
- onClick: (event) => {
706
- event.stopPropagation();
707
- handleEdit(item);
708
- },
709
- children: /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" })
745
+ label: t("ui.actions.edit", "Edit"),
746
+ reason: amountsReadOnly ? t("sales.documents.amountsExternalHint", "Totals on this document come from an external system and are stored as supplied.") : void 0,
747
+ children: /* @__PURE__ */ jsx(
748
+ IconButton,
749
+ {
750
+ type: "button",
751
+ size: "default",
752
+ variant: "ghost",
753
+ "aria-label": t("ui.actions.edit", "Edit"),
754
+ disabled: amountsReadOnly,
755
+ onClick: (event) => {
756
+ event.stopPropagation();
757
+ handleEdit(item);
758
+ },
759
+ children: /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" })
760
+ }
761
+ )
710
762
  }
711
763
  ),
712
764
  /* @__PURE__ */ jsx(
713
- "span",
765
+ DisabledActionHint,
714
766
  {
715
- title: amountsReadOnly ? t("sales.documents.amountsExternalHint", "Totals on this document come from an external system and are stored as supplied.") : kind === "order" && items.length === 1 ? t("sales.documents.items.errorDeleteLast", "An order must contain at least one line item.") : void 0,
767
+ label: t("ui.actions.delete", "Delete"),
768
+ reason: amountsReadOnly ? t("sales.documents.amountsExternalHint", "Totals on this document come from an external system and are stored as supplied.") : kind === "order" && items.length === 1 ? t("sales.documents.items.errorDeleteLast", "An order must contain at least one line item.") : void 0,
716
769
  children: /* @__PURE__ */ jsx(
717
- Button,
770
+ IconButton,
718
771
  {
719
- size: "icon",
772
+ type: "button",
773
+ size: "default",
720
774
  variant: "ghost",
721
- className: "h-8 w-8 text-destructive",
775
+ className: "text-destructive",
722
776
  "aria-label": t("ui.actions.delete", "Delete"),
723
777
  disabled: amountsReadOnly || kind === "order" && items.length === 1,
724
778
  onClick: (event) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/sales/components/documents/ItemsSection.tsx"],
4
- "sourcesContent": ["\"use client\";\n\nimport * as React from \"react\";\nimport { extensionPoints } from \"@open-mercato/core/modules/sales/extension-points\";\nimport { apiCall, withScopedApiRequestHeaders } from \"@open-mercato/ui/backend/utils/apiCall\";\nimport { buildOptimisticLockHeader } from \"@open-mercato/ui/backend/utils/optimisticLock\";\nimport { deleteCrud } from \"@open-mercato/ui/backend/utils/crud\";\nimport { normalizeCrudServerError } from \"@open-mercato/ui/backend/utils/serverErrors\";\nimport { ErrorMessage, LoadingMessage, TabEmptyState } from \"@open-mercato/ui/backend/detail\";\nimport { Button } from \"@open-mercato/ui/primitives/button\";\nimport { flash } from \"@open-mercato/ui/backend/FlashMessages\";\nimport { Pencil, Trash2 } from \"lucide-react\";\nimport {\n DictionaryValue,\n type DictionaryMap,\n createDictionaryMap,\n normalizeDictionaryEntries,\n} from \"@open-mercato/core/modules/dictionaries/components/dictionaryAppearance\";\nimport { cn } from \"@open-mercato/shared/lib/utils\";\nimport { useT, useLocale } from \"@open-mercato/shared/lib/i18n/context\";\nimport { useOrganizationScopeDetail } from \"@open-mercato/shared/lib/frontend/useOrganizationScope\";\nimport { useConfirmDialog } from \"@open-mercato/ui/backend/confirm-dialog\";\nimport { emitSalesDocumentTotalsRefresh } from \"@open-mercato/core/modules/sales/lib/frontend/documentTotalsEvents\";\nimport { LineItemDialog } from \"./LineItemDialog\";\nimport { handleSectionMutationError } from \"./optimisticLock\";\nimport { useSalesDocumentMutation } from \"./useSalesDocumentMutation\";\nimport type { SalesLineRecord } from \"./lineItemTypes\";\nimport {\n formatMoney,\n normalizeNumber,\n resolveLineDiscountDisplay,\n} from \"./lineItemUtils\";\nimport type { SectionAction } from \"@open-mercato/ui/backend/detail\";\nimport { extractCustomFieldValues } from \"./customFieldHelpers\";\nimport { canonicalizeUnitCode } from \"@open-mercato/shared/lib/units/unitCodes\";\nimport type { SalesLineUomSnapshot } from \"../../lib/types\";\nimport { useInjectionDataWidgets } from \"@open-mercato/ui/backend/injection/useInjectionDataWidgets\";\nimport type { InjectionColumnDefinition } from \"@open-mercato/shared/modules/widgets/injection\";\nimport { OrderItemsInjectionContext } from \"../../widgets/injection/order-items-context\";\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\ntype ResolvedUnitPriceReference = {\n grossPerReference: number;\n referenceUnitCode: string;\n};\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isSalesLineUomSnapshot(\n value: unknown,\n): value is SalesLineUomSnapshot {\n if (!isPlainObject(value)) return false;\n return (\n value.version === 1 &&\n typeof value.enteredQuantity === \"string\" &&\n typeof value.toBaseFactor === \"string\" &&\n typeof value.normalizedQuantity === \"string\"\n );\n}\n\nfunction extractUomSnapshot(\n item: Record<string, unknown>,\n): SalesLineUomSnapshot | null {\n const raw = item.uom_snapshot ?? item.uomSnapshot;\n if (isSalesLineUomSnapshot(raw)) return raw;\n return null;\n}\n\nfunction resolveUnitPriceReference(\n snapshot: SalesLineUomSnapshot | Record<string, unknown> | null,\n): ResolvedUnitPriceReference | null {\n if (!snapshot) return null;\n\n const ref = isSalesLineUomSnapshot(snapshot)\n ? snapshot.unitPriceReference\n : isPlainObject(snapshot)\n ? isPlainObject(snapshot.unitPriceReference)\n ? snapshot.unitPriceReference\n : isPlainObject(snapshot.unit_price_reference)\n ? snapshot.unit_price_reference\n : null\n : null;\n\n if (!ref || !isPlainObject(ref)) return null;\n\n const refRecord = ref as Record<string, unknown>;\n const grossPerReference = normalizeNumber(\n refRecord.grossPerReference ?? refRecord.gross_per_reference,\n Number.NaN,\n );\n if (!Number.isFinite(grossPerReference)) return null;\n\n const referenceUnitCode =\n typeof refRecord.referenceUnitCode === \"string\"\n ? refRecord.referenceUnitCode\n : typeof refRecord.reference_unit_code === \"string\"\n ? refRecord.reference_unit_code\n : typeof refRecord.referenceUnit === \"string\"\n ? refRecord.referenceUnit\n : null;\n if (!referenceUnitCode) return null;\n\n return { grossPerReference, referenceUnitCode };\n}\n\nfunction getUomFields(item: Record<string, unknown>) {\n const uomSnapshot = extractUomSnapshot(item);\n return {\n normalizedQuantity: (item.normalized_quantity ?? item.normalizedQuantity ?? null) as\n | number\n | string\n | null,\n normalizedUnit: (item.normalized_unit ?? item.normalizedUnit ?? null) as string | null,\n quantityUnit: (item.quantity_unit ?? item.quantityUnit ?? null) as string | null,\n uomSnapshot,\n };\n}\n\nfunction resolveInjectedColumnValue(\n row: Record<string, unknown>,\n accessorKey: string,\n): unknown {\n const segments = accessorKey.split(\".\").filter(Boolean);\n let current: unknown = row;\n for (const segment of segments) {\n if (!current || typeof current !== \"object\") return undefined;\n current = (current as Record<string, unknown>)[segment];\n }\n return current;\n}\n\nconst LINES_PAGE_SIZE = 100;\n// Upper bound on line pages fetched for one document, so an API that ignores `page`\n// cannot spin the loader forever.\nconst LINES_MAX_PAGES = 200;\n\nconst SHIPMENTS_PAGE_SIZE = 100;\n// A single order beyond this many shipment pages is pathological; stopping there\n// keeps the shipped state explicitly unresolved rather than silently partial.\nconst SHIPMENTS_MAX_PAGES = 50;\n\ntype SalesDocumentItemsSectionProps = {\n documentId: string;\n kind: \"order\" | \"quote\";\n currencyCode: string | null | undefined;\n documentUpdatedAt?: string | null;\n organizationId?: string | null;\n tenantId?: string | null;\n onActionChange?: (action: SectionAction | null) => void;\n onItemsChange?: (items: SalesLineRecord[]) => void;\n /** Disables line writes: on an external order they would all be rejected. */\n amountsReadOnly?: boolean;\n};\n\nexport function SalesDocumentItemsSection({\n documentId,\n kind,\n currencyCode,\n documentUpdatedAt,\n organizationId: orgFromProps,\n tenantId: tenantFromProps,\n onActionChange,\n onItemsChange,\n amountsReadOnly = false,\n}: SalesDocumentItemsSectionProps) {\n const t = useT();\n const runDocumentMutation = useSalesDocumentMutation(kind, documentId);\n const locale = useLocale();\n const { organizationId, tenantId } = useOrganizationScopeDetail();\n const { confirm, ConfirmDialogElement } = useConfirmDialog();\n const resolvedOrganizationId = orgFromProps ?? organizationId ?? null;\n const resolvedTenantId = tenantFromProps ?? tenantId ?? null;\n const [items, setItems] = React.useState<SalesLineRecord[]>([]);\n const [loading, setLoading] = React.useState(false);\n const [error, setError] = React.useState<string | null>(null);\n const [dialogOpen, setDialogOpen] = React.useState(false);\n const [lineForEdit, setLineForEdit] = React.useState<SalesLineRecord | null>(\n null,\n );\n const [lineStatusMap, setLineStatusMap] = React.useState<DictionaryMap>({});\n const [shippedTotals, setShippedTotals] = React.useState<Map<string, number>>(\n new Map(),\n );\n // Quotes have no shipments at all, so their shipped state is known up front.\n // For orders it stays unknown until every shipment page has been read \u2014 an\n // empty map from a pending or failed load must never read as \"nothing shipped\".\n const [shippedTotalsResolved, setShippedTotalsResolved] = React.useState(\n kind !== \"order\",\n );\n\n const { widgets: allColumnWidgets, isLoading: injectedColumnsLoading, error: injectedColumnsError } = useInjectionDataWidgets(\n extensionPoints.hosts.orderItemColumns.spotId,\n );\n const columnWidgets = kind === \"order\" ? allColumnWidgets : [];\n const injectedColumns = React.useMemo<InjectionColumnDefinition[]>(() => {\n const cols: InjectionColumnDefinition[] = [];\n for (const widget of columnWidgets) {\n if (!(\"columns\" in widget)) continue;\n for (const def of (widget as { columns?: InjectionColumnDefinition[] })\n .columns ?? []) {\n cols.push(def);\n }\n }\n return cols;\n }, [columnWidgets]);\n\n const resourcePath = React.useMemo(\n () => (kind === \"order\" ? \"sales/order-lines\" : \"sales/quote-lines\"),\n [kind],\n );\n const documentKey = kind === \"order\" ? \"orderId\" : \"quoteId\";\n const lineStatusesLoaded = React.useRef(false);\n const itemsLoadedForDocument = React.useRef<string | null>(null);\n const itemsLoadSeq = React.useRef(0);\n const shipmentsLoadedForDocument = React.useRef<string | null>(null);\n const loadLineStatuses = React.useCallback(async () => {\n try {\n const params = new URLSearchParams({ page: \"1\", pageSize: \"100\" });\n const response = await apiCall<{\n items?: Array<Record<string, unknown>>;\n }>(`/api/sales/order-line-statuses?${params.toString()}`, undefined, {\n fallback: { items: [] },\n });\n const entries = normalizeDictionaryEntries(response.result?.items ?? [], { sort: false });\n setLineStatusMap(createDictionaryMap(entries));\n } catch (err) {\n logger.error('sales.document.line-statuses.load', { err });\n setLineStatusMap({});\n }\n }, []);\n\n const loadItems = React.useCallback(async () => {\n const loadSeq = ++itemsLoadSeq.current;\n const isCurrentLoad = () => loadSeq === itemsLoadSeq.current;\n setLoading(true);\n setError(null);\n try {\n const collectedItems: Array<Record<string, unknown>> = [];\n const seenIds = new Set<string>();\n let loaded = false;\n let complete = false;\n let page = 1;\n while (page <= LINES_MAX_PAGES) {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(LINES_PAGE_SIZE),\n [documentKey]: documentId,\n });\n const response = await apiCall<{\n items?: Array<Record<string, unknown>>;\n total?: unknown;\n }>(`/api/${resourcePath}?${params.toString()}`, undefined, {\n fallback: { items: [] },\n });\n if (!response.ok || !Array.isArray(response.result?.items)) {\n if (page > 1) throw new Error(\"[internal] sales line page failed to load\");\n complete = true;\n break;\n }\n loaded = true;\n const pageItems = response.result.items;\n let added = 0;\n pageItems.forEach((item) => {\n const id = typeof item.id === \"string\" ? item.id : null;\n if (id && seenIds.has(id)) return;\n if (id) seenIds.add(id);\n collectedItems.push(item);\n added += 1;\n });\n const reportedTotal = normalizeNumber(response.result?.total, Number.NaN);\n const hasMore =\n added > 0 &&\n pageItems.length >= LINES_PAGE_SIZE &&\n (!Number.isFinite(reportedTotal) || collectedItems.length < reportedTotal);\n if (!hasMore) {\n complete = true;\n break;\n }\n page += 1;\n }\n if (!complete) throw new Error(\"[internal] sales line page limit reached\");\n if (!isCurrentLoad()) return;\n if (loaded) {\n const mapped = collectedItems.flatMap<SalesLineRecord>(\n (item) => {\n const id = typeof item.id === \"string\" ? item.id : null;\n if (!id) return [];\n const taxRate = normalizeNumber(\n item.tax_rate ?? item.taxRate,\n 0,\n );\n const customFields = extractCustomFieldValues(\n item as Record<string, unknown>,\n );\n const name =\n typeof item.name === \"string\"\n ? item.name\n : typeof item.catalog_snapshot === \"object\" &&\n item.catalog_snapshot &&\n typeof (item.catalog_snapshot as Record<string, unknown>).name === \"string\"\n ? (item.catalog_snapshot as Record<string, unknown>).name as string\n : null;\n const description =\n typeof item.description === \"string\" && item.description.trim()\n ? item.description\n : null;\n const quantity = normalizeNumber(item.quantity, 0);\n const uomFields = getUomFields(item);\n const quantityUnit = canonicalizeUnitCode(uomFields.quantityUnit);\n const normalizedQuantity = normalizeNumber(\n uomFields.normalizedQuantity,\n quantity,\n );\n const normalizedUnit =\n canonicalizeUnitCode(uomFields.normalizedUnit) ?? quantityUnit;\n const uomSnapshot = uomFields.uomSnapshot;\n const unitPriceNetRaw = normalizeNumber(\n item.unit_price_net ?? item.unitPriceNet,\n Number.NaN,\n );\n const unitPriceGrossRaw = normalizeNumber(\n item.unit_price_gross ?? item.unitPriceGross,\n Number.NaN,\n );\n const unitPriceNet = Number.isFinite(unitPriceNetRaw)\n ? unitPriceNetRaw\n : Number.isFinite(unitPriceGrossRaw)\n ? unitPriceGrossRaw / (1 + taxRate / 100)\n : 0;\n const unitPriceGross = Number.isFinite(unitPriceGrossRaw)\n ? unitPriceGrossRaw\n : Number.isFinite(unitPriceNetRaw)\n ? unitPriceNetRaw * (1 + taxRate / 100)\n : 0;\n const totalNetRaw = normalizeNumber(\n item.total_net_amount ?? item.totalNetAmount,\n Number.NaN,\n );\n const totalGrossRaw = normalizeNumber(\n item.total_gross_amount ?? item.totalGrossAmount,\n Number.NaN,\n );\n const totalNet = Number.isFinite(totalNetRaw)\n ? totalNetRaw\n : unitPriceNet * quantity;\n const totalGross = Number.isFinite(totalGrossRaw)\n ? totalGrossRaw\n : unitPriceGross * quantity;\n const priceModeRaw =\n item.metadata &&\n typeof item.metadata === \"object\"\n ? (item.metadata as Record<string, unknown>).priceMode\n : null;\n const priceMode = priceModeRaw === \"net\" ? \"net\" : \"gross\";\n const customFieldSetId =\n typeof item.custom_field_set_id === \"string\"\n ? item.custom_field_set_id\n : typeof item.customFieldSetId === \"string\"\n ? item.customFieldSetId\n : null;\n const statusEntryId =\n typeof item.status_entry_id === \"string\"\n ? item.status_entry_id\n : typeof item.statusEntryId === \"string\"\n ? item.statusEntryId\n : null;\n const status = typeof item.status === \"string\" ? item.status : null;\n const record: SalesLineRecord = {\n id,\n name,\n description,\n productId:\n typeof item.product_id === \"string\" ? item.product_id : null,\n productVariantId:\n typeof item.product_variant_id === \"string\"\n ? item.product_variant_id\n : null,\n quantity,\n quantityUnit,\n normalizedQuantity,\n normalizedUnit,\n currencyCode:\n typeof item.currency_code === \"string\"\n ? item.currency_code\n : typeof currencyCode === \"string\"\n ? currencyCode\n : null,\n unitPriceNet,\n unitPriceGross,\n discountAmount: normalizeNumber(\n item.discount_amount ?? item.discountAmount,\n 0,\n ),\n discountPercent: normalizeNumber(\n item.discount_percent ?? item.discountPercent,\n 0,\n ),\n taxRate,\n totalNet,\n totalGross,\n priceMode,\n uomSnapshot,\n metadata:\n (item.metadata as Record<string, unknown> | null | undefined) ??\n null,\n catalogSnapshot:\n (item.catalog_snapshot as\n | Record<string, unknown>\n | null\n | undefined) ?? null,\n customFieldSetId,\n customFields: Object.keys(customFields).length\n ? customFields\n : null,\n status,\n statusEntryId,\n };\n return [record];\n },\n );\n setItems(mapped);\n if (onItemsChange) onItemsChange(mapped);\n } else {\n setItems([]);\n if (onItemsChange) onItemsChange([]);\n }\n } catch (err) {\n if (!isCurrentLoad()) return;\n logger.error('sales.document.items.load', { err });\n setError(t(\"sales.documents.items.errorLoad\", \"Failed to load items.\"));\n setItems([]);\n if (onItemsChange) onItemsChange([]);\n } finally {\n if (isCurrentLoad()) setLoading(false);\n }\n }, [currencyCode, documentId, documentKey, onItemsChange, resourcePath, t]);\n\n const loadShippedTotals = React.useCallback(async () => {\n if (kind !== \"order\") {\n setShippedTotals(new Map());\n setShippedTotalsResolved(true);\n return;\n }\n setShippedTotals(new Map());\n setShippedTotalsResolved(false);\n try {\n const totals = new Map<string, number>();\n let page = 1;\n let collected = 0;\n let complete = false;\n while (page <= SHIPMENTS_MAX_PAGES) {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(SHIPMENTS_PAGE_SIZE),\n orderId: documentId,\n });\n const response = await apiCall<{\n items?: Array<Record<string, unknown>>;\n total?: unknown;\n }>(`/api/sales/shipments?${params.toString()}`, undefined, {\n fallback: { items: [] },\n });\n if (!response.ok || !Array.isArray(response.result?.items)) return;\n const shipments = response.result.items;\n shipments.forEach((shipment) => {\n const entries = Array.isArray(shipment.items)\n ? (shipment.items as Array<Record<string, unknown>>)\n : [];\n entries.forEach((entry) => {\n const lineId =\n typeof entry.orderLineId === \"string\"\n ? entry.orderLineId\n : typeof entry.order_line_id === \"string\"\n ? entry.order_line_id\n : null;\n if (!lineId) return;\n const quantity = normalizeNumber(entry.quantity, 0);\n if (!Number.isFinite(quantity) || quantity <= 0) return;\n const current = totals.get(lineId) ?? 0;\n totals.set(lineId, current + quantity);\n });\n });\n collected += shipments.length;\n const reportedTotal = normalizeNumber(response.result?.total, Number.NaN);\n const hasMore =\n shipments.length >= SHIPMENTS_PAGE_SIZE &&\n (!Number.isFinite(reportedTotal) || collected < reportedTotal);\n if (!hasMore) {\n complete = true;\n break;\n }\n page += 1;\n }\n if (!complete) return;\n setShippedTotals(totals);\n setShippedTotalsResolved(true);\n } catch (err) {\n logger.error('sales.document.shipments.load', { err });\n }\n }, [documentId, kind]);\n\n React.useEffect(() => {\n if (lineStatusesLoaded.current) return;\n lineStatusesLoaded.current = true;\n void loadLineStatuses();\n }, [loadLineStatuses]);\n\n React.useEffect(() => {\n if (!documentId) return;\n if (itemsLoadedForDocument.current === documentId) return;\n itemsLoadedForDocument.current = documentId;\n void loadItems();\n }, [documentId, loadItems]);\n\n React.useEffect(() => {\n if (kind !== \"order\") {\n shipmentsLoadedForDocument.current = null;\n setShippedTotals(new Map());\n setShippedTotalsResolved(true);\n return;\n }\n const key = `${kind}:${documentId}`;\n if (shipmentsLoadedForDocument.current === key) return;\n shipmentsLoadedForDocument.current = key;\n void loadShippedTotals();\n }, [documentId, kind, loadShippedTotals]);\n\n const openCreate = React.useCallback(() => {\n setLineForEdit(null);\n setDialogOpen(true);\n }, []);\n\n React.useEffect(() => {\n if (!onActionChange) return;\n onActionChange({\n label: t(\"sales.documents.items.add\", \"Add item\"),\n onClick: openCreate,\n disabled: amountsReadOnly,\n });\n return () => onActionChange(null);\n }, [amountsReadOnly, onActionChange, openCreate, t]);\n\n const handleEdit = React.useCallback(\n (line: SalesLineRecord) => {\n if (amountsReadOnly) return;\n setLineForEdit(line);\n setDialogOpen(true);\n },\n [amountsReadOnly],\n );\n\n const resolveVariantInfo = React.useCallback((record: SalesLineRecord) => {\n const meta =\n (record.metadata as Record<string, unknown> | null | undefined) ?? null;\n const snapshot =\n (record.catalogSnapshot as Record<string, unknown> | null | undefined) ??\n null;\n const variantSnapshot =\n snapshot &&\n typeof snapshot.variant === \"object\" &&\n snapshot.variant\n ? (snapshot.variant as Record<string, unknown>)\n : null;\n const variantTitle =\n meta && typeof meta.variantTitle === \"string\"\n ? meta.variantTitle\n : variantSnapshot && typeof variantSnapshot.name === \"string\"\n ? variantSnapshot.name\n : null;\n const variantSku =\n meta && typeof meta.variantSku === \"string\"\n ? meta.variantSku\n : variantSnapshot && typeof variantSnapshot.sku === \"string\"\n ? variantSnapshot.sku\n : null;\n\n return { variantTitle, variantSku };\n }, []);\n\n const handleDelete = React.useCallback(\n async (line: SalesLineRecord) => {\n const confirmed = await confirm({\n title: t(\n \"sales.documents.items.deleteConfirm\",\n \"Delete this line item?\",\n ),\n variant: \"destructive\",\n });\n if (!confirmed) return;\n try {\n const result = await runDocumentMutation(() => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(documentUpdatedAt),\n () =>\n deleteCrud(resourcePath, {\n body: {\n id: line.id,\n [documentKey]: documentId,\n organizationId: resolvedOrganizationId ?? undefined,\n tenantId: resolvedTenantId ?? undefined,\n },\n errorMessage: t(\n \"sales.documents.items.errorDelete\",\n \"Failed to delete line.\",\n ),\n }),\n ), { id: line.id, [documentKey]: documentId });\n if (result.ok) {\n flash(t(\"sales.documents.items.deleted\", \"Line removed.\"), \"success\");\n await loadItems();\n emitSalesDocumentTotalsRefresh({ documentId, kind });\n }\n } catch (err) {\n if (handleSectionMutationError(err, t, () => void loadItems())) return;\n logger.error('sales.document.items.delete', { err });\n const normalized = normalizeCrudServerError(err);\n const fallback = t(\n \"sales.documents.items.errorDelete\",\n \"Failed to delete line.\",\n );\n flash(normalized.message || fallback, \"error\");\n }\n },\n [\n confirm,\n documentId,\n documentKey,\n documentUpdatedAt,\n kind,\n loadItems,\n resolvedOrganizationId,\n resourcePath,\n t,\n resolvedTenantId,\n runDocumentMutation,\n ],\n );\n\n const renderStatus = React.useCallback(\n (line: SalesLineRecord) => {\n const value = line.status ?? null;\n if (!value) {\n return (\n <span className=\"text-xs text-muted-foreground\">\n {t(\"sales.documents.items.table.statusEmpty\", \"No status\")}\n </span>\n );\n }\n return (\n <DictionaryValue\n value={value}\n map={lineStatusMap}\n fallback={<span className=\"text-xs font-medium\">{value}</span>}\n className=\"text-xs font-medium\"\n iconWrapperClassName=\"inline-flex h-6 w-6 items-center justify-center rounded bg-muted text-muted-foreground\"\n iconClassName=\"h-3.5 w-3.5\"\n colorClassName=\"h-4 w-4 rounded-full border border-border/70\"\n />\n );\n },\n [lineStatusMap, t],\n );\n\n const showDiscountColumn = React.useMemo(\n () => items.some((item) => resolveLineDiscountDisplay(item) !== null),\n [items],\n );\n\n const renderImage = (record: SalesLineRecord) => {\n const meta =\n (record.metadata as Record<string, unknown> | null | undefined) ?? {};\n const snapshot =\n (record.catalogSnapshot as Record<string, unknown> | null | undefined) ??\n {};\n const productSnapshot: Record<string, unknown> =\n typeof snapshot === \"object\" && snapshot\n ? ((snapshot.product as Record<string, unknown>) ?? {})\n : {};\n const variantSnapshot: Record<string, unknown> =\n typeof snapshot === \"object\" && snapshot\n ? ((snapshot.variant as Record<string, unknown>) ?? {})\n : {};\n const productThumb =\n (meta &&\n typeof meta.productThumbnail === \"string\" &&\n meta.productThumbnail) ||\n (productSnapshot &&\n typeof productSnapshot.thumbnailUrl === \"string\" &&\n productSnapshot.thumbnailUrl) ||\n null;\n const variantThumb =\n (meta &&\n typeof meta.variantThumbnail === \"string\" &&\n meta.variantThumbnail) ||\n (variantSnapshot &&\n typeof variantSnapshot.thumbnailUrl === \"string\" &&\n variantSnapshot.thumbnailUrl) ||\n null;\n const thumbnail = variantThumb ?? productThumb;\n if (thumbnail) {\n return (\n <img\n src={thumbnail}\n alt={record.name ?? record.id}\n className=\"h-10 w-10 rounded border object-cover\"\n />\n );\n }\n return (\n <div className=\"flex h-10 w-10 items-center justify-center rounded border bg-muted text-xs text-muted-foreground\">\n N/A\n </div>\n );\n };\n\n return (\n <OrderItemsInjectionContext.Provider value={{ documentId, kind }}>\n <div className=\"space-y-4\">\n {kind === \"order\" && injectedColumnsError ? (\n <ErrorMessage label={t('ui.dataTable.extensions.error', 'Some table extensions could not load. Reload the page to retry.')} />\n ) : null}\n {loading || (kind === \"order\" && injectedColumnsLoading) ? (\n <LoadingMessage\n label={t(\"sales.documents.items.loading\", \"Loading items\u2026\")}\n className=\"border-0 bg-transparent p-0 py-8 justify-center\"\n />\n ) : error ? (\n <p className=\"text-sm text-destructive\">{error}</p>\n ) : items.length === 0 ? (\n <TabEmptyState\n title={t(\"sales.documents.items.empty\", \"No items yet.\")}\n description={t(\n \"sales.documents.items.subtitle\",\n \"Add products and configure pricing for this document.\",\n )}\n action={{\n label: t(\"sales.documents.items.add\", \"Add item\"),\n onClick: openCreate,\n disabled: amountsReadOnly,\n }}\n />\n ) : (\n <div className=\"relative overflow-x-auto rounded border\">\n <table className=\"w-full text-sm\">\n <thead className=\"bg-muted\">\n <tr className=\"text-left\">\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.product\", \"Product\")}\n </th>\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.status\", \"Status\")}\n </th>\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.quantity\", \"Qty\")}\n </th>\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.unit\", \"Unit price\")}\n </th>\n {showDiscountColumn ? (\n <th className=\"px-3 py-2 font-medium whitespace-nowrap\">\n {t(\"sales.documents.items.table.discount\", \"Discount\")}\n </th>\n ) : null}\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.total\", \"Total\")}\n </th>\n {injectedColumns.map((col) => (\n <th\n key={col.id}\n className=\"px-3 py-2 font-medium whitespace-nowrap\"\n >\n {col.headerKey ? t(col.headerKey, col.header) : col.header}\n </th>\n ))}\n <th className=\"px-3 py-2 font-medium sr-only\">\n {t(\"sales.documents.items.table.actions\", \"Actions\")}\n </th>\n </tr>\n </thead>\n <tbody>\n {items.map((item) => {\n const meta =\n (item.metadata as\n | Record<string, unknown>\n | null\n | undefined) ?? null;\n const { variantTitle, variantSku } = resolveVariantInfo(item);\n const productSku =\n meta && typeof meta.productSku === \"string\"\n ? meta.productSku\n : null;\n const variantLabel = variantTitle ?? variantSku;\n const variantSuffix =\n variantSku && variantLabel && variantSku !== variantLabel\n ? ` \u2022 ${variantSku}`\n : \"\";\n const showProductSku =\n productSku && productSku !== variantSku ? productSku : null;\n const shippedQuantity = Math.max(\n 0,\n shippedTotals.get(item.id) ?? 0,\n );\n const quantityLabel = item.quantityUnit\n ? `${item.quantity} ${item.quantityUnit}`\n : String(item.quantity);\n const showNormalized =\n Number.isFinite(item.normalizedQuantity) &&\n item.normalizedQuantity > 0 &&\n (item.normalizedUnit ?? null) &&\n (Math.abs(item.normalizedQuantity - item.quantity) >\n 0.000001 ||\n (item.normalizedUnit ?? null) !==\n (item.quantityUnit ?? null));\n const unitPriceReference = resolveUnitPriceReference(\n item.uomSnapshot,\n );\n const discount = resolveLineDiscountDisplay(item);\n\n return (\n <tr\n key={item.id}\n className={cn(\n \"border-t transition-colors\",\n amountsReadOnly ? \"\" : \"cursor-pointer hover:bg-muted/50\",\n )}\n onClick={() => handleEdit(item)}\n >\n <td className=\"px-3 py-3\">\n <div className=\"flex items-center gap-3\">\n {renderImage(item)}\n <div className=\"min-w-0\">\n <div className=\"truncate font-medium\">\n {item.name ??\n t(\"sales.documents.items.untitled\", \"Untitled\")}\n </div>\n {variantLabel ? (\n <div className=\"text-xs text-muted-foreground truncate\">\n {variantLabel}\n {variantSuffix}\n </div>\n ) : null}\n {showProductSku ? (\n <div className=\"text-xs text-muted-foreground truncate\">\n {showProductSku}\n </div>\n ) : null}\n {item.description ? (\n <div\n className=\"text-xs text-muted-foreground line-clamp-2\"\n title={item.description}\n >\n {item.description}\n </div>\n ) : null}\n </div>\n </div>\n </td>\n <td className=\"px-3 py-3\">\n <div className=\"flex items-center\">\n {renderStatus(item)}\n </div>\n </td>\n <td className=\"px-3 py-3\">\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"font-medium\">{quantityLabel}</span>\n {showNormalized ? (\n <span className=\"text-xs text-muted-foreground\">\n {item.normalizedQuantity} {item.normalizedUnit}\n </span>\n ) : null}\n {shippedQuantity > 0 ? (\n <span className=\"text-xs text-muted-foreground\">\n {t(\n \"sales.documents.items.table.shipped\",\n \"{{shipped}} / {{total}} shipped\",\n {\n shipped: shippedQuantity,\n total: item.quantity,\n },\n )}\n </span>\n ) : null}\n </div>\n </td>\n <td className=\"px-3 py-3\">\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"font-mono text-sm\">\n {formatMoney(\n item.unitPriceGross,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n <span className=\"text-xs text-muted-foreground\">\n {t(\"sales.documents.items.table.gross\", \"gross\")}\n </span>\n </span>\n <span className=\"font-mono text-xs text-muted-foreground\">\n {formatMoney(\n item.unitPriceNet,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n {t(\"sales.documents.items.table.net\", \"net\")}\n </span>\n {unitPriceReference ? (\n <span className=\"text-xs text-muted-foreground\">\n {t(\n \"sales.documents.items.table.unitPriceReference\",\n \"{{value}} per 1 {{unit}}\",\n {\n value: formatMoney(\n unitPriceReference.grossPerReference,\n item.currencyCode ??\n currencyCode ??\n undefined,\n locale,\n ),\n unit: unitPriceReference.referenceUnitCode,\n },\n )}\n </span>\n ) : null}\n </div>\n </td>\n {showDiscountColumn ? (\n <td className=\"px-3 py-3\">\n {discount ? (\n <div className=\"flex flex-col gap-0.5\">\n {discount.amount !== null ? (\n <span className=\"font-mono text-sm\">\n {t(\n \"sales.documents.items.table.discountAmount\",\n \"\u2212{{value}}\",\n {\n value: formatMoney(\n discount.amount,\n item.currencyCode ??\n currencyCode ??\n undefined,\n locale,\n ),\n },\n )}\n </span>\n ) : null}\n {discount.percent !== null ? (\n <span\n className={\n discount.amount !== null\n ? \"font-mono text-xs text-muted-foreground\"\n : \"font-mono text-sm\"\n }\n >\n {t(\n \"sales.documents.items.table.discountPercent\",\n \"{{value}}%\",\n { value: discount.percent },\n )}\n </span>\n ) : null}\n </div>\n ) : null}\n </td>\n ) : null}\n <td className=\"px-3 py-3 font-semibold\">\n <div className=\"flex flex-col gap-0.5\">\n <span>\n {formatMoney(\n item.totalGross,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n <span className=\"text-xs font-normal text-muted-foreground\">\n {t(\"sales.documents.items.table.gross\", \"gross\")}\n </span>\n </span>\n <span className=\"text-xs font-medium text-muted-foreground\">\n {formatMoney(\n item.totalNet,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n {t(\"sales.documents.items.table.net\", \"net\")}\n </span>\n </div>\n </td>\n {injectedColumns.map((col) => {\n const colValue = resolveInjectedColumnValue(\n item as unknown as Record<string, unknown>,\n col.accessorKey,\n );\n const Cell = col.cell;\n return (\n <td\n key={col.id}\n className=\"px-3 py-3\"\n onClick={(e) => e.stopPropagation()}\n >\n {Cell ? <Cell getValue={() => colValue} /> : null}\n </td>\n );\n })}\n <td className=\"px-3 py-3\">\n <div className=\"flex items-center gap-2 justify-end\">\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"h-8 w-8\"\n aria-label={t('ui.actions.edit', 'Edit')}\n disabled={amountsReadOnly}\n onClick={(event) => {\n event.stopPropagation();\n handleEdit(item);\n }}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <span\n title={amountsReadOnly\n ? t('sales.documents.amountsExternalHint', 'Totals on this document come from an external system and are stored as supplied.')\n : kind === 'order' && items.length === 1\n ? t('sales.documents.items.errorDeleteLast', 'An order must contain at least one line item.')\n : undefined}\n >\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"h-8 w-8 text-destructive\"\n aria-label={t('ui.actions.delete', 'Delete')}\n disabled={amountsReadOnly || (kind === 'order' && items.length === 1)}\n onClick={(event) => {\n event.stopPropagation();\n void handleDelete(item);\n }}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </span>\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n )}\n\n <LineItemDialog\n open={dialogOpen}\n onOpenChange={(next) => {\n setDialogOpen(next);\n if (!next) setLineForEdit(null);\n }}\n kind={kind}\n documentId={documentId}\n currencyCode={currencyCode}\n documentUpdatedAt={documentUpdatedAt}\n organizationId={resolvedOrganizationId}\n tenantId={resolvedTenantId}\n initialLine={lineForEdit}\n shippedQuantity={\n lineForEdit\n ? Math.max(0, shippedTotals.get(lineForEdit.id) ?? 0)\n : 0\n }\n shippedQuantityResolved={shippedTotalsResolved}\n onSaved={async () => {\n await loadItems();\n emitSalesDocumentTotalsRefresh({ documentId, kind });\n }}\n />\n {ConfirmDialogElement}\n </div>\n </OrderItemsInjectionContext.Provider>\n );\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\";\n\nimport * as React from \"react\";\nimport { extensionPoints } from \"@open-mercato/core/modules/sales/extension-points\";\nimport { apiCall, withScopedApiRequestHeaders } from \"@open-mercato/ui/backend/utils/apiCall\";\nimport { buildOptimisticLockHeader } from \"@open-mercato/ui/backend/utils/optimisticLock\";\nimport { deleteCrud } from \"@open-mercato/ui/backend/utils/crud\";\nimport { normalizeCrudServerError } from \"@open-mercato/ui/backend/utils/serverErrors\";\nimport { ErrorMessage, LoadingMessage, TabEmptyState } from \"@open-mercato/ui/backend/detail\";\nimport { IconButton } from \"@open-mercato/ui/primitives/icon-button\";\nimport { SimpleTooltip } from \"@open-mercato/ui/primitives/tooltip\";\nimport { flash } from \"@open-mercato/ui/backend/FlashMessages\";\nimport { Pencil, Trash2 } from \"lucide-react\";\nimport {\n DictionaryValue,\n type DictionaryMap,\n createDictionaryMap,\n normalizeDictionaryEntries,\n} from \"@open-mercato/core/modules/dictionaries/components/dictionaryAppearance\";\nimport { cn } from \"@open-mercato/shared/lib/utils\";\nimport { useT, useLocale } from \"@open-mercato/shared/lib/i18n/context\";\nimport { useOrganizationScopeDetail } from \"@open-mercato/shared/lib/frontend/useOrganizationScope\";\nimport { useConfirmDialog } from \"@open-mercato/ui/backend/confirm-dialog\";\nimport { emitSalesDocumentTotalsRefresh } from \"@open-mercato/core/modules/sales/lib/frontend/documentTotalsEvents\";\nimport { LineItemDialog } from \"./LineItemDialog\";\nimport { handleSectionMutationError } from \"./optimisticLock\";\nimport { useSalesDocumentMutation } from \"./useSalesDocumentMutation\";\nimport type { SalesLineRecord } from \"./lineItemTypes\";\nimport {\n formatMoney,\n normalizeNumber,\n resolveLineDiscountDisplay,\n} from \"./lineItemUtils\";\nimport type { SectionAction } from \"@open-mercato/ui/backend/detail\";\nimport { extractCustomFieldValues } from \"./customFieldHelpers\";\nimport { canonicalizeUnitCode } from \"@open-mercato/shared/lib/units/unitCodes\";\nimport type { SalesLineUomSnapshot } from \"../../lib/types\";\nimport { useInjectionDataWidgets } from \"@open-mercato/ui/backend/injection/useInjectionDataWidgets\";\nimport type { InjectionColumnDefinition } from \"@open-mercato/shared/modules/widgets/injection\";\nimport { OrderItemsInjectionContext } from \"../../widgets/injection/order-items-context\";\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\nfunction DisabledActionHint({\n label,\n reason,\n children,\n}: {\n label: string\n reason?: string\n children: React.ReactNode\n}) {\n const [open, setOpen] = React.useState(false)\n const touchOpenRef = React.useRef(false)\n if (!reason) return <>{children}</>\n return (\n <SimpleTooltip\n content={reason}\n open={open}\n onOpenChange={(nextOpen) => {\n if (nextOpen || !touchOpenRef.current) setOpen(nextOpen)\n }}\n >\n <span\n className=\"inline-flex rounded-md focus-visible:outline-none focus-visible:shadow-focus\"\n tabIndex={0}\n aria-label={`${label}: ${reason}`}\n onClick={(event) => event.stopPropagation()}\n onPointerDown={(event) => {\n if (event.pointerType !== 'touch') return\n touchOpenRef.current = true\n setOpen(true)\n event.currentTarget.focus()\n }}\n onBlur={() => {\n touchOpenRef.current = false\n setOpen(false)\n }}\n onKeyDown={(event) => {\n if (event.key !== 'Escape') return\n touchOpenRef.current = false\n setOpen(false)\n }}\n >\n {children}\n </span>\n </SimpleTooltip>\n )\n}\n\ntype ResolvedUnitPriceReference = {\n grossPerReference: number;\n referenceUnitCode: string;\n};\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isSalesLineUomSnapshot(\n value: unknown,\n): value is SalesLineUomSnapshot {\n if (!isPlainObject(value)) return false;\n return (\n value.version === 1 &&\n typeof value.enteredQuantity === \"string\" &&\n typeof value.toBaseFactor === \"string\" &&\n typeof value.normalizedQuantity === \"string\"\n );\n}\n\nfunction extractUomSnapshot(\n item: Record<string, unknown>,\n): SalesLineUomSnapshot | null {\n const raw = item.uom_snapshot ?? item.uomSnapshot;\n if (isSalesLineUomSnapshot(raw)) return raw;\n return null;\n}\n\nfunction resolveUnitPriceReference(\n snapshot: SalesLineUomSnapshot | Record<string, unknown> | null,\n): ResolvedUnitPriceReference | null {\n if (!snapshot) return null;\n\n const ref = isSalesLineUomSnapshot(snapshot)\n ? snapshot.unitPriceReference\n : isPlainObject(snapshot)\n ? isPlainObject(snapshot.unitPriceReference)\n ? snapshot.unitPriceReference\n : isPlainObject(snapshot.unit_price_reference)\n ? snapshot.unit_price_reference\n : null\n : null;\n\n if (!ref || !isPlainObject(ref)) return null;\n\n const refRecord = ref as Record<string, unknown>;\n const grossPerReference = normalizeNumber(\n refRecord.grossPerReference ?? refRecord.gross_per_reference,\n Number.NaN,\n );\n if (!Number.isFinite(grossPerReference)) return null;\n\n const referenceUnitCode =\n typeof refRecord.referenceUnitCode === \"string\"\n ? refRecord.referenceUnitCode\n : typeof refRecord.reference_unit_code === \"string\"\n ? refRecord.reference_unit_code\n : typeof refRecord.referenceUnit === \"string\"\n ? refRecord.referenceUnit\n : null;\n if (!referenceUnitCode) return null;\n\n return { grossPerReference, referenceUnitCode };\n}\n\nfunction getUomFields(item: Record<string, unknown>) {\n const uomSnapshot = extractUomSnapshot(item);\n return {\n normalizedQuantity: (item.normalized_quantity ?? item.normalizedQuantity ?? null) as\n | number\n | string\n | null,\n normalizedUnit: (item.normalized_unit ?? item.normalizedUnit ?? null) as string | null,\n quantityUnit: (item.quantity_unit ?? item.quantityUnit ?? null) as string | null,\n uomSnapshot,\n };\n}\n\nfunction resolveInjectedColumnValue(\n row: Record<string, unknown>,\n accessorKey: string,\n): unknown {\n const segments = accessorKey.split(\".\").filter(Boolean);\n let current: unknown = row;\n for (const segment of segments) {\n if (!current || typeof current !== \"object\") return undefined;\n current = (current as Record<string, unknown>)[segment];\n }\n return current;\n}\n\nconst LINES_PAGE_SIZE = 100;\n// Upper bound on line pages fetched for one document, so an API that ignores `page`\n// cannot spin the loader forever.\nconst LINES_MAX_PAGES = 200;\n\nconst SHIPMENTS_PAGE_SIZE = 100;\n// A single order beyond this many shipment pages is pathological; stopping there\n// keeps the shipped state explicitly unresolved rather than silently partial.\nconst SHIPMENTS_MAX_PAGES = 50;\n\ntype SalesDocumentItemsSectionProps = {\n documentId: string;\n kind: \"order\" | \"quote\";\n currencyCode: string | null | undefined;\n documentUpdatedAt?: string | null;\n organizationId?: string | null;\n tenantId?: string | null;\n onActionChange?: (action: SectionAction | null) => void;\n onItemsChange?: (items: SalesLineRecord[]) => void;\n /** Disables line writes: on an external order they would all be rejected. */\n amountsReadOnly?: boolean;\n};\n\nexport function SalesDocumentItemsSection({\n documentId,\n kind,\n currencyCode,\n documentUpdatedAt,\n organizationId: orgFromProps,\n tenantId: tenantFromProps,\n onActionChange,\n onItemsChange,\n amountsReadOnly = false,\n}: SalesDocumentItemsSectionProps) {\n const t = useT();\n const runDocumentMutation = useSalesDocumentMutation(kind, documentId);\n const locale = useLocale();\n const { organizationId, tenantId } = useOrganizationScopeDetail();\n const { confirm, ConfirmDialogElement } = useConfirmDialog();\n const resolvedOrganizationId = orgFromProps ?? organizationId ?? null;\n const resolvedTenantId = tenantFromProps ?? tenantId ?? null;\n const [items, setItems] = React.useState<SalesLineRecord[]>([]);\n const [loading, setLoading] = React.useState(false);\n const [error, setError] = React.useState<string | null>(null);\n const [dialogOpen, setDialogOpen] = React.useState(false);\n const [lineForEdit, setLineForEdit] = React.useState<SalesLineRecord | null>(\n null,\n );\n const [lineStatusMap, setLineStatusMap] = React.useState<DictionaryMap>({});\n const [shippedTotals, setShippedTotals] = React.useState<Map<string, number>>(\n new Map(),\n );\n // Quotes have no shipments at all, so their shipped state is known up front.\n // For orders it stays unknown until every shipment page has been read \u2014 an\n // empty map from a pending or failed load must never read as \"nothing shipped\".\n const [shippedTotalsResolved, setShippedTotalsResolved] = React.useState(\n kind !== \"order\",\n );\n\n const { widgets: allColumnWidgets, isLoading: injectedColumnsLoading, error: injectedColumnsError } = useInjectionDataWidgets(\n extensionPoints.hosts.orderItemColumns.spotId,\n );\n const columnWidgets = kind === \"order\" ? allColumnWidgets : [];\n const injectedColumns = React.useMemo<InjectionColumnDefinition[]>(() => {\n const cols: InjectionColumnDefinition[] = [];\n for (const widget of columnWidgets) {\n if (!(\"columns\" in widget)) continue;\n for (const def of (widget as { columns?: InjectionColumnDefinition[] })\n .columns ?? []) {\n cols.push(def);\n }\n }\n return cols;\n }, [columnWidgets]);\n\n const resourcePath = React.useMemo(\n () => (kind === \"order\" ? \"sales/order-lines\" : \"sales/quote-lines\"),\n [kind],\n );\n const documentKey = kind === \"order\" ? \"orderId\" : \"quoteId\";\n const lineStatusesLoaded = React.useRef(false);\n const itemsLoadedForDocument = React.useRef<string | null>(null);\n const itemsLoadSeq = React.useRef(0);\n const shipmentsLoadedForDocument = React.useRef<string | null>(null);\n const loadLineStatuses = React.useCallback(async () => {\n try {\n const params = new URLSearchParams({ page: \"1\", pageSize: \"100\" });\n const response = await apiCall<{\n items?: Array<Record<string, unknown>>;\n }>(`/api/sales/order-line-statuses?${params.toString()}`, undefined, {\n fallback: { items: [] },\n });\n const entries = normalizeDictionaryEntries(response.result?.items ?? [], { sort: false });\n setLineStatusMap(createDictionaryMap(entries));\n } catch (err) {\n logger.error('sales.document.line-statuses.load', { err });\n setLineStatusMap({});\n }\n }, []);\n\n const loadItems = React.useCallback(async () => {\n const loadSeq = ++itemsLoadSeq.current;\n const isCurrentLoad = () => loadSeq === itemsLoadSeq.current;\n setLoading(true);\n setError(null);\n try {\n const collectedItems: Array<Record<string, unknown>> = [];\n const seenIds = new Set<string>();\n let loaded = false;\n let complete = false;\n let page = 1;\n while (page <= LINES_MAX_PAGES) {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(LINES_PAGE_SIZE),\n [documentKey]: documentId,\n });\n const response = await apiCall<{\n items?: Array<Record<string, unknown>>;\n total?: unknown;\n }>(`/api/${resourcePath}?${params.toString()}`, undefined, {\n fallback: { items: [] },\n });\n if (!response.ok || !Array.isArray(response.result?.items)) {\n if (page > 1) throw new Error(\"[internal] sales line page failed to load\");\n complete = true;\n break;\n }\n loaded = true;\n const pageItems = response.result.items;\n let added = 0;\n pageItems.forEach((item) => {\n const id = typeof item.id === \"string\" ? item.id : null;\n if (id && seenIds.has(id)) return;\n if (id) seenIds.add(id);\n collectedItems.push(item);\n added += 1;\n });\n const reportedTotal = normalizeNumber(response.result?.total, Number.NaN);\n const hasMore =\n added > 0 &&\n pageItems.length >= LINES_PAGE_SIZE &&\n (!Number.isFinite(reportedTotal) || collectedItems.length < reportedTotal);\n if (!hasMore) {\n complete = true;\n break;\n }\n page += 1;\n }\n if (!complete) throw new Error(\"[internal] sales line page limit reached\");\n if (!isCurrentLoad()) return;\n if (loaded) {\n const mapped = collectedItems.flatMap<SalesLineRecord>(\n (item) => {\n const id = typeof item.id === \"string\" ? item.id : null;\n if (!id) return [];\n const taxRate = normalizeNumber(\n item.tax_rate ?? item.taxRate,\n 0,\n );\n const customFields = extractCustomFieldValues(\n item as Record<string, unknown>,\n );\n const name =\n typeof item.name === \"string\"\n ? item.name\n : typeof item.catalog_snapshot === \"object\" &&\n item.catalog_snapshot &&\n typeof (item.catalog_snapshot as Record<string, unknown>).name === \"string\"\n ? (item.catalog_snapshot as Record<string, unknown>).name as string\n : null;\n const description =\n typeof item.description === \"string\" && item.description.trim()\n ? item.description\n : null;\n const quantity = normalizeNumber(item.quantity, 0);\n const uomFields = getUomFields(item);\n const quantityUnit = canonicalizeUnitCode(uomFields.quantityUnit);\n const normalizedQuantity = normalizeNumber(\n uomFields.normalizedQuantity,\n quantity,\n );\n const normalizedUnit =\n canonicalizeUnitCode(uomFields.normalizedUnit) ?? quantityUnit;\n const uomSnapshot = uomFields.uomSnapshot;\n const unitPriceNetRaw = normalizeNumber(\n item.unit_price_net ?? item.unitPriceNet,\n Number.NaN,\n );\n const unitPriceGrossRaw = normalizeNumber(\n item.unit_price_gross ?? item.unitPriceGross,\n Number.NaN,\n );\n const unitPriceNet = Number.isFinite(unitPriceNetRaw)\n ? unitPriceNetRaw\n : Number.isFinite(unitPriceGrossRaw)\n ? unitPriceGrossRaw / (1 + taxRate / 100)\n : 0;\n const unitPriceGross = Number.isFinite(unitPriceGrossRaw)\n ? unitPriceGrossRaw\n : Number.isFinite(unitPriceNetRaw)\n ? unitPriceNetRaw * (1 + taxRate / 100)\n : 0;\n const totalNetRaw = normalizeNumber(\n item.total_net_amount ?? item.totalNetAmount,\n Number.NaN,\n );\n const totalGrossRaw = normalizeNumber(\n item.total_gross_amount ?? item.totalGrossAmount,\n Number.NaN,\n );\n const totalNet = Number.isFinite(totalNetRaw)\n ? totalNetRaw\n : unitPriceNet * quantity;\n const totalGross = Number.isFinite(totalGrossRaw)\n ? totalGrossRaw\n : unitPriceGross * quantity;\n const priceModeRaw =\n item.metadata &&\n typeof item.metadata === \"object\"\n ? (item.metadata as Record<string, unknown>).priceMode\n : null;\n const priceMode = priceModeRaw === \"net\" ? \"net\" : \"gross\";\n const customFieldSetId =\n typeof item.custom_field_set_id === \"string\"\n ? item.custom_field_set_id\n : typeof item.customFieldSetId === \"string\"\n ? item.customFieldSetId\n : null;\n const statusEntryId =\n typeof item.status_entry_id === \"string\"\n ? item.status_entry_id\n : typeof item.statusEntryId === \"string\"\n ? item.statusEntryId\n : null;\n const status = typeof item.status === \"string\" ? item.status : null;\n const record: SalesLineRecord = {\n id,\n name,\n description,\n productId:\n typeof item.product_id === \"string\" ? item.product_id : null,\n productVariantId:\n typeof item.product_variant_id === \"string\"\n ? item.product_variant_id\n : null,\n quantity,\n quantityUnit,\n normalizedQuantity,\n normalizedUnit,\n currencyCode:\n typeof item.currency_code === \"string\"\n ? item.currency_code\n : typeof currencyCode === \"string\"\n ? currencyCode\n : null,\n unitPriceNet,\n unitPriceGross,\n discountAmount: normalizeNumber(\n item.discount_amount ?? item.discountAmount,\n 0,\n ),\n discountPercent: normalizeNumber(\n item.discount_percent ?? item.discountPercent,\n 0,\n ),\n taxRate,\n totalNet,\n totalGross,\n priceMode,\n uomSnapshot,\n metadata:\n (item.metadata as Record<string, unknown> | null | undefined) ??\n null,\n catalogSnapshot:\n (item.catalog_snapshot as\n | Record<string, unknown>\n | null\n | undefined) ?? null,\n customFieldSetId,\n customFields: Object.keys(customFields).length\n ? customFields\n : null,\n status,\n statusEntryId,\n };\n return [record];\n },\n );\n setItems(mapped);\n if (onItemsChange) onItemsChange(mapped);\n } else {\n setItems([]);\n if (onItemsChange) onItemsChange([]);\n }\n } catch (err) {\n if (!isCurrentLoad()) return;\n logger.error('sales.document.items.load', { err });\n setError(t(\"sales.documents.items.errorLoad\", \"Failed to load items.\"));\n setItems([]);\n if (onItemsChange) onItemsChange([]);\n } finally {\n if (isCurrentLoad()) setLoading(false);\n }\n }, [currencyCode, documentId, documentKey, onItemsChange, resourcePath, t]);\n\n const loadShippedTotals = React.useCallback(async () => {\n if (kind !== \"order\") {\n setShippedTotals(new Map());\n setShippedTotalsResolved(true);\n return;\n }\n setShippedTotals(new Map());\n setShippedTotalsResolved(false);\n try {\n const totals = new Map<string, number>();\n let page = 1;\n let collected = 0;\n let complete = false;\n while (page <= SHIPMENTS_MAX_PAGES) {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(SHIPMENTS_PAGE_SIZE),\n orderId: documentId,\n });\n const response = await apiCall<{\n items?: Array<Record<string, unknown>>;\n total?: unknown;\n }>(`/api/sales/shipments?${params.toString()}`, undefined, {\n fallback: { items: [] },\n });\n if (!response.ok || !Array.isArray(response.result?.items)) return;\n const shipments = response.result.items;\n shipments.forEach((shipment) => {\n const entries = Array.isArray(shipment.items)\n ? (shipment.items as Array<Record<string, unknown>>)\n : [];\n entries.forEach((entry) => {\n const lineId =\n typeof entry.orderLineId === \"string\"\n ? entry.orderLineId\n : typeof entry.order_line_id === \"string\"\n ? entry.order_line_id\n : null;\n if (!lineId) return;\n const quantity = normalizeNumber(entry.quantity, 0);\n if (!Number.isFinite(quantity) || quantity <= 0) return;\n const current = totals.get(lineId) ?? 0;\n totals.set(lineId, current + quantity);\n });\n });\n collected += shipments.length;\n const reportedTotal = normalizeNumber(response.result?.total, Number.NaN);\n const hasMore =\n shipments.length >= SHIPMENTS_PAGE_SIZE &&\n (!Number.isFinite(reportedTotal) || collected < reportedTotal);\n if (!hasMore) {\n complete = true;\n break;\n }\n page += 1;\n }\n if (!complete) return;\n setShippedTotals(totals);\n setShippedTotalsResolved(true);\n } catch (err) {\n logger.error('sales.document.shipments.load', { err });\n }\n }, [documentId, kind]);\n\n React.useEffect(() => {\n if (lineStatusesLoaded.current) return;\n lineStatusesLoaded.current = true;\n void loadLineStatuses();\n }, [loadLineStatuses]);\n\n React.useEffect(() => {\n if (!documentId) return;\n if (itemsLoadedForDocument.current === documentId) return;\n itemsLoadedForDocument.current = documentId;\n void loadItems();\n }, [documentId, loadItems]);\n\n React.useEffect(() => {\n if (kind !== \"order\") {\n shipmentsLoadedForDocument.current = null;\n setShippedTotals(new Map());\n setShippedTotalsResolved(true);\n return;\n }\n const key = `${kind}:${documentId}`;\n if (shipmentsLoadedForDocument.current === key) return;\n shipmentsLoadedForDocument.current = key;\n void loadShippedTotals();\n }, [documentId, kind, loadShippedTotals]);\n\n const openCreate = React.useCallback(() => {\n setLineForEdit(null);\n setDialogOpen(true);\n }, []);\n\n React.useEffect(() => {\n if (!onActionChange) return;\n onActionChange({\n label: t(\"sales.documents.items.add\", \"Add item\"),\n onClick: openCreate,\n disabled: amountsReadOnly,\n });\n return () => onActionChange(null);\n }, [amountsReadOnly, onActionChange, openCreate, t]);\n\n const handleEdit = React.useCallback(\n (line: SalesLineRecord) => {\n if (amountsReadOnly) return;\n setLineForEdit(line);\n setDialogOpen(true);\n },\n [amountsReadOnly],\n );\n\n const resolveVariantInfo = React.useCallback((record: SalesLineRecord) => {\n const meta =\n (record.metadata as Record<string, unknown> | null | undefined) ?? null;\n const snapshot =\n (record.catalogSnapshot as Record<string, unknown> | null | undefined) ??\n null;\n const variantSnapshot =\n snapshot &&\n typeof snapshot.variant === \"object\" &&\n snapshot.variant\n ? (snapshot.variant as Record<string, unknown>)\n : null;\n const variantTitle =\n meta && typeof meta.variantTitle === \"string\"\n ? meta.variantTitle\n : variantSnapshot && typeof variantSnapshot.name === \"string\"\n ? variantSnapshot.name\n : null;\n const variantSku =\n meta && typeof meta.variantSku === \"string\"\n ? meta.variantSku\n : variantSnapshot && typeof variantSnapshot.sku === \"string\"\n ? variantSnapshot.sku\n : null;\n\n return { variantTitle, variantSku };\n }, []);\n\n const handleDelete = React.useCallback(\n async (line: SalesLineRecord) => {\n const confirmed = await confirm({\n title: t(\n \"sales.documents.items.deleteConfirm\",\n \"Delete this line item?\",\n ),\n variant: \"destructive\",\n });\n if (!confirmed) return;\n try {\n const result = await runDocumentMutation(() => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(documentUpdatedAt),\n () =>\n deleteCrud(resourcePath, {\n body: {\n id: line.id,\n [documentKey]: documentId,\n organizationId: resolvedOrganizationId ?? undefined,\n tenantId: resolvedTenantId ?? undefined,\n },\n errorMessage: t(\n \"sales.documents.items.errorDelete\",\n \"Failed to delete line.\",\n ),\n }),\n ), { id: line.id, [documentKey]: documentId });\n if (result.ok) {\n flash(t(\"sales.documents.items.deleted\", \"Line removed.\"), \"success\");\n await loadItems();\n emitSalesDocumentTotalsRefresh({ documentId, kind });\n }\n } catch (err) {\n if (handleSectionMutationError(err, t, () => void loadItems())) return;\n logger.error('sales.document.items.delete', { err });\n const normalized = normalizeCrudServerError(err);\n const fallback = t(\n \"sales.documents.items.errorDelete\",\n \"Failed to delete line.\",\n );\n flash(normalized.message || fallback, \"error\");\n }\n },\n [\n confirm,\n documentId,\n documentKey,\n documentUpdatedAt,\n kind,\n loadItems,\n resolvedOrganizationId,\n resourcePath,\n t,\n resolvedTenantId,\n runDocumentMutation,\n ],\n );\n\n const renderStatus = React.useCallback(\n (line: SalesLineRecord) => {\n const value = line.status ?? null;\n if (!value) {\n return (\n <span className=\"text-xs text-muted-foreground\">\n {t(\"sales.documents.items.table.statusEmpty\", \"No status\")}\n </span>\n );\n }\n return (\n <DictionaryValue\n value={value}\n map={lineStatusMap}\n fallback={<span className=\"text-xs font-medium\">{value}</span>}\n className=\"text-xs font-medium\"\n iconWrapperClassName=\"inline-flex h-6 w-6 items-center justify-center rounded bg-muted text-muted-foreground\"\n iconClassName=\"h-3.5 w-3.5\"\n colorClassName=\"h-4 w-4 rounded-full border border-border/70\"\n />\n );\n },\n [lineStatusMap, t],\n );\n\n const showDiscountColumn = React.useMemo(\n () => items.some((item) => resolveLineDiscountDisplay(item) !== null),\n [items],\n );\n\n const renderImage = (record: SalesLineRecord) => {\n const meta =\n (record.metadata as Record<string, unknown> | null | undefined) ?? {};\n const snapshot =\n (record.catalogSnapshot as Record<string, unknown> | null | undefined) ??\n {};\n const productSnapshot: Record<string, unknown> =\n typeof snapshot === \"object\" && snapshot\n ? ((snapshot.product as Record<string, unknown>) ?? {})\n : {};\n const variantSnapshot: Record<string, unknown> =\n typeof snapshot === \"object\" && snapshot\n ? ((snapshot.variant as Record<string, unknown>) ?? {})\n : {};\n const productThumb =\n (meta &&\n typeof meta.productThumbnail === \"string\" &&\n meta.productThumbnail) ||\n (productSnapshot &&\n typeof productSnapshot.thumbnailUrl === \"string\" &&\n productSnapshot.thumbnailUrl) ||\n null;\n const variantThumb =\n (meta &&\n typeof meta.variantThumbnail === \"string\" &&\n meta.variantThumbnail) ||\n (variantSnapshot &&\n typeof variantSnapshot.thumbnailUrl === \"string\" &&\n variantSnapshot.thumbnailUrl) ||\n null;\n const thumbnail = variantThumb ?? productThumb;\n if (thumbnail) {\n return (\n <img\n src={thumbnail}\n alt={record.name ?? record.id}\n className=\"h-10 w-10 rounded border object-cover\"\n />\n );\n }\n return (\n <div className=\"flex h-10 w-10 items-center justify-center rounded border bg-muted text-xs text-muted-foreground\">\n N/A\n </div>\n );\n };\n\n return (\n <OrderItemsInjectionContext.Provider value={{ documentId, kind }}>\n <div className=\"space-y-4\">\n {kind === \"order\" && injectedColumnsError ? (\n <ErrorMessage label={t('ui.dataTable.extensions.error', 'Some table extensions could not load. Reload the page to retry.')} />\n ) : null}\n {loading || (kind === \"order\" && injectedColumnsLoading) ? (\n <LoadingMessage\n label={t(\"sales.documents.items.loading\", \"Loading items\u2026\")}\n className=\"border-0 bg-transparent p-0 py-8 justify-center\"\n />\n ) : error ? (\n <p className=\"text-sm text-destructive\">{error}</p>\n ) : items.length === 0 ? (\n <TabEmptyState\n title={t(\"sales.documents.items.empty\", \"No items yet.\")}\n description={t(\n \"sales.documents.items.subtitle\",\n \"Add products and configure pricing for this document.\",\n )}\n action={{\n label: t(\"sales.documents.items.add\", \"Add item\"),\n onClick: openCreate,\n disabled: amountsReadOnly,\n }}\n />\n ) : (\n <div className=\"relative overflow-x-auto rounded border\">\n <table className=\"w-full text-sm\">\n <thead className=\"bg-muted\">\n <tr className=\"text-left\">\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.product\", \"Product\")}\n </th>\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.status\", \"Status\")}\n </th>\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.quantity\", \"Qty\")}\n </th>\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.unit\", \"Unit price\")}\n </th>\n {showDiscountColumn ? (\n <th className=\"px-3 py-2 font-medium whitespace-nowrap\">\n {t(\"sales.documents.items.table.discount\", \"Discount\")}\n </th>\n ) : null}\n <th className=\"px-3 py-2 font-medium\">\n {t(\"sales.documents.items.table.total\", \"Total\")}\n </th>\n {injectedColumns.map((col) => (\n <th\n key={col.id}\n className=\"px-3 py-2 font-medium whitespace-nowrap\"\n >\n {col.headerKey ? t(col.headerKey, col.header) : col.header}\n </th>\n ))}\n <th className=\"px-3 py-2 font-medium sr-only\">\n {t(\"sales.documents.items.table.actions\", \"Actions\")}\n </th>\n </tr>\n </thead>\n <tbody>\n {items.map((item) => {\n const meta =\n (item.metadata as\n | Record<string, unknown>\n | null\n | undefined) ?? null;\n const { variantTitle, variantSku } = resolveVariantInfo(item);\n const productSku =\n meta && typeof meta.productSku === \"string\"\n ? meta.productSku\n : null;\n const variantLabel = variantTitle ?? variantSku;\n const variantSuffix =\n variantSku && variantLabel && variantSku !== variantLabel\n ? ` \u2022 ${variantSku}`\n : \"\";\n const showProductSku =\n productSku && productSku !== variantSku ? productSku : null;\n const shippedQuantity = Math.max(\n 0,\n shippedTotals.get(item.id) ?? 0,\n );\n const quantityLabel = item.quantityUnit\n ? `${item.quantity} ${item.quantityUnit}`\n : String(item.quantity);\n const showNormalized =\n Number.isFinite(item.normalizedQuantity) &&\n item.normalizedQuantity > 0 &&\n (item.normalizedUnit ?? null) &&\n (Math.abs(item.normalizedQuantity - item.quantity) >\n 0.000001 ||\n (item.normalizedUnit ?? null) !==\n (item.quantityUnit ?? null));\n const unitPriceReference = resolveUnitPriceReference(\n item.uomSnapshot,\n );\n const discount = resolveLineDiscountDisplay(item);\n\n return (\n <tr\n key={item.id}\n className={cn(\n \"border-t transition-colors\",\n amountsReadOnly ? \"\" : \"cursor-pointer hover:bg-muted/50\",\n )}\n onClick={() => handleEdit(item)}\n >\n <td className=\"px-3 py-3\">\n <div className=\"flex items-center gap-3\">\n {renderImage(item)}\n <div className=\"min-w-0\">\n <div className=\"truncate font-medium\">\n {item.name ??\n t(\"sales.documents.items.untitled\", \"Untitled\")}\n </div>\n {variantLabel ? (\n <div className=\"text-xs text-muted-foreground truncate\">\n {variantLabel}\n {variantSuffix}\n </div>\n ) : null}\n {showProductSku ? (\n <div className=\"text-xs text-muted-foreground truncate\">\n {showProductSku}\n </div>\n ) : null}\n {item.description ? (\n <div\n className=\"text-xs text-muted-foreground line-clamp-2\"\n title={item.description}\n >\n {item.description}\n </div>\n ) : null}\n </div>\n </div>\n </td>\n <td className=\"px-3 py-3\">\n <div className=\"flex items-center\">\n {renderStatus(item)}\n </div>\n </td>\n <td className=\"px-3 py-3\">\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"font-medium\">{quantityLabel}</span>\n {showNormalized ? (\n <span className=\"text-xs text-muted-foreground\">\n {item.normalizedQuantity} {item.normalizedUnit}\n </span>\n ) : null}\n {shippedQuantity > 0 ? (\n <span className=\"text-xs text-muted-foreground\">\n {t(\n \"sales.documents.items.table.shipped\",\n \"{{shipped}} / {{total}} shipped\",\n {\n shipped: shippedQuantity,\n total: item.quantity,\n },\n )}\n </span>\n ) : null}\n </div>\n </td>\n <td className=\"px-3 py-3\">\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"font-mono text-sm\">\n {formatMoney(\n item.unitPriceGross,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n <span className=\"text-xs text-muted-foreground\">\n {t(\"sales.documents.items.table.gross\", \"gross\")}\n </span>\n </span>\n <span className=\"font-mono text-xs text-muted-foreground\">\n {formatMoney(\n item.unitPriceNet,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n {t(\"sales.documents.items.table.net\", \"net\")}\n </span>\n {unitPriceReference ? (\n <span className=\"text-xs text-muted-foreground\">\n {t(\n \"sales.documents.items.table.unitPriceReference\",\n \"{{value}} per 1 {{unit}}\",\n {\n value: formatMoney(\n unitPriceReference.grossPerReference,\n item.currencyCode ??\n currencyCode ??\n undefined,\n locale,\n ),\n unit: unitPriceReference.referenceUnitCode,\n },\n )}\n </span>\n ) : null}\n </div>\n </td>\n {showDiscountColumn ? (\n <td className=\"px-3 py-3\">\n {discount ? (\n <div className=\"flex flex-col gap-0.5\">\n {discount.amount !== null ? (\n <span className=\"font-mono text-sm\">\n {t(\n discount.amount < 0\n ? \"sales.documents.items.table.markupAmount\"\n : \"sales.documents.items.table.discountAmount\",\n discount.amount < 0 ? \"+{{value}}\" : \"\u2212{{value}}\",\n {\n value: formatMoney(\n Math.abs(discount.amount),\n item.currencyCode ??\n currencyCode ??\n undefined,\n locale,\n ),\n },\n )}\n </span>\n ) : null}\n {discount.percent !== null ? (\n <span\n className={\n discount.amount !== null\n ? \"font-mono text-xs text-muted-foreground\"\n : \"font-mono text-sm\"\n }\n >\n {t(\n \"sales.documents.items.table.discountPercent\",\n \"{{value}}%\",\n { value: discount.percent },\n )}\n </span>\n ) : null}\n </div>\n ) : null}\n </td>\n ) : null}\n <td className=\"px-3 py-3 font-semibold\">\n <div className=\"flex flex-col gap-0.5\">\n <span>\n {formatMoney(\n item.totalGross,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n <span className=\"text-xs font-normal text-muted-foreground\">\n {t(\"sales.documents.items.table.gross\", \"gross\")}\n </span>\n </span>\n <span className=\"text-xs font-medium text-muted-foreground\">\n {formatMoney(\n item.totalNet,\n item.currencyCode ?? currencyCode ?? undefined,\n locale,\n )}{\" \"}\n {t(\"sales.documents.items.table.net\", \"net\")}\n </span>\n </div>\n </td>\n {injectedColumns.map((col) => {\n const colValue = resolveInjectedColumnValue(\n item as unknown as Record<string, unknown>,\n col.accessorKey,\n );\n const Cell = col.cell;\n return (\n <td\n key={col.id}\n className=\"px-3 py-3\"\n onClick={(e) => e.stopPropagation()}\n >\n {Cell ? <Cell getValue={() => colValue} /> : null}\n </td>\n );\n })}\n <td className=\"px-3 py-3\">\n <div className=\"flex items-center gap-2 justify-end\">\n <DisabledActionHint\n label={t('ui.actions.edit', 'Edit')}\n reason={amountsReadOnly\n ? t('sales.documents.amountsExternalHint', 'Totals on this document come from an external system and are stored as supplied.')\n : undefined}\n >\n <IconButton\n type=\"button\"\n size=\"default\"\n variant=\"ghost\"\n aria-label={t('ui.actions.edit', 'Edit')}\n disabled={amountsReadOnly}\n onClick={(event) => {\n event.stopPropagation();\n handleEdit(item);\n }}\n >\n <Pencil className=\"h-4 w-4\" />\n </IconButton>\n </DisabledActionHint>\n <DisabledActionHint\n label={t('ui.actions.delete', 'Delete')}\n reason={amountsReadOnly\n ? t('sales.documents.amountsExternalHint', 'Totals on this document come from an external system and are stored as supplied.')\n : kind === 'order' && items.length === 1\n ? t('sales.documents.items.errorDeleteLast', 'An order must contain at least one line item.')\n : undefined}\n >\n <IconButton\n type=\"button\"\n size=\"default\"\n variant=\"ghost\"\n className=\"text-destructive\"\n aria-label={t('ui.actions.delete', 'Delete')}\n disabled={amountsReadOnly || (kind === 'order' && items.length === 1)}\n onClick={(event) => {\n event.stopPropagation();\n void handleDelete(item);\n }}\n >\n <Trash2 className=\"h-4 w-4\" />\n </IconButton>\n </DisabledActionHint>\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n )}\n\n <LineItemDialog\n open={dialogOpen}\n onOpenChange={(next) => {\n setDialogOpen(next);\n if (!next) setLineForEdit(null);\n }}\n kind={kind}\n documentId={documentId}\n currencyCode={currencyCode}\n documentUpdatedAt={documentUpdatedAt}\n organizationId={resolvedOrganizationId}\n tenantId={resolvedTenantId}\n initialLine={lineForEdit}\n shippedQuantity={\n lineForEdit\n ? Math.max(0, shippedTotals.get(lineForEdit.id) ?? 0)\n : 0\n }\n shippedQuantityResolved={shippedTotalsResolved}\n onSaved={async () => {\n await loadItems();\n emitSalesDocumentTotalsRefresh({ documentId, kind });\n }}\n />\n {ConfirmDialogElement}\n </div>\n </OrderItemsInjectionContext.Provider>\n );\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -33,10 +33,10 @@ function percentAccountsForAmount(line, percent, amount) {
33
33
  function resolveLineDiscountDisplay(line) {
34
34
  const amount = normalizeNumber(line.discountAmount, 0);
35
35
  const percent = normalizeNumber(line.discountPercent, 0);
36
- if (amount > 0) {
36
+ if (amount !== 0) {
37
37
  return {
38
38
  amount,
39
- percent: percentAccountsForAmount(line, percent, amount) ? percent : null
39
+ percent: amount > 0 && percentAccountsForAmount(line, percent, amount) ? percent : null
40
40
  };
41
41
  }
42
42
  if (percent > 0) return { amount: null, percent };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/sales/components/documents/lineItemUtils.ts"],
4
- "sourcesContent": ["\"use client\"\n\nexport function normalizeNumber(value: unknown, fallback = 0): 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 fallback\n}\n\n/**\n * A catalog price is only usable on a line when it carries a positive amount, because line\n * submission rejects a unit price of zero. Returns the amount for the requested mode, falling\n * back to the other mode only when the requested amount is missing, or `null` when the price\n * has no positive amount to use.\n */\nexport function resolveCatalogPriceAmount(\n amountNet: number | null | undefined,\n amountGross: number | null | undefined,\n mode: 'net' | 'gross',\n): number | null {\n const isPresent = (value: number | null | undefined): value is number =>\n typeof value === 'number' && Number.isFinite(value)\n const [preferred, fallback] = mode === 'net' ? [amountNet, amountGross] : [amountGross, amountNet]\n const amount = isPresent(preferred) ? preferred : isPresent(fallback) ? fallback : null\n return amount !== null && amount > 0 ? amount : null\n}\n\n/**\n * Pass `locale` to format in the application locale (`useLocale()` in client components).\n * Omitting it keeps the runtime default, which varies per machine and is therefore not\n * assertable in tests.\n */\nexport function formatMoney(value: number, currency: string | null | undefined, locale?: string): string {\n if (!currency) return value.toFixed(2)\n return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(value)\n}\n\nexport type LineDiscountDisplay = {\n amount: number | null\n percent: number | null\n}\n\ntype LineDiscountSource = {\n discountAmount?: unknown\n discountPercent?: unknown\n unitPriceNet?: unknown\n quantity?: unknown\n}\n\nconst DISCOUNT_MATCH_TOLERANCE = 0.01\nconst DISCOUNT_MATCH_TOLERANCE_PER_UNIT = 0.0001\n\nfunction percentAccountsForAmount(\n line: LineDiscountSource,\n percent: number,\n amount: number,\n): boolean {\n if (percent <= 0) return false\n const quantity = normalizeNumber(line.quantity, 0)\n const netBeforeDiscount = normalizeNumber(line.unitPriceNet, 0) * quantity\n if (netBeforeDiscount <= 0) return false\n const tolerance = Math.max(\n DISCOUNT_MATCH_TOLERANCE,\n quantity * DISCOUNT_MATCH_TOLERANCE_PER_UNIT,\n )\n return Math.abs((percent / 100) * netBeforeDiscount - amount) <= tolerance\n}\n\nexport function resolveLineDiscountDisplay(\n line: LineDiscountSource,\n): LineDiscountDisplay | null {\n const amount = normalizeNumber(line.discountAmount, 0)\n const percent = normalizeNumber(line.discountPercent, 0)\n if (amount > 0) {\n return {\n amount,\n percent: percentAccountsForAmount(line, percent, amount) ? percent : null,\n }\n }\n if (percent > 0) return { amount: null, percent }\n return null\n}\n"],
5
- "mappings": ";AAEO,SAAS,gBAAgB,OAAgB,WAAW,GAAW;AACpE,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,EAAG,QAAO;AAChE,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,QAAQ;AACpD,UAAM,SAAS,OAAO,KAAK;AAC3B,QAAI,CAAC,OAAO,MAAM,MAAM,EAAG,QAAO;AAAA,EACpC;AACA,SAAO;AACT;AAQO,SAAS,0BACd,WACA,aACA,MACe;AACf,QAAM,YAAY,CAAC,UACjB,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK;AACpD,QAAM,CAAC,WAAW,QAAQ,IAAI,SAAS,QAAQ,CAAC,WAAW,WAAW,IAAI,CAAC,aAAa,SAAS;AACjG,QAAM,SAAS,UAAU,SAAS,IAAI,YAAY,UAAU,QAAQ,IAAI,WAAW;AACnF,SAAO,WAAW,QAAQ,SAAS,IAAI,SAAS;AAClD;AAOO,SAAS,YAAY,OAAe,UAAqC,QAAyB;AACvG,MAAI,CAAC,SAAU,QAAO,MAAM,QAAQ,CAAC;AACrC,SAAO,IAAI,KAAK,aAAa,QAAQ,EAAE,OAAO,YAAY,SAAS,CAAC,EAAE,OAAO,KAAK;AACpF;AAcA,MAAM,2BAA2B;AACjC,MAAM,oCAAoC;AAE1C,SAAS,yBACP,MACA,SACA,QACS;AACT,MAAI,WAAW,EAAG,QAAO;AACzB,QAAM,WAAW,gBAAgB,KAAK,UAAU,CAAC;AACjD,QAAM,oBAAoB,gBAAgB,KAAK,cAAc,CAAC,IAAI;AAClE,MAAI,qBAAqB,EAAG,QAAO;AACnC,QAAM,YAAY,KAAK;AAAA,IACrB;AAAA,IACA,WAAW;AAAA,EACb;AACA,SAAO,KAAK,IAAK,UAAU,MAAO,oBAAoB,MAAM,KAAK;AACnE;AAEO,SAAS,2BACd,MAC4B;AAC5B,QAAM,SAAS,gBAAgB,KAAK,gBAAgB,CAAC;AACrD,QAAM,UAAU,gBAAgB,KAAK,iBAAiB,CAAC;AACvD,MAAI,SAAS,GAAG;AACd,WAAO;AAAA,MACL;AAAA,MACA,SAAS,yBAAyB,MAAM,SAAS,MAAM,IAAI,UAAU;AAAA,IACvE;AAAA,EACF;AACA,MAAI,UAAU,EAAG,QAAO,EAAE,QAAQ,MAAM,QAAQ;AAChD,SAAO;AACT;",
4
+ "sourcesContent": ["\"use client\"\n\nexport function normalizeNumber(value: unknown, fallback = 0): 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 fallback\n}\n\n/**\n * A catalog price is only usable on a line when it carries a positive amount, because line\n * submission rejects a unit price of zero. Returns the amount for the requested mode, falling\n * back to the other mode only when the requested amount is missing, or `null` when the price\n * has no positive amount to use.\n */\nexport function resolveCatalogPriceAmount(\n amountNet: number | null | undefined,\n amountGross: number | null | undefined,\n mode: 'net' | 'gross',\n): number | null {\n const isPresent = (value: number | null | undefined): value is number =>\n typeof value === 'number' && Number.isFinite(value)\n const [preferred, fallback] = mode === 'net' ? [amountNet, amountGross] : [amountGross, amountNet]\n const amount = isPresent(preferred) ? preferred : isPresent(fallback) ? fallback : null\n return amount !== null && amount > 0 ? amount : null\n}\n\n/**\n * Pass `locale` to format in the application locale (`useLocale()` in client components).\n * Omitting it keeps the runtime default, which varies per machine and is therefore not\n * assertable in tests.\n */\nexport function formatMoney(value: number, currency: string | null | undefined, locale?: string): string {\n if (!currency) return value.toFixed(2)\n return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(value)\n}\n\nexport type LineDiscountDisplay = {\n amount: number | null\n percent: number | null\n}\n\ntype LineDiscountSource = {\n discountAmount?: unknown\n discountPercent?: unknown\n unitPriceNet?: unknown\n quantity?: unknown\n}\n\nconst DISCOUNT_MATCH_TOLERANCE = 0.01\nconst DISCOUNT_MATCH_TOLERANCE_PER_UNIT = 0.0001\n\nfunction percentAccountsForAmount(\n line: LineDiscountSource,\n percent: number,\n amount: number,\n): boolean {\n if (percent <= 0) return false\n const quantity = normalizeNumber(line.quantity, 0)\n const netBeforeDiscount = normalizeNumber(line.unitPriceNet, 0) * quantity\n if (netBeforeDiscount <= 0) return false\n const tolerance = Math.max(\n DISCOUNT_MATCH_TOLERANCE,\n quantity * DISCOUNT_MATCH_TOLERANCE_PER_UNIT,\n )\n return Math.abs((percent / 100) * netBeforeDiscount - amount) <= tolerance\n}\n\nexport function resolveLineDiscountDisplay(\n line: LineDiscountSource,\n): LineDiscountDisplay | null {\n const amount = normalizeNumber(line.discountAmount, 0)\n const percent = normalizeNumber(line.discountPercent, 0)\n if (amount !== 0) {\n return {\n amount,\n percent: amount > 0 && percentAccountsForAmount(line, percent, amount) ? percent : null,\n }\n }\n if (percent > 0) return { amount: null, percent }\n return null\n}\n"],
5
+ "mappings": ";AAEO,SAAS,gBAAgB,OAAgB,WAAW,GAAW;AACpE,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,EAAG,QAAO;AAChE,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,QAAQ;AACpD,UAAM,SAAS,OAAO,KAAK;AAC3B,QAAI,CAAC,OAAO,MAAM,MAAM,EAAG,QAAO;AAAA,EACpC;AACA,SAAO;AACT;AAQO,SAAS,0BACd,WACA,aACA,MACe;AACf,QAAM,YAAY,CAAC,UACjB,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK;AACpD,QAAM,CAAC,WAAW,QAAQ,IAAI,SAAS,QAAQ,CAAC,WAAW,WAAW,IAAI,CAAC,aAAa,SAAS;AACjG,QAAM,SAAS,UAAU,SAAS,IAAI,YAAY,UAAU,QAAQ,IAAI,WAAW;AACnF,SAAO,WAAW,QAAQ,SAAS,IAAI,SAAS;AAClD;AAOO,SAAS,YAAY,OAAe,UAAqC,QAAyB;AACvG,MAAI,CAAC,SAAU,QAAO,MAAM,QAAQ,CAAC;AACrC,SAAO,IAAI,KAAK,aAAa,QAAQ,EAAE,OAAO,YAAY,SAAS,CAAC,EAAE,OAAO,KAAK;AACpF;AAcA,MAAM,2BAA2B;AACjC,MAAM,oCAAoC;AAE1C,SAAS,yBACP,MACA,SACA,QACS;AACT,MAAI,WAAW,EAAG,QAAO;AACzB,QAAM,WAAW,gBAAgB,KAAK,UAAU,CAAC;AACjD,QAAM,oBAAoB,gBAAgB,KAAK,cAAc,CAAC,IAAI;AAClE,MAAI,qBAAqB,EAAG,QAAO;AACnC,QAAM,YAAY,KAAK;AAAA,IACrB;AAAA,IACA,WAAW;AAAA,EACb;AACA,SAAO,KAAK,IAAK,UAAU,MAAO,oBAAoB,MAAM,KAAK;AACnE;AAEO,SAAS,2BACd,MAC4B;AAC5B,QAAM,SAAS,gBAAgB,KAAK,gBAAgB,CAAC;AACrD,QAAM,UAAU,gBAAgB,KAAK,iBAAiB,CAAC;AACvD,MAAI,WAAW,GAAG;AAChB,WAAO;AAAA,MACL;AAAA,MACA,SAAS,SAAS,KAAK,yBAAyB,MAAM,SAAS,MAAM,IAAI,UAAU;AAAA,IACrF;AAAA,EACF;AACA,MAAI,UAAU,EAAG,QAAO,EAAE,QAAQ,MAAM,QAAQ;AAChD,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -2,6 +2,7 @@ import { NextResponse } from "next/server";
2
2
  import { z } from "zod";
3
3
  import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
4
4
  import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
5
+ import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
5
6
  import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
6
7
  import { runRouteMutationGuards } from "@open-mercato/shared/lib/crud/route-mutation-guard";
7
8
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
@@ -39,7 +40,8 @@ async function resolveAccessRequestContext(req) {
39
40
  if (!requesterUserId) {
40
41
  throw new CrudHttpError(401, { error: translate("staff.errors.unauthorized", "Unauthorized") });
41
42
  }
42
- if (!auth.orgId) {
43
+ const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req });
44
+ if (!scope.tenantId || !scope.selectedId || scope.selectionRejected === true) {
43
45
  throw new CrudHttpError(400, {
44
46
  error: translate("staff.errors.missingScope", "Missing tenant or organization scope.")
45
47
  });
@@ -47,8 +49,8 @@ async function resolveAccessRequestContext(req) {
47
49
  return {
48
50
  container,
49
51
  em: container.resolve("em").fork(),
50
- tenantId: auth.tenantId,
51
- organizationId: auth.orgId,
52
+ tenantId: scope.tenantId,
53
+ organizationId: scope.selectedId,
52
54
  requesterUserId,
53
55
  requesterEmail: typeof auth.email === "string" && auth.email.trim().length > 0 ? auth.email : null,
54
56
  translate
@@ -101,10 +103,14 @@ async function resolveRequesterName(context) {
101
103
  async function POST(req) {
102
104
  try {
103
105
  const context = await resolveAccessRequestContext(req);
104
- const grantedFeatures = (await resolveFeatureAccess(context.container, context.requesterUserId, [VIEW_FEATURE], {
106
+ const featureAccess = await resolveFeatureAccess(context.container, context.requesterUserId, [VIEW_FEATURE], {
105
107
  tenantId: context.tenantId,
106
108
  organizationId: context.organizationId
107
- })).grantedFeatures;
109
+ });
110
+ if (!featureAccess.allowed) {
111
+ throw new CrudHttpError(403, { error: context.translate("staff.errors.forbidden", "Forbidden") });
112
+ }
113
+ const grantedFeatures = featureAccess.grantedFeatures;
108
114
  const interceptors = await runTimesheetInterceptors({
109
115
  request: req,
110
116
  method: "POST",