@lucaapp/service-utils 4.3.0 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,16 @@
1
1
  import { Model } from 'sequelize';
2
2
  import { SupportedCurrencies } from './supportedCurrencies';
3
+ export declare enum RoundingStrategy {
4
+ COMMERCIAL = "commercial",// Round half up (default)
5
+ ROUND_DOWN = "round_down",// Always round down
6
+ ROUND_UP = "round_up"
7
+ }
3
8
  interface MoneyInterface<T extends SupportedCurrencies> {
4
9
  getAmount(): number;
5
- add(addend?: Money<T>): Money<T>;
6
- subtract(subtrahend?: Money<T>): Money<T>;
7
- multiply(multiplier: number): Money<T>;
8
- divide(divisor: number): Money<T>;
10
+ add(addend?: Money<T>, roundingStrategy?: RoundingStrategy): Money<T>;
11
+ subtract(subtrahend?: Money<T>, roundingStrategy?: RoundingStrategy): Money<T>;
12
+ multiply(multiplier: number, roundingStrategy?: RoundingStrategy): Money<T>;
13
+ divide(divisor: number, roundingStrategy?: RoundingStrategy): Money<T>;
9
14
  equalsTo(comparator: Money<T>): boolean;
10
15
  lessThan(comparator: Money<T>): boolean;
11
16
  lessThanOrEqual(comparator: Money<T>): boolean;
@@ -19,7 +24,7 @@ export declare class Money<T extends SupportedCurrencies = SupportedCurrencies>
19
24
  readonly currency: T;
20
25
  private readonly value;
21
26
  static fromAmount<T extends SupportedCurrencies>(value: number, currency: T): Money<T>;
22
- static fromFloat<T extends SupportedCurrencies>(value: number, currency: T): Money<T>;
27
+ static fromFloat<T extends SupportedCurrencies>(value: number, currency: T, roundingStrategy?: RoundingStrategy): Money<T>;
23
28
  static zero<T extends SupportedCurrencies>(currency: T): Money<T>;
24
29
  static min<T extends SupportedCurrencies>(value1: Money<T>, value2: Money<T>): Money<T>;
25
30
  static max<T extends SupportedCurrencies>(value1: Money<T>, value2: Money<T>): Money<T>;
@@ -31,9 +36,9 @@ export declare class Money<T extends SupportedCurrencies = SupportedCurrencies>
31
36
  private assertSameCurrency;
32
37
  add(addend?: Money<T>): Money<T>;
33
38
  subtract(subtrahend?: Money<T>): Money<T>;
34
- multiply(multiplier: number): Money<T>;
35
- divide(divisor: number): Money<T>;
36
- percentage(percentage: number): Money<T>;
39
+ multiply(multiplier: number, roundingStrategy?: RoundingStrategy): Money<T>;
40
+ divide(divisor: number, roundingStrategy?: RoundingStrategy): Money<T>;
41
+ percentage(percentage: number, roundingStrategy?: RoundingStrategy): Money<T>;
37
42
  equalsTo(comparator: Money<T>): boolean;
38
43
  lessThan(comparator: Money<T>): boolean;
39
44
  lessThanOrEqual(comparator: Money<T>): boolean;
@@ -1,14 +1,47 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.moneyfiedSet = exports.moneyfiedGet = exports.Money = void 0;
3
+ exports.moneyfiedSet = exports.moneyfiedGet = exports.Money = exports.RoundingStrategy = void 0;
4
4
  const supportedCurrencies_1 = require("./supportedCurrencies");
5
+ var RoundingStrategy;
6
+ (function (RoundingStrategy) {
7
+ RoundingStrategy["COMMERCIAL"] = "commercial";
8
+ RoundingStrategy["ROUND_DOWN"] = "round_down";
9
+ RoundingStrategy["ROUND_UP"] = "round_up";
10
+ })(RoundingStrategy || (exports.RoundingStrategy = RoundingStrategy = {}));
5
11
  const MINOR_UNITS_PER_MAJOR_UNIT = 100;
6
12
  const EPSILON = 0.00000000001;
7
13
  const roundHalfUp = (value) => {
8
14
  const rounded = Math.sign(value) * Math.round(Math.abs(value) + EPSILON);
9
15
  return rounded === 0 ? 0 : rounded;
10
16
  };
11
- const convertToMinorUnits = (amountInMajorUnits) => roundHalfUp(amountInMajorUnits * MINOR_UNITS_PER_MAJOR_UNIT);
17
+ const roundDown = (value) => {
18
+ const truncated = Math.trunc(value);
19
+ return truncated === 0 ? 0 : truncated;
20
+ };
21
+ const roundUp = (value) => {
22
+ if (value >= 0) {
23
+ const ceiled = Math.ceil(value);
24
+ return ceiled === 0 ? 0 : ceiled;
25
+ }
26
+ else {
27
+ // For negative numbers, "round up" means towards zero (less negative)
28
+ const floored = Math.floor(value);
29
+ return floored === 0 ? 0 : floored;
30
+ }
31
+ };
32
+ const applyRounding = (value, strategy = RoundingStrategy.COMMERCIAL) => {
33
+ switch (strategy) {
34
+ case RoundingStrategy.COMMERCIAL:
35
+ return roundHalfUp(value);
36
+ case RoundingStrategy.ROUND_DOWN:
37
+ return roundDown(value);
38
+ case RoundingStrategy.ROUND_UP:
39
+ return roundUp(value);
40
+ default:
41
+ return roundHalfUp(value);
42
+ }
43
+ };
44
+ const convertToMinorUnits = (amountInMajorUnits, roundingStrategy = RoundingStrategy.COMMERCIAL) => applyRounding(amountInMajorUnits * MINOR_UNITS_PER_MAJOR_UNIT, roundingStrategy);
12
45
  const convertToMajorUnits = (amountInMinorUnits) => amountInMinorUnits / MINOR_UNITS_PER_MAJOR_UNIT;
13
46
  class Money {
14
47
  static fromAmount(value, currency) {
@@ -17,8 +50,8 @@ class Money {
17
50
  }
18
51
  return new Money(value, currency);
19
52
  }
20
- static fromFloat(value, currency) {
21
- return new Money(convertToMinorUnits(value), currency);
53
+ static fromFloat(value, currency, roundingStrategy = RoundingStrategy.COMMERCIAL) {
54
+ return new Money(convertToMinorUnits(value, roundingStrategy), currency);
22
55
  }
23
56
  static zero(currency) {
24
57
  return Money.fromAmount(0, currency);
@@ -81,20 +114,20 @@ class Money {
81
114
  this.assertSameCurrency(subtrahend);
82
115
  return Money.fromAmount(this.value - (subtrahend?.value || 0), this.currency);
83
116
  }
84
- multiply(multiplier) {
85
- return Money.fromAmount(roundHalfUp(this.value * multiplier), this.currency);
117
+ multiply(multiplier, roundingStrategy = RoundingStrategy.COMMERCIAL) {
118
+ return Money.fromAmount(applyRounding(this.value * multiplier, roundingStrategy), this.currency);
86
119
  }
87
- divide(divisor) {
120
+ divide(divisor, roundingStrategy = RoundingStrategy.COMMERCIAL) {
88
121
  if (divisor === 0) {
89
122
  throw new TypeError('Divisor cannot be zero');
90
123
  }
91
- return Money.fromAmount(roundHalfUp(this.value / divisor), this.currency);
124
+ return Money.fromAmount(applyRounding(this.value / divisor, roundingStrategy), this.currency);
92
125
  }
93
- percentage(percentage) {
126
+ percentage(percentage, roundingStrategy = RoundingStrategy.COMMERCIAL) {
94
127
  if (Number.isNaN(percentage) || percentage < 0 || percentage > 100) {
95
128
  throw new TypeError('Expected number between 0 and 100');
96
129
  }
97
- return Money.fromAmount(roundHalfUp((this.value / 100) * percentage), this.currency);
130
+ return Money.fromAmount(applyRounding((this.value / 100) * percentage, roundingStrategy), this.currency);
98
131
  }
99
132
  equalsTo(comparator) {
100
133
  this.assertSameCurrency(comparator);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucaapp/service-utils",
3
- "version": "4.3.0",
3
+ "version": "4.4.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [