@open-mercato/core 0.4.5-develop-3ce83a8b24 → 0.4.5-develop-539cff4960

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 (184) hide show
  1. package/dist/generated/entities/catalog_product/index.js +16 -0
  2. package/dist/generated/entities/catalog_product/index.js.map +2 -2
  3. package/dist/generated/entities/catalog_product_unit_conversion/index.js +27 -0
  4. package/dist/generated/entities/catalog_product_unit_conversion/index.js.map +7 -0
  5. package/dist/generated/entities/sales_credit_memo_line/index.js +7 -1
  6. package/dist/generated/entities/sales_credit_memo_line/index.js.map +2 -2
  7. package/dist/generated/entities/sales_invoice_line/index.js +7 -1
  8. package/dist/generated/entities/sales_invoice_line/index.js.map +2 -2
  9. package/dist/generated/entities/sales_order_line/index.js +6 -0
  10. package/dist/generated/entities/sales_order_line/index.js.map +2 -2
  11. package/dist/generated/entities/sales_quote_line/index.js +6 -0
  12. package/dist/generated/entities/sales_quote_line/index.js.map +2 -2
  13. package/dist/generated/entities.ids.generated.js +1 -0
  14. package/dist/generated/entities.ids.generated.js.map +2 -2
  15. package/dist/generated/entity-fields-registry.js +2 -0
  16. package/dist/generated/entity-fields-registry.js.map +2 -2
  17. package/dist/modules/catalog/api/prices/route.js +123 -8
  18. package/dist/modules/catalog/api/prices/route.js.map +2 -2
  19. package/dist/modules/catalog/api/product-unit-conversions/route.js +194 -0
  20. package/dist/modules/catalog/api/product-unit-conversions/route.js.map +7 -0
  21. package/dist/modules/catalog/api/products/route.js +351 -201
  22. package/dist/modules/catalog/api/products/route.js.map +2 -2
  23. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +1267 -497
  24. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  25. package/dist/modules/catalog/backend/catalog/products/create/page.js +733 -210
  26. package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
  27. package/dist/modules/catalog/commands/index.js +1 -0
  28. package/dist/modules/catalog/commands/index.js.map +2 -2
  29. package/dist/modules/catalog/commands/productUnitConversions.js +503 -0
  30. package/dist/modules/catalog/commands/productUnitConversions.js.map +7 -0
  31. package/dist/modules/catalog/commands/products.js +355 -73
  32. package/dist/modules/catalog/commands/products.js.map +2 -2
  33. package/dist/modules/catalog/commands/shared.js +18 -4
  34. package/dist/modules/catalog/commands/shared.js.map +2 -2
  35. package/dist/modules/catalog/components/products/ProductUomSection.js +591 -0
  36. package/dist/modules/catalog/components/products/ProductUomSection.js.map +7 -0
  37. package/dist/modules/catalog/components/products/productForm.js +66 -5
  38. package/dist/modules/catalog/components/products/productForm.js.map +2 -2
  39. package/dist/modules/catalog/components/products/productFormUtils.js +68 -0
  40. package/dist/modules/catalog/components/products/productFormUtils.js.map +7 -0
  41. package/dist/modules/catalog/data/entities.js +86 -0
  42. package/dist/modules/catalog/data/entities.js.map +2 -2
  43. package/dist/modules/catalog/data/validators.js +65 -3
  44. package/dist/modules/catalog/data/validators.js.map +2 -2
  45. package/dist/modules/catalog/events.js +3 -0
  46. package/dist/modules/catalog/events.js.map +2 -2
  47. package/dist/modules/catalog/lib/unitCodes.js +7 -0
  48. package/dist/modules/catalog/lib/unitCodes.js.map +7 -0
  49. package/dist/modules/catalog/lib/unitResolution.js +53 -0
  50. package/dist/modules/catalog/lib/unitResolution.js.map +7 -0
  51. package/dist/modules/catalog/migrations/Migration20260218225422.js +19 -0
  52. package/dist/modules/catalog/migrations/Migration20260218225422.js.map +7 -0
  53. package/dist/modules/catalog/migrations/Migration20260219084500.js +27 -0
  54. package/dist/modules/catalog/migrations/Migration20260219084500.js.map +7 -0
  55. package/dist/modules/catalog/search.js +69 -1
  56. package/dist/modules/catalog/search.js.map +2 -2
  57. package/dist/modules/catalog/seed/examples.js +91 -42
  58. package/dist/modules/catalog/seed/examples.js.map +2 -2
  59. package/dist/modules/dashboards/seed/analytics.js +3 -0
  60. package/dist/modules/dashboards/seed/analytics.js.map +2 -2
  61. package/dist/modules/sales/api/order-lines/route.js +98 -15
  62. package/dist/modules/sales/api/order-lines/route.js.map +2 -2
  63. package/dist/modules/sales/api/quote-lines/route.js +101 -14
  64. package/dist/modules/sales/api/quote-lines/route.js.map +2 -2
  65. package/dist/modules/sales/api/quotes/public/[token]/route.js +87 -12
  66. package/dist/modules/sales/api/quotes/public/[token]/route.js.map +2 -2
  67. package/dist/modules/sales/commands/documents.js +1424 -260
  68. package/dist/modules/sales/commands/documents.js.map +3 -3
  69. package/dist/modules/sales/commands/shared.js +6 -2
  70. package/dist/modules/sales/commands/shared.js.map +2 -2
  71. package/dist/modules/sales/components/documents/ItemsSection.js +216 -86
  72. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  73. package/dist/modules/sales/components/documents/LineItemDialog.js +913 -241
  74. package/dist/modules/sales/components/documents/LineItemDialog.js.map +3 -3
  75. package/dist/modules/sales/components/documents/ShipmentsSection.js +15 -3
  76. package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
  77. package/dist/modules/sales/data/entities.js +59 -3
  78. package/dist/modules/sales/data/entities.js.map +2 -2
  79. package/dist/modules/sales/data/validators.js +35 -0
  80. package/dist/modules/sales/data/validators.js.map +2 -2
  81. package/dist/modules/sales/frontend/quote/[token]/page.js +15 -1
  82. package/dist/modules/sales/frontend/quote/[token]/page.js.map +2 -2
  83. package/dist/modules/sales/migrations/Migration20260218225423.js +31 -0
  84. package/dist/modules/sales/migrations/Migration20260218225423.js.map +7 -0
  85. package/dist/modules/sales/migrations/Migration20260219084501.js +71 -0
  86. package/dist/modules/sales/migrations/Migration20260219084501.js.map +7 -0
  87. package/dist/modules/sales/search.js +28 -0
  88. package/dist/modules/sales/search.js.map +2 -2
  89. package/dist/modules/sales/seed/examples.js +14 -1
  90. package/dist/modules/sales/seed/examples.js.map +2 -2
  91. package/dist/modules/sales/widgets/injection/document-history/widget.client.js +1 -1
  92. package/dist/modules/sales/widgets/injection/document-history/widget.client.js.map +2 -2
  93. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +28 -15
  94. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  95. package/dist/modules/staff/translations.js +9 -0
  96. package/dist/modules/staff/translations.js.map +7 -0
  97. package/dist/modules/translations/components/TranslationDrawerAction.js +97 -0
  98. package/dist/modules/translations/components/TranslationDrawerAction.js.map +7 -0
  99. package/dist/modules/translations/lib/extract-record-id.js +31 -2
  100. package/dist/modules/translations/lib/extract-record-id.js.map +2 -2
  101. package/dist/modules/translations/lib/resolve-field-list.js +3 -0
  102. package/dist/modules/translations/lib/resolve-field-list.js.map +2 -2
  103. package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js +105 -36
  104. package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js.map +2 -2
  105. package/dist/modules/translations/widgets/injection-table.js +18 -29
  106. package/dist/modules/translations/widgets/injection-table.js.map +2 -2
  107. package/generated/entities/catalog_product/index.ts +8 -0
  108. package/generated/entities/catalog_product_unit_conversion/index.ts +12 -0
  109. package/generated/entities/sales_credit_memo_line/index.ts +3 -0
  110. package/generated/entities/sales_invoice_line/index.ts +3 -0
  111. package/generated/entities/sales_order_line/index.ts +3 -0
  112. package/generated/entities/sales_quote_line/index.ts +3 -0
  113. package/generated/entities.ids.generated.ts +1 -0
  114. package/generated/entity-fields-registry.ts +2 -0
  115. package/package.json +2 -2
  116. package/src/modules/auth/i18n/de.json +1 -1
  117. package/src/modules/auth/i18n/en.json +1 -1
  118. package/src/modules/auth/i18n/es.json +1 -1
  119. package/src/modules/auth/i18n/pl.json +1 -1
  120. package/src/modules/catalog/api/prices/route.ts +213 -81
  121. package/src/modules/catalog/api/product-unit-conversions/route.ts +195 -0
  122. package/src/modules/catalog/api/products/route.ts +638 -402
  123. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +2085 -1072
  124. package/src/modules/catalog/backend/catalog/products/create/page.tsx +1288 -593
  125. package/src/modules/catalog/commands/index.ts +1 -0
  126. package/src/modules/catalog/commands/productUnitConversions.ts +626 -0
  127. package/src/modules/catalog/commands/products.ts +1151 -693
  128. package/src/modules/catalog/commands/shared.ts +19 -5
  129. package/src/modules/catalog/components/products/ProductUomSection.tsx +745 -0
  130. package/src/modules/catalog/components/products/productForm.ts +369 -256
  131. package/src/modules/catalog/components/products/productFormUtils.ts +82 -0
  132. package/src/modules/catalog/data/entities.ts +82 -1
  133. package/src/modules/catalog/data/validators.ts +118 -34
  134. package/src/modules/catalog/events.ts +3 -0
  135. package/src/modules/catalog/i18n/de.json +56 -0
  136. package/src/modules/catalog/i18n/en.json +56 -0
  137. package/src/modules/catalog/i18n/es.json +56 -0
  138. package/src/modules/catalog/i18n/pl.json +56 -0
  139. package/src/modules/catalog/lib/unitCodes.ts +1 -0
  140. package/src/modules/catalog/lib/unitResolution.ts +62 -0
  141. package/src/modules/catalog/migrations/.snapshot-open-mercato.json +245 -0
  142. package/src/modules/catalog/migrations/Migration20260218225422.ts +21 -0
  143. package/src/modules/catalog/migrations/Migration20260219084500.ts +26 -0
  144. package/src/modules/catalog/search.ts +73 -1
  145. package/src/modules/catalog/seed/examples.ts +552 -479
  146. package/src/modules/dashboards/i18n/de.json +1 -1
  147. package/src/modules/dashboards/i18n/en.json +1 -1
  148. package/src/modules/dashboards/i18n/es.json +1 -1
  149. package/src/modules/dashboards/i18n/pl.json +1 -1
  150. package/src/modules/dashboards/seed/analytics.ts +3 -0
  151. package/src/modules/sales/api/order-lines/route.ts +158 -68
  152. package/src/modules/sales/api/quote-lines/route.ts +161 -67
  153. package/src/modules/sales/api/quotes/public/[token]/route.ts +122 -36
  154. package/src/modules/sales/commands/documents.ts +4250 -2424
  155. package/src/modules/sales/commands/shared.ts +7 -2
  156. package/src/modules/sales/components/documents/ItemsSection.tsx +580 -310
  157. package/src/modules/sales/components/documents/LineItemDialog.tsx +1988 -833
  158. package/src/modules/sales/components/documents/ShipmentsSection.tsx +17 -3
  159. package/src/modules/sales/components/documents/lineItemTypes.ts +6 -0
  160. package/src/modules/sales/data/entities.ts +53 -0
  161. package/src/modules/sales/data/validators.ts +36 -0
  162. package/src/modules/sales/frontend/quote/[token]/page.tsx +25 -1
  163. package/src/modules/sales/i18n/de.json +23 -3
  164. package/src/modules/sales/i18n/en.json +23 -3
  165. package/src/modules/sales/i18n/es.json +23 -3
  166. package/src/modules/sales/i18n/pl.json +23 -3
  167. package/src/modules/sales/lib/types.ts +30 -0
  168. package/src/modules/sales/migrations/.snapshot-open-mercato.json +172 -0
  169. package/src/modules/sales/migrations/Migration20260218225423.ts +37 -0
  170. package/src/modules/sales/migrations/Migration20260219084501.ts +73 -0
  171. package/src/modules/sales/search.ts +28 -0
  172. package/src/modules/sales/seed/examples.ts +20 -1
  173. package/src/modules/sales/widgets/injection/document-history/widget.client.tsx +1 -1
  174. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +8 -0
  175. package/src/modules/staff/translations.ts +5 -0
  176. package/src/modules/translations/components/TranslationDrawerAction.tsx +107 -0
  177. package/src/modules/translations/lib/extract-record-id.ts +47 -3
  178. package/src/modules/translations/lib/resolve-field-list.ts +4 -0
  179. package/src/modules/translations/widgets/injection/translation-manager/widget.client.tsx +108 -36
  180. package/src/modules/translations/widgets/injection-table.ts +19 -33
  181. package/src/modules/workflows/i18n/de.json +4 -4
  182. package/src/modules/workflows/i18n/en.json +4 -4
  183. package/src/modules/workflows/i18n/es.json +4 -4
  184. package/src/modules/workflows/i18n/pl.json +4 -4
