Coverage for polar/transaction/fees/stripe/__init__.py: 64%
43 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 16:17 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 16:17 +0000
1import csv 1a
2import math 1a
3from pathlib import Path 1a
4from typing import TypedDict 1a
7class CountryFees(TypedDict): 1a
8 currency: str 1a
9 account_fee: int 1a
10 transfer_fee_percentage: float 1a
11 payout_fee_flat: int 1a
12 payout_fee_percentage: float 1a
15def _load_country_fees() -> dict[str, CountryFees]: 1a
16 country_fees = {} 1a
17 with open(Path(__file__).parent / "stripe_country_fees.csv") as file: 1a
18 reader = csv.DictReader(file) 1a
19 for row in reader: 1a
20 country = row["country"] 1a
21 fees = CountryFees( 1a
22 currency=row["currency"].lower(),
23 account_fee=int(row["account_fee"]),
24 transfer_fee_percentage=float(row["transfer_fee_percentage"]),
25 payout_fee_flat=int(row["payout_fee_flat"]),
26 payout_fee_percentage=float(row["payout_fee_percentage"]),
27 )
28 country_fees[country] = fees 1a
30 return country_fees 1a
33country_fees = _load_country_fees() 1a
34us_fees = country_fees["US"] 1a
37def round_stripe(amount: float) -> int: 1a
38 return math.ceil(amount) if amount - int(amount) >= 0.5 else math.floor(amount)
41def get_stripe_international_fee(amount: int) -> int: 1a
42 return round_stripe(amount * 0.015)
45def get_stripe_subscription_fee(amount: int) -> int: 1a
46 return round_stripe(amount * 0.005)
49def get_stripe_invoice_fee(amount: int) -> int: 1a
50 return round_stripe(amount * 0.005)
53def get_stripe_account_fee() -> int: 1a
54 """
55 Account fees vary per country, as per the data in `country_fees`.
57 However, for simplicity now, we will assume that the account fee
58 are the same as the US fees.
59 """
60 return us_fees["account_fee"]
63def get_reverse_stripe_payout_fees(amount: int, country: str) -> tuple[int, int]: 1a
64 fees = country_fees.get(country, us_fees)
65 p1 = fees["transfer_fee_percentage"]
67 # Assume for simplicity that the payout fee is the same as the US fees
68 p2 = us_fees["payout_fee_percentage"]
69 f2 = us_fees["payout_fee_flat"]
71 # Ref: https://www.wolframalpha.com/input?i=x+%2B+%28x*p_1%29+%2B+%28x+-+%28x*p_1%29%29+*+p_2+%2B+f_2+%3D+t
72 reversed_amount = math.floor((f2 - amount) / (p2 * p1 - p1 - p2 - 1))
74 if reversed_amount <= 0:
75 raise ValueError("Fees are higher than the amount to be paid out.")
77 transfer_fee = round_stripe(reversed_amount * p1)
78 payout_fee = amount - reversed_amount - transfer_fee
80 return transfer_fee, payout_fee
83__all__ = [ 1a
84 "round_stripe",
85 "get_stripe_subscription_fee",
86 "get_stripe_invoice_fee",
87 "get_stripe_account_fee",
88 "get_reverse_stripe_payout_fees",
89]