@unchainedshop/utils 3.0.0-alpha7 → 3.0.0-rc2

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 (66) hide show
  1. package/lib/calculation.d.ts +0 -5
  2. package/lib/calculation.d.ts.map +1 -1
  3. package/lib/calculation.js +0 -20
  4. package/lib/calculation.js.map +1 -1
  5. package/lib/director/BaseDiscountAdapter.d.ts +3 -4
  6. package/lib/director/BaseDiscountAdapter.d.ts.map +1 -1
  7. package/lib/director/BaseDiscountAdapter.js.map +1 -1
  8. package/lib/director/BaseDiscountDirector.d.ts +3 -4
  9. package/lib/director/BaseDiscountDirector.d.ts.map +1 -1
  10. package/lib/director/BaseDiscountDirector.js.map +1 -1
  11. package/lib/director/BasePricingAdapter.d.ts +1 -5
  12. package/lib/director/BasePricingAdapter.d.ts.map +1 -1
  13. package/lib/director/BasePricingAdapter.js.map +1 -1
  14. package/lib/director/BasePricingDirector.d.ts +4 -5
  15. package/lib/director/BasePricingDirector.d.ts.map +1 -1
  16. package/lib/director/BasePricingDirector.js +1 -1
  17. package/lib/director/BasePricingDirector.js.map +1 -1
  18. package/lib/intersect-set.d.ts +3 -0
  19. package/lib/intersect-set.d.ts.map +1 -0
  20. package/lib/intersect-set.js +2 -0
  21. package/lib/intersect-set.js.map +1 -0
  22. package/lib/sha1.d.ts +2 -0
  23. package/lib/sha1.d.ts.map +1 -0
  24. package/lib/sha1.js +6 -0
  25. package/lib/sha1.js.map +1 -0
  26. package/lib/sha256.d.ts +2 -0
  27. package/lib/sha256.d.ts.map +1 -0
  28. package/lib/sha256.js +6 -0
  29. package/lib/sha256.js.map +1 -0
  30. package/lib/utils-index.d.ts +18 -6
  31. package/lib/utils-index.d.ts.map +1 -1
  32. package/lib/utils-index.js +3 -12
  33. package/lib/utils-index.js.map +1 -1
  34. package/lib/utils-index_BACKUP_3852.d.ts +35 -0
  35. package/lib/utils-index_BACKUP_3852.d.ts.map +1 -0
  36. package/lib/utils-index_BACKUP_3852.js +25 -0
  37. package/lib/utils-index_BACKUP_3852.js.map +1 -0
  38. package/lib/utils-index_BASE_3852.d.ts +27 -0
  39. package/lib/utils-index_BASE_3852.d.ts.map +1 -0
  40. package/lib/utils-index_BASE_3852.js +28 -0
  41. package/lib/utils-index_BASE_3852.js.map +1 -0
  42. package/lib/utils-index_LOCAL_3852.d.ts +35 -0
  43. package/lib/utils-index_LOCAL_3852.d.ts.map +1 -0
  44. package/lib/utils-index_LOCAL_3852.js +25 -0
  45. package/lib/utils-index_LOCAL_3852.js.map +1 -0
  46. package/lib/utils-index_REMOTE_3852.d.ts +31 -0
  47. package/lib/utils-index_REMOTE_3852.d.ts.map +1 -0
  48. package/lib/utils-index_REMOTE_3852.js +28 -0
  49. package/lib/utils-index_REMOTE_3852.js.map +1 -0
  50. package/package.json +8 -11
  51. package/src/calculation.test.ts +0 -43
  52. package/src/calculation.ts +0 -26
  53. package/src/intersect-set.ts +2 -0
  54. package/src/sha1.ts +5 -0
  55. package/src/sha256.ts +5 -0
  56. package/src/utils-index.test.ts +1 -1
  57. package/src/utils-index.ts +19 -16
  58. package/tsconfig.json +4 -4
  59. package/src/director/BaseDiscountAdapter.ts +0 -89
  60. package/src/director/BaseDiscountDirector.ts +0 -77
  61. package/src/director/BasePricingAdapter.ts +0 -89
  62. package/src/director/BasePricingDirector.ts +0 -133
  63. package/src/director/BasePricingSheet.ts +0 -121
  64. package/src/director/base-discount-adapter.test.ts +0 -49
  65. package/src/director/base-price-sheet.test.ts +0 -100
  66. package/src/random-value-hex.ts +0 -8
