@labdigital/commercetools-mock 2.17.1 → 2.18.1
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/dist/index.cjs +4351 -4099
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +266 -413
- package/dist/index.d.ts +266 -413
- package/dist/index.js +4351 -4099
- package/dist/index.js.map +1 -1
- package/package.json +47 -47
- package/src/constants.ts +2 -2
- package/src/ctMock.test.ts +11 -11
- package/src/ctMock.ts +141 -127
- package/src/deprecation.ts +8 -0
- package/src/exceptions.ts +17 -15
- package/src/helpers.ts +32 -32
- package/src/index.test.ts +128 -128
- package/src/index.ts +3 -3
- package/src/lib/expandParser.ts +13 -13
- package/src/lib/haversine.test.ts +9 -9
- package/src/lib/haversine.ts +11 -11
- package/src/lib/masking.ts +11 -11
- package/src/lib/parser.ts +2 -2
- package/src/lib/password.ts +23 -3
- package/src/lib/predicateParser.test.ts +185 -183
- package/src/lib/predicateParser.ts +234 -234
- package/src/lib/projectionSearchFilter.test.ts +103 -101
- package/src/lib/projectionSearchFilter.ts +152 -150
- package/src/lib/proxy.ts +5 -5
- package/src/oauth/errors.ts +4 -4
- package/src/oauth/helpers.ts +6 -6
- package/src/oauth/server.test.ts +86 -86
- package/src/oauth/server.ts +158 -144
- package/src/oauth/store.ts +44 -43
- package/src/priceSelector.test.ts +35 -35
- package/src/priceSelector.ts +30 -30
- package/src/product-projection-search.ts +136 -134
- package/src/projectAPI.test.ts +7 -7
- package/src/projectAPI.ts +24 -22
- package/src/repositories/abstract.ts +168 -116
- package/src/repositories/associate-role.ts +90 -77
- package/src/repositories/attribute-group.ts +51 -40
- package/src/repositories/business-unit.ts +168 -148
- package/src/repositories/cart/actions.ts +489 -0
- package/src/repositories/cart/helpers.ts +30 -0
- package/src/repositories/cart/index.ts +180 -0
- package/src/repositories/cart-discount/actions.ts +148 -0
- package/src/repositories/cart-discount/index.ts +86 -0
- package/src/repositories/category/actions.ts +231 -0
- package/src/repositories/category/index.ts +52 -0
- package/src/repositories/channel.ts +88 -90
- package/src/repositories/custom-object.ts +46 -45
- package/src/repositories/customer/actions.ts +165 -0
- package/src/repositories/customer/index.ts +79 -0
- package/src/repositories/customer-group.ts +66 -55
- package/src/repositories/discount-code/actions.ts +149 -0
- package/src/repositories/discount-code/index.ts +50 -0
- package/src/repositories/errors.ts +10 -10
- package/src/repositories/extension.ts +64 -62
- package/src/repositories/helpers.ts +117 -118
- package/src/repositories/index.ts +80 -79
- package/src/repositories/inventory-entry/actions.ts +84 -0
- package/src/repositories/inventory-entry/index.ts +44 -0
- package/src/repositories/my-customer.ts +114 -0
- package/src/repositories/my-order.ts +8 -8
- package/src/repositories/order/actions.ts +281 -0
- package/src/repositories/{order.test.ts → order/index.test.ts} +77 -77
- package/src/repositories/order/index.ts +260 -0
- package/src/repositories/order-edit.ts +10 -23
- package/src/repositories/payment/actions.ts +305 -0
- package/src/repositories/payment/helpers.ts +17 -0
- package/src/repositories/payment/index.ts +56 -0
- package/src/repositories/product/actions.ts +943 -0
- package/src/repositories/product/helpers.ts +98 -0
- package/src/repositories/product/index.ts +130 -0
- package/src/repositories/product-discount.ts +127 -117
- package/src/repositories/product-projection.ts +56 -62
- package/src/repositories/product-selection.ts +31 -28
- package/src/repositories/product-type.ts +136 -134
- package/src/repositories/project.ts +133 -118
- package/src/repositories/quote-request.ts +7 -19
- package/src/repositories/quote.ts +7 -22
- package/src/repositories/review.ts +13 -26
- package/src/repositories/shipping-method/actions.ts +198 -0
- package/src/repositories/shipping-method/helpers.ts +10 -0
- package/src/repositories/shipping-method/index.ts +138 -0
- package/src/repositories/shopping-list/actions.ts +295 -0
- package/src/repositories/shopping-list/index.ts +122 -0
- package/src/repositories/staged-quote.ts +7 -20
- package/src/repositories/standalone-price.ts +57 -44
- package/src/repositories/state.ts +113 -68
- package/src/repositories/store.ts +106 -94
- package/src/repositories/subscription.ts +46 -22
- package/src/repositories/tax-category/actions.ts +94 -0
- package/src/repositories/tax-category/helpers.ts +8 -0
- package/src/repositories/tax-category/index.ts +25 -0
- package/src/repositories/type/actions.ts +162 -0
- package/src/repositories/type/index.ts +24 -0
- package/src/repositories/zone.ts +62 -58
- package/src/schemas/update-request.ts +12 -0
- package/src/server.ts +9 -9
- package/src/services/abstract.ts +85 -72
- package/src/services/associate-roles.test.ts +27 -27
- package/src/services/associate-roles.ts +7 -7
- package/src/services/attribute-group.ts +7 -7
- package/src/services/business-units.test.ts +28 -28
- package/src/services/business-units.ts +7 -7
- package/src/services/cart-discount.test.ts +199 -199
- package/src/services/cart-discount.ts +7 -7
- package/src/services/cart.test.ts +261 -261
- package/src/services/cart.ts +22 -21
- package/src/services/category.test.ts +121 -121
- package/src/services/category.ts +7 -7
- package/src/services/channel.ts +7 -7
- package/src/services/custom-object.test.ts +130 -130
- package/src/services/custom-object.ts +34 -31
- package/src/services/customer-group.ts +7 -7
- package/src/services/customer.test.ts +205 -205
- package/src/services/customer.ts +23 -36
- package/src/services/discount-code.ts +7 -7
- package/src/services/extension.ts +7 -7
- package/src/services/index.ts +85 -81
- package/src/services/inventory-entry.test.ts +106 -106
- package/src/services/inventory-entry.ts +7 -7
- package/src/services/my-cart.test.ts +56 -56
- package/src/services/my-cart.ts +20 -20
- package/src/services/my-customer.test.ts +155 -104
- package/src/services/my-customer.ts +66 -75
- package/src/services/my-order.ts +16 -16
- package/src/services/my-payment.test.ts +40 -40
- package/src/services/my-payment.ts +7 -7
- package/src/services/my-shopping-list.ts +7 -7
- package/src/services/order.test.ts +243 -243
- package/src/services/order.ts +23 -18
- package/src/services/payment.test.ts +40 -40
- package/src/services/payment.ts +7 -7
- package/src/services/product-discount.ts +7 -7
- package/src/services/product-projection.test.ts +190 -190
- package/src/services/product-projection.ts +34 -32
- package/src/services/product-selection.test.ts +19 -19
- package/src/services/product-selection.ts +7 -7
- package/src/services/product-type.test.ts +38 -38
- package/src/services/product-type.ts +7 -7
- package/src/services/product.test.ts +658 -656
- package/src/services/product.ts +7 -7
- package/src/services/project.test.ts +29 -24
- package/src/services/project.ts +22 -17
- package/src/services/reviews.ts +7 -7
- package/src/services/shipping-method.test.ts +78 -78
- package/src/services/shipping-method.ts +16 -16
- package/src/services/shopping-list.test.ts +170 -170
- package/src/services/shopping-list.ts +7 -7
- package/src/services/standalone-price.test.ts +112 -112
- package/src/services/standalone-price.ts +7 -7
- package/src/services/state.test.ts +30 -30
- package/src/services/state.ts +7 -7
- package/src/services/store.test.ts +40 -40
- package/src/services/store.ts +7 -7
- package/src/services/subscription.ts +7 -7
- package/src/services/tax-category.test.ts +43 -43
- package/src/services/tax-category.ts +7 -7
- package/src/services/type.ts +7 -7
- package/src/services/zone.ts +7 -7
- package/src/shippingCalculator.test.ts +43 -43
- package/src/shippingCalculator.ts +23 -23
- package/src/storage/abstract.ts +36 -34
- package/src/storage/in-memory.ts +237 -233
- package/src/storage/index.ts +2 -2
- package/src/types.ts +91 -91
- package/src/validate.ts +18 -0
- package/src/repositories/cart-discount.ts +0 -219
- package/src/repositories/cart.ts +0 -659
- package/src/repositories/category.ts +0 -256
- package/src/repositories/customer.ts +0 -228
- package/src/repositories/discount-code.ts +0 -181
- package/src/repositories/inventory-entry.ts +0 -109
- package/src/repositories/order.ts +0 -514
- package/src/repositories/payment.ts +0 -342
- package/src/repositories/product.ts +0 -1106
- package/src/repositories/shipping-method.ts +0 -312
- package/src/repositories/shopping-list.ts +0 -392
- package/src/repositories/tax-category.ts +0 -111
- package/src/repositories/type.ts +0 -172
package/src/repositories/cart.ts
DELETED
|
@@ -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)
|