110 lines
4.6 KiB
Python
110 lines
4.6 KiB
Python
"""CSV Amazon transaction reader — Belgium/FR June sample shape."""
|
||
from __future__ import annotations
|
||
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
from app.core.csv_reader import CsvReader, parse_amount
|
||
from app.core.readers import make_reader
|
||
|
||
|
||
def test_parse_amount_european():
|
||
assert parse_amount("13,49") == 13.49
|
||
assert parse_amount("1.234,56") == 1234.56
|
||
assert parse_amount("1,234.56") == 1234.56
|
||
assert parse_amount("-6,24") == -6.24
|
||
assert parse_amount("0") == 0.0
|
||
assert parse_amount("") == 0.0
|
||
|
||
|
||
def test_parse_amount_unicode_minus_and_spaces():
|
||
"""Sweden writes negatives with U+2212 and groups thousands with (narrow) NBSP.
|
||
|
||
float() rejects both, and the parser's fallback returned 0.0 — every negative
|
||
kronor amount (fees, taxes, transfers) of the Jan-2026 file silently vanished
|
||
while the positives kept adding up (control C2 caught the +165,810.53 drift)."""
|
||
assert parse_amount("−35,70") == -35.70 # −35,70
|
||
assert parse_amount("−78 690,40") == -78690.40 # −78 690,40 (NBSP)
|
||
assert parse_amount("−1 234,56") == -1234.56 # narrow NBSP thousands
|
||
assert parse_amount("1 234,56") == 1234.56
|
||
assert parse_amount("–6,24") == -6.24 # en dash used as minus
|
||
|
||
|
||
def test_second_amount_column_is_summed_not_dropped(tmp_path: Path):
|
||
"""Australia carries BOTH 'sales tax collected' and 'low value goods' (LVIG GST);
|
||
the row `total` includes both. Dropping the second column failed control C2 by its
|
||
sum. Amount-field collisions are summed; only non-amount collisions stay errors."""
|
||
body = (
|
||
'"preamble"\n'
|
||
'"date/time","settlement ID","type","order ID","sales tax collected",'
|
||
'"low value goods","total"\n'
|
||
'"1 Jan 2026 00:00:00 UTC","123","Order","o-1","10,00","-6,60","3,40"\n'
|
||
)
|
||
p = tmp_path / "2026JanMonthlyTransaction.csv"
|
||
p.write_text(body, encoding="utf-8-sig")
|
||
|
||
reader = CsvReader(str(p))
|
||
mapping = reader.detect()
|
||
assert mapping.sum_cols == {"sales_tax_collected": [("F", "low value goods")]}
|
||
assert not mapping.duplicate_fields
|
||
assert "F" not in mapping.unmapped
|
||
|
||
rows = list(reader.iter_records())
|
||
assert len(rows) == 1
|
||
assert rows[0]["sales_tax_collected"] == pytest.approx(3.40) # 10.00 + (-6.60)
|
||
assert rows[0]["total"] == 3.40
|
||
assert reader.file_meta.summed_fields == mapping.sum_cols
|
||
assert not reader.file_meta.unmapped_amount_sums
|
||
reader.close()
|
||
|
||
|
||
def test_make_reader_routes_csv(tmp_path: Path):
|
||
p = tmp_path / "sample.csv"
|
||
p.write_text(
|
||
"preamble\n"
|
||
"date/time,settlement id,type,total\n"
|
||
"1 Jun 2026 00:00:00 UTC,123,Order,10.00\n",
|
||
encoding="utf-8",
|
||
)
|
||
r = make_reader(str(p))
|
||
assert type(r).__name__ == "CsvReader"
|
||
|
||
|
||
def test_csv_reader_belgium_headers(tmp_path: Path):
|
||
# Minimal FR/BE Custom Unified Transaction CSV (preamble + header + 1 row).
|
||
body = (
|
||
'"Comprend les transactions Amazon Marketplace"\n'
|
||
'"Tous les montants sont en EUR, sauf indication contraire"\n'
|
||
'"date/heure","Identifiant du paiement","type","Numéro de la commande","SKU",'
|
||
'"description","quantité","site de vente","expédition","ville de la commande",'
|
||
'"état de la commande","commande postale","ventes de produits",'
|
||
'"crédits d’expédition","crédits d’emballage-cadeau","Total des réductions",'
|
||
'"taxe de ventes prélevée","Taxe Marketplace Facilitator","frais de vente",'
|
||
'"Frais pour le service Expédié par Amazon","autres frais de transaction",'
|
||
'"autres","total","Statut de la transaction","Date de délivrance de la transaction"\n'
|
||
'"31 mai 2026 22:00:44 UTC","27177484042","Commande","405-9354558-3629905",'
|
||
'"SKU1","desc","2","amazon.com.be","Amazon","Enines","","1350","29,74","0","0","0",'
|
||
'"6,24","-6,24","-4,68","-11,57","0","0","13,49","Effectuée","8 juin 2026 15:26:40 UTC"\n'
|
||
)
|
||
p = tmp_path / "2026JunMonthlyTransaction.csv"
|
||
p.write_text(body, encoding="utf-8-sig")
|
||
|
||
reader = CsvReader(str(p))
|
||
mapping = reader.detect()
|
||
assert not mapping.missing_required
|
||
assert reader.sheet_name == "CSV"
|
||
assert reader.file_meta.currency == "EUR"
|
||
|
||
rows = list(reader.iter_records())
|
||
assert len(rows) == 1
|
||
rec = rows[0]
|
||
assert rec["settlement_id"] == "27177484042"
|
||
assert rec["txn_type"] == "Commande"
|
||
assert rec["marketplace"] == "amazon.com.be"
|
||
assert rec["total"] == 13.49
|
||
assert rec["product_sales"] == 29.74
|
||
assert rec["_date"].isoformat() == "2026-05-31"
|
||
assert reader.file_meta.imported_rows == 1
|
||
reader.close()
|