@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.
- package/lib/calculation.d.ts +0 -5
- package/lib/calculation.d.ts.map +1 -1
- package/lib/calculation.js +0 -20
- package/lib/calculation.js.map +1 -1
- package/lib/director/BaseDiscountAdapter.d.ts +3 -4
- package/lib/director/BaseDiscountAdapter.d.ts.map +1 -1
- package/lib/director/BaseDiscountAdapter.js.map +1 -1
- package/lib/director/BaseDiscountDirector.d.ts +3 -4
- package/lib/director/BaseDiscountDirector.d.ts.map +1 -1
- package/lib/director/BaseDiscountDirector.js.map +1 -1
- package/lib/director/BasePricingAdapter.d.ts +1 -5
- package/lib/director/BasePricingAdapter.d.ts.map +1 -1
- package/lib/director/BasePricingAdapter.js.map +1 -1
- package/lib/director/BasePricingDirector.d.ts +4 -5
- package/lib/director/BasePricingDirector.d.ts.map +1 -1
- package/lib/director/BasePricingDirector.js +1 -1
- package/lib/director/BasePricingDirector.js.map +1 -1
- package/lib/intersect-set.d.ts +3 -0
- package/lib/intersect-set.d.ts.map +1 -0
- package/lib/intersect-set.js +2 -0
- package/lib/intersect-set.js.map +1 -0
- package/lib/sha1.d.ts +2 -0
- package/lib/sha1.d.ts.map +1 -0
- package/lib/sha1.js +6 -0
- package/lib/sha1.js.map +1 -0
- package/lib/sha256.d.ts +2 -0
- package/lib/sha256.d.ts.map +1 -0
- package/lib/sha256.js +6 -0
- package/lib/sha256.js.map +1 -0
- package/lib/utils-index.d.ts +18 -6
- package/lib/utils-index.d.ts.map +1 -1
- package/lib/utils-index.js +3 -12
- package/lib/utils-index.js.map +1 -1
- package/lib/utils-index_BACKUP_3852.d.ts +35 -0
- package/lib/utils-index_BACKUP_3852.d.ts.map +1 -0
- package/lib/utils-index_BACKUP_3852.js +25 -0
- package/lib/utils-index_BACKUP_3852.js.map +1 -0
- package/lib/utils-index_BASE_3852.d.ts +27 -0
- package/lib/utils-index_BASE_3852.d.ts.map +1 -0
- package/lib/utils-index_BASE_3852.js +28 -0
- package/lib/utils-index_BASE_3852.js.map +1 -0
- package/lib/utils-index_LOCAL_3852.d.ts +35 -0
- package/lib/utils-index_LOCAL_3852.d.ts.map +1 -0
- package/lib/utils-index_LOCAL_3852.js +25 -0
- package/lib/utils-index_LOCAL_3852.js.map +1 -0
- package/lib/utils-index_REMOTE_3852.d.ts +31 -0
- package/lib/utils-index_REMOTE_3852.d.ts.map +1 -0
- package/lib/utils-index_REMOTE_3852.js +28 -0
- package/lib/utils-index_REMOTE_3852.js.map +1 -0
- package/package.json +8 -11
- package/src/calculation.test.ts +0 -43
- package/src/calculation.ts +0 -26
- package/src/intersect-set.ts +2 -0
- package/src/sha1.ts +5 -0
- package/src/sha256.ts +5 -0
- package/src/utils-index.test.ts +1 -1
- package/src/utils-index.ts +19 -16
- package/tsconfig.json +4 -4
- package/src/director/BaseDiscountAdapter.ts +0 -89
- package/src/director/BaseDiscountDirector.ts +0 -77
- package/src/director/BasePricingAdapter.ts +0 -89
- package/src/director/BasePricingDirector.ts +0 -133
- package/src/director/BasePricingSheet.ts +0 -121
- package/src/director/base-discount-adapter.test.ts +0 -49
- package/src/director/base-price-sheet.test.ts +0 -100
- 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-
|
|
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": "
|
|
13
|
-
"
|
|
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-
|
|
30
|
+
"@unchainedshop/logger": "^3.0.0-rc2",
|
|
34
31
|
"hashids": "^2.3.0",
|
|
35
|
-
"resolve-accept-language": "^3.1.
|
|
32
|
+
"resolve-accept-language": "^3.1.10"
|
|
36
33
|
},
|
|
37
34
|
"devDependencies": {
|
|
38
|
-
"@types/node": "^22.
|
|
35
|
+
"@types/node": "^22.10.2",
|
|
39
36
|
"jest": "^29.7.0",
|
|
40
|
-
"typescript": "^5.
|
|
37
|
+
"typescript": "^5.7.2"
|
|
41
38
|
}
|
|
42
39
|
}
|
package/src/calculation.test.ts
CHANGED
|
@@ -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);
|
package/src/calculation.ts
CHANGED
|
@@ -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,
|
package/src/sha1.ts
ADDED
package/src/sha256.ts
ADDED
package/src/utils-index.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolveBestCountry, resolveBestSupported, slugify, systemLocale } from '
|
|
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', () => {
|
package/src/utils-index.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
"
|
|
5
|
-
"
|
|
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
|
-
};
|