parent
17f59c1fcb
commit
f65fac9661
@ -0,0 +1,18 @@ |
|||||||
|
# Generated by Django 5.1 on 2025-06-23 16:47 |
||||||
|
|
||||||
|
from django.db import migrations, models |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('tournaments', '0128_club_data_access_ids_court_data_access_ids_and_more'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.AddField( |
||||||
|
model_name='tournament', |
||||||
|
name='currency_code', |
||||||
|
field=models.CharField(blank=True, default='EUR', max_length=3, null=True), |
||||||
|
), |
||||||
|
] |
||||||
@ -0,0 +1,189 @@ |
|||||||
|
""" |
||||||
|
Currency service for handling multi-currency support in tournaments. |
||||||
|
""" |
||||||
|
|
||||||
|
class CurrencyService: |
||||||
|
"""Service for handling currency formatting, symbols, and conversions.""" |
||||||
|
|
||||||
|
# Currency symbols mapping |
||||||
|
CURRENCY_SYMBOLS = { |
||||||
|
'EUR': '€', |
||||||
|
'USD': '$', |
||||||
|
'GBP': '£', |
||||||
|
'CHF': 'CHF', |
||||||
|
'CAD': 'C$', |
||||||
|
'AUD': 'A$', |
||||||
|
'JPY': '¥', |
||||||
|
'CNY': '¥', |
||||||
|
'SEK': 'kr', |
||||||
|
'NOK': 'kr', |
||||||
|
'DKK': 'kr', |
||||||
|
'PLN': 'zł', |
||||||
|
'CZK': 'Kč', |
||||||
|
'HUF': 'Ft', |
||||||
|
'RON': 'lei', |
||||||
|
'BGN': 'лв', |
||||||
|
'HRK': 'kn', |
||||||
|
'RSD': 'RSD', |
||||||
|
'BAM': 'KM', |
||||||
|
'MKD': 'ден', |
||||||
|
'ALL': 'L', |
||||||
|
'MDL': 'L', |
||||||
|
'UAH': '₴', |
||||||
|
'RUB': '₽', |
||||||
|
'BYN': 'Br', |
||||||
|
'LTL': 'Lt', |
||||||
|
'LVL': 'Ls', |
||||||
|
'EEK': 'kr', |
||||||
|
'ISK': 'kr', |
||||||
|
'TRY': '₺', |
||||||
|
'ILS': '₪', |
||||||
|
'AED': 'د.إ', |
||||||
|
'SAR': 'ر.س', |
||||||
|
'QAR': 'ر.ق', |
||||||
|
'KWD': 'د.ك', |
||||||
|
'BHD': '.د.ب', |
||||||
|
'OMR': 'ر.ع.', |
||||||
|
'JOD': 'د.أ', |
||||||
|
'LBP': 'ل.ل', |
||||||
|
'EGP': 'ج.م', |
||||||
|
'MAD': 'د.م.', |
||||||
|
'TND': 'د.ت', |
||||||
|
'DZD': 'د.ج', |
||||||
|
'LYD': 'ل.د', |
||||||
|
'ZAR': 'R', |
||||||
|
'NGN': '₦', |
||||||
|
'GHS': '₵', |
||||||
|
'KES': 'KSh', |
||||||
|
'UGX': 'USh', |
||||||
|
'TZS': 'TSh', |
||||||
|
'ETB': 'Br', |
||||||
|
'XOF': 'CFA', |
||||||
|
'XAF': 'FCFA', |
||||||
|
'MZN': 'MT', |
||||||
|
'BWP': 'P', |
||||||
|
'ZMW': 'ZK', |
||||||
|
'INR': '₹', |
||||||
|
'PKR': '₨', |
||||||
|
'BDT': '৳', |
||||||
|
'LKR': '₨', |
||||||
|
'MVR': 'Rf', |
||||||
|
'NPR': '₨', |
||||||
|
'BTN': 'Nu.', |
||||||
|
'THB': '฿', |
||||||
|
'MYR': 'RM', |
||||||
|
'SGD': 'S$', |
||||||
|
'IDR': 'Rp', |
||||||
|
'PHP': '₱', |
||||||
|
'VND': '₫', |
||||||
|
'KHR': '៛', |
||||||
|
'LAK': '₭', |
||||||
|
'MMK': 'K', |
||||||
|
'KRW': '₩', |
||||||
|
'TWD': 'NT$', |
||||||
|
'HKD': 'HK$', |
||||||
|
'MOP': 'MOP$', |
||||||
|
'BND': 'B$', |
||||||
|
'FJD': 'FJ$', |
||||||
|
'PGK': 'K', |
||||||
|
'WST': 'WS$', |
||||||
|
'TOP': 'T$', |
||||||
|
'VUV': 'VT', |
||||||
|
'SBD': 'SI$', |
||||||
|
'MXN': '$', |
||||||
|
'GTQ': 'Q', |
||||||
|
'BZD': 'BZ$', |
||||||
|
'SVC': '$', |
||||||
|
'HNL': 'L', |
||||||
|
'NIO': 'C$', |
||||||
|
'CRC': '₡', |
||||||
|
'PAB': 'B/.', |
||||||
|
'COP': '$', |
||||||
|
'VES': 'Bs.S', |
||||||
|
'GYD': 'GY$', |
||||||
|
'SRD': 'Sr$', |
||||||
|
'UYU': '$U', |
||||||
|
'PYG': '₲', |
||||||
|
'BOB': 'Bs.', |
||||||
|
'BRL': 'R$', |
||||||
|
'PEN': 'S/', |
||||||
|
'ECU': '$', |
||||||
|
'CLP': '$', |
||||||
|
'ARS': '$', |
||||||
|
'FKP': '£', |
||||||
|
'XPF': '₣' |
||||||
|
} |
||||||
|
|
||||||
|
# Zero-decimal currencies (amounts are in their base unit, not subdivided) |
||||||
|
ZERO_DECIMAL_CURRENCIES = { |
||||||
|
'BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', |
||||||
|
'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF' |
||||||
|
} |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def get_currency_symbol(cls, currency_code): |
||||||
|
"""Get the currency symbol for a given currency code.""" |
||||||
|
if not currency_code: |
||||||
|
return '€' # Default to Euro symbol |
||||||
|
return cls.CURRENCY_SYMBOLS.get(currency_code.upper(), currency_code.upper()) |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def format_amount(cls, amount, currency_code, show_symbol=True): |
||||||
|
"""Format amount with proper currency symbol and decimal places.""" |
||||||
|
if amount is None: |
||||||
|
return "0" |
||||||
|
|
||||||
|
currency_code = currency_code.upper() if currency_code else 'EUR' |
||||||
|
|
||||||
|
# Handle zero-decimal currencies |
||||||
|
if currency_code in cls.ZERO_DECIMAL_CURRENCIES: |
||||||
|
formatted_amount = f"{int(amount)}" |
||||||
|
else: |
||||||
|
# Format with 2 decimal places, removing unnecessary zeros |
||||||
|
if amount == int(amount): |
||||||
|
formatted_amount = f"{int(amount)}" |
||||||
|
else: |
||||||
|
formatted_amount = f"{amount:.2f}" |
||||||
|
|
||||||
|
if show_symbol: |
||||||
|
symbol = cls.get_currency_symbol(currency_code) |
||||||
|
return f"{formatted_amount} {symbol}" |
||||||
|
|
||||||
|
return formatted_amount |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def convert_to_stripe_amount(cls, amount, currency_code): |
||||||
|
"""Convert amount to Stripe's expected format (minor units).""" |
||||||
|
if not amount: |
||||||
|
return 0 |
||||||
|
|
||||||
|
currency_code = currency_code.upper() if currency_code else 'EUR' |
||||||
|
|
||||||
|
# Zero-decimal currencies don't need conversion |
||||||
|
if currency_code in cls.ZERO_DECIMAL_CURRENCIES: |
||||||
|
return int(amount) |
||||||
|
|
||||||
|
# Two-decimal currencies need to be multiplied by 100 |
||||||
|
return int(amount * 100) |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def convert_from_stripe_amount(cls, stripe_amount, currency_code): |
||||||
|
"""Convert Stripe amount (minor units) back to standard decimal format.""" |
||||||
|
if not stripe_amount: |
||||||
|
return 0.0 |
||||||
|
|
||||||
|
currency_code = currency_code.upper() if currency_code else 'EUR' |
||||||
|
|
||||||
|
# Zero-decimal currencies are already in the correct format |
||||||
|
if currency_code in cls.ZERO_DECIMAL_CURRENCIES: |
||||||
|
return float(stripe_amount) |
||||||
|
|
||||||
|
# Two-decimal currencies need to be divided by 100 |
||||||
|
return float(stripe_amount) / 100 |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def validate_currency_code(cls, currency_code): |
||||||
|
"""Validate if a currency code is supported.""" |
||||||
|
if not currency_code: |
||||||
|
return False |
||||||
|
return currency_code.upper() in cls.CURRENCY_SYMBOLS |
||||||
Loading…
Reference in new issue