Last active
April 8, 2022 03:51
-
-
Save turbotobias/8f0838625f487c83e3df3a53d0687ef8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { PaymentAmount } from "./" | |
| describe("PaymentAmount", () => { | |
| const PaymentAmount100 = new PaymentAmount(100) | |
| const PaymentAmount500 = new PaymentAmount(500) | |
| const PaymentAmount1000 = new PaymentAmount(1000) | |
| const PaymentAmount10000 = new PaymentAmount(10000) | |
| test("declare amount properly", () => { | |
| expect(PaymentAmount100.amount).toBe(100) | |
| expect(PaymentAmount500.amount).toBe(500) | |
| expect(PaymentAmount1000.amount).toBe(1000) | |
| expect(PaymentAmount10000.amount).toBe(10000) | |
| }) | |
| test("get all fees feesToStripe", () => { | |
| expect(PaymentAmount100.feesToStripe).toBe(13.45) | |
| expect(PaymentAmount500.feesToStripe).toBe(25.55) | |
| expect(PaymentAmount1000.feesToStripe).toBe(40.68) | |
| expect(PaymentAmount10000.feesToStripe).toBe(312.93) | |
| }) | |
| test("get all fees feesToStas", () => { | |
| expect(PaymentAmount100.feesToStas).toBe(6.25) | |
| expect(PaymentAmount500.feesToStas).toBe(6.25) | |
| expect(PaymentAmount1000.feesToStas).toBe(6.25) | |
| expect(PaymentAmount10000.feesToStas).toBe(6.25) | |
| }) | |
| test("get total amount + all fees", () => { | |
| expect(PaymentAmount100.total).toBe(119.7) | |
| expect(PaymentAmount500.total).toBe(531.8) | |
| expect(PaymentAmount1000.total).toBe(1046.93) | |
| expect(PaymentAmount10000.total).toBe(10319.18) | |
| }) | |
| test("get total of % fees", () => { | |
| expect(PaymentAmount100.feesTotalPercent).toBe(19.7) | |
| expect(PaymentAmount500.feesTotalPercent).toBe(6.36) | |
| expect(PaymentAmount1000.feesTotalPercent).toBe(4.69) | |
| expect(PaymentAmount10000.feesTotalPercent).toBe(3.19) | |
| }) | |
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Payment } from "@stas/models" | |
| import { round } from ".." | |
| /** | |
| * @example | |
| * | |
| * ```ts | |
| * const fees = new PaymentAmount(1000) | |
| * fees.amount // 100 | |
| * fees.total // 119.7 | |
| * fees.feesTotalPercent // 19.7 | |
| * ``` | |
| */ | |
| export class PaymentAmount { | |
| /** | |
| * the amount used as the basis for fee calculations | |
| */ | |
| private _amount: number | |
| /** | |
| * the amount used as the basis for fee calculations | |
| */ | |
| private _amountMin: number = 1 | |
| /** | |
| * the amount used as the basis for fee calculations | |
| */ | |
| private _amountMax: number = 50000 | |
| /** | |
| * currency | |
| */ | |
| private _currency: string = "nok" | |
| /** | |
| * how many we assume will donate to one wishlist on average, which dictates the fee amount | |
| */ | |
| private _estimatedDonorsOnAvg: number = 2 | |
| /** | |
| * | |
| * @todo create separate transfers and fees | |
| * | |
| */ | |
| /** | |
| * decimal places: the number of decimals included when getting values, rounded to its nearest or up when 5 | |
| * | |
| * only used on exposed getters, not in calculations | |
| * | |
| * @example ./decimal-precision.test.ts | |
| */ | |
| private _dp: number = 2 | |
| /** | |
| * stripe fees | |
| */ | |
| private _stripePaymentAmountPercent: number = 2.9 | |
| private _stripePaymentAmountNOK: number = 0.3 | |
| private _stripeConnectFeePercent: number = 0.25 | |
| private _stripeConnectFeeNOK: number = 0.25 | |
| private _stripeConnectFeeMonthlyNOK: number = 20 | |
| /** | |
| * stas fees | |
| */ | |
| private _stasFeeNOK: number = 6.25 | |
| /** | |
| * @param amount the amount that fees are calculated from | |
| */ | |
| constructor(amount: number) { | |
| if (amount < this._amountMin || amount > this._amountMax) throw Error("payment amount out of bounds") | |
| this._amount = amount | |
| } | |
| private get stripeFeePrPayment() { | |
| const percent = this._amount * (this._stripePaymentAmountPercent / 100) | |
| return percent + this._stripePaymentAmountNOK | |
| } | |
| private get stripeFeePrWishlist() { | |
| const percent = this._amount * (this._stripeConnectFeePercent / 100) | |
| const flat = this._stripeConnectFeeNOK + this._stripeConnectFeeMonthlyNOK | |
| return percent + flat | |
| } | |
| private get stripeFeePrWishlistReduced() { | |
| return this.stripeFeePrWishlist / this._estimatedDonorsOnAvg | |
| } | |
| private get stasFeePrPayment() { | |
| return this._stasFeeNOK | |
| } | |
| /** | |
| * change the number of decimal places used to round numbers (only on public getters) | |
| * | |
| * @example ./decimal-precision.test.ts | |
| */ | |
| public set decimalPlaces(decimalPlaces: number) { | |
| this._dp = decimalPlaces | |
| } | |
| public get amountMin() { | |
| return this._amountMin | |
| } | |
| public get amountMax() { | |
| return this._amountMax | |
| } | |
| /** | |
| * all fees to stripe | |
| */ | |
| public get feesToStripe() { | |
| return round(this.stripeFeePrPayment + this.stripeFeePrWishlistReduced, this._dp) | |
| } | |
| /** | |
| * all fees to stas | |
| */ | |
| public get feesToStas() { | |
| return round(this.stasFeePrPayment, this._dp) | |
| } | |
| /** | |
| * the total amount of fees | |
| */ | |
| public get feesTotal() { | |
| return this.feesToStripe + this.feesToStas | |
| } | |
| /** | |
| * the % of all fees | |
| */ | |
| public get feesTotalPercent() { | |
| const percent = (this.feesTotal / this._amount) * 100 | |
| return round(percent, 2) | |
| } | |
| /** | |
| * the total amount + all fees | |
| */ | |
| public get total() { | |
| return round(this._amount + this.feesTotal, this._dp) | |
| } | |
| /** | |
| * the total amount + all fees, formatted for Stripe (zero decimal currency support) | |
| */ | |
| public get totalToStripe() { | |
| return PaymentAmount.toZeroDecimal(this.total) | |
| } | |
| /** | |
| * the total amount + all fees, formatted from Stripe (with double decimal currency support) | |
| */ | |
| public totalFromStripe(amount: number) { | |
| return PaymentAmount.toDecimal(amount) | |
| } | |
| /** | |
| * the amount that all fees are calculated from | |
| */ | |
| public get amount() { | |
| return this._amount | |
| } | |
| /** | |
| * the amount that all fees are calculated from | |
| */ | |
| public get amountInSmallestCurrencyUnit() { | |
| return PaymentAmount.toZeroDecimal(this._amount) | |
| } | |
| /** | |
| * which currency this fee is in, probably "nok" | |
| * | |
| * @see https://stripe.com/docs/currencies?presentment-currency=NO | |
| */ | |
| public get currency() { | |
| return this._currency.toLocaleLowerCase("nb-no") | |
| } | |
| /** | |
| * get `1 250 550,00 NOK` from amount `1250550` | |
| * | |
| * @see https://stripe.com/docs/currencies?presentment-currency=NO | |
| */ | |
| public static toStringNOK(amount: number) { | |
| return amount.toLocaleString("nb-no") + " NOK" | |
| } | |
| /** | |
| * returns an integer representation of a double amount. | |
| * | |
| * `converts 51.50 to 5150` | |
| * | |
| * @param amount 1234.5678 | |
| * @returns 123457 (this is implicitly intended as being equal to 1234.57 of X) | |
| */ | |
| public static toZeroDecimal(amount: number) { | |
| return round(amount * 100, 0) | |
| } | |
| /** | |
| * returns a double representation of an integer amount (the opposit of PaymentAmount.toZeroDecimal) | |
| * | |
| * converts `5150` to `51.50` | |
| */ | |
| public static toDecimal(amount: number) { | |
| return round(amount / 100, 2) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment