@reactionary/source 0.0.52 → 0.2.16

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 (293) hide show
  1. package/.env-template +19 -0
  2. package/.github/workflows/pull-request.yml +3 -1
  3. package/.github/workflows/release.yml +9 -0
  4. package/.vscode/extensions.json +0 -2
  5. package/LICENSE +21 -0
  6. package/README.md +175 -23
  7. package/core/package.json +6 -3
  8. package/core/src/cache/cache.interface.ts +1 -0
  9. package/core/src/cache/index.ts +4 -0
  10. package/core/src/cache/memory-cache.ts +30 -2
  11. package/core/src/cache/noop-cache.ts +15 -1
  12. package/core/src/cache/redis-cache.ts +20 -0
  13. package/core/src/client/client-builder.ts +71 -54
  14. package/core/src/client/client.ts +9 -47
  15. package/core/src/client/index.ts +2 -0
  16. package/core/src/decorators/index.ts +1 -0
  17. package/core/src/decorators/reactionary.decorator.ts +203 -34
  18. package/core/src/index.ts +6 -19
  19. package/core/src/initialization.ts +1 -18
  20. package/core/src/metrics/metrics.ts +67 -0
  21. package/core/src/providers/analytics.provider.ts +1 -6
  22. package/core/src/providers/base.provider.ts +5 -69
  23. package/core/src/providers/cart.provider.ts +15 -55
  24. package/core/src/providers/category.provider.ts +7 -11
  25. package/core/src/providers/checkout.provider.ts +17 -15
  26. package/core/src/providers/identity.provider.ts +6 -8
  27. package/core/src/providers/index.ts +2 -1
  28. package/core/src/providers/inventory.provider.ts +15 -5
  29. package/core/src/providers/order-search.provider.ts +29 -0
  30. package/core/src/providers/order.provider.ts +47 -15
  31. package/core/src/providers/price.provider.ts +30 -36
  32. package/core/src/providers/product-search.provider.ts +61 -0
  33. package/core/src/providers/product.provider.ts +71 -12
  34. package/core/src/providers/profile.provider.ts +74 -14
  35. package/core/src/providers/store.provider.ts +3 -5
  36. package/core/src/schemas/capabilities.schema.ts +10 -3
  37. package/core/src/schemas/errors/generic.error.ts +9 -0
  38. package/core/src/schemas/errors/index.ts +4 -0
  39. package/core/src/schemas/errors/invalid-input.error.ts +9 -0
  40. package/core/src/schemas/errors/invalid-output.error.ts +9 -0
  41. package/core/src/schemas/errors/not-found.error.ts +9 -0
  42. package/core/src/schemas/index.ts +7 -0
  43. package/core/src/schemas/models/analytics.model.ts +2 -1
  44. package/core/src/schemas/models/base.model.ts +6 -24
  45. package/core/src/schemas/models/cart.model.ts +5 -8
  46. package/core/src/schemas/models/category.model.ts +4 -9
  47. package/core/src/schemas/models/checkout.model.ts +6 -7
  48. package/core/src/schemas/models/cost.model.ts +4 -3
  49. package/core/src/schemas/models/currency.model.ts +2 -1
  50. package/core/src/schemas/models/identifiers.model.ts +106 -62
  51. package/core/src/schemas/models/identity.model.ts +10 -19
  52. package/core/src/schemas/models/index.ts +2 -1
  53. package/core/src/schemas/models/inventory.model.ts +8 -5
  54. package/core/src/schemas/models/order-search.model.ts +28 -0
  55. package/core/src/schemas/models/order.model.ts +20 -26
  56. package/core/src/schemas/models/payment.model.ts +14 -17
  57. package/core/src/schemas/models/price.model.ts +11 -11
  58. package/core/src/schemas/models/product-search.model.ts +42 -0
  59. package/core/src/schemas/models/product.model.ts +64 -22
  60. package/core/src/schemas/models/profile.model.ts +19 -22
  61. package/core/src/schemas/models/shipping-method.model.ts +24 -29
  62. package/core/src/schemas/models/store.model.ts +9 -5
  63. package/core/src/schemas/mutations/analytics.mutation.ts +8 -7
  64. package/core/src/schemas/mutations/base.mutation.ts +2 -1
  65. package/core/src/schemas/mutations/cart.mutation.ts +33 -33
  66. package/core/src/schemas/mutations/checkout.mutation.ts +23 -30
  67. package/core/src/schemas/mutations/identity.mutation.ts +4 -3
  68. package/core/src/schemas/mutations/profile.mutation.ts +38 -3
  69. package/core/src/schemas/queries/base.query.ts +2 -1
  70. package/core/src/schemas/queries/cart.query.ts +3 -3
  71. package/core/src/schemas/queries/category.query.ts +18 -18
  72. package/core/src/schemas/queries/checkout.query.ts +7 -9
  73. package/core/src/schemas/queries/identity.query.ts +2 -1
  74. package/core/src/schemas/queries/index.ts +2 -1
  75. package/core/src/schemas/queries/inventory.query.ts +5 -5
  76. package/core/src/schemas/queries/order-search.query.ts +10 -0
  77. package/core/src/schemas/queries/order.query.ts +3 -2
  78. package/core/src/schemas/queries/price.query.ts +10 -4
  79. package/core/src/schemas/queries/product-search.query.ts +16 -0
  80. package/core/src/schemas/queries/product.query.ts +13 -6
  81. package/core/src/schemas/queries/profile.query.ts +5 -2
  82. package/core/src/schemas/queries/store.query.ts +6 -5
  83. package/core/src/schemas/result.ts +107 -0
  84. package/core/src/schemas/session.schema.ts +4 -4
  85. package/core/src/test/reactionary.decorator.spec.ts +249 -0
  86. package/core/src/zod-utils.ts +19 -0
  87. package/core/tsconfig.json +1 -1
  88. package/core/tsconfig.spec.json +2 -26
  89. package/core/vitest.config.ts +14 -0
  90. package/documentation/1-purpose.md +114 -0
  91. package/documentation/2-getting-started.md +229 -0
  92. package/documentation/3-querying-and-changing-data.md +74 -0
  93. package/documentation/4-product-data.md +107 -0
  94. package/documentation/5-cart-and-checkout.md +211 -0
  95. package/documentation/6-product-search.md +143 -0
  96. package/documentation/7-marketing.md +3 -0
  97. package/eslint.config.mjs +1 -0
  98. package/examples/node/eslint.config.mjs +1 -4
  99. package/examples/node/package.json +10 -3
  100. package/examples/node/project.json +4 -1
  101. package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +22 -23
  102. package/examples/node/src/basic/basic-node-provider-query-extension.spec.ts +15 -11
  103. package/examples/node/src/basic/basic-node-setup.spec.ts +44 -28
  104. package/examples/node/src/basic/client-creation.spec.ts +53 -0
  105. package/examples/node/src/capabilities/cart.spec.ts +255 -0
  106. package/examples/node/src/capabilities/category.spec.ts +193 -0
  107. package/examples/node/src/capabilities/checkout.spec.ts +341 -0
  108. package/examples/node/src/capabilities/identity.spec.ts +93 -0
  109. package/examples/node/src/capabilities/inventory.spec.ts +66 -0
  110. package/examples/node/src/capabilities/order-search.spec.ts +265 -0
  111. package/examples/node/src/capabilities/order.spec.ts +91 -0
  112. package/examples/node/src/capabilities/price.spec.ts +51 -0
  113. package/examples/node/src/capabilities/product-search.spec.ts +293 -0
  114. package/examples/node/src/capabilities/product.spec.ts +122 -0
  115. package/examples/node/src/capabilities/profile.spec.ts +316 -0
  116. package/examples/node/src/capabilities/store.spec.ts +26 -0
  117. package/examples/node/src/utils.ts +147 -0
  118. package/examples/node/tsconfig.json +9 -12
  119. package/examples/node/tsconfig.lib.json +1 -2
  120. package/examples/node/tsconfig.spec.json +2 -14
  121. package/examples/node/vitest.config.ts +14 -0
  122. package/migrations.json +22 -5
  123. package/nx.json +8 -47
  124. package/package.json +24 -96
  125. package/providers/algolia/README.md +39 -2
  126. package/providers/algolia/package.json +2 -1
  127. package/providers/algolia/src/core/initialize.ts +7 -14
  128. package/providers/algolia/src/index.ts +2 -4
  129. package/providers/algolia/src/providers/index.ts +1 -0
  130. package/providers/algolia/src/providers/product-search.provider.ts +241 -0
  131. package/providers/algolia/src/schema/capabilities.schema.ts +2 -3
  132. package/providers/algolia/src/schema/index.ts +3 -0
  133. package/providers/algolia/src/schema/search.schema.ts +8 -8
  134. package/providers/algolia/tsconfig.json +1 -1
  135. package/providers/algolia/tsconfig.lib.json +1 -1
  136. package/providers/algolia/tsconfig.spec.json +2 -14
  137. package/providers/algolia/vitest.config.ts +14 -0
  138. package/providers/commercetools/README.md +30 -3
  139. package/providers/commercetools/package.json +2 -1
  140. package/providers/commercetools/src/core/client.ts +178 -99
  141. package/providers/commercetools/src/core/initialize.ts +130 -74
  142. package/providers/commercetools/src/core/token-cache.ts +45 -0
  143. package/providers/commercetools/src/index.ts +3 -2
  144. package/providers/commercetools/src/providers/cart.provider.ts +281 -341
  145. package/providers/commercetools/src/providers/category.provider.ts +223 -138
  146. package/providers/commercetools/src/providers/checkout.provider.ts +631 -449
  147. package/providers/commercetools/src/providers/identity.provider.ts +50 -29
  148. package/providers/commercetools/src/providers/index.ts +2 -2
  149. package/providers/commercetools/src/providers/inventory.provider.ts +76 -74
  150. package/providers/commercetools/src/providers/order-search.provider.ts +220 -0
  151. package/providers/commercetools/src/providers/order.provider.ts +96 -61
  152. package/providers/commercetools/src/providers/price.provider.ts +147 -117
  153. package/providers/commercetools/src/providers/product-search.provider.ts +528 -0
  154. package/providers/commercetools/src/providers/product.provider.ts +249 -74
  155. package/providers/commercetools/src/providers/profile.provider.ts +445 -28
  156. package/providers/commercetools/src/providers/store.provider.ts +54 -40
  157. package/providers/commercetools/src/schema/capabilities.schema.ts +3 -1
  158. package/providers/commercetools/src/schema/commercetools.schema.ts +17 -3
  159. package/providers/commercetools/src/schema/configuration.schema.ts +1 -0
  160. package/providers/commercetools/src/schema/session.schema.ts +7 -0
  161. package/providers/commercetools/src/test/caching.spec.ts +82 -0
  162. package/providers/commercetools/src/test/identity.spec.ts +109 -0
  163. package/providers/commercetools/src/test/test-utils.ts +21 -19
  164. package/providers/commercetools/tsconfig.json +1 -1
  165. package/providers/commercetools/tsconfig.lib.json +1 -1
  166. package/providers/commercetools/tsconfig.spec.json +2 -14
  167. package/providers/commercetools/vitest.config.ts +15 -0
  168. package/providers/fake/README.md +20 -4
  169. package/providers/fake/package.json +2 -1
  170. package/providers/fake/src/core/initialize.ts +47 -49
  171. package/providers/fake/src/providers/analytics.provider.ts +5 -7
  172. package/providers/fake/src/providers/cart.provider.ts +163 -92
  173. package/providers/fake/src/providers/category.provider.ts +78 -50
  174. package/providers/fake/src/providers/checkout.provider.ts +254 -0
  175. package/providers/fake/src/providers/identity.provider.ts +57 -65
  176. package/providers/fake/src/providers/index.ts +6 -2
  177. package/providers/fake/src/providers/inventory.provider.ts +40 -36
  178. package/providers/fake/src/providers/order-search.provider.ts +78 -0
  179. package/providers/fake/src/providers/order.provider.ts +106 -0
  180. package/providers/fake/src/providers/price.provider.ts +93 -41
  181. package/providers/fake/src/providers/product-search.provider.ts +206 -0
  182. package/providers/fake/src/providers/product.provider.ts +56 -41
  183. package/providers/fake/src/providers/profile.provider.ts +147 -0
  184. package/providers/fake/src/providers/store.provider.ts +30 -20
  185. package/providers/fake/src/schema/capabilities.schema.ts +5 -1
  186. package/providers/fake/src/test/cart.provider.spec.ts +59 -80
  187. package/providers/fake/src/test/category.provider.spec.ts +145 -87
  188. package/providers/fake/src/test/checkout.provider.spec.ts +222 -0
  189. package/providers/fake/src/test/order-search.provider.spec.ts +50 -0
  190. package/providers/fake/src/test/order.provider.spec.ts +44 -0
  191. package/providers/fake/src/test/price.provider.spec.ts +50 -45
  192. package/providers/fake/src/test/product.provider.spec.ts +15 -7
  193. package/providers/fake/src/test/profile.provider.spec.ts +167 -0
  194. package/providers/fake/tsconfig.json +1 -1
  195. package/providers/fake/tsconfig.lib.json +1 -1
  196. package/providers/fake/tsconfig.spec.json +2 -12
  197. package/providers/fake/vitest.config.ts +14 -0
  198. package/providers/medusa/README.md +30 -0
  199. package/providers/medusa/TESTING.md +98 -0
  200. package/providers/medusa/eslint.config.mjs +19 -0
  201. package/providers/medusa/package.json +22 -0
  202. package/providers/medusa/project.json +34 -0
  203. package/providers/medusa/src/core/client.ts +370 -0
  204. package/providers/medusa/src/core/initialize.ts +78 -0
  205. package/providers/medusa/src/index.ts +13 -0
  206. package/providers/medusa/src/providers/cart.provider.ts +575 -0
  207. package/providers/medusa/src/providers/category.provider.ts +247 -0
  208. package/providers/medusa/src/providers/checkout.provider.ts +636 -0
  209. package/providers/medusa/src/providers/identity.provider.ts +137 -0
  210. package/providers/medusa/src/providers/inventory.provider.ts +173 -0
  211. package/providers/medusa/src/providers/order-search.provider.ts +202 -0
  212. package/providers/medusa/src/providers/order.provider.ts +226 -0
  213. package/providers/medusa/src/providers/price.provider.ts +140 -0
  214. package/providers/medusa/src/providers/product-search.provider.ts +243 -0
  215. package/providers/medusa/src/providers/product.provider.ts +261 -0
  216. package/providers/medusa/src/providers/profile.provider.ts +392 -0
  217. package/providers/medusa/src/schema/capabilities.schema.ts +18 -0
  218. package/providers/medusa/src/schema/configuration.schema.ts +11 -0
  219. package/providers/medusa/src/schema/medusa.schema.ts +31 -0
  220. package/providers/medusa/src/test/cart.provider.spec.ts +240 -0
  221. package/providers/medusa/src/test/category.provider.spec.ts +231 -0
  222. package/providers/medusa/src/test/checkout.spec.ts +349 -0
  223. package/providers/medusa/src/test/identity.provider.spec.ts +122 -0
  224. package/providers/medusa/src/test/inventory.provider.spec.ts +88 -0
  225. package/providers/medusa/src/test/large-cart.provider.spec.ts +103 -0
  226. package/providers/medusa/src/test/price.provider.spec.ts +104 -0
  227. package/providers/medusa/src/test/product.provider.spec.ts +146 -0
  228. package/providers/medusa/src/test/search.provider.spec.ts +203 -0
  229. package/providers/medusa/src/test/test-utils.ts +13 -0
  230. package/providers/medusa/src/utils/medusa-helpers.ts +89 -0
  231. package/providers/medusa/tsconfig.json +21 -0
  232. package/providers/medusa/tsconfig.lib.json +9 -0
  233. package/providers/medusa/tsconfig.spec.json +4 -0
  234. package/providers/medusa/vitest.config.ts +15 -0
  235. package/providers/meilisearch/README.md +48 -0
  236. package/providers/meilisearch/eslint.config.mjs +22 -0
  237. package/providers/meilisearch/package.json +13 -0
  238. package/providers/meilisearch/project.json +34 -0
  239. package/providers/meilisearch/src/core/initialize.ts +21 -0
  240. package/providers/meilisearch/src/index.ts +6 -0
  241. package/providers/meilisearch/src/providers/index.ts +1 -0
  242. package/providers/meilisearch/src/providers/order-search.provider.ts +222 -0
  243. package/providers/meilisearch/src/providers/product-search.provider.ts +251 -0
  244. package/providers/meilisearch/src/schema/capabilities.schema.ts +10 -0
  245. package/providers/meilisearch/src/schema/configuration.schema.ts +11 -0
  246. package/providers/meilisearch/src/schema/index.ts +3 -0
  247. package/providers/meilisearch/src/schema/search.schema.ts +14 -0
  248. package/providers/meilisearch/tsconfig.json +24 -0
  249. package/providers/meilisearch/tsconfig.lib.json +10 -0
  250. package/providers/meilisearch/tsconfig.spec.json +4 -0
  251. package/providers/meilisearch/vitest.config.ts +14 -0
  252. package/providers/posthog/package.json +2 -1
  253. package/providers/posthog/tsconfig.json +1 -1
  254. package/tsconfig.base.json +5 -0
  255. package/vitest.config.ts +10 -0
  256. package/core/src/providers/search.provider.ts +0 -18
  257. package/core/src/schemas/models/search.model.ts +0 -36
  258. package/core/src/schemas/queries/search.query.ts +0 -9
  259. package/examples/next/.swcrc +0 -30
  260. package/examples/next/eslint.config.mjs +0 -21
  261. package/examples/next/index.d.ts +0 -6
  262. package/examples/next/next-env.d.ts +0 -5
  263. package/examples/next/next.config.js +0 -31
  264. package/examples/next/project.json +0 -9
  265. package/examples/next/public/.gitkeep +0 -0
  266. package/examples/next/public/favicon.ico +0 -0
  267. package/examples/next/src/app/global.css +0 -0
  268. package/examples/next/src/app/layout.tsx +0 -18
  269. package/examples/next/src/app/page.module.scss +0 -2
  270. package/examples/next/src/app/page.tsx +0 -47
  271. package/examples/next/src/instrumentation.ts +0 -9
  272. package/examples/next/tsconfig.json +0 -44
  273. package/examples/node/jest.config.ts +0 -10
  274. package/jest.config.ts +0 -6
  275. package/jest.preset.js +0 -3
  276. package/providers/algolia/jest.config.ts +0 -10
  277. package/providers/algolia/src/providers/product.provider.ts +0 -66
  278. package/providers/algolia/src/providers/search.provider.ts +0 -106
  279. package/providers/algolia/src/test/search.provider.spec.ts +0 -91
  280. package/providers/commercetools/jest.config.cjs +0 -10
  281. package/providers/commercetools/src/providers/search.provider.ts +0 -96
  282. package/providers/commercetools/src/test/cart.provider.spec.ts +0 -199
  283. package/providers/commercetools/src/test/category.provider.spec.ts +0 -168
  284. package/providers/commercetools/src/test/checkout.provider.spec.ts +0 -312
  285. package/providers/commercetools/src/test/identity.provider.spec.ts +0 -88
  286. package/providers/commercetools/src/test/inventory.provider.spec.ts +0 -41
  287. package/providers/commercetools/src/test/price.provider.spec.ts +0 -81
  288. package/providers/commercetools/src/test/product.provider.spec.ts +0 -80
  289. package/providers/commercetools/src/test/profile.provider.spec.ts +0 -49
  290. package/providers/commercetools/src/test/search.provider.spec.ts +0 -61
  291. package/providers/commercetools/src/test/store.provider.spec.ts +0 -37
  292. package/providers/fake/jest.config.cjs +0 -10
  293. package/providers/fake/src/providers/search.provider.ts +0 -132