@@ -0,0 +1,31 @@
1
+ export * as calculation from './calculation.js';
2
+ export * from './locale-helpers.js';
3
+ export { default as objectInvert } from './object-invert.js';
4
+ export { default as findUnusedSlug } from './find-unused-slug.js';
5
+ export { default as slugify } from './slugify.js';
6
+ export { default as pipePromises } from './pipe-promises.js';
7
+ export { default as generateRandomHash } from './generate-random-hash.js';
8
+ export { default as randomValueHex } from './random-value-hex.js';
9
+ export { default as buildObfuscatedFieldsFilter } from './build-obfuscated-fields-filter.js';
10
+ export declare enum SortDirection {
11
+ ASC = "ASC",
12
+ DESC = "DESC"
13
+ }
14
+ export type SortOption = {
15
+ key: string;
16
+ value: SortDirection;
17
+ };
18
+ export type NodeOrTree<T> = string | Tree<T>;
19
+ export type Tree<T> = Array<NodeOrTree<T>>;
20
+ export * from './director/BaseAdapter.js';
21
+ export * from './director/BaseDirector.js';
22
+ export * from './director/BasePricingAdapter.js';
23
+ export * from './director/BasePricingDirector.js';
24
+ export * from './director/BasePricingSheet.js';
25
+ export * from './director/BaseDiscountAdapter.js';
26
+ export * from './director/BaseDiscountDirector.js';
27
+ export interface DateFilterInput {
28
+ start?: string;
29
+ end?: string;
30
+ }
31
+ //# sourceMappingURL=utils-index_REMOTE_3852.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils-index_REMOTE_3852.d.ts","sourceRoot":"","sources":["../src/utils-index_REMOTE_3852.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAEhD,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAM7F,oBAAY,aAAa;IACvB,GAAG,QAAQ;IACX,IAAI,SAAS;CACd;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,aAAa,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7C,MAAM,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAK3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAE3C,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAE/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AAEnD,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd"}
@@ -0,0 +1,28 @@
1
+ export * as calculation from './calculation.js';
2
+ export * from './locale-helpers.js';
3
+ export { default as objectInvert } from './object-invert.js';
4
+ export { default as findUnusedSlug } from './find-unused-slug.js';
5
+ export { default as slugify } from './slugify.js';
6
+ export { default as pipePromises } from './pipe-promises.js';
7
+ export { default as generateRandomHash } from './generate-random-hash.js';
8
+ export { default as randomValueHex } from './random-value-hex.js';
9
+ export { default as buildObfuscatedFieldsFilter } from './build-obfuscated-fields-filter.js';
10
+ /*
11
+ * Schemas
12
+ */
13
+ export var SortDirection;
14
+ (function (SortDirection) {
15
+ SortDirection["ASC"] = "ASC";
16
+ SortDirection["DESC"] = "DESC";
17
+ })(SortDirection || (SortDirection = {}));
18
+ /*
19
+ * Director
20
+ */
21
+ export * from './director/BaseAdapter.js';
22
+ export * from './director/BaseDirector.js';
23
+ export * from './director/BasePricingAdapter.js';
24
+ export * from './director/BasePricingDirector.js';
25
+ export * from './director/BasePricingSheet.js';
26
+ export * from './director/BaseDiscountAdapter.js';
27
+ export * from './director/BaseDiscountDirector.js';
28
+ //# sourceMappingURL=utils-index_REMOTE_3852.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils-index_REMOTE_3852.js","sourceRoot":"","sources":["../src/utils-index_REMOTE_3852.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAEhD,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAE7F;;GAEG;AAEH,MAAM,CAAN,IAAY,aAGX;AAHD,WAAY,aAAa;IACvB,4BAAW,CAAA;IACX,8BAAa,CAAA;AACf,CAAC,EAHW,aAAa,KAAb,aAAa,QAGxB;AASD;;GAEG;AAEH,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAE3C,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAE/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC"}
package/package.json CHANGED
@@ -1,16 +1,13 @@
1
1
  {
2
2
  "name": "@unchainedshop/utils",
3
- "version": "3.0.0-alpha7",
3
+ "version": "3.0.0-rc2",
4
4
  "main": "lib/utils-index.js",
5
- "exports": {
6
- ".": "./lib/utils-index.js",
7
- "./*": "./lib/*"
8
- },
9
5
  "types": "lib/utils-index.d.ts",
10
6
  "type": "module",
11
7
  "scripts": {
12
- "clean": "rm -rf lib",
13
- "prepublishOnly": "npm run clean && tsc",
8
+ "clean": "tsc -b --clean",
9
+ "build": "tsc -b",
10
+ "prepublishOnly": "npm run clean && npm run build",
14
11
  "watch": "tsc -w",
15
12
  "test": "NODE_OPTIONS=--experimental-vm-modules jest --detectOpenHandles --forceExit",
16
13
  "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch --detectOpenHandles --forceExit"
@@ -30,13 +27,13 @@
30
27
  },
31
28
  "homepage": "https://github.com/unchainedshop/unchained#readme",
32
29
  "dependencies": {
33
- "@unchainedshop/logger": "^3.0.0-alpha4",
30
+ "@unchainedshop/logger": "^3.0.0-rc2",
34
31
  "hashids": "^2.3.0",
35
- "resolve-accept-language": "^3.1.8"
32
+ "resolve-accept-language": "^3.1.10"
36
33
  },
37
34
  "devDependencies": {
38
- "@types/node": "^22.8.1",
35
+ "@types/node": "^22.10.2",
39
36
  "jest": "^29.7.0",
40
- "typescript": "^5.6.3"
37
+ "typescript": "^5.7.2"
41
38
  }
42
39
  }
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  applyRate,
3
- resolveRatioAndTaxDivisorForPricingSheet,
4
3
  roundToNext,
