Skip to content

Instantly share code, notes, and snippets.

@turbotobias
Last active April 8, 2022 03:51
Show Gist options
  • Save turbotobias/8f0838625f487c83e3df3a53d0687ef8 to your computer and use it in GitHub Desktop.
Save turbotobias/8f0838625f487c83e3df3a53d0687ef8 to your computer and use it in GitHub Desktop.
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)
})
})
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