@labdigital/commercetools-mock 1.8.1 → 1.10.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@labdigital/commercetools-mock",
3
3
  "author": "Michael van Tellingen",
4
- "version": "1.8.1",
4
+ "version": "1.10.0",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.js",
@@ -1,14 +1,215 @@
1
- import type { BusinessUnit } from '@commercetools/platform-sdk'
1
+ import {
2
+ type Associate,
3
+ type BusinessUnit,
4
+ type BusinessUnitAddAddressAction,
5
+ type BusinessUnitAddAssociateAction,
6
+ type BusinessUnitAddStoreAction,
7
+ type BusinessUnitChangeAddressAction,
8
+ type BusinessUnitChangeNameAction,
9
+ type BusinessUnitChangeParentUnitAction,
10
+ type BusinessUnitDraft,
11
+ type BusinessUnitSetAssociatesAction,
12
+ type BusinessUnitSetContactEmailAction,
13
+ type BusinessUnitSetStoreModeAction,
14
+ type Company,
15
+ type Division,
16
+ BusinessUnitChangeStatusAction,
17
+ CompanyDraft,
18
+ DivisionDraft,
19
+ } from '@commercetools/platform-sdk'
2
20
  import {
3
21
  AbstractResourceRepository,
4
22
  type RepositoryContext,
5
23
  } from './abstract.js'
24
+ import { getBaseResourceProperties } from '../helpers.js'
25
+ import {
26
+ createAddress,
27
+ createAssociate,
28
+ createCustomFields,
29
+ getBusinessUnitKeyReference,
30
+ getStoreKeyReference,
31
+ } from './helpers.js'
32
+ import { Writable } from '../types.js'
6
33
 
