From b2299e9efca8fd31ce027109f915afcddb93ae29 Mon Sep 17 00:00:00 2001 From: acazares Date: Wed, 11 Feb 2026 12:47:00 -0600 Subject: [PATCH] feat: add historical tariff fractions seeding and update model schema --- .../7937209f9718_seed_initial_data.py | 57 +++++++++++++++++++ .../historical_tariff_fractions/models.py | 13 +++-- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/backend/alembic/versions/7937209f9718_seed_initial_data.py b/backend/alembic/versions/7937209f9718_seed_initial_data.py index 3d4f719f..586a1da6 100644 --- a/backend/alembic/versions/7937209f9718_seed_initial_data.py +++ b/backend/alembic/versions/7937209f9718_seed_initial_data.py @@ -72,6 +72,12 @@ from api.v1.modules.a76.general_catalogs.units_of_measure.seed_adua import ( from api.v1.modules.a76.general_catalogs.fractions.tariff_fractions.seed import ( seed as tariff_fractions_seed, ) +from api.v1.modules.a76.general_catalogs.fractions.historical_tariff_fractions.seed import ( + seed as historical_tariff_fractions_seed, +) +from api.v1.modules.public.reference_data.trailer_types.seed import ( + seed as trailer_types_seed, +) from api.v1.modules.core.permissions.seed import ( seed_invoices, seed_user, @@ -307,6 +313,20 @@ def upgrade() -> None: """ ) + values_trailer = ", ".join( + [ + f"('{code}', '{desc.replace(chr(39), chr(39)*2)}')" + for code, desc in trailer_types_seed + ] + ) + op.execute( + f""" + INSERT INTO public.trailer_type (trailer_type_key, description) VALUES + {values_trailer} + ON CONFLICT (trailer_type_key) DO NOTHING; + """ + ) + values_vm = ", ".join( [ f"('{key}', '{desc.replace(chr(39), chr(39)*2)}')" @@ -481,12 +501,49 @@ def upgrade() -> None: """ ) + def format_bool(val): + """Convert boolean string to SQL boolean.""" + if val is None or str(val).strip() == "" or str(val).upper() == "NONE": + return "NULL" + return "TRUE" if str(val).upper() == "TRUE" else "FALSE" + + def format_timestamp(val): + """Format timestamp for PostgreSQL.""" + if val is None or str(val).strip() == "" or str(val).upper() == "NONE": + return "NULL" + # El valor ya viene en formato 'YYYY-MM-DD HH:MM:SS' + return f"'{str(val)}'" + + values_historical_fractions = ", ".join( + [ + f"({format_value(historical_fraction)}, {format_value(unit_measure)}, {format_value(country)}, " + f"{format_value(fraction_type)}, {format_value(sector)}, {format_value(import_tax)}, " + f"{format_value(export_tax)}, {format_timestamp(pub_date)}, {format_bool(is_immex)}, " + f"{format_bool(normal_temp)}, {format_bool(services_temp)}, {format_bool(certified_temp)}, " + f"{format_bool(by_log)}, {format_timestamp(end_date)})" + for historical_fraction, unit_measure, country, fraction_type, sector, import_tax, export_tax, pub_date, is_immex, normal_temp, services_temp, certified_temp, by_log, end_date in historical_tariff_fractions_seed + ] + ) + + if values_historical_fractions: + op.execute( + f""" + INSERT INTO a76.historical_tariff_fractions + (historical_fraction, unit_of_measure_code, country, fraction_type, sector, + import_tax_rate, export_tax_rate, publication_date, is_immex, + normal_temporality, services_temporality, certified_temporality, by_log, end_date) + VALUES {values_historical_fractions} + ON CONFLICT DO NOTHING; + """ + ) + def downgrade() -> None: """Downgrade schema.""" op.drop_table("valuation_methods", schema="public") op.drop_table("transport_types", schema="public") + op.drop_table("trailer_types", schema="public") op.drop_table("transport_modes", schema="public") op.drop_table("sectors", schema="public") op.drop_table("payment_methods", schema="public") diff --git a/backend/api/v1/modules/a76/general_catalogs/fractions/historical_tariff_fractions/models.py b/backend/api/v1/modules/a76/general_catalogs/fractions/historical_tariff_fractions/models.py index cd29c6b5..13a7068e 100644 --- a/backend/api/v1/modules/a76/general_catalogs/fractions/historical_tariff_fractions/models.py +++ b/backend/api/v1/modules/a76/general_catalogs/fractions/historical_tariff_fractions/models.py @@ -1,6 +1,7 @@ +from datetime import datetime from typing import Optional from decimal import Decimal -from sqlalchemy import ForeignKey, String, Integer, Numeric, Boolean +from sqlalchemy import DateTime, ForeignKey, String, Integer, Numeric, Boolean from sqlalchemy.orm import Mapped, mapped_column from core.database import Base @@ -12,20 +13,20 @@ class HistoricalTariffFraction(Base): """ __tablename__ = "historical_tariff_fractions" - __table_args__ = {"schema": "76"} + __table_args__ = {"schema": "a76"} id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False) historical_fraction: Mapped[Optional[str]] = mapped_column(String(8), nullable=True) unit_of_measure_code: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.unit_of_measure_customs.code"), nullable=True) - country: Mapped[Optional[str]] = mapped_column(String(3), nullable=True) + country: Mapped[Optional[str]] = mapped_column(ForeignKey("public.countries.m3_key"), nullable=True) fraction_type: Mapped[Optional[str]] = mapped_column(String(7), nullable=True) sector: Mapped[Optional[str]] = mapped_column(String(5), nullable=True) import_tax_rate: Mapped[Optional[Decimal]] = mapped_column(Numeric(7, 2), nullable=True) export_tax_rate: Mapped[Optional[Decimal]] = mapped_column(Numeric(7, 2), nullable=True) - publication_date: Mapped[Optional[int]] = mapped_column(Integer, nullable=True) - is_immex: Mapped[Optional[str]] = mapped_column(String(2), nullable=True) + publication_date: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True) + is_immex: Mapped[Optional[bool]] = mapped_column(Boolean, nullable=True) normal_temporality: Mapped[Optional[bool]] = mapped_column(Boolean, nullable=True) services_temporality: Mapped[Optional[bool]] = mapped_column(Boolean, nullable=True) certified_temporality: Mapped[Optional[bool]] = mapped_column(Boolean, nullable=True) by_log: Mapped[Optional[bool]] = mapped_column(Boolean, nullable=True) - end_date: Mapped[Optional[int]] = mapped_column(Integer, nullable=True) + end_date: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)