@labdigital/commercetools-mock 2.17.1 → 2.18.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 (178) hide show
  1. package/dist/index.cjs +4186 -3974
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +266 -413
  4. package/dist/index.d.ts +266 -413
  5. package/dist/index.js +4186 -3974
  6. package/dist/index.js.map +1 -1
  7. package/package.json +44 -46
  8. package/src/constants.ts +2 -2
  9. package/src/ctMock.test.ts +11 -11
  10. package/src/ctMock.ts +141 -127
  11. package/src/deprecation.ts +8 -0
  12. package/src/exceptions.ts +17 -15
  13. package/src/helpers.ts +32 -32
  14. package/src/index.test.ts +128 -128
  15. package/src/index.ts +3 -3
  16. package/src/lib/expandParser.ts +13 -13
  17. package/src/lib/haversine.test.ts +9 -9
  18. package/src/lib/haversine.ts +11 -11
  19. package/src/lib/masking.ts +11 -11
  20. package/src/lib/parser.ts +2 -2
  21. package/src/lib/password.ts +23 -3
  22. package/src/lib/predicateParser.test.ts +185 -183
  23. package/src/lib/predicateParser.ts +234 -234
  24. package/src/lib/projectionSearchFilter.test.ts +103 -101
  25. package/src/lib/projectionSearchFilter.ts +152 -150
  26. package/src/lib/proxy.ts +5 -5
  27. package/src/oauth/errors.ts +4 -4
  28. package/src/oauth/helpers.ts +6 -6
  29. package/src/oauth/server.test.ts +86 -86
  30. package/src/oauth/server.ts +158 -144
  31. package/src/oauth/store.ts +44 -43
  32. package/src/priceSelector.test.ts +35 -35
  33. package/src/priceSelector.ts +30 -30
  34. package/src/product-projection-search.ts +136 -134
  35. package/src/projectAPI.test.ts +7 -7
  36. package/src/projectAPI.ts +24 -22
  37. package/src/repositories/abstract.ts +168 -116
  38. package/src/repositories/associate-role.ts +90 -77
  39. package/src/repositories/attribute-group.ts +51 -40
  40. package/src/repositories/business-unit.ts +168 -148
  41. package/src/repositories/cart/actions.ts +489 -0
  42. package/src/repositories/cart/helpers.ts +30 -0
  43. package/src/repositories/cart/index.ts +180 -0
  44. package/src/repositories/cart-discount/actions.ts +148 -0
  45. package/src/repositories/cart-discount/index.ts +86 -0
  46. package/src/repositories/category/actions.ts +231 -0
  47. package/src/repositories/category/index.ts +52 -0
  48. package/src/repositories/channel.ts +88 -90
  49. package/src/repositories/custom-object.ts +46 -45
  50. package/src/repositories/customer/actions.ts +165 -0
  51. package/src/repositories/customer/index.ts +79 -0
  52. package/src/repositories/customer-group.ts +66 -55
  53. package/src/repositories/discount-code/actions.ts +149 -0
  54. package/src/repositories/discount-code/index.ts +50 -0
  55. package/src/repositories/errors.ts +10 -10
  56. package/src/repositories/extension.ts +64 -62
  57. package/src/repositories/helpers.ts +117 -118
  58. package/src/repositories/index.ts +80 -79
  59. package/src/repositories/inventory-entry/actions.ts +84 -0
  60. package/src/repositories/inventory-entry/index.ts +44 -0
  61. package/src/repositories/my-customer.ts +114 -0
  62. package/src/repositories/my-order.ts +8 -8
  63. package/src/repositories/order/actions.ts +281 -0
  64. package/src/repositories/{order.test.ts → order/index.test.ts} +77 -77
  65. package/src/repositories/order/index.ts +260 -0
  66. package/src/repositories/order-edit.ts +10 -23
  67. package/src/repositories/payment/actions.ts +305 -0
  68. package/src/repositories/payment/helpers.ts +17 -0
  69. package/src/repositories/payment/index.ts +56 -0
  70. package/src/repositories/product/actions.ts +943 -0
  71. package/src/repositories/product/helpers.ts +98 -0
  72. package/src/repositories/product/index.ts +130 -0
  73. package/src/repositories/product-discount.ts +127 -117
  74. package/src/repositories/product-projection.ts +56 -62
  75. package/src/repositories/product-selection.ts +31 -28
  76. package/src/repositories/product-type.ts +136 -134
  77. package/src/repositories/project.ts +133 -118
  78. package/src/repositories/quote-request.ts +7 -19
  79. package/src/repositories/quote.ts +7 -22
  80. package/src/repositories/review.ts +13 -26
  81. package/src/repositories/shipping-method/actions.ts +198 -0
  82. package/src/repositories/shipping-method/helpers.ts +10 -0
  83. package/src/repositories/shipping-method/index.ts +138 -0
  84. package/src/repositories/shopping-list/actions.ts +295 -0
  85. package/src/repositories/shopping-list/index.ts +122 -0
  86. package/src/repositories/staged-quote.ts +7 -20
  87. package/src/repositories/standalone-price.ts +57 -44
  88. package/src/repositories/state.ts +113 -68
  89. package/src/repositories/store.ts +106 -94
  90. package/src/repositories/subscription.ts +46 -22
  91. package/src/repositories/tax-category/actions.ts +94 -0
  92. package/src/repositories/tax-category/helpers.ts +8 -0
  93. package/src/repositories/tax-category/index.ts +25 -0
  94. package/src/repositories/type/actions.ts +162 -0
  95. package/src/repositories/type/index.ts +24 -0
  96. package/src/repositories/zone.ts +62 -58
  97. package/src/server.ts +9 -9
  98. package/src/services/abstract.ts +75 -72
  99. package/src/services/associate-roles.test.ts +27 -27
  100. package/src/services/associate-roles.ts +7 -7
  101. package/src/services/attribute-group.ts +7 -7
  102. package/src/services/business-units.test.ts +28 -28
  103. package/src/services/business-units.ts +7 -7
  104. package/src/services/cart-discount.test.ts +199 -199
  105. package/src/services/cart-discount.ts +7 -7
  106. package/src/services/cart.test.ts +261 -261
  107. package/src/services/cart.ts +22 -21
  108. package/src/services/category.test.ts +121 -121
  109. package/src/services/category.ts +7 -7
  110. package/src/services/channel.ts +7 -7
  111. package/src/services/custom-object.test.ts +130 -130
  112. package/src/services/custom-object.ts +34 -31
  113. package/src/services/customer-group.ts +7 -7
  114. package/src/services/customer.test.ts +205 -205
  115. package/src/services/customer.ts +23 -36
  116. package/src/services/discount-code.ts +7 -7
  117. package/src/services/extension.ts +7 -7
  118. package/src/services/index.ts +85 -81
  119. package/src/services/inventory-entry.test.ts +106 -106
  120. package/src/services/inventory-entry.ts +7 -7
  121. package/src/services/my-cart.test.ts +56 -56
  122. package/src/services/my-cart.ts +20 -20
  123. package/src/services/my-customer.test.ts +155 -104
  124. package/src/services/my-customer.ts +61 -75
  125. package/src/services/my-order.ts +16 -16
  126. package/src/services/my-payment.test.ts +40 -40
  127. package/src/services/my-payment.ts +7 -7
  128. package/src/services/my-shopping-list.ts +7 -7
  129. package/src/services/order.test.ts +243 -243
  130. package/src/services/order.ts +23 -18
  131. package/src/services/payment.test.ts +40 -40
  132. package/src/services/payment.ts +7 -7
  133. package/src/services/product-discount.ts +7 -7
  134. package/src/services/product-projection.test.ts +190 -190
  135. package/src/services/product-projection.ts +34 -32
  136. package/src/services/product-selection.test.ts +19 -19
  137. package/src/services/product-selection.ts +7 -7
  138. package/src/services/product-type.test.ts +38 -38
  139. package/src/services/product-type.ts +7 -7
  140. package/src/services/product.test.ts +658 -656
  141. package/src/services/product.ts +7 -7
  142. package/src/services/project.test.ts +24 -24
  143. package/src/services/project.ts +17 -17
  144. package/src/services/reviews.ts +7 -7
  145. package/src/services/shipping-method.test.ts +78 -78
  146. package/src/services/shipping-method.ts +16 -16
  147. package/src/services/shopping-list.test.ts +170 -170
  148. package/src/services/shopping-list.ts +7 -7
  149. package/src/services/standalone-price.test.ts +112 -112
  150. package/src/services/standalone-price.ts +7 -7
  151. package/src/services/state.test.ts +30 -30
  152. package/src/services/state.ts +7 -7
  153. package/src/services/store.test.ts +40 -40
  154. package/src/services/store.ts +7 -7
  155. package/src/services/subscription.ts +7 -7
  156. package/src/services/tax-category.test.ts +43 -43
  157. package/src/services/tax-category.ts +7 -7
  158. package/src/services/type.ts +7 -7
  159. package/src/services/zone.ts +7 -7
  160. package/src/shippingCalculator.test.ts +43 -43
  161. package/src/shippingCalculator.ts +23 -23
  162. package/src/storage/abstract.ts +36 -34
  163. package/src/storage/in-memory.ts +237 -233
  164. package/src/storage/index.ts +2 -2
  165. package/src/types.ts +91 -91
  166. package/src/repositories/cart-discount.ts +0 -219
  167. package/src/repositories/cart.ts +0 -659
  168. package/src/repositories/category.ts +0 -256
  169. package/src/repositories/customer.ts +0 -228
  170. package/src/repositories/discount-code.ts +0 -181
  171. package/src/repositories/inventory-entry.ts +0 -109
  172. package/src/repositories/order.ts +0 -514
  173. package/src/repositories/payment.ts +0 -342
  174. package/src/repositories/product.ts +0 -1106
  175. package/src/repositories/shipping-method.ts +0 -312
  176. package/src/repositories/shopping-list.ts +0 -392
  177. package/src/repositories/tax-category.ts +0 -111
  178. package/src/repositories/type.ts +0 -172
