@unchainedshop/utils 3.0.0-alpha7 → 3.0.0-rc10

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 (74) 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/ch/addressToString.d.ts +12 -0
  6. package/lib/ch/addressToString.d.ts.map +1 -0
  7. package/lib/ch/addressToString.js +14 -0
  8. package/lib/ch/addressToString.js.map +1 -0
  9. package/lib/ch/index.d.ts +3 -0
  10. package/lib/ch/index.d.ts.map +1 -0
  11. package/lib/ch/index.js +4 -0
  12. package/lib/ch/index.js.map +1 -0
  13. package/lib/ch/priceToString.d.ts +6 -0
  14. package/lib/ch/priceToString.d.ts.map +1 -0
  15. package/lib/ch/priceToString.js +6 -0
  16. package/lib/ch/priceToString.js.map +1 -0
  17. package/lib/director/BaseDirector.js +1 -1
  18. package/lib/director/BaseDirector.js.map +1 -1
  19. package/lib/sha1.d.ts +2 -0
  20. package/lib/sha1.d.ts.map +1 -0
  21. package/lib/sha1.js +6 -0
  22. package/lib/sha1.js.map +1 -0
  23. package/lib/sha256.d.ts +2 -0
  24. package/lib/sha256.d.ts.map +1 -0
  25. package/lib/sha256.js +6 -0
  26. package/lib/sha256.js.map +1 -0
  27. package/lib/utils-index.d.ts +17 -7
  28. package/lib/utils-index.d.ts.map +1 -1
  29. package/lib/utils-index.js +3 -13
  30. package/lib/utils-index.js.map +1 -1
  31. package/package.json +8 -11
  32. package/src/calculation.test.ts +0 -43
  33. package/src/calculation.ts +0 -26
  34. package/src/ch/addressToString.ts +23 -0
  35. package/src/ch/index.ts +3 -0
  36. package/src/ch/priceToString.ts +6 -0
  37. package/src/director/BaseDirector.ts +1 -1
  38. package/src/sha1.ts +5 -0
  39. package/src/sha256.ts +5 -0
  40. package/src/utils-index.test.ts +1 -1
  41. package/src/utils-index.ts +19 -17
  42. package/tsconfig.json +4 -4
  43. package/lib/director/BaseDiscountAdapter.d.ts +0 -38
  44. package/lib/director/BaseDiscountAdapter.d.ts.map +0 -1
  45. package/lib/director/BaseDiscountAdapter.js +0 -48
  46. package/lib/director/BaseDiscountAdapter.js.map +0 -1
  47. package/lib/director/BaseDiscountDirector.d.ts +0 -13
  48. package/lib/director/BaseDiscountDirector.d.ts.map +0 -1
  49. package/lib/director/BaseDiscountDirector.js +0 -50
  50. package/lib/director/BaseDiscountDirector.js.map +0 -1
  51. package/lib/director/BasePricingAdapter.d.ts +0 -46
  52. package/lib/director/BasePricingAdapter.d.ts.map +0 -1
  53. package/lib/director/BasePricingAdapter.js +0 -25
  54. package/lib/director/BasePricingAdapter.js.map +0 -1
  55. package/lib/director/BasePricingDirector.d.ts +0 -16
  56. package/lib/director/BasePricingDirector.d.ts.map +0 -1
  57. package/lib/director/BasePricingDirector.js +0 -61
  58. package/lib/director/BasePricingDirector.js.map +0 -1
  59. package/lib/director/BasePricingSheet.d.ts +0 -47
  60. package/lib/director/BasePricingSheet.d.ts.map +0 -1
  61. package/lib/director/BasePricingSheet.js +0 -54
  62. package/lib/director/BasePricingSheet.js.map +0 -1
  63. package/lib/random-value-hex.d.ts +0 -2
  64. package/lib/random-value-hex.d.ts.map +0 -1
  65. package/lib/random-value-hex.js +0 -8
  66. package/lib/random-value-hex.js.map +0 -1
  67. package/src/director/BaseDiscountAdapter.ts +0 -89
  68. package/src/director/BaseDiscountDirector.ts +0 -77
  69. package/src/director/BasePricingAdapter.ts +0 -89
  70. package/src/director/BasePricingDirector.ts +0 -133
  71. package/src/director/BasePricingSheet.ts +0 -121
  72. package/src/director/base-discount-adapter.test.ts +0 -49
  73. package/src/director/base-price-sheet.test.ts +0 -100
  74. package/src/random-value-hex.ts +0 -8
