@porulle/core 0.41.0 → 0.43.0
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/interfaces/rest/customer-portal.d.ts.map +1 -1
- package/dist/interfaces/rest/customer-portal.js +1 -1
- package/dist/interfaces/rest/routes/orders.js +1 -1
- package/dist/modules/fulfillment/repository/index.d.ts +11 -11
- package/dist/modules/fulfillment/repository/index.d.ts.map +1 -1
- package/dist/modules/fulfillment/repository/index.js +54 -27
- package/dist/modules/fulfillment/service.d.ts +2 -2
- package/dist/modules/fulfillment/service.d.ts.map +1 -1
- package/dist/modules/fulfillment/service.js +29 -8
- package/package.json +3 -3
- package/src/interfaces/rest/customer-portal.ts +1 -0
- package/src/interfaces/rest/routes/orders.ts +1 -1
- package/src/modules/fulfillment/repository/index.ts +96 -18
- package/src/modules/fulfillment/service.ts +41 -5
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { eq, desc, and, sql } from "drizzle-orm";
|
|
1
|
+
import { eq, desc, and, sql, exists } from "drizzle-orm";
|
|
2
2
|
import type { TxContext } from "../../../kernel/database/tx-context.js";
|
|
3
3
|
import type {
|
|
4
4
|
DrizzleDatabase,
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
fulfillmentLineItems,
|
|
10
10
|
fulfillmentEvents,
|
|
11
11
|
} from "../schema.js";
|
|
12
|
+
import { orders } from "../../orders/schema.js";
|
|
12
13
|
|
|
13
14
|
// Infer types from Drizzle schema
|
|
14
15
|
export type FulfillmentRecord = typeof fulfillmentRecords.$inferSelect;
|
|
@@ -38,29 +39,45 @@ export class FulfillmentRepository {
|
|
|
38
39
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
39
40
|
|
|
40
41
|
async findById(
|
|
42
|
+
orgId: string,
|
|
41
43
|
id: string,
|
|
42
44
|
ctx?: TxContext,
|
|
43
45
|
): Promise<FulfillmentRecord | undefined> {
|
|
44
46
|
const db = this.getDb(ctx);
|
|
45
47
|
const rows = await db
|
|
46
|
-
.select()
|
|
48
|
+
.select({ fulfillment: fulfillmentRecords })
|
|
47
49
|
.from(fulfillmentRecords)
|
|
48
|
-
.
|
|
49
|
-
|
|
50
|
+
.innerJoin(orders, eq(fulfillmentRecords.orderId, orders.id))
|
|
51
|
+
.where(
|
|
52
|
+
and(
|
|
53
|
+
eq(fulfillmentRecords.id, id),
|
|
54
|
+
eq(orders.organizationId, orgId),
|
|
55
|
+
),
|
|
56
|
+
);
|
|
57
|
+
return rows[0]?.fulfillment;
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
async findByOrderId(
|
|
61
|
+
orgId: string,
|
|
53
62
|
orderId: string,
|
|
54
63
|
ctx?: TxContext,
|
|
55
64
|
): Promise<FulfillmentRecord[]> {
|
|
56
65
|
const db = this.getDb(ctx);
|
|
57
|
-
|
|
58
|
-
.select()
|
|
66
|
+
const rows = await db
|
|
67
|
+
.select({ fulfillment: fulfillmentRecords })
|
|
59
68
|
.from(fulfillmentRecords)
|
|
60
|
-
.
|
|
69
|
+
.innerJoin(orders, eq(fulfillmentRecords.orderId, orders.id))
|
|
70
|
+
.where(
|
|
71
|
+
and(
|
|
72
|
+
eq(fulfillmentRecords.orderId, orderId),
|
|
73
|
+
eq(orders.organizationId, orgId),
|
|
74
|
+
),
|
|
75
|
+
)
|
|
61
76
|
.orderBy(desc(fulfillmentRecords.createdAt));
|
|
77
|
+
return rows.map((row) => row.fulfillment);
|
|
62
78
|
}
|
|
63
79
|
|
|
80
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
64
81
|
async findByCustomerId(
|
|
65
82
|
customerId: string,
|
|
66
83
|
ctx?: TxContext,
|
|
@@ -73,6 +90,7 @@ export class FulfillmentRepository {
|
|
|
73
90
|
.orderBy(desc(fulfillmentRecords.createdAt));
|
|
74
91
|
}
|
|
75
92
|
|
|
93
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
76
94
|
async findByStatus(
|
|
77
95
|
status: string,
|
|
78
96
|
ctx?: TxContext,
|
|
@@ -85,6 +103,7 @@ export class FulfillmentRepository {
|
|
|
85
103
|
.orderBy(desc(fulfillmentRecords.createdAt));
|
|
86
104
|
}
|
|
87
105
|
|
|
106
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
88
107
|
async findByType(
|
|
89
108
|
type: string,
|
|
90
109
|
ctx?: TxContext,
|
|
@@ -97,6 +116,7 @@ export class FulfillmentRepository {
|
|
|
97
116
|
.orderBy(desc(fulfillmentRecords.createdAt));
|
|
98
117
|
}
|
|
99
118
|
|
|
119
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
100
120
|
async findByOrderIdAndStatus(
|
|
101
121
|
orderId: string,
|
|
102
122
|
status: string,
|
|
@@ -115,6 +135,7 @@ export class FulfillmentRepository {
|
|
|
115
135
|
.orderBy(desc(fulfillmentRecords.createdAt));
|
|
116
136
|
}
|
|
117
137
|
|
|
138
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
118
139
|
async findActiveAccessGrants(
|
|
119
140
|
customerId: string,
|
|
120
141
|
ctx?: TxContext,
|
|
@@ -133,6 +154,7 @@ export class FulfillmentRepository {
|
|
|
133
154
|
.orderBy(desc(fulfillmentRecords.grantedAt));
|
|
134
155
|
}
|
|
135
156
|
|
|
157
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
136
158
|
async findAll(
|
|
137
159
|
options?: { limit?: number; offset?: number },
|
|
138
160
|
ctx?: TxContext,
|
|
@@ -163,6 +185,7 @@ export class FulfillmentRepository {
|
|
|
163
185
|
}
|
|
164
186
|
|
|
165
187
|
async update(
|
|
188
|
+
orgId: string,
|
|
166
189
|
id: string,
|
|
167
190
|
data: Partial<Omit<FulfillmentRecordInsert, "id">>,
|
|
168
191
|
ctx?: TxContext,
|
|
@@ -171,12 +194,28 @@ export class FulfillmentRepository {
|
|
|
171
194
|
const rows = await db
|
|
172
195
|
.update(fulfillmentRecords)
|
|
173
196
|
.set({ ...data, updatedAt: new Date() })
|
|
174
|
-
.where(
|
|
197
|
+
.where(
|
|
198
|
+
and(
|
|
199
|
+
eq(fulfillmentRecords.id, id),
|
|
200
|
+
exists(
|
|
201
|
+
db
|
|
202
|
+
.select({ id: orders.id })
|
|
203
|
+
.from(orders)
|
|
204
|
+
.where(
|
|
205
|
+
and(
|
|
206
|
+
eq(orders.id, fulfillmentRecords.orderId),
|
|
207
|
+
eq(orders.organizationId, orgId),
|
|
208
|
+
),
|
|
209
|
+
),
|
|
210
|
+
),
|
|
211
|
+
),
|
|
212
|
+
)
|
|
175
213
|
.returning();
|
|
176
214
|
return rows[0];
|
|
177
215
|
}
|
|
178
216
|
|
|
179
217
|
async updateStatus(
|
|
218
|
+
orgId: string,
|
|
180
219
|
id: string,
|
|
181
220
|
status: string,
|
|
182
221
|
ctx?: TxContext,
|
|
@@ -190,9 +229,11 @@ export class FulfillmentRepository {
|
|
|
190
229
|
data.deliveredAt = new Date();
|
|
191
230
|
}
|
|
192
231
|
|
|
193
|
-
return this.update(id, data, ctx);
|
|
232
|
+
return this.update(orgId, id, data, ctx);
|
|
194
233
|
}
|
|
195
234
|
|
|
235
|
+
// not tenant-scoped; do not use for tenant-facing access — this is an unscoped WRITE and
|
|
236
|
+
// has no caller today; it needs the same orgId predicate as `update` before it gains one
|
|
196
237
|
async delete(id: string, ctx?: TxContext): Promise<boolean> {
|
|
197
238
|
const db = this.getDb(ctx);
|
|
198
239
|
const result = await db
|
|
@@ -207,6 +248,7 @@ export class FulfillmentRepository {
|
|
|
207
248
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
208
249
|
|
|
209
250
|
async incrementDownloadCount(
|
|
251
|
+
orgId: string,
|
|
210
252
|
id: string,
|
|
211
253
|
ctx?: TxContext,
|
|
212
254
|
): Promise<FulfillmentRecord | undefined> {
|
|
@@ -217,13 +259,32 @@ export class FulfillmentRepository {
|
|
|
217
259
|
downloadCount: sql`${fulfillmentRecords.downloadCount} + 1`,
|
|
218
260
|
updatedAt: new Date(),
|
|
219
261
|
})
|
|
220
|
-
.where(
|
|
262
|
+
.where(
|
|
263
|
+
and(
|
|
264
|
+
eq(fulfillmentRecords.id, id),
|
|
265
|
+
exists(
|
|
266
|
+
db
|
|
267
|
+
.select({ id: orders.id })
|
|
268
|
+
.from(orders)
|
|
269
|
+
.where(
|
|
270
|
+
and(
|
|
271
|
+
eq(orders.id, fulfillmentRecords.orderId),
|
|
272
|
+
eq(orders.organizationId, orgId),
|
|
273
|
+
),
|
|
274
|
+
),
|
|
275
|
+
),
|
|
276
|
+
),
|
|
277
|
+
)
|
|
221
278
|
.returning();
|
|
222
279
|
return rows[0];
|
|
223
280
|
}
|
|
224
281
|
|
|
225
|
-
async isDownloadAllowed(
|
|
226
|
-
|
|
282
|
+
async isDownloadAllowed(
|
|
283
|
+
orgId: string,
|
|
284
|
+
id: string,
|
|
285
|
+
ctx?: TxContext,
|
|
286
|
+
): Promise<boolean> {
|
|
287
|
+
const fulfillment = await this.findById(orgId, id, ctx);
|
|
227
288
|
if (!fulfillment || fulfillment.type !== "digital") return false;
|
|
228
289
|
|
|
229
290
|
// Check expiration
|
|
@@ -250,21 +311,27 @@ export class FulfillmentRepository {
|
|
|
250
311
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
251
312
|
|
|
252
313
|
async deactivateAccessGrant(
|
|
314
|
+
orgId: string,
|
|
253
315
|
id: string,
|
|
254
316
|
ctx?: TxContext,
|
|
255
317
|
): Promise<FulfillmentRecord | undefined> {
|
|
256
|
-
return this.update(id, { isActive: false }, ctx);
|
|
318
|
+
return this.update(orgId, id, { isActive: false }, ctx);
|
|
257
319
|
}
|
|
258
320
|
|
|
259
321
|
async activateAccessGrant(
|
|
322
|
+
orgId: string,
|
|
260
323
|
id: string,
|
|
261
324
|
ctx?: TxContext,
|
|
262
325
|
): Promise<FulfillmentRecord | undefined> {
|
|
263
|
-
return this.update(id, { isActive: true, grantedAt: new Date() }, ctx);
|
|
326
|
+
return this.update(orgId, id, { isActive: true, grantedAt: new Date() }, ctx);
|
|
264
327
|
}
|
|
265
328
|
|
|
266
|
-
async isAccessGrantActive(
|
|
267
|
-
|
|
329
|
+
async isAccessGrantActive(
|
|
330
|
+
orgId: string,
|
|
331
|
+
id: string,
|
|
332
|
+
ctx?: TxContext,
|
|
333
|
+
): Promise<boolean> {
|
|
334
|
+
const fulfillment = await this.findById(orgId, id, ctx);
|
|
268
335
|
if (!fulfillment || fulfillment.type !== "access_grant") return false;
|
|
269
336
|
|
|
270
337
|
if (!fulfillment.isActive) return false;
|
|
@@ -281,6 +348,7 @@ export class FulfillmentRepository {
|
|
|
281
348
|
// Fulfillment Line Items
|
|
282
349
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
283
350
|
|
|
351
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
284
352
|
async findLineItemsByFulfillmentId(
|
|
285
353
|
fulfillmentId: string,
|
|
286
354
|
ctx?: TxContext,
|
|
@@ -292,6 +360,7 @@ export class FulfillmentRepository {
|
|
|
292
360
|
.where(eq(fulfillmentLineItems.fulfillmentId, fulfillmentId));
|
|
293
361
|
}
|
|
294
362
|
|
|
363
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
295
364
|
async findLineItemsByOrderLineItemId(
|
|
296
365
|
orderLineItemId: string,
|
|
297
366
|
ctx?: TxContext,
|
|
@@ -303,6 +372,7 @@ export class FulfillmentRepository {
|
|
|
303
372
|
.where(eq(fulfillmentLineItems.orderLineItemId, orderLineItemId));
|
|
304
373
|
}
|
|
305
374
|
|
|
375
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
306
376
|
async createLineItem(
|
|
307
377
|
data: FulfillmentLineItemInsert,
|
|
308
378
|
ctx?: TxContext,
|
|
@@ -312,6 +382,7 @@ export class FulfillmentRepository {
|
|
|
312
382
|
return rows[0]!;
|
|
313
383
|
}
|
|
314
384
|
|
|
385
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
315
386
|
async createLineItems(
|
|
316
387
|
data: FulfillmentLineItemInsert[],
|
|
317
388
|
ctx?: TxContext,
|
|
@@ -321,6 +392,7 @@ export class FulfillmentRepository {
|
|
|
321
392
|
return db.insert(fulfillmentLineItems).values(data).returning();
|
|
322
393
|
}
|
|
323
394
|
|
|
395
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
324
396
|
async deleteLineItemsByFulfillmentId(
|
|
325
397
|
fulfillmentId: string,
|
|
326
398
|
ctx?: TxContext,
|
|
@@ -335,6 +407,7 @@ export class FulfillmentRepository {
|
|
|
335
407
|
// Fulfillment Events
|
|
336
408
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
337
409
|
|
|
410
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
338
411
|
async findEventsByFulfillmentId(
|
|
339
412
|
fulfillmentId: string,
|
|
340
413
|
ctx?: TxContext,
|
|
@@ -347,6 +420,7 @@ export class FulfillmentRepository {
|
|
|
347
420
|
.orderBy(desc(fulfillmentEvents.occurredAt));
|
|
348
421
|
}
|
|
349
422
|
|
|
423
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
350
424
|
async createEvent(
|
|
351
425
|
data: FulfillmentEventInsert,
|
|
352
426
|
ctx?: TxContext,
|
|
@@ -356,6 +430,7 @@ export class FulfillmentRepository {
|
|
|
356
430
|
return rows[0]!;
|
|
357
431
|
}
|
|
358
432
|
|
|
433
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
359
434
|
async recordStatusChange(
|
|
360
435
|
fulfillmentId: string,
|
|
361
436
|
fromStatus: string,
|
|
@@ -382,25 +457,27 @@ export class FulfillmentRepository {
|
|
|
382
457
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
383
458
|
|
|
384
459
|
async findWithLineItems(
|
|
460
|
+
orgId: string,
|
|
385
461
|
id: string,
|
|
386
462
|
ctx?: TxContext,
|
|
387
463
|
): Promise<
|
|
388
464
|
| { fulfillment: FulfillmentRecord; lineItems: FulfillmentLineItem[] }
|
|
389
465
|
| undefined
|
|
390
466
|
> {
|
|
391
|
-
const fulfillment = await this.findById(id, ctx);
|
|
467
|
+
const fulfillment = await this.findById(orgId, id, ctx);
|
|
392
468
|
if (!fulfillment) return undefined;
|
|
393
469
|
const lineItems = await this.findLineItemsByFulfillmentId(id, ctx);
|
|
394
470
|
return { fulfillment, lineItems };
|
|
395
471
|
}
|
|
396
472
|
|
|
397
473
|
async findWithEvents(
|
|
474
|
+
orgId: string,
|
|
398
475
|
id: string,
|
|
399
476
|
ctx?: TxContext,
|
|
400
477
|
): Promise<
|
|
401
478
|
{ fulfillment: FulfillmentRecord; events: FulfillmentEvent[] } | undefined
|
|
402
479
|
> {
|
|
403
|
-
const fulfillment = await this.findById(id, ctx);
|
|
480
|
+
const fulfillment = await this.findById(orgId, id, ctx);
|
|
404
481
|
if (!fulfillment) return undefined;
|
|
405
482
|
const events = await this.findEventsByFulfillmentId(id, ctx);
|
|
406
483
|
return { fulfillment, events };
|
|
@@ -410,6 +487,7 @@ export class FulfillmentRepository {
|
|
|
410
487
|
* Get fulfilled quantity for an order line item.
|
|
411
488
|
* Sums all fulfillment line items linked to the order line item.
|
|
412
489
|
*/
|
|
490
|
+
// not tenant-scoped; do not use for tenant-facing access
|
|
413
491
|
async getFulfilledQuantity(
|
|
414
492
|
orderLineItemId: string,
|
|
415
493
|
ctx?: TxContext,
|
|
@@ -15,6 +15,7 @@ import { Err, Ok, type Result } from "../../kernel/result.js";
|
|
|
15
15
|
import { createLogger } from "../../utils/logger.js";
|
|
16
16
|
import type {
|
|
17
17
|
FulfillmentRecord as FulfillmentDbRow,
|
|
18
|
+
FulfillmentRecordInsert,
|
|
18
19
|
FulfillmentRepository,
|
|
19
20
|
} from "./repository/index.js";
|
|
20
21
|
import type { OrdersRepository } from "../orders/repository/index.js";
|
|
@@ -55,6 +56,11 @@ interface FulfillmentServiceDeps {
|
|
|
55
56
|
database: DatabaseAdapter;
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
type FulfillmentTrackingPatch = Pick<
|
|
60
|
+
FulfillmentRecordInsert,
|
|
61
|
+
"carrier" | "trackingNumber" | "trackingUrl" | "status" | "shippedAt" | "deliveredAt"
|
|
62
|
+
>;
|
|
63
|
+
|
|
58
64
|
function toFulfillmentLineItem(lineItem: FulfillmentLineItem): {
|
|
59
65
|
id: string;
|
|
60
66
|
title: string;
|
|
@@ -497,9 +503,21 @@ export class FulfillmentService {
|
|
|
497
503
|
|
|
498
504
|
async getByOrderId(
|
|
499
505
|
orderId: string,
|
|
506
|
+
actor?: Actor | null,
|
|
500
507
|
ctx?: TxContext,
|
|
501
508
|
): Promise<Result<FulfillmentRecord[]>> {
|
|
502
|
-
|
|
509
|
+
// Fail closed through the Result boundary, as updateTracking does. Strict org resolution
|
|
510
|
+
// THROWS, and this method did not resolve an org before this change — so leaving it
|
|
511
|
+
// unwrapped would add a throw to a Result-returning method whose REST callers branch on
|
|
512
|
+
// `!result.ok` and would never see it.
|
|
513
|
+
let orgId: string;
|
|
514
|
+
try {
|
|
515
|
+
orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
516
|
+
} catch (error) {
|
|
517
|
+
return Err(toCommerceError(error));
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const dbRecords = await this.deps.repository.findByOrderId(orgId, orderId, ctx);
|
|
503
521
|
|
|
504
522
|
// Hydrate each record with its associated line items
|
|
505
523
|
const records: FulfillmentRecord[] = [];
|
|
@@ -523,9 +541,18 @@ export class FulfillmentService {
|
|
|
523
541
|
trackingUrl?: string;
|
|
524
542
|
status?: string;
|
|
525
543
|
},
|
|
544
|
+
actor?: Actor | null,
|
|
526
545
|
ctx?: TxContext,
|
|
527
546
|
): Promise<Result<void>> {
|
|
547
|
+
let orgId: string;
|
|
548
|
+
try {
|
|
549
|
+
orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
550
|
+
} catch (error) {
|
|
551
|
+
return Err(toCommerceError(error));
|
|
552
|
+
}
|
|
553
|
+
|
|
528
554
|
const existing = await this.deps.repository.findById(
|
|
555
|
+
orgId,
|
|
529
556
|
input.fulfillmentId,
|
|
530
557
|
ctx,
|
|
531
558
|
);
|
|
@@ -533,7 +560,7 @@ export class FulfillmentService {
|
|
|
533
560
|
return Err(new CommerceNotFoundError("Fulfillment record not found."));
|
|
534
561
|
}
|
|
535
562
|
|
|
536
|
-
const updateData:
|
|
563
|
+
const updateData: Partial<FulfillmentTrackingPatch> = {};
|
|
537
564
|
if (input.carrier !== undefined) updateData.carrier = input.carrier;
|
|
538
565
|
if (input.trackingNumber !== undefined)
|
|
539
566
|
updateData.trackingNumber = input.trackingNumber;
|
|
@@ -543,7 +570,15 @@ export class FulfillmentService {
|
|
|
543
570
|
if (input.status === "shipped") updateData.shippedAt = new Date();
|
|
544
571
|
if (input.status === "delivered") updateData.deliveredAt = new Date();
|
|
545
572
|
|
|
546
|
-
await this.deps.repository.update(
|
|
573
|
+
const updated = await this.deps.repository.update(
|
|
574
|
+
orgId,
|
|
575
|
+
input.fulfillmentId,
|
|
576
|
+
updateData,
|
|
577
|
+
ctx,
|
|
578
|
+
);
|
|
579
|
+
if (!updated) {
|
|
580
|
+
return Err(new CommerceNotFoundError("Fulfillment record not found."));
|
|
581
|
+
}
|
|
547
582
|
return Ok(undefined);
|
|
548
583
|
}
|
|
549
584
|
|
|
@@ -554,7 +589,8 @@ export class FulfillmentService {
|
|
|
554
589
|
actor?: Actor | null,
|
|
555
590
|
ctx?: TxContext,
|
|
556
591
|
): Promise<Result<{ url: string; remaining: number; expiresAt: string }>> {
|
|
557
|
-
const
|
|
592
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
593
|
+
const dbRecords = await this.deps.repository.findByOrderId(orgId, orderId, ctx);
|
|
558
594
|
|
|
559
595
|
let matchedRecord: (typeof dbRecords)[number] | undefined;
|
|
560
596
|
for (const dbRecord of dbRecords) {
|
|
@@ -574,7 +610,6 @@ export class FulfillmentService {
|
|
|
574
610
|
return Err(new CommerceNotFoundError("Digital download not found."));
|
|
575
611
|
}
|
|
576
612
|
|
|
577
|
-
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
578
613
|
const order = await this.deps.ordersRepository.findById(orgId, orderId, ctx);
|
|
579
614
|
if (!order || order.customerId !== userId) {
|
|
580
615
|
return Err(new CommerceNotFoundError("Order not found."));
|
|
@@ -589,6 +624,7 @@ export class FulfillmentService {
|
|
|
589
624
|
}
|
|
590
625
|
|
|
591
626
|
const updated = await this.deps.repository.incrementDownloadCount(
|
|
627
|
+
orgId,
|
|
592
628
|
matchedRecord.id,
|
|
593
629
|
ctx,
|
|
594
630
|
);
|