@labdigital/commercetools-mock 2.17.0 → 2.18.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.
Files changed (178) hide show
  1. package/dist/index.cjs +4219 -3989
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +268 -415
  4. package/dist/index.d.ts +268 -415
  5. package/dist/index.js +4219 -3989
  6. package/dist/index.js.map +1 -1
  7. package/package.json +44 -46
  8. package/src/constants.ts +2 -2
  9. package/src/ctMock.test.ts +11 -11
  10. package/src/ctMock.ts +141 -127
  11. package/src/deprecation.ts +8 -0
  12. package/src/exceptions.ts +17 -15
  13. package/src/helpers.ts +32 -32
  14. package/src/index.test.ts +128 -128
  15. package/src/index.ts +3 -3
  16. package/src/lib/expandParser.ts +13 -13
  17. package/src/lib/haversine.test.ts +9 -9
  18. package/src/lib/haversine.ts +11 -11
  19. package/src/lib/masking.ts +11 -11
  20. package/src/lib/parser.ts +2 -2
  21. package/src/lib/password.ts +23 -3
  22. package/src/lib/predicateParser.test.ts +185 -183
  23. package/src/lib/predicateParser.ts +234 -234
  24. package/src/lib/projectionSearchFilter.test.ts +103 -101
  25. package/src/lib/projectionSearchFilter.ts +152 -150
  26. package/src/lib/proxy.ts +5 -5
  27. package/src/oauth/errors.ts +4 -4
  28. package/src/oauth/helpers.ts +6 -6
  29. package/src/oauth/server.test.ts +110 -67
  30. package/src/oauth/server.ts +161 -141
  31. package/src/oauth/store.ts +49 -44
  32. package/src/priceSelector.test.ts +35 -35
  33. package/src/priceSelector.ts +30 -30
  34. package/src/product-projection-search.ts +136 -134
  35. package/src/projectAPI.test.ts +7 -7
  36. package/src/projectAPI.ts +24 -22
  37. package/src/repositories/abstract.ts +168 -116
  38. package/src/repositories/associate-role.ts +90 -77
  39. package/src/repositories/attribute-group.ts +51 -40
  40. package/src/repositories/business-unit.ts +168 -148
  41. package/src/repositories/cart/actions.ts +489 -0
  42. package/src/repositories/cart/helpers.ts +30 -0
  43. package/src/repositories/cart/index.ts +180 -0
  44. package/src/repositories/cart-discount/actions.ts +148 -0
  45. package/src/repositories/cart-discount/index.ts +86 -0
  46. package/src/repositories/category/actions.ts +231 -0
  47. package/src/repositories/category/index.ts +52 -0
  48. package/src/repositories/channel.ts +88 -90
  49. package/src/repositories/custom-object.ts +46 -45
  50. package/src/repositories/customer/actions.ts +165 -0
  51. package/src/repositories/customer/index.ts +79 -0
  52. package/src/repositories/customer-group.ts +66 -55
  53. package/src/repositories/discount-code/actions.ts +149 -0
  54. package/src/repositories/discount-code/index.ts +50 -0
  55. package/src/repositories/errors.ts +10 -10
  56. package/src/repositories/extension.ts +64 -62
  57. package/src/repositories/helpers.ts +117 -118
  58. package/src/repositories/index.ts +80 -79
  59. package/src/repositories/inventory-entry/actions.ts +84 -0
  60. package/src/repositories/inventory-entry/index.ts +44 -0
  61. package/src/repositories/my-customer.ts +114 -0
  62. package/src/repositories/my-order.ts +8 -8
  63. package/src/repositories/order/actions.ts +281 -0
  64. package/src/repositories/{order.test.ts → order/index.test.ts} +77 -77
  65. package/src/repositories/order/index.ts +260 -0
  66. package/src/repositories/order-edit.ts +10 -23
  67. package/src/repositories/payment/actions.ts +305 -0
  68. package/src/repositories/payment/helpers.ts +17 -0
  69. package/src/repositories/payment/index.ts +56 -0
  70. package/src/repositories/product/actions.ts +943 -0
  71. package/src/repositories/product/helpers.ts +98 -0
  72. package/src/repositories/product/index.ts +130 -0
  73. package/src/repositories/product-discount.ts +127 -117
  74. package/src/repositories/product-projection.ts +56 -62
  75. package/src/repositories/product-selection.ts +31 -28
  76. package/src/repositories/product-type.ts +136 -134
  77. package/src/repositories/project.ts +133 -118
  78. package/src/repositories/quote-request.ts +7 -19
  79. package/src/repositories/quote.ts +7 -22
  80. package/src/repositories/review.ts +13 -26
  81. package/src/repositories/shipping-method/actions.ts +198 -0
  82. package/src/repositories/shipping-method/helpers.ts +10 -0
  83. package/src/repositories/shipping-method/index.ts +138 -0
  84. package/src/repositories/shopping-list/actions.ts +295 -0
  85. package/src/repositories/shopping-list/index.ts +122 -0
  86. package/src/repositories/staged-quote.ts +7 -20
  87. package/src/repositories/standalone-price.ts +57 -44
  88. package/src/repositories/state.ts +113 -68
  89. package/src/repositories/store.ts +106 -94
  90. package/src/repositories/subscription.ts +46 -22
  91. package/src/repositories/tax-category/actions.ts +94 -0
  92. package/src/repositories/tax-category/helpers.ts +8 -0
  93. package/src/repositories/tax-category/index.ts +25 -0
  94. package/src/repositories/type/actions.ts +162 -0
  95. package/src/repositories/type/index.ts +24 -0
  96. package/src/repositories/zone.ts +62 -58
  97. package/src/server.ts +9 -9
  98. package/src/services/abstract.ts +75 -72
  99. package/src/services/associate-roles.test.ts +27 -27
  100. package/src/services/associate-roles.ts +7 -7
  101. package/src/services/attribute-group.ts +7 -7
  102. package/src/services/business-units.test.ts +28 -28
  103. package/src/services/business-units.ts +7 -7
  104. package/src/services/cart-discount.test.ts +199 -199
  105. package/src/services/cart-discount.ts +7 -7
  106. package/src/services/cart.test.ts +261 -261
  107. package/src/services/cart.ts +22 -21
  108. package/src/services/category.test.ts +121 -121
  109. package/src/services/category.ts +7 -7
  110. package/src/services/channel.ts +7 -7
  111. package/src/services/custom-object.test.ts +130 -130
  112. package/src/services/custom-object.ts +34 -31
  113. package/src/services/customer-group.ts +7 -7
  114. package/src/services/customer.test.ts +205 -205
  115. package/src/services/customer.ts +31 -29
  116. package/src/services/discount-code.ts +7 -7
  117. package/src/services/extension.ts +7 -7
  118. package/src/services/index.ts +85 -81
  119. package/src/services/inventory-entry.test.ts +106 -106
  120. package/src/services/inventory-entry.ts +7 -7
  121. package/src/services/my-cart.test.ts +56 -56
  122. package/src/services/my-cart.ts +20 -20
  123. package/src/services/my-customer.test.ts +155 -104
  124. package/src/services/my-customer.ts +61 -75
  125. package/src/services/my-order.ts +16 -16
  126. package/src/services/my-payment.test.ts +40 -40
  127. package/src/services/my-payment.ts +7 -7
  128. package/src/services/my-shopping-list.ts +7 -7
  129. package/src/services/order.test.ts +243 -243
  130. package/src/services/order.ts +23 -18
  131. package/src/services/payment.test.ts +40 -40
  132. package/src/services/payment.ts +7 -7
  133. package/src/services/product-discount.ts +7 -7
  134. package/src/services/product-projection.test.ts +190 -190
  135. package/src/services/product-projection.ts +34 -32
  136. package/src/services/product-selection.test.ts +19 -19
  137. package/src/services/product-selection.ts +7 -7
  138. package/src/services/product-type.test.ts +38 -38
  139. package/src/services/product-type.ts +7 -7
  140. package/src/services/product.test.ts +658 -656
  141. package/src/services/product.ts +7 -7
  142. package/src/services/project.test.ts +24 -24
  143. package/src/services/project.ts +17 -17
  144. package/src/services/reviews.ts +7 -7
  145. package/src/services/shipping-method.test.ts +78 -78
  146. package/src/services/shipping-method.ts +16 -16
  147. package/src/services/shopping-list.test.ts +170 -170
  148. package/src/services/shopping-list.ts +7 -7
  149. package/src/services/standalone-price.test.ts +112 -112
  150. package/src/services/standalone-price.ts +7 -7
  151. package/src/services/state.test.ts +30 -30
  152. package/src/services/state.ts +7 -7
  153. package/src/services/store.test.ts +40 -40
  154. package/src/services/store.ts +7 -7
  155. package/src/services/subscription.ts +7 -7
  156. package/src/services/tax-category.test.ts +43 -43
  157. package/src/services/tax-category.ts +7 -7
  158. package/src/services/type.ts +7 -7
  159. package/src/services/zone.ts +7 -7
  160. package/src/shippingCalculator.test.ts +43 -43
  161. package/src/shippingCalculator.ts +23 -23
  162. package/src/storage/abstract.ts +36 -34
  163. package/src/storage/in-memory.ts +237 -233
  164. package/src/storage/index.ts +2 -2
  165. package/src/types.ts +91 -91
  166. package/src/repositories/cart-discount.ts +0 -219
  167. package/src/repositories/cart.ts +0 -659
  168. package/src/repositories/category.ts +0 -256
  169. package/src/repositories/customer.ts +0 -228
  170. package/src/repositories/discount-code.ts +0 -181
  171. package/src/repositories/inventory-entry.ts +0 -109
  172. package/src/repositories/order.ts +0 -514
  173. package/src/repositories/payment.ts +0 -342
  174. package/src/repositories/product.ts +0 -1106
  175. package/src/repositories/shipping-method.ts +0 -312
  176. package/src/repositories/shopping-list.ts +0 -392
  177. package/src/repositories/tax-category.ts +0 -111
  178. package/src/repositories/type.ts +0 -172
