@open-mercato/core 0.10.1-develop.7723.1.3b2ea82ea7 → 0.10.1-develop.7726.1.a447cc5525

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 (81) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/generated/entities/sales_order/index.js +2 -0
  3. package/dist/generated/entities/sales_order/index.js.map +2 -2
  4. package/dist/generated/entities/sales_order_line/index.js +2 -0
  5. package/dist/generated/entities/sales_order_line/index.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +2 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/modules/planner/api/availability-date-specific.js +2 -7
  9. package/dist/modules/planner/api/availability-date-specific.js.map +2 -2
  10. package/dist/modules/planner/commands/availability-date-specific.js +14 -31
  11. package/dist/modules/planner/commands/availability-date-specific.js.map +2 -2
  12. package/dist/modules/planner/commands/availability-weekly.js +8 -22
  13. package/dist/modules/planner/commands/availability-weekly.js.map +2 -2
  14. package/dist/modules/planner/lib/availabilityMerge.js +10 -18
  15. package/dist/modules/planner/lib/availabilityMerge.js.map +2 -2
  16. package/dist/modules/planner/lib/availabilityTimezone.js +161 -0
  17. package/dist/modules/planner/lib/availabilityTimezone.js.map +7 -0
  18. package/dist/modules/sales/api/documents/factory.js +3 -0
  19. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  20. package/dist/modules/sales/api/order-lines/route.js +2 -1
  21. package/dist/modules/sales/api/order-lines/route.js.map +2 -2
  22. package/dist/modules/sales/backend/sales/documents/[id]/page.js +83 -6
  23. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  24. package/dist/modules/sales/commands/documents.js +141 -18
  25. package/dist/modules/sales/commands/documents.js.map +2 -2
  26. package/dist/modules/sales/commands/returns.js +24 -7
  27. package/dist/modules/sales/commands/returns.js.map +2 -2
  28. package/dist/modules/sales/components/documents/AdjustmentsSection.js +17 -11
  29. package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
  30. package/dist/modules/sales/components/documents/DocumentTotals.js +21 -3
  31. package/dist/modules/sales/components/documents/DocumentTotals.js.map +2 -2
  32. package/dist/modules/sales/components/documents/ItemsSection.js +23 -12
  33. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  34. package/dist/modules/sales/data/entities.js +10 -0
  35. package/dist/modules/sales/data/entities.js.map +2 -2
  36. package/dist/modules/sales/data/validators.js +9 -1
  37. package/dist/modules/sales/data/validators.js.map +2 -2
  38. package/dist/modules/sales/lib/calculations.js +85 -6
  39. package/dist/modules/sales/lib/calculations.js.map +2 -2
  40. package/dist/modules/sales/lib/externalAmounts.js +143 -0
  41. package/dist/modules/sales/lib/externalAmounts.js.map +7 -0
  42. package/dist/modules/sales/lib/lineSnapshots.js +6 -1
  43. package/dist/modules/sales/lib/lineSnapshots.js.map +2 -2
  44. package/dist/modules/sales/lib/makeSalesLineRoute.js +8 -2
  45. package/dist/modules/sales/lib/makeSalesLineRoute.js.map +2 -2
  46. package/dist/modules/sales/lib/providers/totals.js +3 -2
  47. package/dist/modules/sales/lib/providers/totals.js.map +2 -2
  48. package/dist/modules/sales/migrations/Migration20260910120000_sales_external_amounts_mode.js +19 -0
  49. package/dist/modules/sales/migrations/Migration20260910120000_sales_external_amounts_mode.js.map +7 -0
  50. package/generated/entities/sales_order/index.ts +1 -0
  51. package/generated/entities/sales_order_line/index.ts +1 -0
  52. package/generated/entity-fields-registry.ts +2 -0
  53. package/package.json +8 -7
  54. package/src/modules/planner/api/availability-date-specific.ts +5 -10
  55. package/src/modules/planner/commands/availability-date-specific.ts +14 -33
  56. package/src/modules/planner/commands/availability-weekly.ts +15 -24
  57. package/src/modules/planner/lib/availabilityMerge.ts +13 -19
  58. package/src/modules/planner/lib/availabilityTimezone.ts +242 -0
  59. package/src/modules/sales/api/documents/factory.ts +3 -0
  60. package/src/modules/sales/api/order-lines/route.ts +2 -1
  61. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +96 -0
  62. package/src/modules/sales/commands/documents.ts +219 -44
  63. package/src/modules/sales/commands/returns.ts +27 -3
  64. package/src/modules/sales/components/documents/AdjustmentsSection.tsx +34 -25
  65. package/src/modules/sales/components/documents/DocumentTotals.tsx +26 -2
  66. package/src/modules/sales/components/documents/ItemsSection.tsx +27 -12
  67. package/src/modules/sales/data/entities.ts +14 -0
  68. package/src/modules/sales/data/validators.ts +10 -0
  69. package/src/modules/sales/i18n/de.json +12 -0
  70. package/src/modules/sales/i18n/en.json +12 -0
  71. package/src/modules/sales/i18n/es.json +12 -0
  72. package/src/modules/sales/i18n/ko.json +12 -0
  73. package/src/modules/sales/i18n/pl.json +12 -0
  74. package/src/modules/sales/lib/calculations.ts +99 -4
  75. package/src/modules/sales/lib/externalAmounts.ts +174 -0
  76. package/src/modules/sales/lib/lineSnapshots.ts +6 -1
  77. package/src/modules/sales/lib/makeSalesLineRoute.ts +8 -0
  78. package/src/modules/sales/lib/providers/totals.ts +5 -2
  79. package/src/modules/sales/lib/types.ts +19 -2
  80. package/src/modules/sales/migrations/.snapshot-open-mercato.json +33 -1
  81. package/src/modules/sales/migrations/Migration20260910120000_sales_external_amounts_mode.ts +25 -0
