@labdigital/commercetools-mock 2.8.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 +235 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -2
- package/dist/index.d.ts +32 -2
- package/dist/index.js +235 -41
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/predicateParser.test.ts +96 -11
- package/src/lib/predicateParser.ts +43 -12
- package/src/oauth/server.ts +11 -1
- 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/shipping-method.ts +98 -22
- package/src/services/custom-object.ts +19 -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 +82 -59
- package/src/types.ts +2 -0
|
@@ -1,24 +1,48 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
Cart,
|
|
3
|
+
CartDraft,
|
|
2
4
|
ShippingMethodDraft,
|
|
3
5
|
TaxCategoryDraft,
|
|
6
|
+
ZoneDraft,
|
|
4
7
|
} from '@commercetools/platform-sdk'
|
|
5
8
|
import supertest from 'supertest'
|
|
6
9
|
import { afterEach, beforeEach, describe, expect, test } from 'vitest'
|
|
7
10
|
import { CommercetoolsMock } from '../index.js'
|
|
11
|
+
import { isType } from '../types.js'
|
|
8
12
|
|
|
9
13
|
const ctMock = new CommercetoolsMock()
|
|
10
14
|
|
|
11
15
|
describe('Shipping method', () => {
|
|
12
16
|
beforeEach(async () => {
|
|
13
|
-
|
|
14
|
-
name: 'foo',
|
|
15
|
-
key: 'standard',
|
|
16
|
-
rates: [],
|
|
17
|
-
}
|
|
18
|
-
const createResponse = await supertest(ctMock.app)
|
|
17
|
+
await supertest(ctMock.app)
|
|
19
18
|
.post('/dummy/tax-categories')
|
|
20
|
-
.send(
|
|
21
|
-
|
|
19
|
+
.send(
|
|
20
|
+
isType<TaxCategoryDraft>({
|
|
21
|
+
name: 'foo',
|
|
22
|
+
key: 'standard',
|
|
23
|
+
rates: [],
|
|
24
|
+
})
|
|
25
|
+
)
|
|
26
|
+
.then((res) => {
|
|
27
|
+
expect(res.status).toEqual(201)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
await supertest(ctMock.app)
|
|
31
|
+
.post('/dummy/zones')
|
|
32
|
+
.send(
|
|
33
|
+
isType<ZoneDraft>({
|
|
34
|
+
name: 'The Netherlands',
|
|
35
|
+
key: 'NL',
|
|
36
|
+
locations: [
|
|
37
|
+
{
|
|
38
|
+
country: 'NL',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
})
|
|
42
|
+
)
|
|
43
|
+
.then((res) => {
|
|
44
|
+
expect(res.status).toEqual(201)
|
|
45
|
+
})
|
|
22
46
|
})
|
|
23
47
|
|
|
24
48
|
afterEach(async () => {
|
|
@@ -75,28 +99,103 @@ describe('Shipping method', () => {
|
|
|
75
99
|
})
|
|
76
100
|
|
|
77
101
|
test('Get shipping methods matching cart', async () => {
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
102
|
+
const cart = await supertest(ctMock.app)
|
|
103
|
+
.post('/dummy/carts')
|
|
104
|
+
.send(
|
|
105
|
+
isType<CartDraft>({
|
|
106
|
+
currency: 'EUR',
|
|
107
|
+
shippingAddress: {
|
|
108
|
+
country: 'NL',
|
|
109
|
+
},
|
|
110
|
+
})
|
|
111
|
+
)
|
|
112
|
+
.then((res) => res.body as Cart)
|
|
113
|
+
|
|
114
|
+
await supertest(ctMock.app)
|
|
85
115
|
.post('/dummy/shipping-methods')
|
|
86
|
-
.send(
|
|
116
|
+
.send(
|
|
117
|
+
isType<ShippingMethodDraft>({
|
|
118
|
+
name: 'NL',
|
|
119
|
+
taxCategory: { typeId: 'tax-category', key: 'standard' },
|
|
120
|
+
isDefault: true,
|
|
121
|
+
zoneRates: [
|
|
122
|
+
{
|
|
123
|
+
zone: {
|
|
124
|
+
typeId: 'zone',
|
|
125
|
+
key: 'NL',
|
|
126
|
+
},
|
|
127
|
+
shippingRates: [
|
|
128
|
+
{
|
|
129
|
+
price: {
|
|
130
|
+
currencyCode: 'EUR',
|
|
131
|
+
centAmount: 495,
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
})
|
|
138
|
+
)
|
|
139
|
+
.then((res) => {
|
|
140
|
+
expect(res.status).toEqual(201)
|
|
141
|
+
})
|
|
87
142
|
|
|
88
|
-
|
|
143
|
+
await supertest(ctMock.app)
|
|
144
|
+
.post('/dummy/shipping-methods')
|
|
145
|
+
.send(
|
|
146
|
+
isType<ShippingMethodDraft>({
|
|
147
|
+
name: 'NL/GBP',
|
|
148
|
+
taxCategory: { typeId: 'tax-category', key: 'standard' },
|
|
149
|
+
isDefault: true,
|
|
150
|
+
zoneRates: [
|
|
151
|
+
{
|
|
152
|
+
zone: {
|
|
153
|
+
typeId: 'zone',
|
|
154
|
+
key: 'NL',
|
|
155
|
+
},
|
|
156
|
+
shippingRates: [
|
|
157
|
+
{
|
|
158
|
+
price: {
|
|
159
|
+
currencyCode: 'GBP',
|
|
160
|
+
centAmount: 495,
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
})
|
|
167
|
+
)
|
|
168
|
+
.then((res) => {
|
|
169
|
+
expect(res.status).toEqual(201)
|
|
170
|
+
})
|
|
89
171
|
|
|
90
172
|
const response = await supertest(ctMock.app).get(
|
|
91
|
-
`/dummy/shipping-methods/matching-cart?cartId
|
|
173
|
+
`/dummy/shipping-methods/matching-cart?cartId=${cart.id}`
|
|
92
174
|
)
|
|
93
175
|
|
|
94
|
-
expect(response.status).toBe(200)
|
|
95
|
-
expect(response.body).
|
|
176
|
+
expect(response.status, JSON.stringify(response.body)).toBe(200)
|
|
177
|
+
expect(response.body).toMatchObject({
|
|
96
178
|
count: 1,
|
|
97
179
|
limit: 20,
|
|
98
180
|
offset: 0,
|
|
99
|
-
results: [
|
|
181
|
+
results: [
|
|
182
|
+
{
|
|
183
|
+
name: 'NL',
|
|
184
|
+
zoneRates: [
|
|
185
|
+
{
|
|
186
|
+
shippingRates: [
|
|
187
|
+
{
|
|
188
|
+
isMatching: true,
|
|
189
|
+
price: {
|
|
190
|
+
currencyCode: 'EUR',
|
|
191
|
+
centAmount: 495,
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
],
|
|
100
199
|
total: 1,
|
|
101
200
|
})
|
|
102
201
|
})
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { Router } from 'express'
|
|
1
|
+
import { Request, Response, Router } from 'express'
|
|
2
2
|
import { ShippingMethodRepository } from '../repositories/shipping-method.js'
|
|
3
3
|
import AbstractService from './abstract.js'
|
|
4
|
+
import { getRepositoryContext } from '../repositories/helpers.js'
|
|
5
|
+
import { queryParamsValue } from '../helpers.js'
|
|
4
6
|
|
|
5
7
|
export class ShippingMethodService extends AbstractService {
|
|
6
8
|
public repository: ShippingMethodRepository
|
|
@@ -16,6 +18,21 @@ export class ShippingMethodService extends AbstractService {
|
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
extraRoutes(parent: Router) {
|
|
19
|
-
parent.get('/matching-cart', this.
|
|
21
|
+
parent.get('/matching-cart', this.matchingCart.bind(this))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
matchingCart(request: Request, response: Response) {
|
|
25
|
+
const cartId = queryParamsValue(request.query.cartId)
|
|
26
|
+
if (!cartId) {
|
|
27
|
+
return response.status(400).send()
|
|
28
|
+
}
|
|
29
|
+
const result = this.repository.matchingCart(
|
|
30
|
+
getRepositoryContext(request),
|
|
31
|
+
cartId,
|
|
32
|
+
{
|
|
33
|
+
expand: this._parseParam(request.query.expand),
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
return response.status(200).send(result)
|
|
20
37
|
}
|
|
21
38
|
}
|
|
@@ -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