7
34
  export class BusinessUnitRepository extends AbstractResourceRepository<'business-unit'> {
8
35
  getTypeId() {
9
36
  return 'business-unit' as const
10
37
  }
11
- create(context: RepositoryContext, draft: any): BusinessUnit {
12
- throw new Error('Method not implemented.')
38
+
39
+ private _isCompanyDraft(draft: BusinessUnitDraft): draft is CompanyDraft {
40
+ return draft.unitType === 'Company'
41
+ }
42
+
43
+ private _isDivisionDraft(draft: BusinessUnitDraft): draft is DivisionDraft {
44
+ return draft.unitType === 'Division'
45
+ }
46
+
47
+ create(context: RepositoryContext, draft: BusinessUnitDraft): BusinessUnit {
48
+ const resource = {
49
+ ...getBaseResourceProperties(),
50
+ key: draft.key,
51
+ status: draft.status,
52
+ stores: draft.stores?.map((s) =>
53
+ getStoreKeyReference(s, context.projectKey, this._storage)
54
+ ),
55
+ storeMode: draft.storeMode,
56
+ name: draft.name,
57
+ contactEmail: draft.contactEmail,
58
+ addresses: draft.addresses?.map((a) =>
59
+ createAddress(a, context.projectKey, this._storage)
60
+ ),
61
+ custom: createCustomFields(
62
+ draft.custom,
63
+ context.projectKey,
64
+ this._storage
65
+ ),
66
+ shippingAddressIds: draft.shippingAddresses,
67
+ defaultShippingAddressId: draft.defaultShippingAddress,
68
+ billingAddressIds: draft.billingAddresses,
69
+ associateMode: draft.associateMode,
70
+ associates: draft.associates?.map((a) =>
71
+ createAssociate(a, context.projectKey, this._storage)
72
+ ),
73
+ }
74
+
75
+ if (this._isDivisionDraft(draft)) {
76
+ const division = {
77
+ ...resource,
78
+ parentUnit: getBusinessUnitKeyReference(
79
+ draft.parentUnit,
80
+ context.projectKey,
81
+ this._storage
82
+ ),
83
+ } as Division
84
+
85
+ this.saveNew(context, division)
86
+ return division
87
+ } else if (this._isCompanyDraft(draft)) {
88
+ const company = resource as Company
89
+
90
+ this.saveNew(context, company)
91
+ return company
92
+ }
93
+
94
+ throw new Error('Invalid business unit type')
95
+ }
96
+
97
+ actions = {
98
+ addAddress: (
99
+ context: RepositoryContext,
100
+ resource: Writable<BusinessUnit>,
101
+ { address }: BusinessUnitAddAddressAction
102
+ ) => {
103
+ const newAddress = createAddress(
104
+ address,
105
+ context.projectKey,
106
+ this._storage
107
+ )
108
+ if (newAddress) {
109
+ resource.addresses.push(newAddress)
110
+ }
111
+ },
112
+ addAssociate: (
113
+ context: RepositoryContext,
114
+ resource: Writable<BusinessUnit>,
115
+ { associate }: BusinessUnitAddAssociateAction
116
+ ) => {
117
+ const newAssociate = createAssociate(
118
+ associate,
119
+ context.projectKey,
120
+ this._storage
121
+ )
122
+ if (newAssociate) {
123
+ resource.associates.push(newAssociate)
124
+ }
125
+ },
126
+ setAssociates: (
127
+ context: RepositoryContext,
128
+ resource: Writable<BusinessUnit>,
129
+ { associates }: BusinessUnitSetAssociatesAction
130
+ ) => {
131
+ const newAssociates = associates
132
+ .map((a) => createAssociate(a, context.projectKey, this._storage))
133
+ .filter((a): a is Writable<Associate> => a !== undefined)
134
+ resource.associates = newAssociates || undefined
135
+ },
136
+ setContactEmail: (
137
+ context: RepositoryContext,
138
+ resource: Writable<BusinessUnit>,
139
+ { contactEmail }: BusinessUnitSetContactEmailAction
140
+ ) => {
141
+ resource.contactEmail = contactEmail
142
+ },
143
+ setStoreMode: (
144
+ context: RepositoryContext,
145
+ resource: Writable<BusinessUnit>,
146
+ { storeMode }: BusinessUnitSetStoreModeAction
147
+ ) => {
148
+ resource.storeMode = storeMode
149
+ },
150
+ changeAssociateMode: (
151
+ context: RepositoryContext,
152
+ resource: Writable<BusinessUnit>,
153
+ { storeMode }: BusinessUnitSetStoreModeAction
154
+ ) => {
155
+ resource.associateMode = storeMode
156
+ },
157
+ changeName: (
158
+ context: RepositoryContext,
159
+ resource: Writable<BusinessUnit>,
160
+ { name }: BusinessUnitChangeNameAction
161
+ ) => {
162
+ resource.name = name
163
+ },
164
+ changeAddress: (
165
+ context: RepositoryContext,
166
+ resource: Writable<BusinessUnit>,
167
+ { address }: BusinessUnitChangeAddressAction
168
+ ) => {
169
+ const newAddress = createAddress(
170
+ address,
171
+ context.projectKey,
172
+ this._storage
173
+ )
174
+ if (newAddress) {
175
+ resource.addresses.push(newAddress)
176
+ }
177
+ },
178
+ addStore: (
179
+ context: RepositoryContext,
180
+ resource: Writable<BusinessUnit>,
181
+ { store }: BusinessUnitAddStoreAction
182
+ ) => {
183
+ const newStore = getStoreKeyReference(
184
+ store,
185
+ context.projectKey,
186
+ this._storage
187
+ )
188
+ if (newStore) {
189
+ if (!resource.stores) {
190
+ resource.stores = []
191
+ }
192
+
193
+ resource.stores.push(newStore)
194
+ }
195
+ },
196
+ changeParentUnit: (
197
+ context: RepositoryContext,
198
+ resource: Writable<BusinessUnit>,
199
+ { parentUnit }: BusinessUnitChangeParentUnitAction
200
+ ) => {
201
+ resource.parentUnit = getBusinessUnitKeyReference(
202
+ parentUnit,
203
+ context.projectKey,
204
+ this._storage
205
+ )
206
+ },
207
+ changeStatus: (
208
+ context: RepositoryContext,
209
+ resource: Writable<BusinessUnit>,
210
+ { status }: BusinessUnitChangeStatusAction
211
+ ) => {
212
+ resource.status = status
213
+ },
13
214
  }
14
215
  }
@@ -5,6 +5,7 @@ import type {
5
5
  CartDiscountChangeTargetAction,
6
6
  CartDiscountDraft,
7
7
  CartDiscountSetCustomFieldAction,
8
+ CartDiscountSetCustomTypeAction,
8
9
  CartDiscountSetDescriptionAction,
9
10
  CartDiscountSetKeyAction,
10
11
  CartDiscountSetValidFromAction,
@@ -162,7 +163,6 @@ export class CartDiscountRepository extends AbstractResourceRepository<'cart-dis
162
163
  ) => {
163
164
  resource.target = target
164
165
  },
165
-
166
166
  setCustomField: (
167
167
  context: RepositoryContext,
168
168
  resource: Writable<CartDiscount>,
@@ -190,5 +190,30 @@ export class CartDiscountRepository extends AbstractResourceRepository<'cart-dis
190
190
  resource.custom.fields[name] = value
191
191
  }
192
192
  },
