@open-mercato/core 0.6.4-develop.4011.1.4f3ed9ae3e → 0.6.4-develop.4038.1.91ce075c8a

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.
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod'
2
2
  import type { EntityManager } from '@mikro-orm/postgresql'
3
- import { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'
3
+ import { makeCrudRoute, type CrudCtx } from '@open-mercato/shared/lib/crud/factory'
4
4
  import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
5
5
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
6
6
  import { splitCustomFieldPayload } from '@open-mercato/shared/lib/crud/custom-fields'
@@ -53,6 +53,161 @@ const toNumber = (value: unknown): number => {
53
53
  return 0
54
54
  }
55
55
 
56
+ export async function enrichShipmentListResponse(
57
+ payload: { items?: unknown[] },
58
+ ctx: CrudCtx,
59
+ ): Promise<void> {
60
+ const items = Array.isArray(payload.items) ? payload.items : []
61
+ if (!items.length) return
62
+ const snapshotMap = new Map<string, ReturnType<typeof readShipmentItemsSnapshot>>()
63
+ items.forEach((item: unknown) => {
64
+ if (!item || typeof item !== 'object') return
65
+ const id = (item as Record<string, unknown>).id
66
+ if (typeof id !== 'string') return
67
+ const snapshot = readShipmentItemsSnapshot(
68
+ (item as any).items_snapshot ?? (item as any).itemsSnapshot ?? null
69
+ )
70
+ if (snapshot.length) {
71
+ snapshotMap.set(id, snapshot)
72
+ }
73
+ })
74
+ const shipmentIds = items
75
+ .map((item: unknown) => {
76
+ if (!item || typeof item !== 'object') return null
77
+ const raw = (item as Record<string, unknown>).id
78
+ return typeof raw === 'string' ? raw : null
79
+ })
80
+ .filter((value: string | null): value is string => typeof value === 'string')
81
+ if (!shipmentIds.length) return
82
+ const em = ctx.container.resolve('em') as EntityManager
83
+ const statusIds: string[] = Array.from(
84
+ new Set(
85
+ items
86
+ .map((item: unknown) => {
87
+ if (!item || typeof item !== 'object') return null
88
+ const raw = (item as Record<string, unknown>).status_entry_id
89
+ return typeof raw === 'string' ? raw : null
90
+ })
91
+ .filter((value: string | null): value is string => typeof value === 'string' && value.length > 0)
92
+ )
93
+ )
94
+ const [shipmentItems, shippingMethods, statusEntries] = await Promise.all([
95
+ findWithDecryption(
96
+ em,
97
+ SalesShipmentItem,
98
+ { shipment: { $in: shipmentIds } },
99
+ { populate: ['orderLine'] },
100
+ { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.auth?.orgId ?? null },
101
+ ),
102
+ (async () => {
103
+ const ids: string[] = Array.from(
104
+ new Set(
105
+ items
106
+ .map((item: unknown) => {
107
+ if (!item || typeof item !== 'object') return null
108
+ const raw = (item as Record<string, unknown>).shipping_method_id
109
+ return typeof raw === 'string' ? raw : null
110
+ })
111
+ .filter((value: string | null): value is string => typeof value === 'string' && value.length > 0)
112
+ )
113
+ )
114
+ if (!ids.length) return []
115
+ return em.find(SalesShippingMethod, { id: { $in: ids } })
116
+ })(),
117
+ statusIds.length ? em.find(DictionaryEntry, { id: { $in: statusIds } }) : [],
118
+ ])
119
+ const orderLineIds = Array.from(
120
+ new Set(
121
+ shipmentItems
122
+ .map((entry) =>
123
+ typeof entry.orderLine === 'string'
124
+ ? entry.orderLine
125
+ : entry.orderLine?.id ?? (entry as any).orderLineId ?? null
126
+ )
127
+ .filter((value): value is string => typeof value === 'string')
128
+ )
129
+ )
130
+ const orderLines = orderLineIds.length
131
+ ? await em.find(SalesOrderLine, { id: { $in: orderLineIds } })
132
+ : []
133
+ const lineMap = new Map(
134
+ orderLines.map((line) => [
135
+ line.id,
136
+ {
137
+ lineNumber: line.lineNumber ?? null,
138
+ name:
139
+ line.name ??
140
+ (typeof line.catalogSnapshot === 'object' && line.catalogSnapshot
141
+ ? ((line.catalogSnapshot as any).name as string | undefined) ?? null
142
+ : null),
143
+ },
144
+ ])
145
+ )
146
+ const grouped = shipmentItems.reduce<Map<string, Array<Record<string, unknown>>>>((acc, entry) => {
147
+ const shipmentId =
148
+ typeof entry.shipment === 'string'
149
+ ? entry.shipment
150
+ : entry.shipment?.id ?? (entry as any).shipment_id ?? null
151
+ const lineId =
152
+ typeof entry.orderLine === 'string'
153
+ ? entry.orderLine
154
+ : entry.orderLine?.id ?? (entry as any).order_line_id ?? null
155
+ if (!shipmentId || !lineId) return acc
156
+ const line = lineMap.get(lineId)
157
+ const list = acc.get(shipmentId) ?? []
158
+ list.push({
159
+ id: entry.id,
160
+ orderLineId: lineId,
161
+ orderLineName: line?.name ?? null,
162
+ orderLineNumber: line?.lineNumber ?? null,
163
+ quantity: toNumber(entry.quantity),
164
+ metadata: entry.metadata ?? null,
165
+ })
166
+ acc.set(shipmentId, list)
167
+ return acc
168
+ }, new Map())
169
+ const shippingMap = new Map(
170
+ shippingMethods.map((method) => [
171
+ method.id,
172
+ {
173
+ code: method.code ?? null,
174
+ name: method.name ?? method.code ?? null,
175
+ },
176
+ ])
177
+ )
178
+ const statusMap = new Map<string, { value: string | null; label: string | null }>()
179
+ statusEntries.forEach((entry) =>
180
+ statusMap.set(entry.id, {
181
+ value: entry.value ?? null,
182
+ label: entry.label ?? entry.value ?? null,
183
+ })
184
+ )
185
+ items.forEach((item: unknown) => {
186
+ if (!item || typeof item !== 'object') return
187
+ const id = (item as Record<string, unknown>).id
188
+ if (typeof id !== 'string') return
189
+ const snapshot = snapshotMap.get(id)
190
+ if (snapshot?.length) {
191
+ ;(item as Record<string, unknown>).items_snapshot = snapshot
192
+ }
193
+ ;(item as Record<string, unknown>).items = snapshot?.length ? snapshot : grouped.get(id) ?? []
194
+ const shippingId = (item as Record<string, unknown>).shipping_method_id
195
+ if (typeof shippingId === 'string' && shippingMap.has(shippingId)) {
196
+ const method = shippingMap.get(shippingId)
197
+ ;(item as Record<string, unknown>).shipping_method_code = method?.code ?? null
198
+ ;(item as Record<string, unknown>).shipping_method_name = method?.name ?? null
199
+ }
200
+ const statusId = (item as Record<string, unknown>).status_entry_id
201
+ if (typeof statusId === 'string' && statusMap.has(statusId)) {
202
+ const status = statusMap.get(statusId)
203
+ if (!(item as Record<string, unknown>).status) {
204
+ ;(item as Record<string, unknown>).status = status?.value ?? null
205
+ }
206
+ ;(item as Record<string, unknown>).status_label = status?.label ?? status?.value ?? null
207
+ }
208
+ })
209
+ }
210
+
56
211
  const crud = makeCrudRoute({
57
212
  metadata: routeMetadata,
58
213
  orm: {
@@ -153,155 +308,7 @@ const crud = makeCrudRoute({
153
308
  },
154
309
  },
155
310
  hooks: {
156
- afterList: async (payload, ctx) => {
157
- const items = Array.isArray(payload.items) ? payload.items : []
158
- if (!items.length) return
159
- const snapshotMap = new Map<string, ReturnType<typeof readShipmentItemsSnapshot>>()
160
- items.forEach((item: unknown) => {
161
- if (!item || typeof item !== 'object') return
162
- const id = (item as Record<string, unknown>).id
163
- if (typeof id !== 'string') return
164
- const snapshot = readShipmentItemsSnapshot(
165
- (item as any).items_snapshot ?? (item as any).itemsSnapshot ?? null
166
- )
167
- if (snapshot.length) {
168
- snapshotMap.set(id, snapshot)
169
- }
170
- })
171
- const shipmentIds = items
172
- .map((item: unknown) => (item && typeof item === 'object' ? (item as Record<string, unknown>).id : null))
173
- .filter((value: string | null): value is string => typeof value === 'string')
174
- if (!shipmentIds.length) return
175
- const em = ctx.container.resolve('em') as EntityManager
176
- const [shipmentItems, shippingMethods] = await Promise.all([
177
- findWithDecryption(
178
- em,
179
- SalesShipmentItem,
180
- { shipment: { $in: shipmentIds } },
181
- { populate: ['orderLine'] },
182
- { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.auth?.orgId ?? null },
183
- ),
184
- (async () => {
185
- const ids: string[] = Array.from(
186
- new Set(
187
- items
188
- .map((item: unknown) => {
189
- if (!item || typeof item !== 'object') return null
190
- const raw = (item as Record<string, unknown>).shipping_method_id
191
- return typeof raw === 'string' ? raw : null
192
- })
193
- .filter((value: string | null): value is string => typeof value === 'string' && value.length > 0)
194
- )
195
- )
196
- if (!ids.length) return []
197
- return em.find(SalesShippingMethod, { id: { $in: ids } })
198
- })(),
199
- ])
200
- const orderLineIds = Array.from(
201
- new Set(
202
- shipmentItems
203
- .map((entry) =>
204
- typeof entry.orderLine === 'string'
205
- ? entry.orderLine
206
- : entry.orderLine?.id ?? (entry as any).orderLineId ?? null
207
- )
208
- .filter((value): value is string => typeof value === 'string')
209
- )
210
- )
211
- const orderLines = orderLineIds.length
212
- ? await em.find(SalesOrderLine, { id: { $in: orderLineIds } })
213
- : []
214
- const lineMap = new Map(
215
- orderLines.map((line) => [
216
- line.id,
217
- {
218
- lineNumber: line.lineNumber ?? null,
219
- name:
220
- line.name ??
221
- (typeof line.catalogSnapshot === 'object' && line.catalogSnapshot
222
- ? ((line.catalogSnapshot as any).name as string | undefined) ?? null
223
- : null),
224
- },
225
- ])
226
- )
227
- const grouped = shipmentItems.reduce<Map<string, Array<Record<string, unknown>>>>((acc, entry) => {
228
- const shipmentId =
229
- typeof entry.shipment === 'string'
230
- ? entry.shipment
231
- : entry.shipment?.id ?? (entry as any).shipment_id ?? null
232
- const lineId =
233
- typeof entry.orderLine === 'string'
234
- ? entry.orderLine
235
- : entry.orderLine?.id ?? (entry as any).order_line_id ?? null
236
- if (!shipmentId || !lineId) return acc
237
- const line = lineMap.get(lineId)
238
- const list = acc.get(shipmentId) ?? []
239
- list.push({
240
- id: entry.id,
241
- orderLineId: lineId,
242
- orderLineName: line?.name ?? null,
243
- orderLineNumber: line?.lineNumber ?? null,
244
- quantity: toNumber(entry.quantity),
245
- metadata: entry.metadata ?? null,
246
- })
247
- acc.set(shipmentId, list)
248
- return acc
249
- }, new Map())
250
- const shippingMap = new Map(
251
- shippingMethods.map((method) => [
252
- method.id,
253
- {
254
- code: method.code ?? null,
255
- name: method.name ?? method.code ?? null,
256
- },
257
- ])
258
- )
259
- const statusIds: string[] = Array.from(
260
- new Set(
261
- items
262
- .map((item: unknown) => {
263
- if (!item || typeof item !== 'object') return null
264
- const raw = (item as Record<string, unknown>).status_entry_id
265
- return typeof raw === 'string' ? raw : null
266
- })
267
- .filter((value: string | null): value is string => typeof value === 'string' && value.length > 0)
268
- )
269
- )
270
- const statusMap = new Map<string, { value: string | null; label: string | null }>()
271
- if (statusIds.length) {
272
- const entries = await em.find(DictionaryEntry, { id: { $in: statusIds } })
273
- entries.forEach((entry) =>
274
- statusMap.set(entry.id, {
275
- value: entry.value ?? null,
276
- label: entry.label ?? entry.value ?? null,
277
- })
278
- )
279
- }
280
- items.forEach((item: unknown) => {
281
- if (!item || typeof item !== 'object') return
282
- const id = (item as Record<string, unknown>).id
283
- if (typeof id !== 'string') return
284
- const snapshot = snapshotMap.get(id)
285
- if (snapshot?.length) {
286
- ;(item as Record<string, unknown>).items_snapshot = snapshot
287
- }
288
- ;(item as Record<string, unknown>).items = snapshot?.length ? snapshot : grouped.get(id) ?? []
289
- const shippingId = (item as Record<string, unknown>).shipping_method_id
290
- if (typeof shippingId === 'string' && shippingMap.has(shippingId)) {
291
- const method = shippingMap.get(shippingId)
292
- ;(item as Record<string, unknown>).shipping_method_code = method?.code ?? null
293
- ;(item as Record<string, unknown>).shipping_method_name = method?.name ?? null
294
- }
295
- const statusId = (item as Record<string, unknown>).status_entry_id
296
- if (typeof statusId === 'string' && statusMap.has(statusId)) {
297
- const status = statusMap.get(statusId)
298
- if (!(item as Record<string, unknown>).status) {
299
- ;(item as Record<string, unknown>).status = status?.value ?? null
300
- }
301
- ;(item as Record<string, unknown>).status_label = status?.label ?? status?.value ?? null
302
- }
303
- })
304
- },
311
+ afterList: (payload, ctx) => enrichShipmentListResponse(payload, ctx),
305
312
  },
306
313
  })
307
314