@labdigital/commercetools-mock 2.53.2 → 2.55.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.
Files changed (52) hide show
  1. package/dist/index.d.ts +107 -77
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +330 -7
  4. package/dist/index.js.map +1 -1
  5. package/package.json +4 -3
  6. package/src/lib/productSearchFilter.test.ts +1 -0
  7. package/src/lib/projectionSearchFilter.test.ts +1 -0
  8. package/src/priceSelector.test.ts +1 -0
  9. package/src/product-projection-search.ts +2 -0
  10. package/src/product-search.ts +1 -0
  11. package/src/repositories/business-unit.ts +157 -2
  12. package/src/repositories/cart/index.test.ts +2 -0
  13. package/src/repositories/cart/index.ts +1 -0
  14. package/src/repositories/cart-discount/index.ts +1 -1
  15. package/src/repositories/customer/index.ts +2 -0
  16. package/src/repositories/discount-group/actions.ts +50 -0
  17. package/src/repositories/discount-group/index.ts +29 -0
  18. package/src/repositories/index.ts +6 -0
  19. package/src/repositories/order/index.test.ts +126 -125
  20. package/src/repositories/payment/actions.ts +87 -0
  21. package/src/repositories/payment/index.ts +1 -1
  22. package/src/repositories/product/index.ts +1 -0
  23. package/src/repositories/product-type.ts +1 -0
  24. package/src/repositories/quote/index.ts +1 -0
  25. package/src/repositories/quote-request/index.test.ts +1 -0
  26. package/src/repositories/quote-request/index.ts +1 -0
  27. package/src/repositories/recurrence-policy/actions.ts +53 -0
  28. package/src/repositories/recurrence-policy/index.ts +36 -0
  29. package/src/repositories/recurring-order/actions.ts +157 -0
  30. package/src/repositories/recurring-order/index.ts +52 -0
  31. package/src/repositories/review.test.ts +2 -0
  32. package/src/repositories/shopping-list/actions.ts +1 -0
  33. package/src/repositories/shopping-list/index.ts +1 -0
  34. package/src/services/business-units.test.ts +586 -15
  35. package/src/services/discount-group.test.ts +270 -0
  36. package/src/services/discount-group.ts +16 -0
  37. package/src/services/index.ts +12 -0
  38. package/src/services/my-cart.test.ts +1 -0
  39. package/src/services/my-payment.test.ts +1 -0
  40. package/src/services/payment.test.ts +1 -0
  41. package/src/services/product-projection.test.ts +4 -0
  42. package/src/services/product-type.test.ts +1 -0
  43. package/src/services/product.test.ts +1 -0
  44. package/src/services/recurrence-policy.test.ts +316 -0
  45. package/src/services/recurrence-policy.ts +16 -0
  46. package/src/services/recurring-order.test.ts +424 -0
  47. package/src/services/recurring-order.ts +16 -0
  48. package/src/services/shopping-list.test.ts +3 -0
  49. package/src/storage/in-memory.ts +6 -0
  50. package/src/testing/business-unit.ts +48 -0
  51. package/src/testing/type.ts +20 -0
  52. package/src/types.ts +6 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@labdigital/commercetools-mock",
3
- "version": "2.53.2",
3
+ "version": "2.55.0",
4
4
  "license": "MIT",
5
5
  "author": "Michael van Tellingen",
6
6
  "type": "module",
@@ -31,7 +31,7 @@
31
31
  "@types/express": "^5.0.1",
32
32
  "@changesets/changelog-github": "0.5.1",
33
33
  "@changesets/cli": "2.28.1",
34
- "@commercetools/platform-sdk": "8.8.0",
34
+ "@commercetools/platform-sdk": "8.14.0",
35
35
  "@types/basic-auth": "1.1.8",
36
36
  "@types/body-parser": "1.19.5",
37
37
  "@types/express-serve-static-core": "^5.0.6",
@@ -66,6 +66,7 @@
66
66
  "publish:version": "pnpm changeset version && pnpm format",
67
67
  "start": "tsdown src/server.ts --watch --onSuccess 'node dist/server'",
68
68
  "test": "vitest run",
69
- "test:ci": "vitest run --coverage"
69
+ "test:ci": "vitest run --coverage",
70
+ "test:watch": "vitest --watch"
70
71
  }
71
72
  }