193
+ setCustomType: (
194
+ context: RepositoryContext,
195
+ resource: Writable<CartDiscount>,
196
+ { type, fields }: CartDiscountSetCustomTypeAction
197
+ ) => {
198
+ if (!type) {
199
+ resource.custom = undefined
200
+ } else {
201
+ const resolvedType = this._storage.getByResourceIdentifier(
202
+ context.projectKey,
203
+ type
204
+ )
205
+ if (!resolvedType) {
206
+ throw new Error(`Type ${type} not found`)
207
+ }
208
+
209
+ resource.custom = {
210
+ type: {
211
+ typeId: 'type',
212
+ id: resolvedType.id,
213
+ },
214
+ fields: fields || {},
215
+ }
216
+ }
217
+ },
193
218
  }
194
219
  }
@@ -21,6 +21,7 @@ import type {
21
21
  Price,
22
22
  Product,
23
23
  ProductPagedQueryResponse,
24
+ CartRemoveDiscountCodeAction,
24
25
  ProductVariant,
25
26
  } from '@commercetools/platform-sdk'
26
27
  import { v4 as uuidv4 } from 'uuid'
@@ -415,6 +416,15 @@ export class CartRepository extends AbstractResourceRepository<'cart'> {
415
416
  custom: custom,
416
417
  }
417
418
  },
419
+ removeDiscountCode: (
420
+ context: RepositoryContext,
421
+ resource: Writable<Cart>,
422
+ { discountCode }: CartRemoveDiscountCodeAction
423
+ ) => {
424
+ resource.discountCodes = resource.discountCodes.filter(
425
+ (code) => code.discountCode.id !== discountCode.id
426
+ )
427
+ },
418
428
  }