5
4
  resolveAmountAndTax,
6
5
  applyDiscountToMultipleShares,
@@ -29,48 +28,6 @@ describe('roundToNext', () => {
29
28
  });
30
29
  });
31
30
 
32
- describe('resolveRatioAndTaxDivisorForPricingSheet', () => {
33
- it('total is 0 and pricing is provided', () => {
34
- const pricing: any = {
35
- taxSum: () => 10,
36
- gross: () => 20,
37
- net: () => 10,
38
- };
39
- const result = resolveRatioAndTaxDivisorForPricingSheet(pricing, 0);
40
- expect(result).toEqual({ ratio: 1, taxDivisor: 1 });
41
- });
42
-
43
- it('gross - tax is 0', () => {
44
- const pricing: any = {
45
- taxSum: () => 10,
46
- gross: () => 10,
47
- net: () => 0,
48
- };
49
- const result = resolveRatioAndTaxDivisorForPricingSheet(pricing, 20);
50
- expect(result).toEqual({ ratio: 0, taxDivisor: 0 });
51
- });
52
-
53
- it('gross - tax is not 0', () => {
54
- const pricing: any = {
55
- taxSum: () => 10,
56
- gross: () => 20,
57
- net: () => 10,
58
- };
59
- const result = resolveRatioAndTaxDivisorForPricingSheet(pricing, 20);
60
- expect(result).toEqual({ ratio: 1, taxDivisor: 2 });
61
- });
62
-
63
- it('taxSum is 0', () => {
64
- const pricing: any = {
65
- taxSum: () => 0,
66
- gross: () => 20,
67
- net: () => 20,
68
- };
69
- const result = resolveRatioAndTaxDivisorForPricingSheet(pricing, 20);
70
- expect(result).toEqual({ ratio: 1, taxDivisor: 1 });
71
- });
72
- });
73
-
74
31
  describe('resolveAmountAndTax', () => {
75
32
  it('ratio is 0 and taxDivisor is 0', () => {
76
33
  const result = resolveAmountAndTax({ ratio: 0, taxDivisor: 0 }, 100);
@@ -1,32 +1,6 @@
1
- import { IBasePricingSheet, PricingCalculation } from './director/BasePricingSheet.js';
2
-
3
1
  export const roundToNext = (value: number, precision: number) =>
4
2
  Math.ceil(value / precision) * precision;
5
3
 
6
- export const resolveRatioAndTaxDivisorForPricingSheet = (
7
- pricing: IBasePricingSheet<PricingCalculation>,
8
- total: number,
9
- ) => {
10
- if (total === 0 || !pricing) {
11
- return {
12
- ratio: 1,
13
- taxDivisor: 1,
14
- };
15
- }
16
- const tax = pricing.taxSum();
17
- const gross = pricing.gross();
18
- if (gross - tax === 0) {
19
- return {
20
- ratio: 0,
21
- taxDivisor: 0,
22
- };
23
- }
24
- return {
25
- ratio: gross / total,
26
- taxDivisor: gross / (gross - tax),
27
- };
28
- };
29
-
30
4
  export const calculateAmountToSplit = (
31
5
  configuration: { rate?: number; fixedRate?: number },
32
6
  amount: number,
@@ -0,0 +1,2 @@
1
+ export default (productIdSet: Set<string>, filterProductIdSet: Set<string>) =>
2
+ new Set([...productIdSet].filter((currentProductId) => filterProductIdSet.has(currentProductId)));
package/src/sha1.ts ADDED
@@ -0,0 +1,5 @@
1
+ export default async function sha1(message) {
2
+ const bytes = new TextEncoder().encode(message);
3
+ const hashBuffer = await crypto.subtle.digest('SHA-1', bytes);
4
+ return Buffer.from(hashBuffer);
5
+ }
package/src/sha256.ts ADDED
@@ -0,0 +1,5 @@
1
+ export default async function sha256(message) {
2
+ const bytes = new TextEncoder().encode(message);
3
+ const hashBuffer = await crypto.subtle.digest('SHA-256', bytes);
4
+ return Buffer.from(hashBuffer).toString('hex');
5
+ }
@@ -1,4 +1,4 @@
1
- import { resolveBestCountry, resolveBestSupported, slugify, systemLocale } from '@unchainedshop/utils';
1
+ import { resolveBestCountry, resolveBestSupported, slugify, systemLocale } from './utils-index.js';
2
2
  import generateHashId from './generate-random-hash.js';
3
3
 
4
4
  describe('Utils', () => {
@@ -6,12 +6,10 @@ export { default as findUnusedSlug } from './find-unused-slug.js';
6
6
  export { default as slugify } from './slugify.js';
7
7
  export { default as pipePromises } from './pipe-promises.js';
8
8
  export { default as generateRandomHash } from './generate-random-hash.js';
9
- export { default as randomValueHex } from './random-value-hex.js';
10
9
  export { default as buildObfuscatedFieldsFilter } from './build-obfuscated-fields-filter.js';
11
-
12
- /*
13
- * Schemas
14
- */
10
+ export { default as sha256 } from './sha256.js';
11
+ export { default as sha1 } from './sha1.js';
12
+ export { default as intersectSet } from './intersect-set.js';
15
13
 
16
14
  export enum SortDirection {
17
15
  ASC = 'ASC',
@@ -23,18 +21,23 @@ export type SortOption = {
23
21
  value: SortDirection;
24
22
  };
25
23
 
26
- export type NodeOrTree<T> = string | Tree<T>; // eslint-disable-line
24
+ export type Price = { _id?: string; amount: number; currency: string };
25
+
26
+ export interface PricingCalculation {
27
+ category: string;
28
+ amount: number;
29
+ baseCategory?: string;
30
+ meta?: any;
31
+ }
32
+
33
+ export type NodeOrTree<T> = string | Tree<T>;
34
+
27
35
  export type Tree<T> = Array<NodeOrTree<T>>;
28
- /*
29
- * Director
30
- */
36
+
37
+ export interface DateFilterInput {
38
+ start?: string;
39
+ end?: string;
40
+ }
31
41
 
32
42
  export * from './director/BaseAdapter.js';
33
43
  export * from './director/BaseDirector.js';
34
-
35
- export * from './director/BasePricingAdapter.js';
36
- export * from './director/BasePricingDirector.js';
37
- export * from './director/BasePricingSheet.js';
38
-
39
- export * from './director/BaseDiscountAdapter.js';
40
- export * from './director/BaseDiscountDirector.js';
package/tsconfig.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "extends": "../shared/base.tsconfig.json",
3
3
  "compilerOptions": {
4
- "rootDir": "src",
5
- "outDir": "lib"
4
+ "declarationDir": "./lib",
5
+ "rootDir": "./src",
6
+ "outDir": "./lib"
6
7
  },
7
- "exclude": ["**/*.test.ts", "**/*.test.js", "tests"],
8
- "include": ["./src"]
8
+ "exclude": ["**/*.test.ts", "**/*.test.js", "tests", "lib"]
9
9
  }
@@ -1,89 +0,0 @@
1
- import { log, LogLevel } from '@unchainedshop/logger';
2
- import { UnchainedCore } from '@unchainedshop/core';
3
- import { IBaseAdapter } from './BaseAdapter.js';
4
- import { IPricingSheet, PricingCalculation } from './BasePricingSheet.js';
5
-
6
- export interface DiscountContext {
7
- code?: string;
8
- orderDiscount?: { _id?: string; orderId: string };
9
- order?: { _id?: string; userId: string };
10
- }
11
-
12
- export type IDiscountAdapter<DiscountConfiguration> = IBaseAdapter & {
13
- orderIndex: number;
14
-
15
- isManualAdditionAllowed: (code: string) => Promise<boolean>;
16
- isManualRemovalAllowed: () => Promise<boolean>;
17
-
18
- actions: (params: {
19
- context: DiscountContext & UnchainedCore;
20
- }) => Promise<DiscountAdapterActions<DiscountConfiguration>>;
21
- };
22
-
23
- export interface DiscountAdapterActions<DiscountConfiguration> {
24
- isValidForSystemTriggering: () => Promise<boolean>;
25
- isValidForCodeTriggering: (params: { code: string }) => Promise<boolean>;
26
-
27
- discountForPricingAdapterKey: (params: {
28
- pricingAdapterKey: string;
29
- calculationSheet: IPricingSheet<PricingCalculation>;
30
- }) => DiscountConfiguration;
31
-
32
- reserve: (params: { code: string }) => Promise<any>;
33
- release: () => Promise<void>;
34
- }
35
-
36
- export const BaseDiscountAdapter: Omit<IDiscountAdapter<unknown>, 'key' | 'label' | 'version'> = {
37
- orderIndex: 0,
38
-
39
- isManualAdditionAllowed: async () => {
40
- return false;
41
- },
42
-
43
- // return true if a discount is allowed to get removed manually by a user
44
- isManualRemovalAllowed: async () => {
45
- return false;
46
- },
47
-
48
- actions: async () => ({
49
- // return true if a discount is valid to be part of the order
50
- // without input of a user. that could be a time based global discount
51
- // like a 10% discount day
52
- // if you return false, this discount will
53
- // get removed from the order before any price calculation
54
- // takes place.
55
- // eslint-disable-next-line
56
- isValidForSystemTriggering: async () => {
57
- return false;
58
- },
59
-
60
- // return an arbitrary JSON serializable object with reservation data
61
- // this method is called when a discount is added through a manual code and let's
62
- // you manually deduct expendable discounts (coupon balances for ex.) before checkout
63
- reserve: async () => {
64
- return {};
65
- },
66
-
67
- // return void, allows you to free up any reservations in backend systems
68
- release: async () => {
69
- return null;
70
- },
71
-
72
- // return true if a discount is valid to be part of the order.
73
- // if you return false, this discount will
74
- // get removed from the order before any price calculation
75
- // takes place.
76
- isValidForCodeTriggering: async () => {
77
- return false;
78
- },
79
-
80
- // returns the appropriate discount context for a calculation adapter
81
- discountForPricingAdapterKey() {
82
- return null;
83
- },
84
- }),
85
-
86
- log(message: string, { level = LogLevel.Debug, ...options } = {}) {
87
- return log(message, { level, ...options });
88
- },
89
- };
@@ -1,77 +0,0 @@
1
- import { log } from '@unchainedshop/logger';
2
- import { BaseDirector, IBaseDirector } from './BaseDirector.js';
3
- import { DiscountContext, IDiscountAdapter } from './BaseDiscountAdapter.js';
4
- import { UnchainedCore } from '@unchainedshop/core';
5
-
6
- export type IDiscountDirector<DiscountConfiguration> = IBaseDirector<
7
- IDiscountAdapter<DiscountConfiguration>
8
- > & {
9
- actions: (
10
- discountContext: DiscountContext,
11
- unchainedAPI: UnchainedCore,
12
- ) => Promise<{
13
- resolveDiscountKeyFromStaticCode: (params: { code: string }) => Promise<string | null>;
14
- findSystemDiscounts: () => Promise<Array<string>>;
15
- }>;
16
- };
17
-
18
- export const BaseDiscountDirector = <DiscountConfigurationType>(
19
- directorName: string,
20
- ): IDiscountDirector<DiscountConfigurationType> => {
21
- const baseDirector = BaseDirector<IDiscountAdapter<DiscountConfigurationType>>(directorName, {
22
- adapterSortKey: 'orderIndex',
23
- });
24
-
25
- return {
26
- ...baseDirector,
27
-
28
- actions: async (discountContext, unchainedAPI) => {
29
- const context = { ...discountContext, ...unchainedAPI };
30
-
31
- return {
32
- resolveDiscountKeyFromStaticCode: async (options) => {
33
- if (!context.order) return null;
34
-
35
- log(`DiscountDirector -> Find user discount for static code ${options?.code}`);
36
-
37
- const discounts = await Promise.all(
38
- baseDirector
39
- .getAdapters()
40
- .filter((Adapter) => Adapter.isManualAdditionAllowed(options?.code))
41
- .map(async (Adapter) => {
42
- const adapter = await Adapter.actions({ context });
43
- return {
44
- key: Adapter.key,
45
- isValid: await adapter.isValidForCodeTriggering(options),
46
- };
47
- }),
48
- );
49
-
50
- return discounts.find(({ isValid }) => isValid === true)?.key;
51
- },
52
-
53
- async findSystemDiscounts() {
54
- if (!context.order) return [];
55
- const discounts = await Promise.all(
56
- baseDirector.getAdapters().map(async (Adapter) => {
57
- const adapter = await Adapter.actions({ context });
58
- return {
59
- key: Adapter.key,
60
- isValid: await adapter.isValidForSystemTriggering(),
61
- };
62
- }),
63
- );
64
-
65
- const validDiscounts = discounts
66
- .filter(({ isValid }) => isValid === true)
67
- .map(({ key }) => key);
68
-
69
- if (validDiscounts.length > 0) {
70
- log(`DiscountDirector -> Found ${validDiscounts.length} system discounts`);
71
- }
72
- return validDiscounts;
73
- },
74
- };
75
- },
76
- };
77
- };
@@ -1,89 +0,0 @@
1
- import { UnchainedCore } from '@unchainedshop/core';
2
- import { User } from '@unchainedshop/core-users';
3
- import { log, LogLevel } from '@unchainedshop/logger';
4
- import { IPricingSheet, PricingCalculation } from './BasePricingSheet.js';
5
- import { IBaseAdapter } from './BaseAdapter.js';
6
- import { Discount } from './BasePricingDirector.js';
7
-
8
- type Order = { _id?: string };
9
- type OrderDiscount = { _id?: string };
10
-
11
- interface IDiscountableItem {
12
- _id?: string;
13
- orderId?: string;
14
- }
15
-
16
- export interface BasePricingAdapterContext extends UnchainedCore {
17
- order?: Order;
18
- user: User;
19
- discounts: Array<OrderDiscount>;
20
- }
21
-
22
- export type BasePricingContext =
23
- | {
24
- order?: Order;
25
- user?: User;
26
- discounts?: Array<OrderDiscount>;
27
- }
28
- | {
29
- item: IDiscountableItem;
30
- };
31
-
32
- export interface IPricingAdapterActions<
33
- Calculation extends PricingCalculation,
34
- PricingAdapterContext extends BasePricingAdapterContext,
35
- > {
36
- calculate: () => Promise<Array<Calculation>>;
37
- getCalculation: () => Array<Calculation>;
38
- getContext: () => PricingAdapterContext;
39
- }
40
-
41
- export type IPricingAdapter<
42
- PricingAdapterContext extends BasePricingAdapterContext,
43
- Calculation extends PricingCalculation,
44
- Sheet extends IPricingSheet<Calculation>,
45
- DiscountConfiguration = unknown,
46
- > = IBaseAdapter & {
47
- orderIndex: number;
48
-
49
- isActivatedFor: (context: PricingAdapterContext) => boolean;
50
-
51
- actions: (params: {
52
- context: PricingAdapterContext;
53
- calculationSheet: Sheet;
54
- discounts: Array<Discount<DiscountConfiguration>>;
55
- }) => IPricingAdapterActions<Calculation, PricingAdapterContext> & { resultSheet: () => Sheet };
56
- };
57
-
58
- export const BasePricingAdapter = <
59
- PricingAdapterContext extends BasePricingAdapterContext,
60
- Calculation extends PricingCalculation,
61
- >(): IPricingAdapter<PricingAdapterContext, Calculation, IPricingSheet<Calculation>> => ({
62
- key: '',
63
- label: '',
64
- version: '',
65
- orderIndex: 0,
66
-
67
- isActivatedFor: () => {
68
- return false;
69
- },
70
-
71
- actions: (params) => {
72
- const calculation = [];
73
- const actions: IPricingAdapterActions<Calculation, PricingAdapterContext> = {
74
- calculate: async () => {
75
- return [];
76
- },
77
- getCalculation: () => calculation,
78
- getContext: () => params.context,
79
- };
80
-
81
- return actions as IPricingAdapterActions<Calculation, PricingAdapterContext> & {
82
- resultSheet: () => IPricingSheet<Calculation>;
83
- };
84
- },
85
-
86
- log(message: string, { level = LogLevel.Debug, ...options } = {}) {
87
- return log(message, { level, ...options });
88
- },
89
- });
@@ -1,133 +0,0 @@
1
- import { log, LogLevel } from '@unchainedshop/logger';
2
- import { BaseDirector, IBaseDirector } from './BaseDirector.js';
3
- import { UnchainedCore } from '@unchainedshop/core';
4
- import {
5
- BasePricingAdapterContext,
6
- BasePricingContext,
7
- IPricingAdapter,
8
- IPricingAdapterActions,
9
- } from './BasePricingAdapter.js';
10
- import { IPricingSheet, PricingCalculation } from './BasePricingSheet.js';
11
- export interface Discount<DiscountConfiguration> {
12
- discountId: string;
13
- configuration: DiscountConfiguration;
14
- }
15
-
16
- export type IPricingDirector<
17
- PricingContext extends BasePricingContext,
18
- Calculation extends PricingCalculation,
19
- PricingAdapterContext extends BasePricingAdapterContext,
20
- PricingAdapterSheet extends IPricingSheet<Calculation>,
21
- Adapter extends IPricingAdapter<PricingAdapterContext, Calculation, PricingAdapterSheet>,
22
- > = IBaseDirector<Adapter> & {
23
- buildPricingContext: (
24
- context: PricingContext,
25
- unchainedAPI: UnchainedCore,
26
- ) => Promise<PricingAdapterContext>;
27
- actions: (
28
- pricingContext: PricingContext,
29
- unchainedAPI: UnchainedCore,
30
- buildPricingContext?: (
31
- pricingCtx: PricingContext,
32
- _unchainedAPI: UnchainedCore,
33
- ) => Promise<PricingAdapterContext>,
34
- ) => Promise<
35
- IPricingAdapterActions<Calculation, PricingAdapterContext> & {
36
- calculationSheet: () => PricingAdapterSheet;
37
- }
38
- >;
39
- };
40
-
41
- export const BasePricingDirector = <
42
- DirectorContext extends BasePricingContext,
43
- AdapterContext extends BasePricingAdapterContext,
44
- Calculation extends PricingCalculation,
45
- PricingAdapter extends IPricingAdapter<AdapterContext, Calculation, IPricingSheet<Calculation>>,
46
- >(
47
- directorName: string,
48
- ): IPricingDirector<
49
- DirectorContext,
50
- Calculation,
51
- AdapterContext,
52
- IPricingSheet<Calculation>,
53
- PricingAdapter
54
- > => {
55
- const baseDirector = BaseDirector<PricingAdapter>(directorName, {
56
- adapterSortKey: 'orderIndex',
57
- });
58
-
59
- const director: IPricingDirector<
60
- DirectorContext,
61
- Calculation,
62
- AdapterContext,
63
- IPricingSheet<Calculation>,
64
- PricingAdapter
65
- > = {
66
- ...baseDirector,
67
- buildPricingContext: async () => {
68
- return {} as AdapterContext;
69
- },
70
- actions: async (pricingContext, unchainedAPI, buildPricingContext) => {
71
- const context = await buildPricingContext(pricingContext, unchainedAPI);
72
-
73
- let calculation: Array<Calculation> = [];
74
-
75
- const actions: IPricingAdapterActions<Calculation, AdapterContext> = {
76
- async calculate() {
77
- const Adapters = baseDirector.getAdapters({
78
- adapterFilter: (Adapter) => {
79
- return Adapter.isActivatedFor(context);
80
- },
81
- });
82
-
83
- calculation = await Adapters.reduce(async (previousPromise, Adapter) => {
84
- const resolvedCalculation = await previousPromise;
85
- if (!resolvedCalculation) return null;
86
-
87
- const discounts: Array<Discount<any>> = await Promise.all(
88
- context.discounts.map(async (discount) => ({
89
- discountId: discount._id,
90
- configuration: await context.modules.orders.discounts.configurationForPricingAdapterKey(
91
- discount as any,
92
- Adapter.key,
93
- this.calculationSheet(),
94
- context as any,
95
- ),
96
- })),
97
- );
98
-
99
- try {
100
- const adapter = Adapter.actions({
101
- context,
102
- calculationSheet: this.calculationSheet(),
103
- discounts: discounts.filter(({ configuration }) => configuration !== null),
104
- });
105
-
106
- const nextCalculationResult = await adapter.calculate();
107
- if (!nextCalculationResult) return null;
108
- calculation = resolvedCalculation.concat(nextCalculationResult);
109
- return calculation;
110
- } catch (error) {
111
- log(error, { level: LogLevel.Error });
112
- }
113
- return resolvedCalculation;
114
- }, Promise.resolve([]));
115
-
116
- return calculation;
117
- },
118
- getCalculation() {
119
- return calculation;
120
- },
121
- getContext() {
122
- return context;
123
- },
124
- };
125
-
126
- return actions as IPricingAdapterActions<Calculation, AdapterContext> & {
127
- calculationSheet: () => IPricingSheet<Calculation>;
128
- };
129
- },
130
- };
131
-
132
- return director;
133
- };