@@ -25,6 +25,7 @@ describe("Product search filter", () => {
25
25
  "nl-NL": "test",
26
26
  "en-US": "test",
27
27
  },
28
+ attributes: [],
28
29
  variants: [],
29
30
  searchKeywords: {},
30
31
  categories: [],
@@ -24,6 +24,7 @@ describe("Search filter", () => {
24
24
  variants: [],
25
25
  searchKeywords: {},
26
26
  categories: [],
27
+ attributes: [],
27
28
  masterVariant: {
28
29
  id: 1,
29
30
  sku: "MYSKU",
@@ -24,6 +24,7 @@ describe("priceSelector", () => {
24
24
  variants: [],
25
25
  searchKeywords: {},
26
26
  categories: [],
27
+ attributes: [],
27
28
  masterVariant: {
28
29
  id: 1,
29
30
  sku: "MYSKU",
@@ -3,6 +3,7 @@ import type {
3
3
  FilteredFacetResult,
4
4
  InvalidInputError,
5
5
  Product,
6
+ ProductData,
6
7
  ProductProjection,
7
8
  ProductProjectionPagedSearchResponse,
8
9
  QueryParam,
@@ -169,6 +170,7 @@ export class ProductProjectionSearch {
169
170
  return {
170
171
  id: product.id,
171
172
  createdAt: product.createdAt,
173
+ attributes: obj.attributes,
172
174
  lastModifiedAt: product.lastModifiedAt,
173
175
  version: product.version,
174
176
  name: obj.name,
@@ -176,6 +176,7 @@ export class ProductSearch {
176
176
  metaDescription: obj.metaDescription,
177
177
  slug: obj.slug,
178
178
  categories: obj.categories,
179
+ attributes: obj.attributes,
179
180
  masterVariant: {
180
181
  ...obj.masterVariant,
181
182
  availability: getVariantAvailability(obj.masterVariant.sku),
@@ -1,9 +1,18 @@
1
1
  import type {
2
+ BusinessUnitAddBillingAddressIdAction,
2
3
  BusinessUnitAddShippingAddressIdAction,
3
4
  BusinessUnitChangeApprovalRuleModeAction,
5
+ BusinessUnitChangeAssociateAction,
4
6
  BusinessUnitChangeAssociateModeAction,
5
7
  BusinessUnitChangeStatusAction,
8
+ BusinessUnitRemoveAssociateAction,
9
+ BusinessUnitRemoveBillingAddressIdAction,
10
+ BusinessUnitRemoveShippingAddressIdAction,
11
+ BusinessUnitSetAddressCustomFieldAction,
12
+ BusinessUnitSetAddressCustomTypeAction,
13
+ BusinessUnitSetCustomFieldAction,
6
14
  BusinessUnitSetCustomTypeAction,
15
+ BusinessUnitSetDefaultBillingAddressAction,
7
16
  BusinessUnitSetDefaultShippingAddressAction,
8
17
  BusinessUnitUpdateAction,
9
18
  CompanyDraft,
@@ -194,15 +203,25 @@ class BusinessUnitUpdateHandler
194
203
  changeAddress(
195
204
  context: RepositoryContext,
196
205
  resource: Writable<BusinessUnit>,
197
- { address }: BusinessUnitChangeAddressAction,
206
+ { addressId, address }: BusinessUnitChangeAddressAction,
198
207
  ) {
208
+ const existingAddressIndex = resource.addresses.findIndex(
209
+ (addr) => addr.id === addressId,
210
+ );
211
+ if (existingAddressIndex === -1) {
212
+ throw new Error(`Address with id ${addressId} not found`);
213
+ }
214
+
199
215
  const newAddress = createAddress(
200
216
  address,
201
217
  context.projectKey,
202
218
  this._storage,
203
219
  );
204
220
  if (newAddress) {
205
- resource.addresses.push(newAddress);
221
+ resource.addresses[existingAddressIndex] = {
222
+ ...newAddress,
223
+ id: addressId,
224
+ };
206
225
  }
207
226
  }
208
227
 
@@ -261,6 +280,40 @@ class BusinessUnitUpdateHandler
261
280
  resource.associates = newAssociates || undefined;
262
281
  }
263
282
 
283
+ removeAssociate(
284
+ context: RepositoryContext,
285
+ resource: Writable<BusinessUnit>,
286
+ { customer }: BusinessUnitRemoveAssociateAction,
287
+ ) {
288
+ resource.associates = resource.associates.filter(
289
+ (associate) => associate.customer.id !== customer.id,
290
+ );
291
+ }
292
+
293
+ changeAssociate(
294
+ context: RepositoryContext,
295
+ resource: Writable<BusinessUnit>,
296
+ { associate }: BusinessUnitChangeAssociateAction,
297
+ ) {
298
+ const existingAssociateIndex = resource.associates.findIndex(
299
+ (a) => a.customer.id === associate.customer.id,
300
+ );
301
+ if (existingAssociateIndex === -1) {
302
+ throw new Error(
303
+ `Associate with customer id ${associate.customer.id} not found`,
304
+ );
305
+ }
306
+
307
+ const newAssociate = createAssociate(
308
+ associate,
309
+ context.projectKey,
310
+ this._storage,
311
+ );
312
+ if (newAssociate) {
313
+ resource.associates[existingAssociateIndex] = newAssociate;
314
+ }
315
+ }
316
+
264
317
  setContactEmail(
265
318
  context: RepositoryContext,
266
319
  resource: Writable<BusinessUnit>,
@@ -314,6 +367,108 @@ class BusinessUnitUpdateHandler
314
367
  }
315
368
  }
316
369
 
370
+ removeShippingAddressId(
371
+ context: RepositoryContext,
372
+ resource: Writable<BusinessUnit>,
373
+ { addressId }: BusinessUnitRemoveShippingAddressIdAction,
374
+ ) {
375
+ if (resource.shippingAddressIds) {
376
+ resource.shippingAddressIds = resource.shippingAddressIds.filter(
377
+ (id) => id !== addressId,
378
+ );
379
+ }
380
+ if (resource.defaultShippingAddressId === addressId) {
381
+ resource.defaultShippingAddressId = undefined;
382
+ }
383
+ }
384
+
385
+ addBillingAddressId(
386
+ context: RepositoryContext,
387
+ resource: Writable<BusinessUnit>,
388
+ { addressId }: BusinessUnitAddBillingAddressIdAction,
389
+ ) {
390
+ if (!resource.billingAddressIds) {
391
+ resource.billingAddressIds = [];
392
+ }
393
+ if (addressId) {
394
+ resource.billingAddressIds.push(addressId);
395
+ }
396
+ }
397
+
398
+ removeBillingAddressId(
399
+ context: RepositoryContext,
400
+ resource: Writable<BusinessUnit>,
401
+ { addressId }: BusinessUnitRemoveBillingAddressIdAction,
402
+ ) {
403
+ if (resource.billingAddressIds) {
404
+ resource.billingAddressIds = resource.billingAddressIds.filter(
405
+ (id) => id !== addressId,
406
+ );
407
+ }
408
+ if (resource.defaultBillingAddressId === addressId) {
409
+ resource.defaultBillingAddressId = undefined;
410
+ }
411
+ }
412
+
413
+ setDefaultBillingAddress(
414
+ context: RepositoryContext,
415
+ resource: Writable<BusinessUnit>,
416
+ { addressId }: BusinessUnitSetDefaultBillingAddressAction,
417
+ ) {
418
+ resource.defaultBillingAddressId = addressId;
419
+ }
420
+
421
+ setCustomField(
422
+ context: RepositoryContext,
423
+ resource: Writable<BusinessUnit>,
424
+ { name, value }: BusinessUnitSetCustomFieldAction,
425
+ ) {
426
+ if (!resource.custom) {
427
+ throw new Error("Resource has no custom type");
428
+ }
429
+ resource.custom.fields[name] = value;
430
+ }
431
+
432
+ setAddressCustomField(
433
+ context: RepositoryContext,
434
+ resource: Writable<BusinessUnit>,
435
+ { addressId, name, value }: BusinessUnitSetAddressCustomFieldAction,
436
+ ) {
437
+ const address = resource.addresses.find((addr) => addr.id === addressId);
438
+ if (!address) {
439
+ throw new Error(`Address with id ${addressId} not found`);
440
+ }
441
+ if (!address.custom) {
442
+ // If the address doesn't have custom fields, we need to initialize them
443
+ // This might require a type to be set first, but we'll just create minimal structure
444
+ throw new Error(
445
+ "Address has no custom type set. Use setAddressCustomType first.",
446
+ );
447
+ }
448
+ address.custom.fields[name] = value;
449
+ }
450
+
451
+ setAddressCustomType(
452
+ context: RepositoryContext,
453
+ resource: Writable<BusinessUnit>,
454
+ { addressId, type, fields }: BusinessUnitSetAddressCustomTypeAction,
455
+ ) {
456
+ const address = resource.addresses.find((addr) => addr.id === addressId);
457
+ if (!address) {
458
+ throw new Error(`Address with id ${addressId} not found`);
459
+ }
460
+
461
+ if (!type) {
462
+ address.custom = undefined;
463
+ } else {
464
+ address.custom = createCustomFields(
465
+ { type, fields },
466
+ context.projectKey,
467
+ this._storage,
468
+ );
469
+ }
470
+ }
471
+
317
472
  removeAddress(
318
473
  context: RepositoryContext,
319
474
  resource: Writable<BusinessUnit>,
@@ -33,6 +33,7 @@ describe("Cart repository", () => {
33
33
  current: {
34
34
  name: { "nl-NL": "Dummy" },
35
35
  slug: { "nl-NL": "Dummy" },
36
+ attributes: [],
36
37
  categories: [],
37
38
  masterVariant: {
38
39
  sku: "MYSKU",
@@ -57,6 +58,7 @@ describe("Cart repository", () => {
57
58
  staged: {
58
59
  name: { "nl-NL": "Dummy" },
59
60
  slug: { "nl-NL": "Dummy" },
61
+ attributes: [],
60
62
  categories: [],
61
63
  masterVariant: {
62
64
  sku: "MYSKU",
@@ -93,6 +93,7 @@ export class CartRepository extends AbstractResourceRepository<"cart"> {
93
93
  itemShippingAddresses: [],
94
94
  lineItems,
95
95
  locale: draft.locale,
96
+ priceRoundingMode: draft.priceRoundingMode ?? "HalfEven",
96
97
  taxCalculationMode: draft.taxCalculationMode ?? "LineItemLevel",
97
98
  taxMode: draft.taxMode ?? "Platform",
98
99
  taxRoundingMode: draft.taxRoundingMode ?? "HalfEven",
@@ -41,7 +41,7 @@ export class CartDiscountRepository extends AbstractResourceRepository<"cart-dis
41
41
  references: [],
42
42
  target: draft.target,
43
43
  requiresDiscountCode: draft.requiresDiscountCode || false,
44
- sortOrder: draft.sortOrder,
44
+ sortOrder: draft.sortOrder ?? "0.1",
45
45
  stackingMode: draft.stackingMode || "Stacking",
46
46
  validFrom: draft.validFrom,
47
47
  validUntil: draft.validUntil,
@@ -189,6 +189,7 @@ export class CustomerRepository extends AbstractResourceRepository<"customer"> {
189
189
  customerId: customer.id,
190
190
  expiresAt: expiresAt.toISOString(),
191
191
  value: token,
192
+ invalidateOlderTokens: request.invalidateOlderTokens || false,
192
193
  };
193
194
  }
194
195
 
@@ -249,6 +250,7 @@ export class CustomerRepository extends AbstractResourceRepository<"customer"> {
249
250
  customerId: customer.id,
250
251
  expiresAt: expiresAt.toISOString(),
251
252
  value: token,
253
+ invalidateOlderTokens: false,
252
254
  };
253
255
  }
254
256
 
@@ -0,0 +1,50 @@
1
+ import type {
2
+ DiscountGroup,
3
+ DiscountGroupSetDescriptionAction,
4
+ DiscountGroupSetKeyAction,
5
+ DiscountGroupSetNameAction,
6
+ DiscountGroupSetSortOrderAction,
7
+ DiscountGroupUpdateAction,
8
+ } from "@commercetools/platform-sdk";
9
+ import type { Writable } from "~src/types";
10
+ import type { UpdateHandlerInterface } from "../abstract";
11
+ import { AbstractUpdateHandler, type RepositoryContext } from "../abstract";
12
+ import { createCustomFields } from "../helpers";
13
+
14
+ export class DiscountGroupUpdateHandler
15
+ extends AbstractUpdateHandler
16
+ implements
17
+ Partial<UpdateHandlerInterface<DiscountGroup, DiscountGroupUpdateAction>>
18
+ {
19
+ setDescription(
20
+ context: RepositoryContext,
21
+ resource: Writable<DiscountGroup>,
22
+ { description }: DiscountGroupSetDescriptionAction,
23
+ ) {
24
+ resource.description = description;
25
+ }
26
+
27
+ setKey(
28
+ context: RepositoryContext,
29
+ resource: Writable<DiscountGroup>,
30
+ { key }: DiscountGroupSetKeyAction,
31
+ ) {
32
+ resource.key = key;
33
+ }
34
+
35
+ setName(
36
+ context: RepositoryContext,
37
+ resource: Writable<DiscountGroup>,
38
+ { name }: DiscountGroupSetNameAction,
39
+ ) {
40
+ resource.name = name;
41
+ }
42
+
43
+ setSortOrder(
44
+ context: RepositoryContext,
45
+ resource: Writable<DiscountGroup>,
46
+ { sortOrder }: DiscountGroupSetSortOrderAction,
47
+ ) {
48
+ resource.sortOrder = sortOrder;
49
+ }
50
+ }
@@ -0,0 +1,29 @@
1
+ import type {
2
+ DiscountGroup,
3
+ DiscountGroupDraft,
4
+ } from "@commercetools/platform-sdk";
5
+ import type { Config } from "~src/config";
6
+ import { getBaseResourceProperties } from "~src/helpers";
7
+ import {
8
+ AbstractResourceRepository,
9
+ type RepositoryContext,
10
+ } from "../abstract";
11
+ import { DiscountGroupUpdateHandler } from "./actions";
12
+
13
+ export class DiscountGroupRepository extends AbstractResourceRepository<"discount-group"> {
14
+ constructor(config: Config) {
15
+ super("discount-group", config);
16
+ this.actions = new DiscountGroupUpdateHandler(config.storage);
17
+ }
18
+
19
+ create(context: RepositoryContext, draft: DiscountGroupDraft): DiscountGroup {
20
+ const resource: DiscountGroup = {
21
+ ...getBaseResourceProperties(),
22
+ description: draft.description,
23
+ name: draft.name,
24
+ key: draft.key,
25
+ sortOrder: draft.sortOrder,
26
+ };
27
+ return this.saveNew(context, resource);
28
+ }
29
+ }
@@ -16,6 +16,7 @@ import { CustomObjectRepository } from "./custom-object";
16
16
  import { CustomerRepository } from "./customer";
17
17
  import { CustomerGroupRepository } from "./customer-group";
18
18
  import { DiscountCodeRepository } from "./discount-code";
19
+ import { DiscountGroupRepository } from "./discount-group";
19
20
  import { ExtensionRepository } from "./extension";
20
21
  import { InventoryEntryRepository } from "./inventory-entry";
21
22
  import { MyCustomerRepository } from "./my-customer";
@@ -32,6 +33,8 @@ import { ProjectRepository } from "./project";
32
33
  import { QuoteRepository } from "./quote";
33
34
  import { QuoteRequestRepository } from "./quote-request";
34
35
  import { StagedQuoteRepository } from "./quote-staged";
36
+ import { RecurrencePolicyRepository } from "./recurrence-policy";
37
+ import { RecurringOrderRepository } from "./recurring-order";
35
38
  import { ReviewRepository } from "./review";
36
39
  import { ShippingMethodRepository } from "./shipping-method";
37
40
  import { ShoppingListRepository } from "./shopping-list";
@@ -61,6 +64,7 @@ export const createRepositories = (config: Config) => ({
61
64
  channel: new ChannelRepository(config),
62
65
  "customer-group": new CustomerGroupRepository(config),
63
66
  "discount-code": new DiscountCodeRepository(config),
67
+ "discount-group": new DiscountGroupRepository(config),
64
68
  extension: new ExtensionRepository(config),
65
69
  "inventory-entry": new InventoryEntryRepository(config),
66
70
  "key-value-document": new CustomObjectRepository(config),
@@ -79,6 +83,8 @@ export const createRepositories = (config: Config) => ({
79
83
  "product-selection": new ProductSelectionRepository(config),
80
84
  "product-tailoring": new ProductTailoringRepository(config),
81
85
  project: new ProjectRepository(config),
86
+ "recurring-order": new RecurringOrderRepository(config),
87
+ "recurrence-policy": new RecurrencePolicyRepository(config),
82
88
  review: new ReviewRepository(config),
83
89
  quote: new QuoteRepository(config),
84
90
  "quote-request": new QuoteRequestRepository(config),