@@ -9,18 +9,22 @@ import type {
9
9
  ChannelSetCustomTypeAction,
10
10
  ChannelSetGeoLocationAction,
11
11
  ChannelUpdateAction,
12
- } from '@commercetools/platform-sdk'
13
- import { getBaseResourceProperties } from '../helpers.js'
14
- import type { Writable } from '../types.js'
12
+ } from "@commercetools/platform-sdk";
13
+ import { getBaseResourceProperties } from "../helpers";
14
+ import { AbstractStorage } from "../storage/abstract";
15
+ import type { Writable } from "../types";
15
16
  import {
16
17
  AbstractResourceRepository,
18
+ AbstractUpdateHandler,
19
+ UpdateHandlerInterface,
17
20
  type RepositoryContext,
18
- } from './abstract.js'
19
- import { createAddress, createCustomFields } from './helpers.js'
21
+ } from "./abstract";
22
+ import { createAddress, createCustomFields } from "./helpers";
20
23
 
21
- export class ChannelRepository extends AbstractResourceRepository<'channel'> {
22
- getTypeId() {
23
- return 'channel' as const
24
+ export class ChannelRepository extends AbstractResourceRepository<"channel"> {
25
+ constructor(storage: AbstractStorage) {
26
+ super("channel", storage);
27
+ this.actions = new ChannelUpdateHandler(this._storage);
24
28
  }
25
29
 
26
30
  create(context: RepositoryContext, draft: ChannelDraft): Channel {
@@ -35,95 +39,89 @@ export class ChannelRepository extends AbstractResourceRepository<'channel'> {
35
39
  custom: createCustomFields(
36
40
  draft.custom,
37
41
  context.projectKey,
38
- this._storage
42
+ this._storage,
39
43
  ),
40
- }
41
- this.saveNew(context, resource)
42
- return resource
44
+ };
45
+ return this.saveNew(context, resource);
43
46
  }
47
+ }
44
48
 
45
- actions: Partial<
46
- Record<
47
- ChannelUpdateAction['action'],
48
- (
49
- context: RepositoryContext,
50
- resource: Writable<Channel>,
51
- action: any
52
- ) => void
53
- >
54
- > = {
55
- changeKey: (
56
- context: RepositoryContext,
57
- resource: Writable<Channel>,
58
- { key }: ChannelChangeKeyAction
59
- ) => {
60
- resource.key = key
61
- },
49
+ class ChannelUpdateHandler
50
+ extends AbstractUpdateHandler
51
+ implements Partial<UpdateHandlerInterface<Channel, ChannelUpdateAction>>
52
+ {
53
+ changeDescription(
54
+ context: RepositoryContext,
55
+ resource: Writable<Channel>,
56
+ { description }: ChannelChangeDescriptionAction,
57
+ ) {
58
+ resource.description = description;
59
+ }
62
60
 
63
- changeName: (
64
- context: RepositoryContext,
65
- resource: Writable<Channel>,
66
- { name }: ChannelChangeNameAction
67
- ) => {
68
- resource.name = name
69
- },
61
+ changeKey(
62
+ context: RepositoryContext,
63
+ resource: Writable<Channel>,
64
+ { key }: ChannelChangeKeyAction,
65
+ ) {
66
+ resource.key = key;
67
+ }
70
68
 
71
- changeDescription: (
72
- context: RepositoryContext,
73
- resource: Writable<Channel>,
74
- { description }: ChannelChangeDescriptionAction
75
- ) => {
76
- resource.description = description
77
- },
69
+ changeName(
70
+ context: RepositoryContext,
71
+ resource: Writable<Channel>,
72
+ { name }: ChannelChangeNameAction,
73
+ ) {
74
+ resource.name = name;
75
+ }
78
76
 
79
- setAddress: (
80
- context: RepositoryContext,
81
- resource: Writable<Channel>,
82
- { address }: ChannelSetAddressAction
83
- ) => {
84
- resource.address = createAddress(
85
- address,
86
- context.projectKey,
87
- this._storage
88
- )
89
- },
77
+ setAddress(
78
+ context: RepositoryContext,
79
+ resource: Writable<Channel>,
80
+ { address }: ChannelSetAddressAction,
81
+ ) {
82
+ resource.address = createAddress(
83
+ address,
84
+ context.projectKey,
85
+ this._storage,
86
+ );
87
+ }
90
88
 
91
- setGeoLocation: (
92
- context: RepositoryContext,
93
- resource: Writable<Channel>,
94
- { geoLocation }: ChannelSetGeoLocationAction
95
- ) => {
96
- resource.geoLocation = geoLocation
97
- },
89
+ setCustomField(
90
+ context: RepositoryContext,
91
+ resource: Writable<Channel>,
92
+ { name, value }: ChannelSetCustomFieldAction,
93
+ ) {
94
+ if (!resource.custom) {
95
+ return;
96
+ }
97
+ if (value === null) {
98
+ delete resource.custom.fields[name];
99
+ } else {
100
+ resource.custom.fields[name] = value;
101
+ }
102
+ }
103
+
104
+ setCustomType(
105
+ context: RepositoryContext,
106
+ resource: Writable<Channel>,
107
+ { type, fields }: ChannelSetCustomTypeAction,
108
+ ) {
109
+ if (type) {
110
+ resource.custom = createCustomFields(
111
+ { type, fields },
112
+ context.projectKey,
113
+ this._storage,
114
+ );
115
+ } else {
116
+ resource.custom = undefined;
117
+ }
118
+ }
98
119
 
99
- setCustomType: (
100
- context: RepositoryContext,
101
- resource: Writable<Channel>,
102
- { type, fields }: ChannelSetCustomTypeAction
103
- ) => {
104
- if (type) {
105
- resource.custom = createCustomFields(
106
- { type, fields },
107
- context.projectKey,
108
- this._storage
109
- )
110
- } else {
111
- resource.custom = undefined
112
- }
113
- },
114
- setCustomField: (
115
- context: RepositoryContext,
116
- resource: Writable<Channel>,
117
- { name, value }: ChannelSetCustomFieldAction
118
- ) => {
119
- if (!resource.custom) {
120
- return
121
- }
122
- if (value === null) {
123
- delete resource.custom.fields[name]
124
- } else {
125
- resource.custom.fields[name] = value
126
- }
127
- },
120
+ setGeoLocation(
121
+ context: RepositoryContext,
122
+ resource: Writable<Channel>,
123
+ { geoLocation }: ChannelSetGeoLocationAction,
124
+ ) {
125
+ resource.geoLocation = geoLocation;
128
126
  }
129
127
  }
@@ -2,97 +2,98 @@ import type {
2
2
  CustomObject,
3
3
  CustomObjectDraft,
4
4
  InvalidOperationError,
5
- } from '@commercetools/platform-sdk'
6
- import { CommercetoolsError } from '../exceptions.js'
7
- import { cloneObject, getBaseResourceProperties } from '../helpers.js'
8
- import type { Writable } from '../types.js'
5
+ } from "@commercetools/platform-sdk";
6
+ import { CommercetoolsError } from "~src/exceptions";
7
+ import { AbstractStorage } from "~src/storage";
8
+ import { cloneObject, getBaseResourceProperties } from "../helpers";
9
+ import type { Writable } from "../types";
9
10
  import {
10
11
  AbstractResourceRepository,
11
12
  QueryParams,
12
13
  type RepositoryContext,
13
- } from './abstract.js'
14
- import { checkConcurrentModification } from './errors.js'
14
+ } from "./abstract";
15
+ import { checkConcurrentModification } from "./errors";
15
16
 