@@ -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
- };
@@ -1,121 +0,0 @@
1
- export interface PricingCalculation {
2
- category: string;
3
- amount: number;
4
- baseCategory?: string;
5
- meta?: any;
6
- }
7
- export interface PricingDiscount {
8
- discountId: string;
9
- amount: number;
10
- currency: string;
11
- }
12
-
13
- export interface IPricingSheet<Calculation extends PricingCalculation>
14
- extends IBasePricingSheet<Calculation> {
15
- discountPrices: (discountId?: string) => Array<PricingDiscount>;
16
- addDiscount: (params: { amount: number; discountId: string; meta?: any }) => void;
17
- }
18
-
19
- export interface IBasePricingSheet<Calculation extends PricingCalculation> {
20
- calculation: Array<Calculation>;
21
- currency?: string;
22
- quantity?: number;
23
-
24
- getRawPricingSheet: () => Array<Calculation>;
25
- filterBy: (filter?: Partial<Calculation>) => Array<Calculation>;
26
- isValid: () => boolean;
27
-
28
- gross: () => number;
29
- net: () => number;
30
- sum: (filter?: Partial<Calculation>) => number;
31
- total: (params?: { category?: string; discountId?: string; useNetPrice?: boolean }) => {
32
- amount: number;
33
- currency: string;
34
- };
35
-
36
- taxSum: (filter?: Partial<Calculation>) => number;
37
-
38
- resetCalculation: (sheetToInvert: IBasePricingSheet<Calculation>) => Array<Calculation>;
39
- }
40
-
41
- export interface PricingSheetParams<Calculation extends PricingCalculation> {
42
- calculation?: Array<Calculation>;
43
- currency?: string;
44
- quantity?: number;
45
- }
46
-
47
- export const BasePricingSheet = <Calculation extends PricingCalculation>(
48
- params: PricingSheetParams<Calculation>,
49
- ): IBasePricingSheet<Calculation> => {
50
- const pricingSheet: IBasePricingSheet<Calculation> = {
51
- calculation: params.calculation || [],
52
- currency: params.currency,
53
- quantity: params.quantity,
54
-
55
- getRawPricingSheet() {
56
- return this.calculation;
57
- },
58
-
59
- isValid() {
60
- return this.calculation.length > 0;
61
- },
62
-
63
- sum(filter) {
64
- return this.filterBy(filter)
65
- .filter(Boolean)
66
- .reduce((sum: number, calculationRow: Calculation) => sum + calculationRow.amount, 0);
67
- },
68
-
69
- taxSum() {
70
- return 0;
71
- },
72
-
73
- gross() {
74
- // Sum contains taxes, thus it's gross when just suming everything
75
- return this.sum();
76
- },
77
-
78
- net() {
79
- // Remove all taxes from gross to get net
80
- return this.sum() - this.taxSum();
81
- },
82
-
83
- total({ category, useNetPrice, discountId } = { useNetPrice: false }) {
84
- const amount = this.sum({ category, discountId });
85
- const taxAmountForCategory = this.taxSum({ baseCategory: category, discountId });
86
-
87
- // Sum does not contain taxes when filtering by category, it's net in that case and gross if there is no category
88
- const netAmount = !category ? amount - taxAmountForCategory : amount;
89
-
90
- return {
91
- amount: Math.round(useNetPrice ? netAmount : netAmount + taxAmountForCategory),
92
- currency: this.currency,
93
- };
94
- },
95
-
96
- filterBy(filter) {
97
- const filteredCalculation = Object.keys(filter || {}).reduce(
98
- (oldCalculation, filterKey) =>
99
- oldCalculation.filter(
100
- (row: Calculation) =>
101
- !!row && (filter[filterKey] === undefined || row[filterKey] === filter[filterKey]),
102
- ),
103
- this.calculation,
104
- );
105
-
106
- return filteredCalculation;
107
- },
108
-
109
- resetCalculation(calculationSheet) {
110
- calculationSheet.filterBy().forEach(({ amount, ...row }: Calculation) => {
111
- this.calculation.push({
112
- ...row,
113
- amount: amount * -1,
114
- } as Calculation);
115
- });
116
- return this.calculation;
117
- },
118
- };
119
-
120
- return pricingSheet;
121
- };
@@ -1,49 +0,0 @@
1
- import { BaseDiscountAdapter } from './BaseDiscountAdapter.js';
2
-
3
- describe('BaseDiscountAdapter instantiation', () => {
4
- const adapter = BaseDiscountAdapter;
5
- const context = null as any;
6
- it('should initialize with default values', async () => {
7
- expect(adapter.orderIndex).toEqual(0);
8
- expect(adapter.log).toEqual(expect.any(Function));
9
- expect(await adapter.isManualAdditionAllowed('')).toEqual(false);
10
- expect(await adapter.isManualRemovalAllowed()).toEqual(false);
11
- expect(await adapter.actions(context)).toEqual({
12
- isValidForSystemTriggering: expect.any(Function),
13
- reserve: expect.any(Function),
14
- release: expect.any(Function),
15
- isValidForCodeTriggering: expect.any(Function),
16
- discountForPricingAdapterKey: expect.any(Function),
17
- });
18
- });
19
-
20
- describe('actions', () => {
21
- it('isValidForSystemTriggering', async () => {
22
- const result = await adapter.actions(context);
23
- expect(await result.isValidForSystemTriggering()).toEqual(false);
24
- });
25
-
26
- it('reserve', async () => {
27
- const result = await adapter.actions(context);
28
- expect(await result.reserve({ code: '' })).toEqual({});
29
- });
30
-
31
- it('release', async () => {
32
- const result = await adapter.actions(context);
33
- expect(await result.release()).toEqual(null);
34
- });
35
-
36
- it('isValidForCodeTriggering', async () => {
37
- const result = await adapter.actions(context);
38
- expect(await result.isValidForCodeTriggering({ code: '' })).toEqual(false);
39
- });
40
-
41
- it('discountForPricingAdapterKey', async () => {
42
- const result = await adapter.actions(context);
43
- const calculationSheet = {};
44
- expect(
45
- await result.discountForPricingAdapterKey({ calculationSheet, pricingAdapterKey: 'key' } as any),
46
- ).toEqual(null);
47
- });
48
- });
49
- });
@@ -1,100 +0,0 @@
1
- import { BasePricingSheet } from './BasePricingSheet.js';
2
-
3
- describe('BasePricingSheet', () => {
4
- let pricingSheet;
5
- const TAX = { category: 'tax', amount: 100 };
6
- const DISCOUNT = { category: 'discount', amount: 50 };
7
- const ITEM1 = { category: 'item', amount: 200 };
8
- const ITEM2 = { category: 'item', amount: 200 };
9
- const calculations = [TAX, DISCOUNT, ITEM1, ITEM2];
10
-
11
- beforeEach(() => {
12
- pricingSheet = BasePricingSheet({
13
- calculation: calculations,
14
- });
15
- });
16
-
17
- it('gross() calculates the sum of the amounts in the calculations', () => {
18
- expect(pricingSheet.gross()).toEqual(550);
19
- });
20
-
21
- it('gross() returns 0 if the calculation is empty', () => {
22
- expect(BasePricingSheet({ calculation: [] }).gross()).toEqual(0);
23
- });
24
-
25
- it('total() calculates the sum of the amounts in the calculations by default', () => {
26
- expect(pricingSheet.total()).toEqual({ amount: 550, currency: undefined });
27
- });
28
-
29
- it('total() calculates the sum of the amounts in the calculations for a given category', () => {
30
- expect(pricingSheet.total({ category: 'item' })).toEqual({ amount: 400, currency: undefined });
31
- });
32
-
33
- it('total() calculates the net sum of the amounts in the calculations if useNetPrice is true', () => {
34
- expect(pricingSheet.total({ useNetPrice: true })).toEqual({ amount: 550, currency: undefined });
35
- });
36
-
37
- it('total() returns 0 if the calculation is empty', () => {
38
- expect(BasePricingSheet({ calculation: [] }).total()).toEqual({ amount: 0, currency: undefined });
39
- });
40
-
41
- it('calculates the correct net amount', () => {
42
- expect(pricingSheet.net()).toEqual(550);
43
- });
44
-
45
- it('calculates the correct sum for a given category', () => {
46
- expect(pricingSheet.sum({ category: 'item' })).toEqual(400);
47
- });
48
-
49
- it('calculates the correct tax amount', () => {
50
- expect(pricingSheet.taxSum()).toEqual(0);
51
- });
52
-
53
- describe('getRawPricingSheet', () => {
54
- it('returns the correct list of calculations', () => {
55
- expect(pricingSheet.getRawPricingSheet()).toEqual(calculations);
56
- });
57
-
58
- it('returns an empty list of calculations if none are provided', () => {
59
- expect(BasePricingSheet({}).getRawPricingSheet()).toEqual([]);
60
- });
61
- });
62
-
63
- describe('isValid', () => {
64
- it('returns true if the sheet has calculations', () => {
65
- expect(pricingSheet.isValid()).toEqual(true);
66
- });
67
-
68
- it('returns false if the sheet does not have calculations', () => {
69
- expect(BasePricingSheet({}).isValid()).toEqual(false);
70
- });
71
- });
72
-
73
- describe('filterBy', () => {
74
- it('filters the list of calculations correctly', () => {
75
- expect(pricingSheet.filterBy({ category: 'item' })).toEqual([ITEM1, ITEM2]);
76
- });
77
-
78
- it('returns the full list of calculations if no filter is provided', () => {
79
- expect(pricingSheet.filterBy()).toEqual(calculations);
80
- });
81
- });
82
-
83
- describe('resetCalculation', () => {
84
- it('resets the list of calculations correctly', () => {
85
- const expectedCalculations = calculations.reduce(
86
- (prev, { amount, ...row }) => {
87
- return [
88
- ...prev,
89
- {
90
- ...row,
91
- amount: -amount,
92
- },
93
- ];
94
- },
95
- [...calculations],
96
- );
97
- expect(pricingSheet.resetCalculation(pricingSheet)).toEqual(expectedCalculations);
98
- });
99
- });
100
- });
@@ -1,8 +0,0 @@
1
- import crypto from 'crypto';
2
-
3
- export default function randomValueHex(len: number): string {
4
- return crypto
5
- .randomBytes(Math.ceil(len / 2))
6
- .toString('hex') // convert to hexadecimal format
7
- .slice(0, len); // return required number of characters
8
- }