@@ -70,6 +70,7 @@ import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuarde
70
70
  import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from "@open-mercato/ui/backend/injection/recordContext";
71
71
  import { useSalesChannelsEnabled } from "@open-mercato/core/modules/sales/components/useSalesChannelsEnabled";
72
72
  import { createLogger } from "@open-mercato/shared/lib/logger";
73
+ import { getTelemetryRuntime } from "@open-mercato/shared/lib/telemetry/runtime";
73
74
  const logger = createLogger("sales");
74
75
  function formatMessageAmount(amount, currency, locale) {
75
76
  if (typeof amount !== "number" || !Number.isFinite(amount)) return null;
@@ -1129,6 +1130,7 @@ function MethodInlineEditor({
1129
1130
  emptyResultsLabel,
1130
1131
  selectedHint,
1131
1132
  icon,
1133
+ note,
1132
1134
  allowClear = true
1133
1135
  }) {
1134
1136
  const t = useT();
@@ -1222,6 +1224,7 @@ function MethodInlineEditor({
1222
1224
  children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
1223
1225
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
1224
1226
  /* @__PURE__ */ jsx("p", { className: "text-xs uppercase tracking-wide text-muted-foreground", children: label }),
1227
+ note ? /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: note }) : null,
1225
1228
  editing ? /* @__PURE__ */ jsxs(
1226
1229
  "div",
1227
1230
  {
@@ -1532,6 +1535,7 @@ function SalesDocumentDetailPage({
1532
1535
  const [generating, setGenerating] = React.useState(false);
1533
1536
  const [converting, setConverting] = React.useState(false);
1534
1537
  const [deleting, setDeleting] = React.useState(false);
1538
+ const [switchingToComputedAmounts, setSwitchingToComputedAmounts] = React.useState(false);
1535
1539
  const [sending, setSending] = React.useState(false);
1536
1540
  const [sendOpen, setSendOpen] = React.useState(false);
1537
1541
  const [validForDays, setValidForDays] = React.useState(DEFAULT_QUOTE_VALID_FOR_DAYS);
@@ -2293,6 +2297,7 @@ function SalesDocumentDetailPage({
2293
2297
  },
2294
2298
  [t]
2295
2299
  );
2300
+ const amountsAreExternal = kind === "order" && record?.totalsMode === "external";
2296
2301
  const totalsItems = React.useMemo(() => {
2297
2302
  if (!record) return [];
2298
2303
  const items = [
@@ -3071,6 +3076,48 @@ function SalesDocumentDetailPage({
3071
3076
  setSending(false);
3072
3077
  }
3073
3078
  }, [fetchDocumentByKind, kind, record, runMutationWithContext, t, validForDays]);
3079
+ const handleSwitchToComputedAmounts = React.useCallback(async () => {
3080
+ if (!record || kind !== "order") return;
3081
+ const ok = await confirm({
3082
+ title: t(
3083
+ "sales.documents.amountsSwitchConfirm",
3084
+ "Recompute this order\u2019s amounts from its lines? The totals supplied by the source system will be replaced and cannot be restored from here."
3085
+ ),
3086
+ variant: "default"
3087
+ });
3088
+ if (!ok) return;
3089
+ setSwitchingToComputedAmounts(true);
3090
+ try {
3091
+ await runMutationWithContext(async () => {
3092
+ await withScopedApiRequestHeaders(
3093
+ buildOptimisticLockHeader(record.updatedAt),
3094
+ () => apiCallOrThrow("/api/sales/orders", {
3095
+ method: "PUT",
3096
+ headers: { "Content-Type": "application/json" },
3097
+ body: JSON.stringify({ id: record.id, totalsMode: "computed" })
3098
+ })
3099
+ );
3100
+ }, { id: record.id, totalsMode: "computed" });
3101
+ flash(t("sales.documents.amountsSwitchDone", "Amounts are now computed from the lines."), "success");
3102
+ await refreshDocumentTotals();
3103
+ } catch (err) {
3104
+ logger.error("sales.documents.amounts.switchToComputed", { err });
3105
+ try {
3106
+ getTelemetryRuntime()?.reportError(err, {
3107
+ module: "sales",
3108
+ code: "sales.amounts_switch_to_computed_failed",
3109
+ attributes: { orderId: record.id }
3110
+ });
3111
+ } catch (reportFailure) {
3112
+ logger.warn("sales.documents.amounts.switchToComputed.reportFailed", { err: reportFailure });
3113
+ }
3114
+ if (!handleDocumentMutationError(err, t, () => setReloadKey((prev) => prev + 1))) {
3115
+ flash(t("sales.documents.amountsSwitchFailed", "Could not switch to computed amounts."), "error");
3116
+ }
3117
+ } finally {
3118
+ setSwitchingToComputedAmounts(false);
3119
+ }
3120
+ }, [confirm, kind, record, refreshDocumentTotals, runMutationWithContext, t]);
3074
3121
  const handleDelete = React.useCallback(async () => {
3075
3122
  if (!record) return;
3076
3123
  const ok = await confirm({
@@ -3129,7 +3176,11 @@ function SalesDocumentDetailPage({
3129
3176
  loadingLabel: t("sales.documents.detail.shippingMethod.loading", "Loading shipping methods\u2026"),
3130
3177
  emptyResultsLabel: t("sales.documents.detail.shippingMethod.empty", "No shipping methods found."),
3131
3178
  selectedHint: (id) => t("sales.documents.detail.shippingMethod.selected", "Selected shipping method: {{id}}", { id }),
3132
- icon: /* @__PURE__ */ jsx(Truck, { className: "h-5 w-5 text-muted-foreground" })
3179
+ icon: /* @__PURE__ */ jsx(Truck, { className: "h-5 w-5 text-muted-foreground" }),
3180
+ note: amountsAreExternal ? t(
3181
+ "sales.documents.amountsExternalMethodNote",
3182
+ "The method is recorded, but no charge is added \u2014 this order\u2019s totals come from the source system."
3183
+ ) : null
3133
3184
  }
3134
3185
  )
3135
3186
  },
@@ -3154,7 +3205,11 @@ function SalesDocumentDetailPage({
3154
3205
  loadingLabel: t("sales.documents.detail.paymentMethod.loading", "Loading payment methods\u2026"),
3155
3206
  emptyResultsLabel: t("sales.documents.detail.paymentMethod.empty", "No payment methods found."),
3156
3207
  selectedHint: (id) => t("sales.documents.detail.paymentMethod.selected", "Selected payment method: {{id}}", { id }),
3157
- icon: /* @__PURE__ */ jsx(CreditCard, { className: "h-5 w-5 text-muted-foreground" })
3208
+ icon: /* @__PURE__ */ jsx(CreditCard, { className: "h-5 w-5 text-muted-foreground" }),
3209
+ note: amountsAreExternal ? t(
3210
+ "sales.documents.amountsExternalMethodNote",
3211
+ "The method is recorded, but no charge is added \u2014 this order\u2019s totals come from the source system."
3212
+ ) : null
3158
3213
  }
3159
3214
  )
3160
3215
  }
@@ -3227,6 +3282,7 @@ function SalesDocumentDetailPage({
3227
3282
  );
3228
3283
  return fields;
3229
3284
  }, [
3285
+ amountsAreExternal,
3230
3286
  handleUpdateComment,
3231
3287
  handleUpdateCustomerReference,
3232
3288
  handleUpdateExpectedDeliveryAt,
@@ -3525,8 +3581,10 @@ function SalesDocumentDetailPage({
3525
3581
  organizationId: record?.organizationId ?? record?.organization_id ?? null,
3526
3582
  tenantId: record?.tenantId ?? record?.tenant_id ?? null,
3527
3583
  onActionChange: handleSectionActionChange,
3528
- onItemsChange: (items) => setHasItems(items.length > 0)
3529
- }
3584
+ onItemsChange: (items) => setHasItems(items.length > 0),
3585
+ amountsReadOnly: amountsAreExternal
3586
+ },
3587
+ `items:${amountsAreExternal ? "external" : "computed"}`
3530
3588
  );
3531
3589
  }
3532
3590
  if (activeTab === "shipments") {
@@ -3590,7 +3648,8 @@ function SalesDocumentDetailPage({
3590
3648
  organizationId: record?.organizationId ?? record?.organization_id ?? null,
3591
3649
  tenantId: record?.tenantId ?? record?.tenant_id ?? null,
3592
3650
  onActionChange: handleSectionActionChange,
3593
- onRowsChange: setAdjustmentRows
3651
+ onRowsChange: setAdjustmentRows,
3652
+ amountsReadOnly: amountsAreExternal
3594
3653
  }
3595
3654
  );
3596
3655
  }
@@ -4090,7 +4149,25 @@ function SalesDocumentDetailPage({
4090
4149
  {
4091
4150
  title: t("sales.documents.detail.totals.title", "Totals"),
4092
4151
  currency: record.currencyCode ?? null,
4093
- items: totalsItems
4152
+ items: totalsItems,
4153
+ sourceBadge: amountsAreExternal ? {
4154
+ label: t("sales.documents.amountsExternal", "Amounts from source"),
4155
+ hint: t(
4156
+ "sales.documents.amountsExternalHint",
4157
+ "Totals on this document come from an external system and are stored as supplied."
4158
+ )
4159
+ } : null,
4160
+ footerAction: amountsAreExternal ? /* @__PURE__ */ jsx(
4161
+ Button,
4162
+ {
4163
+ type: "button",
4164
+ variant: "outline",
4165
+ size: "sm",
4166
+ disabled: switchingToComputedAmounts,
4167
+ onClick: handleSwitchToComputedAmounts,
4168
+ children: t("sales.documents.amountsSwitchToComputed", "Switch to computed amounts")
4169
+ }
4170
+ ) : null
4094
4171
  }
4095
4172
  ),
4096
4173
  /* @__PURE__ */ jsxs("div", { className: "space-y-4", ref: detailSectionRef, children: [