16
- export class CustomObjectRepository extends AbstractResourceRepository<'key-value-document'> {
17
- getTypeId() {
18
- return 'key-value-document' as const
17
+ export class CustomObjectRepository extends AbstractResourceRepository<"key-value-document"> {
18
+ constructor(storage: AbstractStorage) {
19
+ super("key-value-document", storage);
19
20
  }
20
21
 
21
22
  create(
22
23
  context: RepositoryContext,
23
- draft: Writable<CustomObjectDraft>
24
+ draft: Writable<CustomObjectDraft>,
24
25
  ): CustomObject {
25
26
  const current = this.getWithContainerAndKey(
26
27
  context,
27
28
  draft.container,
28
- draft.key
29
- ) as Writable<CustomObject | undefined>
29
+ draft.key,
30
+ ) as Writable<CustomObject | undefined>;
30
31
 
31
32
  if (current) {
32
33
  // Only check version if it is passed in the draft
33
34
  if (draft.version) {
34
- checkConcurrentModification(current.version, draft.version, current.id)
35
+ checkConcurrentModification(current.version, draft.version, current.id);
35
36
  } else {
36
- draft.version = current.version
37
+ draft.version = current.version;
37
38
  }
38
39
 
39
40
  if (draft.value !== current.value) {
40
- const updated = cloneObject(current) as Writable<CustomObject>
41
- updated.value = draft.value
42
- updated.version += 1
43
- this.saveUpdate(context, draft.version, updated)
44
- return updated
41
+ const updated = cloneObject(current) as Writable<CustomObject>;
42
+ updated.value = draft.value;
43
+ updated.version += 1;
44
+ this.saveUpdate(context, draft.version, updated);
45
+ return updated;
45
46
  }
46
- return current
47
+ return current;
47
48
  } else {
48
49
  // If the resource is new the only valid version is 0
49
50
  if (draft.version) {
50
51
  throw new CommercetoolsError<InvalidOperationError>(
51
52
  {
52
- code: 'InvalidOperation',
53
- message: 'version on create must be 0',
53
+ code: "InvalidOperation",
54
+ message: "version on create must be 0",
54
55
  },
55
- 400
56
- )
56
+ 400,
57
+ );
57
58
  }
58
- const baseProperties = getBaseResourceProperties()
59
+ const baseProperties = getBaseResourceProperties();
59
60
  const resource: CustomObject = {
60
61
  ...baseProperties,
61
62
  container: draft.container,
62
63
  key: draft.key,
63
64
  value: draft.value,
64
- }
65
+ };
65
66
 
66
- this.saveNew(context, resource)
67
- return resource
67
+ this.saveNew(context, resource);
68
+ return resource;
68
69
  }
69
70
  }
