fix/carga-csv-ergonomia

This commit is contained in:
2026-05-06 14:24:41 -06:00
parent 8c8cd0e247
commit daa3a252b9
53 changed files with 3164 additions and 391 deletions

View File

@@ -0,0 +1,143 @@
"""Tests for CSV template header hints (inline) and import lookup aliases (stdlib unittest)."""
import unittest
from api.v1.modules.a76.csv_templates.registry import (
_normalize_header_for_match,
_TEMPLATE_HEADERS,
get_download_headers,
)
from api.v1.modules.a76.layouts_csv.common.template_locale import (
download_header_cell,
display_header_for_locale,
)
from api.v1.modules.a76.layouts_csv.clients_and_providers import template_config as cp_tc
class TestRegistryCsvDownloadSmoke(unittest.TestCase):
"""Smoke: cada template_id del registry tiene fila de descarga misma longitud que columnas base."""
def test_download_headers_length_matches_registry_for_all_templates(self):
for tid in sorted(_TEMPLATE_HEADERS.keys()):
row = get_download_headers(tid, "es")
self.assertIsNotNone(row, tid)
self.assertEqual(len(row), len(_TEMPLATE_HEADERS[tid]), tid)
def test_customs_brokers_lookup_resolves_decorated_tip_header(self):
from api.v1.modules.a76.layouts_csv.customs_brokers import template_config as cb_tc
lookup = cb_tc.build_normalized_lookup(_normalize_header_for_match)
hdr0 = get_download_headers("customs_brokers", "es")[0]
self.assertEqual(lookup[_normalize_header_for_match(hdr0)], "TIPO")
def test_imp_temp_header_lookup_resolves_decorated_e_document(self):
from api.v1.modules.a76.layouts_csv.facturas import template_config as ft_tc
lookup = ft_tc.build_normalized_lookup("imp_temp_header", _normalize_header_for_match)
for cell in get_download_headers("imp_temp_header", "es"):
if lookup.get(_normalize_header_for_match(cell)) == "E DOCUMENT":
self.assertIn("(S, N)", cell)
return
self.fail("E DOCUMENT column missing from imp_temp_header download row")
def test_pedimentos_lookup_resolves_tipo_operacion_decorated(self):
from api.v1.modules.a76.layouts_csv.pedmientos import template_config as ped_tc
lookup = ped_tc.build_normalized_lookup(_normalize_header_for_match, "pedimentos")
for cell in get_download_headers("pedimentos", "es"):
if lookup.get(_normalize_header_for_match(cell)) == "TIPO_OPERACION":
self.assertIn("(I, E)", cell)
return
self.fail("TIPO_OPERACION column missing from pedimentos download row")
def test_material_classes_lookup_resolves_revfisica_enum_header(self):
from api.v1.modules.a76.layouts_csv.classes import template_config as cl_tc
lookup = cl_tc.build_normalized_lookup(_normalize_header_for_match)
for cell in get_download_headers("material_classes", "es"):
if lookup.get(_normalize_header_for_match(cell)) == "REVFISICA":
self.assertIn("(1, 0)", cell)
return
self.fail("REVFISICA column missing from material_classes download row")
class TestCsvHeaderHints(unittest.TestCase):
def test_download_header_cell_enum_within_limit(self):
col = {
"canonical": "TIPO",
"csv_hint": {"kind": "enum_codes", "codes": ["C", "P", "A"]},
}
self.assertEqual(download_header_cell(col, "es"), "TIPO (C, P, A)")
col_en = {**col, "labels": {"en": "Entity type"}}
self.assertEqual(download_header_cell(col_en, "en"), "Entity type (C, P, A)")
def test_download_header_cell_enum_over_limit_ignored(self):
col = {
"canonical": "X",
"csv_hint": {"kind": "enum_codes", "codes": ["a", "b", "c", "d"]},
}
self.assertEqual(download_header_cell(col, "es"), "X")
def test_download_header_cell_digits_es_en(self):
col = {"canonical": "NUMERO", "csv_hint": {"kind": "digits", "n": 7}}
self.assertEqual(download_header_cell(col, "es"), "NUMERO (7 dígitos)")
self.assertEqual(download_header_cell(col, "en"), "NUMERO (7 digits)")
def test_clients_providers_lookup_accepts_extended_headers(self):
lookup = cp_tc.build_normalized_lookup(_normalize_header_for_match)
self.assertEqual(lookup[_normalize_header_for_match("PROCEDENCIA")], "PROCEDENCIA")
self.assertEqual(
lookup[_normalize_header_for_match("PROCEDENCIA (N, E)")],
"PROCEDENCIA",
)
self.assertEqual(lookup[_normalize_header_for_match("TIPO")], "TIPO")
self.assertEqual(lookup[_normalize_header_for_match("TIPO (C, P, A)")], "TIPO")
self.assertEqual(
lookup[_normalize_header_for_match("Origin (foreign/domestic) (N, E)")],
"PROCEDENCIA",
)
self.assertEqual(
lookup[_normalize_header_for_match("Entity type (C, P, A)")],
"TIPO",
)
self.assertEqual(
lookup[_normalize_header_for_match("RFC (máx. 30 caracteres)")],
"RFC",
)
self.assertEqual(
lookup[_normalize_header_for_match("SHORT_NAME (máx. 10 caracteres)")],
"SHORT_NAME",
)
self.assertEqual(
lookup[_normalize_header_for_match("Short code (max. 10 characters)")],
"SHORT_NAME",
)
def test_download_header_cell_max_chars(self):
col = {"canonical": "RFC", "csv_hint": {"kind": "max_chars", "n": 30}}
self.assertEqual(download_header_cell(col, "es"), "RFC (máx. 30 caracteres)")
self.assertEqual(download_header_cell(col, "en"), "RFC (max. 30 characters)")
col_one = {"canonical": "X", "csv_hint": {"kind": "max_chars", "n": 1}}
self.assertEqual(download_header_cell(col_one, "es"), "X (máx. 1 carácter)")
self.assertEqual(download_header_cell(col_one, "en"), "X (max. 1 character)")
def test_download_header_cell_enum_then_max_chars(self):
col = {
"canonical": "TIPO",
"csv_hint": [
{"kind": "enum_codes", "codes": ["C", "P", "A"]},
{"kind": "max_chars", "n": 1},
],
}
self.assertEqual(download_header_cell(col, "es"), "TIPO (C, P, A) (máx. 1 carácter)")
def test_display_header_unchanged_without_hint(self):
col = {"canonical": "ZZZ_NO_SCHEMA_LEN"}
self.assertEqual(
download_header_cell(col, "es"),
display_header_for_locale(col, "es"),
)
if __name__ == "__main__":
unittest.main()