""" Marketplace-specific configuration: localized transaction-type translations, currencies, default FX rates, and storage-fee detection. The type translations were reverse-engineered from the real Jan-2026 files for all 13 marketplaces and cross-checked against the Finance team's own English helper column ("type 2") present in the localized EU reports. """ from __future__ import annotations import unicodedata def fold(s: str) -> str: """Lowercase, strip accents, collapse whitespace — matching key for localized text.""" s = unicodedata.normalize("NFD", str(s).lower().strip()) s = "".join(ch for ch in s if not unicodedata.combining(ch)) return " ".join(s.split()) # --------------------------------------------------------------------------- # Canonical transaction types = the USA vocabulary (what the engine/journal understand). # localized (folded) -> canonical English # --------------------------------------------------------------------------- _TYPE_SOURCES: dict[str, list[str]] = { "Order": [ "order", "commande", "bestellung", "ordine", "pedido", "bestelling", "zamowienie", "siparis", ], "Refund": [ "refund", "remboursement", "erstattung", "rimborso", "reembolso", "terugbetaling", "zwrot kosztow", "zwrot", "aterbetalning", "iade", ], "Adjustment": [ "adjustment", "ajustement", "anpassung", "modifica", "ajuste", "aanpassing", "korekta", "justering", "duzeltme", ], "Transfer": [ "transfer", "transfert", "transferer", "ubertrag", "uberweisung", "trasferimento", "transferir", "overboeking", "przelew", "overforing", "havale", ], "Service Fee": [ "service fee", "frais de service", "servicegebuhr", "commissione di servizio", "tarifa de prestacion de servicio", "servicekosten", "oplata za usluge", "serviceavgift", "hizmet bedeli", ], "FBA Customer Return Fee": [ "fba customer return fee", "fulfilment by amazon customer return fee", "frais de retour client fba", "frais de retour client expedie par amazon", "gebuhren fur kundenrucksendungen mit versand durch amazon", "tariffa di reso cliente di logistica di amazon", "tarifa de devolucion del cliente de logistica de amazon", "fba-kosten retourzending klant", "oplata za zwrot towaru od klienta w ramach fba", "avgift for fba-kundreturer", ], # Storage fees — Amazon calls these "FBA Inventory Fee" in the US report. "FBA Inventory Fee": [ "fba inventory fee", "fulfilment by amazon inventory fee", "frais de stock expedie par amazon", "versand durch amazon lagergebuhr", "costo di stoccaggio logistica di amazon", "tarifas de inventario de logistica de amazon", "lageravgift for fba", ], "FBA Transaction fees": [ "fba transaction fees", "fulfilment by amazon (fba) transaction fees", "frais de transaction expedie par amazon", "transaktionsgebuhren fur versand durch amazon", "commissioni per le transazioni di logistica di amazon", "tarifas de transaccion de logistica de amazon", ], "Amazon Fees": [ "amazon fees", "amazon fee", "gebuhren von amazon", "tariffe e commissioni amazon", "tarifas de amazon", ], "Shipping Services": ["shipping services", "delivery services"], "Order_Retrocharge": ["order_retrocharge", "bestellung_wiedereinzug", "cargo retroactivo"], "Refund_Retrocharge": ["refund_retrocharge", "erstattung_wiedereinzug"], "Chargeback Refund": ["chargeback refund", "erstattung durch ruckbuchung"], "Liquidations": ["liquidations", "liquidationen"], "Liquidations Adjustments": ["liquidations adjustments", "liquidationsanpassungen"], "Fee Adjustment": ["fee adjustment"], "SAFE-T reimbursement": ["safe-t reimbursement"], "A-to-z Guarantee Claim": ["a-to-z guarantee claim"], "Others": ["others"], "Debt": ["debt"], } TYPE_TRANSLATIONS: dict[str, str] = {} for _canon, _variants in _TYPE_SOURCES.items(): for _v in _variants: TYPE_TRANSLATIONS[fold(_v)] = _canon def normalize_type(raw: str | None) -> str: """Localized/variant transaction type -> canonical English (falls back to the original).""" if not raw: return "" return TYPE_TRANSLATIONS.get(fold(raw), str(raw).strip()) # --------------------------------------------------------------------------- # Currencies & default FX (seeded from the Jan-2026 AR workbook; always user-editable). # The workbook converts PLN/SEK/TRY to EUR first, then EUR->USD — collapsed here into # a single to-USD rate. # --------------------------------------------------------------------------- CURRENCY_BY_REGION: dict[str, str] = { "USA": "USD", "Canada": "CAD", "UK": "GBP", "Australia": "AUD", "Germany": "EUR", "France": "EUR", "Italy": "EUR", "Spain": "EUR", "Netherlands": "EUR", "Belgium": "EUR", "Ireland": "EUR", "Poland": "PLN", "Sweden": "SEK", "Turkey": "TRY", } _EUR_USD = 1.185665 DEFAULT_FX_USD: dict[str, float] = { "USA": 1.0, "Canada": 0.734438, "UK": 1.368908, "Australia": 0.696189, "Germany": _EUR_USD, "France": _EUR_USD, "Italy": _EUR_USD, "Spain": _EUR_USD, "Netherlands": _EUR_USD, "Belgium": _EUR_USD, "Ireland": _EUR_USD, "Poland": 0.23728 * _EUR_USD, # PLN->EUR->USD (full precision, matches workbook) "Sweden": 0.094559 * _EUR_USD, # SEK->EUR->USD "Turkey": 0.019409 * _EUR_USD, # TRY->EUR->USD } def currency_for_region(region: str) -> str: return CURRENCY_BY_REGION.get(region, "USD") def default_fx_for_region(region: str) -> float: return DEFAULT_FX_USD.get(region, 1.0) # --------------------------------------------------------------------------- # Storage-fee detection (req #8). Primary signal: canonical type == FBA Inventory Fee. # Secondary: storage keywords in the type/description — used to flag "potential storage # fees" recorded under other categories (never silently reclassified). # --------------------------------------------------------------------------- STORAGE_KEYWORDS = [ "storage", "lagergebuhr", "lagerung", "langzeitlager", # EN / DE "stockage", "frais de stock", # FR "stoccaggio", # IT "almacenamiento", "almacenaje", # ES "opslag", # NL "magazynowanie", "magazyn", # PL "lagring", "lageravgift", # SV "depolama", # TR "inventory storage", "monthly storage", "long-term storage", ] _STORAGE_KEYS_FOLDED = [fold(k) for k in STORAGE_KEYWORDS] # Markets where Amazon bills monthly FBA storage — used for the "expected storage fees # missing" warning. STORAGE_EXPECTED_REGIONS = { "USA", "Canada", "UK", "Germany", "France", "Italy", "Spain", "Netherlands", "Belgium", "Poland", "Sweden", "Australia", "Ireland", } def is_storage_like(type_en: str | None, description: str | None) -> bool: """True when the type/description reads as a storage fee.""" if type_en == "FBA Inventory Fee": return True hay = fold(f"{type_en or ''} {description or ''}") return any(k in hay for k in _STORAGE_KEYS_FOLDED)