70
71
 
72
+ getWithContainerAndKey(
73
+ context: RepositoryContext,
74
+ container: string,
75
+ key: string,
76
+ ) {
77
+ const items = this._storage.all(context.projectKey, this.getTypeId());
78
+ return items.find(
79
+ (item) => item.container === container && item.key === key,
80
+ );
81
+ }
82
+
71
83
  queryWithContainer(
72
84
  context: RepositoryContext,
73
85
  container: string,
74
- params: QueryParams = {}
86
+ params: QueryParams = {},
75
87
  ) {
76
- const whereClause = params.where || []
77
- whereClause.push(`container="${container}"`)
88
+ const whereClause = params.where || [];
89
+ whereClause.push(`container="${container}"`);
78
90
  const result = this._storage.query(context.projectKey, this.getTypeId(), {
79
91
  ...params,
80
92
  where: whereClause,
81
- })
93
+ });
82
94
 
83
95
  // @ts-ignore
84
- result.results = result.results.map(this.postProcessResource)
85
- return result
86
- }
87
-
88
- getWithContainerAndKey(
89
- context: RepositoryContext,
90
- container: string,
91
- key: string
92
- ) {
93
- const items = this._storage.all(context.projectKey, this.getTypeId())
94
- return items.find(
95
- (item) => item.container === container && item.key === key
96
- )
96
+ result.results = result.results.map(this.postProcessResource);
97
+ return result;
97
98
  }