@@ -1,659 +0,0 @@
1
- import {
2
- type Address,
3
- type AddressDraft,
4
- type Cart,
5
- type CartAddLineItemAction,
6
- type CartChangeLineItemQuantityAction,
7
- type CartAddItemShippingAddressAction,
8
- type CartSetLineItemShippingDetailsAction,
9
- type CartDraft,
10
- type CartRemoveLineItemAction,
11
- type CartSetBillingAddressAction,
12
- type CartSetCountryAction,
13
- type CartSetCustomerEmailAction,
14
- type CartSetCustomFieldAction,
15
- type CartSetCustomTypeAction,
16
- type CartSetLocaleAction,
17
- type CartSetShippingAddressAction,
18
- type CartSetShippingMethodAction,
19
- type CustomFields,
20
- type GeneralError,
21
- type LineItem,
22
- type LineItemDraft,
23
- type ItemShippingDetails,
24
- type Price,
25
- type Product,
26
- type ProductPagedQueryResponse,
27
- type CartRemoveDiscountCodeAction,
28
- type ProductVariant,
29
- type CartSetCustomShippingMethodAction,
30
- type CartSetDirectDiscountsAction,
31
- } from '@commercetools/platform-sdk'
32
- import { v4 as uuidv4 } from 'uuid'
33
- import { CommercetoolsError } from '../exceptions.js'
34
- import { getBaseResourceProperties } from '../helpers.js'
35
- import type { Writable } from '../types.js'
36
- import {
37
- AbstractResourceRepository,
38
- type RepositoryContext,
39
- } from './abstract.js'
40
- import {
41
- createAddress,
42
- createCentPrecisionMoney,
43
- createCustomFields,
44
- createTypedMoney,
45
- } from './helpers.js'
46
-
47
- export class CartRepository extends AbstractResourceRepository<'cart'> {
48
- getTypeId() {
49
- return 'cart' as const
50
- }
51
-
52
- create(context: RepositoryContext, draft: CartDraft): Cart {
53
- const lineItems =
54
- draft.lineItems?.map((draftLineItem) =>
55
- this.draftLineItemtoLineItem(
56
- context.projectKey,
57
- draftLineItem,
58
- draft.currency,
59
- draft.country
60
- )
61
- ) ?? []
62
-
63
- const resource: Writable<Cart> = {
64
- ...getBaseResourceProperties(),
65
- cartState: 'Active',
66
- country: draft.country,
67
- customLineItems: [],
68
- directDiscounts: [],
69
- discountCodes: [],
70
- inventoryMode: 'None',
71
- itemShippingAddresses: [],
72
- lineItems,
73
- locale: draft.locale,
74
- taxCalculationMode: draft.taxCalculationMode ?? 'LineItemLevel',
75
- taxMode: draft.taxMode ?? 'Platform',
76
- taxRoundingMode: draft.taxRoundingMode ?? 'HalfEven',
77
- totalPrice: {
78
- type: 'centPrecision',
79
- centAmount: 0,
80
- currencyCode: draft.currency,
81
- fractionDigits: 0,
82
- },
83
- shippingMode: 'Single',
84
- shippingAddress: createAddress(
85
- draft.shippingAddress,
86
- context.projectKey,
87
- this._storage
88
- ),
89
- shipping: [],
90
- origin: draft.origin ?? 'Customer',
91
- refusedGifts: [],
92
- custom: createCustomFields(
93
- draft.custom,
94
- context.projectKey,
95
- this._storage
96
- ),
97
- }
98
- resource.totalPrice.centAmount = calculateCartTotalPrice(resource)
99
-
100
- this.saveNew(context, resource)
101
- return resource
102
- }
103
-
104
- getActiveCart(projectKey: string): Cart | undefined {
105
- // Get first active cart
106
- const results = this._storage.query(projectKey, this.getTypeId(), {
107
- where: [`cartState="Active"`],
108
- })
109
- if (results.count > 0) {
110
- return results.results[0] as Cart
111
- }
112
-
113
- return
114
- }
115
-
116
- actions = {
117
- addLineItem: (
118
- context: RepositoryContext,
119
- resource: Writable<Cart>,
120
- { productId, variantId, sku, quantity = 1 }: CartAddLineItemAction
121
- ) => {
122
- let product: Product | null = null
123
-
124
- if (productId && variantId) {
125
- // Fetch product and variant by ID
126
- product = this._storage.get(
127
- context.projectKey,
128
- 'product',
129
- productId,
130
- {}
131
- )
132
- } else if (sku) {
133
- // Fetch product and variant by SKU
134
- const items = this._storage.query(context.projectKey, 'product', {
135
- where: [
136
- `masterData(current(masterVariant(sku="${sku}"))) or masterData(current(variants(sku="${sku}")))`,
137
- ],
138
- }) as ProductPagedQueryResponse
139
-
140
- if (items.count === 1) {
141
- product = items.results[0]
142
- }
143
- }
144
-
145
- if (!product) {
146
- // Check if product is found
147
- throw new CommercetoolsError<GeneralError>({
148
- code: 'General',
149
- message: sku
150
- ? `A product containing a variant with SKU '${sku}' not found.`
151
- : `A product with ID '${productId}' not found.`,
152
- })
153
- }
154
-
155
- // Find matching variant
156
- const variant: ProductVariant | undefined = [
157
- product.masterData.current.masterVariant,
158
- ...product.masterData.current.variants,
159
- ].find((x) => {
160
- if (sku) return x.sku === sku
161
- if (variantId) return x.id === variantId
162
- return false
163
- })
164
-
165
- if (!variant) {
166
- // Check if variant is found
167
- throw new CommercetoolsError<GeneralError>({
168
- code: 'General',
169
- message: sku
170
- ? `A variant with SKU '${sku}' for product '${product.id}' not found.`
171
- : `A variant with ID '${variantId}' for product '${product.id}' not found.`,
172
- })
173
- }
174
-
175
- const alreadyAdded = resource.lineItems.some(
176
- (x) => x.productId === product?.id && x.variant.id === variant?.id
177
- )
178
- if (alreadyAdded) {
179
- // increase quantity and update total price
180
- resource.lineItems.forEach((x) => {
181
- if (x.productId === product?.id && x.variant.id === variant?.id) {
182
- x.quantity += quantity
183
- x.totalPrice.centAmount = calculateLineItemTotalPrice(x)
184
- }
185
- })
186
- } else {
187
- // add line item
188
- if (!variant.prices?.length) {
189
- throw new CommercetoolsError<GeneralError>({
190
- code: 'General',
191
- message: `A product with ID '${productId}' doesn't have any prices.`,
192
- })
193
- }
194
-
195
- const currency = resource.totalPrice.currencyCode
196
-
197
- const price = selectPrice({
198
- prices: variant.prices,
199
- currency,
200
- country: resource.country,
201
- })
202
- if (!price) {
203
- throw new Error(
204
- `No valid price found for ${productId} for country ${resource.country} and currency ${currency}`
205
- )
206
- }
207
- resource.lineItems.push({
208
- id: uuidv4(),
209
- productId: product.id,
210
- productKey: product.key,
211
- productSlug: product.masterData.current.slug,
212
- productType: product.productType,
213
- name: product.masterData.current.name,
214
- variant,
215
- price: price,
216
- taxedPricePortions: [],
217
- perMethodTaxRate: [],
218
- totalPrice: {
219
- ...price.value,
220
- type: 'centPrecision',
221
- centAmount: price.value.centAmount * quantity,
222
- },
223
- quantity,
224
- discountedPricePerQuantity: [],
225
- lineItemMode: 'Standard',
226
- priceMode: 'Platform',
227
- state: [],
228
- })
229
- }
230
-
231
- // Update cart total price
232
- resource.totalPrice.centAmount = calculateCartTotalPrice(resource)
233
- },
234
- recalculate: () => {
235
- // Dummy action when triggering a recalculation of the cart
236
- //
237
- // From commercetools documentation:
238
- // This update action does not set any Cart field in particular,
239
- // but it triggers several Cart updates to bring prices and discounts to the latest state.
240
- // Those can become stale over time when no Cart updates have been performed for a while
241
- // and prices on related Products have changed in the meanwhile.
242
- },
243
- addItemShippingAddress: (
244
- context: RepositoryContext,
245
- resource: Writable<Cart>,
246
- { action, address }: CartAddItemShippingAddressAction
247
- ) => {
248
- const newAddress = createAddress(
249
- address,
250
- context.projectKey,
251
- this._storage
252
- )
253
- if (newAddress) {
254
- resource.itemShippingAddresses.push(newAddress)
255
- }
256
- },
257
- changeLineItemQuantity: (
258
- context: RepositoryContext,
259
- resource: Writable<Cart>,
260
- { lineItemId, lineItemKey, quantity }: CartChangeLineItemQuantityAction
261
- ) => {
262
- let lineItem: Writable<LineItem> | undefined
263
-
264
- if (lineItemId) {
265
- lineItem = resource.lineItems.find((x) => x.id === lineItemId)
266
- if (!lineItem) {
267
- throw new CommercetoolsError<GeneralError>({
268
- code: 'General',
269
- message: `A line item with ID '${lineItemId}' not found.`,
270
- })
271
- }
272
- } else if (lineItemKey) {
273
- lineItem = resource.lineItems.find((x) => x.id === lineItemId)
274
- if (!lineItem) {
275
- throw new CommercetoolsError<GeneralError>({
276
- code: 'General',
277
- message: `A line item with Key '${lineItemKey}' not found.`,
278
- })
279
- }
280
- } else {
281
- throw new CommercetoolsError<GeneralError>({
282
- code: 'General',
283
- message: `Either lineItemid or lineItemKey needs to be provided.`,
284
- })
285
- }
286
-
287
- if (quantity === 0) {
288
- // delete line item
289
- resource.lineItems = resource.lineItems.filter(
290
- (x) => x.id !== lineItemId
291
- )
292
- } else {
293
- resource.lineItems.forEach((x) => {
294
- if (x.id === lineItemId && quantity) {
295
- x.quantity = quantity
296
- x.totalPrice.centAmount = calculateLineItemTotalPrice(x)
297
- }
298
- })
299
- }
300
-
301
- // Update cart total price
302
- resource.totalPrice.centAmount = calculateCartTotalPrice(resource)
303
- },
304
- removeLineItem: (
305
- context: RepositoryContext,
306
- resource: Writable<Cart>,
307
- { lineItemId, quantity }: CartRemoveLineItemAction
308
- ) => {
309
- const lineItem = resource.lineItems.find((x) => x.id === lineItemId)
310
- if (!lineItem) {
311
- // Check if product is found
312
- throw new CommercetoolsError<GeneralError>({
313
- code: 'General',
314
- message: `A line item with ID '${lineItemId}' not found.`,
315
- })
316
- }
317
-
318
- const shouldDelete = !quantity || quantity >= lineItem.quantity
319
- if (shouldDelete) {
320
- // delete line item
321
- resource.lineItems = resource.lineItems.filter(
322
- (x) => x.id !== lineItemId
323
- )
324
- } else {
325
- // decrease quantity and update total price
326
- resource.lineItems.forEach((x) => {
327
- if (x.id === lineItemId && quantity) {
328
- x.quantity -= quantity
329
- x.totalPrice.centAmount = calculateLineItemTotalPrice(x)
330
- }
331
- })
332
- }
333
-
334
- // Update cart total price
335
- resource.totalPrice.centAmount = calculateCartTotalPrice(resource)
336
- },
337
- setBillingAddress: (
338
- context: RepositoryContext,
339
- resource: Writable<Cart>,
340
- { address }: CartSetBillingAddressAction
341
- ) => {
342
- resource.billingAddress = createAddress(
343
- address,
344
- context.projectKey,
345
- this._storage
346
- )
347
- },
348
- setShippingMethod: (
349
- context: RepositoryContext,
350
- resource: Writable<Cart>,
351
- { shippingMethod }: CartSetShippingMethodAction
352
- ) => {
353
- if (shippingMethod) {
354
- const method = this._storage.getByResourceIdentifier<'shipping-method'>(
355
- context.projectKey,
356
- shippingMethod
357
- )
358
-
359
- // Based on the address we should select a shipping zone and
360
- // use that to define the price.
361
- // @ts-ignore
362
- resource.shippingInfo = {
363
- shippingMethod: {
364
- typeId: 'shipping-method',
365
- id: method.id,
366
- },
367
- shippingMethodName: method.name,
368
- }
369
- } else {
370
- resource.shippingInfo = undefined
371
- }
372
- },
373
- setCountry: (
374
- context: RepositoryContext,
375
- resource: Writable<Cart>,
376
- { country }: CartSetCountryAction
377
- ) => {
378
- resource.country = country
379
- },
380
- setCustomerEmail: (
381
- context: RepositoryContext,
382
- resource: Writable<Cart>,
383
- { email }: CartSetCustomerEmailAction
384
- ) => {
385
- resource.customerEmail = email
386
- },
387
- setCustomField: (
388
- context: RepositoryContext,
389
- resource: Cart,
390
- { name, value }: CartSetCustomFieldAction
391
- ) => {
392
- if (!resource.custom) {
393
- throw new Error('Resource has no custom field')
394
- }
395
- resource.custom.fields[name] = value
396
- },
397
- setCustomShippingMethod: (
398
- context: RepositoryContext,
399
- resource: Writable<Cart>,
400
- {
401
- shippingMethodName,
402
- shippingRate,
403
- taxCategory,
404
- externalTaxRate,
405
- }: CartSetCustomShippingMethodAction
406
- ) => {
407
- if (externalTaxRate) {
408
- throw new Error('External tax rate is not supported')
409
- }
410
-
411
- const tax = taxCategory
412
- ? this._storage.getByResourceIdentifier<'tax-category'>(
413
- context.projectKey,
414
- taxCategory
415
- )
416
- : undefined
417
-
418
- resource.shippingInfo = {
419
- shippingMethodName,
420
- price: createCentPrecisionMoney(shippingRate.price),
421
- shippingRate: {
422
- price: createTypedMoney(shippingRate.price),
423
- tiers: [],
424
- },
425
- taxCategory: tax
426
- ? {
427
- typeId: 'tax-category',
428
- id: tax?.id,
429
- }
430
- : undefined,
431
- shippingMethodState: 'MatchesCart',
432
- }
433
- },
434
- setCustomType: (
435
- context: RepositoryContext,
436
- resource: Writable<Cart>,
437
- { type, fields }: CartSetCustomTypeAction
438
- ) => {
439
- if (!type) {
440
- resource.custom = undefined
441
- } else {
442
- const resolvedType = this._storage.getByResourceIdentifier(
443
- context.projectKey,
444
- type
445
- )
446
- if (!resolvedType) {
447
- throw new Error(`Type ${type} not found`)
448
- }
449
-
450
- resource.custom = {
451
- type: {
452
- typeId: 'type',
453
- id: resolvedType.id,
454
- },
455
- fields: fields || {},
456
- }
457
- }
458
- },
459
- setDirectDiscounts: (
460
- context: RepositoryContext,
461
- resource: Writable<Cart>,
462
- { discounts }: CartSetDirectDiscountsAction
463
- ) => {
464
- // Doesn't apply any discounts logic, just sets the directDiscounts field
465
- resource.directDiscounts = discounts.map((discount) => ({
466
- ...discount,
467
- id: uuidv4(),
468
- }))
469
- },
470
- setLocale: (
471
- context: RepositoryContext,
472
- resource: Writable<Cart>,
473
- { locale }: CartSetLocaleAction
474
- ) => {
475
- resource.locale = locale
476
- },
477
- setLineItemShippingDetails: (
478
- context: RepositoryContext,
479
- resource: Writable<Cart>,
480
- {
481
- action,
482
- shippingDetails,
483
- lineItemId,
484
- lineItemKey,
485
- }: CartSetLineItemShippingDetailsAction
486
- ) => {
487
- const lineItem = resource.lineItems.find(
488
- (x) =>
489
- (lineItemId && x.id === lineItemId) ||
490
- (lineItemKey && x.key === lineItemKey)
491
- )
492
-
493
- if (!lineItem) {
494
- // Check if line item is found
495
- throw new CommercetoolsError<GeneralError>({
496
- code: 'General',
497
- message: lineItemKey
498
- ? `A line item with key '${lineItemKey}' not found.`
499
- : `A line item with ID '${lineItemId}' not found.`,
500
- })
501
- }
502
-
503
- lineItem.shippingDetails = {
504
- ...shippingDetails,
505
- valid: true,
506
- } as ItemShippingDetails
507
- },
508
- setShippingAddress: (
509
- context: RepositoryContext,
510
- resource: Writable<Cart>,
511
- { address }: CartSetShippingAddressAction
512
- ) => {
513
- if (!address) {
514
- resource.shippingAddress = undefined
515
- return
516
- }
517
-
518
- let custom: CustomFields | undefined = undefined
519
- if ((address as Address & AddressDraft).custom) {
520
- custom = createCustomFields(
521
- (address as Address & AddressDraft).custom,
522
- context.projectKey,
523
- this._storage
524
- )
525
- }
526
-
527
- resource.shippingAddress = {
528
- ...address,
529
- custom: custom,
530
- }
531
- },
532
- removeDiscountCode: (
533
- context: RepositoryContext,
534
- resource: Writable<Cart>,
535
- { discountCode }: CartRemoveDiscountCodeAction
536
- ) => {
537
- resource.discountCodes = resource.discountCodes.filter(
538
- (code) => code.discountCode.id !== discountCode.id
539
- )
540
- },
541
- }
542
- draftLineItemtoLineItem = (
543
- projectKey: string,
544
- draftLineItem: LineItemDraft,
545
- currency: string,
546
- country: string | undefined
547
- ): LineItem => {
548
- const { productId, quantity, variantId, sku } = draftLineItem
549
-
550
- let product: Product | null = null
551
-
552
- if (productId && variantId) {
553
- // Fetch product and variant by ID
554
- product = this._storage.get(projectKey, 'product', productId, {})
555
- } else if (sku) {
556
- // Fetch product and variant by SKU
557
- const items = this._storage.query(projectKey, 'product', {
558
- where: [
559
- `masterData(current(masterVariant(sku="${sku}"))) or masterData(current(variants(sku="${sku}")))`,
560
- ],
561
- }) as ProductPagedQueryResponse
562
-
563
- if (items.count === 1) {
564
- product = items.results[0]
565
- }
566
- }
567
-
568
- if (!product) {
569
- // Check if product is found
570
- throw new CommercetoolsError<GeneralError>({
571
- code: 'General',
572
- message: sku
573
- ? `A product containing a variant with SKU '${sku}' not found.`
574
- : `A product with ID '${productId}' not found.`,
575
- })
576
- }
577
-
578
- // Find matching variant
579
- const variant = [
580
- product.masterData.current.masterVariant,
581
- ...product.masterData.current.variants,
582
- ].find((x) => {
583
- if (sku) return x.sku === sku
584
- if (variantId) return x.id === variantId
585
- return false
586
- })
587
-
588
- if (!variant) {
589
- // Check if variant is found
590
- throw new Error(
591
- sku
592
- ? `A variant with SKU '${sku}' for product '${product.id}' not found.`
593
- : `A variant with ID '${variantId}' for product '${product.id}' not found.`
594
- )
595
- }
596
-
597
- const quant = quantity ?? 1
598
-
599
- const price = selectPrice({ prices: variant.prices, currency, country })
600
- if (!price) {
601
- throw new Error(
602
- `No valid price found for ${productId} for country ${country} and currency ${currency}`
603
- )
604
- }
605
-
606
- return {
607
- id: uuidv4(),
608
- productId: product.id,
609
- productKey: product.key,
610
- productSlug: product.masterData.current.slug,
611
- productType: product.productType,
612
- name: product.masterData.current.name,
613
- variant,
614
- price: price,
615
- totalPrice: {
616
- type: 'centPrecision',
617
- currencyCode: price.value.currencyCode,
618
- fractionDigits: price.value.fractionDigits,
619
- centAmount: price.value.centAmount * quant,
620
- },
621
- taxedPricePortions: [],
622
- perMethodTaxRate: [],
623
- quantity: quant,
624
- discountedPricePerQuantity: [],
625
- lineItemMode: 'Standard',
626
- priceMode: 'Platform',
627
- state: [],
628
- }
629
- }
630
- }
631
-
632
- const selectPrice = ({
633
- prices,
634
- currency,
635
- country,
636
- }: {
637
- prices: Price[] | undefined
638
- currency: string
639
- country: string | undefined
640
- }): Price | undefined => {
641
- if (!prices) {
642
- return undefined
643
- }
644
-
645
- // Quick-and-dirty way of selecting price based on the given currency and country.
646
- // Can be improved later to give more priority to exact matches over
647
- // 'all country' matches, and include customer groups in the mix as well
648
- return prices.find((price) => {
649
- const countryMatch = !price.country || price.country === country
650
- const currencyMatch = price.value.currencyCode === currency
651
- return countryMatch && currencyMatch
652
- })
653
- }
654
-
655
- const calculateLineItemTotalPrice = (lineItem: LineItem): number =>
656
- lineItem.price!.value.centAmount * lineItem.quantity
657
-
658
- const calculateCartTotalPrice = (cart: Cart): number =>
659
- cart.lineItems.reduce((cur, item) => cur + item.totalPrice.centAmount, 0)