419
429
  draftLineItemtoLineItem = (
420
430
  projectKey: string,
@@ -1,24 +1,34 @@
1
- import type {
2
- Address,
3
- BaseAddress,
4
- CentPrecisionMoney,
5
- CustomFields,
6
- CustomFieldsDraft,
7
- HighPrecisionMoney,
8
- HighPrecisionMoneyDraft,
9
- InvalidJsonInputError,
10
- Price,
11
- PriceDraft,
12
- Reference,
13
- ReferencedResourceNotFoundError,
14
- ResourceIdentifier,
15
- Store,
16
- StoreKeyReference,
17
- StoreReference,
18
- StoreResourceIdentifier,
19
- Type,
20
- TypedMoney,
21
- _Money,
1
+ import {
2
+ AssociateRoleReference,
3
+ type Address,
4
+ type Associate,
5
+ type AssociateDraft,
6
+ type AssociateRoleAssignment,
7
+ type AssociateRoleAssignmentDraft,
8
+ type AssociateRoleKeyReference,
9
+ type AssociateRoleResourceIdentifier,
10
+ type BaseAddress,
11
+ type CentPrecisionMoney,
12
+ type CustomFields,
13
+ type CustomFieldsDraft,
14
+ type HighPrecisionMoney,
15
+ type HighPrecisionMoneyDraft,
16
+ type InvalidJsonInputError,
17
+ type Price,
18
+ type PriceDraft,
19
+ type Reference,
20
+ type ReferencedResourceNotFoundError,
21
+ type ResourceIdentifier,
22
+ type Store,
23
+ type StoreKeyReference,
24
+ type StoreReference,
25
+ type StoreResourceIdentifier,
26
+ type Type,
27
+ type TypedMoney,
28
+ type _Money,
29
+ BusinessUnitResourceIdentifier,
30
+ BusinessUnitKeyReference,
31
+ BusinessUnitReference,
22
32
  } from '@commercetools/platform-sdk'
23
33
  import type { Request } from 'express'
24
34
  import { v4 as uuidv4 } from 'uuid'
@@ -219,3 +229,90 @@ export const getRepositoryContext = (request: Request): RepositoryContext => ({
219
229
  projectKey: request.params.projectKey,
220
230
  storeKey: request.params.storeKey,
221
231
  })
232
+
233
+ export const createAssociate = (
234
+ a: AssociateDraft,
235
+ projectKey: string,
236
+ storage: AbstractStorage
237
+ ): Associate | undefined => {
238
+ if (!a) return undefined
239
+
240
+ if (!a.associateRoleAssignments) {
241
+ throw new Error('AssociateRoleAssignments is required')
242
+ }
243
+
244
+ return {
245
+ customer: getReferenceFromResourceIdentifier(
246
+ a.customer,
247
+ projectKey,
248
+ storage
249
+ ),
250
+ associateRoleAssignments: a.associateRoleAssignments?.map(
251
+ (a: AssociateRoleAssignmentDraft): AssociateRoleAssignment => ({
252
+ associateRole: getAssociateRoleKeyReference(
253
+ a.associateRole,
254
+ projectKey,
255
+ storage
256
+ ),
257
+ inheritance: a.inheritance as string,
258
+ })
259
+ ),
260
+ roles: a.roles as string[],
261
+ }
262
+ }
263
+
264
+ export const getAssociateRoleKeyReference = (
265
+ id: AssociateRoleResourceIdentifier,
266
+ projectKey: string,
267
+ storage: AbstractStorage
268
+ ): AssociateRoleKeyReference => {
269
+ if (id.key) {
270
+ return {
271
+ typeId: 'associate-role',
272
+ key: id.key,
273
+ }
274
+ }
275
+
276
+ const value = getReferenceFromResourceIdentifier<AssociateRoleReference>(
277
+ id,
278
+ projectKey,
279
+ storage
280
+ )
281
+
282
+ if (!value.obj?.key) {
283
+ throw new Error('No associate-role found for reference')
284
+ }
285
+
286
+ return {
287
+ typeId: 'associate-role',
288
+ key: value.obj?.key,
289
+ }
290
+ }
291
+
292
+ export const getBusinessUnitKeyReference = (
293
+ id: BusinessUnitResourceIdentifier,
294
+ projectKey: string,
295
+ storage: AbstractStorage
296
+ ): BusinessUnitKeyReference => {
297
+ if (id.key) {
298
+ return {
299
+ typeId: 'business-unit',
300
+ key: id.key,
301
+ }
302
+ }
303
+
304
+ const value = getReferenceFromResourceIdentifier<BusinessUnitReference>(
305
+ id,
306
+ projectKey,
307
+ storage
308
+ )
309
+
310
+ if (!value.obj?.key) {
311
+ throw new Error('No business-unit found for reference')
312
+ }
313
+
314
+ return {
315
+ typeId: 'business-unit',
316
+ key: value.obj?.key,
317
+ }
318
+ }
@@ -35,7 +35,7 @@ describe('Associate roles query', () => {
35
35
  expect(response.status).toBe(200)
36
36
  expect(response.body.count).toBe(1)
37
37
 
38
- const associateRole = response.body.results[0] as AssociateRole
38
+ associateRole = response.body.results[0] as AssociateRole
39
39
 
40
40
  expect(associateRole.key).toBe('example-role-associate-role')
41
41
  })
@@ -0,0 +1,42 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from 'vitest'
2
+ import { CommercetoolsMock } from '../ctMock.js'
3
+ import { BusinessUnit } from '@commercetools/platform-sdk'
4
+ import supertest from 'supertest'
5
+
6
+ describe('Business units query', () => {
7
+ const ctMock = new CommercetoolsMock()
8
+ let businessUnit: BusinessUnit | undefined
9
+
10
+ beforeEach(async () => {
11
+ const response = await supertest(ctMock.app)
12
+ .post('/dummy/business-units')
13
+ .send({
14
+ key: 'example-business-unit',
15
+ status: 'Active',
16
+ name: 'Example Business Unit',
17
+ unitType: 'Company',
18
+ })
19
+
20
+ expect(response.status).toBe(201)
21
+
22
+ businessUnit = response.body as BusinessUnit
23
+ })
24
+
25
+ afterEach(() => {
26
+ ctMock.clear()
27
+ })
28
+
29
+ test('no filter', async () => {
30
+ const response = await supertest(ctMock.app)
31
+ .get('/dummy/business-units')
32
+ .query('{}')
33
+ .send()
34
+
35
+ expect(response.status).toBe(200)
36
+ expect(response.body.count).toBe(1)
37
+
38
+ businessUnit = response.body.results[0] as BusinessUnit
39
+
40
+ expect(businessUnit.key).toBe('example-business-unit')
41
+ })
42
+ })
@@ -0,0 +1,17 @@
1
+ import { Router } from 'express'
2
+ import { BusinessUnitRepository } from '../repositories/business-unit.js'
3
+ import AbstractService from './abstract.js'
4
+
5
+ export class BusinessUnitServices extends AbstractService {
6
+ public repository: BusinessUnitRepository
7
+
8
+ constructor(parent: Router, repository: BusinessUnitRepository) {
9
+ super(parent)
10
+
11
+ this.repository = repository
12
+ }
13
+
14
+ protected getBasePath(): string {
15
+ return 'business-units'
16
+ }
17
+ }
@@ -359,4 +359,22 @@ describe('Cart Discounts Update Actions', () => {
359
359
  })
360
360
  expect(response.status).toBe(400)
361
361
  })
