@labdigital/commercetools-mock 2.7.0 → 2.9.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 +362 -77
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -2
- package/dist/index.d.ts +36 -2
- package/dist/index.js +362 -77
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/ctMock.ts +4 -0
- package/src/lib/predicateParser.test.ts +96 -11
- package/src/lib/predicateParser.ts +43 -12
- package/src/oauth/server.ts +11 -1
- package/src/priceSelector.ts +10 -5
- package/src/repositories/abstract.ts +5 -4
- package/src/repositories/cart.ts +77 -33
- package/src/repositories/custom-object.ts +18 -0
- package/src/repositories/customer.ts +1 -0
- package/src/repositories/helpers.ts +1 -1
- package/src/repositories/order.ts +45 -3
- package/src/repositories/product-projection.ts +15 -0
- package/src/repositories/product-selection.ts +0 -1
- package/src/repositories/product.ts +37 -24
- package/src/repositories/review.ts +36 -4
- package/src/repositories/shipping-method.ts +98 -22
- package/src/services/custom-object.ts +19 -0
- package/src/services/index.ts +2 -0
- package/src/services/product-selection.test.ts +0 -1
- package/src/services/reviews.ts +16 -0
- package/src/services/shipping-method.test.ts +120 -21
- package/src/services/shipping-method.ts +19 -2
- package/src/shippingCalculator.test.ts +280 -0
- package/src/shippingCalculator.ts +74 -0
- package/src/storage/abstract.ts +1 -1
- package/src/storage/in-memory.ts +91 -65
- package/src/types.ts +2 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Cart,
|
|
3
|
+
ShippingRate,
|
|
4
|
+
ShippingRatePriceTier,
|
|
5
|
+
} from '@commercetools/platform-sdk'
|
|
6
|
+
import { describe, expect, it } from 'vitest'
|
|
7
|
+
import {
|
|
8
|
+
markMatchingShippingRate,
|
|
9
|
+
markMatchingShippingRatePriceTiers,
|
|
10
|
+
} from './shippingCalculator'
|
|
11
|
+
|
|
12
|
+
// describe('markMatchingShippingMethods', () => {
|
|
13
|
+
// const zones: Record<string, Zone> = {
|
|
14
|
+
// NL: {
|
|
15
|
+
// id: '45b39469-4f3d-4d03-9e24-ed6bd5c038d9',
|
|
16
|
+
// createdAt: '2021-08-05T09:00:00.000Z',
|
|
17
|
+
// lastModifiedAt: '2021-08-05T09:00:00.000Z',
|
|
18
|
+
// version: 1,
|
|
19
|
+
// name: 'NL',
|
|
20
|
+
// description: '',
|
|
21
|
+
// locations: [
|
|
22
|
+
// {
|
|
23
|
+
// country: 'NL',
|
|
24
|
+
// },
|
|
25
|
+
// ],
|
|
26
|
+
// },
|
|
27
|
+
// DE: {
|
|
28
|
+
// id: '45b39469-4f3d-4d03-9e24-ed6bd5c038d9',
|
|
29
|
+
// createdAt: '2021-08-05T09:00:00.000Z',
|
|
30
|
+
// lastModifiedAt: '2021-08-05T09:00:00.000Z',
|
|
31
|
+
// version: 1,
|
|
32
|
+
// name: 'DE',
|
|
33
|
+
// description: '',
|
|
34
|
+
// locations: [
|
|
35
|
+
// {
|
|
36
|
+
// country: 'DE',
|
|
37
|
+
// },
|
|
38
|
+
// ],
|
|
39
|
+
// },
|
|
40
|
+
// }
|
|
41
|
+
|
|
42
|
+
// const shippingMethods: Record<string, Partial<ShippingMethod>> = {
|
|
43
|
+
// default: {
|
|
44
|
+
// id: '1c39b73f-186c-4711-8fd9-de60ec561ac0',
|
|
45
|
+
// key: 'default',
|
|
46
|
+
// zoneRates: [
|
|
47
|
+
// {
|
|
48
|
+
// zone: {
|
|
49
|
+
// typeId: 'zone',
|
|
50
|
+
// id: '45b39469-4f3d-4d03-9e24-ed6bd5c038d9',
|
|
51
|
+
// obj: zones['NL'],
|
|
52
|
+
// },
|
|
53
|
+
// shippingRates: [
|
|
54
|
+
// {
|
|
55
|
+
// price: {
|
|
56
|
+
// type: 'centPrecision',
|
|
57
|
+
// currencyCode: 'EUR',
|
|
58
|
+
// centAmount: 495,
|
|
59
|
+
// fractionDigits: 2,
|
|
60
|
+
// },
|
|
61
|
+
// freeAbove: {
|
|
62
|
+
// type: 'centPrecision',
|
|
63
|
+
// currencyCode: 'USD',
|
|
64
|
+
// centAmount: 5000,
|
|
65
|
+
// fractionDigits: 2,
|
|
66
|
+
// },
|
|
67
|
+
// tiers: [],
|
|
68
|
+
// },
|
|
69
|
+
// ],
|
|
70
|
+
// },
|
|
71
|
+
// ],
|
|
72
|
+
// isDefault: true,
|
|
73
|
+
// },
|
|
74
|
+
// tiered: {
|
|
75
|
+
// id: '2c39b73f-186c-4711-8fd9-de60ec561ac0',
|
|
76
|
+
// key: 'tiered',
|
|
77
|
+
// description: 'More expensive optional one',
|
|
78
|
+
// zoneRates: [
|
|
79
|
+
// {
|
|
80
|
+
// zone: {
|
|
81
|
+
// typeId: 'zone',
|
|
82
|
+
// id: '45b39469-4f3d-4d03-9e24-ed6bd5c038d9',
|
|
83
|
+
// obj: zones['NL'],
|
|
84
|
+
// },
|
|
85
|
+
// shippingRates: [
|
|
86
|
+
// {
|
|
87
|
+
// price: {
|
|
88
|
+
// type: 'centPrecision',
|
|
89
|
+
// currencyCode: 'EUR',
|
|
90
|
+
// centAmount: 495,
|
|
91
|
+
// fractionDigits: 2,
|
|
92
|
+
// },
|
|
93
|
+
// freeAbove: {
|
|
94
|
+
// type: 'centPrecision',
|
|
95
|
+
// currencyCode: 'USD',
|
|
96
|
+
// centAmount: 5000,
|
|
97
|
+
// fractionDigits: 2,
|
|
98
|
+
// },
|
|
99
|
+
// tiers: [],
|
|
100
|
+
// },
|
|
101
|
+
// ],
|
|
102
|
+
// },
|
|
103
|
+
// ],
|
|
104
|
+
// isDefault: false,
|
|
105
|
+
// },
|
|
106
|
+
// german: {
|
|
107
|
+
// id: '8c39b73f-186c-4711-8fd9-de60ec561ac0',
|
|
108
|
+
// key: 'tiered',
|
|
109
|
+
// description: 'More expensive optional one',
|
|
110
|
+
// zoneRates: [
|
|
111
|
+
// {
|
|
112
|
+
// zone: {
|
|
113
|
+
// typeId: 'zone',
|
|
114
|
+
// id: '45b39469-4f3d-4d03-9e24-ed6bd5c038d9',
|
|
115
|
+
// obj: zones['DE'],
|
|
116
|
+
// },
|
|
117
|
+
// shippingRates: [
|
|
118
|
+
// {
|
|
119
|
+
// price: {
|
|
120
|
+
// type: 'centPrecision',
|
|
121
|
+
// currencyCode: 'EUR',
|
|
122
|
+
// centAmount: 495,
|
|
123
|
+
// fractionDigits: 2,
|
|
124
|
+
// },
|
|
125
|
+
// freeAbove: {
|
|
126
|
+
// type: 'centPrecision',
|
|
127
|
+
// currencyCode: 'USD',
|
|
128
|
+
// centAmount: 5000,
|
|
129
|
+
// fractionDigits: 2,
|
|
130
|
+
// },
|
|
131
|
+
// tiers: [],
|
|
132
|
+
// },
|
|
133
|
+
// ],
|
|
134
|
+
// },
|
|
135
|
+
// ],
|
|
136
|
+
// isDefault: false,
|
|
137
|
+
// },
|
|
138
|
+
// }
|
|
139
|
+
|
|
140
|
+
// it('should mark the default shipping method', () => {
|
|
141
|
+
// const cart: Partial<Cart> = {
|
|
142
|
+
// id: '1',
|
|
143
|
+
// version: 1,
|
|
144
|
+
// totalPrice: {
|
|
145
|
+
// currencyCode: 'EUR',
|
|
146
|
+
// centAmount: 1000,
|
|
147
|
+
// fractionDigits: 2,
|
|
148
|
+
// type: 'centPrecision',
|
|
149
|
+
// },
|
|
150
|
+
// shippingAddress: {
|
|
151
|
+
// country: 'NL',
|
|
152
|
+
// },
|
|
153
|
+
// lineItems: [],
|
|
154
|
+
// customLineItems: [],
|
|
155
|
+
// }
|
|
156
|
+
|
|
157
|
+
// const data = markMatchingShippingMethods(
|
|
158
|
+
// cart as Cart,
|
|
159
|
+
// Object.values(shippingMethods) as ShippingMethod[]
|
|
160
|
+
// )
|
|
161
|
+
// })
|
|
162
|
+
// })
|
|
163
|
+
|
|
164
|
+
describe('markMatchingShippingRate', () => {
|
|
165
|
+
const rate: ShippingRate = {
|
|
166
|
+
price: {
|
|
167
|
+
type: 'centPrecision',
|
|
168
|
+
currencyCode: 'EUR',
|
|
169
|
+
centAmount: 495,
|
|
170
|
+
fractionDigits: 2,
|
|
171
|
+
},
|
|
172
|
+
freeAbove: {
|
|
173
|
+
type: 'centPrecision',
|
|
174
|
+
currencyCode: 'USD',
|
|
175
|
+
centAmount: 5000,
|
|
176
|
+
fractionDigits: 2,
|
|
177
|
+
},
|
|
178
|
+
tiers: [],
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
it('should mark the shipping rate as matching', () => {
|
|
182
|
+
const cart: Partial<Cart> = {
|
|
183
|
+
totalPrice: {
|
|
184
|
+
currencyCode: 'EUR',
|
|
185
|
+
centAmount: 1000,
|
|
186
|
+
fractionDigits: 2,
|
|
187
|
+
type: 'centPrecision',
|
|
188
|
+
},
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const result = markMatchingShippingRate(cart as Cart, rate)
|
|
192
|
+
expect(result).toMatchObject({
|
|
193
|
+
...rate,
|
|
194
|
+
isMatching: true,
|
|
195
|
+
})
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
it('should mark the shipping rate as not matching', () => {
|
|
199
|
+
const cart: Partial<Cart> = {
|
|
200
|
+
totalPrice: {
|
|
201
|
+
currencyCode: 'USD',
|
|
202
|
+
centAmount: 1000,
|
|
203
|
+
fractionDigits: 2,
|
|
204
|
+
type: 'centPrecision',
|
|
205
|
+
},
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const result = markMatchingShippingRate(cart as Cart, rate)
|
|
209
|
+
expect(result).toMatchObject({
|
|
210
|
+
...rate,
|
|
211
|
+
isMatching: false,
|
|
212
|
+
})
|
|
213
|
+
})
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
describe('markMatchingShippingRatePriceTiers', () => {
|
|
217
|
+
it('should handle CartValue types', () => {
|
|
218
|
+
const tiers: ShippingRatePriceTier[] = [
|
|
219
|
+
// Above 100 euro shipping is 4 euro
|
|
220
|
+
{
|
|
221
|
+
type: 'CartValue',
|
|
222
|
+
minimumCentAmount: 10000,
|
|
223
|
+
price: {
|
|
224
|
+
type: 'centPrecision',
|
|
225
|
+
currencyCode: 'EUR',
|
|
226
|
+
centAmount: 400,
|
|
227
|
+
fractionDigits: 2,
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
// Above 200 euro shipping is 3 euro
|
|
231
|
+
{
|
|
232
|
+
type: 'CartValue',
|
|
233
|
+
minimumCentAmount: 20000,
|
|
234
|
+
price: {
|
|
235
|
+
type: 'centPrecision',
|
|
236
|
+
currencyCode: 'EUR',
|
|
237
|
+
centAmount: 300,
|
|
238
|
+
fractionDigits: 2,
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
// Above 50 euro shipping is 5 euro
|
|
242
|
+
{
|
|
243
|
+
type: 'CartValue',
|
|
244
|
+
minimumCentAmount: 500,
|
|
245
|
+
price: {
|
|
246
|
+
type: 'centPrecision',
|
|
247
|
+
currencyCode: 'EUR',
|
|
248
|
+
centAmount: 700,
|
|
249
|
+
fractionDigits: 2,
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
]
|
|
253
|
+
|
|
254
|
+
// Create a cart with a total price of 90 euro
|
|
255
|
+
const cart: Partial<Cart> = {
|
|
256
|
+
totalPrice: {
|
|
257
|
+
currencyCode: 'EUR',
|
|
258
|
+
centAmount: 9000,
|
|
259
|
+
fractionDigits: 2,
|
|
260
|
+
type: 'centPrecision',
|
|
261
|
+
},
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const result = markMatchingShippingRatePriceTiers(cart as Cart, tiers)
|
|
265
|
+
expect(result).toMatchObject([
|
|
266
|
+
{
|
|
267
|
+
minimumCentAmount: 10000,
|
|
268
|
+
isMatching: false,
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
minimumCentAmount: 20000,
|
|
272
|
+
isMatching: false,
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
minimumCentAmount: 500,
|
|
276
|
+
isMatching: true,
|
|
277
|
+
},
|
|
278
|
+
])
|
|
279
|
+
})
|
|
280
|
+
})
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Cart,
|
|
3
|
+
CartValueTier,
|
|
4
|
+
ShippingRate,
|
|
5
|
+
ShippingRatePriceTier,
|
|
6
|
+
} from '@commercetools/platform-sdk'
|
|
7
|
+
|
|
8
|
+
export const markMatchingShippingRate = (
|
|
9
|
+
cart: Cart,
|
|
10
|
+
shippingRate: ShippingRate
|
|
11
|
+
): ShippingRate => {
|
|
12
|
+
const isMatching =
|
|
13
|
+
shippingRate.price.currencyCode === cart.totalPrice.currencyCode
|
|
14
|
+
return {
|
|
15
|
+
...shippingRate,
|
|
16
|
+
tiers: markMatchingShippingRatePriceTiers(cart, shippingRate.tiers),
|
|
17
|
+
isMatching: isMatching,
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const markMatchingShippingRatePriceTiers = (
|
|
22
|
+
cart: Cart,
|
|
23
|
+
tiers: ShippingRatePriceTier[]
|
|
24
|
+
): ShippingRatePriceTier[] => {
|
|
25
|
+
if (tiers.length === 0) {
|
|
26
|
+
return []
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (new Set(tiers.map((tier) => tier.type)).size > 1) {
|
|
30
|
+
throw new Error("Can't handle multiple types of tiers")
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const tierType = tiers[0].type
|
|
34
|
+
switch (tierType) {
|
|
35
|
+
case 'CartValue':
|
|
36
|
+
return markMatchingCartValueTiers(cart, tiers as CartValueTier[])
|
|
37
|
+
// case 'CartClassification':
|
|
38
|
+
// return markMatchingCartClassificationTiers(cart, tiers)
|
|
39
|
+
// case 'CartScore':
|
|
40
|
+
// return markMatchingCartScoreTiers(cart, tiers)
|
|
41
|
+
default:
|
|
42
|
+
throw new Error(`Unsupported tier type: ${tierType}`)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const markMatchingCartValueTiers = (
|
|
47
|
+
cart: Cart,
|
|
48
|
+
tiers: readonly CartValueTier[]
|
|
49
|
+
): ShippingRatePriceTier[] => {
|
|
50
|
+
// Sort tiers from high to low since we only want to match the highest tier
|
|
51
|
+
const sortedTiers = [...tiers].sort(
|
|
52
|
+
(a, b) => b.minimumCentAmount - a.minimumCentAmount
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
// Find the first tier that matches the cart and set the flag. We push
|
|
56
|
+
// the results into a map so that we can output the tiers in the same order as
|
|
57
|
+
// we received them.
|
|
58
|
+
const result: Record<number, ShippingRatePriceTier> = {}
|
|
59
|
+
let hasMatchingTier = false
|
|
60
|
+
for (const tier of sortedTiers) {
|
|
61
|
+
const isMatching =
|
|
62
|
+
!hasMatchingTier &&
|
|
63
|
+
cart.totalPrice.currencyCode === tier.price.currencyCode &&
|
|
64
|
+
cart.totalPrice.centAmount >= tier.minimumCentAmount
|
|
65
|
+
|
|
66
|
+
if (isMatching) hasMatchingTier = true
|
|
67
|
+
result[tier.minimumCentAmount] = {
|
|
68
|
+
...tier,
|
|
69
|
+
isMatching: isMatching,
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return tiers.map((tier) => result[tier.minimumCentAmount])
|
|
74
|
+
}
|
package/src/storage/abstract.ts
CHANGED
package/src/storage/in-memory.ts
CHANGED
|
@@ -1,39 +1,41 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
1
|
+
import {
|
|
2
|
+
ReferencedResourceNotFoundError,
|
|
3
|
+
type AssociateRole,
|
|
4
|
+
type AttributeGroup,
|
|
5
|
+
type BusinessUnit,
|
|
6
|
+
type Cart,
|
|
7
|
+
type CartDiscount,
|
|
8
|
+
type Category,
|
|
9
|
+
type Channel,
|
|
10
|
+
type Customer,
|
|
11
|
+
type CustomerGroup,
|
|
12
|
+
type CustomObject,
|
|
13
|
+
type DiscountCode,
|
|
14
|
+
type Extension,
|
|
15
|
+
type InvalidInputError,
|
|
16
|
+
type InventoryEntry,
|
|
17
|
+
type Order,
|
|
18
|
+
type PagedQueryResponse,
|
|
19
|
+
type Payment,
|
|
20
|
+
type Product,
|
|
21
|
+
type ProductDiscount,
|
|
22
|
+
type ProductProjection,
|
|
23
|
+
type ProductType,
|
|
24
|
+
type Project,
|
|
25
|
+
type Quote,
|
|
26
|
+
type QuoteRequest,
|
|
27
|
+
type Reference,
|
|
28
|
+
type ResourceIdentifier,
|
|
29
|
+
type ShippingMethod,
|
|
30
|
+
type ShoppingList,
|
|
31
|
+
type StagedQuote,
|
|
32
|
+
type State,
|
|
33
|
+
type Store,
|
|
34
|
+
type Subscription,
|
|
35
|
+
type TaxCategory,
|
|
36
|
+
type Type,
|
|
37
|
+
type Zone,
|
|
38
|
+
InvalidJsonInputError,
|
|
37
39
|
} from '@commercetools/platform-sdk'
|
|
38
40
|
import assert from 'assert'
|
|
39
41
|
import { CommercetoolsError } from '../exceptions.js'
|
|
@@ -204,9 +206,17 @@ export class InMemoryStorage extends AbstractStorage {
|
|
|
204
206
|
|
|
205
207
|
// Apply predicates
|
|
206
208
|
if (params.where) {
|
|
209
|
+
// Get all key-value pairs starting with 'var.' to pass as variables, removing
|
|
210
|
+
// the 'var.' prefix.
|
|
211
|
+
const vars = Object.fromEntries(
|
|
212
|
+
Object.entries(params)
|
|
213
|
+
.filter(([key]) => key.startsWith('var.'))
|
|
214
|
+
.map(([key, value]) => [key.slice(4), value])
|
|
215
|
+
)
|
|
216
|
+
|
|
207
217
|
try {
|
|
208
218
|
const filterFunc = parseQueryExpression(params.where)
|
|
209
|
-
resources = resources.filter((resource) => filterFunc(resource,
|
|
219
|
+
resources = resources.filter((resource) => filterFunc(resource, vars))
|
|
210
220
|
} catch (err) {
|
|
211
221
|
throw new CommercetoolsError<InvalidInputError>(
|
|
212
222
|
{
|
|
@@ -292,38 +302,51 @@ export class InMemoryStorage extends AbstractStorage {
|
|
|
292
302
|
getByResourceIdentifier<RT extends ResourceType>(
|
|
293
303
|
projectKey: string,
|
|
294
304
|
identifier: ResourceIdentifier
|
|
295
|
-
): ResourceMap[RT]
|
|
305
|
+
): ResourceMap[RT] {
|
|
296
306
|
if (identifier.id) {
|
|
297
307
|
const resource = this.get(projectKey, identifier.typeId, identifier.id)
|
|
298
308
|
if (resource) {
|
|
299
309
|
return resource as ResourceMap[RT]
|
|
300
310
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
311
|
+
|
|
312
|
+
throw new CommercetoolsError<ReferencedResourceNotFoundError>({
|
|
313
|
+
code: 'ReferencedResourceNotFound',
|
|
314
|
+
message:
|
|
315
|
+
`The referenced object of type '${identifier.typeId}' with id ` +
|
|
316
|
+
`'${identifier.id}' was not found. It either doesn't exist, or it ` +
|
|
317
|
+
`can't be accessed from this endpoint (e.g., if the endpoint ` +
|
|
318
|
+
`filters by store or customer account).`,
|
|
319
|
+
typeId: identifier.typeId,
|
|
320
|
+
id: identifier.id,
|
|
321
|
+
})
|
|
305
322
|
}
|
|
306
323
|
|
|
307
324
|
if (identifier.key) {
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
(r) => r.key === identifier.key
|
|
316
|
-
)
|
|
317
|
-
if (resource) {
|
|
318
|
-
return resource as ResourceMap[RT]
|
|
319
|
-
}
|
|
320
|
-
} else {
|
|
321
|
-
throw new Error(
|
|
322
|
-
`No storage found for resource type: ${identifier.typeId}`
|
|
323
|
-
)
|
|
325
|
+
const resource = this.getByKey(
|
|
326
|
+
projectKey,
|
|
327
|
+
identifier.typeId,
|
|
328
|
+
identifier.key
|
|
329
|
+
)
|
|
330
|
+
if (resource) {
|
|
331
|
+
return resource as ResourceMap[RT]
|
|
324
332
|
}
|
|
333
|
+
|
|
334
|
+
throw new CommercetoolsError<ReferencedResourceNotFoundError>({
|
|
335
|
+
code: 'ReferencedResourceNotFound',
|
|
336
|
+
message:
|
|
337
|
+
`The referenced object of type '${identifier.typeId}' with key ` +
|
|
338
|
+
`'${identifier.key}' was not found. It either doesn't exist, or it ` +
|
|
339
|
+
`can't be accessed from this endpoint (e.g., if the endpoint ` +
|
|
340
|
+
`filters by store or customer account).`,
|
|
341
|
+
typeId: identifier.typeId,
|
|
342
|
+
key: identifier.key,
|
|
343
|
+
})
|
|
325
344
|
}
|
|
326
|
-
|
|
345
|
+
throw new CommercetoolsError<InvalidJsonInputError>({
|
|
346
|
+
code: 'InvalidJsonInput',
|
|
347
|
+
message: 'Request body does not contain valid JSON.',
|
|
348
|
+
detailedErrorMessage: "ResourceIdentifier requires an 'id' xor a 'key'",
|
|
349
|
+
})
|
|
327
350
|
}
|
|
328
351
|
|
|
329
352
|
addProject = (projectKey: string): Project => {
|
|
@@ -415,12 +438,15 @@ export class InMemoryStorage extends AbstractStorage {
|
|
|
415
438
|
reference.typeId !== undefined &&
|
|
416
439
|
(reference.id !== undefined || reference.key !== undefined)
|
|
417
440
|
) {
|
|
418
|
-
//
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
441
|
+
// First check if the object is already resolved. This is the case when
|
|
442
|
+
// the complete resource is pushed via the .add() method.
|
|
443
|
+
if (!reference.obj) {
|
|
444
|
+
reference.obj = this.getByResourceIdentifier(projectKey, {
|
|
445
|
+
typeId: reference.typeId,
|
|
446
|
+
id: reference.id,
|
|
447
|
+
key: reference.key,
|
|
448
|
+
} as ResourceIdentifier)
|
|
449
|
+
}
|
|
424
450
|
if (expand) {
|
|
425
451
|
this._resolveResource(projectKey, reference.obj, expand)
|
|
426
452
|
}
|
package/src/types.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type * as ctp from '@commercetools/platform-sdk'
|
|
|
2
2
|
import { RepositoryMap } from './repositories/index.js'
|
|
3
3
|
import AbstractService from './services/abstract.js'
|
|
4
4
|
|
|
5
|
+
export const isType = <T>(x: T) => x
|
|
6
|
+
|
|
5
7
|
export type Writable<T> = { -readonly [P in keyof T]: Writable<T[P]> }
|
|
6
8
|
export type ShallowWritable<T> = { -readonly [P in keyof T]: T[P] }
|
|
7
9
|
|