@labdigital/commercetools-mock 2.14.2 → 2.16.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/dist/index.cjs +364 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -15
- package/dist/index.d.ts +19 -15
- package/dist/index.js +364 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/repositories/customer.ts +13 -0
- package/src/repositories/payment.ts +148 -25
- package/src/repositories/shopping-list.ts +347 -16
- package/src/services/cart.test.ts +2 -2
- package/src/services/customer.test.ts +40 -0
- package/src/services/shopping-list.test.ts +352 -0
- package/src/storage/in-memory.ts +40 -2
package/package.json
CHANGED
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
CustomerSetFirstNameAction,
|
|
10
10
|
CustomerSetLastNameAction,
|
|
11
11
|
CustomerSetVatIdAction,
|
|
12
|
+
CustomerSetCustomerNumberAction,
|
|
12
13
|
DuplicateFieldError,
|
|
13
14
|
InvalidInputError,
|
|
14
15
|
InvalidJsonInputError,
|
|
@@ -211,5 +212,17 @@ export class CustomerRepository extends AbstractResourceRepository<'customer'> {
|
|
|
211
212
|
}
|
|
212
213
|
resource.custom.fields[name] = value
|
|
213
214
|
},
|
|
215
|
+
setCustomerNumber: (
|
|
216
|
+
_context: RepositoryContext,
|
|
217
|
+
resource: Writable<Customer>,
|
|
218
|
+
{ customerNumber }: CustomerSetCustomerNumberAction
|
|
219
|
+
) => {
|
|
220
|
+
if (resource.customerNumber) {
|
|
221
|
+
throw new Error(
|
|
222
|
+
'A Customer number already exists and cannot be set again.'
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
resource.customerNumber = customerNumber
|
|
226
|
+
},
|
|
214
227
|
}
|
|
215
228
|
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
CustomerReference,
|
|
2
3
|
Payment,
|
|
4
|
+
PaymentAddInterfaceInteractionAction,
|
|
3
5
|
PaymentAddTransactionAction,
|
|
6
|
+
PaymentChangeAmountPlannedAction,
|
|
7
|
+
PaymentChangeTransactionInteractionIdAction,
|
|
4
8
|
PaymentChangeTransactionStateAction,
|
|
9
|
+
PaymentChangeTransactionTimestampAction,
|
|
5
10
|
PaymentDraft,
|
|
11
|
+
PaymentSetAnonymousIdAction,
|
|
6
12
|
PaymentSetCustomFieldAction,
|
|
7
13
|
PaymentSetCustomTypeAction,
|
|
14
|
+
PaymentSetCustomerAction,
|
|
8
15
|
PaymentSetInterfaceIdAction,
|
|
9
16
|
PaymentSetKeyAction,
|
|
10
17
|
PaymentSetMethodInfoInterfaceAction,
|
|
@@ -12,7 +19,10 @@ import type {
|
|
|
12
19
|
PaymentSetMethodInfoNameAction,
|
|
13
20
|
PaymentSetStatusInterfaceCodeAction,
|
|
14
21
|
PaymentSetStatusInterfaceTextAction,
|
|
22
|
+
PaymentSetTransactionCustomFieldAction,
|
|
23
|
+
PaymentSetTransactionCustomTypeAction,
|
|
15
24
|
PaymentTransitionStateAction,
|
|
25
|
+
PaymentUpdateAction,
|
|
16
26
|
State,
|
|
17
27
|
StateReference,
|
|
18
28
|
Transaction,
|
|
@@ -79,7 +89,23 @@ export class PaymentRepository extends AbstractResourceRepository<'payment'> {
|
|
|
79
89
|
state: draft.state ?? 'Initial', // Documented as default
|
|
80
90
|
})
|
|
81
91
|
|
|
82
|
-
actions
|
|
92
|
+
actions: Record<
|
|
93
|
+
PaymentUpdateAction['action'],
|
|
94
|
+
(
|
|
95
|
+
context: RepositoryContext,
|
|
96
|
+
resource: Writable<Payment>,
|
|
97
|
+
action: any
|
|
98
|
+
) => void
|
|
99
|
+
> = {
|
|
100
|
+
addInterfaceInteraction: (
|
|
101
|
+
context: RepositoryContext,
|
|
102
|
+
resource: Writable<Payment>,
|
|
103
|
+
{ type, fields }: PaymentAddInterfaceInteractionAction
|
|
104
|
+
) => {
|
|
105
|
+
resource.interfaceInteractions.push(
|
|
106
|
+
createCustomFields({ type, fields }, context.projectKey, this._storage)!
|
|
107
|
+
)
|
|
108
|
+
},
|
|
83
109
|
addTransaction: (
|
|
84
110
|
context: RepositoryContext,
|
|
85
111
|
resource: Writable<Payment>,
|
|
@@ -90,6 +116,28 @@ export class PaymentRepository extends AbstractResourceRepository<'payment'> {
|
|
|
90
116
|
this.transactionFromTransactionDraft(transaction, context),
|
|
91
117
|
]
|
|
92
118
|
},
|
|
119
|
+
changeAmountPlanned: (
|
|
120
|
+
_context: RepositoryContext,
|
|
121
|
+
resource: Writable<Payment>,
|
|
122
|
+
{ amount }: PaymentChangeAmountPlannedAction
|
|
123
|
+
) => {
|
|
124
|
+
resource.amountPlanned = createCentPrecisionMoney(amount)
|
|
125
|
+
},
|
|
126
|
+
changeTransactionInteractionId: (
|
|
127
|
+
_context: RepositoryContext,
|
|
128
|
+
resource: Writable<Payment>,
|
|
129
|
+
{
|
|
130
|
+
transactionId,
|
|
131
|
+
interactionId,
|
|
132
|
+
}: PaymentChangeTransactionInteractionIdAction
|
|
133
|
+
) => {
|
|
134
|
+
const transaction = resource.transactions.find(
|
|
135
|
+
(e: Transaction) => e.id === transactionId
|
|
136
|
+
)
|
|
137
|
+
if (transaction) {
|
|
138
|
+
transaction.interactionId = interactionId
|
|
139
|
+
}
|
|
140
|
+
},
|
|
93
141
|
changeTransactionState: (
|
|
94
142
|
_context: RepositoryContext,
|
|
95
143
|
resource: Writable<Payment>,
|
|
@@ -104,6 +152,18 @@ export class PaymentRepository extends AbstractResourceRepository<'payment'> {
|
|
|
104
152
|
}
|
|
105
153
|
resource.transactions[index] = updatedTransaction
|
|
106
154
|
},
|
|
155
|
+
changeTransactionTimestamp: (
|
|
156
|
+
_context: RepositoryContext,
|
|
157
|
+
resource: Writable<Payment>,
|
|
158
|
+
{ transactionId, timestamp }: PaymentChangeTransactionTimestampAction
|
|
159
|
+
) => {
|
|
160
|
+
const transaction = resource.transactions.find(
|
|
161
|
+
(e: Transaction) => e.id === transactionId
|
|
162
|
+
)
|
|
163
|
+
if (transaction) {
|
|
164
|
+
transaction.timestamp = timestamp
|
|
165
|
+
}
|
|
166
|
+
},
|
|
107
167
|
transitionState: (
|
|
108
168
|
context: RepositoryContext,
|
|
109
169
|
resource: Writable<Payment>,
|
|
@@ -124,6 +184,29 @@ export class PaymentRepository extends AbstractResourceRepository<'payment'> {
|
|
|
124
184
|
obj: stateObj,
|
|
125
185
|
}
|
|
126
186
|
},
|
|
187
|
+
setAnonymousId: (
|
|
188
|
+
_context: RepositoryContext,
|
|
189
|
+
resource: Writable<Payment>,
|
|
190
|
+
{ anonymousId }: PaymentSetAnonymousIdAction
|
|
191
|
+
) => {
|
|
192
|
+
resource.anonymousId = anonymousId
|
|
193
|
+
resource.customer = undefined
|
|
194
|
+
},
|
|
195
|
+
setCustomer: (
|
|
196
|
+
_context: RepositoryContext,
|
|
197
|
+
resource: Writable<Payment>,
|
|
198
|
+
{ customer }: PaymentSetCustomerAction
|
|
199
|
+
) => {
|
|
200
|
+
if (customer) {
|
|
201
|
+
const c = getReferenceFromResourceIdentifier<CustomerReference>(
|
|
202
|
+
customer,
|
|
203
|
+
_context.projectKey,
|
|
204
|
+
this._storage
|
|
205
|
+
)
|
|
206
|
+
resource.customer = c
|
|
207
|
+
resource.anonymousId = undefined
|
|
208
|
+
}
|
|
209
|
+
},
|
|
127
210
|
setCustomField: (
|
|
128
211
|
context: RepositoryContext,
|
|
129
212
|
resource: Payment,
|
|
@@ -160,26 +243,26 @@ export class PaymentRepository extends AbstractResourceRepository<'payment'> {
|
|
|
160
243
|
}
|
|
161
244
|
}
|
|
162
245
|
},
|
|
163
|
-
|
|
246
|
+
setInterfaceId: (
|
|
164
247
|
_context: RepositoryContext,
|
|
165
248
|
resource: Writable<Payment>,
|
|
166
|
-
{
|
|
249
|
+
{ interfaceId }: PaymentSetInterfaceIdAction
|
|
167
250
|
) => {
|
|
168
|
-
resource.
|
|
251
|
+
resource.interfaceId = interfaceId
|
|
169
252
|
},
|
|
170
|
-
|
|
253
|
+
setKey: (
|
|
171
254
|
_context: RepositoryContext,
|
|
172
255
|
resource: Writable<Payment>,
|
|
173
|
-
{
|
|
256
|
+
{ key }: PaymentSetKeyAction
|
|
174
257
|
) => {
|
|
175
|
-
resource.
|
|
258
|
+
resource.key = key
|
|
176
259
|
},
|
|
177
|
-
|
|
260
|
+
setMethodInfoMethod: (
|
|
178
261
|
_context: RepositoryContext,
|
|
179
262
|
resource: Writable<Payment>,
|
|
180
|
-
{
|
|
263
|
+
{ method }: PaymentSetMethodInfoMethodAction
|
|
181
264
|
) => {
|
|
182
|
-
resource.
|
|
265
|
+
resource.paymentMethodInfo.method = method
|
|
183
266
|
},
|
|
184
267
|
setMethodInfoName: (
|
|
185
268
|
_context: RepositoryContext,
|
|
@@ -188,32 +271,72 @@ export class PaymentRepository extends AbstractResourceRepository<'payment'> {
|
|
|
188
271
|
) => {
|
|
189
272
|
resource.paymentMethodInfo.name = name
|
|
190
273
|
},
|
|
191
|
-
|
|
274
|
+
setMethodInfoInterface: (
|
|
192
275
|
_context: RepositoryContext,
|
|
193
276
|
resource: Writable<Payment>,
|
|
194
|
-
|
|
277
|
+
args: PaymentSetMethodInfoInterfaceAction
|
|
195
278
|
) => {
|
|
196
|
-
resource.paymentMethodInfo.
|
|
279
|
+
resource.paymentMethodInfo.paymentInterface = args.interface
|
|
197
280
|
},
|
|
198
|
-
|
|
281
|
+
setStatusInterfaceCode: (
|
|
199
282
|
_context: RepositoryContext,
|
|
200
283
|
resource: Writable<Payment>,
|
|
201
|
-
|
|
284
|
+
{ interfaceCode }: PaymentSetStatusInterfaceCodeAction
|
|
202
285
|
) => {
|
|
203
|
-
resource.
|
|
286
|
+
resource.paymentStatus.interfaceCode = interfaceCode
|
|
204
287
|
},
|
|
205
|
-
|
|
288
|
+
setStatusInterfaceText: (
|
|
206
289
|
_context: RepositoryContext,
|
|
207
290
|
resource: Writable<Payment>,
|
|
208
|
-
{
|
|
291
|
+
{ interfaceText }: PaymentSetStatusInterfaceTextAction
|
|
209
292
|
) => {
|
|
210
|
-
resource.
|
|
293
|
+
resource.paymentStatus.interfaceText = interfaceText
|
|
294
|
+
},
|
|
295
|
+
setTransactionCustomField: (
|
|
296
|
+
_context: RepositoryContext,
|
|
297
|
+
resource: Writable<Payment>,
|
|
298
|
+
{ transactionId, name, value }: PaymentSetTransactionCustomFieldAction
|
|
299
|
+
) => {
|
|
300
|
+
const transaction = resource.transactions.find(
|
|
301
|
+
(e: Transaction) => e.id === transactionId
|
|
302
|
+
)
|
|
303
|
+
if (transaction) {
|
|
304
|
+
if (!transaction.custom) {
|
|
305
|
+
throw new Error('Transaction has no custom field')
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
transaction.custom.fields[name] = value
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
setTransactionCustomType: (
|
|
312
|
+
context: RepositoryContext,
|
|
313
|
+
resource: Writable<Payment>,
|
|
314
|
+
{ transactionId, type, fields }: PaymentSetTransactionCustomTypeAction
|
|
315
|
+
) => {
|
|
316
|
+
const transaction = resource.transactions.find(
|
|
317
|
+
(e: Transaction) => e.id === transactionId
|
|
318
|
+
)
|
|
319
|
+
if (transaction) {
|
|
320
|
+
if (!type) {
|
|
321
|
+
transaction.custom = undefined
|
|
322
|
+
} else {
|
|
323
|
+
const resolvedType = this._storage.getByResourceIdentifier(
|
|
324
|
+
context.projectKey,
|
|
325
|
+
type
|
|
326
|
+
)
|
|
327
|
+
if (!resolvedType) {
|
|
328
|
+
throw new Error(`Type ${type} not found`)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
transaction.custom = {
|
|
332
|
+
type: {
|
|
333
|
+
typeId: 'type',
|
|
334
|
+
id: resolvedType.id,
|
|
335
|
+
},
|
|
336
|
+
fields: fields ?? {},
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
211
340
|
},
|
|
212
|
-
// addInterfaceInteraction: () => {},
|
|
213
|
-
// changeAmountPlanned: () => {},
|
|
214
|
-
// changeTransactionInteractionId: () => {},
|
|
215
|
-
// changeTransactionTimestamp: () => {},
|
|
216
|
-
// setAnonymousId: () => {},
|
|
217
|
-
// setCustomer: () => {},
|
|
218
341
|
}
|
|
219
342
|
}
|
|
@@ -1,9 +1,30 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
CustomerReference,
|
|
3
|
+
GeneralError,
|
|
4
|
+
LineItemDraft,
|
|
5
|
+
Product,
|
|
6
|
+
ProductPagedQueryResponse,
|
|
3
7
|
ShoppingList,
|
|
8
|
+
ShoppingListAddLineItemAction,
|
|
9
|
+
ShoppingListChangeLineItemQuantityAction,
|
|
10
|
+
ShoppingListChangeNameAction,
|
|
4
11
|
ShoppingListDraft,
|
|
12
|
+
ShoppingListLineItem,
|
|
13
|
+
ShoppingListRemoveLineItemAction,
|
|
14
|
+
ShoppingListSetAnonymousIdAction,
|
|
15
|
+
ShoppingListSetCustomFieldAction,
|
|
16
|
+
ShoppingListSetCustomTypeAction,
|
|
17
|
+
ShoppingListSetCustomerAction,
|
|
18
|
+
ShoppingListSetDeleteDaysAfterLastModificationAction,
|
|
19
|
+
ShoppingListSetDescriptionAction,
|
|
20
|
+
ShoppingListSetKeyAction,
|
|
21
|
+
ShoppingListSetSlugAction,
|
|
22
|
+
ShoppingListSetStoreAction,
|
|
5
23
|
} from '@commercetools/platform-sdk'
|
|
24
|
+
import { v4 as uuidv4 } from 'uuid'
|
|
25
|
+
import { CommercetoolsError } from '../exceptions.js'
|
|
6
26
|
import { getBaseResourceProperties } from '../helpers.js'
|
|
27
|
+
import { Writable } from '../types.js'
|
|
7
28
|
import { AbstractResourceRepository, RepositoryContext } from './abstract.js'
|
|
8
29
|
import {
|
|
9
30
|
createCustomFields,
|
|
@@ -17,7 +38,10 @@ export class ShoppingListRepository extends AbstractResourceRepository<'shopping
|
|
|
17
38
|
}
|
|
18
39
|
|
|
19
40
|
create(context: RepositoryContext, draft: ShoppingListDraft): ShoppingList {
|
|
20
|
-
|
|
41
|
+
const lineItems =
|
|
42
|
+
draft.lineItems?.map((draftLineItem) =>
|
|
43
|
+
this.draftLineItemtoLineItem(context.projectKey, draftLineItem)
|
|
44
|
+
) ?? []
|
|
21
45
|
|
|
22
46
|
const resource: ShoppingList = {
|
|
23
47
|
...getBaseResourceProperties(),
|
|
@@ -28,21 +52,7 @@ export class ShoppingListRepository extends AbstractResourceRepository<'shopping
|
|
|
28
52
|
this._storage
|
|
29
53
|
),
|
|
30
54
|
textLineItems: [],
|
|
31
|
-
lineItems
|
|
32
|
-
draft.lineItems?.map((e) => ({
|
|
33
|
-
...getBaseResourceProperties(),
|
|
34
|
-
...e,
|
|
35
|
-
addedAt: e.addedAt ?? '',
|
|
36
|
-
productId: e.productId ?? '',
|
|
37
|
-
name: {},
|
|
38
|
-
quantity: e.quantity ?? 1,
|
|
39
|
-
productType: { typeId: 'product-type', id: '' },
|
|
40
|
-
custom: createCustomFields(
|
|
41
|
-
e.custom,
|
|
42
|
-
context.projectKey,
|
|
43
|
-
this._storage
|
|
44
|
-
),
|
|
45
|
-
})) ?? [],
|
|
55
|
+
lineItems,
|
|
46
56
|
customer: draft.customer
|
|
47
57
|
? getReferenceFromResourceIdentifier<CustomerReference>(
|
|
48
58
|
draft.customer,
|
|
@@ -57,4 +67,325 @@ export class ShoppingListRepository extends AbstractResourceRepository<'shopping
|
|
|
57
67
|
this.saveNew(context, resource)
|
|
58
68
|
return resource
|
|
59
69
|
}
|
|
70
|
+
|
|
71
|
+
actions = {
|
|
72
|
+
setKey: (
|
|
73
|
+
context: RepositoryContext,
|
|
74
|
+
resource: Writable<ShoppingList>,
|
|
75
|
+
{ key }: ShoppingListSetKeyAction
|
|
76
|
+
) => {
|
|
77
|
+
resource.key = key
|
|
78
|
+
},
|
|
79
|
+
setSlug: (
|
|
80
|
+
context: RepositoryContext,
|
|
81
|
+
resource: Writable<ShoppingList>,
|
|
82
|
+
{ slug }: ShoppingListSetSlugAction
|
|
83
|
+
) => {
|
|
84
|
+
resource.slug = slug
|
|
85
|
+
},
|
|
86
|
+
changeName: (
|
|
87
|
+
context: RepositoryContext,
|
|
88
|
+
resource: Writable<ShoppingList>,
|
|
89
|
+
{ name }: ShoppingListChangeNameAction
|
|
90
|
+
) => {
|
|
91
|
+
resource.name = name
|
|
92
|
+
},
|
|
93
|
+
setDescription: (
|
|
94
|
+
context: RepositoryContext,
|
|
95
|
+
resource: Writable<ShoppingList>,
|
|
96
|
+
{ description }: ShoppingListSetDescriptionAction
|
|
97
|
+
) => {
|
|
98
|
+
resource.description = description
|
|
99
|
+
},
|
|
100
|
+
setCustomer: (
|
|
101
|
+
context: RepositoryContext,
|
|
102
|
+
resource: Writable<ShoppingList>,
|
|
103
|
+
{ customer }: ShoppingListSetCustomerAction
|
|
104
|
+
) => {
|
|
105
|
+
if (customer?.key) {
|
|
106
|
+
throw new Error('set customer on shoppinglist by key not implemented')
|
|
107
|
+
}
|
|
108
|
+
if (customer?.id) {
|
|
109
|
+
resource.customer = { typeId: 'customer', id: customer.id }
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
setStore: (
|
|
113
|
+
context: RepositoryContext,
|
|
114
|
+
resource: Writable<ShoppingList>,
|
|
115
|
+
{ store }: ShoppingListSetStoreAction
|
|
116
|
+
) => {
|
|
117
|
+
if (store?.key) {
|
|
118
|
+
resource.store = { typeId: 'store', key: store.key }
|
|
119
|
+
}
|
|
120
|
+
if (store?.id) {
|
|
121
|
+
throw new Error('set store on shoppinglist by id not implemented')
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
setAnonymousId: (
|
|
125
|
+
context: RepositoryContext,
|
|
126
|
+
resource: Writable<ShoppingList>,
|
|
127
|
+
{ anonymousId }: ShoppingListSetAnonymousIdAction
|
|
128
|
+
) => {
|
|
129
|
+
resource.anonymousId = anonymousId
|
|
130
|
+
},
|
|
131
|
+
setCustomType: (
|
|
132
|
+
context: RepositoryContext,
|
|
133
|
+
resource: Writable<ShoppingList>,
|
|
134
|
+
{ type, fields }: ShoppingListSetCustomTypeAction
|
|
135
|
+
) => {
|
|
136
|
+
if (!type) {
|
|
137
|
+
resource.custom = undefined
|
|
138
|
+
} else {
|
|
139
|
+
const resolvedType = this._storage.getByResourceIdentifier(
|
|
140
|
+
context.projectKey,
|
|
141
|
+
type
|
|
142
|
+
)
|
|
143
|
+
if (!resolvedType) {
|
|
144
|
+
throw new Error(`Type ${type} not found`)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
resource.custom = {
|
|
148
|
+
type: {
|
|
149
|
+
typeId: 'type',
|
|
150
|
+
id: resolvedType.id,
|
|
151
|
+
},
|
|
152
|
+
fields: fields || {},
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
setCustomField: (
|
|
157
|
+
context: RepositoryContext,
|
|
158
|
+
resource: ShoppingList,
|
|
159
|
+
{ name, value }: ShoppingListSetCustomFieldAction
|
|
160
|
+
) => {
|
|
161
|
+
if (!resource.custom) {
|
|
162
|
+
throw new Error('Resource has no custom field')
|
|
163
|
+
}
|
|
164
|
+
resource.custom.fields[name] = value
|
|
165
|
+
},
|
|
166
|
+
setDeleteDaysAfterLastModification: (
|
|
167
|
+
context: RepositoryContext,
|
|
168
|
+
resource: Writable<ShoppingList>,
|
|
169
|
+
{
|
|
170
|
+
deleteDaysAfterLastModification,
|
|
171
|
+
}: ShoppingListSetDeleteDaysAfterLastModificationAction
|
|
172
|
+
) => {
|
|
173
|
+
resource.deleteDaysAfterLastModification = deleteDaysAfterLastModification
|
|
174
|
+
},
|
|
175
|
+
addLineItem: (
|
|
176
|
+
context: RepositoryContext,
|
|
177
|
+
resource: Writable<ShoppingList>,
|
|
178
|
+
{ productId, variantId, sku, quantity = 1 }: ShoppingListAddLineItemAction
|
|
179
|
+
) => {
|
|
180
|
+
let product: Product | null = null
|
|
181
|
+
|
|
182
|
+
if (productId) {
|
|
183
|
+
// Fetch product and variant by ID
|
|
184
|
+
product = this._storage.get(
|
|
185
|
+
context.projectKey,
|
|
186
|
+
'product',
|
|
187
|
+
productId,
|
|
188
|
+
{}
|
|
189
|
+
)
|
|
190
|
+
} else if (sku) {
|
|
191
|
+
// Fetch product and variant by SKU
|
|
192
|
+
const items = this._storage.query(context.projectKey, 'product', {
|
|
193
|
+
where: [
|
|
194
|
+
`masterData(current(masterVariant(sku="${sku}"))) or masterData(current(variants(sku="${sku}")))`,
|
|
195
|
+
],
|
|
196
|
+
}) as ProductPagedQueryResponse
|
|
197
|
+
|
|
198
|
+
if (items.count === 1) {
|
|
199
|
+
product = items.results[0]
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (!product) {
|
|
204
|
+
// Check if product is found
|
|
205
|
+
throw new CommercetoolsError<GeneralError>({
|
|
206
|
+
code: 'General',
|
|
207
|
+
message: sku
|
|
208
|
+
? `A product containing a variant with SKU '${sku}' not found.`
|
|
209
|
+
: `A product with ID '${productId}' not found.`,
|
|
210
|
+
})
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
let varId: number | undefined = variantId
|
|
214
|
+
if (sku) {
|
|
215
|
+
varId = [
|
|
216
|
+
product.masterData.current.masterVariant,
|
|
217
|
+
...product.masterData.current.variants,
|
|
218
|
+
].find((x) => x.sku === sku)?.id
|
|
219
|
+
}
|
|
220
|
+
if (!varId) {
|
|
221
|
+
varId = product.masterData.current.masterVariant.id
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const alreadyAdded = resource.lineItems.some(
|
|
225
|
+
(x) => x.productId === product?.id && x.variantId === varId
|
|
226
|
+
)
|
|
227
|
+
if (alreadyAdded) {
|
|
228
|
+
// increase quantity and update total price
|
|
229
|
+
resource.lineItems.forEach((x) => {
|
|
230
|
+
if (x.productId === product?.id && x.variantId === varId) {
|
|
231
|
+
x.quantity += quantity
|
|
232
|
+
}
|
|
233
|
+
})
|
|
234
|
+
} else {
|
|
235
|
+
// add line item
|
|
236
|
+
resource.lineItems.push({
|
|
237
|
+
addedAt: new Date().toISOString(),
|
|
238
|
+
id: uuidv4(),
|
|
239
|
+
productId: product.id,
|
|
240
|
+
productSlug: product.masterData.current.slug,
|
|
241
|
+
productType: product.productType,
|
|
242
|
+
name: product.masterData.current.name,
|
|
243
|
+
variantId: varId,
|
|
244
|
+
quantity,
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
removeLineItem: (
|
|
249
|
+
context: RepositoryContext,
|
|
250
|
+
resource: Writable<ShoppingList>,
|
|
251
|
+
{ lineItemId, quantity }: ShoppingListRemoveLineItemAction
|
|
252
|
+
) => {
|
|
253
|
+
const lineItem = resource.lineItems.find((x) => x.id === lineItemId)
|
|
254
|
+
if (!lineItem) {
|
|
255
|
+
// Check if product is found
|
|
256
|
+
throw new CommercetoolsError<GeneralError>({
|
|
257
|
+
code: 'General',
|
|
258
|
+
message: `A line item with ID '${lineItemId}' not found.`,
|
|
259
|
+
})
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const shouldDelete = !quantity || quantity >= lineItem.quantity
|
|
263
|
+
if (shouldDelete) {
|
|
264
|
+
// delete line item
|
|
265
|
+
resource.lineItems = resource.lineItems.filter(
|
|
266
|
+
(x) => x.id !== lineItemId
|
|
267
|
+
)
|
|
268
|
+
} else {
|
|
269
|
+
// decrease quantity and update total price
|
|
270
|
+
resource.lineItems.forEach((x) => {
|
|
271
|
+
if (x.id === lineItemId && quantity) {
|
|
272
|
+
x.quantity -= quantity
|
|
273
|
+
}
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
changeLineItemQuantity: (
|
|
278
|
+
context: RepositoryContext,
|
|
279
|
+
resource: Writable<ShoppingList>,
|
|
280
|
+
{
|
|
281
|
+
lineItemId,
|
|
282
|
+
lineItemKey,
|
|
283
|
+
quantity,
|
|
284
|
+
}: ShoppingListChangeLineItemQuantityAction
|
|
285
|
+
) => {
|
|
286
|
+
let lineItem: Writable<ShoppingListLineItem> | undefined
|
|
287
|
+
|
|
288
|
+
if (lineItemId) {
|
|
289
|
+
lineItem = resource.lineItems.find((x) => x.id === lineItemId)
|
|
290
|
+
if (!lineItem) {
|
|
291
|
+
throw new CommercetoolsError<GeneralError>({
|
|
292
|
+
code: 'General',
|
|
293
|
+
message: `A line item with ID '${lineItemId}' not found.`,
|
|
294
|
+
})
|
|
295
|
+
}
|
|
296
|
+
} else if (lineItemKey) {
|
|
297
|
+
lineItem = resource.lineItems.find((x) => x.id === lineItemId)
|
|
298
|
+
if (!lineItem) {
|
|
299
|
+
throw new CommercetoolsError<GeneralError>({
|
|
300
|
+
code: 'General',
|
|
301
|
+
message: `A line item with Key '${lineItemKey}' not found.`,
|
|
302
|
+
})
|
|
303
|
+
}
|
|
304
|
+
} else {
|
|
305
|
+
throw new CommercetoolsError<GeneralError>({
|
|
306
|
+
code: 'General',
|
|
307
|
+
message: `Either lineItemid or lineItemKey needs to be provided.`,
|
|
308
|
+
})
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (quantity === 0) {
|
|
312
|
+
// delete line item
|
|
313
|
+
resource.lineItems = resource.lineItems.filter(
|
|
314
|
+
(x) => x.id !== lineItemId
|
|
315
|
+
)
|
|
316
|
+
} else {
|
|
317
|
+
resource.lineItems.forEach((x) => {
|
|
318
|
+
if (x.id === lineItemId && quantity) {
|
|
319
|
+
x.quantity = quantity
|
|
320
|
+
}
|
|
321
|
+
})
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
draftLineItemtoLineItem = (
|
|
327
|
+
projectKey: string,
|
|
328
|
+
draftLineItem: LineItemDraft
|
|
329
|
+
): ShoppingListLineItem => {
|
|
330
|
+
const { sku, productId, variantId } = draftLineItem
|
|
331
|
+
|
|
332
|
+
const lineItem: Writable<ShoppingListLineItem> = {
|
|
333
|
+
...getBaseResourceProperties(),
|
|
334
|
+
...draftLineItem,
|
|
335
|
+
addedAt: draftLineItem.addedAt ?? '',
|
|
336
|
+
productId: draftLineItem.productId ?? '',
|
|
337
|
+
name: {},
|
|
338
|
+
variantId,
|
|
339
|
+
quantity: draftLineItem.quantity ?? 1,
|
|
340
|
+
productType: { typeId: 'product-type', id: '' },
|
|
341
|
+
custom: createCustomFields(
|
|
342
|
+
draftLineItem.custom,
|
|
343
|
+
projectKey,
|
|
344
|
+
this._storage
|
|
345
|
+
),
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (variantId) {
|
|
349
|
+
return lineItem
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (sku) {
|
|
353
|
+
const items = this._storage.query(projectKey, 'product', {
|
|
354
|
+
where: [
|
|
355
|
+
`masterData(current(masterVariant(sku="${sku}"))) or masterData(current(variants(sku="${sku}")))`,
|
|
356
|
+
],
|
|
357
|
+
}) as ProductPagedQueryResponse
|
|
358
|
+
|
|
359
|
+
if (items.count === 0) {
|
|
360
|
+
throw new Error(`Product with sku ${sku} not found`)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const product = items.results[0]
|
|
364
|
+
const allVariants = [
|
|
365
|
+
product.masterData.current.masterVariant,
|
|
366
|
+
...product.masterData.current.variants,
|
|
367
|
+
]
|
|
368
|
+
const variantId = allVariants.find((e) => e.sku === sku)?.id
|
|
369
|
+
lineItem.variantId = variantId
|
|
370
|
+
return lineItem
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (productId) {
|
|
374
|
+
const items = this._storage.query(projectKey, 'product', {
|
|
375
|
+
where: [`id="${productId}"`],
|
|
376
|
+
}) as ProductPagedQueryResponse
|
|
377
|
+
|
|
378
|
+
if (items.count === 0) {
|
|
379
|
+
throw new Error(`Product with id ${productId} not found`)
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const variantId = items.results[0].masterData.current.masterVariant.id
|
|
383
|
+
lineItem.variantId = variantId
|
|
384
|
+
return lineItem
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
throw new Error(
|
|
388
|
+
`must provide either sku, productId or variantId for ShoppingListLineItem`
|
|
389
|
+
)
|
|
390
|
+
}
|
|
60
391
|
}
|
|
@@ -273,7 +273,7 @@ describe('Cart Update Actions', () => {
|
|
|
273
273
|
})
|
|
274
274
|
|
|
275
275
|
test('addItemShippingAddress', async () => {
|
|
276
|
-
|
|
276
|
+
await supertest(ctMock.app)
|
|
277
277
|
.post(`/dummy/products`)
|
|
278
278
|
.send(productDraft)
|
|
279
279
|
.then((x) => x.body)
|
|
@@ -304,7 +304,7 @@ describe('Cart Update Actions', () => {
|
|
|
304
304
|
})
|
|
305
305
|
|
|
306
306
|
test('recalculate', async () => {
|
|
307
|
-
|
|
307
|
+
await supertest(ctMock.app)
|
|
308
308
|
.post(`/dummy/products`)
|
|
309
309
|
.send(productDraft)
|
|
310
310
|
.then((x) => x.body)
|