@labdigital/commercetools-mock 2.7.0 → 2.8.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@labdigital/commercetools-mock",
3
3
  "author": "Michael van Tellingen",
4
- "version": "2.7.0",
4
+ "version": "2.8.0",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.js",
@@ -46,7 +46,7 @@
46
46
  "devDependencies": {
47
47
  "@changesets/changelog-github": "^0.4.8",
48
48
  "@changesets/cli": "^2.26.2",
49
- "@commercetools/platform-sdk": "4.11.0",
49
+ "@commercetools/platform-sdk": "6.0.0",
50
50
  "@types/basic-auth": "^1.1.3",
51
51
  "@types/body-parser": "^1.19.2",
52
52
  "@types/deep-equal": "^1.0.1",
package/src/ctMock.ts CHANGED
@@ -264,6 +264,10 @@ export class CommercetoolsMock {
264
264
  )
265
265
  }
266
266
 
267
+ public mswServer() {
268
+ return this._mswServer
269
+ }
270
+
267
271
  private startServer() {
268
272
  // Check if there are any other servers running
269
273
  if (_globalListeners.length > 0) {
@@ -21,11 +21,13 @@ export type PriceSelector = {
21
21
  */
22
22
  export const applyPriceSelector = (
23
23
  products: ProductProjection[],
24
- selector: PriceSelector
24
+ selector: PriceSelector,
25
+ noScopedPrice: boolean = false
25
26
  ) => {
26
27
  validatePriceSelector(selector)
27
28
 
28
29
  for (const product of products) {
30
+ // Get list of all variants (master + variants)
29
31
  const variants: Writable<ProductVariant>[] = [
30
32
  product.masterVariant,
31
33
  ...(product.variants ?? []),
@@ -38,10 +40,13 @@ export const applyPriceSelector = (
38
40
  if (scopedPrices.length > 0) {
39
41
  const price = scopedPrices[0]
40
42
 
41
- variant.scopedPriceDiscounted = false
42
- variant.scopedPrice = {
43
- ...price,
44
- currentValue: price.value,
43
+ variant.price = scopedPrices[0]
44
+ if (!noScopedPrice) {
45
+ variant.scopedPriceDiscounted = false
46
+ variant.scopedPrice = {
47
+ ...price,
48
+ currentValue: price.value,
49
+ }
45
50
  }
46
51
  }
47
52
  }
@@ -51,6 +51,7 @@ export class CustomerRepository extends AbstractResourceRepository<'customer'> {
51
51
  password: draft.password ? hashPassword(draft.password) : undefined,
52
52
  isEmailVerified: draft.isEmailVerified || false,
53
53
  addresses: [],
54
+ customerNumber: draft.customerNumber,
54
55
  }
55
56
  this.saveNew(context, resource)
56
57
  return resource
@@ -180,7 +180,7 @@ export const getReferenceFromResourceIdentifier = <T extends Reference>(
180
180
  if (!resource) {
181
181
  const errIdentifier = resourceIdentifier.key
182
182
  ? `key '${resourceIdentifier.key}'`
183
- : `identifier '${resourceIdentifier.key}'`
183
+ : `identifier '${resourceIdentifier.id}'`
184
184
 
185
185
  throw new CommercetoolsError<ReferencedResourceNotFoundError>(
186
186
  {
@@ -2,12 +2,15 @@ import type {
2
2
  Cart,
3
3
  CartReference,
4
4
  CustomLineItem,
5
- CustomLineItemDraft,
5
+ CustomLineItemImportDraft,
6
+ CustomLineItemReturnItem,
6
7
  GeneralError,
7
8
  LineItem,
8
9
  LineItemImportDraft,
10
+ LineItemReturnItem,
9
11
  Order,
10
12
  OrderAddPaymentAction,
13
+ OrderAddReturnInfoAction,
11
14
  OrderChangeOrderStateAction,
12
15
  OrderChangePaymentStateAction,
13
16
  OrderFromCartDraft,
@@ -24,6 +27,7 @@ import type {
24
27
  Product,
25
28
  ProductPagedQueryResponse,
26
29
  ProductVariant,
30
+ ReturnInfo,
27
31
  State,
28
32
  Store,
29
33
  } from '@commercetools/platform-sdk'
@@ -227,7 +231,7 @@ export class OrderRepository extends AbstractResourceRepository<'order'> {
227
231
 
228
232
  private customLineItemFromImportDraft(
229
233
  context: RepositoryContext,
230
- draft: CustomLineItemDraft
234
+ draft: CustomLineItemImportDraft
231
235
  ): CustomLineItem {
232
236
  const lineItem: CustomLineItem = {
233
237
  ...getBaseResourceProperties(),
@@ -241,10 +245,11 @@ export class OrderRepository extends AbstractResourceRepository<'order'> {
241
245
  name: draft.name,
242
246
  quantity: draft.quantity ?? 0,
243
247
  perMethodTaxRate: [],
244
- priceMode: draft.priceMode,
248
+ priceMode: draft.priceMode ?? 'Standard',
245
249
  slug: draft.slug,
246
250
  state: [],
247
251
  totalPrice: createCentPrecisionMoney(draft.money),
252
+ taxedPricePortions: [],
248
253
  }
249
254
 
250
255
  return lineItem
@@ -296,6 +301,43 @@ export class OrderRepository extends AbstractResourceRepository<'order'> {
296
301
  id: payment.id!,
297
302
  })
298
303
  },
304
+ addReturnInfo: (
305
+ context: RepositoryContext,
306
+ resource: Writable<Order>,
307
+ info: OrderAddReturnInfoAction
308
+ ) => {
309
+ if (!resource.returnInfo) {
310
+ resource.returnInfo = []
311
+ }
312
+
313
+ const resolved: ReturnInfo = {
314
+ items: info.items.map((item) => {
315
+ const common = {
316
+ ...getBaseResourceProperties(),
317
+ quantity: item.quantity,
318
+ paymentState: 'Initial',
319
+ shipmentState: 'Initial',
320
+ comment: item.comment,
321
+ }
322
+ if (item.customLineItemId) {
323
+ return {
324
+ ...common,
325
+ type: 'CustomLineItemReturnItem',
326
+ customLineItemId: item.customLineItemId,
327
+ } as CustomLineItemReturnItem
328
+ }
329
+ return {
330
+ ...common,
331
+ type: 'LineItemReturnItem',
332
+ lineItemId: item.customLineItemId || item.lineItemId,
333
+ } as LineItemReturnItem
334
+ }),
335
+ returnTrackingId: info.returnTrackingId,
336
+ returnDate: info.returnDate,
337
+ }
338
+
339
+ resource.returnInfo.push(resolved)
340
+ },
299
341
  changeOrderState: (
300
342
  context: RepositoryContext,
301
343
  resource: Writable<Order>,
@@ -13,6 +13,7 @@ import {
13
13
  GetParams,
14
14
  RepositoryContext,
15
15
  } from './abstract.js'
16
+ import { applyPriceSelector } from '../priceSelector.js'
16
17
 
17
18
  export type ProductProjectionQueryParams = {
18
19
  staged?: boolean
@@ -100,6 +101,20 @@ export class ProductProjectionRepository extends AbstractResourceRepository<'pro
100
101
  }
101
102
  }
102
103
 
104
+ // We do this after the filtering, since the docs mention:
105
+ // Only available when Price selection is used. Cannot be used in a Query
106
+ // Predicate.
107
+ applyPriceSelector(
108
+ resources,
109
+ {
110
+ country: params.priceCountry,
111
+ channel: params.priceChannel,
112
+ customerGroup: params.priceCustomerGroup,
113
+ currency: params.priceCurrency,
114
+ },
115
+ true
116
+ )
117
+
103
118
  // Expand the resources
104
119
  if (params.expand !== undefined) {
105
120
  resources = resources.map((resource) =>
@@ -22,7 +22,6 @@ export class ProductSelectionRepository extends AbstractResourceRepository<'prod
22
22
  productCount: 0,
23
23
  key: draft.key,
24
24
  name: draft.name,
25
- type: 'individual',
26
25
  mode: 'Individual',
27
26
  }
28
27
  this.saveNew(context, resource)
@@ -36,6 +36,7 @@ import type {
36
36
  ProductAddToCategoryAction,
37
37
  ProductRemoveFromCategoryAction,
38
38
  ProductTransitionStateAction,
39
+ ChannelReference,
39
40
  } from '@commercetools/platform-sdk'
40
41
  import { v4 as uuidv4 } from 'uuid'
41
42
  import type { Writable } from '../types.js'
@@ -126,10 +127,10 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
126
127
  slug: draft.slug,
127
128
  description: draft.description,
128
129
  categories: categoryReferences,
129
- masterVariant: variantFromDraft(1, draft.masterVariant),
130
+ masterVariant: this.variantFromDraft(context, 1, draft.masterVariant),
130
131
  variants:
131
132
  draft.variants?.map((variant, index) =>
132
- variantFromDraft(index + 2, variant)
133
+ this.variantFromDraft(context, index + 2, variant)
133
134
  ) ?? [],
134
135
  metaTitle: draft.metaTitle,
135
136
  metaDescription: draft.metaDescription,
@@ -156,6 +157,38 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
156
157
  return resource
157
158
  }
158
159
 
160
+ private variantFromDraft(
161
+ context: RepositoryContext,
162
+ variantId: number,
163
+ variant: ProductVariantDraft
164
+ ): ProductVariant {
165
+ return {
166
+ id: variantId,
167
+ sku: variant?.sku,
168
+ key: variant?.key,
169
+ attributes: variant?.attributes ?? [],
170
+ prices: variant?.prices?.map((p) => this.priceFromDraft(context, p)),
171
+ assets: [],
172
+ images: [],
173
+ }
174
+ }
175
+
176
+ private priceFromDraft(context: RepositoryContext, draft: PriceDraft): Price {
177
+ return {
178
+ id: uuidv4(),
179
+ key: draft.key,
180
+ country: draft.country,
181
+ value: createTypedMoney(draft.value),
182
+ channel: draft.channel
183
+ ? getReferenceFromResourceIdentifier<ChannelReference>(
184
+ draft.channel,
185
+ context.projectKey,
186
+ this._storage
187
+ )
188
+ : undefined,
189
+ }
190
+ }
191
+
159
192
  actions: Partial<
160
193
  Record<
161
194
  ProductUpdateAction['action'],
@@ -528,7 +561,7 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
528
561
  }
529
562
 
530
563
  // Pre-creating the price object ensures consistency between staged and current versions
531
- const priceToAdd = priceFromDraft(price)
564
+ const priceToAdd = this.priceFromDraft(context, price)
532
565
 
533
566
  // If true, only the staged Attribute is set. If false, both current and
534
567
  // staged Attribute is set. Default is true
@@ -754,7 +787,7 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
754
787
  (max, element) => (element.id > max ? element.id : max),
755
788
  0
756
789
  )
757
- const variant = variantFromDraft(maxId + 1, variantDraft)
790
+ const variant = this.variantFromDraft(context, maxId + 1, variantDraft)
758
791
  dataStaged.variants.push(variant)
759
792
 
760
793
  const onlyStaged = staged !== undefined ? staged : true
@@ -1071,23 +1104,3 @@ const getVariant = (
1071
1104
  : -1,
1072
1105
  }
1073
1106
  }
1074
-
1075
- const variantFromDraft = (
1076
- variantId: number,
1077
- variant: ProductVariantDraft
1078
- ): ProductVariant => ({
1079
- id: variantId,
1080
- sku: variant?.sku,
1081
- key: variant?.key,
1082
- attributes: variant?.attributes ?? [],
1083
- prices: variant?.prices?.map(priceFromDraft),
1084
- assets: [],
1085
- images: [],
1086
- })
1087
-
1088
- const priceFromDraft = (draft: PriceDraft): Price => ({
1089
- id: uuidv4(),
1090
- key: draft.key,
1091
- country: draft.country,
1092
- value: createTypedMoney(draft.value),
1093
- })
@@ -1,11 +1,18 @@
1
- import type {
2
- Review,
3
- ReviewDraft,
4
- ReviewUpdateAction,
1
+ import {
2
+ ChannelReference,
3
+ ProductReference,
4
+ type Review,
5
+ type ReviewDraft,
6
+ type ReviewUpdateAction,
7
+ type StateReference,
5
8
  } from '@commercetools/platform-sdk'
6
9
  import { getBaseResourceProperties } from '../helpers.js'
7
10
  import type { Writable } from '../types.js'
8
11
  import { AbstractResourceRepository, RepositoryContext } from './abstract.js'
12
+ import {
13
+ createCustomFields,
14
+ getReferenceFromResourceIdentifier,
15
+ } from './helpers.js'
9
16
 
10
17
  export class ReviewRepository extends AbstractResourceRepository<'review'> {
11
18
  getTypeId() {
@@ -13,9 +20,34 @@ export class ReviewRepository extends AbstractResourceRepository<'review'> {
13
20
  }
14
21
 
15
22
  create(context: RepositoryContext, draft: ReviewDraft): Review {
23
+ if (!draft.target) throw new Error('Missing target')
16
24
  const resource: Review = {
17
25
  ...getBaseResourceProperties(),
26
+
27
+ locale: draft.locale,
28
+ authorName: draft.authorName,
29
+ title: draft.title,
30
+ text: draft.text,
31
+ rating: draft.rating,
32
+ uniquenessValue: draft.uniquenessValue,
33
+ state: draft.state
34
+ ? getReferenceFromResourceIdentifier<StateReference>(
35
+ draft.state,
36
+ context.projectKey,
37
+ this._storage
38
+ )
39
+ : undefined,
40
+ target: draft.target
41
+ ? getReferenceFromResourceIdentifier<
42
+ ProductReference | ChannelReference
43
+ >(draft.target, context.projectKey, this._storage)
44
+ : undefined,
18
45
  includedInStatistics: false,
46
+ custom: createCustomFields(
47
+ draft.custom,
48
+ context.projectKey,
49
+ this._storage
50
+ ),
19
51
  }
20
52
  this.saveNew(context, resource)
21
53
  return resource
@@ -23,6 +23,7 @@ import { ProductProjectionService } from './product-projection.js'
23
23
  import { ProductSelectionService } from './product-selection.js'
24
24
  import { ProductTypeService } from './product-type.js'
25
25
  import { ProductService } from './product.js'
26
+ import { ReviewService } from './reviews.js'
26
27
  import { ShippingMethodService } from './shipping-method.js'
27
28
  import { ShoppingListService } from './shopping-list.js'
28
29
  import { StandAlonePriceService } from './standalone-price.js'
@@ -84,6 +85,7 @@ export const createServices = (router: any, repos: any) => ({
84
85
  router,
85
86
  repos['product-selection']
86
87
  ),
88
+ reviews: new ReviewService(router, repos['review']),
87
89
  'shopping-list': new ShoppingListService(router, repos['shopping-list']),
88
90
  state: new StateService(router, repos['state']),
89
91
  store: new StoreService(router, repos['store']),
@@ -29,7 +29,6 @@ describe('product-selection', () => {
29
29
  key: 'foo',
30
30
  version: 1,
31
31
  productCount: 0,
32
- type: 'individual',
33
32
  mode: 'Individual',
34
33
  })
35
34
  })
@@ -0,0 +1,16 @@
1
+ import { Router } from 'express'
2
+ import AbstractService from './abstract.js'
3
+ import { ReviewRepository } from '../repositories/review.js'
4
+
5
+ export class ReviewService extends AbstractService {
6
+ public repository: ReviewRepository
7
+
8
+ constructor(parent: Router, repository: ReviewRepository) {
9
+ super(parent)
10
+ this.repository = repository
11
+ }
12
+
13
+ getBasePath() {
14
+ return 'reviews'
15
+ }
16
+ }
@@ -415,12 +415,15 @@ export class InMemoryStorage extends AbstractStorage {
415
415
  reference.typeId !== undefined &&
416
416
  (reference.id !== undefined || reference.key !== undefined)
417
417
  ) {
418
- // @ts-ignore
419
- reference.obj = this.getByResourceIdentifier(projectKey, {
420
- typeId: reference.typeId,
421
- id: reference.id,
422
- key: reference.key,
423
- } as ResourceIdentifier)
418
+ // First check if the object is already resolved. This is the case when
419
+ // the complete resource is pushed via the .add() method.
420
+ if (!reference.obj) {
421
+ reference.obj = this.getByResourceIdentifier(projectKey, {
422
+ typeId: reference.typeId,
423
+ id: reference.id,
424
+ key: reference.key,
425
+ } as ResourceIdentifier)
426
+ }
424
427
  if (expand) {
425
428
  this._resolveResource(projectKey, reference.obj, expand)
426
429
  }