Merge pull request 'catalogos-frontend' (#8) from catalogos-frontend into development
Reviewed-on: ADUANASOFT/anexo76#8
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -15,18 +15,18 @@ downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
.pnpm-store/
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.env.local
|
||||
|
||||
backend/SCRIPTS/
|
||||
# IDEs
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
@@ -84,7 +84,8 @@ path_separator = os
|
||||
# database URL. This is consumed by the user-maintained env.py script only.
|
||||
# other means of configuring database URLs may be customized within the env.py
|
||||
# file.
|
||||
sqlalchemy.url = ${DATABASE_URL}
|
||||
|
||||
sqlalchemy.url = postgresql://${CORE_DB_USER}:${CORE_DB_PASSWORD}@${CORE_DB_HOST}:${CORE_DB_PORT}/${CORE_DB_NAME}
|
||||
|
||||
|
||||
[post_write_hooks]
|
||||
|
||||
@@ -78,8 +78,9 @@ fileConfig(config.config_file_name)
|
||||
target_metadata = Base.metadata
|
||||
|
||||
def import_models_from_dir(dir_path: str):
|
||||
"""Importa recursivamente cualquier archivo models.py desde dir_path"""
|
||||
"""Importa recursivamente cualquier archivo models.py desde dir_path y archivos en directorios models/"""
|
||||
for root, dirs, files in os.walk(dir_path):
|
||||
# Importar archivos models.py directos
|
||||
if "models.py" in files:
|
||||
module_path = os.path.join(root, "models.py")
|
||||
# Convertir path en nombre de módulo compatible
|
||||
@@ -89,6 +90,20 @@ def import_models_from_dir(dir_path: str):
|
||||
spec = importlib.util.spec_from_file_location(module_name, module_path)
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(mod)
|
||||
|
||||
# Importar todos los archivos .py en directorios llamados "models"
|
||||
if os.path.basename(root) == "models":
|
||||
for file in files:
|
||||
if file.endswith(".py") and not file.startswith("__"):
|
||||
module_path = os.path.join(root, file)
|
||||
rel_path = os.path.relpath(module_path, BASE_DIR)
|
||||
module_name = rel_path.replace(os.sep, ".").replace(".py", "")
|
||||
try:
|
||||
spec = importlib.util.spec_from_file_location(module_name, module_path)
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(mod)
|
||||
except Exception as e:
|
||||
logger.warning(f"No se pudo importar {module_path}: {e}")
|
||||
|
||||
# Importar todos los models dentro de api/v1/modules y api/v1/modules/uploads
|
||||
modules_dir = os.path.join(BASE_DIR, "api", "v1", "modules")
|
||||
|
||||
424
backend/alembic/versions/03b786378f94_pedimentos.py
Normal file
424
backend/alembic/versions/03b786378f94_pedimentos.py
Normal file
@@ -0,0 +1,424 @@
|
||||
"""Pedimentos
|
||||
|
||||
Revision ID: 03b786378f94
|
||||
Revises: 7937209f9718
|
||||
Create Date: 2025-11-06 17:07:16.536298
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '03b786378f94'
|
||||
down_revision: Union[str, Sequence[str], None] = '54f2046774d0'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('pedimentos',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('year', sa.String(length=2), nullable=True),
|
||||
sa.Column('customs_office', sa.String(length=2), nullable=True),
|
||||
sa.Column('license', sa.String(length=4), nullable=True),
|
||||
sa.Column('pedimento_number', sa.String(length=7), nullable=True),
|
||||
sa.Column('client_id', sa.Integer(), nullable=True),
|
||||
sa.Column('operation_type', sa.Integer(), nullable=True),
|
||||
sa.Column('pedimento_type', sa.Integer(), nullable=True),
|
||||
sa.Column('pedimento_key', sa.String(length=2), nullable=True),
|
||||
sa.Column('regime', sa.String(length=3), nullable=True),
|
||||
sa.Column('status', sa.String(length=30), nullable=True),
|
||||
sa.Column('usd_value', sa.Numeric(precision=17, scale=6), nullable=True),
|
||||
sa.Column('paid_price', sa.Numeric(precision=17, scale=6), nullable=True),
|
||||
sa.Column('gross_weight', sa.Numeric(precision=19, scale=3), nullable=True),
|
||||
sa.Column('exchange_rate', sa.Numeric(precision=9, scale=5), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimentos_pkey'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index('idx_pedimentos_client_id', 'pedimentos', ['client_id'], unique=False, schema='a76')
|
||||
op.create_index('idx_pedimentos_created_at', 'pedimentos', ['created_at'], unique=False, schema='a76')
|
||||
op.create_index('idx_pedimentos_status', 'pedimentos', ['status'], unique=False, schema='a76')
|
||||
op.create_index(op.f('ix_a76_pedimentos_tenant_id'), 'pedimentos', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_config_additional',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('add_po_identifier', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('do_not_exempt_norms_complement_x', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('manual_pedimento_year', sa.String(length=2), nullable=True),
|
||||
sa.Column('enable_import_invoice_recipient', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('send_502_validation_file_for_consolidated', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('add_remove_norms', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_config_additional', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_config_additional_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_config_additional_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_pedimento_config_additional_tenant_id'), 'pedimento_config_additional', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_config_calculations',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('dta_type', sa.String(length=1), nullable=True),
|
||||
sa.Column('dta_operation', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('dta_vehicle_count', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('dta_mixed_rate_8permil', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('pays_vat', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('pays_prevalidation', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('include_sagar_certificate_fee', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('fixed_vehicle_dta_fee', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('additional_fixed_fee', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('additional_fixed_fee_payment_method', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_config_calculations', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_config_calculations_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_config_calculations_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_pedimento_config_calculations_tenant_id'), 'pedimento_config_calculations', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_config_parameters',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('is_embassy', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('embassy_dta', sa.Numeric(precision=11, scale=2), nullable=True),
|
||||
sa.Column('rule_3121_section_ii', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('use_previous_tariff', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('use_payment_date_fi', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('add_state_supplier_record_505', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('customs_value_calculation', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('two_decimals_unit_value', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('customs_value_per_item', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('is_national_supplier', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('is_consolidated', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_config_parameters', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_config_parameters_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_config_parameters_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_pedimento_config_parameters_tenant_id'), 'pedimento_config_parameters', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_config_surcharges',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('surcharge_igi', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('surcharge_dta', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('surcharge_vat', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('surcharge_isan', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('surcharge_ieps', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('surcharge_cc', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_config_surcharges', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_config_surcharges_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_config_surcharges_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_pedimento_config_surcharges_tenant_id'), 'pedimento_config_surcharges', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_config_update_rectification',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('update_vat', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('update_advalorem', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('update_cc', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('update_ieps', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('calculate_surcharge', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_config_update_rectification', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_config_update_rectification_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_config_update_rectification_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_pedimento_config_update_rectification_tenant_id'), 'pedimento_config_update_rectification', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_config_updates',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('update_vat', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('update_advalorem', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('update_cc', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('update_ieps', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_config_updates', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_config_updates_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_config_updates_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_pedimento_config_updates_tenant_id'), 'pedimento_config_updates', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_customs_offices',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('dispatch_customs', sa.String(length=3), nullable=True),
|
||||
sa.Column('entry_exit_customs', sa.String(length=3), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_customs_offices', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_customs_offices_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_customs_offices_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_pedimento_customs_offices_tenant_id'), 'pedimento_customs_offices', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_dates',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('entry_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('pedimento_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('payment_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('rectification_payment_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('extraction_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('submission_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('eucan_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('original_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('start_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('end_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('capture_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('capture_time', sa.Time(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_dates', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_dates_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_dates_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index('idx_pedimento_dates_pedimento_id', 'pedimento_dates', ['pedimento_id'], unique=False, schema='a76')
|
||||
op.create_index(op.f('ix_a76_pedimento_dates_tenant_id'), 'pedimento_dates', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_decrementables',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('freight', sa.Numeric(precision=13, scale=2), nullable=True),
|
||||
sa.Column('insurance', sa.Numeric(precision=13, scale=2), nullable=True),
|
||||
sa.Column('loading', sa.Numeric(precision=13, scale=2), nullable=True),
|
||||
sa.Column('unloading', sa.Numeric(precision=13, scale=2), nullable=True),
|
||||
sa.Column('others', sa.Numeric(precision=13, scale=2), nullable=True),
|
||||
sa.Column('currency', sa.String(length=3), nullable=True),
|
||||
sa.Column('currency_factor', sa.Numeric(precision=15, scale=8), nullable=True),
|
||||
sa.Column('not_affect_usd_value', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('not_affect_customs_value', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_decrementables', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_decrementables_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_decrementables_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_pedimento_decrementables_tenant_id'), 'pedimento_decrementables', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_incrementables',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('insured_value', sa.Numeric(precision=13, scale=2), nullable=True),
|
||||
sa.Column('freight', sa.Numeric(precision=13, scale=2), nullable=True),
|
||||
sa.Column('insurance', sa.Numeric(precision=13, scale=2), nullable=True),
|
||||
sa.Column('packaging', sa.Numeric(precision=13, scale=2), nullable=True),
|
||||
sa.Column('others', sa.Numeric(precision=13, scale=3), nullable=True),
|
||||
sa.Column('deductibles', sa.Numeric(precision=13, scale=3), nullable=True),
|
||||
sa.Column('currency', sa.String(length=3), nullable=True),
|
||||
sa.Column('currency_factor', sa.Numeric(precision=15, scale=8), nullable=True),
|
||||
sa.Column('not_affect_usd_value', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('not_affect_customs_value', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_incrementables', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_incrementables_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_incrementables_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_pedimento_incrementables_tenant_id'), 'pedimento_incrementables', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_indexes',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('update_factor_type', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('update_factor', sa.Numeric(precision=7, scale=4), nullable=True),
|
||||
sa.Column('manual_update_factor', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_indexes', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_indexes_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_indexes_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_pedimento_indexes_tenant_id'), 'pedimento_indexes', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_payments',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('acknowledgment', sa.String(length=20), nullable=True),
|
||||
sa.Column('operation_number', sa.String(length=14), nullable=True),
|
||||
sa.Column('bank_code', sa.Integer(), nullable=True),
|
||||
sa.Column('cashier', sa.String(length=2), nullable=True),
|
||||
sa.Column('date', sa.Date(), nullable=True),
|
||||
sa.Column('time', sa.Time(), nullable=True),
|
||||
sa.Column('shift', sa.String(length=1), nullable=True),
|
||||
sa.Column('total_cash_paid', sa.Integer(), nullable=True),
|
||||
sa.Column('total_contributions', sa.Integer(), nullable=True),
|
||||
sa.Column('counter_payment', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('pece_code', sa.String(length=5), nullable=True),
|
||||
sa.Column('payment_id', sa.Integer(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_payments', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_payments_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_payments_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index('idx_pedimento_payments_pedimento_id', 'pedimento_payments', ['pedimento_id'], unique=False, schema='a76')
|
||||
op.create_index(op.f('ix_a76_pedimento_payments_tenant_id'), 'pedimento_payments', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_rectification_destination',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('destination_pedimento_year', sa.String(length=2), nullable=True),
|
||||
sa.Column('destination_customs_office', sa.String(length=3), nullable=True),
|
||||
sa.Column('destination_license', sa.String(length=4), nullable=True),
|
||||
sa.Column('destination_pedimento_number', sa.String(length=7), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_rectification_destination', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_rectification_destination_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_rectification_destination_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_pedimento_rectification_destination_tenant_id'), 'pedimento_rectification_destination', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_rectification_origin',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('original_pedimento_year', sa.String(length=2), nullable=True),
|
||||
sa.Column('original_customs_office', sa.String(length=3), nullable=True),
|
||||
sa.Column('original_license', sa.String(length=4), nullable=True),
|
||||
sa.Column('original_pedimento_number', sa.String(length=7), nullable=True),
|
||||
sa.Column('original_pedimento_key', sa.String(length=2), nullable=True),
|
||||
sa.Column('original_payment_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('total_cash', sa.Integer(), nullable=True),
|
||||
sa.Column('total_others', sa.Integer(), nullable=True),
|
||||
sa.Column('reason', sa.String(length=255), nullable=True),
|
||||
sa.Column('charge_to_client', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('use_original_payment_date_for_interest_calc', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('manual_calculation', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('original_pedimento_norms', sa.SmallInteger(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_rectification_origin', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_rectification_origin_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_rectification_origin_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_pedimento_rectification_origin_tenant_id'), 'pedimento_rectification_origin', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_transport_means',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('destination', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('entry_exit', sa.String(length=2), nullable=True),
|
||||
sa.Column('arrival', sa.String(length=2), nullable=True),
|
||||
sa.Column('departure', sa.String(length=2), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_transport_means', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_transport_means_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_transport_means_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_pedimento_transport_means_tenant_id'), 'pedimento_transport_means', ['tenant_id'], unique=False, schema='a76')
|
||||
op.create_table('pedimento_validation',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('pedimento_id', sa.Integer(), nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=False),
|
||||
sa.Column('validator', sa.String(length=3), nullable=True),
|
||||
sa.Column('validation_ack', sa.String(length=8), nullable=True),
|
||||
sa.Column('pre_ack', sa.String(length=8), nullable=True),
|
||||
sa.Column('line_signature', sa.String(length=50), nullable=True),
|
||||
sa.Column('electronic_signature', sa.String(length=999), nullable=True),
|
||||
sa.Column('certificate_number', sa.String(length=99), nullable=True),
|
||||
sa.Column('validator_id', sa.Integer(), nullable=True),
|
||||
sa.Column('responsible_id', sa.Integer(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], name='fk_pedimento_validation', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id', name='pedimento_validation_pkey'),
|
||||
sa.UniqueConstraint('pedimento_id', name='pedimento_validation_pedimento_id_key'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_pedimento_validation_tenant_id'), 'pedimento_validation', ['tenant_id'], unique=False, schema='a76')
|
||||
op.drop_constraint(op.f('fk_regimenped'), 'code_pedimento_regimens', type_='foreignkey')
|
||||
op.drop_constraint(op.f('fk_codeped'), 'code_pedimento_regimens', type_='foreignkey')
|
||||
op.create_foreign_key('fk_codeped', 'code_pedimento_regimens', 'pedimento_codes', ['pedimento_code'], ['code'], source_schema='public', referent_schema='public')
|
||||
op.create_foreign_key('fk_regimenped', 'code_pedimento_regimens', 'pedimento_regimens', ['regimen_code'], ['code'], source_schema='public', referent_schema='public')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint('fk_regimenped', 'code_pedimento_regimens', schema='public', type_='foreignkey')
|
||||
op.drop_constraint('fk_codeped', 'code_pedimento_regimens', schema='public', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('fk_codeped'), 'code_pedimento_regimens', 'pedimento_codes', ['pedimento_code'], ['code'])
|
||||
op.create_foreign_key(op.f('fk_regimenped'), 'code_pedimento_regimens', 'pedimento_regimens', ['regimen_code'], ['code'])
|
||||
op.drop_index(op.f('ix_a76_pedimento_validation_tenant_id'), table_name='pedimento_validation', schema='a76')
|
||||
op.drop_table('pedimento_validation', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_transport_means_tenant_id'), table_name='pedimento_transport_means', schema='a76')
|
||||
op.drop_table('pedimento_transport_means', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_rectification_origin_tenant_id'), table_name='pedimento_rectification_origin', schema='a76')
|
||||
op.drop_table('pedimento_rectification_origin', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_rectification_destination_tenant_id'), table_name='pedimento_rectification_destination', schema='a76')
|
||||
op.drop_table('pedimento_rectification_destination', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_payments_tenant_id'), table_name='pedimento_payments', schema='a76')
|
||||
op.drop_index('idx_pedimento_payments_pedimento_id', table_name='pedimento_payments', schema='a76')
|
||||
op.drop_table('pedimento_payments', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_indexes_tenant_id'), table_name='pedimento_indexes', schema='a76')
|
||||
op.drop_table('pedimento_indexes', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_incrementables_tenant_id'), table_name='pedimento_incrementables', schema='a76')
|
||||
op.drop_table('pedimento_incrementables', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_decrementables_tenant_id'), table_name='pedimento_decrementables', schema='a76')
|
||||
op.drop_table('pedimento_decrementables', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_dates_tenant_id'), table_name='pedimento_dates', schema='a76')
|
||||
op.drop_index('idx_pedimento_dates_pedimento_id', table_name='pedimento_dates', schema='a76')
|
||||
op.drop_table('pedimento_dates', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_customs_offices_tenant_id'), table_name='pedimento_customs_offices', schema='a76')
|
||||
op.drop_table('pedimento_customs_offices', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_config_updates_tenant_id'), table_name='pedimento_config_updates', schema='a76')
|
||||
op.drop_table('pedimento_config_updates', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_config_update_rectification_tenant_id'), table_name='pedimento_config_update_rectification', schema='a76')
|
||||
op.drop_table('pedimento_config_update_rectification', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_config_surcharges_tenant_id'), table_name='pedimento_config_surcharges', schema='a76')
|
||||
op.drop_table('pedimento_config_surcharges', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_config_parameters_tenant_id'), table_name='pedimento_config_parameters', schema='a76')
|
||||
op.drop_table('pedimento_config_parameters', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_config_calculations_tenant_id'), table_name='pedimento_config_calculations', schema='a76')
|
||||
op.drop_table('pedimento_config_calculations', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimento_config_additional_tenant_id'), table_name='pedimento_config_additional', schema='a76')
|
||||
op.drop_table('pedimento_config_additional', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_pedimentos_tenant_id'), table_name='pedimentos', schema='a76')
|
||||
op.drop_index('idx_pedimentos_status', table_name='pedimentos', schema='a76')
|
||||
op.drop_index('idx_pedimentos_created_at', table_name='pedimentos', schema='a76')
|
||||
op.drop_index('idx_pedimentos_client_id', table_name='pedimentos', schema='a76')
|
||||
op.drop_table('pedimentos', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_licenses_tenant_id'), table_name='licenses', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_licenses_id'), table_name='licenses', schema='a76')
|
||||
op.drop_table('licenses', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_license_usage_tenant_id'), table_name='license_usage', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_license_usage_id'), table_name='license_usage', schema='a76')
|
||||
op.drop_table('license_usage', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_tenants_slug'), table_name='tenants', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_tenants_name'), table_name='tenants', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_tenants_id'), table_name='tenants', schema='a76')
|
||||
op.drop_table('tenants', schema='a76')
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,195 @@
|
||||
"""Create new A76 tables only - company, clients, parts, classes
|
||||
|
||||
Revision ID: 54f2046774d0
|
||||
Revises: 7937209f9718
|
||||
Create Date: 2025-11-06 03:38:27.848630
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '54f2046774d0'
|
||||
down_revision: Union[str, Sequence[str], None] = '7937209f9718'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema - Create only new A76 tables."""
|
||||
|
||||
# Create new A76 tables only (skip existing tenants, licenses, license_usage)
|
||||
op.create_table('client_provider',
|
||||
sa.Column('client_id', sa.String(length=8), nullable=False),
|
||||
sa.Column('type_nat_foreign', sa.String(length=1), nullable=True),
|
||||
sa.Column('name', sa.String(length=256), nullable=True),
|
||||
sa.Column('short_name', sa.String(length=10), nullable=True),
|
||||
sa.Column('rfc', sa.String(length=30), nullable=True),
|
||||
sa.Column('curp', sa.String(length=19), nullable=True),
|
||||
sa.Column('client_or_provider', sa.String(length=1), nullable=True),
|
||||
sa.Column('linking', sa.String(length=1), nullable=True),
|
||||
sa.Column('transform_subassembly', sa.String(length=1), nullable=True),
|
||||
sa.Column('extra_information', sa.String(length=399), nullable=True),
|
||||
sa.Column('web_key', sa.String(length=40), nullable=True),
|
||||
sa.Column('responsible', sa.String(length=80), nullable=True),
|
||||
sa.Column('position', sa.String(length=30), nullable=True),
|
||||
sa.Column('incoterm', sa.String(length=19), nullable=True),
|
||||
sa.Column('is_national_provider', sa.String(length=2), nullable=True),
|
||||
sa.Column('enabled_disabled', sa.SmallInteger(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('client_id'),
|
||||
schema='a76'
|
||||
)
|
||||
|
||||
op.create_table('gcompany',
|
||||
sa.Column('id', sa.String(length=3), nullable=False),
|
||||
sa.Column('consecutive', sa.Boolean(), nullable=False),
|
||||
sa.Column('name', sa.String(length=255), nullable=True),
|
||||
sa.Column('rfc', sa.String(length=30), nullable=True),
|
||||
sa.Column('main_activity', sa.String(length=255), nullable=True),
|
||||
sa.Column('program', sa.String(length=10), nullable=True),
|
||||
sa.Column('program_number', sa.String(length=40), nullable=True),
|
||||
sa.Column('prosec', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('prosec_authorization', sa.String(length=20), nullable=True),
|
||||
sa.Column('manufacturer_id', sa.String(length=25), nullable=True),
|
||||
sa.Column('broker_company', sa.String(length=10), nullable=True),
|
||||
sa.Column('responsible', sa.String(length=80), nullable=True),
|
||||
sa.Column('responsible_name', sa.String(length=20), nullable=True),
|
||||
sa.Column('responsible_last_name', sa.String(length=20), nullable=True),
|
||||
sa.Column('responsible_mother_last_name', sa.String(length=20), nullable=True),
|
||||
sa.Column('responsible_rfc', sa.String(length=30), nullable=True),
|
||||
sa.Column('position', sa.String(length=30), nullable=True),
|
||||
sa.Column('logo', sa.String(length=255), nullable=True),
|
||||
sa.Column('has_express_line', sa.Boolean(), nullable=True),
|
||||
sa.Column('order_format_type', sa.String(length=19), nullable=True),
|
||||
sa.Column('previous_code', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('is_service_company', sa.Boolean(), nullable=True),
|
||||
sa.Column('client_name', sa.String(length=300), nullable=True),
|
||||
sa.Column('subassembly_mode', sa.String(length=7), nullable=True),
|
||||
sa.Column('curp', sa.String(length=19), nullable=True),
|
||||
sa.Column('inter_db_name', sa.String(length=100), nullable=True),
|
||||
sa.Column('ctpat_svi', sa.String(length=100), nullable=True),
|
||||
sa.Column('trusted_exporter_number', sa.String(length=50), nullable=True),
|
||||
sa.Column('prevalidator_key', sa.String(length=20), nullable=True),
|
||||
sa.Column('seventh_amendment', sa.Boolean(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('consecutive'),
|
||||
schema='a76'
|
||||
)
|
||||
|
||||
op.create_table('classes',
|
||||
sa.Column('client_key', sa.Integer(), nullable=False),
|
||||
sa.Column('class_code', sa.String(length=8), nullable=False),
|
||||
sa.Column('description_spanish', sa.String(length=500), nullable=True),
|
||||
sa.Column('description_english', sa.String(length=500), nullable=True),
|
||||
sa.Column('material_key', sa.String(length=10), nullable=True),
|
||||
sa.Column('unit_of_measure', sa.String(length=5), nullable=True),
|
||||
sa.Column('fraction', sa.String(length=10), nullable=True),
|
||||
sa.Column('us_fraction', sa.String(length=16), nullable=True),
|
||||
sa.Column('sub_key', sa.String(length=5), nullable=True),
|
||||
sa.Column('physical_review', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('iva_exempt_fraction', sa.String(length=4), nullable=True),
|
||||
sa.ForeignKeyConstraint(['material_key'], ['public.material_types.key'], ),
|
||||
sa.PrimaryKeyConstraint('client_key', 'class_code'),
|
||||
schema='a76'
|
||||
)
|
||||
|
||||
op.create_table('parts',
|
||||
sa.Column('client_key', sa.Integer(), nullable=False),
|
||||
sa.Column('part_number', sa.String(length=49), nullable=False),
|
||||
sa.Column('fraction', sa.String(length=10), nullable=True),
|
||||
sa.Column('description_spanish', sa.String(length=500), nullable=True),
|
||||
sa.Column('description_english', sa.String(length=500), nullable=True),
|
||||
sa.Column('part_class', sa.String(length=8), nullable=True),
|
||||
sa.Column('unit_of_measure', sa.String(length=5), nullable=True),
|
||||
sa.Column('commercial_part_number', sa.String(length=70), nullable=True),
|
||||
sa.Column('country_of_origin', sa.String(length=3), nullable=True),
|
||||
sa.Column('unit_cost', sa.Numeric(precision=23, scale=8), nullable=True),
|
||||
sa.Column('currency_type', sa.String(length=2), nullable=True),
|
||||
sa.Column('currency_key', sa.String(length=3), nullable=True),
|
||||
sa.Column('unit_weight', sa.Numeric(precision=19, scale=8), nullable=True),
|
||||
sa.Column('weight_type', sa.String(length=6), nullable=True),
|
||||
sa.Column('us_fraction', sa.String(length=16), nullable=True),
|
||||
sa.Column('fda_key', sa.String(length=20), nullable=True),
|
||||
sa.Column('fcc_key', sa.String(length=30), nullable=True),
|
||||
sa.Column('license_code', sa.String(length=3), nullable=True),
|
||||
sa.Column('eccn', sa.String(length=20), nullable=True),
|
||||
sa.Column('export_code', sa.String(length=2), nullable=True),
|
||||
sa.Column('exclusion_symbol', sa.String(length=19), nullable=True),
|
||||
sa.Column('supplier', sa.String(length=14), nullable=True),
|
||||
sa.Column('alternate_unit_measure', sa.String(length=14), nullable=True),
|
||||
sa.Column('added_value', sa.Numeric(precision=23, scale=8), nullable=True),
|
||||
sa.Column('enabled_disabled', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('creation_date', sa.Integer(), nullable=True),
|
||||
sa.Column('modification_date', sa.Integer(), nullable=True),
|
||||
sa.Column('modification_date_iso', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('part_photo', sa.String(length=255), nullable=True),
|
||||
sa.ForeignKeyConstraint(['country_of_origin'], ['public.countries.m3_key'], ),
|
||||
sa.ForeignKeyConstraint(['currency_key'], ['public.currency_types.code'], ),
|
||||
sa.PrimaryKeyConstraint('client_key', 'part_number'),
|
||||
schema='a76'
|
||||
)
|
||||
|
||||
# Create dependent tables after main tables
|
||||
op.create_table('gclient_provider_address',
|
||||
sa.Column('client_id', sa.String(length=8), nullable=False),
|
||||
sa.Column('municipality', sa.String(length=150), nullable=True),
|
||||
sa.Column('streets', sa.String(length=100), nullable=True),
|
||||
sa.Column('neighborhood', sa.String(length=40), nullable=True),
|
||||
sa.Column('interior_number', sa.String(length=20), nullable=True),
|
||||
sa.Column('exterior_number', sa.String(length=20), nullable=True),
|
||||
sa.Column('postal_code', sa.String(length=15), nullable=True),
|
||||
sa.Column('city', sa.String(length=30), nullable=True),
|
||||
sa.Column('state', sa.String(length=30), nullable=True),
|
||||
sa.Column('country', sa.String(length=3), nullable=True),
|
||||
sa.Column('phone', sa.String(length=30), nullable=True),
|
||||
sa.Column('fax_number', sa.String(length=30), nullable=True),
|
||||
sa.Column('email', sa.String(length=100), nullable=True),
|
||||
sa.Column('contact', sa.String(length=50), nullable=True),
|
||||
sa.Column('reference', sa.String(length=250), nullable=True),
|
||||
sa.ForeignKeyConstraint(['client_id'], ['a76.client_provider.client_id'], ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('client_id'),
|
||||
schema='a76'
|
||||
)
|
||||
|
||||
op.create_table('gclient_provider_programs',
|
||||
sa.Column('client_id', sa.String(length=8), nullable=False),
|
||||
sa.Column('program', sa.String(length=7), nullable=True),
|
||||
sa.Column('program_number', sa.String(length=40), nullable=True),
|
||||
sa.Column('prosec', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('prosec_authorization', sa.String(length=20), nullable=True),
|
||||
sa.Column('secon_auth_date', sa.Integer(), nullable=True),
|
||||
sa.Column('manufacturer_id', sa.String(length=25), nullable=True),
|
||||
sa.Column('tax_id', sa.String(length=30), nullable=True),
|
||||
sa.Column('broker', sa.String(length=6), nullable=True),
|
||||
sa.Column('import_broker', sa.String(length=6), nullable=True),
|
||||
sa.Column('transfer_key', sa.String(length=8), nullable=True),
|
||||
sa.Column('secon_authorization', sa.String(length=20), nullable=True),
|
||||
sa.Column('applied_proportion', sa.Numeric(precision=7, scale=2), nullable=True),
|
||||
sa.Column('is_certified_company', sa.String(length=1), nullable=True),
|
||||
sa.Column('certified_company_registry', sa.String(length=40), nullable=True),
|
||||
sa.Column('donation_auth_number', sa.String(length=50), nullable=True),
|
||||
sa.Column('ctpat_svi', sa.String(length=100), nullable=True),
|
||||
sa.Column('tax_registry_number', sa.String(length=40), nullable=True),
|
||||
sa.Column('subassembly_service', sa.SmallInteger(), nullable=True),
|
||||
sa.Column('autse_dates', sa.Integer(), nullable=True),
|
||||
sa.Column('autse_number', sa.String(length=300), nullable=True),
|
||||
sa.ForeignKeyConstraint(['client_id'], ['a76.client_provider.client_id'], ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('client_id'),
|
||||
schema='a76'
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema - Drop only new A76 tables."""
|
||||
# Drop tables in reverse dependency order
|
||||
op.drop_table('gclient_provider_programs', schema='a76')
|
||||
op.drop_table('gclient_provider_address', schema='a76')
|
||||
op.drop_table('parts', schema='a76')
|
||||
op.drop_table('classes', schema='a76')
|
||||
op.drop_table('gcompany', schema='a76')
|
||||
op.drop_table('client_provider', schema='a76')
|
||||
6
backend/api/v1/modules/a76/classes/__init__.py
Normal file
6
backend/api/v1/modules/a76/classes/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
"""
|
||||
Módulo de Class
|
||||
"""
|
||||
from .routes import router
|
||||
|
||||
__all__ = ["router"]
|
||||
97
backend/api/v1/modules/a76/classes/dto.py
Normal file
97
backend/api/v1/modules/a76/classes/dto.py
Normal file
@@ -0,0 +1,97 @@
|
||||
"""
|
||||
DTOs (Data Transfer Objects) para módulo de clases SCAII y SCAF
|
||||
Reemplaza schemas.py siguiendo enfoque DDD y estilo NestJS
|
||||
"""
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class ClassCreateDTO(BaseModel):
|
||||
"""DTO para crear una clase"""
|
||||
client_key: int = Field(..., description="Client key")
|
||||
class_code: str = Field(..., max_length=8, description="Class code")
|
||||
description_spanish: Optional[str] = Field(None, max_length=500, description="Description in Spanish")
|
||||
description_english: Optional[str] = Field(None, max_length=500, description="Description in English")
|
||||
material_key: Optional[str] = Field(None, max_length=10, description="Material key (homologated TIPOMAT/TIPOMATEQUIPO)")
|
||||
unit_of_measure: Optional[str] = Field(None, max_length=5, description="Unit of measure (homologated UNIMEDIDA)")
|
||||
fraction: Optional[str] = Field(None, max_length=10, description="Mexican tariff fraction")
|
||||
us_fraction: Optional[str] = Field(None, max_length=16, description="US tariff fraction")
|
||||
sub_key: Optional[str] = Field(None, max_length=5, description="Sub classification key")
|
||||
physical_review: Optional[int] = Field(None, description="Physical review indicator")
|
||||
iva_exempt_fraction: Optional[str] = Field(None, max_length=4, description="IVA exempt fraction")
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ClassUpdateDTO(BaseModel):
|
||||
"""DTO para actualizar una clase"""
|
||||
description_spanish: Optional[str] = Field(None, max_length=500, description="Description in Spanish")
|
||||
description_english: Optional[str] = Field(None, max_length=500, description="Description in English")
|
||||
material_key: Optional[str] = Field(None, max_length=10, description="Material key (homologated TIPOMAT/TIPOMATEQUIPO)")
|
||||
unit_of_measure: Optional[str] = Field(None, max_length=5, description="Unit of measure (homologated UNIMEDIDA)")
|
||||
fraction: Optional[str] = Field(None, max_length=10, description="Mexican tariff fraction")
|
||||
us_fraction: Optional[str] = Field(None, max_length=16, description="US tariff fraction")
|
||||
sub_key: Optional[str] = Field(None, max_length=5, description="Sub classification key")
|
||||
physical_review: Optional[int] = Field(None, description="Physical review indicator")
|
||||
iva_exempt_fraction: Optional[str] = Field(None, max_length=4, description="IVA exempt fraction")
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ClassResponseDTO(BaseModel):
|
||||
"""DTO para respuesta de clase"""
|
||||
client_key: int
|
||||
class_code: str
|
||||
description_spanish: Optional[str] = None
|
||||
description_english: Optional[str] = None
|
||||
material_key: Optional[str] = None
|
||||
unit_of_measure: Optional[str] = None
|
||||
fraction: Optional[str] = None
|
||||
us_fraction: Optional[str] = None
|
||||
sub_key: Optional[str] = None
|
||||
physical_review: Optional[int] = None
|
||||
iva_exempt_fraction: Optional[str] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ClassBasicDTO(BaseModel):
|
||||
"""DTO para información básica de clase"""
|
||||
client_key: int
|
||||
class_code: str
|
||||
description_spanish: Optional[str] = None
|
||||
description_english: Optional[str] = None
|
||||
material_key: Optional[str] = None
|
||||
fraction: Optional[str] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ClassListDTO(BaseModel):
|
||||
"""DTO para lista de clases"""
|
||||
classes: list[ClassBasicDTO]
|
||||
total: int
|
||||
page: int
|
||||
size: int
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ClassSearchDTO(BaseModel):
|
||||
"""DTO para búsqueda de clases"""
|
||||
client_key: Optional[int] = Field(None, description="Filter by client key")
|
||||
class_code: Optional[str] = Field(None, description="Search by class code")
|
||||
description: Optional[str] = Field(None, description="Search in descriptions")
|
||||
material_key: Optional[str] = Field(None, description="Filter by material key")
|
||||
fraction: Optional[str] = Field(None, description="Filter by tariff fraction")
|
||||
physical_review: Optional[int] = Field(None, description="Filter by physical review indicator")
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
61
backend/api/v1/modules/a76/classes/models.py
Normal file
61
backend/api/v1/modules/a76/classes/models.py
Normal file
@@ -0,0 +1,61 @@
|
||||
"""
|
||||
Modelos ORM para gestión de clases SCAII y SCAF
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text, Numeric, SmallInteger, ForeignKey
|
||||
from sqlalchemy.sql import func
|
||||
from sqlalchemy.orm import relationship
|
||||
from core.database import Base
|
||||
import enum
|
||||
|
||||
# Importar modelos relacionados para type hints y relationships
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from api.v1.modules.a76.parts.models import Part
|
||||
from api.v1.modules.public.reference_data.material_types.models import MaterialType
|
||||
|
||||
|
||||
class Class(Base):
|
||||
"""
|
||||
Modelo para la tabla GClases - Información de clases en sistemas SCAII y SCAF
|
||||
"""
|
||||
__tablename__ = "classes"
|
||||
__table_args__ = {"schema": "a76"}
|
||||
|
||||
# Primary key compuesta
|
||||
client_key = Column(Integer, primary_key=True, nullable=False)
|
||||
class_code = Column(String(8), primary_key=True, nullable=False)
|
||||
|
||||
# Basic information
|
||||
description_spanish = Column(String(500), nullable=True)
|
||||
description_english = Column(String(500), nullable=True)
|
||||
|
||||
# Material and measurement
|
||||
material_key = Column(String(10), ForeignKey('public.material_types.key'), nullable=True) # CLAVEMAT - homologated from TIPOMAT/TIPOMATEQUIPO
|
||||
unit_of_measure = Column(String(5), nullable=True) # UNIMED - homologated from UNIMEDIDA
|
||||
|
||||
# Tariff fractions
|
||||
fraction = Column(String(10), nullable=True) # Mexican tariff fraction
|
||||
us_fraction = Column(String(16), nullable=True) # FRACCIONAME - US tariff fraction
|
||||
|
||||
# Additional classification
|
||||
sub_key = Column(String(5), nullable=True) # CLAVESUB
|
||||
physical_review = Column(SmallInteger, nullable=True) # REVFISICA
|
||||
iva_exempt_fraction = Column(String(4), nullable=True) # FRACCIONEXENTAIVA
|
||||
|
||||
# Relationships
|
||||
material_type = relationship("MaterialType", foreign_keys=[material_key])
|
||||
|
||||
# Inverse relationship with GParts that have this class
|
||||
parts = relationship(
|
||||
"Part",
|
||||
primaryjoin="and_(Class.client_key == Part.client_key, Class.class_code == Part.part_class)",
|
||||
foreign_keys="[Part.client_key, Part.part_class]",
|
||||
viewonly=True,
|
||||
back_populates="part_class_info"
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Class(client_key={self.client_key}, class_code='{self.class_code}', description='{self.description_spanish}')>"
|
||||
|
||||
|
||||
261
backend/api/v1/modules/a76/classes/routes.py
Normal file
261
backend/api/v1/modules/a76/classes/routes.py
Normal file
@@ -0,0 +1,261 @@
|
||||
"""
|
||||
Endpoints API para gestión de clases SCAII y SCAF
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List, Optional
|
||||
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, has_role
|
||||
from .service import ClassService
|
||||
from .dto import (
|
||||
ClassCreateDTO,
|
||||
ClassUpdateDTO,
|
||||
ClassResponseDTO,
|
||||
ClassBasicDTO,
|
||||
ClassListDTO,
|
||||
ClassSearchDTO
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/classes", tags=["Classes"])
|
||||
|
||||
|
||||
@router.post("/", response_model=ClassResponseDTO, status_code=status.HTTP_201_CREATED)
|
||||
async def create_class(
|
||||
class_data: ClassCreateDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Create a new class in the system
|
||||
"""
|
||||
service = ClassService(db)
|
||||
return service.create_class(class_data)
|
||||
|
||||
|
||||
@router.get("/", response_model=ClassListDTO)
|
||||
async def list_classes(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum number of records to return"),
|
||||
client_key: Optional[int] = Query(None, description="Filter by client key"),
|
||||
class_code: Optional[str] = Query(None, description="Search by class code"),
|
||||
description: Optional[str] = Query(None, description="Search in descriptions"),
|
||||
material_key: Optional[str] = Query(None, description="Filter by material key"),
|
||||
fraction: Optional[str] = Query(None, description="Filter by tariff fraction"),
|
||||
physical_review: Optional[int] = Query(None, description="Filter by physical review indicator"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
List classes with optional filters and pagination
|
||||
"""
|
||||
service = ClassService(db)
|
||||
search_params = ClassSearchDTO(
|
||||
client_key=client_key,
|
||||
class_code=class_code,
|
||||
description=description,
|
||||
material_key=material_key,
|
||||
fraction=fraction,
|
||||
physical_review=physical_review
|
||||
)
|
||||
return service.list_classes(skip, limit, search_params)
|
||||
|
||||
|
||||
@router.get("/client/{client_key}", response_model=List[ClassBasicDTO])
|
||||
async def get_classes_by_client(
|
||||
client_key: int,
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get all classes for a specific client
|
||||
"""
|
||||
service = ClassService(db)
|
||||
return service.search_by_client(client_key, skip, limit)
|
||||
|
||||
|
||||
@router.get("/search/fraction/{fraction}", response_model=List[ClassBasicDTO])
|
||||
async def search_by_fraction(
|
||||
fraction: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Search classes by tariff fraction
|
||||
"""
|
||||
service = ClassService(db)
|
||||
return service.search_by_fraction(fraction)
|
||||
|
||||
|
||||
@router.get("/search/material/{material_key}", response_model=List[ClassBasicDTO])
|
||||
async def search_by_material(
|
||||
material_key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Search classes by material key
|
||||
"""
|
||||
service = ClassService(db)
|
||||
return service.search_by_material(material_key)
|
||||
|
||||
|
||||
@router.get("/search/unit-measure/{unit_of_measure}", response_model=List[ClassBasicDTO])
|
||||
async def get_classes_by_unit_measure(
|
||||
unit_of_measure: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get classes by unit of measure
|
||||
"""
|
||||
service = ClassService(db)
|
||||
return service.get_classes_by_unit_measure(unit_of_measure)
|
||||
|
||||
|
||||
@router.get("/search/physical-review/{physical_review}", response_model=List[ClassBasicDTO])
|
||||
async def get_classes_by_physical_review(
|
||||
physical_review: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get classes by physical review indicator
|
||||
"""
|
||||
service = ClassService(db)
|
||||
return service.get_classes_by_physical_review(physical_review)
|
||||
|
||||
|
||||
@router.get("/statistics", response_model=dict)
|
||||
async def get_classes_statistics(
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get basic classes statistics
|
||||
"""
|
||||
service = ClassService(db)
|
||||
return service.get_classes_statistics()
|
||||
|
||||
|
||||
@router.get("/{client_key}/{class_code}", response_model=ClassResponseDTO)
|
||||
async def get_class(
|
||||
client_key: int,
|
||||
class_code: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get class by composite key (client_key + class_code)
|
||||
"""
|
||||
service = ClassService(db)
|
||||
class_obj = service.get_class(client_key, class_code)
|
||||
if not class_obj:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Class with client_key '{client_key}' and class_code '{class_code}' not found"
|
||||
)
|
||||
return class_obj
|
||||
|
||||
|
||||
@router.put("/{client_key}/{class_code}", response_model=ClassResponseDTO)
|
||||
async def update_class(
|
||||
client_key: int,
|
||||
class_code: str,
|
||||
class_data: ClassUpdateDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Update class information
|
||||
"""
|
||||
service = ClassService(db)
|
||||
class_obj = service.update_class(client_key, class_code, class_data)
|
||||
if not class_obj:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Class with client_key '{client_key}' and class_code '{class_code}' not found"
|
||||
)
|
||||
return class_obj
|
||||
|
||||
|
||||
@router.delete("/{client_key}/{class_code}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_class(
|
||||
client_key: int,
|
||||
class_code: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Delete class from the system
|
||||
|
||||
Note: This will completely remove the class from the system.
|
||||
"""
|
||||
service = ClassService(db)
|
||||
if not service.delete_class(client_key, class_code):
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Class with client_key '{client_key}' and class_code '{class_code}' not found"
|
||||
)
|
||||
|
||||
|
||||
# Endpoints específicos para información detallada
|
||||
@router.get("/{client_key}/{class_code}/basic", response_model=ClassBasicDTO)
|
||||
async def get_class_basic_info(
|
||||
client_key: int,
|
||||
class_code: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get basic information for a class
|
||||
"""
|
||||
service = ClassService(db)
|
||||
class_obj = service.get_class(client_key, class_code)
|
||||
if not class_obj:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Class with client_key '{client_key}' and class_code '{class_code}' not found"
|
||||
)
|
||||
|
||||
return ClassBasicDTO(
|
||||
client_key=class_obj.client_key,
|
||||
class_code=class_obj.class_code,
|
||||
description_spanish=class_obj.description_spanish,
|
||||
description_english=class_obj.description_english,
|
||||
material_key=class_obj.material_key,
|
||||
fraction=class_obj.fraction
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{client_key}/{class_code}/tariff", response_model=dict)
|
||||
async def get_class_tariff_info(
|
||||
client_key: int,
|
||||
class_code: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get tariff information for a class (fractions, IVA exempt, etc.)
|
||||
"""
|
||||
service = ClassService(db)
|
||||
class_obj = service.get_class(client_key, class_code)
|
||||
if not class_obj:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Class with client_key '{client_key}' and class_code '{class_code}' not found"
|
||||
)
|
||||
|
||||
return {
|
||||
"client_key": class_obj.client_key,
|
||||
"class_code": class_obj.class_code,
|
||||
"fraction": class_obj.fraction,
|
||||
"us_fraction": class_obj.us_fraction,
|
||||
"iva_exempt_fraction": class_obj.iva_exempt_fraction,
|
||||
"sub_key": class_obj.sub_key,
|
||||
"physical_review": class_obj.physical_review
|
||||
}
|
||||
|
||||
|
||||
294
backend/api/v1/modules/a76/classes/service.py
Normal file
294
backend/api/v1/modules/a76/classes/service.py
Normal file
@@ -0,0 +1,294 @@
|
||||
"""
|
||||
Capa de servicio para lógica de negocio de clases SCAII y SCAF
|
||||
"""
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy import or_, and_, func
|
||||
from fastapi import HTTPException
|
||||
from typing import List, Optional
|
||||
import logging
|
||||
|
||||
from .models import Class
|
||||
from .dto import (
|
||||
ClassCreateDTO,
|
||||
ClassUpdateDTO,
|
||||
ClassResponseDTO,
|
||||
ClassBasicDTO,
|
||||
ClassListDTO,
|
||||
ClassSearchDTO
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ClassService:
|
||||
"""Servicio para gestión de clases SCAII y SCAF"""
|
||||
|
||||
def __init__(self, db: Session):
|
||||
self.db = db
|
||||
|
||||
def create_class(self, class_data: ClassCreateDTO) -> ClassResponseDTO:
|
||||
"""
|
||||
Crea una nueva clase en el sistema
|
||||
|
||||
Args:
|
||||
class_data: Datos de la clase a crear
|
||||
|
||||
Returns:
|
||||
ClassResponseDTO con información de la clase creada
|
||||
|
||||
Raises:
|
||||
HTTPException: Si la clase ya existe o error en la creación
|
||||
"""
|
||||
try:
|
||||
# Verificar que no exista la clase
|
||||
existing = self.db.query(Class).filter(
|
||||
and_(
|
||||
Class.client_key == class_data.client_key,
|
||||
Class.class_code == class_data.class_code
|
||||
)
|
||||
).first()
|
||||
|
||||
if existing:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Class with client_key '{class_data.client_key}' and class_code '{class_data.class_code}' already exists"
|
||||
)
|
||||
|
||||
# Crear clase
|
||||
db_class = Class(
|
||||
client_key=class_data.client_key,
|
||||
class_code=class_data.class_code,
|
||||
description_spanish=class_data.description_spanish,
|
||||
description_english=class_data.description_english,
|
||||
material_key=class_data.material_key,
|
||||
unit_of_measure=class_data.unit_of_measure,
|
||||
fraction=class_data.fraction,
|
||||
us_fraction=class_data.us_fraction,
|
||||
sub_key=class_data.sub_key,
|
||||
physical_review=class_data.physical_review,
|
||||
iva_exempt_fraction=class_data.iva_exempt_fraction
|
||||
)
|
||||
|
||||
self.db.add(db_class)
|
||||
self.db.commit()
|
||||
self.db.refresh(db_class)
|
||||
|
||||
logger.info(f"Class created: {db_class.client_key}-{db_class.class_code}")
|
||||
|
||||
return ClassResponseDTO.model_validate(db_class)
|
||||
|
||||
except IntegrityError as e:
|
||||
self.db.rollback()
|
||||
logger.error(f"IntegrityError creating class: {str(e)}")
|
||||
raise HTTPException(status_code=400, detail="Class with this client_key and class_code already exists")
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
self.db.rollback()
|
||||
logger.error(f"Error creating class: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Error creating class")
|
||||
|
||||
def get_class(self, client_key: int, class_code: str) -> Optional[ClassResponseDTO]:
|
||||
"""
|
||||
Obtiene una clase por clave compuesta
|
||||
|
||||
Args:
|
||||
client_key: Clave del cliente
|
||||
class_code: Código de clase
|
||||
|
||||
Returns:
|
||||
ClassResponseDTO o None si no existe
|
||||
"""
|
||||
class_obj = self.db.query(Class).filter(
|
||||
and_(
|
||||
Class.client_key == client_key,
|
||||
Class.class_code == class_code
|
||||
)
|
||||
).first()
|
||||
|
||||
if not class_obj:
|
||||
return None
|
||||
return ClassResponseDTO.model_validate(class_obj)
|
||||
|
||||
def list_classes(
|
||||
self,
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
search_params: Optional[ClassSearchDTO] = None
|
||||
) -> ClassListDTO:
|
||||
"""
|
||||
Lista clases con filtros
|
||||
|
||||
Args:
|
||||
skip: Número de registros a omitir
|
||||
limit: Número máximo de registros a retornar
|
||||
search_params: Parámetros de búsqueda
|
||||
|
||||
Returns:
|
||||
ClassListDTO con la lista paginada
|
||||
"""
|
||||
query = self.db.query(Class)
|
||||
|
||||
# Aplicar filtros si se proporcionan
|
||||
if search_params:
|
||||
if search_params.client_key:
|
||||
query = query.filter(Class.client_key == search_params.client_key)
|
||||
|
||||
if search_params.class_code:
|
||||
query = query.filter(Class.class_code.ilike(f"%{search_params.class_code}%"))
|
||||
|
||||
if search_params.description:
|
||||
description_pattern = f"%{search_params.description}%"
|
||||
query = query.filter(
|
||||
or_(
|
||||
Class.description_spanish.ilike(description_pattern),
|
||||
Class.description_english.ilike(description_pattern)
|
||||
)
|
||||
)
|
||||
|
||||
if search_params.material_key:
|
||||
query = query.filter(Class.material_key.ilike(f"%{search_params.material_key}%"))
|
||||
|
||||
if search_params.fraction:
|
||||
query = query.filter(Class.fraction.ilike(f"%{search_params.fraction}%"))
|
||||
|
||||
if search_params.physical_review is not None:
|
||||
query = query.filter(Class.physical_review == search_params.physical_review)
|
||||
|
||||
# Contar total
|
||||
total = query.count()
|
||||
|
||||
# Aplicar paginación
|
||||
classes = query.offset(skip).limit(limit).all()
|
||||
|
||||
# Convertir a DTOs básicos
|
||||
class_dtos = [ClassBasicDTO.model_validate(class_obj) for class_obj in classes]
|
||||
|
||||
return ClassListDTO(
|
||||
classes=class_dtos,
|
||||
total=total,
|
||||
page=(skip // limit) + 1 if limit > 0 else 1,
|
||||
size=len(class_dtos)
|
||||
)
|
||||
|
||||
def update_class(self, client_key: int, class_code: str, class_data: ClassUpdateDTO) -> Optional[ClassResponseDTO]:
|
||||
"""
|
||||
Actualiza una clase
|
||||
|
||||
Args:
|
||||
client_key: Clave del cliente
|
||||
class_code: Código de clase
|
||||
class_data: Datos a actualizar
|
||||
|
||||
Returns:
|
||||
ClassResponseDTO actualizado o None si no existe
|
||||
"""
|
||||
class_obj = self.db.query(Class).filter(
|
||||
and_(
|
||||
Class.client_key == client_key,
|
||||
Class.class_code == class_code
|
||||
)
|
||||
).first()
|
||||
|
||||
if not class_obj:
|
||||
return None
|
||||
|
||||
try:
|
||||
# Actualizar solo campos proporcionados
|
||||
update_data = class_data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(class_obj, field, value)
|
||||
|
||||
self.db.commit()
|
||||
self.db.refresh(class_obj)
|
||||
logger.info(f"Class updated: {client_key}-{class_code}")
|
||||
|
||||
return ClassResponseDTO.model_validate(class_obj)
|
||||
|
||||
except Exception as e:
|
||||
self.db.rollback()
|
||||
logger.error(f"Error updating class {client_key}-{class_code}: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Error updating class")
|
||||
|
||||
def delete_class(self, client_key: int, class_code: str) -> bool:
|
||||
"""
|
||||
Elimina una clase
|
||||
|
||||
Args:
|
||||
client_key: Clave del cliente
|
||||
class_code: Código de clase
|
||||
|
||||
Returns:
|
||||
True si se eliminó, False si no existe
|
||||
"""
|
||||
class_obj = self.db.query(Class).filter(
|
||||
and_(
|
||||
Class.client_key == client_key,
|
||||
Class.class_code == class_code
|
||||
)
|
||||
).first()
|
||||
|
||||
if not class_obj:
|
||||
return False
|
||||
|
||||
try:
|
||||
self.db.delete(class_obj)
|
||||
self.db.commit()
|
||||
logger.info(f"Class deleted: {client_key}-{class_code}")
|
||||
return True
|
||||
except Exception as e:
|
||||
self.db.rollback()
|
||||
logger.error(f"Error deleting class {client_key}-{class_code}: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Error deleting class")
|
||||
|
||||
def search_by_fraction(self, fraction: str) -> List[ClassBasicDTO]:
|
||||
"""Busca clases por fracción arancelaria"""
|
||||
classes = self.db.query(Class).filter(Class.fraction.ilike(f"%{fraction}%")).all()
|
||||
return [ClassBasicDTO.model_validate(class_obj) for class_obj in classes]
|
||||
|
||||
def search_by_client(self, client_key: int, skip: int = 0, limit: int = 100) -> List[ClassBasicDTO]:
|
||||
"""Obtiene todas las clases de un cliente específico"""
|
||||
classes = self.db.query(Class).filter(Class.client_key == client_key).offset(skip).limit(limit).all()
|
||||
return [ClassBasicDTO.model_validate(class_obj) for class_obj in classes]
|
||||
|
||||
def search_by_material(self, material_key: str) -> List[ClassBasicDTO]:
|
||||
"""Busca clases por clave de material"""
|
||||
classes = self.db.query(Class).filter(Class.material_key.ilike(f"%{material_key}%")).all()
|
||||
return [ClassBasicDTO.model_validate(class_obj) for class_obj in classes]
|
||||
|
||||
def get_classes_by_physical_review(self, physical_review: int) -> List[ClassBasicDTO]:
|
||||
"""Obtiene clases por indicador de revisión física"""
|
||||
classes = self.db.query(Class).filter(Class.physical_review == physical_review).all()
|
||||
return [ClassBasicDTO.model_validate(class_obj) for class_obj in classes]
|
||||
|
||||
def get_classes_statistics(self) -> dict:
|
||||
"""Obtiene estadísticas básicas de clases"""
|
||||
total_classes = self.db.query(Class).count()
|
||||
|
||||
# Contar por clientes
|
||||
clients_count = self.db.query(Class.client_key).distinct().count()
|
||||
|
||||
# Contar por revisión física
|
||||
physical_review_stats = {}
|
||||
for i in range(3): # Asumiendo valores 0, 1, 2
|
||||
count = self.db.query(Class).filter(Class.physical_review == i).count()
|
||||
physical_review_stats[f"physical_review_{i}"] = count
|
||||
|
||||
# Contar clases con fracciones
|
||||
with_fraction = self.db.query(Class).filter(Class.fraction.isnot(None)).count()
|
||||
with_us_fraction = self.db.query(Class).filter(Class.us_fraction.isnot(None)).count()
|
||||
|
||||
return {
|
||||
"total_classes": total_classes,
|
||||
"clients_with_classes": clients_count,
|
||||
"classes_with_fraction": with_fraction,
|
||||
"classes_with_us_fraction": with_us_fraction,
|
||||
**physical_review_stats
|
||||
}
|
||||
|
||||
def get_classes_by_unit_measure(self, unit_of_measure: str) -> List[ClassBasicDTO]:
|
||||
"""Obtiene clases por unidad de medida"""
|
||||
classes = self.db.query(Class).filter(Class.unit_of_measure == unit_of_measure).all()
|
||||
return [ClassBasicDTO.model_validate(class_obj) for class_obj in classes]
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
"""
|
||||
Módulo de Client & Provider
|
||||
"""
|
||||
from .routes import router
|
||||
|
||||
__all__ = ["router"]
|
||||
165
backend/api/v1/modules/a76/client_and_provider/dto.py
Normal file
165
backend/api/v1/modules/a76/client_and_provider/dto.py
Normal file
@@ -0,0 +1,165 @@
|
||||
"""
|
||||
DTOs (Data Transfer Objects) para módulo de clientes y proveedores
|
||||
Reemplaza schemas.py siguiendo enfoque DDD y estilo NestJS
|
||||
"""
|
||||
from pydantic import BaseModel, Field, EmailStr
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
|
||||
|
||||
# DTOs para dirección
|
||||
class ClientProviderAddressDTO(BaseModel):
|
||||
"""DTO para dirección de cliente/proveedor"""
|
||||
municipality: Optional[str] = Field(None, max_length=150, description="Municipality")
|
||||
streets: Optional[str] = Field(None, max_length=100, description="Streets")
|
||||
neighborhood: Optional[str] = Field(None, max_length=40, description="Neighborhood")
|
||||
interior_number: Optional[str] = Field(None, max_length=20, description="Interior number")
|
||||
exterior_number: Optional[str] = Field(None, max_length=20, description="Exterior number")
|
||||
postal_code: Optional[str] = Field(None, max_length=15, description="Postal code")
|
||||
city: Optional[str] = Field(None, max_length=30, description="City")
|
||||
state: Optional[str] = Field(None, max_length=30, description="State")
|
||||
country: Optional[str] = Field(None, max_length=3, description="Country code")
|
||||
phone: Optional[str] = Field(None, max_length=30, description="Phone number")
|
||||
fax_number: Optional[str] = Field(None, max_length=30, description="Fax number")
|
||||
email: Optional[str] = Field(None, max_length=100, description="Email address")
|
||||
contact: Optional[str] = Field(None, max_length=50, description="Contact person")
|
||||
reference: Optional[str] = Field(None, max_length=250, description="Reference")
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
# DTOs para programas
|
||||
class ClientProviderProgramsDTO(BaseModel):
|
||||
"""DTO para programas de cliente/proveedor"""
|
||||
program: Optional[str] = Field(None, max_length=7, description="Program")
|
||||
program_number: Optional[str] = Field(None, max_length=40, description="Program number")
|
||||
prosec: Optional[int] = Field(None, description="PROSEC")
|
||||
prosec_authorization: Optional[str] = Field(None, max_length=20, description="PROSEC authorization")
|
||||
secon_auth_date: Optional[int] = Field(None, description="SECON authorization date")
|
||||
manufacturer_id: Optional[str] = Field(None, max_length=25, description="Manufacturer ID")
|
||||
tax_id: Optional[str] = Field(None, max_length=30, description="Tax ID")
|
||||
broker: Optional[str] = Field(None, max_length=6, description="Broker")
|
||||
import_broker: Optional[str] = Field(None, max_length=6, description="Import broker")
|
||||
transfer_key: Optional[str] = Field(None, max_length=8, description="Transfer key")
|
||||
secon_authorization: Optional[str] = Field(None, max_length=20, description="SECON authorization")
|
||||
applied_proportion: Optional[Decimal] = Field(None, description="Applied proportion")
|
||||
is_certified_company: Optional[str] = Field(None, max_length=1, description="Is certified company")
|
||||
certified_company_registry: Optional[str] = Field(None, max_length=40, description="Certified company registry")
|
||||
donation_auth_number: Optional[str] = Field(None, max_length=50, description="Donation authorization number")
|
||||
ctpat_svi: Optional[str] = Field(None, max_length=100, description="CTPAT SVI")
|
||||
tax_registry_number: Optional[str] = Field(None, max_length=40, description="Tax registry number")
|
||||
subassembly_service: Optional[int] = Field(None, description="Subassembly service")
|
||||
autse_dates: Optional[int] = Field(None, description="AUTSE dates")
|
||||
autse_number: Optional[str] = Field(None, max_length=300, description="AUTSE number")
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
# DTOs principales
|
||||
class ClientProviderCreateDTO(BaseModel):
|
||||
"""DTO para crear cliente/proveedor"""
|
||||
client_id: str = Field(..., max_length=8, description="Client ID")
|
||||
type_nat_foreign: Optional[str] = Field(None, max_length=1, description="Type national/foreign")
|
||||
name: Optional[str] = Field(None, max_length=256, description="Name")
|
||||
short_name: Optional[str] = Field(None, max_length=10, description="Short name")
|
||||
rfc: Optional[str] = Field(None, max_length=30, description="RFC")
|
||||
curp: Optional[str] = Field(None, max_length=19, description="CURP")
|
||||
client_or_provider: Optional[str] = Field(None, max_length=1, description="Client or provider")
|
||||
linking: Optional[str] = Field(None, max_length=1, description="Linking")
|
||||
transform_subassembly: Optional[str] = Field(None, max_length=1, description="Transform subassembly")
|
||||
extra_information: Optional[str] = Field(None, max_length=399, description="Extra information")
|
||||
web_key: Optional[str] = Field(None, max_length=40, description="Web key")
|
||||
responsible: Optional[str] = Field(None, max_length=80, description="Responsible person")
|
||||
position: Optional[str] = Field(None, max_length=30, description="Position")
|
||||
incoterm: Optional[str] = Field(None, max_length=19, description="Incoterm")
|
||||
is_national_provider: Optional[str] = Field(None, max_length=2, description="Is national provider")
|
||||
enabled_disabled: Optional[int] = Field(None, description="Enabled/Disabled status")
|
||||
|
||||
# Nested DTOs
|
||||
address: Optional[ClientProviderAddressDTO] = Field(None, description="Address information")
|
||||
programs: Optional[ClientProviderProgramsDTO] = Field(None, description="Programs information")
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ClientProviderUpdateDTO(BaseModel):
|
||||
"""DTO para actualizar cliente/proveedor"""
|
||||
type_nat_foreign: Optional[str] = Field(None, max_length=1, description="Type national/foreign")
|
||||
name: Optional[str] = Field(None, max_length=256, description="Name")
|
||||
short_name: Optional[str] = Field(None, max_length=10, description="Short name")
|
||||
rfc: Optional[str] = Field(None, max_length=30, description="RFC")
|
||||
curp: Optional[str] = Field(None, max_length=19, description="CURP")
|
||||
client_or_provider: Optional[str] = Field(None, max_length=1, description="Client or provider")
|
||||
linking: Optional[str] = Field(None, max_length=1, description="Linking")
|
||||
transform_subassembly: Optional[str] = Field(None, max_length=1, description="Transform subassembly")
|
||||
extra_information: Optional[str] = Field(None, max_length=399, description="Extra information")
|
||||
web_key: Optional[str] = Field(None, max_length=40, description="Web key")
|
||||
responsible: Optional[str] = Field(None, max_length=80, description="Responsible person")
|
||||
position: Optional[str] = Field(None, max_length=30, description="Position")
|
||||
incoterm: Optional[str] = Field(None, max_length=19, description="Incoterm")
|
||||
is_national_provider: Optional[str] = Field(None, max_length=2, description="Is national provider")
|
||||
enabled_disabled: Optional[int] = Field(None, description="Enabled/Disabled status")
|
||||
|
||||
# Nested DTOs
|
||||
address: Optional[ClientProviderAddressDTO] = Field(None, description="Address information")
|
||||
programs: Optional[ClientProviderProgramsDTO] = Field(None, description="Programs information")
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ClientProviderResponseDTO(BaseModel):
|
||||
"""DTO para respuesta de cliente/proveedor"""
|
||||
client_id: str
|
||||
type_nat_foreign: Optional[str] = None
|
||||
name: Optional[str] = None
|
||||
short_name: Optional[str] = None
|
||||
rfc: Optional[str] = None
|
||||
curp: Optional[str] = None
|
||||
client_or_provider: Optional[str] = None
|
||||
linking: Optional[str] = None
|
||||
transform_subassembly: Optional[str] = None
|
||||
extra_information: Optional[str] = None
|
||||
web_key: Optional[str] = None
|
||||
responsible: Optional[str] = None
|
||||
position: Optional[str] = None
|
||||
incoterm: Optional[str] = None
|
||||
is_national_provider: Optional[str] = None
|
||||
enabled_disabled: Optional[int] = None
|
||||
|
||||
# Nested DTOs
|
||||
address: Optional[ClientProviderAddressDTO] = None
|
||||
programs: Optional[ClientProviderProgramsDTO] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
# DTOs para respuestas específicas
|
||||
class ClientProviderBasicDTO(BaseModel):
|
||||
"""DTO para información básica de cliente/proveedor"""
|
||||
client_id: str
|
||||
name: Optional[str] = None
|
||||
short_name: Optional[str] = None
|
||||
rfc: Optional[str] = None
|
||||
client_or_provider: Optional[str] = None
|
||||
enabled_disabled: Optional[int] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ClientProviderListDTO(BaseModel):
|
||||
"""DTO para lista de clientes/proveedores"""
|
||||
clients: list[ClientProviderBasicDTO]
|
||||
total: int
|
||||
page: int
|
||||
size: int
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
108
backend/api/v1/modules/a76/client_and_provider/models.py
Normal file
108
backend/api/v1/modules/a76/client_and_provider/models.py
Normal file
@@ -0,0 +1,108 @@
|
||||
"""
|
||||
Modelos ORM para gestión de clientes y proveedores
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text, SmallInteger, Numeric, ForeignKey
|
||||
from sqlalchemy.sql import func
|
||||
from sqlalchemy.orm import relationship
|
||||
from core.database import Base
|
||||
import enum
|
||||
|
||||
|
||||
class ClientProvider(Base):
|
||||
"""
|
||||
Modelo para la tabla GClientesPro - Información de clientes y proveedores
|
||||
"""
|
||||
__tablename__ = "client_provider"
|
||||
__table_args__ = {"schema": "a76"}
|
||||
|
||||
# Primary key
|
||||
client_id = Column(String(8), primary_key=True, nullable=False)
|
||||
|
||||
# Basic information
|
||||
type_nat_foreign = Column(String(1), nullable=True) # TIPO NACIONAL/EXTRANJERO
|
||||
name = Column(String(256), nullable=True)
|
||||
short_name = Column(String(10), nullable=True)
|
||||
rfc = Column(String(30), nullable=True)
|
||||
curp = Column(String(19), nullable=True)
|
||||
client_or_provider = Column(String(1), nullable=True)
|
||||
linking = Column(String(1), nullable=True)
|
||||
transform_subassembly = Column(String(1), nullable=True)
|
||||
extra_information = Column(String(399), nullable=True)
|
||||
web_key = Column(String(40), nullable=True)
|
||||
responsible = Column(String(80), nullable=True)
|
||||
position = Column(String(30), nullable=True)
|
||||
incoterm = Column(String(19), nullable=True)
|
||||
is_national_provider = Column(String(2), nullable=True)
|
||||
enabled_disabled = Column(SmallInteger, nullable=True)
|
||||
|
||||
# Relationships
|
||||
address = relationship("GClientProviderAddress", back_populates="client_provider", uselist=False, cascade="all, delete-orphan")
|
||||
programs = relationship("GClientProviderPrograms", back_populates="client_provider", uselist=False, cascade="all, delete-orphan")
|
||||
|
||||
|
||||
class GClientProviderAddress(Base):
|
||||
"""
|
||||
Modelo para la tabla GClientesPro_Direccion - Dirección de clientes y proveedores
|
||||
"""
|
||||
__tablename__ = "gclient_provider_address"
|
||||
__table_args__ = {"schema": "a76"}
|
||||
|
||||
# Primary key (foreign key)
|
||||
client_id = Column(String(8), ForeignKey('a76.client_provider.client_id', ondelete='CASCADE'), primary_key=True, nullable=False)
|
||||
|
||||
# Address information
|
||||
municipality = Column(String(150), nullable=True)
|
||||
streets = Column(String(100), nullable=True)
|
||||
neighborhood = Column(String(40), nullable=True)
|
||||
interior_number = Column(String(20), nullable=True)
|
||||
exterior_number = Column(String(20), nullable=True)
|
||||
postal_code = Column(String(15), nullable=True)
|
||||
city = Column(String(30), nullable=True)
|
||||
state = Column(String(30), nullable=True)
|
||||
country = Column(String(3), nullable=True)
|
||||
phone = Column(String(30), nullable=True)
|
||||
fax_number = Column(String(30), nullable=True)
|
||||
email = Column(String(100), nullable=True)
|
||||
contact = Column(String(50), nullable=True)
|
||||
reference = Column(String(250), nullable=True)
|
||||
|
||||
# Relationship
|
||||
client_provider = relationship("ClientProvider", back_populates="address")
|
||||
|
||||
|
||||
class GClientProviderPrograms(Base):
|
||||
"""
|
||||
Modelo para la tabla GClientesPro_Programas - Programas de clientes y proveedores
|
||||
"""
|
||||
__tablename__ = "gclient_provider_programs"
|
||||
__table_args__ = {"schema": "a76"}
|
||||
|
||||
# Primary key (foreign key)
|
||||
client_id = Column(String(8), ForeignKey('a76.client_provider.client_id', ondelete='CASCADE'), primary_key=True, nullable=False)
|
||||
|
||||
# Program information
|
||||
program = Column(String(7), nullable=True)
|
||||
program_number = Column(String(40), nullable=True)
|
||||
prosec = Column(SmallInteger, nullable=True)
|
||||
prosec_authorization = Column(String(20), nullable=True)
|
||||
secon_auth_date = Column(Integer, nullable=True)
|
||||
manufacturer_id = Column(String(25), nullable=True)
|
||||
tax_id = Column(String(30), nullable=True)
|
||||
broker = Column(String(6), nullable=True)
|
||||
import_broker = Column(String(6), nullable=True)
|
||||
transfer_key = Column(String(8), nullable=True)
|
||||
secon_authorization = Column(String(20), nullable=True)
|
||||
applied_proportion = Column(Numeric(7, 2), nullable=True)
|
||||
is_certified_company = Column(String(1), nullable=True)
|
||||
certified_company_registry = Column(String(40), nullable=True)
|
||||
donation_auth_number = Column(String(50), nullable=True)
|
||||
ctpat_svi = Column(String(100), nullable=True)
|
||||
tax_registry_number = Column(String(40), nullable=True)
|
||||
subassembly_service = Column(SmallInteger, nullable=True)
|
||||
autse_dates = Column(Integer, nullable=True)
|
||||
autse_number = Column(String(300), nullable=True)
|
||||
|
||||
# Relationship
|
||||
client_provider = relationship("ClientProvider", back_populates="programs")
|
||||
|
||||
|
||||
221
backend/api/v1/modules/a76/client_and_provider/routes.py
Normal file
221
backend/api/v1/modules/a76/client_and_provider/routes.py
Normal file
@@ -0,0 +1,221 @@
|
||||
"""
|
||||
Endpoints API para gestión de clientes y proveedores
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List, Optional
|
||||
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, has_role
|
||||
from .service import ClientProviderService
|
||||
from .dto import (
|
||||
ClientProviderCreateDTO,
|
||||
ClientProviderUpdateDTO,
|
||||
ClientProviderResponseDTO,
|
||||
ClientProviderBasicDTO,
|
||||
ClientProviderListDTO
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/clients-providers")
|
||||
|
||||
|
||||
@router.post("/", response_model=ClientProviderResponseDTO, status_code=status.HTTP_201_CREATED)
|
||||
async def create_client_provider(
|
||||
client_data: ClientProviderCreateDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Create a new client or provider in the system
|
||||
"""
|
||||
service = ClientProviderService(db)
|
||||
return service.create_client_provider(client_data)
|
||||
|
||||
|
||||
@router.get("/", response_model=ClientProviderListDTO)
|
||||
async def list_clients_providers(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum number of records to return"),
|
||||
search: Optional[str] = Query(None, description="Search text for name, RFC, or ID"),
|
||||
client_or_provider: Optional[str] = Query(None, regex="^[CP]$", description="Filter by type: C=Client, P=Provider"),
|
||||
enabled_only: bool = Query(False, description="Show only enabled records"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
List clients and providers with optional filters and pagination
|
||||
"""
|
||||
service = ClientProviderService(db)
|
||||
return service.list_clients_providers(skip, limit, search, client_or_provider, enabled_only)
|
||||
|
||||
|
||||
@router.get("/clients", response_model=List[ClientProviderBasicDTO])
|
||||
async def get_clients_only(
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get only clients (client_or_provider = 'C')
|
||||
"""
|
||||
service = ClientProviderService(db)
|
||||
return service.get_clients_only(skip, limit)
|
||||
|
||||
|
||||
@router.get("/providers", response_model=List[ClientProviderBasicDTO])
|
||||
async def get_providers_only(
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get only providers (client_or_provider = 'P')
|
||||
"""
|
||||
service = ClientProviderService(db)
|
||||
return service.get_providers_only(skip, limit)
|
||||
|
||||
|
||||
@router.get("/search/rfc/{rfc}", response_model=List[ClientProviderBasicDTO])
|
||||
async def search_by_rfc(
|
||||
rfc: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Search clients/providers by RFC
|
||||
"""
|
||||
service = ClientProviderService(db)
|
||||
return service.search_by_rfc(rfc)
|
||||
|
||||
|
||||
@router.get("/{client_id}", response_model=ClientProviderResponseDTO)
|
||||
async def get_client_provider(
|
||||
client_id: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get client/provider by ID with all related information
|
||||
"""
|
||||
service = ClientProviderService(db)
|
||||
client = service.get_client_provider(client_id)
|
||||
if not client:
|
||||
raise HTTPException(status_code=404, detail=f"Client/Provider with ID '{client_id}' not found")
|
||||
return client
|
||||
|
||||
|
||||
@router.put("/{client_id}", response_model=ClientProviderResponseDTO)
|
||||
async def update_client_provider(
|
||||
client_id: str,
|
||||
client_data: ClientProviderUpdateDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Update client/provider information
|
||||
"""
|
||||
service = ClientProviderService(db)
|
||||
client = service.update_client_provider(client_id, client_data)
|
||||
if not client:
|
||||
raise HTTPException(status_code=404, detail=f"Client/Provider with ID '{client_id}' not found")
|
||||
return client
|
||||
|
||||
|
||||
@router.delete("/{client_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_client_provider(
|
||||
client_id: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Delete client/provider from the system
|
||||
|
||||
Note: This will completely remove the client/provider and all related data.
|
||||
"""
|
||||
service = ClientProviderService(db)
|
||||
if not service.delete_client_provider(client_id):
|
||||
raise HTTPException(status_code=404, detail=f"Client/Provider with ID '{client_id}' not found")
|
||||
|
||||
|
||||
@router.patch("/{client_id}/toggle-status", response_model=ClientProviderResponseDTO)
|
||||
async def toggle_client_provider_status(
|
||||
client_id: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Toggle client/provider enabled/disabled status
|
||||
"""
|
||||
service = ClientProviderService(db)
|
||||
client = service.toggle_status(client_id)
|
||||
if not client:
|
||||
raise HTTPException(status_code=404, detail=f"Client/Provider with ID '{client_id}' not found")
|
||||
return client
|
||||
|
||||
|
||||
# Endpoints específicos para información detallada
|
||||
@router.get("/{client_id}/address", response_model=dict)
|
||||
async def get_client_provider_address(
|
||||
client_id: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get only address information for a client/provider
|
||||
"""
|
||||
service = ClientProviderService(db)
|
||||
client = service.get_client_provider(client_id)
|
||||
if not client:
|
||||
raise HTTPException(status_code=404, detail=f"Client/Provider with ID '{client_id}' not found")
|
||||
|
||||
return {
|
||||
"client_id": client.client_id,
|
||||
"address": client.address
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{client_id}/programs", response_model=dict)
|
||||
async def get_client_provider_programs(
|
||||
client_id: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get only programs information for a client/provider
|
||||
"""
|
||||
service = ClientProviderService(db)
|
||||
client = service.get_client_provider(client_id)
|
||||
if not client:
|
||||
raise HTTPException(status_code=404, detail=f"Client/Provider with ID '{client_id}' not found")
|
||||
|
||||
return {
|
||||
"client_id": client.client_id,
|
||||
"programs": client.programs
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{client_id}/basic", response_model=ClientProviderBasicDTO)
|
||||
async def get_client_provider_basic_info(
|
||||
client_id: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get basic information for a client/provider (without address and programs)
|
||||
"""
|
||||
service = ClientProviderService(db)
|
||||
client = service.get_client_provider(client_id)
|
||||
if not client:
|
||||
raise HTTPException(status_code=404, detail=f"Client/Provider with ID '{client_id}' not found")
|
||||
|
||||
return ClientProviderBasicDTO(
|
||||
client_id=client.client_id,
|
||||
name=client.name,
|
||||
short_name=client.short_name,
|
||||
rfc=client.rfc,
|
||||
client_or_provider=client.client_or_provider,
|
||||
enabled_disabled=client.enabled_disabled
|
||||
)
|
||||
|
||||
309
backend/api/v1/modules/a76/client_and_provider/service.py
Normal file
309
backend/api/v1/modules/a76/client_and_provider/service.py
Normal file
@@ -0,0 +1,309 @@
|
||||
"""
|
||||
Capa de servicio para lógica de negocio de clientes y proveedores
|
||||
"""
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy import or_, and_
|
||||
from fastapi import HTTPException
|
||||
from typing import List, Optional
|
||||
import logging
|
||||
|
||||
from .models import ClientProvider, GClientProviderAddress, GClientProviderPrograms
|
||||
from .dto import (
|
||||
ClientProviderCreateDTO,
|
||||
ClientProviderUpdateDTO,
|
||||
ClientProviderResponseDTO,
|
||||
ClientProviderBasicDTO,
|
||||
ClientProviderListDTO,
|
||||
ClientProviderAddressDTO,
|
||||
ClientProviderProgramsDTO
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ClientProviderService:
|
||||
"""Servicio para gestión de clientes y proveedores"""
|
||||
|
||||
def __init__(self, db: Session):
|
||||
self.db = db
|
||||
|
||||
def create_client_provider(self, client_data: ClientProviderCreateDTO) -> ClientProviderResponseDTO:
|
||||
"""
|
||||
Crea un nuevo cliente/proveedor en el sistema
|
||||
|
||||
Args:
|
||||
client_data: Datos del cliente/proveedor a crear
|
||||
|
||||
Returns:
|
||||
ClientProviderResponseDTO con información del cliente/proveedor creado
|
||||
|
||||
Raises:
|
||||
HTTPException: Si el cliente ya existe o error en la creación
|
||||
"""
|
||||
try:
|
||||
# Verificar que no exista el cliente
|
||||
existing = self.db.query(ClientProvider).filter(ClientProvider.client_id == client_data.client_id).first()
|
||||
if existing:
|
||||
raise HTTPException(status_code=400, detail=f"Client with ID '{client_data.client_id}' already exists")
|
||||
|
||||
# Crear cliente/proveedor principal
|
||||
db_client = ClientProvider(
|
||||
client_id=client_data.client_id,
|
||||
type_nat_foreign=client_data.type_nat_foreign,
|
||||
name=client_data.name,
|
||||
short_name=client_data.short_name,
|
||||
rfc=client_data.rfc,
|
||||
curp=client_data.curp,
|
||||
client_or_provider=client_data.client_or_provider,
|
||||
linking=client_data.linking,
|
||||
transform_subassembly=client_data.transform_subassembly,
|
||||
extra_information=client_data.extra_information,
|
||||
web_key=client_data.web_key,
|
||||
responsible=client_data.responsible,
|
||||
position=client_data.position,
|
||||
incoterm=client_data.incoterm,
|
||||
is_national_provider=client_data.is_national_provider,
|
||||
enabled_disabled=client_data.enabled_disabled
|
||||
)
|
||||
|
||||
self.db.add(db_client)
|
||||
self.db.flush() # Para obtener el ID antes del commit
|
||||
|
||||
# Crear dirección si se proporciona
|
||||
if client_data.address:
|
||||
db_address = GClientProviderAddress(
|
||||
client_id=client_data.client_id,
|
||||
**client_data.address.model_dump(exclude_unset=True)
|
||||
)
|
||||
self.db.add(db_address)
|
||||
|
||||
# Crear programas si se proporciona
|
||||
if client_data.programs:
|
||||
db_programs = GClientProviderPrograms(
|
||||
client_id=client_data.client_id,
|
||||
**client_data.programs.model_dump(exclude_unset=True)
|
||||
)
|
||||
self.db.add(db_programs)
|
||||
|
||||
self.db.commit()
|
||||
self.db.refresh(db_client)
|
||||
|
||||
logger.info(f"Client/Provider created: {db_client.client_id} - {db_client.name}")
|
||||
|
||||
return self._get_client_with_relations(client_data.client_id)
|
||||
|
||||
except IntegrityError as e:
|
||||
self.db.rollback()
|
||||
logger.error(f"IntegrityError creating client/provider: {str(e)}")
|
||||
raise HTTPException(status_code=400, detail="Client/Provider with this ID already exists")
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
self.db.rollback()
|
||||
logger.error(f"Error creating client/provider: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Error creating client/provider")
|
||||
|
||||
def get_client_provider(self, client_id: str) -> Optional[ClientProviderResponseDTO]:
|
||||
"""
|
||||
Obtiene un cliente/proveedor por ID
|
||||
|
||||
Args:
|
||||
client_id: ID del cliente/proveedor
|
||||
|
||||
Returns:
|
||||
ClientProviderResponseDTO o None si no existe
|
||||
"""
|
||||
return self._get_client_with_relations(client_id)
|
||||
|
||||
def _get_client_with_relations(self, client_id: str) -> Optional[ClientProviderResponseDTO]:
|
||||
"""Método privado para obtener cliente con relaciones"""
|
||||
client = self.db.query(ClientProvider).options(
|
||||
joinedload(ClientProvider.address),
|
||||
joinedload(ClientProvider.programs)
|
||||
).filter(ClientProvider.client_id == client_id).first()
|
||||
|
||||
if not client:
|
||||
return None
|
||||
return ClientProviderResponseDTO.model_validate(client)
|
||||
|
||||
def list_clients_providers(
|
||||
self,
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
search: Optional[str] = None,
|
||||
client_or_provider: Optional[str] = None,
|
||||
enabled_only: bool = False
|
||||
) -> ClientProviderListDTO:
|
||||
"""
|
||||
Lista clientes/proveedores con filtros
|
||||
|
||||
Args:
|
||||
skip: Número de registros a omitir
|
||||
limit: Número máximo de registros a retornar
|
||||
search: Texto de búsqueda (nombre, RFC, ID)
|
||||
client_or_provider: Filtrar por tipo (C=Cliente, P=Proveedor)
|
||||
enabled_only: Si True, solo retorna activos
|
||||
|
||||
Returns:
|
||||
ClientProviderListDTO con la lista paginada
|
||||
"""
|
||||
query = self.db.query(ClientProvider)
|
||||
|
||||
# Aplicar filtros
|
||||
if search:
|
||||
search_pattern = f"%{search}%"
|
||||
query = query.filter(
|
||||
or_(
|
||||
ClientProvider.name.ilike(search_pattern),
|
||||
ClientProvider.short_name.ilike(search_pattern),
|
||||
ClientProvider.rfc.ilike(search_pattern),
|
||||
ClientProvider.client_id.ilike(search_pattern)
|
||||
)
|
||||
)
|
||||
|
||||
if client_or_provider:
|
||||
query = query.filter(ClientProvider.client_or_provider == client_or_provider)
|
||||
|
||||
if enabled_only:
|
||||
query = query.filter(ClientProvider.enabled_disabled == 1)
|
||||
|
||||
# Contar total
|
||||
total = query.count()
|
||||
|
||||
# Aplicar paginación
|
||||
clients = query.offset(skip).limit(limit).all()
|
||||
|
||||
# Convertir a DTOs básicos
|
||||
client_dtos = [ClientProviderBasicDTO.model_validate(client) for client in clients]
|
||||
|
||||
return ClientProviderListDTO(
|
||||
clients=client_dtos,
|
||||
total=total,
|
||||
page=(skip // limit) + 1 if limit > 0 else 1,
|
||||
size=len(client_dtos)
|
||||
)
|
||||
|
||||
def update_client_provider(self, client_id: str, client_data: ClientProviderUpdateDTO) -> Optional[ClientProviderResponseDTO]:
|
||||
"""
|
||||
Actualiza un cliente/proveedor
|
||||
|
||||
Args:
|
||||
client_id: ID del cliente/proveedor a actualizar
|
||||
client_data: Datos a actualizar
|
||||
|
||||
Returns:
|
||||
ClientProviderResponseDTO actualizado o None si no existe
|
||||
"""
|
||||
client = self.db.query(ClientProvider).filter(ClientProvider.client_id == client_id).first()
|
||||
if not client:
|
||||
return None
|
||||
|
||||
try:
|
||||
# Actualizar campos del cliente principal
|
||||
update_data = client_data.model_dump(exclude_unset=True, exclude={'address', 'programs'})
|
||||
for field, value in update_data.items():
|
||||
setattr(client, field, value)
|
||||
|
||||
# Actualizar dirección
|
||||
if client_data.address:
|
||||
address = self.db.query(GClientProviderAddress).filter(GClientProviderAddress.client_id == client_id).first()
|
||||
if address:
|
||||
# Actualizar dirección existente
|
||||
address_data = client_data.address.model_dump(exclude_unset=True)
|
||||
for field, value in address_data.items():
|
||||
setattr(address, field, value)
|
||||
else:
|
||||
# Crear nueva dirección
|
||||
address = GClientProviderAddress(
|
||||
client_id=client_id,
|
||||
**client_data.address.model_dump(exclude_unset=True)
|
||||
)
|
||||
self.db.add(address)
|
||||
|
||||
# Actualizar programas
|
||||
if client_data.programs:
|
||||
programs = self.db.query(GClientProviderPrograms).filter(GClientProviderPrograms.client_id == client_id).first()
|
||||
if programs:
|
||||
# Actualizar programas existentes
|
||||
programs_data = client_data.programs.model_dump(exclude_unset=True)
|
||||
for field, value in programs_data.items():
|
||||
setattr(programs, field, value)
|
||||
else:
|
||||
# Crear nuevos programas
|
||||
programs = GClientProviderPrograms(
|
||||
client_id=client_id,
|
||||
**client_data.programs.model_dump(exclude_unset=True)
|
||||
)
|
||||
self.db.add(programs)
|
||||
|
||||
self.db.commit()
|
||||
logger.info(f"Client/Provider updated: {client_id}")
|
||||
|
||||
return self._get_client_with_relations(client_id)
|
||||
|
||||
except Exception as e:
|
||||
self.db.rollback()
|
||||
logger.error(f"Error updating client/provider {client_id}: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Error updating client/provider")
|
||||
|
||||
def delete_client_provider(self, client_id: str) -> bool:
|
||||
"""
|
||||
Elimina un cliente/proveedor
|
||||
|
||||
Args:
|
||||
client_id: ID del cliente/proveedor a eliminar
|
||||
|
||||
Returns:
|
||||
True si se eliminó, False si no existe
|
||||
"""
|
||||
client = self.db.query(ClientProvider).filter(ClientProvider.client_id == client_id).first()
|
||||
if not client:
|
||||
return False
|
||||
|
||||
try:
|
||||
self.db.delete(client) # Las relaciones se eliminan en cascada
|
||||
self.db.commit()
|
||||
logger.info(f"Client/Provider deleted: {client_id}")
|
||||
return True
|
||||
except Exception as e:
|
||||
self.db.rollback()
|
||||
logger.error(f"Error deleting client/provider {client_id}: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Error deleting client/provider")
|
||||
|
||||
def get_clients_only(self, skip: int = 0, limit: int = 100) -> List[ClientProviderBasicDTO]:
|
||||
"""Obtiene solo clientes (C)"""
|
||||
query = self.db.query(ClientProvider).filter(ClientProvider.client_or_provider == 'C')
|
||||
clients = query.offset(skip).limit(limit).all()
|
||||
return [ClientProviderBasicDTO.model_validate(client) for client in clients]
|
||||
|
||||
def get_providers_only(self, skip: int = 0, limit: int = 100) -> List[ClientProviderBasicDTO]:
|
||||
"""Obtiene solo proveedores (P)"""
|
||||
query = self.db.query(ClientProvider).filter(ClientProvider.client_or_provider == 'P')
|
||||
providers = query.offset(skip).limit(limit).all()
|
||||
return [ClientProviderBasicDTO.model_validate(provider) for provider in providers]
|
||||
|
||||
def search_by_rfc(self, rfc: str) -> List[ClientProviderBasicDTO]:
|
||||
"""Busca clientes/proveedores por RFC"""
|
||||
clients = self.db.query(ClientProvider).filter(ClientProvider.rfc.ilike(f"%{rfc}%")).all()
|
||||
return [ClientProviderBasicDTO.model_validate(client) for client in clients]
|
||||
|
||||
def toggle_status(self, client_id: str) -> Optional[ClientProviderResponseDTO]:
|
||||
"""Cambia el estado habilitado/deshabilitado"""
|
||||
client = self.db.query(ClientProvider).filter(ClientProvider.client_id == client_id).first()
|
||||
if not client:
|
||||
return None
|
||||
|
||||
# Toggle status (1 = habilitado, 0 = deshabilitado)
|
||||
client.enabled_disabled = 1 if client.enabled_disabled == 0 else 0
|
||||
|
||||
try:
|
||||
self.db.commit()
|
||||
logger.info(f"Client/Provider status toggled: {client_id} -> {client.enabled_disabled}")
|
||||
return self._get_client_with_relations(client_id)
|
||||
except Exception as e:
|
||||
self.db.rollback()
|
||||
logger.error(f"Error toggling status for {client_id}: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Error updating status")
|
||||
|
||||
|
||||
6
backend/api/v1/modules/a76/company/__init__.py
Normal file
6
backend/api/v1/modules/a76/company/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
"""
|
||||
Módulo de Company
|
||||
"""
|
||||
from .routes import router
|
||||
|
||||
__all__ = ["router"]
|
||||
157
backend/api/v1/modules/a76/company/dto.py
Normal file
157
backend/api/v1/modules/a76/company/dto.py
Normal file
@@ -0,0 +1,157 @@
|
||||
"""
|
||||
DTOs (Data Transfer Objects) para módulo de empresa
|
||||
Reemplaza schemas.py siguiendo enfoque DDD y estilo NestJS
|
||||
"""
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class CompanyCreateDTO(BaseModel):
|
||||
"""DTO para crear una empresa"""
|
||||
id: str = Field(default='EMP', max_length=3, description="Company ID")
|
||||
consecutive: bool = Field(default=True, description="Unique record control")
|
||||
name: Optional[str] = Field(None, max_length=255, description="Company name")
|
||||
rfc: Optional[str] = Field(None, max_length=30, description="Company RFC")
|
||||
main_activity: Optional[str] = Field(None, max_length=255, description="Main activity")
|
||||
|
||||
# Program information
|
||||
program: Optional[str] = Field(None, max_length=10, description="Program")
|
||||
program_number: Optional[str] = Field(None, max_length=40, description="Program number")
|
||||
prosec: Optional[int] = Field(None, description="PROSEC")
|
||||
prosec_authorization: Optional[str] = Field(None, max_length=20, description="PROSEC authorization")
|
||||
|
||||
# Identifiers
|
||||
manufacturer_id: Optional[str] = Field(None, max_length=25, description="Manufacturer ID")
|
||||
broker_company: Optional[str] = Field(None, max_length=10, description="Broker company")
|
||||
|
||||
# Responsible person
|
||||
responsible: Optional[str] = Field(None, max_length=80, description="Responsible person")
|
||||
responsible_name: Optional[str] = Field(None, max_length=20, description="Responsible first name")
|
||||
responsible_last_name: Optional[str] = Field(None, max_length=20, description="Responsible last name")
|
||||
responsible_mother_last_name: Optional[str] = Field(None, max_length=20, description="Responsible mother's last name")
|
||||
responsible_rfc: Optional[str] = Field(None, max_length=30, description="Responsible RFC")
|
||||
position: Optional[str] = Field(None, max_length=30, description="Responsible position")
|
||||
|
||||
# Configuration
|
||||
logo: Optional[str] = Field(None, max_length=255, description="Company logo")
|
||||
has_express_line: Optional[bool] = Field(None, description="Has express line")
|
||||
order_format_type: Optional[str] = Field(None, max_length=19, description="Order format type")
|
||||
previous_code: Optional[int] = Field(None, description="Previous code")
|
||||
is_service_company: Optional[bool] = Field(None, description="Is service company")
|
||||
|
||||
# Client and subassembly
|
||||
client_name: Optional[str] = Field(None, max_length=300, description="Client name")
|
||||
subassembly_mode: Optional[str] = Field(None, max_length=7, description="Subassembly mode")
|
||||
|
||||
# Additional information
|
||||
curp: Optional[str] = Field(None, max_length=19, description="CURP")
|
||||
inter_db_name: Optional[str] = Field(None, max_length=100, description="Inter DB name")
|
||||
ctpat_svi: Optional[str] = Field(None, max_length=100, description="CTPAT SVI")
|
||||
trusted_exporter_number: Optional[str] = Field(None, max_length=50, description="Trusted exporter number")
|
||||
prevalidator_key: Optional[str] = Field(None, max_length=20, description="Prevalidator key")
|
||||
seventh_amendment: Optional[bool] = Field(None, description="Seventh amendment")
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class CompanyUpdateDTO(BaseModel):
|
||||
"""DTO para actualizar una empresa"""
|
||||
name: Optional[str] = Field(None, max_length=255, description="Company name")
|
||||
rfc: Optional[str] = Field(None, max_length=30, description="Company RFC")
|
||||
main_activity: Optional[str] = Field(None, max_length=255, description="Main activity")
|
||||
|
||||
# Program information
|
||||
program: Optional[str] = Field(None, max_length=10, description="Program")
|
||||
program_number: Optional[str] = Field(None, max_length=40, description="Program number")
|
||||
prosec: Optional[int] = Field(None, description="PROSEC")
|
||||
prosec_authorization: Optional[str] = Field(None, max_length=20, description="PROSEC authorization")
|
||||
|
||||
# Identifiers
|
||||
manufacturer_id: Optional[str] = Field(None, max_length=25, description="Manufacturer ID")
|
||||
broker_company: Optional[str] = Field(None, max_length=10, description="Broker company")
|
||||
|
||||
# Responsible person
|
||||
responsible: Optional[str] = Field(None, max_length=80, description="Responsible person")
|
||||
responsible_name: Optional[str] = Field(None, max_length=20, description="Responsible first name")
|
||||
responsible_last_name: Optional[str] = Field(None, max_length=20, description="Responsible last name")
|
||||
responsible_mother_last_name: Optional[str] = Field(None, max_length=20, description="Responsible mother's last name")
|
||||
responsible_rfc: Optional[str] = Field(None, max_length=30, description="Responsible RFC")
|
||||
position: Optional[str] = Field(None, max_length=30, description="Responsible position")
|
||||
|
||||
# Configuration
|
||||
logo: Optional[str] = Field(None, max_length=255, description="Company logo")
|
||||
has_express_line: Optional[bool] = Field(None, description="Has express line")
|
||||
order_format_type: Optional[str] = Field(None, max_length=19, description="Order format type")
|
||||
previous_code: Optional[int] = Field(None, description="Previous code")
|
||||
is_service_company: Optional[bool] = Field(None, description="Is service company")
|
||||
|
||||
# Client and subassembly
|
||||
client_name: Optional[str] = Field(None, max_length=300, description="Client name")
|
||||
subassembly_mode: Optional[str] = Field(None, max_length=7, description="Subassembly mode")
|
||||
|
||||
# Additional information
|
||||
curp: Optional[str] = Field(None, max_length=19, description="CURP")
|
||||
inter_db_name: Optional[str] = Field(None, max_length=100, description="Inter DB name")
|
||||
ctpat_svi: Optional[str] = Field(None, max_length=100, description="CTPAT SVI")
|
||||
trusted_exporter_number: Optional[str] = Field(None, max_length=50, description="Trusted exporter number")
|
||||
prevalidator_key: Optional[str] = Field(None, max_length=20, description="Prevalidator key")
|
||||
seventh_amendment: Optional[bool] = Field(None, description="Seventh amendment")
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class CompanyResponseDTO(BaseModel):
|
||||
"""DTO para respuesta de empresa"""
|
||||
id: str
|
||||
consecutive: bool
|
||||
name: Optional[str] = None
|
||||
rfc: Optional[str] = None
|
||||
main_activity: Optional[str] = None
|
||||
|
||||
# Program information
|
||||
program: Optional[str] = None
|
||||
program_number: Optional[str] = None
|
||||
prosec: Optional[int] = None
|
||||
prosec_authorization: Optional[str] = None
|
||||
|
||||
# Identifiers
|
||||
manufacturer_id: Optional[str] = None
|
||||
broker_company: Optional[str] = None
|
||||
|
||||
# Responsible person
|
||||
responsible: Optional[str] = None
|
||||
responsible_name: Optional[str] = None
|
||||
responsible_last_name: Optional[str] = None
|
||||
responsible_mother_last_name: Optional[str] = None
|
||||
responsible_rfc: Optional[str] = None
|
||||
position: Optional[str] = None
|
||||
|
||||
# Configuration
|
||||
logo: Optional[str] = None
|
||||
has_express_line: Optional[bool] = None
|
||||
order_format_type: Optional[str] = None
|
||||
previous_code: Optional[int] = None
|
||||
is_service_company: Optional[bool] = None
|
||||
|
||||
# Client and subassembly
|
||||
client_name: Optional[str] = None
|
||||
subassembly_mode: Optional[str] = None
|
||||
|
||||
# Additional information
|
||||
curp: Optional[str] = None
|
||||
inter_db_name: Optional[str] = None
|
||||
ctpat_svi: Optional[str] = None
|
||||
trusted_exporter_number: Optional[str] = None
|
||||
prevalidator_key: Optional[str] = None
|
||||
seventh_amendment: Optional[bool] = None
|
||||
|
||||
# Timestamps
|
||||
created_at: datetime
|
||||
updated_at: Optional[datetime] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
69
backend/api/v1/modules/a76/company/models.py
Normal file
69
backend/api/v1/modules/a76/company/models.py
Normal file
@@ -0,0 +1,69 @@
|
||||
"""
|
||||
Modelos ORM para gestión de empresa
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text, SmallInteger
|
||||
from sqlalchemy.sql import func
|
||||
from core.database import Base
|
||||
import enum
|
||||
|
||||
|
||||
class GCompany(Base):
|
||||
"""
|
||||
Modelo para la tabla GCompany - Información de la empresa
|
||||
"""
|
||||
__tablename__ = "gcompany"
|
||||
__table_args__ = {"schema": "a76"}
|
||||
|
||||
# Primary key
|
||||
id = Column(String(3), primary_key=True, default='EMP', nullable=False)
|
||||
|
||||
# Control de registro único
|
||||
consecutive = Column(Boolean, unique=True, default=True, nullable=False)
|
||||
|
||||
# Información básica de la empresa
|
||||
name = Column(String(255), nullable=True)
|
||||
rfc = Column(String(30), nullable=True)
|
||||
main_activity = Column(String(255), nullable=True)
|
||||
|
||||
# Información del programa
|
||||
program = Column(String(10), nullable=True)
|
||||
program_number = Column(String(40), nullable=True)
|
||||
prosec = Column(SmallInteger, nullable=True)
|
||||
prosec_authorization = Column(String(20), nullable=True)
|
||||
|
||||
# Identificadores
|
||||
manufacturer_id = Column(String(25), nullable=True)
|
||||
broker_company = Column(String(10), nullable=True)
|
||||
|
||||
# Responsable
|
||||
responsible = Column(String(80), nullable=True)
|
||||
responsible_name = Column(String(20), nullable=True)
|
||||
responsible_last_name = Column(String(20), nullable=True)
|
||||
responsible_mother_last_name = Column(String(20), nullable=True)
|
||||
responsible_rfc = Column(String(30), nullable=True)
|
||||
position = Column(String(30), nullable=True)
|
||||
|
||||
# Configuración
|
||||
logo = Column(String(255), nullable=True)
|
||||
has_express_line = Column(Boolean, nullable=True)
|
||||
order_format_type = Column(String(19), nullable=True)
|
||||
previous_code = Column(SmallInteger, nullable=True)
|
||||
is_service_company = Column(Boolean, nullable=True)
|
||||
|
||||
# Cliente y submaquila
|
||||
client_name = Column(String(300), nullable=True)
|
||||
subassembly_mode = Column(String(7), nullable=True)
|
||||
|
||||
# Información adicional
|
||||
curp = Column(String(19), nullable=True)
|
||||
inter_db_name = Column(String(100), nullable=True)
|
||||
ctpat_svi = Column(String(100), nullable=True)
|
||||
trusted_exporter_number = Column(String(50), nullable=True)
|
||||
prevalidator_key = Column(String(20), nullable=True)
|
||||
seventh_amendment = Column(Boolean, nullable=True) # FINALCONTADORAELECTRONICO renombrado
|
||||
|
||||
# Timestamps
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now(), nullable=True)
|
||||
|
||||
|
||||
176
backend/api/v1/modules/a76/company/routes.py
Normal file
176
backend/api/v1/modules/a76/company/routes.py
Normal file
@@ -0,0 +1,176 @@
|
||||
"""
|
||||
Endpoints API para gestión de empresa
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import Optional
|
||||
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, has_role
|
||||
from .service import CompanyService
|
||||
from .dto import CompanyCreateDTO, CompanyUpdateDTO, CompanyResponseDTO
|
||||
|
||||
router = APIRouter(prefix="/company")
|
||||
|
||||
|
||||
@router.post("/", response_model=CompanyResponseDTO, status_code=status.HTTP_201_CREATED)
|
||||
async def create_company(
|
||||
company_data: CompanyCreateDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Create a new company in the system
|
||||
|
||||
Only one company can exist per system due to the unique consecutive field.
|
||||
"""
|
||||
service = CompanyService(db)
|
||||
return service.create_company(company_data)
|
||||
|
||||
|
||||
@router.get("/", response_model=Optional[CompanyResponseDTO])
|
||||
async def get_company(
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get the registered company information
|
||||
|
||||
Returns the unique company in the system or None if it doesn't exist.
|
||||
"""
|
||||
service = CompanyService(db)
|
||||
company = service.get_company()
|
||||
if not company:
|
||||
raise HTTPException(status_code=404, detail="No company found")
|
||||
return company
|
||||
|
||||
|
||||
@router.get("/{company_id}", response_model=CompanyResponseDTO)
|
||||
async def get_company_by_id(
|
||||
company_id: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get company by specific ID
|
||||
"""
|
||||
service = CompanyService(db)
|
||||
company = service.get_company_by_id(company_id)
|
||||
if not company:
|
||||
raise HTTPException(status_code=404, detail=f"Company with ID '{company_id}' not found")
|
||||
return company
|
||||
|
||||
|
||||
@router.put("/{company_id}", response_model=CompanyResponseDTO)
|
||||
async def update_company(
|
||||
company_id: str,
|
||||
company_data: CompanyUpdateDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Update company information
|
||||
"""
|
||||
service = CompanyService(db)
|
||||
company = service.update_company(company_id, company_data)
|
||||
if not company:
|
||||
raise HTTPException(status_code=404, detail=f"Company with ID '{company_id}' not found")
|
||||
return company
|
||||
|
||||
|
||||
@router.delete("/{company_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_company(
|
||||
company_id: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Delete company from the system
|
||||
|
||||
Note: This will completely remove the company from the system.
|
||||
"""
|
||||
service = CompanyService(db)
|
||||
if not service.delete_company(company_id):
|
||||
raise HTTPException(status_code=404, detail=f"Company with ID '{company_id}' not found")
|
||||
|
||||
|
||||
@router.get("/status/exists", response_model=dict)
|
||||
async def check_company_exists(
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Check if a company is registered in the system
|
||||
"""
|
||||
service = CompanyService(db)
|
||||
exists = service.exists_company()
|
||||
return {"exists": exists, "message": "Company found" if exists else "No company registered"}
|
||||
|
||||
|
||||
# Specific endpoints for important fields
|
||||
@router.get("/info/basic", response_model=dict)
|
||||
async def get_company_basic_info(
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get basic company information (name, RFC, main activity)
|
||||
"""
|
||||
service = CompanyService(db)
|
||||
company = service.get_company()
|
||||
if not company:
|
||||
raise HTTPException(status_code=404, detail="No company found")
|
||||
|
||||
return {
|
||||
"name": company.name,
|
||||
"rfc": company.rfc,
|
||||
"main_activity": company.main_activity,
|
||||
"logo": company.logo
|
||||
}
|
||||
|
||||
|
||||
@router.get("/info/responsible", response_model=dict)
|
||||
async def get_company_responsible_info(
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get company responsible person information
|
||||
"""
|
||||
service = CompanyService(db)
|
||||
company = service.get_company()
|
||||
if not company:
|
||||
raise HTTPException(status_code=404, detail="No company found")
|
||||
|
||||
return {
|
||||
"responsible": company.responsible,
|
||||
"responsible_name": company.responsible_name,
|
||||
"responsible_last_name": company.responsible_last_name,
|
||||
"responsible_mother_last_name": company.responsible_mother_last_name,
|
||||
"responsible_rfc": company.responsible_rfc,
|
||||
"position": company.position
|
||||
}
|
||||
|
||||
|
||||
@router.get("/info/program", response_model=dict)
|
||||
async def get_company_program_info(
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get company program information
|
||||
"""
|
||||
service = CompanyService(db)
|
||||
company = service.get_company()
|
||||
if not company:
|
||||
raise HTTPException(status_code=404, detail="No company found")
|
||||
|
||||
return {
|
||||
"program": company.program,
|
||||
"program_number": company.program_number,
|
||||
"prosec": company.prosec,
|
||||
"prosec_authorization": company.prosec_authorization,
|
||||
"manufacturer_id": company.manufacturer_id
|
||||
}
|
||||
|
||||
|
||||
184
backend/api/v1/modules/a76/company/service.py
Normal file
184
backend/api/v1/modules/a76/company/service.py
Normal file
@@ -0,0 +1,184 @@
|
||||
"""
|
||||
Capa de servicio para lógica de negocio de empresa
|
||||
"""
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from fastapi import HTTPException
|
||||
from typing import List, Optional
|
||||
import logging
|
||||
|
||||
from .models import GCompany
|
||||
from .dto import CompanyCreateDTO, CompanyUpdateDTO, CompanyResponseDTO
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CompanyService:
|
||||
"""Servicio para gestión de empresa"""
|
||||
|
||||
def __init__(self, db: Session):
|
||||
self.db = db
|
||||
|
||||
def create_company(self, company_data: CompanyCreateDTO) -> CompanyResponseDTO:
|
||||
"""
|
||||
Crea una nueva empresa en el sistema
|
||||
|
||||
Args:
|
||||
company_data: Datos de la empresa a crear
|
||||
|
||||
Returns:
|
||||
CompanyResponseDTO con información de la empresa creada
|
||||
|
||||
Raises:
|
||||
HTTPException: Si ya existe una empresa o error en la creación
|
||||
"""
|
||||
try:
|
||||
# Verificar que no exista ya una empresa (solo puede haber una por el consecutivo único)
|
||||
existing = self.db.query(GCompany).filter(GCompany.consecutive == True).first()
|
||||
if existing:
|
||||
raise HTTPException(status_code=400, detail="A company is already registered in the system")
|
||||
|
||||
# Crear empresa
|
||||
db_company = GCompany(
|
||||
id=company_data.id,
|
||||
consecutive=company_data.consecutive,
|
||||
name=company_data.name,
|
||||
rfc=company_data.rfc,
|
||||
main_activity=company_data.main_activity,
|
||||
program=company_data.program,
|
||||
program_number=company_data.program_number,
|
||||
prosec=company_data.prosec,
|
||||
prosec_authorization=company_data.prosec_authorization,
|
||||
manufacturer_id=company_data.manufacturer_id,
|
||||
broker_company=company_data.broker_company,
|
||||
responsible=company_data.responsible,
|
||||
responsible_name=company_data.responsible_name,
|
||||
responsible_last_name=company_data.responsible_last_name,
|
||||
responsible_mother_last_name=company_data.responsible_mother_last_name,
|
||||
responsible_rfc=company_data.responsible_rfc,
|
||||
position=company_data.position,
|
||||
logo=company_data.logo,
|
||||
has_express_line=company_data.has_express_line,
|
||||
order_format_type=company_data.order_format_type,
|
||||
previous_code=company_data.previous_code,
|
||||
is_service_company=company_data.is_service_company,
|
||||
client_name=company_data.client_name,
|
||||
subassembly_mode=company_data.subassembly_mode,
|
||||
curp=company_data.curp,
|
||||
inter_db_name=company_data.inter_db_name,
|
||||
ctpat_svi=company_data.ctpat_svi,
|
||||
trusted_exporter_number=company_data.trusted_exporter_number,
|
||||
prevalidator_key=company_data.prevalidator_key,
|
||||
seventh_amendment=company_data.seventh_amendment
|
||||
)
|
||||
|
||||
self.db.add(db_company)
|
||||
self.db.commit()
|
||||
self.db.refresh(db_company)
|
||||
|
||||
logger.info(f"Company created: {db_company.id} - {db_company.name}")
|
||||
|
||||
return CompanyResponseDTO.model_validate(db_company)
|
||||
|
||||
except IntegrityError as e:
|
||||
self.db.rollback()
|
||||
logger.error(f"IntegrityError creating company: {str(e)}")
|
||||
raise HTTPException(status_code=400, detail="Integrity error: A company already exists in the system")
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
self.db.rollback()
|
||||
logger.error(f"Error creating company: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Error creating company")
|
||||
|
||||
def get_company(self) -> Optional[CompanyResponseDTO]:
|
||||
"""
|
||||
Obtiene la empresa (solo puede haber una)
|
||||
|
||||
Returns:
|
||||
CompanyResponseDTO o None si no existe
|
||||
"""
|
||||
company = self.db.query(GCompany).filter(GCompany.consecutive == True).first()
|
||||
if not company:
|
||||
return None
|
||||
return CompanyResponseDTO.model_validate(company)
|
||||
|
||||
def get_company_by_id(self, company_id: str) -> Optional[CompanyResponseDTO]:
|
||||
"""
|
||||
Obtiene una empresa por ID
|
||||
|
||||
Args:
|
||||
company_id: ID de la empresa
|
||||
|
||||
Returns:
|
||||
CompanyResponseDTO o None si no existe
|
||||
"""
|
||||
company = self.db.query(GCompany).filter(GCompany.id == company_id).first()
|
||||
if not company:
|
||||
return None
|
||||
return CompanyResponseDTO.model_validate(company)
|
||||
|
||||
def update_company(self, company_id: str, company_data: CompanyUpdateDTO) -> Optional[CompanyResponseDTO]:
|
||||
"""
|
||||
Actualiza una empresa
|
||||
|
||||
Args:
|
||||
company_id: ID de la empresa a actualizar
|
||||
company_data: Datos a actualizar
|
||||
|
||||
Returns:
|
||||
CompanyResponseDTO actualizada o None si no existe
|
||||
"""
|
||||
company = self.db.query(GCompany).filter(GCompany.id == company_id).first()
|
||||
if not company:
|
||||
return None
|
||||
|
||||
# Actualizar solo campos proporcionados
|
||||
update_data = company_data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(company, field, value)
|
||||
|
||||
try:
|
||||
self.db.commit()
|
||||
self.db.refresh(company)
|
||||
logger.info(f"Company updated: {company_id}")
|
||||
return CompanyResponseDTO.model_validate(company)
|
||||
except Exception as e:
|
||||
self.db.rollback()
|
||||
logger.error(f"Error updating company {company_id}: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Error updating company")
|
||||
|
||||
def delete_company(self, company_id: str) -> bool:
|
||||
"""
|
||||
Elimina una empresa
|
||||
|
||||
Args:
|
||||
company_id: ID de la empresa a eliminar
|
||||
|
||||
Returns:
|
||||
True si se eliminó, False si no existe
|
||||
"""
|
||||
company = self.db.query(GCompany).filter(GCompany.id == company_id).first()
|
||||
if not company:
|
||||
return False
|
||||
|
||||
try:
|
||||
self.db.delete(company)
|
||||
self.db.commit()
|
||||
logger.info(f"Company deleted: {company_id}")
|
||||
return True
|
||||
except Exception as e:
|
||||
self.db.rollback()
|
||||
logger.error(f"Error deleting company {company_id}: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Error deleting company")
|
||||
|
||||
def exists_company(self) -> bool:
|
||||
"""
|
||||
Verifica si existe una empresa registrada
|
||||
|
||||
Returns:
|
||||
True si existe una empresa, False en caso contrario
|
||||
"""
|
||||
return self.db.query(GCompany).filter(GCompany.consecutive == True).first() is not None
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ from .dto import (
|
||||
)
|
||||
from .service import LicenseService
|
||||
|
||||
router = APIRouter(prefix="/licenses", tags=["Licenses"])
|
||||
router = APIRouter(prefix="/licenses")
|
||||
|
||||
|
||||
@router.post("/", response_model=LicenseResponseDTO, status_code=201)
|
||||
|
||||
6
backend/api/v1/modules/a76/parts/__init__.py
Normal file
6
backend/api/v1/modules/a76/parts/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
"""
|
||||
Módulo de GParts
|
||||
"""
|
||||
from .routes import router
|
||||
|
||||
__all__ = ["router"]
|
||||
182
backend/api/v1/modules/a76/parts/dto.py
Normal file
182
backend/api/v1/modules/a76/parts/dto.py
Normal file
@@ -0,0 +1,182 @@
|
||||
"""
|
||||
DTOs (Data Transfer Objects) para módulo de partes/componentes
|
||||
Reemplaza schemas.py siguiendo enfoque DDD y estilo NestJS
|
||||
"""
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
|
||||
|
||||
class PartCreateDTO(BaseModel):
|
||||
"""DTO para crear una parte"""
|
||||
client_key: int = Field(..., description="Client key")
|
||||
part_number: str = Field(..., max_length=49, description="Part number")
|
||||
fraction: Optional[str] = Field(None, max_length=10, description="Tariff fraction")
|
||||
description_spanish: Optional[str] = Field(None, max_length=500, description="Description in Spanish")
|
||||
description_english: Optional[str] = Field(None, max_length=500, description="Description in English")
|
||||
part_class: Optional[str] = Field(None, max_length=8, description="Part class")
|
||||
unit_of_measure: Optional[str] = Field(None, max_length=5, description="Unit of measure")
|
||||
commercial_part_number: Optional[str] = Field(None, max_length=70, description="Commercial part number")
|
||||
country_of_origin: Optional[str] = Field(None, max_length=3, description="Country of origin code")
|
||||
|
||||
# Pricing and currency
|
||||
unit_cost: Optional[Decimal] = Field(None, description="Unit cost")
|
||||
currency_type: Optional[str] = Field(None, max_length=2, description="Currency type")
|
||||
currency_key: Optional[str] = Field(None, max_length=3, description="Currency key")
|
||||
|
||||
# Weight information
|
||||
unit_weight: Optional[Decimal] = Field(None, description="Unit weight")
|
||||
weight_type: Optional[str] = Field(None, max_length=6, description="Weight type")
|
||||
|
||||
# Classification and regulatory
|
||||
us_fraction: Optional[str] = Field(None, max_length=16, description="US tariff fraction")
|
||||
fda_key: Optional[str] = Field(None, max_length=20, description="FDA key")
|
||||
fcc_key: Optional[str] = Field(None, max_length=30, description="FCC key")
|
||||
license_code: Optional[str] = Field(None, max_length=3, description="License code")
|
||||
eccn: Optional[str] = Field(None, max_length=20, description="Export Control Classification Number")
|
||||
export_code: Optional[str] = Field(None, max_length=2, description="Export code")
|
||||
exclusion_symbol: Optional[str] = Field(None, max_length=19, description="Exclusion symbol")
|
||||
|
||||
# Additional information
|
||||
supplier: Optional[str] = Field(None, max_length=14, description="Supplier")
|
||||
alternate_unit_measure: Optional[str] = Field(None, max_length=14, description="Alternate unit of measure")
|
||||
added_value: Optional[Decimal] = Field(None, description="Added value")
|
||||
|
||||
# Status and media
|
||||
enabled_disabled: Optional[int] = Field(None, description="Enabled/Disabled status")
|
||||
creation_date: Optional[int] = Field(None, description="Creation date")
|
||||
part_photo: Optional[str] = Field(None, max_length=255, description="Part photo URL")
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class PartUpdateDTO(BaseModel):
|
||||
"""DTO para actualizar una parte"""
|
||||
fraction: Optional[str] = Field(None, max_length=10, description="Tariff fraction")
|
||||
description_spanish: Optional[str] = Field(None, max_length=500, description="Description in Spanish")
|
||||
description_english: Optional[str] = Field(None, max_length=500, description="Description in English")
|
||||
part_class: Optional[str] = Field(None, max_length=8, description="Part class")
|
||||
unit_of_measure: Optional[str] = Field(None, max_length=5, description="Unit of measure")
|
||||
commercial_part_number: Optional[str] = Field(None, max_length=70, description="Commercial part number")
|
||||
country_of_origin: Optional[str] = Field(None, max_length=3, description="Country of origin code")
|
||||
|
||||
# Pricing and currency
|
||||
unit_cost: Optional[Decimal] = Field(None, description="Unit cost")
|
||||
currency_type: Optional[str] = Field(None, max_length=2, description="Currency type")
|
||||
currency_key: Optional[str] = Field(None, max_length=3, description="Currency key")
|
||||
|
||||
# Weight information
|
||||
unit_weight: Optional[Decimal] = Field(None, description="Unit weight")
|
||||
weight_type: Optional[str] = Field(None, max_length=6, description="Weight type")
|
||||
|
||||
# Classification and regulatory
|
||||
us_fraction: Optional[str] = Field(None, max_length=16, description="US tariff fraction")
|
||||
fda_key: Optional[str] = Field(None, max_length=20, description="FDA key")
|
||||
fcc_key: Optional[str] = Field(None, max_length=30, description="FCC key")
|
||||
license_code: Optional[str] = Field(None, max_length=3, description="License code")
|
||||
eccn: Optional[str] = Field(None, max_length=20, description="Export Control Classification Number")
|
||||
export_code: Optional[str] = Field(None, max_length=2, description="Export code")
|
||||
exclusion_symbol: Optional[str] = Field(None, max_length=19, description="Exclusion symbol")
|
||||
|
||||
# Additional information
|
||||
supplier: Optional[str] = Field(None, max_length=14, description="Supplier")
|
||||
alternate_unit_measure: Optional[str] = Field(None, max_length=14, description="Alternate unit of measure")
|
||||
added_value: Optional[Decimal] = Field(None, description="Added value")
|
||||
|
||||
# Status and media
|
||||
enabled_disabled: Optional[int] = Field(None, description="Enabled/Disabled status")
|
||||
part_photo: Optional[str] = Field(None, max_length=255, description="Part photo URL")
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class PartResponseDTO(BaseModel):
|
||||
"""DTO para respuesta de parte"""
|
||||
client_key: int
|
||||
part_number: str
|
||||
fraction: Optional[str] = None
|
||||
description_spanish: Optional[str] = None
|
||||
description_english: Optional[str] = None
|
||||
part_class: Optional[str] = None
|
||||
unit_of_measure: Optional[str] = None
|
||||
commercial_part_number: Optional[str] = None
|
||||
country_of_origin: Optional[str] = None
|
||||
|
||||
# Pricing and currency
|
||||
unit_cost: Optional[Decimal] = None
|
||||
currency_type: Optional[str] = None
|
||||
currency_key: Optional[str] = None
|
||||
|
||||
# Weight information
|
||||
unit_weight: Optional[Decimal] = None
|
||||
weight_type: Optional[str] = None
|
||||
|
||||
# Classification and regulatory
|
||||
us_fraction: Optional[str] = None
|
||||
fda_key: Optional[str] = None
|
||||
fcc_key: Optional[str] = None
|
||||
license_code: Optional[str] = None
|
||||
eccn: Optional[str] = None
|
||||
export_code: Optional[str] = None
|
||||
exclusion_symbol: Optional[str] = None
|
||||
|
||||
# Additional information
|
||||
supplier: Optional[str] = None
|
||||
alternate_unit_measure: Optional[str] = None
|
||||
added_value: Optional[Decimal] = None
|
||||
|
||||
# Status and dates
|
||||
enabled_disabled: Optional[int] = None
|
||||
creation_date: Optional[int] = None
|
||||
modification_date: Optional[int] = None
|
||||
modification_date_iso: Optional[datetime] = None
|
||||
|
||||
# Media
|
||||
part_photo: Optional[str] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class PartBasicDTO(BaseModel):
|
||||
"""DTO para información básica de parte"""
|
||||
client_key: int
|
||||
part_number: str
|
||||
description_spanish: Optional[str] = None
|
||||
description_english: Optional[str] = None
|
||||
part_class: Optional[str] = None
|
||||
unit_cost: Optional[Decimal] = None
|
||||
currency_key: Optional[str] = None
|
||||
enabled_disabled: Optional[int] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class PartListDTO(BaseModel):
|
||||
"""DTO para lista de partes"""
|
||||
parts: list[PartBasicDTO]
|
||||
total: int
|
||||
page: int
|
||||
size: int
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class PartSearchDTO(BaseModel):
|
||||
"""DTO para búsqueda de partes"""
|
||||
client_key: Optional[int] = Field(None, description="Filter by client key")
|
||||
part_number: Optional[str] = Field(None, description="Search by part number")
|
||||
description: Optional[str] = Field(None, description="Search in descriptions")
|
||||
fraction: Optional[str] = Field(None, description="Filter by tariff fraction")
|
||||
supplier: Optional[str] = Field(None, description="Filter by supplier")
|
||||
enabled_only: bool = Field(False, description="Show only enabled parts")
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
88
backend/api/v1/modules/a76/parts/models.py
Normal file
88
backend/api/v1/modules/a76/parts/models.py
Normal file
@@ -0,0 +1,88 @@
|
||||
"""
|
||||
Modelos ORM para gestión de partes/componentes
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text, Numeric, SmallInteger, ForeignKey
|
||||
from sqlalchemy.sql import func
|
||||
from sqlalchemy.orm import relationship
|
||||
from core.database import Base
|
||||
import enum
|
||||
|
||||
# Importar modelos relacionados para type hints y relationships
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from api.v1.modules.public.reference_data.countries.models import Country
|
||||
from api.v1.modules.public.reference_data.currency_types.models import CurrencyType
|
||||
from api.v1.modules.a76.classes.models import Class
|
||||
|
||||
|
||||
class Part(Base):
|
||||
"""
|
||||
Modelo para la tabla GPartes - Información de partes en los sistemas SCAII (N), SCAF (S) Y WINSAAI (W)
|
||||
"""
|
||||
__tablename__ = "parts"
|
||||
__table_args__ = {"schema": "a76"}
|
||||
|
||||
# Primary key compuesta
|
||||
client_key = Column(Integer, primary_key=True, nullable=False)
|
||||
part_number = Column(String(49), primary_key=True, nullable=False)
|
||||
|
||||
# Basic information
|
||||
fraction = Column(String(10), nullable=True)
|
||||
description_spanish = Column(String(500), nullable=True)
|
||||
description_english = Column(String(500), nullable=True)
|
||||
part_class = Column(String(8), nullable=True)
|
||||
unit_of_measure = Column(String(5), nullable=True)
|
||||
commercial_part_number = Column(String(70), nullable=True)
|
||||
country_of_origin = Column(String(3), ForeignKey('public.countries.m3_key'), nullable=True)
|
||||
|
||||
# Pricing and currency
|
||||
unit_cost = Column(Numeric(23, 8), nullable=True)
|
||||
currency_type = Column(String(2), nullable=True)
|
||||
currency_key = Column(String(3), ForeignKey('public.currency_types.code'), nullable=True)
|
||||
|
||||
# Weight information
|
||||
unit_weight = Column(Numeric(19, 8), nullable=True)
|
||||
weight_type = Column(String(6), nullable=True)
|
||||
|
||||
# Classification and regulatory
|
||||
us_fraction = Column(String(16), nullable=True) # FRACCIONAME
|
||||
fda_key = Column(String(20), nullable=True)
|
||||
fcc_key = Column(String(30), nullable=True)
|
||||
license_code = Column(String(3), nullable=True)
|
||||
eccn = Column(String(20), nullable=True) # Export Control Classification Number
|
||||
export_code = Column(String(2), nullable=True)
|
||||
exclusion_symbol = Column(String(19), nullable=True) # SIMBOLOEXCLIC
|
||||
|
||||
# Additional information
|
||||
supplier = Column(String(14), nullable=True)
|
||||
alternate_unit_measure = Column(String(14), nullable=True)
|
||||
added_value = Column(Numeric(23, 8), nullable=True)
|
||||
|
||||
# Status and dates
|
||||
enabled_disabled = Column(SmallInteger, nullable=True)
|
||||
creation_date = Column(Integer, nullable=True) # FECHACREACIONPARTE
|
||||
modification_date = Column(Integer, nullable=True) # FECHAMODIFICA
|
||||
modification_date_iso = Column(DateTime(timezone=True), nullable=True) # FECHAMODIFICA_ISO
|
||||
|
||||
# Media
|
||||
part_photo = Column(String(255), nullable=True)
|
||||
|
||||
# Relationships
|
||||
country = relationship("Country", foreign_keys=[country_of_origin])
|
||||
currency = relationship("CurrencyType", foreign_keys=[currency_key])
|
||||
|
||||
# Relationship with Class through composite foreign key
|
||||
# Note: This requires both client_key and part_class to match client_key and class_code in Class
|
||||
part_class_info = relationship(
|
||||
"Class",
|
||||
primaryjoin="and_(Part.client_key == Class.client_key, Part.part_class == Class.class_code)",
|
||||
foreign_keys="[Part.client_key, Part.part_class]",
|
||||
viewonly=True,
|
||||
back_populates="parts"
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Part(client_key={self.client_key}, part_number='{self.part_number}', description='{self.description_spanish}')>"
|
||||
|
||||
|
||||
273
backend/api/v1/modules/a76/parts/routes.py
Normal file
273
backend/api/v1/modules/a76/parts/routes.py
Normal file
@@ -0,0 +1,273 @@
|
||||
"""
|
||||
Endpoints API para gestión de partes/componentes
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List, Optional
|
||||
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, has_role
|
||||
from .service import PartService
|
||||
from .dto import (
|
||||
PartCreateDTO,
|
||||
PartUpdateDTO,
|
||||
PartResponseDTO,
|
||||
PartBasicDTO,
|
||||
PartListDTO,
|
||||
PartSearchDTO
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/parts")
|
||||
|
||||
|
||||
@router.post("/", response_model=PartResponseDTO, status_code=status.HTTP_201_CREATED)
|
||||
async def create_part(
|
||||
part_data: PartCreateDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Create a new part in the system
|
||||
"""
|
||||
service = PartService(db)
|
||||
return service.create_part(part_data)
|
||||
|
||||
|
||||
@router.get("/", response_model=PartListDTO)
|
||||
async def list_parts(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum number of records to return"),
|
||||
client_key: Optional[int] = Query(None, description="Filter by client key"),
|
||||
part_number: Optional[str] = Query(None, description="Search by part number"),
|
||||
description: Optional[str] = Query(None, description="Search in descriptions"),
|
||||
fraction: Optional[str] = Query(None, description="Filter by tariff fraction"),
|
||||
supplier: Optional[str] = Query(None, description="Filter by supplier"),
|
||||
enabled_only: bool = Query(False, description="Show only enabled parts"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
List parts with optional filters and pagination
|
||||
"""
|
||||
service = PartService(db)
|
||||
search_params = PartSearchDTO(
|
||||
client_key=client_key,
|
||||
part_number=part_number,
|
||||
description=description,
|
||||
fraction=fraction,
|
||||
supplier=supplier,
|
||||
enabled_only=enabled_only
|
||||
)
|
||||
return service.list_parts(skip, limit, search_params)
|
||||
|
||||
|
||||
@router.get("/client/{client_key}", response_model=List[PartBasicDTO])
|
||||
async def get_parts_by_client(
|
||||
client_key: int,
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get all parts for a specific client
|
||||
"""
|
||||
service = PartService(db)
|
||||
return service.search_by_client(client_key, skip, limit)
|
||||
|
||||
|
||||
@router.get("/search/fraction/{fraction}", response_model=List[PartBasicDTO])
|
||||
async def search_by_fraction(
|
||||
fraction: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Search parts by tariff fraction
|
||||
"""
|
||||
service = PartService(db)
|
||||
return service.search_by_fraction(fraction)
|
||||
|
||||
|
||||
@router.get("/search/supplier/{supplier}", response_model=List[PartBasicDTO])
|
||||
async def search_by_supplier(
|
||||
supplier: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Search parts by supplier
|
||||
"""
|
||||
service = PartService(db)
|
||||
return service.search_by_supplier(supplier)
|
||||
|
||||
|
||||
@router.get("/search/country/{country_code}", response_model=List[PartBasicDTO])
|
||||
async def get_parts_by_country(
|
||||
country_code: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get parts by country of origin
|
||||
"""
|
||||
service = PartService(db)
|
||||
return service.get_parts_by_country(country_code)
|
||||
|
||||
|
||||
@router.get("/statistics", response_model=dict)
|
||||
async def get_parts_statistics(
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get basic parts statistics
|
||||
"""
|
||||
service = PartService(db)
|
||||
return service.get_parts_statistics()
|
||||
|
||||
|
||||
@router.get("/{client_key}/{part_number}", response_model=PartResponseDTO)
|
||||
async def get_part(
|
||||
client_key: int,
|
||||
part_number: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get part by composite key (client_key + part_number)
|
||||
"""
|
||||
service = PartService(db)
|
||||
part = service.get_part(client_key, part_number)
|
||||
if not part:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Part with client_key '{client_key}' and part_number '{part_number}' not found"
|
||||
)
|
||||
return part
|
||||
|
||||
|
||||
@router.put("/{client_key}/{part_number}", response_model=PartResponseDTO)
|
||||
async def update_part(
|
||||
client_key: int,
|
||||
part_number: str,
|
||||
part_data: PartUpdateDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Update part information
|
||||
"""
|
||||
service = PartService(db)
|
||||
part = service.update_part(client_key, part_number, part_data)
|
||||
if not part:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Part with client_key '{client_key}' and part_number '{part_number}' not found"
|
||||
)
|
||||
return part
|
||||
|
||||
|
||||
@router.delete("/{client_key}/{part_number}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_part(
|
||||
client_key: int,
|
||||
part_number: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Delete part from the system
|
||||
|
||||
Note: This will completely remove the part from the system.
|
||||
"""
|
||||
service = PartService(db)
|
||||
if not service.delete_part(client_key, part_number):
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Part with client_key '{client_key}' and part_number '{part_number}' not found"
|
||||
)
|
||||
|
||||
|
||||
@router.patch("/{client_key}/{part_number}/toggle-status", response_model=PartResponseDTO)
|
||||
async def toggle_part_status(
|
||||
client_key: int,
|
||||
part_number: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Toggle part enabled/disabled status
|
||||
"""
|
||||
service = PartService(db)
|
||||
part = service.toggle_status(client_key, part_number)
|
||||
if not part:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Part with client_key '{client_key}' and part_number '{part_number}' not found"
|
||||
)
|
||||
return part
|
||||
|
||||
|
||||
# Endpoints específicos para información detallada
|
||||
@router.get("/{client_key}/{part_number}/basic", response_model=PartBasicDTO)
|
||||
async def get_part_basic_info(
|
||||
client_key: int,
|
||||
part_number: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get basic information for a part
|
||||
"""
|
||||
service = PartService(db)
|
||||
part = service.get_part(client_key, part_number)
|
||||
if not part:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Part with client_key '{client_key}' and part_number '{part_number}' not found"
|
||||
)
|
||||
|
||||
return PartBasicDTO(
|
||||
client_key=part.client_key,
|
||||
part_number=part.part_number,
|
||||
description_spanish=part.description_spanish,
|
||||
description_english=part.description_english,
|
||||
part_class=part.part_class,
|
||||
unit_cost=part.unit_cost,
|
||||
currency_key=part.currency_key,
|
||||
enabled_disabled=part.enabled_disabled
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{client_key}/{part_number}/regulatory", response_model=dict)
|
||||
async def get_part_regulatory_info(
|
||||
client_key: int,
|
||||
part_number: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get regulatory information for a part (FDA, FCC, ECCN, etc.)
|
||||
"""
|
||||
service = PartService(db)
|
||||
part = service.get_part(client_key, part_number)
|
||||
if not part:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Part with client_key '{client_key}' and part_number '{part_number}' not found"
|
||||
)
|
||||
|
||||
return {
|
||||
"client_key": part.client_key,
|
||||
"part_number": part.part_number,
|
||||
"fraction": part.fraction,
|
||||
"us_fraction": part.us_fraction,
|
||||
"fda_key": part.fda_key,
|
||||
"fcc_key": part.fcc_key,
|
||||
"license_code": part.license_code,
|
||||
"eccn": part.eccn,
|
||||
"export_code": part.export_code,
|
||||
"exclusion_symbol": part.exclusion_symbol
|
||||
}
|
||||
|
||||
|
||||
275
backend/api/v1/modules/a76/parts/service.py
Normal file
275
backend/api/v1/modules/a76/parts/service.py
Normal file
@@ -0,0 +1,275 @@
|
||||
"""
|
||||
Capa de servicio para lógica de negocio de partes/componentes
|
||||
"""
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy import or_, and_, func
|
||||
from fastapi import HTTPException
|
||||
from typing import List, Optional
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
from .models import Part
|
||||
from .dto import PartCreateDTO, PartUpdateDTO
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PartService:
|
||||
"""
|
||||
Servicio para gestión de partes/componentes
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def create_part(db: Session, part_data: PartCreateDTO) -> Part:
|
||||
"""
|
||||
Crear una nueva parte
|
||||
"""
|
||||
try:
|
||||
db_part = Part(**part_data.model_dump())
|
||||
db.add(db_part)
|
||||
db.commit()
|
||||
db.refresh(db_part)
|
||||
return db_part
|
||||
except IntegrityError as e:
|
||||
db.rollback()
|
||||
logger.error(f"Error creating part: {e}")
|
||||
raise HTTPException(status_code=400, detail="Part with this client_key and part_number already exists")
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f"Unexpected error creating part: {e}")
|
||||
raise HTTPException(status_code=500, detail="Error creating part")
|
||||
|
||||
@staticmethod
|
||||
def get_part(db: Session, client_key: int, part_number: str) -> Optional[Part]:
|
||||
"""
|
||||
Obtener una parte por clave de cliente y número de parte
|
||||
"""
|
||||
try:
|
||||
return db.query(Part).filter(
|
||||
and_(
|
||||
Part.client_key == client_key,
|
||||
Part.part_number == part_number
|
||||
)
|
||||
).first()
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting part: {e}")
|
||||
raise HTTPException(status_code=500, detail="Error retrieving part")
|
||||
|
||||
@staticmethod
|
||||
def get_parts_paginated(
|
||||
db: Session,
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
search: Optional[str] = None,
|
||||
client_key: Optional[int] = None,
|
||||
fraction: Optional[str] = None,
|
||||
country_of_origin: Optional[str] = None
|
||||
) -> tuple[List[Part], int]:
|
||||
"""
|
||||
Obtener partes con paginación y filtros
|
||||
"""
|
||||
try:
|
||||
query = db.query(Part)
|
||||
|
||||
# Aplicar filtros
|
||||
if search:
|
||||
query = query.filter(or_(
|
||||
Part.description_spanish.ilike(f"%{search}%"),
|
||||
Part.description_english.ilike(f"%{search}%"),
|
||||
Part.part_number.ilike(f"%{search}%")
|
||||
))
|
||||
|
||||
if client_key is not None:
|
||||
query = query.filter(Part.client_key == client_key)
|
||||
|
||||
if fraction:
|
||||
query = query.filter(Part.fraction == fraction)
|
||||
|
||||
if country_of_origin:
|
||||
query = query.filter(Part.country_of_origin == country_of_origin)
|
||||
|
||||
# Contar total
|
||||
total = query.count()
|
||||
|
||||
# Aplicar paginación
|
||||
parts = query.offset(skip).limit(limit).all()
|
||||
|
||||
return parts, total
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting paginated parts: {e}")
|
||||
raise HTTPException(status_code=500, detail="Error retrieving parts")
|
||||
|
||||
@staticmethod
|
||||
def get_parts_by_client(db: Session, client_key: int) -> List[Part]:
|
||||
"""
|
||||
Obtener todas las partes de un cliente específico
|
||||
"""
|
||||
try:
|
||||
return db.query(Part).filter(Part.client_key == client_key).all()
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting parts by client: {e}")
|
||||
raise HTTPException(status_code=500, detail="Error retrieving client parts")
|
||||
|
||||
@staticmethod
|
||||
def search_parts_by_fraction(db: Session, fraction: str) -> List[Part]:
|
||||
"""
|
||||
Buscar partes por fracción arancelaria
|
||||
"""
|
||||
try:
|
||||
return db.query(Part).filter(
|
||||
or_(
|
||||
Part.fraction.ilike(f"%{fraction}%"),
|
||||
Part.us_fraction.ilike(f"%{fraction}%")
|
||||
)
|
||||
).all()
|
||||
except Exception as e:
|
||||
logger.error(f"Error searching parts by fraction: {e}")
|
||||
raise HTTPException(status_code=500, detail="Error searching parts by fraction")
|
||||
|
||||
@staticmethod
|
||||
def search_parts_by_supplier(db: Session, supplier: str) -> List[Part]:
|
||||
"""
|
||||
Buscar partes por proveedor
|
||||
"""
|
||||
try:
|
||||
return db.query(Part).filter(Part.supplier.ilike(f"%{supplier}%")).all()
|
||||
except Exception as e:
|
||||
logger.error(f"Error searching parts by supplier: {e}")
|
||||
raise HTTPException(status_code=500, detail="Error searching parts by supplier")
|
||||
|
||||
@staticmethod
|
||||
def search_parts_by_country(db: Session, country_code: str) -> List[Part]:
|
||||
"""
|
||||
Buscar partes por país de origen
|
||||
"""
|
||||
try:
|
||||
return db.query(Part).filter(Part.country_of_origin == country_code).all()
|
||||
except Exception as e:
|
||||
logger.error(f"Error searching parts by country: {e}")
|
||||
raise HTTPException(status_code=500, detail="Error searching parts by country")
|
||||
|
||||
@staticmethod
|
||||
def update_part(db: Session, client_key: int, part_number: str, part_data: PartUpdateDTO) -> Optional[Part]:
|
||||
"""
|
||||
Actualizar una parte existente
|
||||
"""
|
||||
try:
|
||||
db_part = PartService.get_part(db, client_key, part_number)
|
||||
if not db_part:
|
||||
return None
|
||||
|
||||
# Actualizar campos
|
||||
for field, value in part_data.model_dump(exclude_unset=True).items():
|
||||
setattr(db_part, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(db_part)
|
||||
return db_part
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f"Error updating part: {e}")
|
||||
raise HTTPException(status_code=500, detail="Error updating part")
|
||||
|
||||
@staticmethod
|
||||
def delete_part(db: Session, client_key: int, part_number: str) -> bool:
|
||||
"""
|
||||
Eliminar una parte
|
||||
"""
|
||||
try:
|
||||
db_part = PartService.get_part(db, client_key, part_number)
|
||||
if not db_part:
|
||||
return False
|
||||
|
||||
db.delete(db_part)
|
||||
db.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f"Error deleting part: {e}")
|
||||
raise HTTPException(status_code=500, detail="Error deleting part")
|
||||
|
||||
@staticmethod
|
||||
def toggle_part_status(db: Session, client_key: int, part_number: str) -> Optional[Part]:
|
||||
"""
|
||||
Cambiar el estado habilitado/deshabilitado de una parte
|
||||
"""
|
||||
try:
|
||||
db_part = PartService.get_part(db, client_key, part_number)
|
||||
if not db_part:
|
||||
return None
|
||||
|
||||
# Toggle status (assuming 1 = enabled, 0 = disabled)
|
||||
db_part.enabled_disabled = 1 if db_part.enabled_disabled == 0 else 0
|
||||
|
||||
db.commit()
|
||||
db.refresh(db_part)
|
||||
return db_part
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f"Error toggling part status: {e}")
|
||||
raise HTTPException(status_code=500, detail="Error toggling part status")
|
||||
|
||||
@staticmethod
|
||||
def get_parts_statistics(db: Session) -> dict:
|
||||
"""
|
||||
Obtener estadísticas de partes
|
||||
"""
|
||||
try:
|
||||
total_parts = db.query(Part).count()
|
||||
|
||||
# Partes por cliente
|
||||
parts_by_client = db.query(
|
||||
Part.client_key,
|
||||
func.count(Part.part_number).label('count')
|
||||
).group_by(Part.client_key).all()
|
||||
|
||||
# Partes por país de origen
|
||||
parts_by_country = db.query(
|
||||
Part.country_of_origin,
|
||||
func.count(Part.part_number).label('count')
|
||||
).filter(Part.country_of_origin.isnot(None))\
|
||||
.group_by(Part.country_of_origin).all()
|
||||
|
||||
# Partes habilitadas vs deshabilitadas
|
||||
enabled_parts = db.query(Part).filter(Part.enabled_disabled == 1).count()
|
||||
disabled_parts = db.query(Part).filter(Part.enabled_disabled == 0).count()
|
||||
|
||||
return {
|
||||
"total_parts": total_parts,
|
||||
"enabled_parts": enabled_parts,
|
||||
"disabled_parts": disabled_parts,
|
||||
"parts_by_client": [{"client_key": item[0], "count": item[1]} for item in parts_by_client],
|
||||
"parts_by_country": [{"country": item[0], "count": item[1]} for item in parts_by_country]
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting parts statistics: {e}")
|
||||
raise HTTPException(status_code=500, detail="Error retrieving parts statistics")
|
||||
|
||||
@staticmethod
|
||||
def get_part_regulatory_info(db: Session, client_key: int, part_number: str) -> Optional[dict]:
|
||||
"""
|
||||
Obtener información regulatoria específica de una parte
|
||||
"""
|
||||
try:
|
||||
db_part = PartService.get_part(db, client_key, part_number)
|
||||
if not db_part:
|
||||
return None
|
||||
|
||||
return {
|
||||
"client_key": db_part.client_key,
|
||||
"part_number": db_part.part_number,
|
||||
"fraction": db_part.fraction,
|
||||
"us_fraction": db_part.us_fraction,
|
||||
"fda_key": db_part.fda_key,
|
||||
"fcc_key": db_part.fcc_key,
|
||||
"license_code": db_part.license_code,
|
||||
"eccn": db_part.eccn,
|
||||
"export_code": db_part.export_code,
|
||||
"exclusion_symbol": db_part.exclusion_symbol,
|
||||
"country_of_origin": db_part.country_of_origin
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting part regulatory info: {e}")
|
||||
raise HTTPException(status_code=500, detail="Error retrieving part regulatory information")
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PedimentoConfigAdditionalBase(BaseModel):
|
||||
"""Base schema for Pedimento Config Additional"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
add_po_identifier: Optional[int] = Field(None, description="Add PO identifier")
|
||||
do_not_exempt_norms_complement_x: Optional[int] = Field(None, description="Do not exempt norms complement X")
|
||||
manual_pedimento_year: Optional[str] = Field(None, max_length=2, description="Manual pedimento year")
|
||||
enable_import_invoice_recipient: Optional[int] = Field(None, description="Enable import invoice recipient")
|
||||
send_502_validation_file_for_consolidated: Optional[int] = Field(None, description="Send 502 validation file for consolidated")
|
||||
add_remove_norms: Optional[int] = Field(None, description="Add/remove norms")
|
||||
|
||||
|
||||
class PedimentoConfigAdditionalCreate(PedimentoConfigAdditionalBase):
|
||||
"""Schema for creating a new Pedimento Config Additional"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoConfigAdditionalUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Config Additional"""
|
||||
add_po_identifier: Optional[int] = None
|
||||
do_not_exempt_norms_complement_x: Optional[int] = None
|
||||
manual_pedimento_year: Optional[str] = Field(None, max_length=2)
|
||||
enable_import_invoice_recipient: Optional[int] = None
|
||||
send_502_validation_file_for_consolidated: Optional[int] = None
|
||||
add_remove_norms: Optional[int] = None
|
||||
|
||||
|
||||
class PedimentoConfigAdditionalResponse(PedimentoConfigAdditionalBase):
|
||||
"""Schema for Pedimento Config Additional response"""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,46 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PedimentoConfigCalculationsBase(BaseModel):
|
||||
"""Base schema for Pedimento Config Calculations"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
dta_type: Optional[str] = Field(None, max_length=1, description="DTA type")
|
||||
dta_operation: Optional[int] = Field(None, description="DTA operation")
|
||||
dta_vehicle_count: Optional[int] = Field(None, description="DTA vehicle count")
|
||||
dta_mixed_rate_8permil: Optional[int] = Field(None, description="DTA mixed rate 8 per mil")
|
||||
pays_vat: Optional[int] = Field(None, description="Pays VAT")
|
||||
pays_prevalidation: Optional[int] = Field(None, description="Pays prevalidation")
|
||||
include_sagar_certificate_fee: Optional[int] = Field(None, description="Include SAGAR certificate fee")
|
||||
fixed_vehicle_dta_fee: Optional[int] = Field(None, description="Fixed vehicle DTA fee")
|
||||
additional_fixed_fee: Optional[int] = Field(None, description="Additional fixed fee")
|
||||
additional_fixed_fee_payment_method: Optional[int] = Field(None, description="Additional fixed fee payment method")
|
||||
|
||||
|
||||
class PedimentoConfigCalculationsCreate(PedimentoConfigCalculationsBase):
|
||||
"""Schema for creating a new Pedimento Config Calculations"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoConfigCalculationsUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Config Calculations"""
|
||||
dta_type: Optional[str] = Field(None, max_length=1)
|
||||
dta_operation: Optional[int] = None
|
||||
dta_vehicle_count: Optional[int] = None
|
||||
dta_mixed_rate_8permil: Optional[int] = None
|
||||
pays_vat: Optional[int] = None
|
||||
pays_prevalidation: Optional[int] = None
|
||||
include_sagar_certificate_fee: Optional[int] = None
|
||||
fixed_vehicle_dta_fee: Optional[int] = None
|
||||
additional_fixed_fee: Optional[int] = None
|
||||
additional_fixed_fee_payment_method: Optional[int] = None
|
||||
|
||||
|
||||
class PedimentoConfigCalculationsResponse(PedimentoConfigCalculationsBase):
|
||||
"""Schema for Pedimento Config Calculations response"""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,49 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from decimal import Decimal
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PedimentoConfigParametersBase(BaseModel):
|
||||
"""Base schema for Pedimento Config Parameters"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
is_embassy: Optional[int] = Field(None, description="Is embassy")
|
||||
embassy_dta: Optional[Decimal] = Field(None, description="Embassy DTA")
|
||||
rule_3121_section_ii: Optional[int] = Field(None, description="Rule 3.1.21 Section II")
|
||||
use_previous_tariff: Optional[int] = Field(None, description="Use previous tariff")
|
||||
use_payment_date_fi: Optional[int] = Field(None, description="Use payment date FI")
|
||||
add_state_supplier_record_505: Optional[int] = Field(None, description="Add state supplier record 505")
|
||||
customs_value_calculation: Optional[int] = Field(None, description="Customs value calculation")
|
||||
two_decimals_unit_value: Optional[int] = Field(None, description="Two decimals unit value")
|
||||
customs_value_per_item: Optional[int] = Field(None, description="Customs value per item")
|
||||
is_national_supplier: Optional[int] = Field(None, description="Is national supplier")
|
||||
is_consolidated: Optional[int] = Field(None, description="Is consolidated")
|
||||
|
||||
|
||||
class PedimentoConfigParametersCreate(PedimentoConfigParametersBase):
|
||||
"""Schema for creating a new Pedimento Config Parameters"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoConfigParametersUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Config Parameters"""
|
||||
is_embassy: Optional[int] = None
|
||||
embassy_dta: Optional[Decimal] = None
|
||||
rule_3121_section_ii: Optional[int] = None
|
||||
use_previous_tariff: Optional[int] = None
|
||||
use_payment_date_fi: Optional[int] = None
|
||||
add_state_supplier_record_505: Optional[int] = None
|
||||
customs_value_calculation: Optional[int] = None
|
||||
two_decimals_unit_value: Optional[int] = None
|
||||
customs_value_per_item: Optional[int] = None
|
||||
is_national_supplier: Optional[int] = None
|
||||
is_consolidated: Optional[int] = None
|
||||
|
||||
|
||||
class PedimentoConfigParametersResponse(PedimentoConfigParametersBase):
|
||||
"""Schema for Pedimento Config Parameters response"""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,38 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PedimentoConfigSurchargesBase(BaseModel):
|
||||
"""Base schema for Pedimento Config Surcharges"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
surcharge_igi: Optional[int] = Field(None, description="Surcharge IGI")
|
||||
surcharge_dta: Optional[int] = Field(None, description="Surcharge DTA")
|
||||
surcharge_vat: Optional[int] = Field(None, description="Surcharge VAT")
|
||||
surcharge_isan: Optional[int] = Field(None, description="Surcharge ISAN")
|
||||
surcharge_ieps: Optional[int] = Field(None, description="Surcharge IEPS")
|
||||
surcharge_cc: Optional[int] = Field(None, description="Surcharge CC")
|
||||
|
||||
|
||||
class PedimentoConfigSurchargesCreate(PedimentoConfigSurchargesBase):
|
||||
"""Schema for creating a new Pedimento Config Surcharges"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoConfigSurchargesUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Config Surcharges"""
|
||||
surcharge_igi: Optional[int] = None
|
||||
surcharge_dta: Optional[int] = None
|
||||
surcharge_vat: Optional[int] = None
|
||||
surcharge_isan: Optional[int] = None
|
||||
surcharge_ieps: Optional[int] = None
|
||||
surcharge_cc: Optional[int] = None
|
||||
|
||||
|
||||
class PedimentoConfigSurchargesResponse(PedimentoConfigSurchargesBase):
|
||||
"""Schema for Pedimento Config Surcharges response"""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,36 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PedimentoConfigUpdateRectificationBase(BaseModel):
|
||||
"""Base schema for Pedimento Config Update Rectification"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
update_vat: Optional[int] = Field(None, description="Update VAT")
|
||||
update_advalorem: Optional[int] = Field(None, description="Update advalorem")
|
||||
update_cc: Optional[int] = Field(None, description="Update CC")
|
||||
update_ieps: Optional[int] = Field(None, description="Update IEPS")
|
||||
calculate_surcharge: Optional[int] = Field(None, description="Calculate surcharge")
|
||||
|
||||
|
||||
class PedimentoConfigUpdateRectificationCreate(PedimentoConfigUpdateRectificationBase):
|
||||
"""Schema for creating a new Pedimento Config Update Rectification"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoConfigUpdateRectificationUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Config Update Rectification"""
|
||||
update_vat: Optional[int] = None
|
||||
update_advalorem: Optional[int] = None
|
||||
update_cc: Optional[int] = None
|
||||
update_ieps: Optional[int] = None
|
||||
calculate_surcharge: Optional[int] = None
|
||||
|
||||
|
||||
class PedimentoConfigUpdateRectificationResponse(PedimentoConfigUpdateRectificationBase):
|
||||
"""Schema for Pedimento Config Update Rectification response"""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,34 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PedimentoConfigUpdatesBase(BaseModel):
|
||||
"""Base schema for Pedimento Config Updates"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
update_vat: Optional[int] = Field(None, description="Update VAT")
|
||||
update_advalorem: Optional[int] = Field(None, description="Update advalorem")
|
||||
update_cc: Optional[int] = Field(None, description="Update CC")
|
||||
update_ieps: Optional[int] = Field(None, description="Update IEPS")
|
||||
|
||||
|
||||
class PedimentoConfigUpdatesCreate(PedimentoConfigUpdatesBase):
|
||||
"""Schema for creating a new Pedimento Config Updates"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoConfigUpdatesUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Config Updates"""
|
||||
update_vat: Optional[int] = None
|
||||
update_advalorem: Optional[int] = None
|
||||
update_cc: Optional[int] = None
|
||||
update_ieps: Optional[int] = None
|
||||
|
||||
|
||||
class PedimentoConfigUpdatesResponse(PedimentoConfigUpdatesBase):
|
||||
"""Schema for Pedimento Config Updates response"""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,30 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PedimentoCustomsOfficesBase(BaseModel):
|
||||
"""Base schema for Pedimento Customs Offices"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
dispatch_customs: Optional[str] = Field(None, max_length=3, description="Dispatch customs")
|
||||
entry_exit_customs: Optional[str] = Field(None, max_length=3, description="Entry/exit customs")
|
||||
|
||||
|
||||
class PedimentoCustomsOfficesCreate(PedimentoCustomsOfficesBase):
|
||||
"""Schema for creating a new Pedimento Customs Offices"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoCustomsOfficesUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Customs Offices"""
|
||||
dispatch_customs: Optional[str] = Field(None, max_length=3)
|
||||
entry_exit_customs: Optional[str] = Field(None, max_length=3)
|
||||
|
||||
|
||||
class PedimentoCustomsOfficesResponse(PedimentoCustomsOfficesBase):
|
||||
"""Schema for Pedimento Customs Offices response"""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,50 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from datetime import datetime, time
|
||||
|
||||
|
||||
class PedimentoDatesBase(BaseModel):
|
||||
"""Base schema for Pedimento Dates"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
entry_date: Optional[datetime] = Field(None, description="Entry date")
|
||||
pedimento_date: Optional[datetime] = Field(None, description="Pedimento date")
|
||||
payment_date: Optional[datetime] = Field(None, description="Payment date")
|
||||
rectification_payment_date: Optional[datetime] = Field(None, description="Rectification payment date")
|
||||
extraction_date: Optional[datetime] = Field(None, description="Extraction date")
|
||||
submission_date: Optional[datetime] = Field(None, description="Submission date")
|
||||
eucan_date: Optional[datetime] = Field(None, description="EUCAN date")
|
||||
original_date: Optional[datetime] = Field(None, description="Original date")
|
||||
start_date: Optional[datetime] = Field(None, description="Start date")
|
||||
end_date: Optional[datetime] = Field(None, description="End date")
|
||||
capture_date: Optional[datetime] = Field(None, description="Capture date")
|
||||
capture_time: Optional[time] = Field(None, description="Capture time")
|
||||
|
||||
|
||||
class PedimentoDatesCreate(PedimentoDatesBase):
|
||||
"""Schema for creating a new Pedimento Dates"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoDatesUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Dates"""
|
||||
entry_date: Optional[datetime] = None
|
||||
pedimento_date: Optional[datetime] = None
|
||||
payment_date: Optional[datetime] = None
|
||||
rectification_payment_date: Optional[datetime] = None
|
||||
extraction_date: Optional[datetime] = None
|
||||
submission_date: Optional[datetime] = None
|
||||
eucan_date: Optional[datetime] = None
|
||||
original_date: Optional[datetime] = None
|
||||
start_date: Optional[datetime] = None
|
||||
end_date: Optional[datetime] = None
|
||||
capture_date: Optional[datetime] = None
|
||||
capture_time: Optional[time] = None
|
||||
|
||||
|
||||
class PedimentoDatesResponse(PedimentoDatesBase):
|
||||
"""Schema for Pedimento Dates response"""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,45 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from decimal import Decimal
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PedimentoDecrementablesBase(BaseModel):
|
||||
"""Base schema for Pedimento Decrementables"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
freight: Optional[Decimal] = Field(None, description="Freight")
|
||||
insurance: Optional[Decimal] = Field(None, description="Insurance")
|
||||
loading: Optional[Decimal] = Field(None, description="Loading")
|
||||
unloading: Optional[Decimal] = Field(None, description="Unloading")
|
||||
others: Optional[Decimal] = Field(None, description="Others")
|
||||
currency: Optional[str] = Field(None, max_length=3, description="Currency")
|
||||
currency_factor: Optional[Decimal] = Field(None, description="Currency factor")
|
||||
not_affect_usd_value: Optional[int] = Field(None, description="Not affect USD value")
|
||||
not_affect_customs_value: Optional[int] = Field(None, description="Not affect customs value")
|
||||
|
||||
|
||||
class PedimentoDecrementablesCreate(PedimentoDecrementablesBase):
|
||||
"""Schema for creating a new Pedimento Decrementables"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoDecrementablesUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Decrementables"""
|
||||
freight: Optional[Decimal] = None
|
||||
insurance: Optional[Decimal] = None
|
||||
loading: Optional[Decimal] = None
|
||||
unloading: Optional[Decimal] = None
|
||||
others: Optional[Decimal] = None
|
||||
currency: Optional[str] = Field(None, max_length=3)
|
||||
currency_factor: Optional[Decimal] = None
|
||||
not_affect_usd_value: Optional[int] = None
|
||||
not_affect_customs_value: Optional[int] = None
|
||||
|
||||
|
||||
class PedimentoDecrementablesResponse(PedimentoDecrementablesBase):
|
||||
"""Schema for Pedimento Decrementables response"""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,47 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from decimal import Decimal
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PedimentoIncrementablesBase(BaseModel):
|
||||
"""Base schema for Pedimento Incrementables"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
insured_value: Optional[Decimal] = Field(None, description="Insured value")
|
||||
freight: Optional[Decimal] = Field(None, description="Freight")
|
||||
insurance: Optional[Decimal] = Field(None, description="Insurance")
|
||||
packaging: Optional[Decimal] = Field(None, description="Packaging")
|
||||
others: Optional[Decimal] = Field(None, description="Others")
|
||||
deductibles: Optional[Decimal] = Field(None, description="Deductibles")
|
||||
currency: Optional[str] = Field(None, max_length=3, description="Currency")
|
||||
currency_factor: Optional[Decimal] = Field(None, description="Currency factor")
|
||||
not_affect_usd_value: Optional[int] = Field(None, description="Not affect USD value")
|
||||
not_affect_customs_value: Optional[int] = Field(None, description="Not affect customs value")
|
||||
|
||||
|
||||
class PedimentoIncrementablesCreate(PedimentoIncrementablesBase):
|
||||
"""Schema for creating a new Pedimento Incrementables"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoIncrementablesUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Incrementables"""
|
||||
insured_value: Optional[Decimal] = None
|
||||
freight: Optional[Decimal] = None
|
||||
insurance: Optional[Decimal] = None
|
||||
packaging: Optional[Decimal] = None
|
||||
others: Optional[Decimal] = None
|
||||
deductibles: Optional[Decimal] = None
|
||||
currency: Optional[str] = Field(None, max_length=3)
|
||||
currency_factor: Optional[Decimal] = None
|
||||
not_affect_usd_value: Optional[int] = None
|
||||
not_affect_customs_value: Optional[int] = None
|
||||
|
||||
|
||||
class PedimentoIncrementablesResponse(PedimentoIncrementablesBase):
|
||||
"""Schema for Pedimento Incrementables response"""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,33 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from decimal import Decimal
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PedimentoIndexesBase(BaseModel):
|
||||
"""Base schema for Pedimento Indexes"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
update_factor_type: Optional[int] = Field(None, description="Update factor type")
|
||||
update_factor: Optional[Decimal] = Field(None, description="Update factor")
|
||||
manual_update_factor: Optional[int] = Field(None, description="Manual update factor")
|
||||
|
||||
|
||||
class PedimentoIndexesCreate(PedimentoIndexesBase):
|
||||
"""Schema for creating a new Pedimento Indexes"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoIndexesUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Indexes"""
|
||||
update_factor_type: Optional[int] = None
|
||||
update_factor: Optional[Decimal] = None
|
||||
manual_update_factor: Optional[int] = None
|
||||
|
||||
|
||||
class PedimentoIndexesResponse(PedimentoIndexesBase):
|
||||
"""Schema for Pedimento Indexes response"""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,50 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from datetime import datetime, date as Date, time as Time
|
||||
|
||||
|
||||
class PedimentoPaymentsBase(BaseModel):
|
||||
"""Base schema for Pedimento Payments"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
acknowledgment: Optional[str] = Field(None, max_length=20, description="Acknowledgment")
|
||||
operation_number: Optional[str] = Field(None, max_length=14, description="Operation number")
|
||||
bank_code: Optional[int] = Field(None, description="Bank code")
|
||||
cashier: Optional[str] = Field(None, max_length=2, description="Cashier")
|
||||
date: Optional[Date] = Field(None, description="Date")
|
||||
time: Optional[Time] = Field(None, description="Time")
|
||||
shift: Optional[str] = Field(None, max_length=1, description="Shift")
|
||||
total_cash_paid: Optional[int] = Field(None, description="Total cash paid")
|
||||
total_contributions: Optional[int] = Field(None, description="Total contributions")
|
||||
counter_payment: Optional[int] = Field(None, description="Counter payment")
|
||||
pece_code: Optional[str] = Field(None, max_length=5, description="PECE code")
|
||||
payment_id: Optional[int] = Field(None, description="Payment ID")
|
||||
|
||||
|
||||
class PedimentoPaymentsCreate(PedimentoPaymentsBase):
|
||||
"""Schema for creating a new Pedimento Payments"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoPaymentsUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Payments"""
|
||||
acknowledgment: Optional[str] = Field(None, max_length=20)
|
||||
operation_number: Optional[str] = Field(None, max_length=14)
|
||||
bank_code: Optional[int] = None
|
||||
cashier: Optional[str] = Field(None, max_length=2)
|
||||
date: Optional[Date] = None
|
||||
time: Optional[Time] = None
|
||||
shift: Optional[str] = Field(None, max_length=1)
|
||||
total_cash_paid: Optional[int] = None
|
||||
total_contributions: Optional[int] = None
|
||||
counter_payment: Optional[int] = None
|
||||
pece_code: Optional[str] = Field(None, max_length=5)
|
||||
payment_id: Optional[int] = None
|
||||
|
||||
|
||||
class PedimentoPaymentsResponse(PedimentoPaymentsBase):
|
||||
"""Schema for Pedimento Payments response"""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,32 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class PedimentoRectificationDestinationBase(BaseModel):
|
||||
"""Base schema for Pedimento Rectification Destination"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
destination_pedimento_year: Optional[str] = Field(None, max_length=2, description="Destination pedimento year")
|
||||
destination_customs_office: Optional[str] = Field(None, max_length=3, description="Destination customs office")
|
||||
destination_license: Optional[str] = Field(None, max_length=4, description="Destination license")
|
||||
destination_pedimento_number: Optional[str] = Field(None, max_length=7, description="Destination pedimento number")
|
||||
|
||||
|
||||
class PedimentoRectificationDestinationCreate(PedimentoRectificationDestinationBase):
|
||||
"""Schema for creating a new Pedimento Rectification Destination"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoRectificationDestinationUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Rectification Destination"""
|
||||
destination_pedimento_year: Optional[str] = Field(None, max_length=2)
|
||||
destination_customs_office: Optional[str] = Field(None, max_length=3)
|
||||
destination_license: Optional[str] = Field(None, max_length=4)
|
||||
destination_pedimento_number: Optional[str] = Field(None, max_length=7)
|
||||
|
||||
|
||||
class PedimentoRectificationDestinationResponse(PedimentoRectificationDestinationBase):
|
||||
"""Schema for Pedimento Rectification Destination response"""
|
||||
id: int
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,51 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PedimentoRectificationOriginBase(BaseModel):
|
||||
"""Base schema for Pedimento Rectification Origin"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
original_pedimento_year: Optional[str] = Field(None, max_length=2, description="Original pedimento year")
|
||||
original_customs_office: Optional[str] = Field(None, max_length=3, description="Original customs office")
|
||||
original_license: Optional[str] = Field(None, max_length=4, description="Original license")
|
||||
original_pedimento_number: Optional[str] = Field(None, max_length=7, description="Original pedimento number")
|
||||
original_pedimento_key: Optional[str] = Field(None, max_length=2, description="Original pedimento key")
|
||||
original_payment_date: Optional[datetime] = Field(None, description="Original payment date")
|
||||
total_cash: Optional[int] = Field(None, description="Total cash")
|
||||
total_others: Optional[int] = Field(None, description="Total others")
|
||||
reason: Optional[str] = Field(None, max_length=255, description="Reason")
|
||||
charge_to_client: Optional[int] = Field(None, description="Charge to client")
|
||||
use_original_payment_date_for_interest_calc: Optional[int] = Field(None, description="Use original payment date for interest calculation")
|
||||
manual_calculation: Optional[int] = Field(None, description="Manual calculation")
|
||||
original_pedimento_norms: Optional[int] = Field(None, description="Original pedimento norms")
|
||||
|
||||
|
||||
class PedimentoRectificationOriginCreate(PedimentoRectificationOriginBase):
|
||||
"""Schema for creating a new Pedimento Rectification Origin"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoRectificationOriginUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Rectification Origin"""
|
||||
original_pedimento_year: Optional[str] = Field(None, max_length=2)
|
||||
original_customs_office: Optional[str] = Field(None, max_length=3)
|
||||
original_license: Optional[str] = Field(None, max_length=4)
|
||||
original_pedimento_number: Optional[str] = Field(None, max_length=7)
|
||||
original_pedimento_key: Optional[str] = Field(None, max_length=2)
|
||||
original_payment_date: Optional[datetime] = None
|
||||
total_cash: Optional[int] = None
|
||||
total_others: Optional[int] = None
|
||||
reason: Optional[str] = Field(None, max_length=255)
|
||||
charge_to_client: Optional[int] = None
|
||||
use_original_payment_date_for_interest_calc: Optional[int] = None
|
||||
manual_calculation: Optional[int] = None
|
||||
original_pedimento_norms: Optional[int] = None
|
||||
|
||||
|
||||
class PedimentoRectificationOriginResponse(PedimentoRectificationOriginBase):
|
||||
"""Schema for Pedimento Rectification Origin response"""
|
||||
id: int
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,34 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PedimentoTransportMeansBase(BaseModel):
|
||||
"""Base schema for Pedimento Transport Means"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
destination: Optional[int] = Field(None, description="Destination")
|
||||
entry_exit: Optional[str] = Field(None, max_length=2, description="Entry/exit")
|
||||
arrival: Optional[str] = Field(None, max_length=2, description="Arrival")
|
||||
departure: Optional[str] = Field(None, max_length=2, description="Departure")
|
||||
|
||||
|
||||
class PedimentoTransportMeansCreate(PedimentoTransportMeansBase):
|
||||
"""Schema for creating a new Pedimento Transport Means"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoTransportMeansUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Transport Means"""
|
||||
destination: Optional[int] = None
|
||||
entry_exit: Optional[str] = Field(None, max_length=2)
|
||||
arrival: Optional[str] = Field(None, max_length=2)
|
||||
departure: Optional[str] = Field(None, max_length=2)
|
||||
|
||||
|
||||
class PedimentoTransportMeansResponse(PedimentoTransportMeansBase):
|
||||
"""Schema for Pedimento Transport Means response"""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,42 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PedimentoValidationBase(BaseModel):
|
||||
"""Base schema for Pedimento Validation"""
|
||||
pedimento_id: int = Field(..., description="Pedimento ID")
|
||||
tenant_id: int = Field(..., description="Tenant ID")
|
||||
validator: Optional[str] = Field(None, max_length=3, description="Validator")
|
||||
validation_ack: Optional[str] = Field(None, max_length=8, description="Validation acknowledgment")
|
||||
pre_ack: Optional[str] = Field(None, max_length=8, description="Pre-acknowledgment")
|
||||
line_signature: Optional[str] = Field(None, max_length=50, description="Line signature")
|
||||
electronic_signature: Optional[str] = Field(None, max_length=999, description="Electronic signature")
|
||||
certificate_number: Optional[str] = Field(None, max_length=99, description="Certificate number")
|
||||
validator_id: Optional[int] = Field(None, description="Validator ID")
|
||||
responsible_id: Optional[int] = Field(None, description="Responsible ID")
|
||||
|
||||
|
||||
class PedimentoValidationCreate(PedimentoValidationBase):
|
||||
"""Schema for creating a new Pedimento Validation"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentoValidationUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento Validation"""
|
||||
validator: Optional[str] = Field(None, max_length=3)
|
||||
validation_ack: Optional[str] = Field(None, max_length=8)
|
||||
pre_ack: Optional[str] = Field(None, max_length=8)
|
||||
line_signature: Optional[str] = Field(None, max_length=50)
|
||||
electronic_signature: Optional[str] = Field(None, max_length=999)
|
||||
certificate_number: Optional[str] = Field(None, max_length=99)
|
||||
validator_id: Optional[int] = None
|
||||
responsible_id: Optional[int] = None
|
||||
|
||||
|
||||
class PedimentoValidationResponse(PedimentoValidationBase):
|
||||
"""Schema for Pedimento Validation response"""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
54
backend/api/v1/modules/a76/pedmientos/dtos/pedimentos.py
Normal file
54
backend/api/v1/modules/a76/pedmientos/dtos/pedimentos.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from decimal import Decimal
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PedimentosBase(BaseModel):
|
||||
"""Base schema for Pedimentos"""
|
||||
year: Optional[str] = Field(None, max_length=2, description="Year")
|
||||
customs_office: Optional[str] = Field(None, max_length=2, description="Customs office")
|
||||
license: Optional[str] = Field(None, max_length=4, description="License")
|
||||
pedimento_number: Optional[str] = Field(None, max_length=7, description="Pedimento number")
|
||||
client_id: Optional[int] = Field(None, description="Client ID")
|
||||
operation_type: Optional[int] = Field(None, description="Operation type")
|
||||
pedimento_type: Optional[int] = Field(None, description="Pedimento type")
|
||||
pedimento_key: Optional[str] = Field(None, max_length=2, description="Pedimento key")
|
||||
regime: Optional[str] = Field(None, max_length=3, description="Regime")
|
||||
status: Optional[str] = Field(None, max_length=30, description="Status")
|
||||
usd_value: Optional[Decimal] = Field(None, description="USD value")
|
||||
paid_price: Optional[Decimal] = Field(None, description="Paid price")
|
||||
gross_weight: Optional[Decimal] = Field(None, description="Gross weight")
|
||||
exchange_rate: Optional[Decimal] = Field(None, description="Exchange rate")
|
||||
|
||||
|
||||
class PedimentosCreate(PedimentosBase):
|
||||
"""Schema for creating a new Pedimento"""
|
||||
pass
|
||||
|
||||
|
||||
class PedimentosUpdate(BaseModel):
|
||||
"""Schema for updating a Pedimento"""
|
||||
year: Optional[str] = Field(None, max_length=2)
|
||||
customs_office: Optional[str] = Field(None, max_length=2)
|
||||
license: Optional[str] = Field(None, max_length=4)
|
||||
pedimento_number: Optional[str] = Field(None, max_length=7)
|
||||
client_id: Optional[int] = None
|
||||
operation_type: Optional[int] = None
|
||||
pedimento_type: Optional[int] = None
|
||||
pedimento_key: Optional[str] = Field(None, max_length=2)
|
||||
regime: Optional[str] = Field(None, max_length=3)
|
||||
status: Optional[str] = Field(None, max_length=30)
|
||||
usd_value: Optional[Decimal] = None
|
||||
paid_price: Optional[Decimal] = None
|
||||
gross_weight: Optional[Decimal] = None
|
||||
exchange_rate: Optional[Decimal] = None
|
||||
|
||||
|
||||
class PedimentosResponse(PedimentosBase):
|
||||
"""Schema for Pedimento response"""
|
||||
id: int
|
||||
tenant_id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,27 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Integer, PrimaryKeyConstraint, SmallInteger, String, UniqueConstraint, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoConfigAdditional(Base):
|
||||
__tablename__ = 'pedimento_config_additional'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_config_additional'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_config_additional_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_config_additional_pedimento_id_key'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
add_po_identifier = mapped_column(SmallInteger)
|
||||
do_not_exempt_norms_complement_x = mapped_column(SmallInteger)
|
||||
manual_pedimento_year = mapped_column(String(2))
|
||||
enable_import_invoice_recipient = mapped_column(SmallInteger)
|
||||
send_502_validation_file_for_consolidated = mapped_column(SmallInteger)
|
||||
add_remove_norms = mapped_column(SmallInteger)
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_config_additional')
|
||||
@@ -0,0 +1,31 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Integer, PrimaryKeyConstraint, SmallInteger, String, UniqueConstraint, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoConfigCalculations(Base):
|
||||
__tablename__ = 'pedimento_config_calculations'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_config_calculations'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_config_calculations_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_config_calculations_pedimento_id_key'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
dta_type = mapped_column(String(1))
|
||||
dta_operation = mapped_column(SmallInteger)
|
||||
dta_vehicle_count = mapped_column(SmallInteger)
|
||||
dta_mixed_rate_8permil = mapped_column(SmallInteger)
|
||||
pays_vat = mapped_column(SmallInteger)
|
||||
pays_prevalidation = mapped_column(SmallInteger)
|
||||
include_sagar_certificate_fee = mapped_column(SmallInteger)
|
||||
fixed_vehicle_dta_fee = mapped_column(SmallInteger)
|
||||
additional_fixed_fee = mapped_column(SmallInteger)
|
||||
additional_fixed_fee_payment_method = mapped_column(SmallInteger)
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_config_calculations')
|
||||
@@ -0,0 +1,33 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Integer, Numeric, PrimaryKeyConstraint, SmallInteger, UniqueConstraint, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
|
||||
class PedimentoConfigParameters(Base):
|
||||
__tablename__ = 'pedimento_config_parameters'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_config_parameters'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_config_parameters_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_config_parameters_pedimento_id_key'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
is_embassy = mapped_column(SmallInteger)
|
||||
embassy_dta = mapped_column(Numeric(11, 2))
|
||||
rule_3121_section_ii = mapped_column(SmallInteger)
|
||||
use_previous_tariff = mapped_column(SmallInteger)
|
||||
use_payment_date_fi = mapped_column(SmallInteger)
|
||||
add_state_supplier_record_505 = mapped_column(SmallInteger)
|
||||
customs_value_calculation = mapped_column(SmallInteger)
|
||||
two_decimals_unit_value = mapped_column(SmallInteger)
|
||||
customs_value_per_item = mapped_column(SmallInteger)
|
||||
is_national_supplier = mapped_column(SmallInteger)
|
||||
is_consolidated = mapped_column(SmallInteger)
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_config_parameters')
|
||||
@@ -0,0 +1,27 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Integer, PrimaryKeyConstraint, SmallInteger, UniqueConstraint, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoConfigSurcharges(Base):
|
||||
__tablename__ = 'pedimento_config_surcharges'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_config_surcharges'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_config_surcharges_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_config_surcharges_pedimento_id_key'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
surcharge_igi = mapped_column(SmallInteger)
|
||||
surcharge_dta = mapped_column(SmallInteger)
|
||||
surcharge_vat = mapped_column(SmallInteger)
|
||||
surcharge_isan = mapped_column(SmallInteger)
|
||||
surcharge_ieps = mapped_column(SmallInteger)
|
||||
surcharge_cc = mapped_column(SmallInteger)
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_config_surcharges')
|
||||
@@ -0,0 +1,26 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Integer, PrimaryKeyConstraint, SmallInteger, UniqueConstraint, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoConfigUpdateRectification(Base):
|
||||
__tablename__ = 'pedimento_config_update_rectification'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_config_update_rectification'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_config_update_rectification_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_config_update_rectification_pedimento_id_key'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
update_vat = mapped_column(SmallInteger)
|
||||
update_advalorem = mapped_column(SmallInteger)
|
||||
update_cc = mapped_column(SmallInteger)
|
||||
update_ieps = mapped_column(SmallInteger)
|
||||
calculate_surcharge = mapped_column(SmallInteger)
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_config_update_rectification')
|
||||
@@ -0,0 +1,25 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Integer, PrimaryKeyConstraint, SmallInteger, UniqueConstraint, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoConfigUpdates(Base):
|
||||
__tablename__ = 'pedimento_config_updates'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_config_updates'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_config_updates_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_config_updates_pedimento_id_key'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
update_vat = mapped_column(SmallInteger)
|
||||
update_advalorem = mapped_column(SmallInteger)
|
||||
update_cc = mapped_column(SmallInteger)
|
||||
update_ieps = mapped_column(SmallInteger)
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_config_updates')
|
||||
@@ -0,0 +1,23 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Integer, PrimaryKeyConstraint, String, UniqueConstraint, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoCustomsOffices(Base):
|
||||
__tablename__ = 'pedimento_customs_offices'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_customs_offices'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_customs_offices_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_customs_offices_pedimento_id_key'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
dispatch_customs = mapped_column(String(3))
|
||||
entry_exit_customs = mapped_column(String(3))
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_customs_offices')
|
||||
@@ -0,0 +1,34 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Index, Integer, PrimaryKeyConstraint, Time, UniqueConstraint, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoDates(Base):
|
||||
__tablename__ = 'pedimento_dates'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_dates'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_dates_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_dates_pedimento_id_key'),
|
||||
Index('idx_pedimento_dates_pedimento_id', 'pedimento_id'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
entry_date = mapped_column(DateTime)
|
||||
pedimento_date = mapped_column(DateTime)
|
||||
payment_date = mapped_column(DateTime)
|
||||
rectification_payment_date = mapped_column(DateTime)
|
||||
extraction_date = mapped_column(DateTime)
|
||||
submission_date = mapped_column(DateTime)
|
||||
eucan_date = mapped_column(DateTime)
|
||||
original_date = mapped_column(DateTime)
|
||||
start_date = mapped_column(DateTime)
|
||||
end_date = mapped_column(DateTime)
|
||||
capture_date = mapped_column(DateTime)
|
||||
capture_time = mapped_column(Time)
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_dates')
|
||||
@@ -0,0 +1,30 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Integer, Numeric, PrimaryKeyConstraint, SmallInteger, String, UniqueConstraint, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoDecrementables(Base):
|
||||
__tablename__ = 'pedimento_decrementables'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_decrementables'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_decrementables_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_decrementables_pedimento_id_key'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
freight = mapped_column(Numeric(13, 2))
|
||||
insurance = mapped_column(Numeric(13, 2))
|
||||
loading = mapped_column(Numeric(13, 2))
|
||||
unloading = mapped_column(Numeric(13, 2))
|
||||
others = mapped_column(Numeric(13, 2))
|
||||
currency = mapped_column(String(3))
|
||||
currency_factor = mapped_column(Numeric(15, 8))
|
||||
not_affect_usd_value = mapped_column(SmallInteger)
|
||||
not_affect_customs_value = mapped_column(SmallInteger)
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_decrementables')
|
||||
@@ -0,0 +1,31 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Integer, Numeric, PrimaryKeyConstraint, SmallInteger, String, UniqueConstraint, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoIncrementables(Base):
|
||||
__tablename__ = 'pedimento_incrementables'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_incrementables'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_incrementables_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_incrementables_pedimento_id_key'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
insured_value = mapped_column(Numeric(13, 2))
|
||||
freight = mapped_column(Numeric(13, 2))
|
||||
insurance = mapped_column(Numeric(13, 2))
|
||||
packaging = mapped_column(Numeric(13, 2))
|
||||
others = mapped_column(Numeric(13, 3))
|
||||
deductibles = mapped_column(Numeric(13, 3))
|
||||
currency = mapped_column(String(3))
|
||||
currency_factor = mapped_column(Numeric(15, 8))
|
||||
not_affect_usd_value = mapped_column(SmallInteger)
|
||||
not_affect_customs_value = mapped_column(SmallInteger)
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_incrementables')
|
||||
@@ -0,0 +1,24 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Integer, Numeric, PrimaryKeyConstraint, SmallInteger, UniqueConstraint, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoIndexes(Base):
|
||||
__tablename__ = 'pedimento_indexes'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_indexes'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_indexes_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_indexes_pedimento_id_key'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
update_factor_type = mapped_column(SmallInteger)
|
||||
update_factor = mapped_column(Numeric(7, 4))
|
||||
manual_update_factor = mapped_column(SmallInteger)
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_indexes')
|
||||
@@ -0,0 +1,34 @@
|
||||
from sqlalchemy import Date, DateTime, ForeignKeyConstraint, Index, Integer, PrimaryKeyConstraint, SmallInteger, String, Time, UniqueConstraint, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoPayments(Base):
|
||||
__tablename__ = 'pedimento_payments'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_payments'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_payments_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_payments_pedimento_id_key'),
|
||||
Index('idx_pedimento_payments_pedimento_id', 'pedimento_id'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
acknowledgment = mapped_column(String(20))
|
||||
operation_number = mapped_column(String(14))
|
||||
bank_code = mapped_column(Integer)
|
||||
cashier = mapped_column(String(2))
|
||||
date = mapped_column(Date)
|
||||
time = mapped_column(Time)
|
||||
shift = mapped_column(String(1))
|
||||
total_cash_paid = mapped_column(Integer)
|
||||
total_contributions = mapped_column(Integer)
|
||||
counter_payment = mapped_column(SmallInteger)
|
||||
pece_code = mapped_column(String(5))
|
||||
payment_id = mapped_column(Integer)
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_payments')
|
||||
@@ -0,0 +1,24 @@
|
||||
from sqlalchemy import ForeignKeyConstraint, Integer, PrimaryKeyConstraint, String, UniqueConstraint
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoRectificationDestination(Base):
|
||||
__tablename__ = 'pedimento_rectification_destination'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_rectification_destination'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_rectification_destination_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_rectification_destination_pedimento_id_key'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
destination_pedimento_year = mapped_column(String(2))
|
||||
destination_customs_office = mapped_column(String(3))
|
||||
destination_license = mapped_column(String(4))
|
||||
destination_pedimento_number = mapped_column(String(7))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_rectification_destination')
|
||||
@@ -0,0 +1,33 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Integer, PrimaryKeyConstraint, SmallInteger, String, UniqueConstraint
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoRectificationOrigin(Base):
|
||||
__tablename__ = 'pedimento_rectification_origin'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_rectification_origin'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_rectification_origin_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_rectification_origin_pedimento_id_key'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
original_pedimento_year = mapped_column(String(2))
|
||||
original_customs_office = mapped_column(String(3))
|
||||
original_license = mapped_column(String(4))
|
||||
original_pedimento_number = mapped_column(String(7))
|
||||
original_pedimento_key = mapped_column(String(2))
|
||||
original_payment_date = mapped_column(DateTime)
|
||||
total_cash = mapped_column(Integer)
|
||||
total_others = mapped_column(Integer)
|
||||
reason = mapped_column(String(255))
|
||||
charge_to_client = mapped_column(SmallInteger)
|
||||
use_original_payment_date_for_interest_calc = mapped_column(SmallInteger)
|
||||
manual_calculation = mapped_column(SmallInteger)
|
||||
original_pedimento_norms = mapped_column(SmallInteger)
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_rectification_origin')
|
||||
@@ -0,0 +1,25 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Integer, PrimaryKeyConstraint, SmallInteger, String, UniqueConstraint, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoTransportMeans(Base):
|
||||
__tablename__ = 'pedimento_transport_means'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_transport_means'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_transport_means_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_transport_means_pedimento_id_key'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
destination = mapped_column(SmallInteger)
|
||||
entry_exit = mapped_column(String(2))
|
||||
arrival = mapped_column(String(2))
|
||||
departure = mapped_column(String(2))
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_transport_means')
|
||||
@@ -0,0 +1,29 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Integer, PrimaryKeyConstraint, String, UniqueConstraint, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
class PedimentoValidation(Base):
|
||||
__tablename__ = 'pedimento_validation' #PedimentoValidacion
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
ForeignKeyConstraint(['pedimento_id'], ['a76.pedimentos.id'], ondelete='CASCADE', name='fk_pedimento_validation'),
|
||||
PrimaryKeyConstraint('id', name='pedimento_validation_pkey'),
|
||||
UniqueConstraint('pedimento_id', name='pedimento_validation_pedimento_id_key'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
pedimento_id = mapped_column(Integer, nullable=False)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
validator = mapped_column(String(3)) #validador
|
||||
validation_ack = mapped_column(String(8)) #acuse_validacion
|
||||
pre_ack = mapped_column(String(8)) #acuse_previo
|
||||
line_signature = mapped_column(String(50)) #firma_linea_captura
|
||||
electronic_signature = mapped_column(String(999)) #firma_electronica
|
||||
certificate_number = mapped_column(String(99)) #numero_certificado
|
||||
validator_id = mapped_column(Integer)
|
||||
responsible_id = mapped_column(Integer)
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento: Mapped['Pedimentos'] = relationship('Pedimentos', back_populates='pedimento_validation')
|
||||
52
backend/api/v1/modules/a76/pedmientos/models/pedimentos.py
Normal file
52
backend/api/v1/modules/a76/pedmientos/models/pedimentos.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from sqlalchemy import DateTime, ForeignKeyConstraint, Index, Integer, Numeric, PrimaryKeyConstraint, String, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.base import Mapped
|
||||
from core.database import Base
|
||||
|
||||
|
||||
class Pedimentos(Base):
|
||||
__tablename__ = 'pedimentos'
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id']),
|
||||
PrimaryKeyConstraint('id', name='pedimentos_pkey'),
|
||||
Index('idx_pedimentos_client_id', 'client_id'),
|
||||
Index('idx_pedimentos_created_at', 'created_at'),
|
||||
Index('idx_pedimentos_status', 'status'),
|
||||
{'schema': 'a76'}
|
||||
)
|
||||
|
||||
id = mapped_column(Integer)
|
||||
tenant_id = mapped_column(Integer, nullable=False, index=True)
|
||||
year = mapped_column(String(2))
|
||||
customs_office = mapped_column(String(2))
|
||||
license = mapped_column(String(4))
|
||||
pedimento_number = mapped_column(String(7))
|
||||
client_id = mapped_column(Integer)
|
||||
operation_type = mapped_column(Integer)
|
||||
pedimento_type = mapped_column(Integer)
|
||||
pedimento_key = mapped_column(String(2))
|
||||
regime = mapped_column(String(3))
|
||||
status = mapped_column(String(30))
|
||||
usd_value = mapped_column(Numeric(17, 6))
|
||||
paid_price = mapped_column(Numeric(17, 6))
|
||||
gross_weight = mapped_column(Numeric(19, 3))
|
||||
exchange_rate = mapped_column(Numeric(9, 5))
|
||||
created_at = mapped_column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
|
||||
|
||||
pedimento_config_additional: Mapped['PedimentoConfigAdditional'] = relationship('PedimentoConfigAdditional', uselist=False, back_populates='pedimento')
|
||||
pedimento_config_calculations: Mapped['PedimentoConfigCalculations'] = relationship('PedimentoConfigCalculations', uselist=False, back_populates='pedimento')
|
||||
pedimento_config_parameters: Mapped['PedimentoConfigParameters'] = relationship('PedimentoConfigParameters', uselist=False, back_populates='pedimento')
|
||||
pedimento_config_surcharges: Mapped['PedimentoConfigSurcharges'] = relationship('PedimentoConfigSurcharges', uselist=False, back_populates='pedimento')
|
||||
pedimento_config_update_rectification: Mapped['PedimentoConfigUpdateRectification'] = relationship('PedimentoConfigUpdateRectification', uselist=False, back_populates='pedimento')
|
||||
pedimento_config_updates: Mapped['PedimentoConfigUpdates'] = relationship('PedimentoConfigUpdates', uselist=False, back_populates='pedimento')
|
||||
pedimento_customs_offices: Mapped['PedimentoCustomsOffices'] = relationship('PedimentoCustomsOffices', uselist=False, back_populates='pedimento')
|
||||
pedimento_dates: Mapped['PedimentoDates'] = relationship('PedimentoDates', uselist=False, back_populates='pedimento')
|
||||
pedimento_decrementables: Mapped['PedimentoDecrementables'] = relationship('PedimentoDecrementables', uselist=False, back_populates='pedimento')
|
||||
pedimento_incrementables: Mapped['PedimentoIncrementables'] = relationship('PedimentoIncrementables', uselist=False, back_populates='pedimento')
|
||||
pedimento_indexes: Mapped['PedimentoIndexes'] = relationship('PedimentoIndexes', uselist=False, back_populates='pedimento')
|
||||
pedimento_payments: Mapped['PedimentoPayments'] = relationship('PedimentoPayments', uselist=False, back_populates='pedimento')
|
||||
pedimento_rectification_destination: Mapped['PedimentoRectificationDestination'] = relationship('PedimentoRectificationDestination', uselist=False, back_populates='pedimento')
|
||||
pedimento_rectification_origin: Mapped['PedimentoRectificationOrigin'] = relationship('PedimentoRectificationOrigin', uselist=False, back_populates='pedimento')
|
||||
pedimento_transport_means: Mapped['PedimentoTransportMeans'] = relationship('PedimentoTransportMeans', uselist=False, back_populates='pedimento')
|
||||
pedimento_validation: Mapped['PedimentoValidation'] = relationship('PedimentoValidation', uselist=False, back_populates='pedimento')
|
||||
|
||||
39
backend/api/v1/modules/a76/pedmientos/router.py
Normal file
39
backend/api/v1/modules/a76/pedmientos/router.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from .routes.pedimento_config_additional import router as pedimento_config_additional_router
|
||||
from .routes.pedimento_config_calculations import router as pedimento_config_calculations_router
|
||||
from .routes.pedimento_config_parameters import router as pedimento_config_parameters_router
|
||||
from .routes.pedimento_config_surcharges import router as pedimento_config_surcharges_router
|
||||
from .routes.pedimento_config_update_rectification import router as pedimento_config_update_rectification_router
|
||||
from .routes.pedimento_config_updates import router as pedimento_config_updates_router
|
||||
from .routes.pedimento_customs_offices import router as pedimento_customs_offices_router
|
||||
from .routes.pedimento_dates import router as pedimento_dates_router
|
||||
from .routes.pedimento_decrementables import router as pedimento_decrementables_router
|
||||
from .routes.pedimento_incrementables import router as pedimento_incrementables_router
|
||||
from .routes.pedimento_indexes import router as pedimento_indexes_router
|
||||
from .routes.pedimento_payments import router as pedimento_payments_router
|
||||
from .routes.pedimento_rectification_destination import router as pedimento_rectification_destination_router
|
||||
from .routes.pedimento_rectification_origin import router as pedimento_rectification_origin_router
|
||||
from .routes.pedimento_transport_means import router as pedimento_transport_means_router
|
||||
from .routes.pedimento_validation import router as pedimento_validation_router
|
||||
from .routes.pedimentos import router as pedimentos_router
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
router.include_router(pedimento_config_additional_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_config_additional"])
|
||||
router.include_router(pedimento_config_calculations_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_config_calculations"])
|
||||
router.include_router(pedimento_config_parameters_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_config_parameters"])
|
||||
router.include_router(pedimento_config_surcharges_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_config_surcharges"])
|
||||
router.include_router(pedimento_config_update_rectification_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_config_update_rectification"])
|
||||
router.include_router(pedimento_config_updates_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_config_updates"])
|
||||
router.include_router(pedimento_customs_offices_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_customs_offices"])
|
||||
router.include_router(pedimento_dates_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_dates"])
|
||||
router.include_router(pedimento_decrementables_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_decrementables"])
|
||||
router.include_router(pedimento_incrementables_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_incrementables"])
|
||||
router.include_router(pedimento_indexes_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_indexes"])
|
||||
router.include_router(pedimento_payments_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_payments"])
|
||||
router.include_router(pedimento_rectification_destination_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_rectification_destination"])
|
||||
router.include_router(pedimento_rectification_origin_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_rectification_origin"])
|
||||
router.include_router(pedimento_transport_means_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_transport_means"])
|
||||
router.include_router(pedimento_validation_router, prefix="/pedimentos", tags=["a76 / pedimentos / pedimento_validation"])
|
||||
router.include_router(pedimentos_router, prefix="/pedimentos", tags=["a76 / pedimentos"])
|
||||
@@ -0,0 +1,94 @@
|
||||
"""
|
||||
Routes for PedimentoConfigAdditional CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_config_additional import PedimentoConfigAdditionalService
|
||||
from ..dtos.pedimento_config_additional import (
|
||||
PedimentoConfigAdditionalCreate,
|
||||
PedimentoConfigAdditionalUpdate,
|
||||
PedimentoConfigAdditionalResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/config-additional")
|
||||
|
||||
|
||||
@router.get("/", response_model=PedimentoConfigAdditionalResponse)
|
||||
async def get_config_additional(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get config additional by pedimento ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
config = PedimentoConfigAdditionalService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
raise HTTPException(status_code=404, detail="Config additional not found")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoConfigAdditionalResponse, status_code=201)
|
||||
async def create_config_additional(
|
||||
pedimento_id: int,
|
||||
data: PedimentoConfigAdditionalCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create config additional"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id and tenant_id match
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
if data.tenant_id != tenant_id:
|
||||
raise HTTPException(status_code=403, detail="Tenant ID mismatch")
|
||||
|
||||
config = PedimentoConfigAdditionalService.create(db, data)
|
||||
return config
|
||||
|
||||
|
||||
@router.put("/", response_model=PedimentoConfigAdditionalResponse)
|
||||
async def update_config_additional(
|
||||
pedimento_id: int,
|
||||
data: PedimentoConfigAdditionalUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update config additional"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
config = PedimentoConfigAdditionalService.update(db, pedimento_id, tenant_id, data)
|
||||
if not config:
|
||||
raise HTTPException(status_code=404, detail="Config additional not found")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@router.delete("/", status_code=204)
|
||||
async def delete_config_additional(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete config additional"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoConfigAdditionalService.delete(db, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Config additional not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
Routes for PedimentoConfigCalculations CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_config_calculations import PedimentoConfigCalculationsService
|
||||
from ..dtos.pedimento_config_calculations import (
|
||||
PedimentoConfigCalculationsCreate,
|
||||
PedimentoConfigCalculationsUpdate,
|
||||
PedimentoConfigCalculationsResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/config-calculations")
|
||||
|
||||
|
||||
@router.get("/", response_model=PedimentoConfigCalculationsResponse)
|
||||
async def get_config_calculations(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get config calculations by pedimento ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
config = PedimentoConfigCalculationsService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
raise HTTPException(status_code=404, detail="Config calculations not found")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoConfigCalculationsResponse, status_code=201)
|
||||
async def create_config_calculations(
|
||||
pedimento_id: int,
|
||||
data: PedimentoConfigCalculationsCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create config calculations"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
config = PedimentoConfigCalculationsService.create(db, data, tenant_id)
|
||||
return config
|
||||
|
||||
|
||||
@router.put("/", response_model=PedimentoConfigCalculationsResponse)
|
||||
async def update_config_calculations(
|
||||
pedimento_id: int,
|
||||
data: PedimentoConfigCalculationsUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update config calculations"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
config = PedimentoConfigCalculationsService.update(db, pedimento_id, tenant_id, data)
|
||||
if not config:
|
||||
raise HTTPException(status_code=404, detail="Config calculations not found")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@router.delete("/", status_code=204)
|
||||
async def delete_config_calculations(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete config calculations"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoConfigCalculationsService.delete(db, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Config calculations not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
Routes for PedimentoConfigParameters CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_config_parameters import PedimentoConfigParametersService
|
||||
from ..dtos.pedimento_config_parameters import (
|
||||
PedimentoConfigParametersCreate,
|
||||
PedimentoConfigParametersUpdate,
|
||||
PedimentoConfigParametersResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/config-parameters")
|
||||
|
||||
|
||||
@router.get("/", response_model=PedimentoConfigParametersResponse)
|
||||
async def get_config_parameters(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get config parameters by pedimento ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
config = PedimentoConfigParametersService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
raise HTTPException(status_code=404, detail="Config parameters not found")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoConfigParametersResponse, status_code=201)
|
||||
async def create_config_parameters(
|
||||
pedimento_id: int,
|
||||
data: PedimentoConfigParametersCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create config parameters"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
config = PedimentoConfigParametersService.create(db, data, tenant_id)
|
||||
return config
|
||||
|
||||
|
||||
@router.put("/", response_model=PedimentoConfigParametersResponse)
|
||||
async def update_config_parameters(
|
||||
pedimento_id: int,
|
||||
data: PedimentoConfigParametersUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update config parameters"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
config = PedimentoConfigParametersService.update(db, pedimento_id, tenant_id, data)
|
||||
if not config:
|
||||
raise HTTPException(status_code=404, detail="Config parameters not found")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@router.delete("/", status_code=204)
|
||||
async def delete_config_parameters(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete config parameters"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoConfigParametersService.delete(db, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Config parameters not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
Routes for PedimentoConfigSurcharges CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_config_surcharges import PedimentoConfigSurchargesService
|
||||
from ..dtos.pedimento_config_surcharges import (
|
||||
PedimentoConfigSurchargesCreate,
|
||||
PedimentoConfigSurchargesUpdate,
|
||||
PedimentoConfigSurchargesResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/config-surcharges")
|
||||
|
||||
|
||||
@router.get("/", response_model=PedimentoConfigSurchargesResponse)
|
||||
async def get_config_surcharges(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get config surcharges by pedimento ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
config = PedimentoConfigSurchargesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
raise HTTPException(status_code=404, detail="Config surcharges not found")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoConfigSurchargesResponse, status_code=201)
|
||||
async def create_config_surcharges(
|
||||
pedimento_id: int,
|
||||
data: PedimentoConfigSurchargesCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create config surcharges"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
config = PedimentoConfigSurchargesService.create(db, data, tenant_id)
|
||||
return config
|
||||
|
||||
|
||||
@router.put("/", response_model=PedimentoConfigSurchargesResponse)
|
||||
async def update_config_surcharges(
|
||||
pedimento_id: int,
|
||||
data: PedimentoConfigSurchargesUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update config surcharges"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
config = PedimentoConfigSurchargesService.update(db, pedimento_id, tenant_id, data)
|
||||
if not config:
|
||||
raise HTTPException(status_code=404, detail="Config surcharges not found")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@router.delete("/", status_code=204)
|
||||
async def delete_config_surcharges(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete config surcharges"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoConfigSurchargesService.delete(db, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Config surcharges not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
Routes for PedimentoConfigUpdateRectification CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_config_update_rectification import PedimentoConfigUpdateRectificationService
|
||||
from ..dtos.pedimento_config_update_rectification import (
|
||||
PedimentoConfigUpdateRectificationCreate,
|
||||
PedimentoConfigUpdateRectificationUpdate,
|
||||
PedimentoConfigUpdateRectificationResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/config-update-rectification")
|
||||
|
||||
|
||||
@router.get("/", response_model=PedimentoConfigUpdateRectificationResponse)
|
||||
async def get_config_update_rectification(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get config update rectification by pedimento ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
config = PedimentoConfigUpdateRectificationService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
raise HTTPException(status_code=404, detail="Config update rectification not found")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoConfigUpdateRectificationResponse, status_code=201)
|
||||
async def create_config_update_rectification(
|
||||
pedimento_id: int,
|
||||
data: PedimentoConfigUpdateRectificationCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create config update rectification"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
config = PedimentoConfigUpdateRectificationService.create(db, data, tenant_id)
|
||||
return config
|
||||
|
||||
|
||||
@router.put("/", response_model=PedimentoConfigUpdateRectificationResponse)
|
||||
async def update_config_update_rectification(
|
||||
pedimento_id: int,
|
||||
data: PedimentoConfigUpdateRectificationUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update config update rectification"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
config = PedimentoConfigUpdateRectificationService.update(db, pedimento_id, tenant_id, data)
|
||||
if not config:
|
||||
raise HTTPException(status_code=404, detail="Config update rectification not found")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@router.delete("/", status_code=204)
|
||||
async def delete_config_update_rectification(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete config update rectification"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoConfigUpdateRectificationService.delete(db, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Config update rectification not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
Routes for PedimentoConfigUpdates CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_config_updates import PedimentoConfigUpdatesService
|
||||
from ..dtos.pedimento_config_updates import (
|
||||
PedimentoConfigUpdatesCreate,
|
||||
PedimentoConfigUpdatesUpdate,
|
||||
PedimentoConfigUpdatesResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/config-updates")
|
||||
|
||||
|
||||
@router.get("/", response_model=PedimentoConfigUpdatesResponse)
|
||||
async def get_config_updates(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get config updates by pedimento ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
config = PedimentoConfigUpdatesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
raise HTTPException(status_code=404, detail="Config updates not found")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoConfigUpdatesResponse, status_code=201)
|
||||
async def create_config_updates(
|
||||
pedimento_id: int,
|
||||
data: PedimentoConfigUpdatesCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create config updates"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
config = PedimentoConfigUpdatesService.create(db, data, tenant_id)
|
||||
return config
|
||||
|
||||
|
||||
@router.put("/", response_model=PedimentoConfigUpdatesResponse)
|
||||
async def update_config_updates(
|
||||
pedimento_id: int,
|
||||
data: PedimentoConfigUpdatesUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update config updates"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
config = PedimentoConfigUpdatesService.update(db, pedimento_id, tenant_id, data)
|
||||
if not config:
|
||||
raise HTTPException(status_code=404, detail="Config updates not found")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@router.delete("/", status_code=204)
|
||||
async def delete_config_updates(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete config updates"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoConfigUpdatesService.delete(db, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Config updates not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,111 @@
|
||||
"""
|
||||
Routes for PedimentoCustomsOffices CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_customs_offices import PedimentoCustomsOfficesService
|
||||
from ..dtos.pedimento_customs_offices import (
|
||||
PedimentoCustomsOfficesCreate,
|
||||
PedimentoCustomsOfficesUpdate,
|
||||
PedimentoCustomsOfficesResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/customs-offices")
|
||||
|
||||
|
||||
@router.get("/", response_model=List[PedimentoCustomsOfficesResponse])
|
||||
async def list_customs_offices(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get all customs offices for a pedimento"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
offices = PedimentoCustomsOfficesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
return offices
|
||||
|
||||
|
||||
@router.get("/{office_id}", response_model=PedimentoCustomsOfficesResponse)
|
||||
async def get_customs_office(
|
||||
pedimento_id: int,
|
||||
office_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get a specific customs office by ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
office = PedimentoCustomsOfficesService.get_by_id(db, office_id, pedimento_id, tenant_id)
|
||||
if not office:
|
||||
raise HTTPException(status_code=404, detail="Customs office not found")
|
||||
|
||||
return office
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoCustomsOfficesResponse, status_code=201)
|
||||
async def create_customs_office(
|
||||
pedimento_id: int,
|
||||
data: PedimentoCustomsOfficesCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create a new customs office"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
office = PedimentoCustomsOfficesService.create(db, data, tenant_id)
|
||||
return office
|
||||
|
||||
|
||||
@router.put("/{office_id}", response_model=PedimentoCustomsOfficesResponse)
|
||||
async def update_customs_office(
|
||||
pedimento_id: int,
|
||||
office_id: int,
|
||||
data: PedimentoCustomsOfficesUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update a customs office"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
office = PedimentoCustomsOfficesService.update(db, office_id, pedimento_id, tenant_id, data)
|
||||
if not office:
|
||||
raise HTTPException(status_code=404, detail="Customs office not found")
|
||||
|
||||
return office
|
||||
|
||||
|
||||
@router.delete("/{office_id}", status_code=204)
|
||||
async def delete_customs_office(
|
||||
pedimento_id: int,
|
||||
office_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete a customs office"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoCustomsOfficesService.delete(db, office_id, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Customs office not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
Routes for PedimentoDates CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_dates import PedimentoDatesService
|
||||
from ..dtos.pedimento_dates import (
|
||||
PedimentoDatesCreate,
|
||||
PedimentoDatesUpdate,
|
||||
PedimentoDatesResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/dates")
|
||||
|
||||
|
||||
@router.get("/", response_model=PedimentoDatesResponse)
|
||||
async def get_dates(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get dates by pedimento ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
dates = PedimentoDatesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not dates:
|
||||
raise HTTPException(status_code=404, detail="Pedimento dates not found")
|
||||
|
||||
return dates
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoDatesResponse, status_code=201)
|
||||
async def create_dates(
|
||||
pedimento_id: int,
|
||||
data: PedimentoDatesCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create pedimento dates"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
dates = PedimentoDatesService.create(db, data, tenant_id)
|
||||
return dates
|
||||
|
||||
|
||||
@router.put("/", response_model=PedimentoDatesResponse)
|
||||
async def update_dates(
|
||||
pedimento_id: int,
|
||||
data: PedimentoDatesUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update pedimento dates"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
dates = PedimentoDatesService.update(db, pedimento_id, tenant_id, data)
|
||||
if not dates:
|
||||
raise HTTPException(status_code=404, detail="Pedimento dates not found")
|
||||
|
||||
return dates
|
||||
|
||||
|
||||
@router.delete("/", status_code=204)
|
||||
async def delete_dates(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete pedimento dates"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoDatesService.delete(db, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Pedimento dates not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,111 @@
|
||||
"""
|
||||
Routes for PedimentoDecrementables CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_decrementables import PedimentoDecrementablesService
|
||||
from ..dtos.pedimento_decrementables import (
|
||||
PedimentoDecrementablesCreate,
|
||||
PedimentoDecrementablesUpdate,
|
||||
PedimentoDecrementablesResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/decrementables")
|
||||
|
||||
|
||||
@router.get("/", response_model=List[PedimentoDecrementablesResponse])
|
||||
async def list_decrementables(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get all decrementables for a pedimento"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
decrementables = PedimentoDecrementablesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
return decrementables
|
||||
|
||||
|
||||
@router.get("/{decrementable_id}", response_model=PedimentoDecrementablesResponse)
|
||||
async def get_decrementable(
|
||||
pedimento_id: int,
|
||||
decrementable_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get a specific decrementable by ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
decrementable = PedimentoDecrementablesService.get_by_id(db, decrementable_id, pedimento_id, tenant_id)
|
||||
if not decrementable:
|
||||
raise HTTPException(status_code=404, detail="Decrementable not found")
|
||||
|
||||
return decrementable
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoDecrementablesResponse, status_code=201)
|
||||
async def create_decrementable(
|
||||
pedimento_id: int,
|
||||
data: PedimentoDecrementablesCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create a new decrementable"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
decrementable = PedimentoDecrementablesService.create(db, data, tenant_id)
|
||||
return decrementable
|
||||
|
||||
|
||||
@router.put("/{decrementable_id}", response_model=PedimentoDecrementablesResponse)
|
||||
async def update_decrementable(
|
||||
pedimento_id: int,
|
||||
decrementable_id: int,
|
||||
data: PedimentoDecrementablesUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update a decrementable"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
decrementable = PedimentoDecrementablesService.update(db, decrementable_id, pedimento_id, tenant_id, data)
|
||||
if not decrementable:
|
||||
raise HTTPException(status_code=404, detail="Decrementable not found")
|
||||
|
||||
return decrementable
|
||||
|
||||
|
||||
@router.delete("/{decrementable_id}", status_code=204)
|
||||
async def delete_decrementable(
|
||||
pedimento_id: int,
|
||||
decrementable_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete a decrementable"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoDecrementablesService.delete(db, decrementable_id, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Decrementable not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,111 @@
|
||||
"""
|
||||
Routes for PedimentoIncrementables CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_incrementables import PedimentoIncrementablesService
|
||||
from ..dtos.pedimento_incrementables import (
|
||||
PedimentoIncrementablesCreate,
|
||||
PedimentoIncrementablesUpdate,
|
||||
PedimentoIncrementablesResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/incrementables")
|
||||
|
||||
|
||||
@router.get("/", response_model=List[PedimentoIncrementablesResponse])
|
||||
async def list_incrementables(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get all incrementables for a pedimento"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
incrementables = PedimentoIncrementablesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
return incrementables
|
||||
|
||||
|
||||
@router.get("/{incrementable_id}", response_model=PedimentoIncrementablesResponse)
|
||||
async def get_incrementable(
|
||||
pedimento_id: int,
|
||||
incrementable_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get a specific incrementable by ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
incrementable = PedimentoIncrementablesService.get_by_id(db, incrementable_id, pedimento_id, tenant_id)
|
||||
if not incrementable:
|
||||
raise HTTPException(status_code=404, detail="Incrementable not found")
|
||||
|
||||
return incrementable
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoIncrementablesResponse, status_code=201)
|
||||
async def create_incrementable(
|
||||
pedimento_id: int,
|
||||
data: PedimentoIncrementablesCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create a new incrementable"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
incrementable = PedimentoIncrementablesService.create(db, data, tenant_id)
|
||||
return incrementable
|
||||
|
||||
|
||||
@router.put("/{incrementable_id}", response_model=PedimentoIncrementablesResponse)
|
||||
async def update_incrementable(
|
||||
pedimento_id: int,
|
||||
incrementable_id: int,
|
||||
data: PedimentoIncrementablesUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update an incrementable"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
incrementable = PedimentoIncrementablesService.update(db, incrementable_id, pedimento_id, tenant_id, data)
|
||||
if not incrementable:
|
||||
raise HTTPException(status_code=404, detail="Incrementable not found")
|
||||
|
||||
return incrementable
|
||||
|
||||
|
||||
@router.delete("/{incrementable_id}", status_code=204)
|
||||
async def delete_incrementable(
|
||||
pedimento_id: int,
|
||||
incrementable_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete an incrementable"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoIncrementablesService.delete(db, incrementable_id, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Incrementable not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
Routes for PedimentoIndexes CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_indexes import PedimentoIndexesService
|
||||
from ..dtos.pedimento_indexes import (
|
||||
PedimentoIndexesCreate,
|
||||
PedimentoIndexesUpdate,
|
||||
PedimentoIndexesResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/indexes")
|
||||
|
||||
|
||||
@router.get("/", response_model=PedimentoIndexesResponse)
|
||||
async def get_indexes(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get indexes by pedimento ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
indexes = PedimentoIndexesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not indexes:
|
||||
raise HTTPException(status_code=404, detail="Pedimento indexes not found")
|
||||
|
||||
return indexes
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoIndexesResponse, status_code=201)
|
||||
async def create_indexes(
|
||||
pedimento_id: int,
|
||||
data: PedimentoIndexesCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create pedimento indexes"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
indexes = PedimentoIndexesService.create(db, data, tenant_id)
|
||||
return indexes
|
||||
|
||||
|
||||
@router.put("/", response_model=PedimentoIndexesResponse)
|
||||
async def update_indexes(
|
||||
pedimento_id: int,
|
||||
data: PedimentoIndexesUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update pedimento indexes"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
indexes = PedimentoIndexesService.update(db, pedimento_id, tenant_id, data)
|
||||
if not indexes:
|
||||
raise HTTPException(status_code=404, detail="Pedimento indexes not found")
|
||||
|
||||
return indexes
|
||||
|
||||
|
||||
@router.delete("/", status_code=204)
|
||||
async def delete_indexes(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete pedimento indexes"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoIndexesService.delete(db, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Pedimento indexes not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,111 @@
|
||||
"""
|
||||
Routes for PedimentoPayments CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_payments import PedimentoPaymentsService
|
||||
from ..dtos.pedimento_payments import (
|
||||
PedimentoPaymentsCreate,
|
||||
PedimentoPaymentsUpdate,
|
||||
PedimentoPaymentsResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/payments")
|
||||
|
||||
|
||||
@router.get("/", response_model=List[PedimentoPaymentsResponse])
|
||||
async def list_payments(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get all payments for a pedimento"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
payments = PedimentoPaymentsService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
return payments
|
||||
|
||||
|
||||
@router.get("/{payment_id}", response_model=PedimentoPaymentsResponse)
|
||||
async def get_payment(
|
||||
pedimento_id: int,
|
||||
payment_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get a specific payment by ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
payment = PedimentoPaymentsService.get_by_id(db, payment_id, pedimento_id, tenant_id)
|
||||
if not payment:
|
||||
raise HTTPException(status_code=404, detail="Payment not found")
|
||||
|
||||
return payment
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoPaymentsResponse, status_code=201)
|
||||
async def create_payment(
|
||||
pedimento_id: int,
|
||||
data: PedimentoPaymentsCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create a new payment"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
payment = PedimentoPaymentsService.create(db, data, tenant_id)
|
||||
return payment
|
||||
|
||||
|
||||
@router.put("/{payment_id}", response_model=PedimentoPaymentsResponse)
|
||||
async def update_payment(
|
||||
pedimento_id: int,
|
||||
payment_id: int,
|
||||
data: PedimentoPaymentsUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update a payment"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
payment = PedimentoPaymentsService.update(db, payment_id, pedimento_id, tenant_id, data)
|
||||
if not payment:
|
||||
raise HTTPException(status_code=404, detail="Payment not found")
|
||||
|
||||
return payment
|
||||
|
||||
|
||||
@router.delete("/{payment_id}", status_code=204)
|
||||
async def delete_payment(
|
||||
pedimento_id: int,
|
||||
payment_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete a payment"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoPaymentsService.delete(db, payment_id, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Payment not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
Routes for PedimentoRectificationDestination CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_rectification_destination import PedimentoRectificationDestinationService
|
||||
from ..dtos.pedimento_rectification_destination import (
|
||||
PedimentoRectificationDestinationCreate,
|
||||
PedimentoRectificationDestinationUpdate,
|
||||
PedimentoRectificationDestinationResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/rectification-destination")
|
||||
|
||||
|
||||
@router.get("/", response_model=PedimentoRectificationDestinationResponse)
|
||||
async def get_rectification_destination(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get rectification destination by pedimento ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
rectification = PedimentoRectificationDestinationService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not rectification:
|
||||
raise HTTPException(status_code=404, detail="Rectification destination not found")
|
||||
|
||||
return rectification
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoRectificationDestinationResponse, status_code=201)
|
||||
async def create_rectification_destination(
|
||||
pedimento_id: int,
|
||||
data: PedimentoRectificationDestinationCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create rectification destination"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
rectification = PedimentoRectificationDestinationService.create(db, data, tenant_id)
|
||||
return rectification
|
||||
|
||||
|
||||
@router.put("/", response_model=PedimentoRectificationDestinationResponse)
|
||||
async def update_rectification_destination(
|
||||
pedimento_id: int,
|
||||
data: PedimentoRectificationDestinationUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update rectification destination"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
rectification = PedimentoRectificationDestinationService.update(db, pedimento_id, tenant_id, data)
|
||||
if not rectification:
|
||||
raise HTTPException(status_code=404, detail="Rectification destination not found")
|
||||
|
||||
return rectification
|
||||
|
||||
|
||||
@router.delete("/", status_code=204)
|
||||
async def delete_rectification_destination(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete rectification destination"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoRectificationDestinationService.delete(db, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Rectification destination not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
Routes for PedimentoRectificationOrigin CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_rectification_origin import PedimentoRectificationOriginService
|
||||
from ..dtos.pedimento_rectification_origin import (
|
||||
PedimentoRectificationOriginCreate,
|
||||
PedimentoRectificationOriginUpdate,
|
||||
PedimentoRectificationOriginResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/rectification-origin")
|
||||
|
||||
|
||||
@router.get("/", response_model=PedimentoRectificationOriginResponse)
|
||||
async def get_rectification_origin(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get rectification origin by pedimento ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
rectification = PedimentoRectificationOriginService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not rectification:
|
||||
raise HTTPException(status_code=404, detail="Rectification origin not found")
|
||||
|
||||
return rectification
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoRectificationOriginResponse, status_code=201)
|
||||
async def create_rectification_origin(
|
||||
pedimento_id: int,
|
||||
data: PedimentoRectificationOriginCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create rectification origin"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
rectification = PedimentoRectificationOriginService.create(db, data, tenant_id)
|
||||
return rectification
|
||||
|
||||
|
||||
@router.put("/", response_model=PedimentoRectificationOriginResponse)
|
||||
async def update_rectification_origin(
|
||||
pedimento_id: int,
|
||||
data: PedimentoRectificationOriginUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update rectification origin"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
rectification = PedimentoRectificationOriginService.update(db, pedimento_id, tenant_id, data)
|
||||
if not rectification:
|
||||
raise HTTPException(status_code=404, detail="Rectification origin not found")
|
||||
|
||||
return rectification
|
||||
|
||||
|
||||
@router.delete("/", status_code=204)
|
||||
async def delete_rectification_origin(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete rectification origin"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoRectificationOriginService.delete(db, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Rectification origin not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,111 @@
|
||||
"""
|
||||
Routes for PedimentoTransportMeans CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_transport_means import PedimentoTransportMeansService
|
||||
from ..dtos.pedimento_transport_means import (
|
||||
PedimentoTransportMeansCreate,
|
||||
PedimentoTransportMeansUpdate,
|
||||
PedimentoTransportMeansResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/transport-means")
|
||||
|
||||
|
||||
@router.get("/", response_model=List[PedimentoTransportMeansResponse])
|
||||
async def list_transport_means(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get all transport means for a pedimento"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
transport_means = PedimentoTransportMeansService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
return transport_means
|
||||
|
||||
|
||||
@router.get("/{transport_mean_id}", response_model=PedimentoTransportMeansResponse)
|
||||
async def get_transport_mean(
|
||||
pedimento_id: int,
|
||||
transport_mean_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get a specific transport mean by ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
transport_mean = PedimentoTransportMeansService.get_by_id(db, transport_mean_id, pedimento_id, tenant_id)
|
||||
if not transport_mean:
|
||||
raise HTTPException(status_code=404, detail="Transport mean not found")
|
||||
|
||||
return transport_mean
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoTransportMeansResponse, status_code=201)
|
||||
async def create_transport_mean(
|
||||
pedimento_id: int,
|
||||
data: PedimentoTransportMeansCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create a new transport mean"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
transport_mean = PedimentoTransportMeansService.create(db, data, tenant_id)
|
||||
return transport_mean
|
||||
|
||||
|
||||
@router.put("/{transport_mean_id}", response_model=PedimentoTransportMeansResponse)
|
||||
async def update_transport_mean(
|
||||
pedimento_id: int,
|
||||
transport_mean_id: int,
|
||||
data: PedimentoTransportMeansUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update a transport mean"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
transport_mean = PedimentoTransportMeansService.update(db, transport_mean_id, pedimento_id, tenant_id, data)
|
||||
if not transport_mean:
|
||||
raise HTTPException(status_code=404, detail="Transport mean not found")
|
||||
|
||||
return transport_mean
|
||||
|
||||
|
||||
@router.delete("/{transport_mean_id}", status_code=204)
|
||||
async def delete_transport_mean(
|
||||
pedimento_id: int,
|
||||
transport_mean_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete a transport mean"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoTransportMeansService.delete(db, transport_mean_id, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Transport mean not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
Routes for PedimentoValidation CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimento_validation import PedimentoValidationService
|
||||
from ..dtos.pedimento_validation import (
|
||||
PedimentoValidationCreate,
|
||||
PedimentoValidationUpdate,
|
||||
PedimentoValidationResponse
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/{pedimento_id}/validation")
|
||||
|
||||
|
||||
@router.get("/", response_model=PedimentoValidationResponse)
|
||||
async def get_validation(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get validation by pedimento ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
validation = PedimentoValidationService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not validation:
|
||||
raise HTTPException(status_code=404, detail="Pedimento validation not found")
|
||||
|
||||
return validation
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoValidationResponse, status_code=201)
|
||||
async def create_validation(
|
||||
pedimento_id: int,
|
||||
data: PedimentoValidationCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create pedimento validation"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
# Ensure pedimento_id matches
|
||||
if data.pedimento_id != pedimento_id:
|
||||
raise HTTPException(status_code=400, detail="Pedimento ID mismatch")
|
||||
|
||||
validation = PedimentoValidationService.create(db, data, tenant_id)
|
||||
return validation
|
||||
|
||||
|
||||
@router.put("/", response_model=PedimentoValidationResponse)
|
||||
async def update_validation(
|
||||
pedimento_id: int,
|
||||
data: PedimentoValidationUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update pedimento validation"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
validation = PedimentoValidationService.update(db, pedimento_id, tenant_id, data)
|
||||
if not validation:
|
||||
raise HTTPException(status_code=404, detail="Pedimento validation not found")
|
||||
|
||||
return validation
|
||||
|
||||
|
||||
@router.delete("/", status_code=204)
|
||||
async def delete_validation(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete pedimento validation"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentoValidationService.delete(db, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Pedimento validation not found")
|
||||
|
||||
return None
|
||||
118
backend/api/v1/modules/a76/pedmientos/routes/pedimentos.py
Normal file
118
backend/api/v1/modules/a76/pedmientos/routes/pedimentos.py
Normal file
@@ -0,0 +1,118 @@
|
||||
"""
|
||||
Routes for Pedimentos CRUD operations
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import Dict, Any, Optional
|
||||
from core.database import get_core_db
|
||||
from core.security import get_current_user, get_tenant_from_token
|
||||
|
||||
from ..services.pedimentos import PedimentosService
|
||||
from ..dtos.pedimentos import PedimentosCreate, PedimentosUpdate, PedimentosResponse
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/", response_model=Dict[str, Any])
|
||||
async def list_pedimentos(
|
||||
page: int = Query(1, ge=1, description="Page number"),
|
||||
page_size: int = Query(50, ge=1, le=100, description="Page size"),
|
||||
status: Optional[str] = Query(None, description="Filter by status"),
|
||||
client_id: Optional[int] = Query(None, description="Filter by client ID"),
|
||||
year: Optional[str] = Query(None, description="Filter by year"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get all pedimentos with pagination and filters"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
filters = {}
|
||||
if status:
|
||||
filters["status"] = status
|
||||
if client_id:
|
||||
filters["client_id"] = client_id
|
||||
if year:
|
||||
filters["year"] = year
|
||||
|
||||
skip = (page - 1) * page_size
|
||||
items, total = PedimentosService.get_all(db, tenant_id, skip, page_size, filters)
|
||||
|
||||
return {
|
||||
"items": [PedimentosResponse.model_validate(item) for item in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{pedimento_id}", response_model=PedimentosResponse)
|
||||
async def get_pedimento(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Get a pedimento by ID"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
pedimento = PedimentosService.get_by_id(db, pedimento_id, tenant_id)
|
||||
if not pedimento:
|
||||
raise HTTPException(status_code=404, detail="Pedimento not found")
|
||||
|
||||
return pedimento
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentosResponse, status_code=201)
|
||||
async def create_pedimento(
|
||||
data: PedimentosCreate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Create a new pedimento"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
pedimento = PedimentosService.create(db, data, tenant_id)
|
||||
return pedimento
|
||||
|
||||
|
||||
@router.put("/{pedimento_id}", response_model=PedimentosResponse)
|
||||
async def update_pedimento(
|
||||
pedimento_id: int,
|
||||
data: PedimentosUpdate,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Update a pedimento"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
pedimento = PedimentosService.update(db, pedimento_id, tenant_id, data)
|
||||
if not pedimento:
|
||||
raise HTTPException(status_code=404, detail="Pedimento not found")
|
||||
|
||||
return pedimento
|
||||
|
||||
|
||||
@router.delete("/{pedimento_id}", status_code=204)
|
||||
async def delete_pedimento(
|
||||
pedimento_id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""Delete a pedimento"""
|
||||
tenant_id = get_tenant_from_token(current_user)
|
||||
if not tenant_id:
|
||||
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
|
||||
|
||||
success = PedimentosService.delete(db, pedimento_id, tenant_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Pedimento not found")
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoConfigAdditional CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_config_additional import PedimentoConfigAdditional
|
||||
from ..dtos.pedimento_config_additional import PedimentoConfigAdditionalCreate, PedimentoConfigAdditionalUpdate
|
||||
|
||||
|
||||
class PedimentoConfigAdditionalService:
|
||||
"""Service class for PedimentoConfigAdditional business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoConfigAdditional]:
|
||||
"""Get config by pedimento ID"""
|
||||
return db.query(PedimentoConfigAdditional).filter(
|
||||
PedimentoConfigAdditional.pedimento_id == pedimento_id,
|
||||
PedimentoConfigAdditional.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, config_data: PedimentoConfigAdditionalCreate) -> PedimentoConfigAdditional:
|
||||
"""Create a new config"""
|
||||
config = PedimentoConfigAdditional(**config_data.model_dump())
|
||||
db.add(config)
|
||||
db.commit()
|
||||
db.refresh(config)
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
config_data: PedimentoConfigAdditionalUpdate
|
||||
) -> Optional[PedimentoConfigAdditional]:
|
||||
"""Update config"""
|
||||
config = PedimentoConfigAdditionalService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
return None
|
||||
|
||||
update_data = config_data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(config, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(config)
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete config"""
|
||||
config = PedimentoConfigAdditionalService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
return False
|
||||
|
||||
db.delete(config)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoConfigCalculations CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_config_calculations import PedimentoConfigCalculations
|
||||
from ..dtos.pedimento_config_calculations import PedimentoConfigCalculationsCreate, PedimentoConfigCalculationsUpdate
|
||||
|
||||
|
||||
class PedimentoConfigCalculationsService:
|
||||
"""Service class for PedimentoConfigCalculations business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoConfigCalculations]:
|
||||
"""Get config by pedimento ID"""
|
||||
return db.query(PedimentoConfigCalculations).filter(
|
||||
PedimentoConfigCalculations.pedimento_id == pedimento_id,
|
||||
PedimentoConfigCalculations.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, config_data: PedimentoConfigCalculationsCreate) -> PedimentoConfigCalculations:
|
||||
"""Create a new config"""
|
||||
config = PedimentoConfigCalculations(**config_data.model_dump())
|
||||
db.add(config)
|
||||
db.commit()
|
||||
db.refresh(config)
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
config_data: PedimentoConfigCalculationsUpdate
|
||||
) -> Optional[PedimentoConfigCalculations]:
|
||||
"""Update config"""
|
||||
config = PedimentoConfigCalculationsService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
return None
|
||||
|
||||
update_data = config_data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(config, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(config)
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete config"""
|
||||
config = PedimentoConfigCalculationsService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
return False
|
||||
|
||||
db.delete(config)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoConfigParameters CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_config_parameters import PedimentoConfigParameters
|
||||
from ..dtos.pedimento_config_parameters import PedimentoConfigParametersCreate, PedimentoConfigParametersUpdate
|
||||
|
||||
|
||||
class PedimentoConfigParametersService:
|
||||
"""Service class for PedimentoConfigParameters business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoConfigParameters]:
|
||||
"""Get config by pedimento ID"""
|
||||
return db.query(PedimentoConfigParameters).filter(
|
||||
PedimentoConfigParameters.pedimento_id == pedimento_id,
|
||||
PedimentoConfigParameters.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, config_data: PedimentoConfigParametersCreate) -> PedimentoConfigParameters:
|
||||
"""Create a new config"""
|
||||
config = PedimentoConfigParameters(**config_data.model_dump())
|
||||
db.add(config)
|
||||
db.commit()
|
||||
db.refresh(config)
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
config_data: PedimentoConfigParametersUpdate
|
||||
) -> Optional[PedimentoConfigParameters]:
|
||||
"""Update config"""
|
||||
config = PedimentoConfigParametersService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
return None
|
||||
|
||||
update_data = config_data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(config, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(config)
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete config"""
|
||||
config = PedimentoConfigParametersService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
return False
|
||||
|
||||
db.delete(config)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoConfigSurcharges CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_config_surcharges import PedimentoConfigSurcharges
|
||||
from ..dtos.pedimento_config_surcharges import PedimentoConfigSurchargesCreate, PedimentoConfigSurchargesUpdate
|
||||
|
||||
|
||||
class PedimentoConfigSurchargesService:
|
||||
"""Service class for PedimentoConfigSurcharges business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoConfigSurcharges]:
|
||||
"""Get config by pedimento ID"""
|
||||
return db.query(PedimentoConfigSurcharges).filter(
|
||||
PedimentoConfigSurcharges.pedimento_id == pedimento_id,
|
||||
PedimentoConfigSurcharges.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, config_data: PedimentoConfigSurchargesCreate) -> PedimentoConfigSurcharges:
|
||||
"""Create a new config"""
|
||||
config = PedimentoConfigSurcharges(**config_data.model_dump())
|
||||
db.add(config)
|
||||
db.commit()
|
||||
db.refresh(config)
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
config_data: PedimentoConfigSurchargesUpdate
|
||||
) -> Optional[PedimentoConfigSurcharges]:
|
||||
"""Update config"""
|
||||
config = PedimentoConfigSurchargesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
return None
|
||||
|
||||
update_data = config_data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(config, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(config)
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete config"""
|
||||
config = PedimentoConfigSurchargesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
return False
|
||||
|
||||
db.delete(config)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoConfigUpdateRectification CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_config_update_rectification import PedimentoConfigUpdateRectification
|
||||
from ..dtos.pedimento_config_update_rectification import PedimentoConfigUpdateRectificationCreate, PedimentoConfigUpdateRectificationUpdate
|
||||
|
||||
|
||||
class PedimentoConfigUpdateRectificationService:
|
||||
"""Service class for PedimentoConfigUpdateRectification business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoConfigUpdateRectification]:
|
||||
"""Get config by pedimento ID"""
|
||||
return db.query(PedimentoConfigUpdateRectification).filter(
|
||||
PedimentoConfigUpdateRectification.pedimento_id == pedimento_id,
|
||||
PedimentoConfigUpdateRectification.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, config_data: PedimentoConfigUpdateRectificationCreate) -> PedimentoConfigUpdateRectification:
|
||||
"""Create a new config"""
|
||||
config = PedimentoConfigUpdateRectification(**config_data.model_dump())
|
||||
db.add(config)
|
||||
db.commit()
|
||||
db.refresh(config)
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
config_data: PedimentoConfigUpdateRectificationUpdate
|
||||
) -> Optional[PedimentoConfigUpdateRectification]:
|
||||
"""Update config"""
|
||||
config = PedimentoConfigUpdateRectificationService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
return None
|
||||
|
||||
update_data = config_data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(config, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(config)
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete config"""
|
||||
config = PedimentoConfigUpdateRectificationService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
return False
|
||||
|
||||
db.delete(config)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoConfigUpdates CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_config_updates import PedimentoConfigUpdates
|
||||
from ..dtos.pedimento_config_updates import PedimentoConfigUpdatesCreate, PedimentoConfigUpdatesUpdate
|
||||
|
||||
|
||||
class PedimentoConfigUpdatesService:
|
||||
"""Service class for PedimentoConfigUpdates business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoConfigUpdates]:
|
||||
"""Get config by pedimento ID"""
|
||||
return db.query(PedimentoConfigUpdates).filter(
|
||||
PedimentoConfigUpdates.pedimento_id == pedimento_id,
|
||||
PedimentoConfigUpdates.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, config_data: PedimentoConfigUpdatesCreate) -> PedimentoConfigUpdates:
|
||||
"""Create a new config"""
|
||||
config = PedimentoConfigUpdates(**config_data.model_dump())
|
||||
db.add(config)
|
||||
db.commit()
|
||||
db.refresh(config)
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
config_data: PedimentoConfigUpdatesUpdate
|
||||
) -> Optional[PedimentoConfigUpdates]:
|
||||
"""Update config"""
|
||||
config = PedimentoConfigUpdatesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
return None
|
||||
|
||||
update_data = config_data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(config, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(config)
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete config"""
|
||||
config = PedimentoConfigUpdatesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not config:
|
||||
return False
|
||||
|
||||
db.delete(config)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoCustomsOffices CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_customs_offices import PedimentoCustomsOffices
|
||||
from ..dtos.pedimento_customs_offices import PedimentoCustomsOfficesCreate, PedimentoCustomsOfficesUpdate
|
||||
|
||||
|
||||
class PedimentoCustomsOfficesService:
|
||||
"""Service class for PedimentoCustomsOffices business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoCustomsOffices]:
|
||||
"""Get customs offices by pedimento ID"""
|
||||
return db.query(PedimentoCustomsOffices).filter(
|
||||
PedimentoCustomsOffices.pedimento_id == pedimento_id,
|
||||
PedimentoCustomsOffices.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, data: PedimentoCustomsOfficesCreate) -> PedimentoCustomsOffices:
|
||||
"""Create new customs offices"""
|
||||
offices = PedimentoCustomsOffices(**data.model_dump())
|
||||
db.add(offices)
|
||||
db.commit()
|
||||
db.refresh(offices)
|
||||
return offices
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
data: PedimentoCustomsOfficesUpdate
|
||||
) -> Optional[PedimentoCustomsOffices]:
|
||||
"""Update customs offices"""
|
||||
offices = PedimentoCustomsOfficesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not offices:
|
||||
return None
|
||||
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(offices, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(offices)
|
||||
return offices
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete customs offices"""
|
||||
offices = PedimentoCustomsOfficesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not offices:
|
||||
return False
|
||||
|
||||
db.delete(offices)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoDates CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_dates import PedimentoDates
|
||||
from ..dtos.pedimento_dates import PedimentoDatesCreate, PedimentoDatesUpdate
|
||||
|
||||
|
||||
class PedimentoDatesService:
|
||||
"""Service class for PedimentoDates business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoDates]:
|
||||
"""Get dates by pedimento ID"""
|
||||
return db.query(PedimentoDates).filter(
|
||||
PedimentoDates.pedimento_id == pedimento_id,
|
||||
PedimentoDates.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, data: PedimentoDatesCreate) -> PedimentoDates:
|
||||
"""Create new pedimento dates"""
|
||||
dates = PedimentoDates(**data.model_dump())
|
||||
db.add(dates)
|
||||
db.commit()
|
||||
db.refresh(dates)
|
||||
return dates
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
data: PedimentoDatesUpdate
|
||||
) -> Optional[PedimentoDates]:
|
||||
"""Update pedimento dates"""
|
||||
dates = PedimentoDatesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not dates:
|
||||
return None
|
||||
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(dates, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(dates)
|
||||
return dates
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete pedimento dates"""
|
||||
dates = PedimentoDatesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not dates:
|
||||
return False
|
||||
|
||||
db.delete(dates)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoDecrementables CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_decrementables import PedimentoDecrementables
|
||||
from ..dtos.pedimento_decrementables import PedimentoDecrementablesCreate, PedimentoDecrementablesUpdate
|
||||
|
||||
|
||||
class PedimentoDecrementablesService:
|
||||
"""Service class for PedimentoDecrementables business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoDecrementables]:
|
||||
"""Get decrementables by pedimento ID"""
|
||||
return db.query(PedimentoDecrementables).filter(
|
||||
PedimentoDecrementables.pedimento_id == pedimento_id,
|
||||
PedimentoDecrementables.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, data: PedimentoDecrementablesCreate) -> PedimentoDecrementables:
|
||||
"""Create new decrementables"""
|
||||
decrementables = PedimentoDecrementables(**data.model_dump())
|
||||
db.add(decrementables)
|
||||
db.commit()
|
||||
db.refresh(decrementables)
|
||||
return decrementables
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
data: PedimentoDecrementablesUpdate
|
||||
) -> Optional[PedimentoDecrementables]:
|
||||
"""Update decrementables"""
|
||||
decrementables = PedimentoDecrementablesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not decrementables:
|
||||
return None
|
||||
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(decrementables, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(decrementables)
|
||||
return decrementables
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete decrementables"""
|
||||
decrementables = PedimentoDecrementablesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not decrementables:
|
||||
return False
|
||||
|
||||
db.delete(decrementables)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoIncrementables CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_incrementables import PedimentoIncrementables
|
||||
from ..dtos.pedimento_incrementables import PedimentoIncrementablesCreate, PedimentoIncrementablesUpdate
|
||||
|
||||
|
||||
class PedimentoIncrementablesService:
|
||||
"""Service class for PedimentoIncrementables business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoIncrementables]:
|
||||
"""Get incrementables by pedimento ID"""
|
||||
return db.query(PedimentoIncrementables).filter(
|
||||
PedimentoIncrementables.pedimento_id == pedimento_id,
|
||||
PedimentoIncrementables.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, data: PedimentoIncrementablesCreate) -> PedimentoIncrementables:
|
||||
"""Create new incrementables"""
|
||||
incrementables = PedimentoIncrementables(**data.model_dump())
|
||||
db.add(incrementables)
|
||||
db.commit()
|
||||
db.refresh(incrementables)
|
||||
return incrementables
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
data: PedimentoIncrementablesUpdate
|
||||
) -> Optional[PedimentoIncrementables]:
|
||||
"""Update incrementables"""
|
||||
incrementables = PedimentoIncrementablesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not incrementables:
|
||||
return None
|
||||
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(incrementables, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(incrementables)
|
||||
return incrementables
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete incrementables"""
|
||||
incrementables = PedimentoIncrementablesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not incrementables:
|
||||
return False
|
||||
|
||||
db.delete(incrementables)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoIndexes CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_indexes import PedimentoIndexes
|
||||
from ..dtos.pedimento_indexes import PedimentoIndexesCreate, PedimentoIndexesUpdate
|
||||
|
||||
|
||||
class PedimentoIndexesService:
|
||||
"""Service class for PedimentoIndexes business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoIndexes]:
|
||||
"""Get indexes by pedimento ID"""
|
||||
return db.query(PedimentoIndexes).filter(
|
||||
PedimentoIndexes.pedimento_id == pedimento_id,
|
||||
PedimentoIndexes.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, data: PedimentoIndexesCreate) -> PedimentoIndexes:
|
||||
"""Create new indexes"""
|
||||
indexes = PedimentoIndexes(**data.model_dump())
|
||||
db.add(indexes)
|
||||
db.commit()
|
||||
db.refresh(indexes)
|
||||
return indexes
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
data: PedimentoIndexesUpdate
|
||||
) -> Optional[PedimentoIndexes]:
|
||||
"""Update indexes"""
|
||||
indexes = PedimentoIndexesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not indexes:
|
||||
return None
|
||||
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(indexes, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(indexes)
|
||||
return indexes
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete indexes"""
|
||||
indexes = PedimentoIndexesService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not indexes:
|
||||
return False
|
||||
|
||||
db.delete(indexes)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoPayments CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_payments import PedimentoPayments
|
||||
from ..dtos.pedimento_payments import PedimentoPaymentsCreate, PedimentoPaymentsUpdate
|
||||
|
||||
|
||||
class PedimentoPaymentsService:
|
||||
"""Service class for PedimentoPayments business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoPayments]:
|
||||
"""Get payments by pedimento ID"""
|
||||
return db.query(PedimentoPayments).filter(
|
||||
PedimentoPayments.pedimento_id == pedimento_id,
|
||||
PedimentoPayments.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, data: PedimentoPaymentsCreate) -> PedimentoPayments:
|
||||
"""Create new payments"""
|
||||
payments = PedimentoPayments(**data.model_dump())
|
||||
db.add(payments)
|
||||
db.commit()
|
||||
db.refresh(payments)
|
||||
return payments
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
data: PedimentoPaymentsUpdate
|
||||
) -> Optional[PedimentoPayments]:
|
||||
"""Update payments"""
|
||||
payments = PedimentoPaymentsService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not payments:
|
||||
return None
|
||||
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(payments, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(payments)
|
||||
return payments
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete payments"""
|
||||
payments = PedimentoPaymentsService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not payments:
|
||||
return False
|
||||
|
||||
db.delete(payments)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoRectificationDestination CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_rectification_destination import PedimentoRectificationDestination
|
||||
from ..dtos.pedimento_rectification_destination import PedimentoRectificationDestinationCreate, PedimentoRectificationDestinationUpdate
|
||||
|
||||
|
||||
class PedimentoRectificationDestinationService:
|
||||
"""Service class for PedimentoRectificationDestination business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoRectificationDestination]:
|
||||
"""Get rectification destination by pedimento ID"""
|
||||
return db.query(PedimentoRectificationDestination).filter(
|
||||
PedimentoRectificationDestination.pedimento_id == pedimento_id,
|
||||
PedimentoRectificationDestination.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, data: PedimentoRectificationDestinationCreate) -> PedimentoRectificationDestination:
|
||||
"""Create new rectification destination"""
|
||||
rectification = PedimentoRectificationDestination(**data.model_dump())
|
||||
db.add(rectification)
|
||||
db.commit()
|
||||
db.refresh(rectification)
|
||||
return rectification
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
data: PedimentoRectificationDestinationUpdate
|
||||
) -> Optional[PedimentoRectificationDestination]:
|
||||
"""Update rectification destination"""
|
||||
rectification = PedimentoRectificationDestinationService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not rectification:
|
||||
return None
|
||||
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(rectification, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(rectification)
|
||||
return rectification
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete rectification destination"""
|
||||
rectification = PedimentoRectificationDestinationService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not rectification:
|
||||
return False
|
||||
|
||||
db.delete(rectification)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoRectificationOrigin CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_rectification_origin import PedimentoRectificationOrigin
|
||||
from ..dtos.pedimento_rectification_origin import PedimentoRectificationOriginCreate, PedimentoRectificationOriginUpdate
|
||||
|
||||
|
||||
class PedimentoRectificationOriginService:
|
||||
"""Service class for PedimentoRectificationOrigin business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoRectificationOrigin]:
|
||||
"""Get rectification origin by pedimento ID"""
|
||||
return db.query(PedimentoRectificationOrigin).filter(
|
||||
PedimentoRectificationOrigin.pedimento_id == pedimento_id,
|
||||
PedimentoRectificationOrigin.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, data: PedimentoRectificationOriginCreate) -> PedimentoRectificationOrigin:
|
||||
"""Create new rectification origin"""
|
||||
rectification = PedimentoRectificationOrigin(**data.model_dump())
|
||||
db.add(rectification)
|
||||
db.commit()
|
||||
db.refresh(rectification)
|
||||
return rectification
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
data: PedimentoRectificationOriginUpdate
|
||||
) -> Optional[PedimentoRectificationOrigin]:
|
||||
"""Update rectification origin"""
|
||||
rectification = PedimentoRectificationOriginService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not rectification:
|
||||
return None
|
||||
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(rectification, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(rectification)
|
||||
return rectification
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete rectification origin"""
|
||||
rectification = PedimentoRectificationOriginService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not rectification:
|
||||
return False
|
||||
|
||||
db.delete(rectification)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoTransportMeans CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_transport_means import PedimentoTransportMeans
|
||||
from ..dtos.pedimento_transport_means import PedimentoTransportMeansCreate, PedimentoTransportMeansUpdate
|
||||
|
||||
|
||||
class PedimentoTransportMeansService:
|
||||
"""Service class for PedimentoTransportMeans business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoTransportMeans]:
|
||||
"""Get transport means by pedimento ID"""
|
||||
return db.query(PedimentoTransportMeans).filter(
|
||||
PedimentoTransportMeans.pedimento_id == pedimento_id,
|
||||
PedimentoTransportMeans.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, data: PedimentoTransportMeansCreate) -> PedimentoTransportMeans:
|
||||
"""Create new transport means"""
|
||||
transport = PedimentoTransportMeans(**data.model_dump())
|
||||
db.add(transport)
|
||||
db.commit()
|
||||
db.refresh(transport)
|
||||
return transport
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
data: PedimentoTransportMeansUpdate
|
||||
) -> Optional[PedimentoTransportMeans]:
|
||||
"""Update transport means"""
|
||||
transport = PedimentoTransportMeansService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not transport:
|
||||
return None
|
||||
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(transport, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(transport)
|
||||
return transport
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete transport means"""
|
||||
transport = PedimentoTransportMeansService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not transport:
|
||||
return False
|
||||
|
||||
db.delete(transport)
|
||||
db.commit()
|
||||
return True
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Service layer for PedimentoValidation CRUD operations
|
||||
"""
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models.pedimento_validation import PedimentoValidation
|
||||
from ..dtos.pedimento_validation import PedimentoValidationCreate, PedimentoValidationUpdate
|
||||
|
||||
|
||||
class PedimentoValidationService:
|
||||
"""Service class for PedimentoValidation business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_by_pedimento_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[PedimentoValidation]:
|
||||
"""Get validation by pedimento ID"""
|
||||
return db.query(PedimentoValidation).filter(
|
||||
PedimentoValidation.pedimento_id == pedimento_id,
|
||||
PedimentoValidation.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, data: PedimentoValidationCreate) -> PedimentoValidation:
|
||||
"""Create new validation"""
|
||||
validation = PedimentoValidation(**data.model_dump())
|
||||
db.add(validation)
|
||||
db.commit()
|
||||
db.refresh(validation)
|
||||
return validation
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
data: PedimentoValidationUpdate
|
||||
) -> Optional[PedimentoValidation]:
|
||||
"""Update validation"""
|
||||
validation = PedimentoValidationService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not validation:
|
||||
return None
|
||||
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(validation, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(validation)
|
||||
return validation
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""Delete validation"""
|
||||
validation = PedimentoValidationService.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
if not validation:
|
||||
return False
|
||||
|
||||
db.delete(validation)
|
||||
db.commit()
|
||||
return True
|
||||
140
backend/api/v1/modules/a76/pedmientos/services/pedimentos.py
Normal file
140
backend/api/v1/modules/a76/pedmientos/services/pedimentos.py
Normal file
@@ -0,0 +1,140 @@
|
||||
"""
|
||||
Service layer for Pedimentos CRUD operations
|
||||
"""
|
||||
from typing import List, Optional, Dict, Any
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import desc
|
||||
from fastapi import HTTPException
|
||||
|
||||
from ..models.pedimentos import Pedimentos
|
||||
from ..dtos.pedimentos import PedimentosCreate, PedimentosUpdate
|
||||
|
||||
|
||||
class PedimentosService:
|
||||
"""Service class for Pedimentos business logic"""
|
||||
|
||||
@staticmethod
|
||||
def get_all(
|
||||
db: Session,
|
||||
tenant_id: int,
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
filters: Optional[Dict[str, Any]] = None
|
||||
) -> tuple[List[Pedimentos], int]:
|
||||
"""
|
||||
Get all pedimentos for a tenant with pagination and filters
|
||||
|
||||
Args:
|
||||
db: Database session
|
||||
tenant_id: Tenant ID
|
||||
skip: Number of records to skip
|
||||
limit: Maximum number of records to return
|
||||
filters: Optional filters dict
|
||||
|
||||
Returns:
|
||||
Tuple of (list of pedimentos, total count)
|
||||
"""
|
||||
query = db.query(Pedimentos).filter(Pedimentos.tenant_id == tenant_id)
|
||||
|
||||
if filters:
|
||||
if filters.get("status"):
|
||||
query = query.filter(Pedimentos.status == filters["status"])
|
||||
if filters.get("client_id"):
|
||||
query = query.filter(Pedimentos.client_id == filters["client_id"])
|
||||
if filters.get("year"):
|
||||
query = query.filter(Pedimentos.year == filters["year"])
|
||||
|
||||
total = query.count()
|
||||
items = query.order_by(desc(Pedimentos.created_at)).offset(skip).limit(limit).all()
|
||||
|
||||
return items, total
|
||||
|
||||
@staticmethod
|
||||
def get_by_id(db: Session, pedimento_id: int, tenant_id: int) -> Optional[Pedimentos]:
|
||||
"""
|
||||
Get a pedimento by ID
|
||||
|
||||
Args:
|
||||
db: Database session
|
||||
pedimento_id: Pedimento ID
|
||||
tenant_id: Tenant ID
|
||||
|
||||
Returns:
|
||||
Pedimento or None if not found
|
||||
"""
|
||||
return db.query(Pedimentos).filter(
|
||||
Pedimentos.id == pedimento_id,
|
||||
Pedimentos.tenant_id == tenant_id
|
||||
).first()
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, pedimento_data: PedimentosCreate, tenant_id: int) -> Pedimentos:
|
||||
"""
|
||||
Create a new pedimento
|
||||
|
||||
Args:
|
||||
db: Database session
|
||||
pedimento_data: Pedimento creation data
|
||||
|
||||
Returns:
|
||||
Created pedimento
|
||||
"""
|
||||
pedimento = Pedimentos(**pedimento_data.model_dump())
|
||||
pedimento.tenant_id = 1
|
||||
|
||||
db.add(pedimento)
|
||||
db.commit()
|
||||
db.refresh(pedimento)
|
||||
return pedimento
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
pedimento_id: int,
|
||||
tenant_id: int,
|
||||
pedimento_data: PedimentosUpdate
|
||||
) -> Optional[Pedimentos]:
|
||||
"""
|
||||
Update a pedimento
|
||||
|
||||
Args:
|
||||
db: Database session
|
||||
pedimento_id: Pedimento ID
|
||||
tenant_id: Tenant ID
|
||||
pedimento_data: Updated data
|
||||
|
||||
Returns:
|
||||
Updated pedimento or None if not found
|
||||
"""
|
||||
pedimento = PedimentosService.get_by_id(db, pedimento_id, tenant_id)
|
||||
if not pedimento:
|
||||
return None
|
||||
|
||||
update_data = pedimento_data.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(pedimento, field, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(pedimento)
|
||||
return pedimento
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, pedimento_id: int, tenant_id: int) -> bool:
|
||||
"""
|
||||
Delete a pedimento
|
||||
|
||||
Args:
|
||||
db: Database session
|
||||
pedimento_id: Pedimento ID
|
||||
tenant_id: Tenant ID
|
||||
|
||||
Returns:
|
||||
True if deleted, False if not found
|
||||
"""
|
||||
pedimento = PedimentosService.get_by_id(db, pedimento_id, tenant_id)
|
||||
if not pedimento:
|
||||
return False
|
||||
|
||||
db.delete(pedimento)
|
||||
db.commit()
|
||||
return True
|
||||
29
backend/api/v1/modules/a76/router.py
Normal file
29
backend/api/v1/modules/a76/router.py
Normal file
@@ -0,0 +1,29 @@
|
||||
"""
|
||||
Router principal de API v1
|
||||
Agrega todos los módulos de la aplicación
|
||||
"""
|
||||
from fastapi import APIRouter
|
||||
|
||||
# Importar routers de módulos
|
||||
from .auth import router as auth_router
|
||||
from .tenants import router as tenants_router
|
||||
from .licenses import router as licenses_router
|
||||
from .pedmientos.router import router as pedimentos_router
|
||||
from .client_and_provider import router as client_and_provider_router
|
||||
from .company import router as company_router
|
||||
from .classes import router as classes_router
|
||||
from .parts import router as parts_router
|
||||
|
||||
# Router principal
|
||||
router = APIRouter()
|
||||
|
||||
# Registrar módulos
|
||||
router.include_router(auth_router)
|
||||
router.include_router(tenants_router, prefix="/a76", tags=["a76 / tenants"])
|
||||
router.include_router(licenses_router, prefix="/a76", tags=["a76 / licenses"])
|
||||
router.include_router(pedimentos_router, prefix="/a76")
|
||||
router.include_router(client_and_provider_router, prefix="/a76", tags=["a76 / clients and providers"])
|
||||
router.include_router(company_router, prefix="/a76", tags=["a76 / company"])
|
||||
router.include_router(classes_router, prefix="/a76", tags=["a76 / classes"])
|
||||
router.include_router(parts_router, prefix="/a76", tags=["a76 / parts"])
|
||||
|
||||
@@ -10,7 +10,7 @@ from core.security import get_current_user, has_role
|
||||
from .dto import TenantCreateDTO, TenantUpdateDTO, TenantResponseDTO, TenantListResponseDTO
|
||||
from .service import TenantService
|
||||
|
||||
router = APIRouter(prefix="/tenants", tags=["Tenants"])
|
||||
router = APIRouter(prefix="/tenants")
|
||||
|
||||
|
||||
@router.post("/", response_model=TenantResponseDTO, status_code=201)
|
||||
|
||||
@@ -3,7 +3,7 @@ from pydantic import ConfigDict
|
||||
from typing import Optional
|
||||
|
||||
class CodePedimentoRegimenDTO(BaseModel):
|
||||
id: int
|
||||
id: Optional[int] = None
|
||||
pedimento_code: str = Field(..., min_length=1, max_length=3)
|
||||
regimen_code: Optional[str] = Field(None, min_length=1, max_length=3)
|
||||
type_code: Optional[str] = Field(None, min_length=1, max_length=1)
|
||||
|
||||
@@ -8,7 +8,7 @@ from .dto import CodePedimentoRegimenDTO
|
||||
from typing import Any, Dict
|
||||
|
||||
|
||||
router = APIRouter(prefix="/code-pedimento-regimens", tags=["Code Pedimento Regimens"])
|
||||
router = APIRouter(prefix="/code-pedimento-regimens")
|
||||
|
||||
|
||||
@router.get("/", response_model=Dict[str, Any])
|
||||
|
||||
@@ -8,7 +8,7 @@ from .dto import ContainerDTO
|
||||
from typing import Any, Dict
|
||||
|
||||
|
||||
router = APIRouter(prefix="/containers", tags=["Containers"])
|
||||
router = APIRouter(prefix="/containers")
|
||||
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user