@@ -0,0 +1,503 @@
1
+ import { registerCommand } from "@open-mercato/shared/lib/commands";
2
+ import {
3
+ buildChanges,
4
+ requireId,
5
+ emitCrudSideEffects,
6
+ emitCrudUndoSideEffects
7
+ } from "@open-mercato/shared/lib/commands/helpers";
8
+ import { UniqueConstraintViolationException } from "@mikro-orm/core";
9
+ import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
10
+ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
11
+ import { E } from "../../../generated/entities.ids.generated.js";
12
+ import {
13
+ findOneWithDecryption
14
+ } from "@open-mercato/shared/lib/encryption/find";
15
+ import { CatalogProduct, CatalogProductUnitConversion } from "../data/entities.js";
16
+ import {
17
+ productUnitConversionCreateSchema,
18
+ productUnitConversionUpdateSchema,
19
+ productUnitConversionDeleteSchema
20
+ } from "../data/validators.js";
21
+ import {
22
+ ensureOrganizationScope,
23
+ ensureSameScope,
24
+ cloneJson,
25
+ ensureTenantScope,
26
+ extractUndoPayload,
27
+ requireProduct,
28
+ toNumericString,
29
+ getErrorConstraint,
30
+ getErrorMessage
31
+ } from "./shared.js";
32
+ import { toUnitLookupKey } from "../lib/unitCodes.js";
33
+ import { resolveCanonicalUnitCode } from "../lib/unitResolution.js";
34
+ const conversionCrudEvents = {
35
+ module: "catalog",
36
+ entity: "product_unit_conversion",
37
+ persistent: true,
38
+ buildPayload: (ctx) => ({
39
+ id: ctx.identifiers.id,
40
+ productId: ctx.entity.product && typeof ctx.entity.product !== "string" ? ctx.entity.product.id : null,
41
+ unitCode: ctx.entity.unitCode,
42
+ tenantId: ctx.identifiers.tenantId,
43
+ organizationId: ctx.identifiers.organizationId
44
+ })
45
+ };
46
+ const conversionCrudIndexer = {
47
+ entityType: E.catalog.catalog_product_unit_conversion,
48
+ buildUpsertPayload: (ctx) => ({
49
+ entityType: E.catalog.catalog_product_unit_conversion,
50
+ recordId: ctx.identifiers.id,
51
+ tenantId: ctx.identifiers.tenantId,
52
+ organizationId: ctx.identifiers.organizationId
53
+ }),
54
+ buildDeletePayload: (ctx) => ({
55
+ entityType: E.catalog.catalog_product_unit_conversion,
56
+ recordId: ctx.identifiers.id,
57
+ tenantId: ctx.identifiers.tenantId,
58
+ organizationId: ctx.identifiers.organizationId
59
+ })
60
+ };
61
+ function buildIdentifiers(record) {
62
+ return {
63
+ id: record.id,
64
+ organizationId: record.organizationId,
65
+ tenantId: record.tenantId
66
+ };
67
+ }
68
+ async function emitConversionCrudChange(opts) {
69
+ const { dataEngine, action, conversion } = opts;
70
+ await emitCrudSideEffects({
71
+ dataEngine,
72
+ action,
73
+ entity: conversion,
74
+ identifiers: buildIdentifiers(conversion),
75
+ events: conversionCrudEvents,
76
+ indexer: conversionCrudIndexer
77
+ });
78
+ }
79
+ async function emitConversionCrudUndoChange(opts) {
80
+ const { dataEngine, action, conversion } = opts;
81
+ await emitCrudUndoSideEffects({
82
+ dataEngine,
83
+ action,
84
+ entity: conversion,
85
+ identifiers: buildIdentifiers(conversion),
86
+ events: conversionCrudEvents,
87
+ indexer: conversionCrudIndexer
88
+ });
89
+ }
90
+ async function loadConversionSnapshot(em, id) {
91
+ const record = await findOneWithDecryption(
92
+ em,
93
+ CatalogProductUnitConversion,
94
+ { id, deletedAt: null },
95
+ { populate: ["product"] }
96
+ );
97
+ if (!record) return null;
98
+ const productId = typeof record.product === "string" ? record.product : record.product?.id ?? null;
99
+ if (!productId) return null;
100
+ return {
101
+ id: record.id,
102
+ productId,
103
+ organizationId: record.organizationId,
104
+ tenantId: record.tenantId,
105
+ unitCode: record.unitCode,
106
+ toBaseFactor: record.toBaseFactor,
107
+ sortOrder: record.sortOrder,
108
+ isActive: record.isActive,
109
+ metadata: record.metadata ? cloneJson(record.metadata) : null,
110
+ createdAt: record.createdAt.toISOString(),
111
+ updatedAt: record.updatedAt.toISOString()
112
+ };
113
+ }
114
+ function applyConversionSnapshot(em, record, snapshot) {
115
+ record.organizationId = snapshot.organizationId;
116
+ record.tenantId = snapshot.tenantId;
117
+ record.product = em.getReference(CatalogProduct, snapshot.productId);
118
+ record.unitCode = snapshot.unitCode;
119
+ record.toBaseFactor = snapshot.toBaseFactor;
120
+ record.sortOrder = snapshot.sortOrder;
121
+ record.isActive = snapshot.isActive;
122
+ record.metadata = snapshot.metadata ? cloneJson(snapshot.metadata) : null;
123
+ record.createdAt = new Date(snapshot.createdAt);
124
+ record.updatedAt = new Date(snapshot.updatedAt);
125
+ }
126
+ async function ensureDefaultSalesUnitIsNotRemoved(em, record, nextIsActive) {
127
+ if (nextIsActive) return;
128
+ const product = typeof record.product === "string" ? await findOneWithDecryption(em, CatalogProduct, {
129
+ id: record.product,
130
+ deletedAt: null
131
+ }) : record.product;
132
+ if (!product) return;
133
+ const defaultSalesUnitKey = toUnitLookupKey(product.defaultSalesUnit);
134
+ const conversionUnitKey = toUnitLookupKey(record.unitCode);
135
+ if (defaultSalesUnitKey && conversionUnitKey && defaultSalesUnitKey === conversionUnitKey) {
136
+ throw new CrudHttpError(409, {
137
+ error: "uom.default_sales_unit_conversion_required"
138
+ });
139
+ }
140
+ }
141
+ function resolveConversionUniqueConstraint(error) {
142
+ if (error instanceof UniqueConstraintViolationException) {
143
+ const constraint = getErrorConstraint(error);
144
+ if (constraint === "catalog_product_unit_conversions_unique") return true;
145
+ const message = getErrorMessage(error);
146
+ return message.toLowerCase().includes("catalog_product_unit_conversions_unique");
147
+ }
148
+ return false;
149
+ }
150
+ function rethrowConversionUniqueConstraint(error) {
151
+ if (resolveConversionUniqueConstraint(error)) {
152
+ throw new CrudHttpError(409, { error: "uom.duplicate_conversion" });
153
+ }
154
+ throw error;
155
+ }
156
+ const createProductUnitConversionCommand = {
157
+ id: "catalog.product-unit-conversions.create",
158
+ async execute(rawInput, ctx) {
159
+ const parsed = productUnitConversionCreateSchema.parse(rawInput);
160
+ ensureTenantScope(ctx, parsed.tenantId);
161
+ ensureOrganizationScope(ctx, parsed.organizationId);
162
+ const em = ctx.container.resolve("em").fork();
163
+ const { translate } = await resolveTranslations();
164
+ const product = await requireProduct(
165
+ em,
166
+ parsed.productId,
167
+ translate("catalog.errors.productNotFound", "Catalog product not found")
168
+ );
169
+ ensureSameScope(product, parsed.organizationId, parsed.tenantId);
170
+ const canonicalUnitCode = await resolveCanonicalUnitCode(em, {
171
+ organizationId: parsed.organizationId,
172
+ tenantId: parsed.tenantId,
173
+ unitCode: parsed.unitCode
174
+ });
175
+ const toBaseFactorStr = toNumericString(parsed.toBaseFactor);
176
+ if (!toBaseFactorStr) {
177
+ throw new CrudHttpError(400, {
178
+ error: "uom.conversion_factor_required"
179
+ });
180
+ }
181
+ const conversion = em.create(CatalogProductUnitConversion, {
182
+ product,
183
+ organizationId: parsed.organizationId,
184
+ tenantId: parsed.tenantId,
185
+ unitCode: canonicalUnitCode,
186
+ toBaseFactor: toBaseFactorStr,
187
+ sortOrder: parsed.sortOrder ?? 0,
188
+ isActive: parsed.isActive !== false,
189
+ metadata: parsed.metadata ? cloneJson(parsed.metadata) : null,
190
+ createdAt: /* @__PURE__ */ new Date(),
191
+ updatedAt: /* @__PURE__ */ new Date()
192
+ });
193
+ em.persist(conversion);
194
+ try {
195
+ await em.flush();
196
+ } catch (error) {
197
+ rethrowConversionUniqueConstraint(error);
198
+ }
199
+ const dataEngine = ctx.container.resolve("dataEngine");
200
+ await emitConversionCrudChange({
201
+ dataEngine,
202
+ action: "created",
203
+ conversion
204
+ });
205
+ return { conversionId: conversion.id };
206
+ },
207
+ captureAfter: async (_input, result, ctx) => {
208
+ const em = ctx.container.resolve("em").fork();
209
+ return loadConversionSnapshot(em, result.conversionId);
210
+ },
211
+ buildLog: async ({ snapshots }) => {
212
+ const after = snapshots.after;
213
+ if (!after) return null;
214
+ const { translate } = await resolveTranslations();
215
+ return {
216
+ actionLabel: translate(
217
+ "catalog.audit.productUnitConversions.create",
218
+ "Create product unit conversion"
219
+ ),
220
+ resourceKind: "catalog.product_unit_conversion",
221
+ resourceId: after.id,
222
+ tenantId: after.tenantId,
223
+ organizationId: after.organizationId,
224
+ snapshotAfter: after,
225
+ payload: {
226
+ undo: {
227
+ after
228
+ }
229
+ }
230
+ };
231
+ },
232
+ undo: async ({ logEntry, ctx }) => {
233
+ const payload = extractUndoPayload(logEntry);
234
+ const after = payload?.after;
235
+ if (!after) return;
236
+ const em = ctx.container.resolve("em").fork();
237
+ const record = await findOneWithDecryption(
238
+ em,
239
+ CatalogProductUnitConversion,
240
+ { id: after.id, deletedAt: null }
241
+ );
242
+ if (!record) return;
243
+ ensureTenantScope(ctx, record.tenantId);
244
+ ensureOrganizationScope(ctx, record.organizationId);
245
+ em.remove(record);
246
+ await em.flush();
247
+ const dataEngine = ctx.container.resolve("dataEngine");
248
+ await emitConversionCrudUndoChange({
249
+ dataEngine,
250
+ action: "deleted",
251
+ conversion: record
252
+ });
253
+ }
254
+ };
255
+ const updateProductUnitConversionCommand = {
256
+ id: "catalog.product-unit-conversions.update",
257
+ async prepare(input, ctx) {
258
+ const id = requireId(input, "Product unit conversion id is required");
259
+ const em = ctx.container.resolve("em");
260
+ const snapshot = await loadConversionSnapshot(em, id);
261
+ if (snapshot) {
262
+ ensureTenantScope(ctx, snapshot.tenantId);
263
+ ensureOrganizationScope(ctx, snapshot.organizationId);
264
+ }
265
+ return snapshot ? { before: snapshot } : {};
266
+ },
267
+ async execute(rawInput, ctx) {
268
+ const parsed = productUnitConversionUpdateSchema.parse(rawInput);
269
+ const em = ctx.container.resolve("em").fork();
270
+ const { translate } = await resolveTranslations();
271
+ const record = await findOneWithDecryption(
272
+ em,
273
+ CatalogProductUnitConversion,
274
+ { id: parsed.id, deletedAt: null },
275
+ { populate: ["product"] }
276
+ );
277
+ if (!record)
278
+ throw new CrudHttpError(404, {
279
+ error: translate("catalog.errors.conversionNotFound", "Catalog product unit conversion not found")
280
+ });
281
+ const product = typeof record.product === "string" ? await requireProduct(em, record.product, translate("catalog.errors.productNotFound", "Catalog product not found")) : record.product;
282
+ ensureTenantScope(ctx, record.tenantId);
283
+ ensureOrganizationScope(ctx, record.organizationId);
284
+ ensureSameScope(product, record.organizationId, record.tenantId);
285
+ const resolvedUnitCode = parsed.unitCode !== void 0 ? await resolveCanonicalUnitCode(em, {
286
+ organizationId: record.organizationId,
287
+ tenantId: record.tenantId,
288
+ unitCode: parsed.unitCode
289
+ }) : void 0;
290
+ if (parsed.isActive !== void 0) {
291
+ await ensureDefaultSalesUnitIsNotRemoved(em, record, parsed.isActive);
292
+ }
293
+ if (resolvedUnitCode !== void 0) {
294
+ record.unitCode = resolvedUnitCode;
295
+ }
296
+ if (parsed.toBaseFactor !== void 0) {
297
+ record.toBaseFactor = toNumericString(parsed.toBaseFactor) ?? record.toBaseFactor;
298
+ }
299
+ if (parsed.sortOrder !== void 0) {
300
+ record.sortOrder = parsed.sortOrder;
301
+ }
302
+ if (parsed.isActive !== void 0) {
303
+ record.isActive = parsed.isActive;
304
+ }
305
+ if (parsed.metadata !== void 0) {
306
+ record.metadata = parsed.metadata ? cloneJson(parsed.metadata) : null;
307
+ }
308
+ try {
309
+ await em.flush();
310
+ } catch (error) {
311
+ rethrowConversionUniqueConstraint(error);
312
+ }
313
+ const dataEngine = ctx.container.resolve("dataEngine");
314
+ await emitConversionCrudChange({
315
+ dataEngine,
316
+ action: "updated",
317
+ conversion: record
318
+ });
319
+ return { conversionId: record.id };
320
+ },
321
+ captureAfter: async (_input, result, ctx) => {
322
+ const em = ctx.container.resolve("em").fork();
323
+ return loadConversionSnapshot(em, result.conversionId);
324
+ },
325
+ buildLog: async ({ snapshots }) => {
326
+ const before = snapshots.before;
327
+ const after = snapshots.after;
328
+ if (!before || !after) return null;
329
+ const { translate } = await resolveTranslations();
330
+ return {
331
+ actionLabel: translate(
332
+ "catalog.audit.productUnitConversions.update",
333
+ "Update product unit conversion"
334
+ ),
335
+ resourceKind: "catalog.product_unit_conversion",
336
+ resourceId: before.id,
337
+ tenantId: before.tenantId,
338
+ organizationId: before.organizationId,
339
+ changes: buildChanges(before, after, [
340
+ "unitCode",
341
+ "toBaseFactor",
342
+ "sortOrder",
343
+ "isActive",
344
+ "metadata"
345
+ ]),
346
+ snapshotBefore: before,
347
+ snapshotAfter: after,
348
+ payload: {
349
+ undo: {
350
+ before,
351
+ after
352
+ }
353
+ }
354
+ };
355
+ },
356
+ undo: async ({ logEntry, ctx }) => {
357
+ const payload = extractUndoPayload(logEntry);
358
+ const before = payload?.before;
359
+ if (!before) return;
360
+ const em = ctx.container.resolve("em").fork();
361
+ let record = await findOneWithDecryption(
362
+ em,
363
+ CatalogProductUnitConversion,
364
+ { id: before.id, deletedAt: null }
365
+ );
366
+ let undoAction = "updated";
367
+ if (!record) {
368
+ record = em.create(CatalogProductUnitConversion, {
369
+ id: before.id,
370
+ organizationId: before.organizationId,
371
+ tenantId: before.tenantId,
372
+ product: em.getReference(CatalogProduct, before.productId),
373
+ unitCode: before.unitCode,
374
+ toBaseFactor: before.toBaseFactor,
375
+ sortOrder: before.sortOrder,
376
+ isActive: before.isActive,
377
+ metadata: before.metadata ? cloneJson(before.metadata) : null,
378
+ createdAt: new Date(before.createdAt),
379
+ updatedAt: new Date(before.updatedAt)
380
+ });
381
+ em.persist(record);
382
+ undoAction = "created";
383
+ }
384
+ ensureTenantScope(ctx, before.tenantId);
385
+ ensureOrganizationScope(ctx, before.organizationId);
386
+ applyConversionSnapshot(em, record, before);
387
+ await em.transactional(async () => {
388
+ await em.flush();
389
+ });
390
+ const dataEngine = ctx.container.resolve("dataEngine");
391
+ await emitConversionCrudUndoChange({
392
+ dataEngine,
393
+ action: undoAction,
394
+ conversion: record
395
+ });
396
+ }
397
+ };
398
+ const deleteProductUnitConversionCommand = {
399
+ id: "catalog.product-unit-conversions.delete",
400
+ async prepare(input, ctx) {
401
+ const id = requireId(input, "Product unit conversion id is required");
402
+ const em = ctx.container.resolve("em");
403
+ const snapshot = await loadConversionSnapshot(em, id);
404
+ if (snapshot) {
405
+ ensureTenantScope(ctx, snapshot.tenantId);
406
+ ensureOrganizationScope(ctx, snapshot.organizationId);
407
+ }
408
+ return snapshot ? { before: snapshot } : {};
409
+ },
410
+ async execute(rawInput, ctx) {
411
+ const parsed = productUnitConversionDeleteSchema.parse(rawInput);
412
+ const em = ctx.container.resolve("em").fork();
413
+ const { translate } = await resolveTranslations();
414
+ const record = await findOneWithDecryption(
415
+ em,
416
+ CatalogProductUnitConversion,
417
+ { id: parsed.id, deletedAt: null },
418
+ { populate: ["product"] }
419
+ );
420
+ if (!record)
421
+ throw new CrudHttpError(404, {
422
+ error: translate("catalog.errors.conversionNotFound", "Catalog product unit conversion not found")
423
+ });
424
+ ensureTenantScope(ctx, record.tenantId);
425
+ ensureOrganizationScope(ctx, record.organizationId);
426
+ await ensureDefaultSalesUnitIsNotRemoved(em, record, false);
427
+ em.remove(record);
428
+ await em.transactional(async () => {
429
+ await em.flush();
430
+ });
431
+ const dataEngine = ctx.container.resolve("dataEngine");
432
+ await emitConversionCrudChange({
433
+ dataEngine,
434
+ action: "deleted",
435
+ conversion: record
436
+ });
437
+ return { conversionId: parsed.id };
438
+ },
439
+ buildLog: async ({ snapshots }) => {
440
+ const before = snapshots.before;
441
+ if (!before) return null;
442
+ const { translate } = await resolveTranslations();
443
+ return {
444
+ actionLabel: translate(
445
+ "catalog.audit.productUnitConversions.delete",
446
+ "Delete product unit conversion"
447
+ ),
448
+ resourceKind: "catalog.product_unit_conversion",
449
+ resourceId: before.id,
450
+ tenantId: before.tenantId,
451
+ organizationId: before.organizationId,
452
+ snapshotBefore: before,
453
+ payload: {
454
+ undo: {
455
+ before
456
+ }
457
+ }
458
+ };
459
+ },
460
+ undo: async ({ logEntry, ctx }) => {
461
+ const payload = extractUndoPayload(logEntry);
462
+ const before = payload?.before;
463
+ if (!before) return;
464
+ const em = ctx.container.resolve("em").fork();
465
+ let record = await findOneWithDecryption(
466
+ em,
467
+ CatalogProductUnitConversion,
468
+ { id: before.id, deletedAt: null }
469
+ );
470
+ if (!record) {
471
+ record = em.create(CatalogProductUnitConversion, {
472
+ id: before.id,
473
+ organizationId: before.organizationId,
474
+ tenantId: before.tenantId,
475
+ product: em.getReference(CatalogProduct, before.productId),
476
+ unitCode: before.unitCode,
477
+ toBaseFactor: before.toBaseFactor,
478
+ sortOrder: before.sortOrder,
479
+ isActive: before.isActive,
480
+ metadata: before.metadata ? cloneJson(before.metadata) : null,
481
+ createdAt: new Date(before.createdAt),
482
+ updatedAt: new Date(before.updatedAt)
483
+ });
484
+ em.persist(record);
485
+ }
486
+ ensureTenantScope(ctx, before.tenantId);
487
+ ensureOrganizationScope(ctx, before.organizationId);
488
+ applyConversionSnapshot(em, record, before);
489
+ await em.transactional(async () => {
490
+ await em.flush();
491
+ });
492
+ const dataEngine = ctx.container.resolve("dataEngine");
493
+ await emitConversionCrudUndoChange({
494
+ dataEngine,
495
+ action: "created",
496
+ conversion: record
497
+ });
498
+ }
499
+ };
500
+ registerCommand(createProductUnitConversionCommand);
501
+ registerCommand(updateProductUnitConversionCommand);
502
+ registerCommand(deleteProductUnitConversionCommand);
503
+ //# sourceMappingURL=productUnitConversions.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/catalog/commands/productUnitConversions.ts"],
4
+ "sourcesContent": ["import { registerCommand } from \"@open-mercato/shared/lib/commands\";\nimport type { CommandHandler } from \"@open-mercato/shared/lib/commands\";\nimport {\n buildChanges,\n requireId,\n emitCrudSideEffects,\n emitCrudUndoSideEffects,\n} from \"@open-mercato/shared/lib/commands/helpers\";\nimport type {\n CrudEventAction,\n CrudEventsConfig,\n CrudIndexerConfig,\n} from \"@open-mercato/shared/lib/crud/types\";\nimport type { EntityManager } from \"@mikro-orm/postgresql\";\nimport { UniqueConstraintViolationException } from \"@mikro-orm/core\";\nimport { CrudHttpError } from \"@open-mercato/shared/lib/crud/errors\";\nimport { resolveTranslations } from \"@open-mercato/shared/lib/i18n/server\";\nimport type { DataEngine } from \"@open-mercato/shared/lib/data/engine\";\nimport { E } from \"#generated/entities.ids.generated\";\nimport {\n findOneWithDecryption,\n} from \"@open-mercato/shared/lib/encryption/find\";\nimport { CatalogProduct, CatalogProductUnitConversion } from \"../data/entities\";\nimport {\n productUnitConversionCreateSchema,\n productUnitConversionUpdateSchema,\n productUnitConversionDeleteSchema,\n type ProductUnitConversionCreateInput,\n type ProductUnitConversionUpdateInput,\n type ProductUnitConversionDeleteInput,\n} from \"../data/validators\";\nimport {\n ensureOrganizationScope,\n ensureSameScope,\n cloneJson,\n ensureTenantScope,\n extractUndoPayload,\n requireProduct,\n toNumericString,\n getErrorConstraint,\n getErrorMessage,\n} from \"./shared\";\nimport { toUnitLookupKey } from \"../lib/unitCodes\";\nimport { resolveCanonicalUnitCode } from \"../lib/unitResolution\";\n\ntype ProductUnitConversionSnapshot = {\n id: string;\n productId: string;\n organizationId: string;\n tenantId: string;\n unitCode: string;\n toBaseFactor: string;\n sortOrder: number;\n isActive: boolean;\n metadata: Record<string, unknown> | null;\n createdAt: string;\n updatedAt: string;\n};\n\ntype ProductUnitConversionUndoPayload = {\n before?: ProductUnitConversionSnapshot | null;\n after?: ProductUnitConversionSnapshot | null;\n};\n\nconst conversionCrudEvents: CrudEventsConfig<CatalogProductUnitConversion> = {\n module: \"catalog\",\n entity: \"product_unit_conversion\",\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n productId:\n ctx.entity.product && typeof ctx.entity.product !== \"string\"\n ? ctx.entity.product.id\n : null,\n unitCode: ctx.entity.unitCode,\n tenantId: ctx.identifiers.tenantId,\n organizationId: ctx.identifiers.organizationId,\n }),\n};\n\nconst conversionCrudIndexer: CrudIndexerConfig<CatalogProductUnitConversion> = {\n entityType: E.catalog.catalog_product_unit_conversion,\n buildUpsertPayload: (ctx) => ({\n entityType: E.catalog.catalog_product_unit_conversion,\n recordId: ctx.identifiers.id,\n tenantId: ctx.identifiers.tenantId,\n organizationId: ctx.identifiers.organizationId,\n }),\n buildDeletePayload: (ctx) => ({\n entityType: E.catalog.catalog_product_unit_conversion,\n recordId: ctx.identifiers.id,\n tenantId: ctx.identifiers.tenantId,\n organizationId: ctx.identifiers.organizationId,\n }),\n};\n\nfunction buildIdentifiers(record: CatalogProductUnitConversion) {\n return {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n };\n}\n\nasync function emitConversionCrudChange(opts: {\n dataEngine: DataEngine;\n action: CrudEventAction;\n conversion: CatalogProductUnitConversion;\n}) {\n const { dataEngine, action, conversion } = opts;\n await emitCrudSideEffects({\n dataEngine,\n action,\n entity: conversion,\n identifiers: buildIdentifiers(conversion),\n events: conversionCrudEvents,\n indexer: conversionCrudIndexer,\n });\n}\n\nasync function emitConversionCrudUndoChange(opts: {\n dataEngine: DataEngine;\n action: CrudEventAction;\n conversion: CatalogProductUnitConversion;\n}) {\n const { dataEngine, action, conversion } = opts;\n await emitCrudUndoSideEffects({\n dataEngine,\n action,\n entity: conversion,\n identifiers: buildIdentifiers(conversion),\n events: conversionCrudEvents,\n indexer: conversionCrudIndexer,\n });\n}\n\nasync function loadConversionSnapshot(\n em: EntityManager,\n id: string,\n): Promise<ProductUnitConversionSnapshot | null> {\n const record = await findOneWithDecryption(\n em,\n CatalogProductUnitConversion,\n { id, deletedAt: null },\n { populate: [\"product\"] },\n );\n if (!record) return null;\n const productId =\n typeof record.product === \"string\"\n ? record.product\n : (record.product?.id ?? null);\n if (!productId) return null;\n return {\n id: record.id,\n productId,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n unitCode: record.unitCode,\n toBaseFactor: record.toBaseFactor,\n sortOrder: record.sortOrder,\n isActive: record.isActive,\n metadata: record.metadata\n ? cloneJson(record.metadata)\n : null,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString(),\n };\n}\n\nfunction applyConversionSnapshot(\n em: EntityManager,\n record: CatalogProductUnitConversion,\n snapshot: ProductUnitConversionSnapshot,\n): void {\n record.organizationId = snapshot.organizationId;\n record.tenantId = snapshot.tenantId;\n record.product = em.getReference(CatalogProduct, snapshot.productId);\n record.unitCode = snapshot.unitCode;\n record.toBaseFactor = snapshot.toBaseFactor;\n record.sortOrder = snapshot.sortOrder;\n record.isActive = snapshot.isActive;\n record.metadata = snapshot.metadata\n ? cloneJson(snapshot.metadata)\n : null;\n record.createdAt = new Date(snapshot.createdAt);\n record.updatedAt = new Date(snapshot.updatedAt);\n}\n\nasync function ensureDefaultSalesUnitIsNotRemoved(\n em: EntityManager,\n record: CatalogProductUnitConversion,\n nextIsActive: boolean,\n): Promise<void> {\n if (nextIsActive) return;\n const product =\n typeof record.product === \"string\"\n ? await findOneWithDecryption(em, CatalogProduct, {\n id: record.product,\n deletedAt: null,\n })\n : record.product;\n if (!product) return;\n const defaultSalesUnitKey = toUnitLookupKey(product.defaultSalesUnit);\n const conversionUnitKey = toUnitLookupKey(record.unitCode);\n if (\n defaultSalesUnitKey &&\n conversionUnitKey &&\n defaultSalesUnitKey === conversionUnitKey\n ) {\n throw new CrudHttpError(409, {\n error: \"uom.default_sales_unit_conversion_required\",\n });\n }\n}\n\nfunction resolveConversionUniqueConstraint(error: unknown): boolean {\n if (error instanceof UniqueConstraintViolationException) {\n const constraint = getErrorConstraint(error);\n if (constraint === \"catalog_product_unit_conversions_unique\") return true;\n const message = getErrorMessage(error);\n return message.toLowerCase().includes(\"catalog_product_unit_conversions_unique\");\n }\n return false;\n}\n\nfunction rethrowConversionUniqueConstraint(\n error: unknown,\n): never {\n if (resolveConversionUniqueConstraint(error)) {\n throw new CrudHttpError(409, { error: \"uom.duplicate_conversion\" });\n }\n throw error;\n}\n\nconst createProductUnitConversionCommand: CommandHandler<\n ProductUnitConversionCreateInput,\n { conversionId: string }\n> = {\n id: \"catalog.product-unit-conversions.create\",\n async execute(rawInput, ctx) {\n const parsed = productUnitConversionCreateSchema.parse(rawInput);\n ensureTenantScope(ctx, parsed.tenantId);\n ensureOrganizationScope(ctx, parsed.organizationId);\n\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const { translate } = await resolveTranslations();\n const product = await requireProduct(\n em,\n parsed.productId,\n translate(\"catalog.errors.productNotFound\", \"Catalog product not found\"),\n );\n ensureSameScope(product, parsed.organizationId, parsed.tenantId);\n const canonicalUnitCode = await resolveCanonicalUnitCode(em, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n unitCode: parsed.unitCode,\n });\n\n const toBaseFactorStr = toNumericString(parsed.toBaseFactor);\n if (!toBaseFactorStr) {\n throw new CrudHttpError(400, {\n error: \"uom.conversion_factor_required\",\n });\n }\n\n const conversion = em.create(CatalogProductUnitConversion, {\n product,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n unitCode: canonicalUnitCode,\n toBaseFactor: toBaseFactorStr,\n sortOrder: parsed.sortOrder ?? 0,\n isActive: parsed.isActive !== false,\n metadata: parsed.metadata\n ? cloneJson(parsed.metadata)\n : null,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(conversion);\n try {\n await em.flush();\n } catch (error) {\n rethrowConversionUniqueConstraint(error);\n }\n\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n await emitConversionCrudChange({\n dataEngine,\n action: \"created\",\n conversion,\n });\n return { conversionId: conversion.id };\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n return loadConversionSnapshot(em, result.conversionId);\n },\n buildLog: async ({ snapshots }) => {\n const after = snapshots.after as ProductUnitConversionSnapshot | undefined;\n if (!after) return null;\n const { translate } = await resolveTranslations();\n return {\n actionLabel: translate(\n \"catalog.audit.productUnitConversions.create\",\n \"Create product unit conversion\",\n ),\n resourceKind: \"catalog.product_unit_conversion\",\n resourceId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n snapshotAfter: after,\n payload: {\n undo: {\n after,\n } satisfies ProductUnitConversionUndoPayload,\n },\n };\n },\n undo: async ({ logEntry, ctx }) => {\n const payload =\n extractUndoPayload<ProductUnitConversionUndoPayload>(logEntry);\n const after = payload?.after;\n if (!after) return;\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const record = await findOneWithDecryption(\n em,\n CatalogProductUnitConversion,\n { id: after.id, deletedAt: null },\n );\n if (!record) return;\n ensureTenantScope(ctx, record.tenantId);\n ensureOrganizationScope(ctx, record.organizationId);\n em.remove(record);\n await em.flush();\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n await emitConversionCrudUndoChange({\n dataEngine,\n action: \"deleted\",\n conversion: record,\n });\n },\n};\n\nconst updateProductUnitConversionCommand: CommandHandler<\n ProductUnitConversionUpdateInput,\n { conversionId: string }\n> = {\n id: \"catalog.product-unit-conversions.update\",\n async prepare(input, ctx) {\n const id = requireId(input, \"Product unit conversion id is required\");\n const em = ctx.container.resolve(\"em\") as EntityManager;\n const snapshot = await loadConversionSnapshot(em, id);\n if (snapshot) {\n ensureTenantScope(ctx, snapshot.tenantId);\n ensureOrganizationScope(ctx, snapshot.organizationId);\n }\n return snapshot ? { before: snapshot } : {};\n },\n async execute(rawInput, ctx) {\n const parsed = productUnitConversionUpdateSchema.parse(rawInput);\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const { translate } = await resolveTranslations();\n const record = await findOneWithDecryption(\n em,\n CatalogProductUnitConversion,\n { id: parsed.id, deletedAt: null },\n { populate: [\"product\"] },\n );\n if (!record)\n throw new CrudHttpError(404, {\n error: translate(\"catalog.errors.conversionNotFound\", \"Catalog product unit conversion not found\"),\n });\n const product =\n typeof record.product === \"string\"\n ? await requireProduct(em, record.product, translate(\"catalog.errors.productNotFound\", \"Catalog product not found\"))\n : record.product;\n ensureTenantScope(ctx, record.tenantId);\n ensureOrganizationScope(ctx, record.organizationId);\n ensureSameScope(product, record.organizationId, record.tenantId);\n\n // Resolve all query-dependent values BEFORE applying scalar mutations\n const resolvedUnitCode =\n parsed.unitCode !== undefined\n ? await resolveCanonicalUnitCode(em, {\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n unitCode: parsed.unitCode,\n })\n : undefined;\n if (parsed.isActive !== undefined) {\n await ensureDefaultSalesUnitIsNotRemoved(em, record, parsed.isActive);\n }\n\n // Apply all scalar mutations after queries are complete\n if (resolvedUnitCode !== undefined) {\n record.unitCode = resolvedUnitCode;\n }\n if (parsed.toBaseFactor !== undefined) {\n record.toBaseFactor =\n toNumericString(parsed.toBaseFactor) ?? record.toBaseFactor;\n }\n if (parsed.sortOrder !== undefined) {\n record.sortOrder = parsed.sortOrder;\n }\n if (parsed.isActive !== undefined) {\n record.isActive = parsed.isActive;\n }\n if (parsed.metadata !== undefined) {\n record.metadata = parsed.metadata\n ? cloneJson(parsed.metadata)\n : null;\n }\n try {\n await em.flush();\n } catch (error) {\n rethrowConversionUniqueConstraint(error);\n }\n\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n await emitConversionCrudChange({\n dataEngine,\n action: \"updated\",\n conversion: record,\n });\n return { conversionId: record.id };\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n return loadConversionSnapshot(em, result.conversionId);\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as\n | ProductUnitConversionSnapshot\n | undefined;\n const after = snapshots.after as ProductUnitConversionSnapshot | undefined;\n if (!before || !after) return null;\n const { translate } = await resolveTranslations();\n return {\n actionLabel: translate(\n \"catalog.audit.productUnitConversions.update\",\n \"Update product unit conversion\",\n ),\n resourceKind: \"catalog.product_unit_conversion\",\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n changes: buildChanges(before, after, [\n \"unitCode\",\n \"toBaseFactor\",\n \"sortOrder\",\n \"isActive\",\n \"metadata\",\n ]),\n snapshotBefore: before,\n snapshotAfter: after,\n payload: {\n undo: {\n before,\n after,\n } satisfies ProductUnitConversionUndoPayload,\n },\n };\n },\n undo: async ({ logEntry, ctx }) => {\n const payload =\n extractUndoPayload<ProductUnitConversionUndoPayload>(logEntry);\n const before = payload?.before;\n if (!before) return;\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n let record = await findOneWithDecryption(\n em,\n CatalogProductUnitConversion,\n { id: before.id, deletedAt: null },\n );\n let undoAction: \"updated\" | \"created\" = \"updated\";\n if (!record) {\n record = em.create(CatalogProductUnitConversion, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n product: em.getReference(CatalogProduct, before.productId),\n unitCode: before.unitCode,\n toBaseFactor: before.toBaseFactor,\n sortOrder: before.sortOrder,\n isActive: before.isActive,\n metadata: before.metadata\n ? cloneJson(before.metadata)\n : null,\n createdAt: new Date(before.createdAt),\n updatedAt: new Date(before.updatedAt),\n });\n em.persist(record);\n undoAction = \"created\";\n }\n ensureTenantScope(ctx, before.tenantId);\n ensureOrganizationScope(ctx, before.organizationId);\n applyConversionSnapshot(em, record, before);\n await em.transactional(async () => {\n await em.flush();\n });\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n await emitConversionCrudUndoChange({\n dataEngine,\n action: undoAction,\n conversion: record,\n });\n },\n};\n\nconst deleteProductUnitConversionCommand: CommandHandler<\n ProductUnitConversionDeleteInput,\n { conversionId: string }\n> = {\n id: \"catalog.product-unit-conversions.delete\",\n async prepare(input, ctx) {\n const id = requireId(input, \"Product unit conversion id is required\");\n const em = ctx.container.resolve(\"em\") as EntityManager;\n const snapshot = await loadConversionSnapshot(em, id);\n if (snapshot) {\n ensureTenantScope(ctx, snapshot.tenantId);\n ensureOrganizationScope(ctx, snapshot.organizationId);\n }\n return snapshot ? { before: snapshot } : {};\n },\n async execute(rawInput, ctx) {\n const parsed = productUnitConversionDeleteSchema.parse(rawInput);\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const { translate } = await resolveTranslations();\n const record = await findOneWithDecryption(\n em,\n CatalogProductUnitConversion,\n { id: parsed.id, deletedAt: null },\n { populate: [\"product\"] },\n );\n if (!record)\n throw new CrudHttpError(404, {\n error: translate(\"catalog.errors.conversionNotFound\", \"Catalog product unit conversion not found\"),\n });\n ensureTenantScope(ctx, record.tenantId);\n ensureOrganizationScope(ctx, record.organizationId);\n await ensureDefaultSalesUnitIsNotRemoved(em, record, false);\n\n em.remove(record);\n await em.transactional(async () => {\n await em.flush();\n });\n\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n await emitConversionCrudChange({\n dataEngine,\n action: \"deleted\",\n conversion: record,\n });\n return { conversionId: parsed.id };\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as\n | ProductUnitConversionSnapshot\n | undefined;\n if (!before) return null;\n const { translate } = await resolveTranslations();\n return {\n actionLabel: translate(\n \"catalog.audit.productUnitConversions.delete\",\n \"Delete product unit conversion\",\n ),\n resourceKind: \"catalog.product_unit_conversion\",\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies ProductUnitConversionUndoPayload,\n },\n };\n },\n undo: async ({ logEntry, ctx }) => {\n const payload =\n extractUndoPayload<ProductUnitConversionUndoPayload>(logEntry);\n const before = payload?.before;\n if (!before) return;\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n let record = await findOneWithDecryption(\n em,\n CatalogProductUnitConversion,\n { id: before.id, deletedAt: null },\n );\n if (!record) {\n record = em.create(CatalogProductUnitConversion, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n product: em.getReference(CatalogProduct, before.productId),\n unitCode: before.unitCode,\n toBaseFactor: before.toBaseFactor,\n sortOrder: before.sortOrder,\n isActive: before.isActive,\n metadata: before.metadata\n ? cloneJson(before.metadata)\n : null,\n createdAt: new Date(before.createdAt),\n updatedAt: new Date(before.updatedAt),\n });\n em.persist(record);\n }\n ensureTenantScope(ctx, before.tenantId);\n ensureOrganizationScope(ctx, before.organizationId);\n applyConversionSnapshot(em, record, before);\n await em.transactional(async () => {\n await em.flush();\n });\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n await emitConversionCrudUndoChange({\n dataEngine,\n action: \"created\",\n conversion: record,\n });\n },\n};\n\nregisterCommand(createProductUnitConversionCommand);\nregisterCommand(updateProductUnitConversionCommand);\nregisterCommand(deleteProductUnitConversionCommand);\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }