@open-mercato/core 0.4.8-develop-409bb4a065 → 0.4.8-develop-344cc68055
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generated/entities/sales_return/index.js +31 -0
- package/dist/generated/entities/sales_return/index.js.map +7 -0
- package/dist/generated/entities/sales_return_line/index.js +29 -0
- package/dist/generated/entities/sales_return_line/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +2 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +4 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/auth/api/reset.js +4 -1
- package/dist/modules/auth/api/reset.js.map +2 -2
- package/dist/modules/auth/frontend/reset.js +8 -1
- package/dist/modules/auth/frontend/reset.js.map +2 -2
- package/dist/modules/sales/acl.js +2 -0
- package/dist/modules/sales/acl.js.map +2 -2
- package/dist/modules/sales/api/document-history/route.js +20 -2
- package/dist/modules/sales/api/document-history/route.js.map +2 -2
- package/dist/modules/sales/api/documents/factory.js +34 -0
- package/dist/modules/sales/api/documents/factory.js.map +2 -2
- package/dist/modules/sales/api/returns/[id]/route.js +147 -0
- package/dist/modules/sales/api/returns/[id]/route.js.map +7 -0
- package/dist/modules/sales/api/returns/route.js +158 -0
- package/dist/modules/sales/api/returns/route.js.map +7 -0
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +20 -1
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/index.js +1 -0
- package/dist/modules/sales/commands/index.js.map +2 -2
- package/dist/modules/sales/commands/returns.js +467 -0
- package/dist/modules/sales/commands/returns.js.map +7 -0
- package/dist/modules/sales/components/documents/ReturnDialog.js +176 -0
- package/dist/modules/sales/components/documents/ReturnDialog.js.map +7 -0
- package/dist/modules/sales/components/documents/ReturnsSection.js +188 -0
- package/dist/modules/sales/components/documents/ReturnsSection.js.map +7 -0
- package/dist/modules/sales/data/entities.js +115 -1
- package/dist/modules/sales/data/entities.js.map +2 -2
- package/dist/modules/sales/data/validators.js +13 -0
- package/dist/modules/sales/data/validators.js.map +2 -2
- package/dist/modules/sales/events.js +4 -0
- package/dist/modules/sales/events.js.map +2 -2
- package/dist/modules/sales/lib/calculations.js +7 -0
- package/dist/modules/sales/lib/calculations.js.map +2 -2
- package/dist/modules/sales/lib/dictionaries.js +1 -0
- package/dist/modules/sales/lib/dictionaries.js.map +2 -2
- package/dist/modules/sales/lib/documentNumberTokens.js +2 -0
- package/dist/modules/sales/lib/documentNumberTokens.js.map +2 -2
- package/dist/modules/sales/lib/historyHelpers.js +15 -7
- package/dist/modules/sales/lib/historyHelpers.js.map +2 -2
- package/dist/modules/sales/lib/makeSalesLineRoute.js +42 -37
- package/dist/modules/sales/lib/makeSalesLineRoute.js.map +2 -2
- package/dist/modules/sales/migrations/Migration20260309073310.js +23 -0
- package/dist/modules/sales/migrations/Migration20260309073310.js.map +7 -0
- package/dist/modules/sales/services/salesDocumentNumberGenerator.js +8 -6
- package/dist/modules/sales/services/salesDocumentNumberGenerator.js.map +2 -2
- package/dist/modules/sales/setup.js +1 -1
- package/dist/modules/sales/setup.js.map +2 -2
- package/dist/modules/sales/widgets/injection/document-history/widget.client.js +25 -16
- package/dist/modules/sales/widgets/injection/document-history/widget.client.js.map +2 -2
- package/generated/entities/sales_return/index.ts +14 -0
- package/generated/entities/sales_return_line/index.ts +13 -0
- package/generated/entities.ids.generated.ts +2 -0
- package/generated/entity-fields-registry.ts +4 -0
- package/package.json +3 -3
- package/src/modules/auth/api/reset.ts +4 -1
- package/src/modules/auth/frontend/reset.tsx +8 -1
- package/src/modules/auth/i18n/de.json +1 -0
- package/src/modules/auth/i18n/en.json +1 -0
- package/src/modules/auth/i18n/es.json +1 -0
- package/src/modules/auth/i18n/pl.json +1 -0
- package/src/modules/sales/AGENTS.md +1 -0
- package/src/modules/sales/acl.ts +2 -0
- package/src/modules/sales/api/document-history/route.ts +25 -1
- package/src/modules/sales/api/documents/factory.ts +35 -0
- package/src/modules/sales/api/returns/[id]/route.ts +156 -0
- package/src/modules/sales/api/returns/route.ts +171 -0
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +18 -0
- package/src/modules/sales/commands/index.ts +1 -0
- package/src/modules/sales/commands/returns.ts +540 -0
- package/src/modules/sales/components/documents/ReturnDialog.tsx +216 -0
- package/src/modules/sales/components/documents/ReturnsSection.tsx +270 -0
- package/src/modules/sales/data/entities.ts +99 -3
- package/src/modules/sales/data/validators.ts +16 -0
- package/src/modules/sales/events.ts +5 -0
- package/src/modules/sales/i18n/de.json +32 -0
- package/src/modules/sales/i18n/en.json +32 -0
- package/src/modules/sales/i18n/es.json +32 -0
- package/src/modules/sales/i18n/pl.json +32 -0
- package/src/modules/sales/lib/calculations.ts +9 -0
- package/src/modules/sales/lib/dictionaries.ts +1 -0
- package/src/modules/sales/lib/documentNumberTokens.ts +2 -1
- package/src/modules/sales/lib/historyHelpers.ts +20 -9
- package/src/modules/sales/lib/makeSalesLineRoute.ts +42 -37
- package/src/modules/sales/migrations/.snapshot-open-mercato.json +398 -0
- package/src/modules/sales/migrations/Migration20260309073310.ts +26 -0
- package/src/modules/sales/services/salesDocumentNumberGenerator.ts +15 -4
- package/src/modules/sales/setup.ts +1 -1
- package/src/modules/sales/widgets/injection/document-history/widget.client.tsx +26 -17
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/sales/commands/index.ts"],
|
|
4
|
-
"sourcesContent": ["import './configuration'\nimport './documents'\nimport './statuses'\nimport './settings'\nimport './tags'\nimport './documentAddresses'\nimport './shipments'\nimport './payments'\nimport './notes'\n"],
|
|
5
|
-
"mappings": "AAAA,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;",
|
|
4
|
+
"sourcesContent": ["import './configuration'\nimport './documents'\nimport './statuses'\nimport './settings'\nimport './tags'\nimport './documentAddresses'\nimport './shipments'\nimport './payments'\nimport './notes'\nimport './returns'\n"],
|
|
5
|
+
"mappings": "AAAA,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
import { registerCommand } from "@open-mercato/shared/lib/commands";
|
|
3
|
+
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
4
|
+
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
5
|
+
import { emitCrudSideEffects } from "@open-mercato/shared/lib/commands/helpers";
|
|
6
|
+
import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
7
|
+
import { SalesDocumentNumberGenerator } from "../services/salesDocumentNumberGenerator.js";
|
|
8
|
+
import { cloneJson, ensureOrganizationScope, ensureSameScope, ensureTenantScope, extractUndoPayload, toNumericString } from "./shared.js";
|
|
9
|
+
import { SalesOrder, SalesOrderAdjustment, SalesOrderLine, SalesReturn, SalesReturnLine } from "../data/entities.js";
|
|
10
|
+
import { returnCreateSchema } from "../data/validators.js";
|
|
11
|
+
import { E } from "../../../generated/entities.ids.generated.js";
|
|
12
|
+
const returnCrudEvents = {
|
|
13
|
+
module: "sales",
|
|
14
|
+
entity: "return",
|
|
15
|
+
persistent: true,
|
|
16
|
+
buildPayload: (ctx) => ({
|
|
17
|
+
id: ctx.identifiers.id,
|
|
18
|
+
organizationId: ctx.identifiers.organizationId,
|
|
19
|
+
tenantId: ctx.identifiers.tenantId
|
|
20
|
+
})
|
|
21
|
+
};
|
|
22
|
+
function toNumeric(value) {
|
|
23
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
24
|
+
if (typeof value === "string" && value.trim().length) {
|
|
25
|
+
const parsed = Number(value);
|
|
26
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
27
|
+
}
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
function round(value) {
|
|
31
|
+
return Math.round((value + Number.EPSILON) * 1e4) / 1e4;
|
|
32
|
+
}
|
|
33
|
+
function applyOrderTotals(order, totals, lineCount) {
|
|
34
|
+
order.subtotalNetAmount = toNumericString(totals.subtotalNetAmount) ?? "0";
|
|
35
|
+
order.subtotalGrossAmount = toNumericString(totals.subtotalGrossAmount) ?? "0";
|
|
36
|
+
order.discountTotalAmount = toNumericString(totals.discountTotalAmount) ?? "0";
|
|
37
|
+
order.taxTotalAmount = toNumericString(totals.taxTotalAmount) ?? "0";
|
|
38
|
+
order.shippingNetAmount = toNumericString(totals.shippingNetAmount) ?? "0";
|
|
39
|
+
order.shippingGrossAmount = toNumericString(totals.shippingGrossAmount) ?? "0";
|
|
40
|
+
order.surchargeTotalAmount = toNumericString(totals.surchargeTotalAmount) ?? "0";
|
|
41
|
+
order.grandTotalNetAmount = toNumericString(totals.grandTotalNetAmount) ?? "0";
|
|
42
|
+
order.grandTotalGrossAmount = toNumericString(totals.grandTotalGrossAmount) ?? "0";
|
|
43
|
+
order.paidTotalAmount = toNumericString(totals.paidTotalAmount) ?? "0";
|
|
44
|
+
order.refundedTotalAmount = toNumericString(totals.refundedTotalAmount) ?? "0";
|
|
45
|
+
order.outstandingAmount = toNumericString(totals.outstandingAmount) ?? "0";
|
|
46
|
+
order.totalsSnapshot = cloneJson(totals);
|
|
47
|
+
order.lineItemCount = lineCount;
|
|
48
|
+
}
|
|
49
|
+
function mapOrderLineEntityToSnapshot(line) {
|
|
50
|
+
return {
|
|
51
|
+
id: line.id,
|
|
52
|
+
lineNumber: line.lineNumber,
|
|
53
|
+
kind: line.kind,
|
|
54
|
+
productId: line.productId ?? null,
|
|
55
|
+
productVariantId: line.productVariantId ?? null,
|
|
56
|
+
name: line.name ?? null,
|
|
57
|
+
description: line.description ?? null,
|
|
58
|
+
comment: line.comment ?? null,
|
|
59
|
+
quantity: toNumeric(line.quantity),
|
|
60
|
+
quantityUnit: line.quantityUnit ?? null,
|
|
61
|
+
normalizedQuantity: toNumeric(line.normalizedQuantity ?? line.quantity),
|
|
62
|
+
normalizedUnit: line.normalizedUnit ?? line.quantityUnit ?? null,
|
|
63
|
+
uomSnapshot: line.uomSnapshot ? cloneJson(line.uomSnapshot) : null,
|
|
64
|
+
currencyCode: line.currencyCode,
|
|
65
|
+
unitPriceNet: toNumeric(line.unitPriceNet),
|
|
66
|
+
unitPriceGross: toNumeric(line.unitPriceGross),
|
|
67
|
+
discountAmount: toNumeric(line.discountAmount),
|
|
68
|
+
discountPercent: toNumeric(line.discountPercent),
|
|
69
|
+
taxRate: toNumeric(line.taxRate),
|
|
70
|
+
taxAmount: toNumeric(line.taxAmount),
|
|
71
|
+
totalNetAmount: toNumeric(line.totalNetAmount),
|
|
72
|
+
totalGrossAmount: toNumeric(line.totalGrossAmount),
|
|
73
|
+
configuration: line.configuration ? cloneJson(line.configuration) : null,
|
|
74
|
+
promotionCode: line.promotionCode ?? null,
|
|
75
|
+
metadata: line.metadata ? cloneJson(line.metadata) : null,
|
|
76
|
+
customFieldSetId: line.customFieldSetId ?? null
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function mapOrderAdjustmentToDraft(adjustment) {
|
|
80
|
+
return {
|
|
81
|
+
id: adjustment.id,
|
|
82
|
+
scope: adjustment.scope ?? "order",
|
|
83
|
+
kind: adjustment.kind,
|
|
84
|
+
code: adjustment.code ?? null,
|
|
85
|
+
label: adjustment.label ?? null,
|
|
86
|
+
calculatorKey: adjustment.calculatorKey ?? null,
|
|
87
|
+
promotionId: adjustment.promotionId ?? null,
|
|
88
|
+
rate: toNumeric(adjustment.rate),
|
|
89
|
+
amountNet: toNumeric(adjustment.amountNet),
|
|
90
|
+
amountGross: toNumeric(adjustment.amountGross),
|
|
91
|
+
currencyCode: adjustment.currencyCode ?? null,
|
|
92
|
+
metadata: adjustment.metadata ? cloneJson(adjustment.metadata) : null,
|
|
93
|
+
position: adjustment.position ?? 0
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function buildCalculationContext(order) {
|
|
97
|
+
return {
|
|
98
|
+
tenantId: order.tenantId,
|
|
99
|
+
organizationId: order.organizationId,
|
|
100
|
+
currencyCode: order.currencyCode,
|
|
101
|
+
metadata: {
|
|
102
|
+
shippingMethod: order.shippingMethodSnapshot ? cloneJson(order.shippingMethodSnapshot) : null,
|
|
103
|
+
paymentMethod: order.paymentMethodSnapshot ? cloneJson(order.paymentMethodSnapshot) : null
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
async function recalculateOrderTotalsForDisplay(em, container, orderId, scope) {
|
|
108
|
+
const order = await findOneWithDecryption(
|
|
109
|
+
em,
|
|
110
|
+
SalesOrder,
|
|
111
|
+
{ id: orderId, deletedAt: null },
|
|
112
|
+
{},
|
|
113
|
+
scope
|
|
114
|
+
);
|
|
115
|
+
if (!order) return null;
|
|
116
|
+
const [orderLines, adjustments] = await Promise.all([
|
|
117
|
+
findWithDecryption(em, SalesOrderLine, { order: order.id, deletedAt: null }, {}, scope),
|
|
118
|
+
findWithDecryption(
|
|
119
|
+
em,
|
|
120
|
+
SalesOrderAdjustment,
|
|
121
|
+
{ order: order.id, deletedAt: null },
|
|
122
|
+
{ orderBy: { position: "asc" } },
|
|
123
|
+
scope
|
|
124
|
+
)
|
|
125
|
+
]);
|
|
126
|
+
const lineSnapshots = orderLines.map(mapOrderLineEntityToSnapshot);
|
|
127
|
+
const adjustmentDrafts = adjustments.map(mapOrderAdjustmentToDraft);
|
|
128
|
+
const salesCalculationService = container.resolve("salesCalculationService");
|
|
129
|
+
const calculation = await salesCalculationService.calculateDocumentTotals({
|
|
130
|
+
documentKind: "order",
|
|
131
|
+
lines: lineSnapshots,
|
|
132
|
+
adjustments: adjustmentDrafts,
|
|
133
|
+
context: buildCalculationContext(order),
|
|
134
|
+
existingTotals: {
|
|
135
|
+
paidTotalAmount: toNumeric(order.paidTotalAmount),
|
|
136
|
+
refundedTotalAmount: toNumeric(order.refundedTotalAmount)
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
return calculation.totals;
|
|
140
|
+
}
|
|
141
|
+
async function loadReturnSnapshot(em, id) {
|
|
142
|
+
const header = await findOneWithDecryption(
|
|
143
|
+
em,
|
|
144
|
+
SalesReturn,
|
|
145
|
+
{ id, deletedAt: null },
|
|
146
|
+
{ populate: ["order"] },
|
|
147
|
+
{}
|
|
148
|
+
);
|
|
149
|
+
if (!header || !header.order) return null;
|
|
150
|
+
const orderId = typeof header.order === "string" ? header.order : header.order.id;
|
|
151
|
+
const lines = await findWithDecryption(
|
|
152
|
+
em,
|
|
153
|
+
SalesReturnLine,
|
|
154
|
+
{ salesReturn: header.id, deletedAt: null },
|
|
155
|
+
{ populate: ["orderLine"] },
|
|
156
|
+
{ tenantId: header.tenantId, organizationId: header.organizationId }
|
|
157
|
+
);
|
|
158
|
+
const adjustmentIds = [];
|
|
159
|
+
const adjustments = await findWithDecryption(
|
|
160
|
+
em,
|
|
161
|
+
SalesOrderAdjustment,
|
|
162
|
+
{ order: orderId, kind: "return", deletedAt: null },
|
|
163
|
+
{},
|
|
164
|
+
{ tenantId: header.tenantId, organizationId: header.organizationId }
|
|
165
|
+
);
|
|
166
|
+
adjustments.forEach((adj) => {
|
|
167
|
+
const meta = adj.metadata;
|
|
168
|
+
if (meta && meta.returnId === header.id) adjustmentIds.push(adj.id);
|
|
169
|
+
});
|
|
170
|
+
return {
|
|
171
|
+
id: header.id,
|
|
172
|
+
orderId,
|
|
173
|
+
organizationId: header.organizationId,
|
|
174
|
+
tenantId: header.tenantId,
|
|
175
|
+
returnNumber: header.returnNumber,
|
|
176
|
+
returnedAt: header.returnedAt ? header.returnedAt.toISOString() : null,
|
|
177
|
+
reason: header.reason ?? null,
|
|
178
|
+
notes: header.notes ?? null,
|
|
179
|
+
lines: lines.map((line) => ({
|
|
180
|
+
id: line.id,
|
|
181
|
+
orderLineId: typeof line.orderLine === "string" ? line.orderLine : line.orderLine?.id ?? null,
|
|
182
|
+
quantityReturned: toNumeric(line.quantityReturned),
|
|
183
|
+
unitPriceNet: toNumeric(line.unitPriceNet),
|
|
184
|
+
unitPriceGross: toNumeric(line.unitPriceGross),
|
|
185
|
+
totalNetAmount: toNumeric(line.totalNetAmount),
|
|
186
|
+
totalGrossAmount: toNumeric(line.totalGrossAmount)
|
|
187
|
+
})),
|
|
188
|
+
adjustmentIds
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function normalizeLinesInput(lines) {
|
|
192
|
+
const seen = /* @__PURE__ */ new Set();
|
|
193
|
+
const result = [];
|
|
194
|
+
for (const line of lines) {
|
|
195
|
+
const orderLineId = line.orderLineId;
|
|
196
|
+
if (!orderLineId || seen.has(orderLineId)) continue;
|
|
197
|
+
const quantity = toNumeric(line.quantity);
|
|
198
|
+
if (!Number.isFinite(quantity) || quantity <= 0) continue;
|
|
199
|
+
seen.add(orderLineId);
|
|
200
|
+
result.push({ orderLineId, quantity });
|
|
201
|
+
}
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
const createReturnCommand = {
|
|
205
|
+
id: "sales.returns.create",
|
|
206
|
+
async execute(rawInput, ctx) {
|
|
207
|
+
const input = returnCreateSchema.parse(rawInput ?? {});
|
|
208
|
+
ensureTenantScope(ctx, input.tenantId);
|
|
209
|
+
ensureOrganizationScope(ctx, input.organizationId);
|
|
210
|
+
const { translate } = await resolveTranslations();
|
|
211
|
+
const em = ctx.container.resolve("em").fork();
|
|
212
|
+
const order = await findOneWithDecryption(
|
|
213
|
+
em,
|
|
214
|
+
SalesOrder,
|
|
215
|
+
{ id: input.orderId, deletedAt: null },
|
|
216
|
+
{},
|
|
217
|
+
{ tenantId: input.tenantId, organizationId: input.organizationId }
|
|
218
|
+
);
|
|
219
|
+
if (!order) {
|
|
220
|
+
throw new CrudHttpError(404, { error: translate("sales.returns.orderMissing", "Order not found.") });
|
|
221
|
+
}
|
|
222
|
+
ensureSameScope(order, input.organizationId, input.tenantId);
|
|
223
|
+
const requested = normalizeLinesInput(input.lines);
|
|
224
|
+
if (!requested.length) {
|
|
225
|
+
throw new CrudHttpError(400, { error: translate("sales.returns.linesRequired", "Select at least one line to return.") });
|
|
226
|
+
}
|
|
227
|
+
const orderLines = await findWithDecryption(
|
|
228
|
+
em,
|
|
229
|
+
SalesOrderLine,
|
|
230
|
+
{ order: order.id, deletedAt: null },
|
|
231
|
+
{},
|
|
232
|
+
{ tenantId: input.tenantId, organizationId: input.organizationId }
|
|
233
|
+
);
|
|
234
|
+
const lineMap = new Map(orderLines.map((line) => [line.id, line]));
|
|
235
|
+
requested.forEach(({ orderLineId, quantity }) => {
|
|
236
|
+
const line = lineMap.get(orderLineId);
|
|
237
|
+
if (!line) {
|
|
238
|
+
throw new CrudHttpError(404, { error: translate("sales.returns.lineMissing", "Order line not found.") });
|
|
239
|
+
}
|
|
240
|
+
const available = toNumeric(line.quantity) - toNumeric(line.returnedQuantity);
|
|
241
|
+
if (quantity - 1e-6 > available) {
|
|
242
|
+
throw new CrudHttpError(400, { error: translate("sales.returns.quantityExceeded", "Cannot return more than the remaining quantity.") });
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
const existingAdjustments = await findWithDecryption(
|
|
246
|
+
em,
|
|
247
|
+
SalesOrderAdjustment,
|
|
248
|
+
{ order: order.id, deletedAt: null },
|
|
249
|
+
{ orderBy: { position: "asc" } },
|
|
250
|
+
{ tenantId: input.tenantId, organizationId: input.organizationId }
|
|
251
|
+
);
|
|
252
|
+
const positionStart = existingAdjustments.reduce((acc, adj) => Math.max(acc, adj.position ?? 0), 0) + 1;
|
|
253
|
+
const numberGenerator = new SalesDocumentNumberGenerator(em);
|
|
254
|
+
const generated = await numberGenerator.generate({
|
|
255
|
+
kind: "return",
|
|
256
|
+
tenantId: input.tenantId,
|
|
257
|
+
organizationId: input.organizationId
|
|
258
|
+
});
|
|
259
|
+
const returnId = randomUUID();
|
|
260
|
+
const header = em.create(SalesReturn, {
|
|
261
|
+
id: returnId,
|
|
262
|
+
order,
|
|
263
|
+
organizationId: input.organizationId,
|
|
264
|
+
tenantId: input.tenantId,
|
|
265
|
+
returnNumber: generated.number,
|
|
266
|
+
reason: input.reason ?? null,
|
|
267
|
+
notes: input.notes ?? null,
|
|
268
|
+
returnedAt: input.returnedAt ?? /* @__PURE__ */ new Date(),
|
|
269
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
270
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
271
|
+
});
|
|
272
|
+
em.persist(header);
|
|
273
|
+
const createdAdjustments = [];
|
|
274
|
+
const createdLines = [];
|
|
275
|
+
requested.forEach((lineInput, index) => {
|
|
276
|
+
const line = lineMap.get(lineInput.orderLineId);
|
|
277
|
+
if (!line) return;
|
|
278
|
+
const quantity = lineInput.quantity;
|
|
279
|
+
const lineQuantity = Math.max(toNumeric(line.quantity), 0);
|
|
280
|
+
const unitNet = lineQuantity > 0 ? toNumeric(line.totalNetAmount) / lineQuantity : toNumeric(line.unitPriceNet);
|
|
281
|
+
const unitGross = lineQuantity > 0 ? toNumeric(line.totalGrossAmount) / lineQuantity : toNumeric(line.unitPriceGross);
|
|
282
|
+
const totalNet = -round(Math.max(unitNet, 0) * quantity);
|
|
283
|
+
const totalGross = -round(Math.max(unitGross, 0) * quantity);
|
|
284
|
+
const returnLineId = randomUUID();
|
|
285
|
+
const returnLine = em.create(SalesReturnLine, {
|
|
286
|
+
id: returnLineId,
|
|
287
|
+
salesReturn: header,
|
|
288
|
+
orderLine: em.getReference(SalesOrderLine, line.id),
|
|
289
|
+
organizationId: input.organizationId,
|
|
290
|
+
tenantId: input.tenantId,
|
|
291
|
+
quantityReturned: quantity.toString(),
|
|
292
|
+
unitPriceNet: round(unitNet).toString(),
|
|
293
|
+
unitPriceGross: round(unitGross).toString(),
|
|
294
|
+
totalNetAmount: totalNet.toString(),
|
|
295
|
+
totalGrossAmount: totalGross.toString(),
|
|
296
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
297
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
298
|
+
});
|
|
299
|
+
createdLines.push(returnLine);
|
|
300
|
+
em.persist(returnLine);
|
|
301
|
+
const adjustment = em.create(SalesOrderAdjustment, {
|
|
302
|
+
id: randomUUID(),
|
|
303
|
+
order,
|
|
304
|
+
orderLine: em.getReference(SalesOrderLine, line.id),
|
|
305
|
+
organizationId: input.organizationId,
|
|
306
|
+
tenantId: input.tenantId,
|
|
307
|
+
scope: "line",
|
|
308
|
+
kind: "return",
|
|
309
|
+
rate: "0",
|
|
310
|
+
amountNet: totalNet.toString(),
|
|
311
|
+
amountGross: totalGross.toString(),
|
|
312
|
+
currencyCode: order.currencyCode,
|
|
313
|
+
metadata: { returnId, returnLineId },
|
|
314
|
+
position: positionStart + index,
|
|
315
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
316
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
317
|
+
});
|
|
318
|
+
createdAdjustments.push(adjustment);
|
|
319
|
+
em.persist(adjustment);
|
|
320
|
+
line.returnedQuantity = (toNumeric(line.returnedQuantity) + quantity).toString();
|
|
321
|
+
line.updatedAt = /* @__PURE__ */ new Date();
|
|
322
|
+
em.persist(line);
|
|
323
|
+
});
|
|
324
|
+
const salesCalculationService = ctx.container.resolve("salesCalculationService");
|
|
325
|
+
const lineSnapshots = orderLines.map(mapOrderLineEntityToSnapshot);
|
|
326
|
+
const adjustmentDrafts = [...existingAdjustments, ...createdAdjustments].map(mapOrderAdjustmentToDraft);
|
|
327
|
+
const calculation = await salesCalculationService.calculateDocumentTotals({
|
|
328
|
+
documentKind: "order",
|
|
329
|
+
lines: lineSnapshots,
|
|
330
|
+
adjustments: adjustmentDrafts,
|
|
331
|
+
context: buildCalculationContext(order)
|
|
332
|
+
});
|
|
333
|
+
applyOrderTotals(order, calculation.totals, calculation.lines.length);
|
|
334
|
+
order.updatedAt = /* @__PURE__ */ new Date();
|
|
335
|
+
em.persist(order);
|
|
336
|
+
await em.flush();
|
|
337
|
+
const dataEngine = ctx.container.resolve("dataEngine");
|
|
338
|
+
await emitCrudSideEffects({
|
|
339
|
+
dataEngine,
|
|
340
|
+
action: "created",
|
|
341
|
+
entity: header,
|
|
342
|
+
identifiers: { id: header.id, organizationId: header.organizationId, tenantId: header.tenantId },
|
|
343
|
+
indexer: { entityType: E.sales.sales_return },
|
|
344
|
+
events: returnCrudEvents
|
|
345
|
+
});
|
|
346
|
+
if (createdLines.length) {
|
|
347
|
+
await Promise.all(
|
|
348
|
+
createdLines.map(
|
|
349
|
+
(line) => emitCrudSideEffects({
|
|
350
|
+
dataEngine,
|
|
351
|
+
action: "created",
|
|
352
|
+
entity: line,
|
|
353
|
+
identifiers: { id: line.id, organizationId: line.organizationId, tenantId: line.tenantId },
|
|
354
|
+
indexer: { entityType: E.sales.sales_return_line }
|
|
355
|
+
})
|
|
356
|
+
)
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
return { returnId };
|
|
360
|
+
},
|
|
361
|
+
captureAfter: async (_input, result, ctx) => {
|
|
362
|
+
const em = ctx.container.resolve("em").fork();
|
|
363
|
+
return loadReturnSnapshot(em, result.returnId);
|
|
364
|
+
},
|
|
365
|
+
buildLog: async ({ result, snapshots }) => {
|
|
366
|
+
const after = snapshots.after;
|
|
367
|
+
if (!after) return null;
|
|
368
|
+
const { translate } = await resolveTranslations();
|
|
369
|
+
return {
|
|
370
|
+
actionLabel: translate("sales.audit.returns.create", "Create return"),
|
|
371
|
+
resourceKind: "sales.return",
|
|
372
|
+
resourceId: result.returnId,
|
|
373
|
+
parentResourceKind: "sales.order",
|
|
374
|
+
parentResourceId: after.orderId ?? null,
|
|
375
|
+
tenantId: after.tenantId,
|
|
376
|
+
organizationId: after.organizationId,
|
|
377
|
+
snapshotAfter: after,
|
|
378
|
+
payload: {
|
|
379
|
+
undo: { after }
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
},
|
|
383
|
+
undo: async ({ logEntry, ctx }) => {
|
|
384
|
+
const payload = extractUndoPayload(logEntry);
|
|
385
|
+
const after = payload?.after;
|
|
386
|
+
if (!after) return;
|
|
387
|
+
const em = ctx.container.resolve("em").fork();
|
|
388
|
+
const order = await findOneWithDecryption(
|
|
389
|
+
em,
|
|
390
|
+
SalesOrder,
|
|
391
|
+
{ id: after.orderId, deletedAt: null },
|
|
392
|
+
{},
|
|
393
|
+
{ tenantId: after.tenantId, organizationId: after.organizationId }
|
|
394
|
+
);
|
|
395
|
+
if (!order) return;
|
|
396
|
+
const lines = await findWithDecryption(
|
|
397
|
+
em,
|
|
398
|
+
SalesOrderLine,
|
|
399
|
+
{ order: order.id, deletedAt: null },
|
|
400
|
+
{},
|
|
401
|
+
{ tenantId: after.tenantId, organizationId: after.organizationId }
|
|
402
|
+
);
|
|
403
|
+
const lineMap = new Map(lines.map((line) => [line.id, line]));
|
|
404
|
+
after.lines.forEach((entry) => {
|
|
405
|
+
const line = lineMap.get(entry.orderLineId);
|
|
406
|
+
if (!line) return;
|
|
407
|
+
const next = Math.max(0, toNumeric(line.returnedQuantity) - entry.quantityReturned);
|
|
408
|
+
line.returnedQuantity = next.toString();
|
|
409
|
+
line.updatedAt = /* @__PURE__ */ new Date();
|
|
410
|
+
em.persist(line);
|
|
411
|
+
});
|
|
412
|
+
if (after.adjustmentIds.length) {
|
|
413
|
+
const adjustments = await findWithDecryption(
|
|
414
|
+
em,
|
|
415
|
+
SalesOrderAdjustment,
|
|
416
|
+
{ id: { $in: after.adjustmentIds }, deletedAt: null },
|
|
417
|
+
{},
|
|
418
|
+
{ tenantId: after.tenantId, organizationId: after.organizationId }
|
|
419
|
+
);
|
|
420
|
+
adjustments.forEach((adj) => em.remove(adj));
|
|
421
|
+
}
|
|
422
|
+
const header = await findOneWithDecryption(
|
|
423
|
+
em,
|
|
424
|
+
SalesReturn,
|
|
425
|
+
{ id: after.id, deletedAt: null },
|
|
426
|
+
{},
|
|
427
|
+
{ tenantId: after.tenantId, organizationId: after.organizationId }
|
|
428
|
+
);
|
|
429
|
+
const returnLines = await findWithDecryption(
|
|
430
|
+
em,
|
|
431
|
+
SalesReturnLine,
|
|
432
|
+
{ salesReturn: after.id, deletedAt: null },
|
|
433
|
+
{},
|
|
434
|
+
{ tenantId: after.tenantId, organizationId: after.organizationId }
|
|
435
|
+
);
|
|
436
|
+
returnLines.forEach((line) => em.remove(line));
|
|
437
|
+
if (header) em.remove(header);
|
|
438
|
+
const existingAdjustments = await findWithDecryption(
|
|
439
|
+
em,
|
|
440
|
+
SalesOrderAdjustment,
|
|
441
|
+
{ order: order.id, deletedAt: null },
|
|
442
|
+
{ orderBy: { position: "asc" } },
|
|
443
|
+
{ tenantId: after.tenantId, organizationId: after.organizationId }
|
|
444
|
+
);
|
|
445
|
+
const salesCalculationService = ctx.container.resolve("salesCalculationService");
|
|
446
|
+
const lineSnapshots = lines.map(mapOrderLineEntityToSnapshot);
|
|
447
|
+
const adjustmentDrafts = existingAdjustments.map(mapOrderAdjustmentToDraft);
|
|
448
|
+
const calculation = await salesCalculationService.calculateDocumentTotals({
|
|
449
|
+
documentKind: "order",
|
|
450
|
+
lines: lineSnapshots,
|
|
451
|
+
adjustments: adjustmentDrafts,
|
|
452
|
+
context: buildCalculationContext(order)
|
|
453
|
+
});
|
|
454
|
+
applyOrderTotals(order, calculation.totals, calculation.lines.length);
|
|
455
|
+
order.updatedAt = /* @__PURE__ */ new Date();
|
|
456
|
+
em.persist(order);
|
|
457
|
+
await em.flush();
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
registerCommand(createReturnCommand);
|
|
461
|
+
const returnCommands = [createReturnCommand];
|
|
462
|
+
export {
|
|
463
|
+
loadReturnSnapshot,
|
|
464
|
+
recalculateOrderTotalsForDisplay,
|
|
465
|
+
returnCommands
|
|
466
|
+
};
|
|
467
|
+
//# sourceMappingURL=returns.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/sales/commands/returns.ts"],
|
|
4
|
+
"sourcesContent": ["import { randomUUID } from 'crypto'\nimport { registerCommand, type CommandHandler } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { emitCrudSideEffects } from '@open-mercato/shared/lib/commands/helpers'\nimport type { CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { SalesDocumentNumberGenerator } from '../services/salesDocumentNumberGenerator'\nimport type { SalesCalculationService } from '../services/salesCalculationService'\nimport type { SalesAdjustmentDraft, SalesLineSnapshot, SalesDocumentCalculationResult } from '../lib/types'\nimport { cloneJson, ensureOrganizationScope, ensureSameScope, ensureTenantScope, extractUndoPayload, toNumericString } from './shared'\nimport { SalesOrder, SalesOrderAdjustment, SalesOrderLine, SalesReturn, SalesReturnLine } from '../data/entities'\nimport { returnCreateSchema, type ReturnCreateInput } from '../data/validators'\nimport { E } from '#generated/entities.ids.generated'\n\ntype ReturnLineInput = { orderLineId: string; quantity: number }\n\ntype ReturnSnapshot = {\n id: string\n orderId: string\n organizationId: string\n tenantId: string\n returnNumber: string\n returnedAt: string | null\n reason: string | null\n notes: string | null\n lines: Array<{\n id: string\n orderLineId: string\n quantityReturned: number\n unitPriceNet: number\n unitPriceGross: number\n totalNetAmount: number\n totalGrossAmount: number\n }>\n adjustmentIds: string[]\n}\n\ntype ReturnUndoPayload = {\n after?: ReturnSnapshot | null\n}\n\nconst returnCrudEvents: CrudEventsConfig = {\n module: 'sales',\n entity: 'return',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\nfunction toNumeric(value: unknown): number {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n if (Number.isFinite(parsed)) return parsed\n }\n return 0\n}\n\nfunction round(value: number): number {\n return Math.round((value + Number.EPSILON) * 1e4) / 1e4\n}\n\nfunction applyOrderTotals(order: SalesOrder, totals: SalesDocumentCalculationResult['totals'], lineCount: number): void {\n order.subtotalNetAmount = toNumericString(totals.subtotalNetAmount) ?? '0'\n order.subtotalGrossAmount = toNumericString(totals.subtotalGrossAmount) ?? '0'\n order.discountTotalAmount = toNumericString(totals.discountTotalAmount) ?? '0'\n order.taxTotalAmount = toNumericString(totals.taxTotalAmount) ?? '0'\n order.shippingNetAmount = toNumericString(totals.shippingNetAmount) ?? '0'\n order.shippingGrossAmount = toNumericString(totals.shippingGrossAmount) ?? '0'\n order.surchargeTotalAmount = toNumericString(totals.surchargeTotalAmount) ?? '0'\n order.grandTotalNetAmount = toNumericString(totals.grandTotalNetAmount) ?? '0'\n order.grandTotalGrossAmount = toNumericString(totals.grandTotalGrossAmount) ?? '0'\n order.paidTotalAmount = toNumericString(totals.paidTotalAmount) ?? '0'\n order.refundedTotalAmount = toNumericString(totals.refundedTotalAmount) ?? '0'\n order.outstandingAmount = toNumericString(totals.outstandingAmount) ?? '0'\n order.totalsSnapshot = cloneJson(totals)\n order.lineItemCount = lineCount\n}\n\nfunction mapOrderLineEntityToSnapshot(line: SalesOrderLine): SalesLineSnapshot {\n return {\n id: line.id,\n lineNumber: line.lineNumber,\n kind: line.kind,\n productId: line.productId ?? null,\n productVariantId: line.productVariantId ?? null,\n name: line.name ?? null,\n description: line.description ?? null,\n comment: line.comment ?? null,\n quantity: toNumeric(line.quantity),\n quantityUnit: line.quantityUnit ?? null,\n normalizedQuantity: toNumeric(line.normalizedQuantity ?? line.quantity),\n normalizedUnit: line.normalizedUnit ?? line.quantityUnit ?? null,\n uomSnapshot: line.uomSnapshot ? cloneJson(line.uomSnapshot) : null,\n currencyCode: line.currencyCode,\n unitPriceNet: toNumeric(line.unitPriceNet),\n unitPriceGross: toNumeric(line.unitPriceGross),\n discountAmount: toNumeric(line.discountAmount),\n discountPercent: toNumeric(line.discountPercent),\n taxRate: toNumeric(line.taxRate),\n taxAmount: toNumeric(line.taxAmount),\n totalNetAmount: toNumeric(line.totalNetAmount),\n totalGrossAmount: toNumeric(line.totalGrossAmount),\n configuration: line.configuration ? cloneJson(line.configuration) : null,\n promotionCode: line.promotionCode ?? null,\n metadata: line.metadata ? cloneJson(line.metadata) : null,\n customFieldSetId: line.customFieldSetId ?? null,\n }\n}\n\nfunction mapOrderAdjustmentToDraft(adjustment: SalesOrderAdjustment): SalesAdjustmentDraft {\n return {\n id: adjustment.id,\n scope: adjustment.scope ?? 'order',\n kind: adjustment.kind,\n code: adjustment.code ?? null,\n label: adjustment.label ?? null,\n calculatorKey: adjustment.calculatorKey ?? null,\n promotionId: adjustment.promotionId ?? null,\n rate: toNumeric(adjustment.rate),\n amountNet: toNumeric(adjustment.amountNet),\n amountGross: toNumeric(adjustment.amountGross),\n currencyCode: adjustment.currencyCode ?? null,\n metadata: adjustment.metadata ? cloneJson(adjustment.metadata) : null,\n position: adjustment.position ?? 0,\n }\n}\n\nfunction buildCalculationContext(order: SalesOrder) {\n return {\n tenantId: order.tenantId,\n organizationId: order.organizationId,\n currencyCode: order.currencyCode,\n metadata: {\n shippingMethod: order.shippingMethodSnapshot\n ? cloneJson(order.shippingMethodSnapshot as Record<string, unknown>)\n : null,\n paymentMethod: order.paymentMethodSnapshot ? cloneJson(order.paymentMethodSnapshot as Record<string, unknown>) : null,\n },\n }\n}\n\n/**\n * Recalculates order totals (including line-scoped return adjustments) for display.\n * Returns the totals object to merge into an order API response, or null if order not found.\n */\nexport async function recalculateOrderTotalsForDisplay(\n em: EntityManager,\n container: { resolve: (key: string) => unknown },\n orderId: string,\n scope: { tenantId: string; organizationId: string },\n): Promise<SalesDocumentCalculationResult['totals'] | null> {\n const order = await findOneWithDecryption(\n em,\n SalesOrder,\n { id: orderId, deletedAt: null },\n {},\n scope,\n )\n if (!order) return null\n const [orderLines, adjustments] = await Promise.all([\n findWithDecryption(em, SalesOrderLine, { order: order.id, deletedAt: null }, {}, scope),\n findWithDecryption(\n em,\n SalesOrderAdjustment,\n { order: order.id, deletedAt: null },\n { orderBy: { position: 'asc' } },\n scope,\n ),\n ])\n const lineSnapshots: SalesLineSnapshot[] = orderLines.map(mapOrderLineEntityToSnapshot)\n const adjustmentDrafts: SalesAdjustmentDraft[] = adjustments.map(mapOrderAdjustmentToDraft)\n const salesCalculationService = container.resolve('salesCalculationService') as SalesCalculationService\n const calculation = await salesCalculationService.calculateDocumentTotals({\n documentKind: 'order',\n lines: lineSnapshots,\n adjustments: adjustmentDrafts,\n context: buildCalculationContext(order),\n existingTotals: {\n paidTotalAmount: toNumeric(order.paidTotalAmount),\n refundedTotalAmount: toNumeric(order.refundedTotalAmount),\n },\n })\n return calculation.totals\n}\n\nexport async function loadReturnSnapshot(em: EntityManager, id: string): Promise<ReturnSnapshot | null> {\n const header = await findOneWithDecryption(\n em,\n SalesReturn,\n { id, deletedAt: null },\n { populate: ['order'] },\n {},\n )\n if (!header || !header.order) return null\n const orderId = typeof header.order === 'string' ? header.order : header.order.id\n const lines = await findWithDecryption(\n em,\n SalesReturnLine,\n { salesReturn: header.id, deletedAt: null },\n { populate: ['orderLine'] },\n { tenantId: header.tenantId, organizationId: header.organizationId },\n )\n const adjustmentIds: string[] = []\n const adjustments = await findWithDecryption(\n em,\n SalesOrderAdjustment,\n { order: orderId, kind: 'return', deletedAt: null },\n {},\n { tenantId: header.tenantId, organizationId: header.organizationId },\n )\n adjustments.forEach((adj) => {\n const meta = adj.metadata as Record<string, unknown> | null | undefined\n if (meta && meta.returnId === header.id) adjustmentIds.push(adj.id)\n })\n\n return {\n id: header.id,\n orderId,\n organizationId: header.organizationId,\n tenantId: header.tenantId,\n returnNumber: header.returnNumber,\n returnedAt: header.returnedAt ? header.returnedAt.toISOString() : null,\n reason: header.reason ?? null,\n notes: header.notes ?? null,\n lines: lines.map((line) => ({\n id: line.id,\n orderLineId: typeof line.orderLine === 'string' ? line.orderLine : line.orderLine?.id ?? null,\n quantityReturned: toNumeric(line.quantityReturned),\n unitPriceNet: toNumeric(line.unitPriceNet),\n unitPriceGross: toNumeric(line.unitPriceGross),\n totalNetAmount: toNumeric(line.totalNetAmount),\n totalGrossAmount: toNumeric(line.totalGrossAmount),\n })),\n adjustmentIds,\n }\n}\n\nfunction normalizeLinesInput(lines: ReturnCreateInput['lines']): ReturnLineInput[] {\n const seen = new Set<string>()\n const result: ReturnLineInput[] = []\n for (const line of lines) {\n const orderLineId = line.orderLineId\n if (!orderLineId || seen.has(orderLineId)) continue\n const quantity = toNumeric(line.quantity)\n if (!Number.isFinite(quantity) || quantity <= 0) continue\n seen.add(orderLineId)\n result.push({ orderLineId, quantity })\n }\n return result\n}\n\nconst createReturnCommand: CommandHandler<ReturnCreateInput, { returnId: string }> = {\n id: 'sales.returns.create',\n async execute(rawInput, ctx) {\n const input = returnCreateSchema.parse(rawInput ?? {})\n ensureTenantScope(ctx, input.tenantId)\n ensureOrganizationScope(ctx, input.organizationId)\n\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n\n const order = await findOneWithDecryption(\n em,\n SalesOrder,\n { id: input.orderId, deletedAt: null },\n {},\n { tenantId: input.tenantId, organizationId: input.organizationId },\n )\n if (!order) {\n throw new CrudHttpError(404, { error: translate('sales.returns.orderMissing', 'Order not found.') })\n }\n ensureSameScope(order, input.organizationId, input.tenantId)\n\n const requested = normalizeLinesInput(input.lines)\n if (!requested.length) {\n throw new CrudHttpError(400, { error: translate('sales.returns.linesRequired', 'Select at least one line to return.') })\n }\n\n const orderLines = await findWithDecryption(\n em,\n SalesOrderLine,\n { order: order.id, deletedAt: null },\n {},\n { tenantId: input.tenantId, organizationId: input.organizationId },\n )\n const lineMap = new Map(orderLines.map((line) => [line.id, line]))\n\n requested.forEach(({ orderLineId, quantity }) => {\n const line = lineMap.get(orderLineId)\n if (!line) {\n throw new CrudHttpError(404, { error: translate('sales.returns.lineMissing', 'Order line not found.') })\n }\n const available = toNumeric(line.quantity) - toNumeric(line.returnedQuantity)\n if (quantity - 1e-6 > available) {\n throw new CrudHttpError(400, { error: translate('sales.returns.quantityExceeded', 'Cannot return more than the remaining quantity.') })\n }\n })\n\n const existingAdjustments = await findWithDecryption(\n em,\n SalesOrderAdjustment,\n { order: order.id, deletedAt: null },\n { orderBy: { position: 'asc' } },\n { tenantId: input.tenantId, organizationId: input.organizationId },\n )\n const positionStart = existingAdjustments.reduce((acc, adj) => Math.max(acc, adj.position ?? 0), 0) + 1\n\n const numberGenerator = new SalesDocumentNumberGenerator(em)\n const generated = await numberGenerator.generate({\n kind: 'return',\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n const returnId = randomUUID()\n const header = em.create(SalesReturn, {\n id: returnId,\n order,\n organizationId: input.organizationId,\n tenantId: input.tenantId,\n returnNumber: generated.number,\n reason: input.reason ?? null,\n notes: input.notes ?? null,\n returnedAt: input.returnedAt ?? new Date(),\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(header)\n\n const createdAdjustments: SalesOrderAdjustment[] = []\n const createdLines: SalesReturnLine[] = []\n requested.forEach((lineInput, index) => {\n const line = lineMap.get(lineInput.orderLineId)\n if (!line) return\n const quantity = lineInput.quantity\n const lineQuantity = Math.max(toNumeric(line.quantity), 0)\n const unitNet = lineQuantity > 0 ? toNumeric(line.totalNetAmount) / lineQuantity : toNumeric(line.unitPriceNet)\n const unitGross = lineQuantity > 0 ? toNumeric(line.totalGrossAmount) / lineQuantity : toNumeric(line.unitPriceGross)\n const totalNet = -round(Math.max(unitNet, 0) * quantity)\n const totalGross = -round(Math.max(unitGross, 0) * quantity)\n\n const returnLineId = randomUUID()\n const returnLine = em.create(SalesReturnLine, {\n id: returnLineId,\n salesReturn: header,\n orderLine: em.getReference(SalesOrderLine, line.id),\n organizationId: input.organizationId,\n tenantId: input.tenantId,\n quantityReturned: quantity.toString(),\n unitPriceNet: round(unitNet).toString(),\n unitPriceGross: round(unitGross).toString(),\n totalNetAmount: totalNet.toString(),\n totalGrossAmount: totalGross.toString(),\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n createdLines.push(returnLine)\n em.persist(returnLine)\n\n const adjustment = em.create(SalesOrderAdjustment, {\n id: randomUUID(),\n order,\n orderLine: em.getReference(SalesOrderLine, line.id),\n organizationId: input.organizationId,\n tenantId: input.tenantId,\n scope: 'line',\n kind: 'return',\n rate: '0',\n amountNet: totalNet.toString(),\n amountGross: totalGross.toString(),\n currencyCode: order.currencyCode,\n metadata: { returnId, returnLineId },\n position: positionStart + index,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n createdAdjustments.push(adjustment)\n em.persist(adjustment)\n\n line.returnedQuantity = (toNumeric(line.returnedQuantity) + quantity).toString()\n line.updatedAt = new Date()\n em.persist(line)\n })\n\n const salesCalculationService = ctx.container.resolve<SalesCalculationService>('salesCalculationService')\n const lineSnapshots: SalesLineSnapshot[] = orderLines.map(mapOrderLineEntityToSnapshot)\n const adjustmentDrafts: SalesAdjustmentDraft[] = [...existingAdjustments, ...createdAdjustments].map(mapOrderAdjustmentToDraft)\n const calculation = await salesCalculationService.calculateDocumentTotals({\n documentKind: 'order',\n lines: lineSnapshots,\n adjustments: adjustmentDrafts,\n context: buildCalculationContext(order),\n })\n applyOrderTotals(order, calculation.totals, calculation.lines.length)\n order.updatedAt = new Date()\n em.persist(order)\n\n await em.flush()\n\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine,\n action: 'created',\n entity: header,\n identifiers: { id: header.id, organizationId: header.organizationId, tenantId: header.tenantId },\n indexer: { entityType: E.sales.sales_return },\n events: returnCrudEvents,\n })\n\n if (createdLines.length) {\n await Promise.all(\n createdLines.map((line) =>\n emitCrudSideEffects({\n dataEngine,\n action: 'created',\n entity: line,\n identifiers: { id: line.id, organizationId: line.organizationId, tenantId: line.tenantId },\n indexer: { entityType: E.sales.sales_return_line },\n }),\n ),\n )\n }\n\n return { returnId }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadReturnSnapshot(em, result.returnId)\n },\n buildLog: async ({ result, snapshots }) => {\n const after = snapshots.after as ReturnSnapshot | undefined\n if (!after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('sales.audit.returns.create', 'Create return'),\n resourceKind: 'sales.return',\n resourceId: result.returnId,\n parentResourceKind: 'sales.order',\n parentResourceId: after.orderId ?? null,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n snapshotAfter: after,\n payload: {\n undo: { after } satisfies ReturnUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<ReturnUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const order = await findOneWithDecryption(\n em,\n SalesOrder,\n { id: after.orderId, deletedAt: null },\n {},\n { tenantId: after.tenantId, organizationId: after.organizationId },\n )\n if (!order) return\n\n const lines = await findWithDecryption(\n em,\n SalesOrderLine,\n { order: order.id, deletedAt: null },\n {},\n { tenantId: after.tenantId, organizationId: after.organizationId },\n )\n const lineMap = new Map(lines.map((line) => [line.id, line]))\n after.lines.forEach((entry) => {\n const line = lineMap.get(entry.orderLineId)\n if (!line) return\n const next = Math.max(0, toNumeric(line.returnedQuantity) - entry.quantityReturned)\n line.returnedQuantity = next.toString()\n line.updatedAt = new Date()\n em.persist(line)\n })\n\n if (after.adjustmentIds.length) {\n const adjustments = await findWithDecryption(\n em,\n SalesOrderAdjustment,\n { id: { $in: after.adjustmentIds }, deletedAt: null },\n {},\n { tenantId: after.tenantId, organizationId: after.organizationId },\n )\n adjustments.forEach((adj) => em.remove(adj))\n }\n\n const header = await findOneWithDecryption(\n em,\n SalesReturn,\n { id: after.id, deletedAt: null },\n {},\n { tenantId: after.tenantId, organizationId: after.organizationId },\n )\n const returnLines = await findWithDecryption(\n em,\n SalesReturnLine,\n { salesReturn: after.id, deletedAt: null },\n {},\n { tenantId: after.tenantId, organizationId: after.organizationId },\n )\n returnLines.forEach((line) => em.remove(line))\n if (header) em.remove(header)\n\n const existingAdjustments = await findWithDecryption(\n em,\n SalesOrderAdjustment,\n { order: order.id, deletedAt: null },\n { orderBy: { position: 'asc' } },\n { tenantId: after.tenantId, organizationId: after.organizationId },\n )\n const salesCalculationService = ctx.container.resolve<SalesCalculationService>('salesCalculationService')\n const lineSnapshots: SalesLineSnapshot[] = lines.map(mapOrderLineEntityToSnapshot)\n const adjustmentDrafts: SalesAdjustmentDraft[] = existingAdjustments.map(mapOrderAdjustmentToDraft)\n const calculation = await salesCalculationService.calculateDocumentTotals({\n documentKind: 'order',\n lines: lineSnapshots,\n adjustments: adjustmentDrafts,\n context: buildCalculationContext(order),\n })\n applyOrderTotals(order, calculation.totals, calculation.lines.length)\n order.updatedAt = new Date()\n em.persist(order)\n\n await em.flush()\n },\n}\n\nregisterCommand(createReturnCommand)\n\nexport const returnCommands = [createReturnCommand]\n\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|