Coverage for polar/transaction/fees/stripe/__init__.py: 64%

43 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-12-05 15:52 +0000

1import csv 1a

2import math 1a

3from pathlib import Path 1a

4from typing import TypedDict 1a

5 

6 

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

13 

14 

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

29 

30 return country_fees 1a

31 

32 

33country_fees = _load_country_fees() 1a

34us_fees = country_fees["US"] 1a

35 

36 

37def round_stripe(amount: float) -> int: 1a

38 return math.ceil(amount) if amount - int(amount) >= 0.5 else math.floor(amount) 

39 

40 

41def get_stripe_international_fee(amount: int) -> int: 1a

42 return round_stripe(amount * 0.015) 

43 

44 

45def get_stripe_subscription_fee(amount: int) -> int: 1a

46 return round_stripe(amount * 0.005) 

47 

48 

49def get_stripe_invoice_fee(amount: int) -> int: 1a

50 return round_stripe(amount * 0.005) 

51 

52 

53def get_stripe_account_fee() -> int: 1a

54 """ 

55 Account fees vary per country, as per the data in `country_fees`. 

56 

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"] 

61 

62 

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"] 

66 

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"] 

70 

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)) 

73 

74 if reversed_amount <= 0: 

75 raise ValueError("Fees are higher than the amount to be paid out.") 

76 

77 transfer_fee = round_stripe(reversed_amount * p1) 

78 payout_fee = amount - reversed_amount - transfer_fee 

79 

80 return transfer_fee, payout_fee 

81 

82 

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]