362
+
363
+ test('remove all custom fields', async () => {
364
+ assert(cartDiscount, 'cart discount not created')
365
+
366
+ const response = await supertest(ctMock.app)
367
+ .post(`/dummy/cart-discounts/${cartDiscount.id}`)
368
+ .send({
369
+ version: 1,
370
+ actions: [
371
+ {
372
+ action: 'setCustomType',
373
+ },
374
+ ],
375
+ })
376
+ expect(response.status).toBe(200)
377
+ expect(response.body.version).toBe(2)
378
+ expect(response.body.custom).toBeUndefined()
379
+ })
362
380
  })
@@ -42,7 +42,7 @@ describe('Categories Query', () => {
42
42
  expect(response.status).toBe(200)
43
43
  expect(response.body.count).toBe(1)
44
44
 
45
- const category = response.body.results[0] as Category
45
+ category = response.body.results[0] as Category
46
46
 
47
47
  expect(category.name.en).toBe('Top hat')
48
48
  })
@@ -27,6 +27,7 @@ export class CustomerService extends AbstractService {
27
27
  ? // @ts-ignore
28
28
  +request.params.ttlMinutes
29
29
  : 34560
30
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
30
31
  const { version, ...rest } = getBaseResourceProperties()
31
32
 
32
33
  return response.status(200).send({
@@ -1,4 +1,5 @@
1
- import { AssociateRoleServices } from './associate-roles'
1
+ import { AssociateRoleServices } from './associate-roles.js'
2
+ import { BusinessUnitServices } from './business-units.js'
2
3
  import { CartService } from './cart.js'
3
4
  import { CartDiscountService } from './cart-discount.js'
4
5
  import { CategoryServices } from './category.js'
@@ -32,6 +33,7 @@ import { AttributeGroupService } from './attribute-group.js'
32
33
 
33
34
  export const createServices = (router: any, repos: any) => ({
34
35
  'associate-role': new AssociateRoleServices(router, repos['associate-role']),
36
+ 'business-unit': new BusinessUnitServices(router, repos['business-unit']),
35
37
  category: new CategoryServices(router, repos['category']),
36
38
  cart: new CartService(router, repos['cart'], repos['order']),
37
39
  'cart-discount': new CartDiscountService(router, repos['cart-discount']),
@@ -163,7 +163,6 @@ describe('Product', () => {
163
163
  describe('Product update actions', () => {
164
164
  const ctMock = new CommercetoolsMock()
165
165
  let productPublished: Product | undefined
166
- let productUnpublished: Product | undefined
167
166
 
168
167
  beforeEach(async () => {
169
168
  let response
@@ -179,7 +178,6 @@ describe('Product update actions', () => {
179
178
  .send(unpublishedProductDraft)
180
179
 
181
180
  expect(response.status).toBe(201)
182
- productUnpublished = response.body
183
181
  })
184
182
 
185
183
  test('setAttribute masterVariant (staged)', async () => {
@@ -0,0 +1,52 @@
1
+ import type { Project } from '@commercetools/platform-sdk'
2
+ import supertest from 'supertest'
3
+ import { afterAll, afterEach, beforeAll, describe, expect, test } from 'vitest'
4
+ import { CommercetoolsMock } from '../index.js'
5
+
6
+ const ctMock = new CommercetoolsMock()
7
+
8
+ describe('Project', () => {
9
+ beforeAll(() => {
10
+ ctMock.start()
11
+ })
12
+
13
+ afterEach(() => {
14
+ ctMock.clear()
15
+ })
16
+
17
+ afterAll(() => {
18
+ ctMock.stop()
19
+ })
20
+
21
+ test('Get project by key', async () => {
22
+ const response = await supertest(ctMock.app).get('/dummy/')
23
+
24
+ expect(response.status).toBe(200)
25
+ expect(response.body).toEqual({
26
+ version: 1,
27
+ carts: {
28
+ countryTaxRateFallbackEnabled: false,
29
+ deleteDaysAfterLastModification: 90,
30
+ },
31
+ countries: [],
32
+ createdAt: '2018-10-04T11:32:12.603Z',
33
+ currencies: [],
34
+ key: 'dummy',
35
+ languages: [],
36
+ messages: {
37
+ deleteDaysAfterCreation: 15,
38
+ enabled: false,
39
+ },
40
+ name: '',
41
+ searchIndexing: {
42
+ orders: {
43
+ status: 'Deactivated',
44
+ },
45
+ products: {
46
+ status: 'Deactivated',
47
+ },
48
+ },
49
+ trialUntil: '2018-12',
50
+ } as Project)
51
+ })
52
+ })