98
99
  }
@@ -0,0 +1,165 @@
1
+ import type {
2
+ Customer,
3
+ CustomerChangeAddressAction,
4
+ CustomerChangeEmailAction,
5
+ CustomerSetAuthenticationModeAction,
6
+ CustomerSetCompanyNameAction,
7
+ CustomerSetCustomFieldAction,
8
+ CustomerSetCustomerNumberAction,
9
+ CustomerSetFirstNameAction,
10
+ CustomerSetLastNameAction,
11
+ CustomerSetVatIdAction,
12
+ CustomerUpdateAction,
13
+ InvalidInputError,
14
+ InvalidJsonInputError,
15
+ } from "@commercetools/platform-sdk";
16
+ import { CommercetoolsError } from "~src/exceptions";
17
+ import { hashPassword } from "~src/lib/password";
18
+ import type { Writable } from "~src/types";
19
+ import {
20
+ AbstractUpdateHandler,
21
+ UpdateHandlerInterface,
22
+ type RepositoryContext,
23
+ } from "../abstract";
24
+ import { createAddress } from "../helpers";
25
+
26
+ export class CustomerUpdateHandler
27
+ extends AbstractUpdateHandler
28
+ implements Partial<UpdateHandlerInterface<Customer, CustomerUpdateAction>>
29
+ {
30
+ changeAddress(
31
+ context: RepositoryContext,
32
+ resource: Writable<Customer>,
33
+ { addressId, addressKey, address }: CustomerChangeAddressAction,
34
+ ) {
35
+ const oldAddressIndex = resource.addresses.findIndex((a) => {
36
+ if (a.id != undefined && addressId != undefined && a.id === addressId) {
37
+ return true;
38
+ }
39
+
40
+ return (
41
+ a.key != undefined && addressKey != undefined && a.key === addressKey
42
+ );
43
+ });
44
+
45
+ if (oldAddressIndex === -1) {
46
+ throw new CommercetoolsError<InvalidInputError>(
47
+ {
48
+ code: "InvalidInput",
49
+ message: `Address with id '${addressId}' or key '${addressKey}' not found.`,
50
+ },
51
+ 400,
52
+ );
53
+ }
54
+
55
+ const newAddress = createAddress(
56
+ address,
57
+ context.projectKey,
58
+ this._storage,
59
+ );
60
+
61
+ if (newAddress) {
62
+ resource.addresses[oldAddressIndex] = {
63
+ id: addressId,
64
+ ...newAddress,
65
+ };
66
+ }
67
+ }
68
+
69
+ changeEmail(
70
+ _context: RepositoryContext,
71
+ resource: Writable<Customer>,
72
+ { email }: CustomerChangeEmailAction,
73
+ ) {
74
+ resource.email = email;
75
+ }
76
+
77
+ setAuthenticationMode(
78
+ _context: RepositoryContext,
79
+ resource: Writable<Customer>,
80
+ { authMode, password }: CustomerSetAuthenticationModeAction,
81
+ ) {
82
+ if (resource.authenticationMode === authMode) {
83
+ throw new CommercetoolsError<InvalidInputError>(
84
+ {
85
+ code: "InvalidInput",
86
+ message: `The customer is already using the '${resource.authenticationMode}' authentication mode.`,
87
+ },
88
+ 400,
89
+ );
90
+ }
91
+ resource.authenticationMode = authMode;
92
+ if (authMode === "ExternalAuth") {
93
+ delete resource.password;
94
+ return;
95
+ }
96
+ if (authMode === "Password") {
97
+ resource.password = password ? hashPassword(password) : undefined;
98
+ return;
99
+ }
100
+ throw new CommercetoolsError<InvalidJsonInputError>(
101
+ {
102
+ code: "InvalidJsonInput",
103
+ message: "Request body does not contain valid JSON.",
104
+ detailedErrorMessage: `actions -> authMode: Invalid enum value: '${authMode}'. Expected one of: 'Password','ExternalAuth'`,
105
+ },
106
+ 400,
107
+ );
108
+ }
109
+
110
+ setCompanyName(
111
+ _context: RepositoryContext,
112
+ resource: Writable<Customer>,
113
+ { companyName }: CustomerSetCompanyNameAction,
114
+ ) {
115
+ resource.companyName = companyName;
116
+ }
117
+
118
+ setCustomerNumber(
119
+ _context: RepositoryContext,
120
+ resource: Writable<Customer>,
121
+ { customerNumber }: CustomerSetCustomerNumberAction,
122
+ ) {
123
+ if (resource.customerNumber) {
124
+ throw new Error(
125
+ "A Customer number already exists and cannot be set again.",
126
+ );
127
+ }
128
+ resource.customerNumber = customerNumber;
129
+ }
130
+
131
+ setCustomField(
132
+ _context: RepositoryContext,
133
+ resource: Writable<Customer>,
134
+ { name, value }: CustomerSetCustomFieldAction,
135
+ ) {
136
+ if (!resource.custom) {
137
+ throw new Error("Resource has no custom field");
138
+ }
139
+ resource.custom.fields[name] = value;
140
+ }
141
+
142
+ setFirstName(
143
+ _context: RepositoryContext,
144
+ resource: Writable<Customer>,
145
+ { firstName }: CustomerSetFirstNameAction,
146
+ ) {
147
+ resource.firstName = firstName;
148
+ }
149
+
150
+ setLastName(
151
+ _context: RepositoryContext,
152
+ resource: Writable<Customer>,
153
+ { lastName }: CustomerSetLastNameAction,
154
+ ) {
155
+ resource.lastName = lastName;
156
+ }
157
+
158
+ setVatId(
159
+ _context: RepositoryContext,
160
+ resource: Writable<Customer>,
161
+ { vatId }: CustomerSetVatIdAction,
162
+ ) {
163
+ resource.vatId = vatId;
164
+ }
165
+ }
@@ -0,0 +1,79 @@
1
+ import type {
2
+ Customer,
3
+ CustomerDraft,
4
+ CustomerToken,
5
+ DuplicateFieldError,
6
+ ResourceNotFoundError,
7
+ } from "@commercetools/platform-sdk";
8
+ import { CommercetoolsError } from "~src/exceptions";
9
+ import { getBaseResourceProperties } from "~src/helpers";
10
+ import { createPasswordResetToken, hashPassword } from "~src/lib/password";
11
+ import { AbstractStorage } from "~src/storage/abstract";
12
+ import {
13
+ AbstractResourceRepository,
14
+ type RepositoryContext,
15
+ } from "../abstract";
16
+ import { CustomerUpdateHandler } from "./actions";
17
+
18
+ export class CustomerRepository extends AbstractResourceRepository<"customer"> {
19
+ constructor(storage: AbstractStorage) {
20
+ super("customer", storage);
21
+ this.actions = new CustomerUpdateHandler(storage);
22
+ }
23
+
24
+ create(context: RepositoryContext, draft: CustomerDraft): Customer {
25
+ // Check uniqueness
26
+ const results = this._storage.query(context.projectKey, this.getTypeId(), {
27
+ where: [`email="${draft.email.toLocaleLowerCase()}"`],
28
+ });
29
+ if (results.count > 0) {
30
+ throw new CommercetoolsError<any>({
31
+ code: "CustomerAlreadyExists",
32
+ statusCode: 400,
33
+ message:
34
+ "There is already an existing customer with the provided email.",
35
+ errors: [
36
+ {
37
+ code: "DuplicateField",
38
+ message: `Customer with email '${draft.email}' already exists.`,
39
+ duplicateValue: draft.email,
40
+ field: "email",
41
+ } as DuplicateFieldError,
42
+ ],
43
+ });
44
+ }
45
+
46
+ const resource: Customer = {
47
+ ...getBaseResourceProperties(),
48
+ authenticationMode: draft.authenticationMode || "Password",
49
+ email: draft.email.toLowerCase(),
50
+ password: draft.password ? hashPassword(draft.password) : undefined,
51
+ isEmailVerified: draft.isEmailVerified || false,
52
+ addresses: [],
53
+ customerNumber: draft.customerNumber,
54
+ };
55
+ return this.saveNew(context, resource);
56
+ }
57
+
58
+ passwordResetToken(context: RepositoryContext, email: string): CustomerToken {
59
+ const results = this._storage.query(context.projectKey, this.getTypeId(), {
60
+ where: [`email="${email.toLocaleLowerCase()}"`],
61
+ });
62
+ if (results.count === 0) {
63
+ throw new CommercetoolsError<ResourceNotFoundError>({
64
+ code: "ResourceNotFound",
65
+ message: `The Customer with ID '${email}' was not found.`,
66
+ });
67
+ }
68
+ const expiresAt = new Date(Date.now() + 30 * 60);
69
+ const customer = results.results[0] as Customer;
70
+ const { version: _, ...rest } = getBaseResourceProperties();
71
+ const token = createPasswordResetToken(customer);
72
+ return {
73
+ ...rest,
74
+ customerId: customer.id,
75
+ expiresAt: expiresAt.toISOString(),
76
+ value: token,
77
+ };
78
+ }
79
+ }