@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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/generated/entities/sales_order/index.js +2 -0
- package/dist/generated/entities/sales_order/index.js.map +2 -2
- package/dist/generated/entities/sales_order_line/index.js +2 -0
- package/dist/generated/entities/sales_order_line/index.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/planner/api/availability-date-specific.js +2 -7
- package/dist/modules/planner/api/availability-date-specific.js.map +2 -2
- package/dist/modules/planner/commands/availability-date-specific.js +14 -31
- package/dist/modules/planner/commands/availability-date-specific.js.map +2 -2
- package/dist/modules/planner/commands/availability-weekly.js +8 -22
- package/dist/modules/planner/commands/availability-weekly.js.map +2 -2
- package/dist/modules/planner/lib/availabilityMerge.js +10 -18
- package/dist/modules/planner/lib/availabilityMerge.js.map +2 -2
- package/dist/modules/planner/lib/availabilityTimezone.js +161 -0
- package/dist/modules/planner/lib/availabilityTimezone.js.map +7 -0
- package/dist/modules/sales/api/documents/factory.js +3 -0
- package/dist/modules/sales/api/documents/factory.js.map +2 -2
- package/dist/modules/sales/api/order-lines/route.js +2 -1
- package/dist/modules/sales/api/order-lines/route.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +83 -6
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +141 -18
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/returns.js +24 -7
- package/dist/modules/sales/commands/returns.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js +17 -11
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/DocumentTotals.js +21 -3
- package/dist/modules/sales/components/documents/DocumentTotals.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +23 -12
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/data/entities.js +10 -0
- package/dist/modules/sales/data/entities.js.map +2 -2
- package/dist/modules/sales/data/validators.js +9 -1
- package/dist/modules/sales/data/validators.js.map +2 -2
- package/dist/modules/sales/lib/calculations.js +85 -6
- package/dist/modules/sales/lib/calculations.js.map +2 -2
- package/dist/modules/sales/lib/externalAmounts.js +143 -0
- package/dist/modules/sales/lib/externalAmounts.js.map +7 -0
- package/dist/modules/sales/lib/lineSnapshots.js +6 -1
- package/dist/modules/sales/lib/lineSnapshots.js.map +2 -2
- package/dist/modules/sales/lib/makeSalesLineRoute.js +8 -2
- package/dist/modules/sales/lib/makeSalesLineRoute.js.map +2 -2
- package/dist/modules/sales/lib/providers/totals.js +3 -2
- package/dist/modules/sales/lib/providers/totals.js.map +2 -2
- package/dist/modules/sales/migrations/Migration20260910120000_sales_external_amounts_mode.js +19 -0
- package/dist/modules/sales/migrations/Migration20260910120000_sales_external_amounts_mode.js.map +7 -0
- package/generated/entities/sales_order/index.ts +1 -0
- package/generated/entities/sales_order_line/index.ts +1 -0
- package/generated/entity-fields-registry.ts +2 -0
- package/package.json +8 -7
- package/src/modules/planner/api/availability-date-specific.ts +5 -10
- package/src/modules/planner/commands/availability-date-specific.ts +14 -33
- package/src/modules/planner/commands/availability-weekly.ts +15 -24
- package/src/modules/planner/lib/availabilityMerge.ts +13 -19
- package/src/modules/planner/lib/availabilityTimezone.ts +242 -0
- package/src/modules/sales/api/documents/factory.ts +3 -0
- package/src/modules/sales/api/order-lines/route.ts +2 -1
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +96 -0
- package/src/modules/sales/commands/documents.ts +219 -44
- package/src/modules/sales/commands/returns.ts +27 -3
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +34 -25
- package/src/modules/sales/components/documents/DocumentTotals.tsx +26 -2
- package/src/modules/sales/components/documents/ItemsSection.tsx +27 -12
- package/src/modules/sales/data/entities.ts +14 -0
- package/src/modules/sales/data/validators.ts +10 -0
- package/src/modules/sales/i18n/de.json +12 -0
- package/src/modules/sales/i18n/en.json +12 -0
- package/src/modules/sales/i18n/es.json +12 -0
- package/src/modules/sales/i18n/ko.json +12 -0
- package/src/modules/sales/i18n/pl.json +12 -0
- package/src/modules/sales/lib/calculations.ts +99 -4
- package/src/modules/sales/lib/externalAmounts.ts +174 -0
- package/src/modules/sales/lib/lineSnapshots.ts +6 -1
- package/src/modules/sales/lib/makeSalesLineRoute.ts +8 -0
- package/src/modules/sales/lib/providers/totals.ts +5 -2
- package/src/modules/sales/lib/types.ts +19 -2
- package/src/modules/sales/migrations/.snapshot-open-mercato.json +33 -1
- 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: [
|