@@ -3,68 +3,79 @@ import type {
3
3
  Cache,
4
4
  Order,
5
5
  OrderQueryById,
6
- Currency} from '@reactionary/core';
7
- import { OrderItemSchema, OrderProvider } from '@reactionary/core';
6
+ Currency,
7
+ OrderIdentifier,
8
+ CostBreakDown,
9
+ OrderStatus,
10
+ OrderItem,
11
+ ProductVariantIdentifier,
12
+ ItemCostBreakdown,
13
+ Result,
14
+ NotFoundError,
15
+ } from '@reactionary/core';
16
+ import { OrderProvider, OrderQueryByIdSchema, OrderSchema, Reactionary, success, error } from '@reactionary/core';
8
17
  import type z from 'zod';
9
18
  import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
10
- import { CommercetoolsClient } from '../core/client.js';
11
19
  import type { Order as CTOrder } from '@commercetools/platform-sdk';
12
- import { CommercetoolsOrderIdentifierSchema } from '../schema/commercetools.schema.js';
13
- export class CommercetoolsOrderProvider<
14
- T extends Order = Order
15
- > extends OrderProvider<T> {
20
+ import { type CommercetoolsOrderIdentifier } from '../schema/commercetools.schema.js';
21
+ import type { CommercetoolsAPI } from '../core/client.js';
22
+
23
+ export class CommercetoolsOrderProvider extends OrderProvider {
16
24
  protected config: CommercetoolsConfiguration;
25
+ protected commercetools: CommercetoolsAPI;
17
26
 
18
27
  constructor(
19
28
  config: CommercetoolsConfiguration,
20
- schema: z.ZodType<T>,
21
- cache: Cache
29
+ cache: Cache,
30
+ context: RequestContext,
31
+ commercetools: CommercetoolsAPI
22
32
  ) {
23
- super(schema, cache);
33
+ super(cache, context);
24
34
 
25
35
  this.config = config;
36
+ this.commercetools = commercetools;
26
37
  }
27
38
 
28
- protected async getClient(reqCtx: RequestContext) {
29
-
30
- const client = await new CommercetoolsClient(this.config).getClient(
31
- reqCtx
32
- );
33
- return client.withProjectKey({ projectKey: this.config.projectKey }).me().orders();
39
+ protected async getClient() {
40
+ const client = await this.commercetools.getClient();
41
+ return client
42
+ .withProjectKey({ projectKey: this.config.projectKey })
43
+ .me()
44
+ .orders();
34
45
  }
35
46
 
36
-
37
- public override async getById(payload: OrderQueryById, reqCtx: RequestContext): Promise<T> {
38
- const client = await new CommercetoolsClient(this.config).getClient(reqCtx);
47
+ @Reactionary({
48
+ inputSchema: OrderQueryByIdSchema,
49
+ outputSchema: OrderSchema,
50
+ })
51
+ public override async getById(payload: OrderQueryById): Promise<Result<Order, NotFoundError>> {
52
+ const client = await this.getClient();
39
53
 
40
54
  try {
41
55
  const remote = await client
42
- .withProjectKey({ projectKey: this.config.projectKey })
43
- .orders()
44
56
  .withId({ ID: payload.order.key })
45
57
  .get()
46
58
  .execute();
47
59
 
48
- return this.parseSingle(remote.body, reqCtx);
60
+ return success(this.parseSingle(remote.body));
49
61
  } catch (e) {
50
- return this.createEmptyOrder();
62
+ return error<NotFoundError>({
63
+ type: 'NotFound',
64
+ identifier: payload
65
+ })
51
66
  }
52
67
  }
53
68
 
69
+ protected parseSingle(_body: unknown): Order {
70
+ const remote = _body as CTOrder;
54
71
 
55
- protected override parseSingle(_body: unknown, reqCtx: RequestContext): T {
56
- const remote = _body as CTOrder;
57
- const result = this.newModel();
58
-
59
- result.identifier = CommercetoolsOrderIdentifierSchema.parse({
60
- key: remote.id,
61
- version: remote.version || 0,
62
- });
63
-
72
+ const identifier = {
73
+ key: remote.id,
74
+ version: remote.version || 0,
75
+ } satisfies CommercetoolsOrderIdentifier;
64
76
 
65
-
66
- result.name = remote.custom?.fields['name'] || '';
67
- result.description = remote.custom?.fields['description'] || '';
77
+ const name = remote.custom?.fields['name'] || '';
78
+ const description = remote.custom?.fields['description'] || '';
68
79
 
69
80
  const grandTotal = remote.totalPrice.centAmount || 0;
70
81
  const shippingTotal = remote.shippingInfo?.price.centAmount || 0;
@@ -75,7 +86,7 @@ export class CommercetoolsOrderProvider<
75
86
  const surchargeTotal = 0;
76
87
  const currency = remote.totalPrice.currencyCode as Currency;
77
88
 
78
- result.price = {
89
+ const price = {
79
90
  totalTax: {
80
91
  value: taxTotal / 100,
81
92
  currency,
@@ -100,33 +111,45 @@ export class CommercetoolsOrderProvider<
100
111
  value: grandTotal / 100,
101
112
  currency,
102
113
  },
103
- };
104
-
105
- if (remote.paymentState === 'Pending' && remote.orderState === 'Open') {
106
- result.orderStatus = 'AwaitingPayment';
107
- } else if (remote.paymentState === 'Paid' && remote.orderState === 'Confirmed') {
108
- result.orderStatus = 'ReleasedToFulfillment';
114
+ } satisfies CostBreakDown;
115
+
116
+ let orderStatus: OrderStatus = 'AwaitingPayment';
117
+ if (remote.paymentState === 'Pending' && remote.orderState === 'Open') {
118
+ orderStatus = 'AwaitingPayment';
119
+ } else if (
120
+ remote.paymentState === 'Paid' &&
121
+ remote.orderState === 'Confirmed'
122
+ ) {
123
+ orderStatus = 'ReleasedToFulfillment';
109
124
  }
110
125
  if (remote.shipmentState === 'Ready' && remote.orderState === 'Confirmed') {
111
- result.orderStatus = 'ReleasedToFulfillment';
126
+ orderStatus = 'ReleasedToFulfillment';
112
127
  }
113
- if ( (remote.shipmentState === 'Shipped' || remote.shipmentState === 'Delivered') && remote.orderState === 'Completed') {
114
- result.orderStatus = 'Shipped';
128
+ if (
129
+ (remote.shipmentState === 'Shipped' ||
130
+ remote.shipmentState === 'Delivered') &&
131
+ remote.orderState === 'Completed'
132
+ ) {
133
+ orderStatus = 'Shipped';
115
134
  }
116
135
 
136
+ const items = new Array<OrderItem>();
117
137
  for (const remoteItem of remote.lineItems) {
118
- const item = OrderItemSchema.parse({});
138
+ const identifier = {
139
+ key: remoteItem.id
140
+ } satisfies OrderIdentifier;
119
141
 
120
- item.identifier.key = remoteItem.id;
121
- item.sku.key = remoteItem.variant.sku || '';
122
- item.quantity = remoteItem.quantity;
142
+ const variant = {
143
+ sku: remoteItem.variant.sku || ''
144
+ } satisfies ProductVariantIdentifier;
145
+ const quantity = remoteItem.quantity;
123
146
 
124
147
  const unitPrice = remoteItem.price.value.centAmount;
125
148
  const totalPrice = remoteItem.totalPrice.centAmount || 0;
126
149
  const totalDiscount = remoteItem.price.discounted?.value.centAmount || 0;
127
150
  const unitDiscount = totalDiscount / remoteItem.quantity;
128
151
 
129
- item.price = {
152
+ const price = {
130
153
  unitPrice: {
131
154
  value: unitPrice / 100,
132
155
  currency,
@@ -143,21 +166,33 @@ export class CommercetoolsOrderProvider<
143
166
  value: totalDiscount / 100,
144
167
  currency,
145
168
  },
146
- };
169
+ } satisfies ItemCostBreakdown;
170
+
171
+ const item = {
172
+ identifier,
173
+ inventoryStatus: 'NotAllocated',
174
+ price,
175
+ quantity,
176
+ variant
177
+ } satisfies OrderItem;
147
178
 
148
- result.items.push(item);
179
+ items.push(item);
149
180
  }
150
181
 
151
- result.meta = {
152
- cache: {
153
- hit: false,
154
- key: this.generateCacheKeySingle(result.identifier, reqCtx),
182
+ const result = {
183
+ identifier,
184
+ name,
185
+ description,
186
+ price,
187
+ items,
188
+ inventoryStatus: 'NotAllocated',
189
+ paymentInstructions: [],
190
+ userId: {
191
+ userId: ''
155
192
  },
156
- placeholder: false,
157
- };
158
-
159
-
193
+ orderStatus
194
+ } satisfies Order;
160
195
 
161
- return this.assert(result);
196
+ return result;
162
197
  }
163
198
  }
@@ -1,150 +1,180 @@
1
- import { PriceProvider, TieredPriceSchema } from '@reactionary/core';
2
- import type { PriceQueryBySku, RequestContext , Price, Cache, Currency, TieredPrice } from '@reactionary/core';
3
- import type z from 'zod';
1
+ import {
2
+ CustomerPriceQuerySchema,
3
+ ListPriceQuerySchema,
4
+ PriceProvider,
5
+ PriceSchema,
6
+ Reactionary,
7
+ success,
8
+ } from '@reactionary/core';
9
+ import type {
10
+ RequestContext,
11
+ Price,
12
+ Cache,
13
+ Currency,
14
+ CustomerPriceQuery,
15
+ ListPriceQuery,
16
+ PriceIdentifier,
17
+ MonetaryAmount,
18
+ Result,
19
+ } from '@reactionary/core';
4
20
  import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
5
- import { CommercetoolsClient } from '../core/client.js';
6
- import type { Price as CTPrice, ProductVariant as CTProductVariant } from '@commercetools/platform-sdk';
7
- export class CommercetoolsPriceProvider<
8
- T extends Price = Price
9
- > extends PriceProvider<T> {
10
- protected config: CommercetoolsConfiguration;
11
-
21
+ import type {
22
+ Price as CTPrice,
23
+ ProductVariant as CTProductVariant,
24
+ } from '@commercetools/platform-sdk';
25
+ import type { CommercetoolsAPI } from '../core/client.js';
12
26
 
27
+ export class CommercetoolsPriceProvider extends PriceProvider {
28
+ protected config: CommercetoolsConfiguration;
29
+ protected commercetools: CommercetoolsAPI;
13
30
 
14
- constructor(config: CommercetoolsConfiguration, schema: z.ZodType<T>, cache: Cache) {
15
- super(schema, cache);
31
+ constructor(
32
+ config: CommercetoolsConfiguration,
33
+ cache: Cache,
34
+ context: RequestContext,
35
+ commercetools: CommercetoolsAPI
36
+ ) {
37
+ super(cache, context);
16
38
 
17
39
  this.config = config;
40
+ this.commercetools = commercetools;
18
41
  }
19
42
 
20
-
21
- protected async getClient(reqCtx: RequestContext) {
22
- const client = await new CommercetoolsClient(this.config).getClient(
23
- reqCtx
43
+ @Reactionary({
44
+ inputSchema: CustomerPriceQuerySchema,
45
+ outputSchema: PriceSchema,
46
+ })
47
+ public override async getCustomerPrice(
48
+ payload: CustomerPriceQuery
49
+ ): Promise<Result<Price>> {
50
+ const client = await this.getClient();
51
+ const priceChannelId = 'ee6e75e9-c9ab-4e2f-85f1-d8c734d0cb86';
52
+
53
+ const response = await client
54
+ .productProjections()
55
+ .get({
56
+ queryArgs: {
57
+ staged: false,
58
+ priceCountry: this.context.taxJurisdiction.countryCode,
59
+ priceCustomerGroup: undefined,
60
+ priceChannel: priceChannelId,
61
+ priceCurrency: this.context.languageContext.currencyCode,
62
+ where: 'variants(sku in (:skus)) OR (masterVariant(sku in (:skus))) ',
63
+ 'var.skus': [payload.variant.sku],
64
+ limit: 1,
65
+ },
66
+ })
67
+ .execute();
68
+
69
+ const result = response.body.results[0];
70
+ const sku = [result.masterVariant, ...result.variants].find(
71
+ (x) => x.sku === payload.variant.sku
24
72
  );
25
- return client.withProjectKey({ projectKey: this.config.projectKey }).productProjections()
26
- }
27
-
28
-
29
-
30
- public override async getBySKUs(payload: PriceQueryBySku[], reqCtx: RequestContext): Promise<T[]> {
31
-
32
- const client = await this.getClient(reqCtx);
33
73
 
34
- // AND (validFrom is not defined OR validFrom <= now()) AND (validUntil is not defined OR validUntil >= now())
35
-
36
- const channels = await this.getChannels(reqCtx);
37
-
38
- const response = await client.get({
39
- queryArgs: {
40
- staged: false,
41
- priceCountry: reqCtx.taxJurisdiction.countryCode,
42
- priceCustomerGroup: undefined,
43
- priceChannel: channels.offerChannelGUID,
44
- priceCurrency: reqCtx.languageContext.currencyCode,
45
- // storeProjection: reqCtx.storeIdentifier?.key || undefined,
46
- where: 'variants(sku in (:skus)) OR (masterVariant(sku in (:skus))) ',
47
- 'var.skus': payload.map(p => p.sku.key),
48
- limit: payload.length,
49
- },
50
- }).execute();
51
-
52
- const result = [];
53
- const allReturnedVariants = [...response.body.results.map(x => x.variants).flat(), ...response.body.results.map(x => x.masterVariant).flat()];
54
- // Now we need to match the skus requested with the prices returned.
55
- for(const p of payload) {
56
- const foundSku = allReturnedVariants.find(v => v.sku === p.sku.key);
57
-
58
- if (!foundSku) {
59
- result.push(this.createEmptyPriceResult(p.sku.key, reqCtx.languageContext.currencyCode ));
60
- } else {
61
- result.push(this.parseSingle(foundSku, reqCtx));
62
- }
63
- }
64
-
65
- return result;
74
+ return success(this.parseSingle(sku, { includeDiscounts: true }));
66
75
  }
67
76
 
77
+ @Reactionary({
78
+ inputSchema: ListPriceQuerySchema,
79
+ outputSchema: PriceSchema,
80
+ })
81
+ public override async getListPrice(payload: ListPriceQuery): Promise<Result<Price>> {
82
+ const client = await this.getClient();
83
+ const priceChannelId = 'ee6e75e9-c9ab-4e2f-85f1-d8c734d0cb86';
84
+
85
+ const response = await client
86
+ .productProjections()
87
+ .get({
88
+ queryArgs: {
89
+ staged: false,
90
+ priceCountry: this.context.taxJurisdiction.countryCode,
91
+ priceCustomerGroup: undefined,
92
+ priceChannel: priceChannelId,
93
+ priceCurrency: this.context.languageContext.currencyCode,
94
+ where: 'variants(sku in (:skus)) OR (masterVariant(sku in (:skus))) ',
95
+ 'var.skus': [payload.variant.sku],
96
+ limit: 1,
97
+ },
98
+ })
99
+ .execute();
100
+
101
+ const result = response.body.results[0];
102
+ const sku = [result.masterVariant, ...result.variants].find(
103
+ (x) => x.sku === payload.variant.sku
104
+ );
68
105
 
69
- public override async getBySKU(
70
- payload: PriceQueryBySku,
71
- reqCtx: RequestContext
72
- ): Promise<T> {
73
- return this.getBySKUs([payload], reqCtx).then(r => r[0]);
106
+ return success(this.parseSingle(sku));
74
107
  }
75
108
 
109
+ protected async getClient() {
110
+ const client = await this.commercetools.getClient();
111
+ return client.withProjectKey({ projectKey: this.config.projectKey });
112
+ }
76
113
 
77
-
78
- protected override parseSingle(_body: unknown, reqCtx: RequestContext): T {
114
+ protected parseSingle(
115
+ _body: unknown,
116
+ options = { includeDiscounts: false }
117
+ ): Price {
79
118
  const body = _body as CTProductVariant;
80
119
  const price = body.price as CTPrice | undefined;
81
120
 
82
121
  if (!price) {
83
- return this.createEmptyPriceResult(body.sku!, reqCtx.languageContext.currencyCode);
122
+ return this.createEmptyPriceResult(body.sku!);
84
123
  }
85
124
 
86
- const base = this.newModel();
87
- base.unitPrice = {
88
- value: (price.value.centAmount / 100),
125
+ let unitPrice = {
126
+ value: price.value.centAmount / 100,
89
127
  currency: price.value.currencyCode as Currency,
90
- };
128
+ } satisfies MonetaryAmount;
91
129
 
92
- if (price.tiers && price.tiers.length > 0) {
93
- const p = price.tiers.map(x => {
94
- const tp: TieredPrice = TieredPriceSchema.parse({});
95
- tp.minimumQuantity = x.minimumQuantity;
96
- tp.price = {
97
- value: (x.value.centAmount / 100),
98
- currency: x.value.currencyCode as Currency,
99
- };
100
- return tp;
101
- });
102
- base.tieredPrices = p;
103
- }
130
+ if (options.includeDiscounts) {
131
+ const discountedPrice = price.discounted?.value || price.value;
104
132
 
105
- base.identifier = {
106
- sku: {
107
- key: body.sku!
108
- }
109
- };
133
+ unitPrice = {
134
+ value: discountedPrice.centAmount / 100,
135
+ currency: price.value.currencyCode as Currency,
136
+ } satisfies MonetaryAmount;
137
+ }
110
138
 
111
- base.meta = {
112
- cache: { hit: false, key: this.generateCacheKeySingle(base.identifier, reqCtx) },
113
- placeholder: false
114
- };
139
+ const identifier = {
140
+ variant: {
141
+ sku: body.sku!,
142
+ },
143
+ } satisfies PriceIdentifier;
115
144
 
116
- return this.assert(base);
145
+ const result = {
146
+ identifier,
147
+ tieredPrices: [],
148
+ unitPrice,
149
+ } satisfies Price;
117
150
 
151
+ return result;
118
152
  }
119
153
 
120
- protected async getChannels(reqCtx: RequestContext) {
121
-
122
- if (!(reqCtx.session['commercetools'] && reqCtx.session['commercetools'].offerChannelGUID && reqCtx.session['commercetools'].listChannelGUID)) {
123
-
124
- /**
125
- * Bah - have to be an admin to call these....
126
- * So either we cache them in the session, or we make the user provide them in the config.
127
- */
128
-
129
- /*
130
- const configClient = await new CommercetoolsClient(this.config).getClient(reqCtx);
131
- const offerPriceChannelPromise = configClient.withProjectKey({ projectKey: this.config.projectKey }).channels().withKey({ key: 'Offer Price'}).get().execute();
132
- const listPriceChannelPromise = configClient.withProjectKey({ projectKey: this.config.projectKey }).channels().withKey({ key: 'List Price'}).get().execute();
133
-
134
- const [offerChannel, listChannel] = await Promise.all([offerPriceChannelPromise, listPriceChannelPromise]);
135
- */
136
-
137
- reqCtx.session['commercetools'] = {
138
- ...reqCtx.session['commercetools'],
139
- offerChannelGUID: undefined,
140
- listChannelGUID: undefined
141
- };
142
- }
143
-
154
+ protected async getChannels() {
155
+ const adminClient = await this.commercetools.getAdminClient();
156
+
157
+ const offerPriceChannelPromise = adminClient
158
+ .withProjectKey({ projectKey: this.config.projectKey })
159
+ .channels()
160
+ .withKey({ key: 'Offer Price' })
161
+ .get()
162
+ .execute();
163
+ const listPriceChannelPromise = adminClient
164
+ .withProjectKey({ projectKey: this.config.projectKey })
165
+ .channels()
166
+ .withKey({ key: 'List Price' })
167
+ .get()
168
+ .execute();
169
+
170
+ const [offerChannel, listChannel] = await Promise.all([
171
+ offerPriceChannelPromise,
172
+ listPriceChannelPromise,
173
+ ]);
144
174
 
145
175
  return {
146
- offerChannelGUID: reqCtx.session['commercetools'].offerChannelGUID,
147
- listChannelGUID: reqCtx.session['commercetools'].listChannelGUID
148
- }
176
+ offer: offerChannel.body.id,
177
+ list: listChannel.body.id,
178
+ };
149
179
  }
150
180
  }