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 { round } from ".." | |
| /** | |
| * @example | |
| * | |
| * ```ts | |
| * const fees = new PaymentAmount(1000) | |
| * fees.getAmountToUser() // === 976.66 | |
| * fees.getAmountToStripe() // === 21 | |
| * ``` | |
| */ | |
| export class PaymentAmount { | |
| /** | |
| * the amount used as the basis for fee calculations | |
| */ | |
| private _amount: number | |
| /** | |
| * the amount used as the basis for fee calculations | |
| */ | |
| public static _amountMin: number = 1 | |
| /** | |
| * the amount used as the basis for fee calculations | |
| */ | |
| public static _amountMax: number = 50000 | |
| /** | |
| * currency | |
| */ | |
| public static _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 _decimals: 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 < PaymentAmount._amountMin || amount > PaymentAmount._amountMax) this._amount = 1 | |
| this._amount = amount | |
| } | |
| public get stripePaymentAmountPercent() { | |
| return this._stripePaymentAmountPercent | |
| } | |
| public get stripePaymentAmountNOK() { | |
| return this._stripePaymentAmountNOK | |
| } | |
| public get stripeConnectFeePercent() { | |
| return this._stripeConnectFeePercent | |
| } | |
| public get stripeConnectFeeNOK() { | |
| return this._stripeConnectFeeNOK | |
| } | |
| public get stripeConnectFeeMonthlyNOK() { | |
| return this._stripeConnectFeeMonthlyNOK | |
| } | |
| public get stasFeeNOK() { | |
| return this._stasFeeNOK | |
| } | |
| public get decimals() { | |
| return this._decimals | |
| } | |
| 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._decimals = decimalPlaces | |
| } | |
| public get amountMin() { | |
| return PaymentAmount._amountMin | |
| } | |
| public get amountMax() { | |
| return PaymentAmount._amountMax | |
| } | |
| /** | |
| * all fees to stripe | |
| */ | |
| public get feesToStripe() { | |
| return round(this.stripeFeePrPayment + this.stripeFeePrWishlistReduced, this._decimals) | |
| } | |
| /** | |
| * all fees to stas | |
| */ | |
| public get feesToStas() { | |
| return round(this.stasFeePrPayment, this._decimals) | |
| } | |
| /** | |
| * 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, this.decimals) | |
| } | |
| /** | |
| * the total amount + all fees | |
| */ | |
| public get total() { | |
| const total = Number(this._amount + this.feesTotal) | |
| return round(total, this.decimals) | |
| } | |
| /** | |
| * 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 PaymentAmount._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) | |
| } | |
| /** | |
| * converts `5150` to `51.50` | |
| * | |
| * returns a double representation of an integer amount (the opposit of PaymentAmount.toZeroDecimal) | |
| */ | |
| public static toDecimal(amount: number) { | |
| return round(amount / 100, 2) | |
| } | |
| } |
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
| const intPow10 = (power: number) => { | |
| if (power < 0 || power > 22) { | |
| return Math.pow(10, power) | |
| } | |
| const powers = [ | |
| 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, | |
| 1e21, 1e22, | |
| ] | |
| return powers[power] | |
| } | |
| /** | |
| * | |
| * @example | |
| * ```ts | |
| * round(10.234, 2) // 10.23 | |
| * round(10.235, 2) // 10.24 | |
| * round(10.236999999, 2) // 10.24 | |
| * ``` | |
| */ | |
| export const round = (num: number, decimalPlaces: number) => { | |
| if (typeof num !== "number" || typeof decimalPlaces !== "number") return NaN | |
| const power = intPow10(decimalPlaces || 0) | |
| const n = num * power * (1 + Number.EPSILON) | |
| return Math["round"](n) / power | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment