@labdigital/commercetools-mock 0.9.0 → 0.10.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 (95) hide show
  1. package/README.md +8 -0
  2. package/dist/index.d.ts +18 -17
  3. package/dist/index.global.js +1751 -1664
  4. package/dist/index.global.js.map +1 -1
  5. package/dist/index.js +1773 -1684
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +1966 -1877
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +28 -20
  10. package/src/constants.ts +4 -2
  11. package/src/ctMock.ts +19 -84
  12. package/src/helpers.ts +9 -10
  13. package/src/index.test.ts +1 -1
  14. package/src/lib/haversine.ts +2 -2
  15. package/src/lib/masking.ts +3 -1
  16. package/src/lib/predicateParser.test.ts +16 -0
  17. package/src/lib/predicateParser.ts +94 -86
  18. package/src/lib/projectionSearchFilter.test.ts +28 -36
  19. package/src/lib/projectionSearchFilter.ts +86 -102
  20. package/src/oauth/store.ts +3 -3
  21. package/src/priceSelector.test.ts +18 -35
  22. package/src/priceSelector.ts +6 -9
  23. package/src/product-projection-search.ts +51 -57
  24. package/src/repositories/abstract.ts +85 -41
  25. package/src/repositories/cart-discount.ts +1 -1
  26. package/src/repositories/cart.ts +36 -31
  27. package/src/repositories/category.ts +17 -19
  28. package/src/repositories/channel.ts +1 -1
  29. package/src/repositories/custom-object.ts +35 -22
  30. package/src/repositories/customer-group.ts +1 -1
  31. package/src/repositories/customer.ts +39 -1
  32. package/src/repositories/discount-code.ts +1 -1
  33. package/src/repositories/errors.ts +9 -11
  34. package/src/repositories/extension.ts +13 -11
  35. package/src/repositories/helpers.ts +8 -13
  36. package/src/repositories/index.ts +59 -0
  37. package/src/repositories/inventory-entry.ts +1 -1
  38. package/src/repositories/order.ts +6 -6
  39. package/src/repositories/payment.ts +3 -3
  40. package/src/repositories/product-discount.ts +1 -1
  41. package/src/repositories/product-projection.ts +1 -0
  42. package/src/repositories/product-type.ts +29 -34
  43. package/src/repositories/product.ts +124 -80
  44. package/src/repositories/project.ts +10 -27
  45. package/src/repositories/shipping-method.ts +15 -17
  46. package/src/repositories/shopping-list.ts +2 -2
  47. package/src/repositories/state.ts +9 -9
  48. package/src/repositories/store.ts +2 -2
  49. package/src/repositories/subscription.ts +1 -1
  50. package/src/repositories/tax-category.ts +4 -4
  51. package/src/repositories/type.ts +12 -14
  52. package/src/repositories/zone.ts +5 -6
  53. package/src/server.ts +5 -0
  54. package/src/services/abstract.ts +44 -11
  55. package/src/services/cart-discount.ts +2 -3
  56. package/src/services/cart.test.ts +8 -10
  57. package/src/services/cart.ts +8 -11
  58. package/src/services/category.test.ts +1 -2
  59. package/src/services/category.ts +2 -3
  60. package/src/services/channel.ts +2 -3
  61. package/src/services/custom-object.test.ts +5 -5
  62. package/src/services/custom-object.ts +2 -3
  63. package/src/services/customer-group.ts +2 -3
  64. package/src/services/customer.test.ts +136 -0
  65. package/src/services/customer.ts +2 -3
  66. package/src/services/discount-code.ts +2 -3
  67. package/src/services/extension.ts +2 -3
  68. package/src/services/index.ts +74 -0
  69. package/src/services/inventory-entry.test.ts +8 -12
  70. package/src/services/inventory-entry.ts +2 -3
  71. package/src/services/my-cart.ts +3 -4
  72. package/src/services/my-customer.ts +2 -3
  73. package/src/services/my-order.ts +3 -4
  74. package/src/services/my-payment.ts +2 -3
  75. package/src/services/order.test.ts +4 -6
  76. package/src/services/order.ts +2 -3
  77. package/src/services/payment.ts +2 -3
  78. package/src/services/product-discount.ts +2 -3
  79. package/src/services/product-projection.test.ts +76 -8
  80. package/src/services/product-projection.ts +2 -3
  81. package/src/services/product-type.ts +2 -3
  82. package/src/services/product.test.ts +199 -89
  83. package/src/services/product.ts +2 -3
  84. package/src/services/project.ts +3 -3
  85. package/src/services/shipping-method.ts +2 -3
  86. package/src/services/shopping-list.ts +2 -3
  87. package/src/services/state.ts +2 -3
  88. package/src/services/store.test.ts +11 -2
  89. package/src/services/store.ts +2 -3
  90. package/src/services/subscription.ts +2 -3
  91. package/src/services/tax-category.ts +2 -3
  92. package/src/services/type.ts +2 -3
  93. package/src/services/zone.ts +2 -3
  94. package/src/storage.ts +23 -30
  95. package/src/types.ts +46 -6
@@ -5,14 +5,11 @@ import {
5
5
  ProductProjection,
6
6
  QueryParam,
7
7
  FacetResults,
8
- FacetTerm,
9
8
  TermFacetResult,
10
9
  RangeFacetResult,
11
10
  FilteredFacetResult,
12
11
  } from '@commercetools/platform-sdk'
13
- import { ByProjectKeyProductProjectionsSearchRequestBuilder } from '@commercetools/platform-sdk/dist/declarations/src/generated/client/search/by-project-key-product-projections-search-request-builder'
14
12
  import { nestedLookup } from './helpers'
15
- import { ProductService } from './services/product'
16
13
  import { Writable } from './types'
17
14
  import { CommercetoolsError } from './exceptions'
18
15
  import {
@@ -60,13 +57,18 @@ export class ProductProjectionSearch {
60
57
  projectKey: string,
61
58
  params: ProductProjectionSearchParams
62
59
  ): ProductProjectionPagedSearchResponse {
63
- // Get a copy of all the products in the storage engine. We need a copy
64
- // since we will be modifying the data.
65
60
  let resources = this._storage
66
61
  .all(projectKey, 'product')
67
- .map(r => JSON.parse(JSON.stringify(r)))
62
+ .map((r) => this.transform(r, params.staged ?? false))
63
+ .filter((p): p is ProductProjection => p !== null)
64
+ .filter((p) => {
65
+ if (!params.staged ?? false) {
66
+ return p.published
67
+ }
68
+ return true
69
+ })
68
70
 
69
- let markMatchingVariant = params.markMatchingVariants ?? false
71
+ const markMatchingVariant = params.markMatchingVariants ?? false
70
72
 
71
73
  // Apply the priceSelector
72
74
  applyPriceSelector(resources, {
@@ -79,15 +81,14 @@ export class ProductProjectionSearch {
79
81
  // Apply filters pre facetting
80
82
  if (params.filter) {
81
83
  try {
82
- const filters = params.filter.map(f =>
83
- parseFilterExpression(f, params.staged ?? false)
84
- )
84
+ const filters = params.filter.map(parseFilterExpression)
85
85
 
86
86
  // Filters can modify the output. So clone the resources first.
87
- resources = resources.filter(resource =>
88
- filters.every(f => f(resource, markMatchingVariant))
87
+ resources = resources.filter((resource) =>
88
+ filters.every((f) => f(resource, markMatchingVariant))
89
89
  )
90
90
  } catch (err) {
91
+ console.error(err)
91
92
  throw new CommercetoolsError<InvalidInputError>(
92
93
  {
93
94
  code: 'InvalidInput',
@@ -104,12 +105,9 @@ export class ProductProjectionSearch {
104
105
  // Apply filters post facetting
105
106
  if (params['filter.query']) {
106
107
  try {
107
- const filters = params['filter.query'].map(f =>
108
- parseFilterExpression(f, params.staged ?? false)
109
- )
110
-
111
- resources = resources.filter(resource =>
112
- filters.every(f => f(resource, markMatchingVariant))
108
+ const filters = params['filter.query'].map(parseFilterExpression)
109
+ resources = resources.filter((resource) =>
110
+ filters.every((f) => f(resource, markMatchingVariant))
113
111
  )
114
112
  } catch (err) {
115
113
  throw new CommercetoolsError<InvalidInputError>(
@@ -122,33 +120,35 @@ export class ProductProjectionSearch {
122
120
  }
123
121
  }
124
122
 
125
- // Get the total before slicing the array
126
- const totalResources = resources.length
127
-
128
- // Apply offset, limit
129
- const offset = params.offset || 0
130
- const limit = params.limit || 20
131
- resources = resources.slice(offset, offset + limit)
132
-
133
123
  // Expand the resources
134
124
  if (params.expand !== undefined) {
135
- resources = resources.map(resource => {
136
- return this._storage.expand(projectKey, resource, params.expand)
137
- })
125
+ resources = resources.map((resource) =>
126
+ this._storage.expand(projectKey, resource, params.expand)
127
+ )
138
128
  }
139
129
 
130
+ // Create a slice for the pagination. If we were working with large datasets
131
+ // then we should have done this before transforming. But that isn't the
132
+ // goal of this library. So lets keep it simple.
133
+ const totalResults = resources.length
134
+ const offset = params.offset || 0
135
+ const limit = params.limit || 20
136
+ const results = resources.slice(offset, offset + limit)
137
+
140
138
  return {
141
- count: totalResources,
142
- total: resources.length,
139
+ count: totalResults,
140
+ total: results.length,
143
141
  offset: offset,
144
142
  limit: limit,
145
- results: resources.map(this.transform),
143
+ results: results,
146
144
  facets: facets,
147
145
  }
148
146
  }
149
147
 
150
- transform(product: Product): ProductProjection {
151
- const obj = product.masterData.current
148
+ transform(product: Product, staged: boolean): ProductProjection | null {
149
+ const obj = !staged ? product.masterData.current : product.masterData.staged
150
+ if (!obj) return null
151
+
152
152
  return {
153
153
  id: product.id,
154
154
  createdAt: product.createdAt,
@@ -163,12 +163,14 @@ export class ProductProjectionSearch {
163
163
  masterVariant: obj.masterVariant,
164
164
  variants: obj.variants,
165
165
  productType: product.productType,
166
+ hasStagedChanges: product.masterData.hasStagedChanges,
167
+ published: product.masterData.published,
166
168
  }
167
169
  }
168
170
 
169
171
  getFacets(
170
172
  params: ProductProjectionSearchParams,
171
- products: Product[]
173
+ products: ProductProjection[]
172
174
  ): FacetResults {
173
175
  if (!params.facet) return {}
174
176
  const staged = false
@@ -179,7 +181,7 @@ export class ProductProjectionSearch {
179
181
 
180
182
  // Term Facet
181
183
  if (expression.type === 'TermExpression') {
182
- result[facet] = this.termFacet(expression.source, products, staged)
184
+ result[facet] = this.termFacet(expression.source, products)
183
185
  }
184
186
 
185
187
  // Range Facet
@@ -187,8 +189,7 @@ export class ProductProjectionSearch {
187
189
  result[expression.source] = this.rangeFacet(
188
190
  expression.source,
189
191
  expression.children,
190
- products,
191
- staged
192
+ products
192
193
  )
193
194
  }
194
195
 
@@ -197,8 +198,7 @@ export class ProductProjectionSearch {
197
198
  result[expression.source] = this.filterFacet(
198
199
  expression.source,
199
200
  expression.children,
200
- products,
201
- staged
201
+ products
202
202
  )
203
203
  }
204
204
  }
@@ -211,11 +211,7 @@ export class ProductProjectionSearch {
211
211
  * - counting products
212
212
  * - correct dataType
213
213
  */
214
- termFacet(
215
- facet: string,
216
- products: Product[],
217
- staged: boolean
218
- ): TermFacetResult {
214
+ termFacet(facet: string, products: ProductProjection[]): TermFacetResult {
219
215
  const result: Writable<TermFacetResult> = {
220
216
  type: 'terms',
221
217
  dataType: 'text',
@@ -227,9 +223,9 @@ export class ProductProjectionSearch {
227
223
  const terms: Record<any, number> = {}
228
224
 
229
225
  if (facet.startsWith('variants.')) {
230
- products.forEach(p => {
231
- const variants = getVariants(p, staged)
232
- variants.forEach(v => {
226
+ products.forEach((p) => {
227
+ const variants = getVariants(p)
228
+ variants.forEach((v) => {
233
229
  result.total++
234
230
 
235
231
  let value = resolveVariantValue(v, facet)
@@ -244,7 +240,7 @@ export class ProductProjectionSearch {
244
240
  })
245
241
  })
246
242
  } else {
247
- products.forEach(p => {
243
+ products.forEach((p) => {
248
244
  const value = nestedLookup(p, facet)
249
245
  result.total++
250
246
  if (value === undefined) {
@@ -266,15 +262,14 @@ export class ProductProjectionSearch {
266
262
  filterFacet(
267
263
  source: string,
268
264
  filters: FilterExpression[] | undefined,
269
- products: Product[],
270
- staged: boolean
265
+ products: ProductProjection[]
271
266
  ): FilteredFacetResult {
272
267
  let count = 0
273
268
  if (source.startsWith('variants.')) {
274
269
  for (const p of products) {
275
- for (const v of getVariants(p, staged)) {
270
+ for (const v of getVariants(p)) {
276
271
  const val = resolveVariantValue(v, source)
277
- if (filters?.some(f => f.match(val))) {
272
+ if (filters?.some((f) => f.match(val))) {
278
273
  count++
279
274
  }
280
275
  }
@@ -292,15 +287,14 @@ export class ProductProjectionSearch {
292
287
  rangeFacet(
293
288
  source: string,
294
289
  ranges: RangeExpression[] | undefined,
295
- products: Product[],
296
- staged: boolean
290
+ products: ProductProjection[]
297
291
  ): RangeFacetResult {
298
292
  const counts =
299
- ranges?.map(range => {
293
+ ranges?.map((range) => {
300
294
  if (source.startsWith('variants.')) {
301
295
  const values = []
302
296
  for (const p of products) {
303
- for (const v of getVariants(p, staged)) {
297
+ for (const v of getVariants(p)) {
304
298
  const val = resolveVariantValue(v, source)
305
299
  if (val === undefined) {
306
300
  continue
@@ -1,15 +1,16 @@
1
- import { RepositoryTypes } from './../types'
1
+ import { RepositoryTypes, Resource, Writable } from './../types'
2
2
  import deepEqual from 'deep-equal'
3
3
 
4
4
  import {
5
5
  BaseResource,
6
- InvalidOperationError,
7
6
  Project,
7
+ ResourceNotFoundError,
8
8
  UpdateAction,
9
9
  } from '@commercetools/platform-sdk'
10
10
  import { AbstractStorage } from '../storage'
11
11
  import { checkConcurrentModification } from './errors'
12
12
  import { CommercetoolsError } from '../exceptions'
13
+ import { cloneObject } from '../helpers'
13
14
 
14
15
  export type QueryParams = {
15
16
  expand?: string[]
@@ -39,44 +40,68 @@ export abstract class AbstractRepository {
39
40
  this._storage = storage
40
41
  }
41
42
 
42
- abstract save(
43
+ abstract saveNew({ projectKey }: RepositoryContext, resource: Resource): void
44
+
45
+ abstract saveUpdate(
43
46
  { projectKey }: RepositoryContext,
44
- resource: BaseResource | Project
47
+ version: number,
48
+ resource: Resource
45
49
  ): void
46
50
 
47
- processUpdateActions(
51
+ processUpdateActions<T extends Resource>(
48
52
  context: RepositoryContext,
49
- resource: BaseResource | Project,
53
+ resource: T,
54
+ version: number,
50
55
  actions: UpdateAction[]
51
- ): BaseResource {
56
+ ): T {
52
57
  // Deep-copy
53
- const modifiedResource = JSON.parse(JSON.stringify(resource))
58
+ const updatedResource = cloneObject(resource) as Writable<Resource>
59
+ const identifier = (resource as BaseResource).id
60
+ ? (resource as BaseResource).id
61
+ : (resource as Project).key
54
62
 
55
- actions.forEach(action => {
63
+ actions.forEach((action) => {
56
64
  const updateFunc = this.actions[action.action]
57
65
 
58
66
  if (!updateFunc) {
59
67
  console.error(`No mock implemented for update action ${action.action}`)
60
- return
68
+ throw new Error(
69
+ `No mock implemented for update action ${action.action}`
70
+ )
71
+ }
72
+
73
+ const beforeUpdate = cloneObject(resource)
74
+ updateFunc(context, updatedResource, action)
75
+
76
+ // Check if the object is updated. We need to increase the version of
77
+ // an object per action which does an actual modification.
78
+ // This isn't the most performant method to do this (the update action
79
+ // should return a flag) but for now the easiest.
80
+ if (!deepEqual(beforeUpdate, updatedResource)) {
81
+ // We only check the version when there is an actual modification to
82
+ // be stored.
83
+ checkConcurrentModification(resource.version, version, identifier)
84
+
85
+ updatedResource.version += 1
61
86
  }
62
- updateFunc(context, modifiedResource, action)
63
87
  })
64
88
 
65
- if (!deepEqual(modifiedResource, resource)) {
66
- this.save(context, modifiedResource)
89
+ // If all actions succeeded we write the new version
90
+ // to the storage.
91
+ if (resource.version != updatedResource.version) {
92
+ this.saveUpdate(context, version, updatedResource)
67
93
  }
68
94
 
69
- const result = this.postProcessResource(modifiedResource)
95
+ const result = this.postProcessResource(updatedResource)
70
96
  if (!result) {
71
- throw new Error("invalid post process action")
97
+ throw new Error('invalid post process action')
72
98
  }
73
- return result
99
+ return result as T
74
100
  }
75
101
 
76
- postProcessResource(resource: BaseResource | null): BaseResource | null {
102
+ postProcessResource<T extends Resource>(resource: T): T {
77
103
  return resource
78
104
  }
79
-
80
105
  }
81
106
 
82
107
  export abstract class AbstractResourceRepository extends AbstractRepository {
@@ -85,7 +110,6 @@ export abstract class AbstractResourceRepository extends AbstractRepository {
85
110
 
86
111
  constructor(storage: AbstractStorage) {
87
112
  super(storage)
88
- this._storage.assertStorage(this.getTypeId())
89
113
  }
90
114
 
91
115
  query(context: RepositoryContext, params: QueryParams = {}) {
@@ -98,7 +122,6 @@ export abstract class AbstractResourceRepository extends AbstractRepository {
98
122
 
99
123
  // @ts-ignore
100
124
  result.results = result.results.map(this.postProcessResource)
101
-
102
125
  return result
103
126
  }
104
127
 
@@ -107,8 +130,13 @@ export abstract class AbstractResourceRepository extends AbstractRepository {
107
130
  id: string,
108
131
  params: GetParams = {}
109
132
  ): BaseResource | null {
110
- const resource = this._storage.get(context.projectKey, this.getTypeId(), id, params)
111
- return this.postProcessResource(resource)
133
+ const resource = this._storage.get(
134
+ context.projectKey,
135
+ this.getTypeId(),
136
+ id,
137
+ params
138
+ )
139
+ return resource ? this.postProcessResource(resource) : null
112
140
  }
113
141
 
114
142
  getByKey(
@@ -122,7 +150,7 @@ export abstract class AbstractResourceRepository extends AbstractRepository {
122
150
  key,
123
151
  params
124
152
  )
125
- return this.postProcessResource(resource)
153
+ return resource ? this.postProcessResource(resource) : null
126
154
  }
127
155
 
128
156
  delete(
@@ -136,28 +164,44 @@ export abstract class AbstractResourceRepository extends AbstractRepository {
136
164
  id,
137
165
  params
138
166
  )
139
- return this.postProcessResource(resource)
167
+ return resource ? this.postProcessResource(resource) : null
140
168
  }
141
169
 
142
- save(context: RepositoryContext, resource: BaseResource) {
143
- const current = this.get(context, resource.id)
144
-
145
- if (current) {
146
- checkConcurrentModification(current, resource.version)
147
- } else {
148
- if (resource.version !== 0) {
149
- throw new CommercetoolsError<InvalidOperationError>(
150
- {
151
- code: 'InvalidOperation',
152
- message: 'version on create must be 0',
153
- },
154
- 400
155
- )
156
- }
170
+ saveNew(context: RepositoryContext, resource: Writable<BaseResource>) {
171
+ resource.version = 1
172
+ this._storage.add(context.projectKey, this.getTypeId(), resource as any)
173
+ }
174
+
175
+ saveUpdate(
176
+ context: RepositoryContext,
177
+ version: number,
178
+ resource: Writable<BaseResource>
179
+ ) {
180
+ // Check if the resource still exists.
181
+ const current = this._storage.get(
182
+ context.projectKey,
183
+ this.getTypeId(),
184
+ resource.id
185
+ )
186
+ if (!current) {
187
+ throw new CommercetoolsError<ResourceNotFoundError>(
188
+ {
189
+ code: 'ResourceNotFound',
190
+ message: 'Resource not found while updating',
191
+ },
192
+ 400
193
+ )
157
194
  }
158
195
 
159
- // @ts-ignore
160
- resource.version += 1
196
+ checkConcurrentModification(current.version, version, resource.id)
197
+
198
+ if (current.version === resource.version) {
199
+ throw new Error('Internal error: no changes to save')
200
+ }
201
+ resource.lastModifiedAt = new Date().toISOString()
202
+
161
203
  this._storage.add(context.projectKey, this.getTypeId(), resource as any)
204
+
205
+ return resource
162
206
  }
163
207
  }
@@ -43,7 +43,7 @@ export class CartDiscountRepository extends AbstractResourceRepository {
43
43
  validUntil: draft.validUntil,
44
44
  value: this.transformValueDraft(draft.value),
45
45
  }
46
- this.save(context, resource)
46
+ this.saveNew(context, resource)
47
47
  return resource
48
48
  }
49
49
 
@@ -34,7 +34,7 @@ export class CartRepository extends AbstractResourceRepository {
34
34
 
35
35
  create(context: RepositoryContext, draft: CartDraft): Cart {
36
36
  const lineItems =
37
- draft.lineItems?.map(draftLineItem =>
37
+ draft.lineItems?.map((draftLineItem) =>
38
38
  this.draftLineItemtoLineItem(
39
39
  context.projectKey,
40
40
  draftLineItem,
@@ -43,7 +43,7 @@ export class CartRepository extends AbstractResourceRepository {
43
43
  )
44
44
  ) ?? []
45
45
 
46
- const resource: Cart = {
46
+ const resource: Writable<Cart> = {
47
47
  ...getBaseResourceProperties(),
48
48
  cartState: 'Active',
49
49
  lineItems,
@@ -67,11 +67,9 @@ export class CartRepository extends AbstractResourceRepository {
67
67
  this._storage
68
68
  ),
69
69
  }
70
-
71
- // @ts-ignore
72
70
  resource.totalPrice.centAmount = calculateCartTotalPrice(resource)
73
71
 
74
- this.save(context, resource)
72
+ this.saveNew(context, resource)
75
73
  return resource
76
74
  }
77
75
 
@@ -94,7 +92,6 @@ export class CartRepository extends AbstractResourceRepository {
94
92
  { productId, variantId, sku, quantity = 1 }: CartAddLineItemAction
95
93
  ) => {
96
94
  let product: Product | null = null
97
- let variant: ProductVariant | undefined
98
95
 
99
96
  if (productId && variantId) {
100
97
  // Fetch product and variant by ID
@@ -128,10 +125,10 @@ export class CartRepository extends AbstractResourceRepository {
128
125
  }
129
126
 
130
127
  // Find matching variant
131
- variant = [
128
+ const variant: ProductVariant | undefined = [
132
129
  product.masterData.current.masterVariant,
133
130
  ...product.masterData.current.variants,
134
- ].find(x => {
131
+ ].find((x) => {
135
132
  if (sku) return x.sku === sku
136
133
  if (variantId) return x.id === variantId
137
134
  return false
@@ -148,11 +145,11 @@ export class CartRepository extends AbstractResourceRepository {
148
145
  }
149
146
 
150
147
  const alreadyAdded = resource.lineItems.some(
151
- x => x.productId === product?.id && x.variant.id === variant?.id
148
+ (x) => x.productId === product?.id && x.variant.id === variant?.id
152
149
  )
153
150
  if (alreadyAdded) {
154
151
  // increase quantity and update total price
155
- resource.lineItems.map(x => {
152
+ resource.lineItems.map((x) => {
156
153
  if (x.productId === product?.id && x.variant.id === variant?.id) {
157
154
  x.quantity += quantity
158
155
  x.totalPrice.centAmount = calculateLineItemTotalPrice(x)
@@ -209,7 +206,7 @@ export class CartRepository extends AbstractResourceRepository {
209
206
  resource: Writable<Cart>,
210
207
  { lineItemId, quantity }: CartRemoveLineItemAction
211
208
  ) => {
212
- const lineItem = resource.lineItems.find(x => x.id === lineItemId)
209
+ const lineItem = resource.lineItems.find((x) => x.id === lineItemId)
213
210
  if (!lineItem) {
214
211
  // Check if product is found
215
212
  throw new CommercetoolsError<GeneralError>({
@@ -221,10 +218,12 @@ export class CartRepository extends AbstractResourceRepository {
221
218
  const shouldDelete = !quantity || quantity >= lineItem.quantity
222
219
  if (shouldDelete) {
223
220
  // delete line item
224
- resource.lineItems = resource.lineItems.filter(x => x.id !== lineItemId)
221
+ resource.lineItems = resource.lineItems.filter(
222
+ (x) => x.id !== lineItemId
223
+ )
225
224
  } else {
226
225
  // decrease quantity and update total price
227
- resource.lineItems.map(x => {
226
+ resource.lineItems.map((x) => {
228
227
  if (x.id === lineItemId && quantity) {
229
228
  x.quantity -= quantity
230
229
  x.totalPrice.centAmount = calculateLineItemTotalPrice(x)
@@ -248,21 +247,28 @@ export class CartRepository extends AbstractResourceRepository {
248
247
  resource: Writable<Cart>,
249
248
  { shippingMethod }: CartSetShippingMethodAction
250
249
  ) => {
251
- const resolvedType = this._storage.getByResourceIdentifier(
252
- context.projectKey,
253
- //@ts-ignore
254
- shippingMethod
255
- )
250
+ if (shippingMethod) {
251
+ const method = this._storage.getByResourceIdentifier<'shipping-method'>(
252
+ context.projectKey,
253
+ shippingMethod
254
+ )
256
255
 
257
- if (!resolvedType) {
258
- throw new Error(`Type ${shippingMethod} not found`)
259
- }
260
- //@ts-ignore
261
- resource.shippingInfo = {
262
- shippingMethod: {
263
- typeId: 'shipping-method',
264
- id: resolvedType.id,
265
- },
256
+ if (!method) {
257
+ throw new Error(`Type ${shippingMethod} not found`)
258
+ }
259
+
260
+ // Based on the address we should select a shipping zone and
261
+ // use that to define the price.
262
+ // @ts-ignore
263
+ resource.shippingInfo = {
264
+ shippingMethod: {
265
+ typeId: 'shipping-method',
266
+ id: method.id,
267
+ },
268
+ shippingMethodName: method.name,
269
+ }
270
+ } else {
271
+ resource.shippingInfo = undefined
266
272
  }
267
273
  },
268
274
  setCountry: (
@@ -338,7 +344,6 @@ export class CartRepository extends AbstractResourceRepository {
338
344
  const { productId, quantity, variantId, sku } = draftLineItem
339
345
 
340
346
  let product: Product | null = null
341
- let variant: ProductVariant | undefined
342
347
 
343
348
  if (productId && variantId) {
344
349
  // Fetch product and variant by ID
@@ -367,10 +372,10 @@ export class CartRepository extends AbstractResourceRepository {
367
372
  }
368
373
 
369
374
  // Find matching variant
370
- variant = [
375
+ const variant = [
371
376
  product.masterData.current.masterVariant,
372
377
  ...product.masterData.current.variants,
373
- ].find(x => {
378
+ ].find((x) => {
374
379
  if (sku) return x.sku === sku
375
380
  if (variantId) return x.id === variantId
376
381
  return false
@@ -432,7 +437,7 @@ const selectPrice = ({
432
437
  // Quick-and-dirty way of selecting price based on the given currency and country.
433
438
  // Can be improved later to give more priority to exact matches over
434
439
  // 'all country' matches, and include customer groups in the mix as well
435
- return prices.find(price => {
440
+ return prices.find((price) => {
436
441
  const countryMatch = !price.country || price.country === country
437
442
  const currencyMatch = price.value.currencyCode === currency
438
443
  return countryMatch && currencyMatch
@@ -38,28 +38,26 @@ export class CategoryRepository extends AbstractResourceRepository {
38
38
  : undefined,
39
39
  ancestors: [], // TODO
40
40
  assets:
41
- draft.assets?.map(d => {
42
- return {
43
- id: uuidv4(),
44
- name: d.name,
45
- description: d.description,
46
- sources: d.sources,
47
- tags: d.tags,
48
- key: d.key,
49
- custom: createCustomFields(
50
- draft.custom,
51
- context.projectKey,
52
- this._storage
53
- ),
54
- }
55
- }) || [],
41
+ draft.assets?.map((d) => ({
42
+ id: uuidv4(),
43
+ name: d.name,
44
+ description: d.description,
45
+ sources: d.sources,
46
+ tags: d.tags,
47
+ key: d.key,
48
+ custom: createCustomFields(
49
+ draft.custom,
50
+ context.projectKey,
51
+ this._storage
52
+ ),
53
+ })) || [],
56
54
  custom: createCustomFields(
57
55
  draft.custom,
58
56
  context.projectKey,
59
57
  this._storage
60
58
  ),
61
59
  }
62
- this.save(context, resource)
60
+ this.saveNew(context, resource)
63
61
  return resource
64
62
  }
65
63
 
@@ -69,7 +67,7 @@ export class CategoryRepository extends AbstractResourceRepository {
69
67
  resource: Writable<Category>,
70
68
  { assetId, assetKey, name }: CategoryChangeAssetNameAction
71
69
  ) => {
72
- resource.assets?.forEach(asset => {
70
+ resource.assets?.forEach((asset) => {
73
71
  if (assetId && assetId === asset.id) {
74
72
  asset.name = name
75
73
  }
@@ -97,7 +95,7 @@ export class CategoryRepository extends AbstractResourceRepository {
97
95
  resource: Writable<Category>,
98
96
  { assetId, assetKey, description }: CategorySetAssetDescriptionAction
99
97
  ) => {
100
- resource.assets?.forEach(asset => {
98
+ resource.assets?.forEach((asset) => {
101
99
  if (assetId && assetId === asset.id) {
102
100
  asset.description = description
103
101
  }
@@ -111,7 +109,7 @@ export class CategoryRepository extends AbstractResourceRepository {
111
109
  resource: Writable<Category>,
112
110
  { assetId, assetKey, sources }: CategorySetAssetSourcesAction
113
111
  ) => {
114
- resource.assets?.forEach(asset => {
112
+ resource.assets?.forEach((asset) => {
115
113
  if (assetId && assetId === asset.id) {
116
114
  asset.sources = sources
117
115
  }