@porulle/core 0.22.0 → 0.23.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.
|
@@ -37,6 +37,13 @@ export declare class CartService {
|
|
|
37
37
|
lineItems: CartLineItem[];
|
|
38
38
|
}>>;
|
|
39
39
|
addItem(input: AddCartItemInput, actor?: Actor | null, ctx?: TxContext, presentedSecret?: string): Promise<Result<CartLineItem>>;
|
|
40
|
+
/**
|
|
41
|
+
* The unit price for a new cart line, from the pricing step. Refuses — naming the entity and the
|
|
42
|
+
* currency — when no price is configured, when the pricing service is absent, or when resolution
|
|
43
|
+
* fails for any other reason: every one of those is a value the system cannot determine, and the
|
|
44
|
+
* defect this replaces was substituting a literal for exactly that.
|
|
45
|
+
*/
|
|
46
|
+
private resolveUnitPrice;
|
|
40
47
|
removeItem(cartId: string, itemId: string, actor?: Actor | null, ctx?: TxContext, presentedSecret?: string): Promise<Result<void>>;
|
|
41
48
|
updateQuantity(input: UpdateCartItemInput, actor?: Actor | null, ctx?: TxContext, presentedSecret?: string): Promise<Result<CartLineItem>>;
|
|
42
49
|
merge(sourceCartId: string, targetCartId: string, actor?: Actor | null, ctx?: TxContext): Promise<Result<void>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/cart/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAc5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,KAAK,IAAI,EAAE,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAExE,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAE5E,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,cAAc,CAAC;IAC3B,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,EAAE,eAAe,CAAC;IAC1B,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AA+BD,qBAAa,WAAW;IAIV,OAAO,CAAC,IAAI;IAHxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiB;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;gBAE5B,IAAI,EAAE,eAAe;IAKnC,MAAM,CACV,KAAK,EAAE,eAAe,EACtB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IA0ElB,OAAO,CACX,EAAE,EAAE,MAAM,EACV,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,EACf,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,IAAI,GAAG;QAAE,SAAS,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC,CAAC;IA6BxD;;;;OAIG;IACG,qBAAqB,CACzB,EAAE,EAAE,MAAM,EACV,cAAc,EAAE,MAAM,EACtB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,IAAI,GAAG;QAAE,SAAS,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC,CAAC;IAWlD,OAAO,CACX,KAAK,EAAE,gBAAgB,EACvB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/cart/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -191,12 +191,35 @@ export class CartService {
|
|
|
191
191
|
item = updated;
|
|
192
192
|
}
|
|
193
193
|
else {
|
|
194
|
+
// A new line needs a price, and a price the system cannot determine is refused rather than
|
|
195
|
+
// invented. This used to read `processed.unitPriceSnapshot ?? 1000`: a silent default in a
|
|
196
|
+
// money path, which nothing in the response, the logs or the schema disclosed. An integrator
|
|
197
|
+
// found it by comparing a deployed cart reading 1000 against a catalog priced 14500-22800.
|
|
198
|
+
//
|
|
199
|
+
// A hook still wins when it supplies one, so bespoke pricing keeps its seam; otherwise the
|
|
200
|
+
// pricing step answers — the SAME step `resolveCurrentPrices` uses at checkout, so a cart and
|
|
201
|
+
// its order agree by construction rather than by an integrator remembering to install a hook.
|
|
202
|
+
const currency = processed.currency ?? cart.currency;
|
|
203
|
+
let unitPriceSnapshot = processed.unitPriceSnapshot;
|
|
204
|
+
if (unitPriceSnapshot === undefined) {
|
|
205
|
+
const resolved = await this.resolveUnitPrice({
|
|
206
|
+
entityId: processed.entityId,
|
|
207
|
+
currency,
|
|
208
|
+
quantity,
|
|
209
|
+
...(processed.variantId != null
|
|
210
|
+
? { variantId: processed.variantId }
|
|
211
|
+
: {}),
|
|
212
|
+
}, actor ?? null, ctx);
|
|
213
|
+
if (!resolved.ok)
|
|
214
|
+
return resolved;
|
|
215
|
+
unitPriceSnapshot = resolved.value;
|
|
216
|
+
}
|
|
194
217
|
item = await this.repo.createLineItem({
|
|
195
218
|
cartId: input.cartId,
|
|
196
219
|
entityId: processed.entityId,
|
|
197
220
|
quantity,
|
|
198
|
-
unitPriceSnapshot
|
|
199
|
-
currency
|
|
221
|
+
unitPriceSnapshot,
|
|
222
|
+
currency,
|
|
200
223
|
metadata: processed.metadata ?? {},
|
|
201
224
|
...(processed.variantId !== undefined
|
|
202
225
|
? { variantId: processed.variantId }
|
|
@@ -206,6 +229,23 @@ export class CartService {
|
|
|
206
229
|
await runAfterHooks(afterHooks, null, item, "addItem", context);
|
|
207
230
|
return Ok(item);
|
|
208
231
|
}
|
|
232
|
+
/**
|
|
233
|
+
* The unit price for a new cart line, from the pricing step. Refuses — naming the entity and the
|
|
234
|
+
* currency — when no price is configured, when the pricing service is absent, or when resolution
|
|
235
|
+
* fails for any other reason: every one of those is a value the system cannot determine, and the
|
|
236
|
+
* defect this replaces was substituting a literal for exactly that.
|
|
237
|
+
*/
|
|
238
|
+
async resolveUnitPrice(input, actor, ctx) {
|
|
239
|
+
const pricing = this.deps.services.pricing;
|
|
240
|
+
if (typeof pricing?.resolve !== "function") {
|
|
241
|
+
return Err(new CommerceValidationError(`Cannot resolve a unit price for ${input.entityId}: no pricing service is configured.`));
|
|
242
|
+
}
|
|
243
|
+
const resolved = await pricing.resolve(input, actor, ctx);
|
|
244
|
+
if (!resolved.ok) {
|
|
245
|
+
return Err(new CommerceValidationError(`Cannot resolve a unit price for ${input.entityId} (${input.currency}). Configure a price for it, or supply unitPriceSnapshot from a cart.beforeAddItem hook.`));
|
|
246
|
+
}
|
|
247
|
+
return Ok(resolved.value.finalAmount);
|
|
248
|
+
}
|
|
209
249
|
async removeItem(cartId, itemId, actor, ctx, presentedSecret) {
|
|
210
250
|
try {
|
|
211
251
|
assertPermission(actor ?? null, "cart:update");
|
package/package.json
CHANGED
|
@@ -318,13 +318,39 @@ export class CartService {
|
|
|
318
318
|
);
|
|
319
319
|
item = updated!;
|
|
320
320
|
} else {
|
|
321
|
+
// A new line needs a price, and a price the system cannot determine is refused rather than
|
|
322
|
+
// invented. This used to read `processed.unitPriceSnapshot ?? 1000`: a silent default in a
|
|
323
|
+
// money path, which nothing in the response, the logs or the schema disclosed. An integrator
|
|
324
|
+
// found it by comparing a deployed cart reading 1000 against a catalog priced 14500-22800.
|
|
325
|
+
//
|
|
326
|
+
// A hook still wins when it supplies one, so bespoke pricing keeps its seam; otherwise the
|
|
327
|
+
// pricing step answers — the SAME step `resolveCurrentPrices` uses at checkout, so a cart and
|
|
328
|
+
// its order agree by construction rather than by an integrator remembering to install a hook.
|
|
329
|
+
const currency = processed.currency ?? cart.currency;
|
|
330
|
+
let unitPriceSnapshot = processed.unitPriceSnapshot;
|
|
331
|
+
if (unitPriceSnapshot === undefined) {
|
|
332
|
+
const resolved = await this.resolveUnitPrice(
|
|
333
|
+
{
|
|
334
|
+
entityId: processed.entityId,
|
|
335
|
+
currency,
|
|
336
|
+
quantity,
|
|
337
|
+
...(processed.variantId != null
|
|
338
|
+
? { variantId: processed.variantId }
|
|
339
|
+
: {}),
|
|
340
|
+
},
|
|
341
|
+
actor ?? null,
|
|
342
|
+
ctx,
|
|
343
|
+
);
|
|
344
|
+
if (!resolved.ok) return resolved;
|
|
345
|
+
unitPriceSnapshot = resolved.value;
|
|
346
|
+
}
|
|
321
347
|
item = await this.repo.createLineItem(
|
|
322
348
|
{
|
|
323
349
|
cartId: input.cartId,
|
|
324
350
|
entityId: processed.entityId,
|
|
325
351
|
quantity,
|
|
326
|
-
unitPriceSnapshot
|
|
327
|
-
currency
|
|
352
|
+
unitPriceSnapshot,
|
|
353
|
+
currency,
|
|
328
354
|
metadata: processed.metadata ?? {},
|
|
329
355
|
...(processed.variantId !== undefined
|
|
330
356
|
? { variantId: processed.variantId }
|
|
@@ -339,6 +365,56 @@ export class CartService {
|
|
|
339
365
|
return Ok(item);
|
|
340
366
|
}
|
|
341
367
|
|
|
368
|
+
/**
|
|
369
|
+
* The unit price for a new cart line, from the pricing step. Refuses — naming the entity and the
|
|
370
|
+
* currency — when no price is configured, when the pricing service is absent, or when resolution
|
|
371
|
+
* fails for any other reason: every one of those is a value the system cannot determine, and the
|
|
372
|
+
* defect this replaces was substituting a literal for exactly that.
|
|
373
|
+
*/
|
|
374
|
+
private async resolveUnitPrice(
|
|
375
|
+
input: {
|
|
376
|
+
entityId: string;
|
|
377
|
+
currency: string;
|
|
378
|
+
quantity: number;
|
|
379
|
+
variantId?: string;
|
|
380
|
+
},
|
|
381
|
+
actor: Actor | null,
|
|
382
|
+
ctx?: TxContext,
|
|
383
|
+
): Promise<Result<number>> {
|
|
384
|
+
const pricing = this.deps.services.pricing as
|
|
385
|
+
| {
|
|
386
|
+
resolve(
|
|
387
|
+
params: {
|
|
388
|
+
entityId: string;
|
|
389
|
+
currency: string;
|
|
390
|
+
quantity: number;
|
|
391
|
+
variantId?: string;
|
|
392
|
+
},
|
|
393
|
+
actor?: Actor | null,
|
|
394
|
+
ctx?: TxContext,
|
|
395
|
+
): Promise<Result<{ finalAmount: number }>>;
|
|
396
|
+
}
|
|
397
|
+
| undefined;
|
|
398
|
+
|
|
399
|
+
if (typeof pricing?.resolve !== "function") {
|
|
400
|
+
return Err(
|
|
401
|
+
new CommerceValidationError(
|
|
402
|
+
`Cannot resolve a unit price for ${input.entityId}: no pricing service is configured.`,
|
|
403
|
+
),
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const resolved = await pricing.resolve(input, actor, ctx);
|
|
408
|
+
if (!resolved.ok) {
|
|
409
|
+
return Err(
|
|
410
|
+
new CommerceValidationError(
|
|
411
|
+
`Cannot resolve a unit price for ${input.entityId} (${input.currency}). Configure a price for it, or supply unitPriceSnapshot from a cart.beforeAddItem hook.`,
|
|
412
|
+
),
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
return Ok(resolved.value.finalAmount);
|
|
416
|
+
}
|
|
417
|
+
|
|
342
418
|
async removeItem(
|
|
343
419
|
cartId: string,
|
|
344
420
|
itemId: string,
|