feature/refactorizacion-tabla-sector

This commit is contained in:
hreyes
2026-03-17 11:21:28 -06:00
parent 20a351c475
commit fbbe4370de
32 changed files with 4167 additions and 3947 deletions

View File

@@ -44,7 +44,7 @@ from api.v1.modules.public.reference_data.pedimento_codes.seed import (
from api.v1.modules.public.reference_data.pedimento_regimens.seed import (
seed as pedimento_regimens_seed,
)
from api.v1.modules.public.reference_data.sectors.seed import seed as sectors_seed
from api.v1.modules.a76.general_catalogs.sectors.seed import seed as sectors_seed
from api.v1.modules.public.reference_data.states.seed import seed as states_seed
from api.v1.modules.public.reference_data.transport_modes.seed import (
seed as transport_modes_seed,
@@ -268,19 +268,8 @@ def upgrade() -> None:
"""
)
values_sectors = ", ".join(
[
f"('{key}', '{desc.replace(chr(39), chr(39)*2)}', '{authorized}')"
for key, desc, authorized in sectors_seed
]
)
op.execute(
f"""
INSERT INTO public.sectors (key, description, authorized) VALUES
{values_sectors}
ON CONFLICT (key) DO NOTHING;
"""
)
# Sectors se siembran por compañía en _seed_company_data
# (a76.sectors requiere tenant_id/company_id — no aplica en seed global)
values_tm = ", ".join(
[
@@ -493,7 +482,7 @@ def downgrade() -> None:
op.drop_table("transport_types", schema="public")
op.drop_table("trailer_types", schema="public")
op.drop_table("transport_modes", schema="public")
op.drop_table("sectors", schema="public")
op.drop_table("sectors", schema="a76")
op.drop_table("payment_methods", schema="public")
op.drop_table("material_types", schema="public")
op.drop_table("invoice_types", schema="public")

View File

@@ -16,6 +16,7 @@ from ...audit_log.services.service import AuditService
from ..units_of_measure.seed import seed as units_of_measure_seed
from ..fractions.historical_tariff_fractions.seed import seed as historical_tariff_fractions_seed
from ..fractions.warning_fractions.seed import seed as warning_fractions_seed
from ..sectors.seed import seed as sectors_seed
from core.context import get_user_context
from sqlalchemy import text
@@ -774,6 +775,21 @@ class CompanyService:
"""))
db.execute(text("ALTER TABLE public.warning_fractions ENABLE TRIGGER ALL;"))
# 4. Sectors
values_sectors = ", ".join(
[
f"({format_value(key)}, {format_value(description)}, {str(authorized).upper()}, {tenant_id}, {company_id})"
for key, description, authorized in sectors_seed
]
)
if values_sectors:
db.execute(text(f"""
INSERT INTO a76.sectors (key, description, authorized, tenant_id, company_id)
VALUES {values_sectors}
ON CONFLICT (key, tenant_id, company_id) DO NOTHING;
"""))
def get_companies_by_tenant(self, tenant_id: int) -> List[Company]:
"""Get all companies for a tenant"""
return (

View File

@@ -26,6 +26,7 @@ from .doda.routes import router as doda_router
from .prevalidators.routes import router as prevalidators_router
from .electronic_notices.routes import router as electronic_notices_router
from .location.routes import router as location_router
from .sectors.routes import router as sectors_router
router = APIRouter()
@@ -56,3 +57,4 @@ router.include_router(error_catalogs_router)
router.include_router(doda_router)
router.include_router(prevalidators_router)
router.include_router(electronic_notices_router)
router.include_router(sectors_router)

View File

@@ -0,0 +1,30 @@
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, ConfigDict, Field
class SectorBaseDTO(BaseModel):
key: str = Field(..., description="Clave del sector (ej: 'XIX', 'IIa')", max_length=8)
description: str = Field(..., description="Descripción del sector", max_length=150)
authorized: Optional[bool] = Field(False, description="True = autorizado para PROSEC")
class SectorCreateDTO(SectorBaseDTO):
pass
class SectorUpdateDTO(BaseModel):
key: Optional[str] = Field(None, max_length=8)
description: Optional[str] = Field(None, max_length=150)
authorized: Optional[bool] = None
class SectorResponseDTO(SectorBaseDTO):
id: int
company_id: int
tenant_id: int
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)

View File

@@ -0,0 +1,23 @@
from typing import Optional
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base
from sqlalchemy import Boolean, Integer, PrimaryKeyConstraint, String, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column
class Sector(Base, TenantScopedMixin, TimestampMixin):
__tablename__ = "sectors" # GSectores
__table_args__ = (
PrimaryKeyConstraint("id", name="sectors_pkey"),
UniqueConstraint("tenant_id", "company_id", "key", name="sectors_key_ukey"),
{"schema": "a76", "extend_existing": True},
)
id: Mapped[int] = mapped_column(Integer, primary_key=True)
key: Mapped[str] = mapped_column(String(8), nullable=False)
description: Mapped[str] = mapped_column(String(150), nullable=False)
authorized: Mapped[Optional[bool]] = mapped_column(Boolean, default=False, server_default="false")
def __repr__(self):
return f"<Sector(id={self.id}, key={self.key}, description={self.description}, authorized={self.authorized})>"

View File

@@ -0,0 +1,23 @@
"""
Routes for managing Sectors (GSectores) — a76 tenant-scoped catalog.
"""
from api.v1.common.tenant_crud_routes import TenantCRUDRoutes
from .dto import SectorCreateDTO, SectorResponseDTO, SectorUpdateDTO
from .service import SectorService
router = TenantCRUDRoutes(
service=SectorService,
create_schema=SectorCreateDTO,
update_schema=SectorUpdateDTO,
response_schema=SectorResponseDTO,
prefix="/sectors",
tags=["a76 / sectors"],
resource_name="Sector",
id_name="sector_id",
enable_list=True,
enable_filters=True,
default_page_size=50,
max_page_size=100,
).router

View File

@@ -0,0 +1,36 @@
# (key, description, authorized)
seed = [
("I", "INDUSTRIA ELECTRICA", False),
("II", "INDUSTRIA ELECTRONICA", False),
("IIa", "PARA LOS BIENES A QUE SE REFIERE LA FRACCION II, INCISO a) o b), DE ARTICULO 4to DE ESTE DECRETO.", False),
("IIb", "PARA LOS BIENES A QUE SE REFIERE LA FRACCION II, INCISO b), DE ARTICULO 4to DE ESTE DECRETO.", False),
("III", "INDUSTRIA DEL MUEBLE", False),
("IV", "INDUSTRIA DEL JUGUETE, JUEGOS DE RECREO Y ARTICULOS DEPORTIVOS", False),
("IX", "INDUSTRIA DE MAQUINARIA AGRICOLA", False),
("V", "INDUSTRIA DEL CALZADO", False),
("VI", "INDUSTRIA MINERA Y METALURGICA", False),
("VII", "INDUSTRIA DE BIENES DE CAPITAL", False),
("VIII", "INDUSTRIA FOTOGRAFICA", False),
("X", "INDUSTRIAS DIVERSAS", False),
("XI", "INDUSTRIA QUIMICA", False),
("XII", "INDUSTRIAS DE MANUFACTURAS DEL CAUCHO Y PLASTICOS", False),
("XIII", "INDUSTRIA SIDERURGICA", False),
("XIV", "INDUSTRIA DE PRODUCTOS FARMOQUIMICOS, MEDICAMENTOS Y EQUIPO MEDICO", False),
("XIX", "INDUSTRIA AUTOMOTRIZ Y DE AUTOPARTES", False),
("XIXa", "INDUSTRIA AUTOMOTRIZ Y DE AUTOPARTES", False),
("XIXb", "INDUSTRIA AUTOMOTRIZ Y DE AUTOPARTES", False),
("XV", "INDUSTRIA DEL TRANSPORTE, EXCEPTO EL SECTOR DE LA INDUSTRIA AUTOMOTRIZ Y DE AUTOPARTES", False),
("XVa", "INDUSTRIA DEL TRANSPORTE, EXCEPTO EL SECTOR DE LA INDUSTRIA AUTOMOTRIZ Y DE AUTOPARTES.", False),
("XVb", "INDUSTRIA DEL TRANSPORTE, EXCEPTO EL SECTOR DE LA INDUSTRIA AUTOMOTRIZ Y DE AUTOPARTES.", False),
("XVI", "INDUSTRIA DEL PAPEL Y CARTON", False),
("XVII", "INDUSTRIA DE LA MADERA", False),
("XVIII", "INDUSTRIA DEL CUERO Y PIELES", False),
("XX", "INDUSTRIA TEXTIL Y DE LA CONFECCION", False),
("XXa", "INDUSTRIA TEXTIL Y DE LA CONFECCION", False),
("XXb", "INDUSTRIA TEXTIL Y DE LA CONFECCION", False),
("XXc", "INDUSTRIA TEXTIL Y DE LA CONFECCION", False),
("XXd", "INDUSTRIA TEXTIL Y DE LA CONFECCION", False),
("XXe", "INDUSTRIA TEXTIL Y DE LA CONFECCION", False),
("XXI", "INDUSTRIA DE CHOCOLATES, DULCES Y SIMILARES", False),
("XXII", "INDUSTRIA DEL CAFE", False),
]

View File

@@ -0,0 +1,143 @@
"""
Service layer for Sectors (GSectores) — a76 tenant-scoped catalog.
"""
import logging
from typing import Any, Dict, List, Optional, Tuple
from fastapi import HTTPException
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from . import dto, models
logger = logging.getLogger(__name__)
class SectorService:
"""Service for Sector CRUD operations with tenant support"""
@staticmethod
def get_all(
db: Session,
tenant_id: int,
company_id: int,
skip: int = 0,
limit: int = 50,
filters: Optional[Dict[str, Any]] = None,
) -> Tuple[List[models.Sector], int]:
"""Get all sectors for a tenant/company with pagination"""
query = db.query(models.Sector).filter(
models.Sector.tenant_id == tenant_id,
models.Sector.company_id == company_id,
)
if filters:
if filters.get("key"):
query = query.filter(
models.Sector.key.ilike(f"%{filters['key']}%")
)
if filters.get("description"):
query = query.filter(
models.Sector.description.ilike(f"%{filters['description']}%")
)
total = query.count()
sectors = query.order_by(models.Sector.key).offset(skip).limit(limit).all()
return sectors, total
@staticmethod
def get_by_id(
db: Session, sector_id: int, tenant_id: int, company_id: int
) -> Optional[models.Sector]:
"""Get sector by ID"""
return (
db.query(models.Sector)
.filter(
models.Sector.id == sector_id,
models.Sector.tenant_id == tenant_id,
models.Sector.company_id == company_id,
)
.first()
)
@staticmethod
def create(
db: Session,
sector_data: dto.SectorCreateDTO,
tenant_id: int,
company_id: int,
) -> models.Sector:
"""Create a new sector"""
new_sector = models.Sector(
**sector_data.model_dump(), tenant_id=tenant_id, company_id=company_id
)
db.add(new_sector)
try:
db.commit()
db.refresh(new_sector)
return new_sector
except IntegrityError as e:
db.rollback()
logger.error(f"IntegrityError creating sector: {str(e)}")
raise HTTPException(
status_code=400,
detail="Ya existe un sector con esa clave para esta empresa.",
)
@staticmethod
def update(
db: Session,
sector_id: int,
tenant_id: int,
sector_data: dto.SectorUpdateDTO,
company_id: int,
) -> Optional[models.Sector]:
"""Update a sector"""
sector = SectorService.get_by_id(db, sector_id, tenant_id, company_id)
if not sector:
return None
update_data = sector_data.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(sector, field, value)
try:
db.commit()
db.refresh(sector)
return sector
except IntegrityError as e:
db.rollback()
logger.error(f"IntegrityError updating sector {sector_id}: {str(e)}")
raise HTTPException(
status_code=400,
detail="Ya existe un sector con esa clave para esta empresa.",
)
@staticmethod
def delete(
db: Session, sector_id: int, tenant_id: int, company_id: int
) -> bool:
"""Delete a sector"""
sector = SectorService.get_by_id(db, sector_id, tenant_id, company_id)
if not sector:
return False
try:
db.delete(sector)
db.commit()
return True
except IntegrityError as e:
db.rollback()
logger.error(f"IntegrityError deleting sector {sector_id}: {str(e)}")
if "foreign key constraint" in str(e).lower():
raise HTTPException(
status_code=400,
detail="No se puede eliminar el sector porque tiene registros relacionados.",
)
raise HTTPException(status_code=400, detail="Error al eliminar el sector.")
except Exception as e:
db.rollback()
logger.error(f"Error deleting sector {sector_id}: {str(e)}")
raise HTTPException(status_code=500, detail="Error al eliminar el sector.")

View File

@@ -16,7 +16,7 @@ from api.v1.modules.a76.general_catalogs.units_of_measure.models import UnitOfMe
from api.v1.modules.a76.general_catalogs.packages.models import Package
from api.v1.modules.a24.fa.fa_item_lines.models import FaLineItem
from api.v1.modules.public.reference_data.countries.models import Country
from api.v1.modules.public.reference_data.sectors.models import Sector
from api.v1.modules.a76.general_catalogs.sectors.models import Sector
from api.v1.modules.public.reference_data.valuation_methods.models import (
ValuationMethod,
)
@@ -314,7 +314,11 @@ def validate_common(
)
elif fraction_type.strip().upper() == FractionType.PROSEC and sector:
sector_db: Sector = (
db.query(Sector).filter(Sector.key == sector).scalar()
db.query(Sector).filter(
Sector.key == sector,
Sector.tenant_id == tenant_id,
Sector.company_id == company_id,
).scalar()
)
if sector_db:
errors.add_error(

View File

@@ -15,7 +15,7 @@ from api.v1.modules.a76.classes.models import Class
from api.v1.modules.a76.general_catalogs.units_of_measure.models import UnitOfMeasure
from api.v1.modules.a76.general_catalogs.packages.models import Package
from api.v1.modules.public.reference_data.countries.models import Country
from api.v1.modules.public.reference_data.sectors.models import Sector
from api.v1.modules.a76.general_catalogs.sectors.models import Sector
from api.v1.modules.public.reference_data.valuation_methods.models import (
ValuationMethod,
)
@@ -239,7 +239,11 @@ def validate_common(
)
elif fraction_type.strip().upper() == FractionType.PROSEC and sector:
sector_db: Sector = (
db.query(Sector).filter(Sector.key == sector).scalar()
db.query(Sector).filter(
Sector.key == sector,
Sector.tenant_id == tenant_id,
Sector.company_id == company_id,
).scalar()
)
if sector_db:
errors.add_error(

View File

@@ -895,7 +895,7 @@ def _do_scan_file(job_id: str, model_target: str, config: Optional[str] = None,
from api.v1.modules.a76.general_catalogs.units_of_measure.models import UnitOfMeasure
from api.v1.modules.a76.general_catalogs.packages.models import Package
from api.v1.modules.public.reference_data.countries.models import Country
from api.v1.modules.public.reference_data.sectors.models import Sector
from api.v1.modules.a76.general_catalogs.sectors.models import Sector
from api.v1.modules.public.reference_data.valuation_methods.models import ValuationMethod
from api.v1.modules.public.reference_data.payment_methods.models import PaymentMethod
from api.v1.modules.a76.general_catalogs.fractions.us_tariff_fractions.models import USTariffFraction
@@ -1018,7 +1018,11 @@ def _do_scan_file(job_id: str, model_target: str, config: Optional[str] = None,
valid_fraction_ame.add((row[0] or "").strip())
authorized_sectors: Set[str] = set()
for row in session.query(Sector.key).filter(Sector.authorized == True).all():
for row in session.query(Sector.key).filter(
Sector.authorized == True,
Sector.tenant_id == tenant_id,
Sector.company_id == company_id,
).all():
if row[0]:
authorized_sectors.add((row[0] or "").strip().upper())
@@ -1151,7 +1155,7 @@ def _do_scan_file(job_id: str, model_target: str, config: Optional[str] = None,
from api.v1.modules.a76.general_catalogs.units_of_measure.models import UnitOfMeasure
from api.v1.modules.a76.general_catalogs.packages.models import Package
from api.v1.modules.public.reference_data.countries.models import Country
from api.v1.modules.public.reference_data.sectors.models import Sector
from api.v1.modules.a76.general_catalogs.sectors.models import Sector
from api.v1.modules.public.reference_data.valuation_methods.models import ValuationMethod
from api.v1.modules.public.reference_data.payment_methods.models import PaymentMethod
from api.v1.modules.a76.general_catalogs.fractions.us_tariff_fractions.models import USTariffFraction
@@ -1277,7 +1281,11 @@ def _do_scan_file(job_id: str, model_target: str, config: Optional[str] = None,
valid_fraction_ame.add((row[0] or "").strip())
authorized_sectors: Set[str] = set()
for row in session.query(Sector.key).filter(Sector.authorized == True).all():
for row in session.query(Sector.key).filter(
Sector.authorized == True,
Sector.tenant_id == tenant_id,
Sector.company_id == company_id,
).all():
if row[0]:
authorized_sectors.add((row[0] or "").strip().upper())
@@ -1679,7 +1687,7 @@ def _do_scan_file(job_id: str, model_target: str, config: Optional[str] = None,
from api.v1.modules.a76.general_catalogs.units_of_measure.models import UnitOfMeasure
from api.v1.modules.a76.general_catalogs.packages.models import Package
from api.v1.modules.public.reference_data.countries.models import Country
from api.v1.modules.public.reference_data.sectors.models import Sector
from api.v1.modules.a76.general_catalogs.sectors.models import Sector
from api.v1.modules.public.reference_data.valuation_methods.models import ValuationMethod
from api.v1.modules.public.reference_data.payment_methods.models import PaymentMethod
from api.v1.modules.a76.general_catalogs.fractions.us_tariff_fractions.models import USTariffFraction
@@ -1804,7 +1812,11 @@ def _do_scan_file(job_id: str, model_target: str, config: Optional[str] = None,
valid_fraction_ame.add((row[0] or "").strip())
authorized_sectors: Set[str] = set()
for row in session.query(Sector.key).filter(Sector.authorized == True).all():
for row in session.query(Sector.key).filter(
Sector.authorized == True,
Sector.tenant_id == tenant_id,
Sector.company_id == company_id,
).all():
if row[0]:
authorized_sectors.add((row[0] or "").strip().upper())

View File

@@ -54,7 +54,7 @@ def load_parts_fk_sets(
from api.v1.modules.public.reference_data.currency_types.models import CurrencyType
from api.v1.modules.a76.general_catalogs.company.models import Company
from api.v1.modules.public.reference_data.countries.models import Country
from api.v1.modules.public.reference_data.sectors.models import Sector
from api.v1.modules.a76.general_catalogs.sectors.models import Sector
from api.v1.modules.a76.general_catalogs.fractions.tariff_fractions.models import TariffFraction
from api.v1.modules.a76.general_catalogs.fractions.historical_tariff_fractions.models import (
HistoricalTariffFraction,
@@ -102,7 +102,11 @@ def load_parts_fk_sets(
for row in (
session.query(Sector.key)
.filter(Sector.authorized == True)
.filter(
Sector.authorized == True,
Sector.tenant_id == tenant_id,
Sector.company_id == company_id,
)
.all()
):
if row[0]:

View File

@@ -320,12 +320,11 @@ def validate_row_sector(
# Formato: solo A-Z/0-9 (sin espacios ni especiales), hasta 8
if sector:
s = sector.strip().upper()
# Alinear con modelo A76: solo dígitos, máx 8
if not (1 <= len(s) <= 8) or not s.isdigit():
if not (1 <= len(s) <= 8) or not s.isalnum():
return {
"line": line_num,
"col": "SECTOR",
"msg": "Error: (Col. P) El Sector contiene caracteres no permitidos. Use solo números (máx. 8 dígitos).",
"msg": "Error: (Col. P) El Sector contiene caracteres no permitidos. Use solo letras y números sin espacios (máx. 8 caracteres).",
}
if pref == "PROSEC":
if not sector:

View File

@@ -6,7 +6,7 @@ from pydantic import BaseModel, Field, ConfigDict
# --- SUB-DTO: DATOS ADUANALES (FaData) ---
class FaDataDTO(BaseModel):
origin_country: Optional[str] = Field(default=None, pattern=r"^[A-Z]{3}$")
sector: Optional[str] = Field(default=None, pattern=r"^[0-9]{1,8}$")
sector: Optional[str] = Field(default=None, pattern=r"^[A-Za-z0-9]{1,8}$")
fraction_type: Optional[Literal["GENERAL", "PROSEC", "ALADI", "TLCS"]] = None
model_config = ConfigDict(from_attributes=True)

View File

@@ -17,7 +17,6 @@ from .material_types.routes import router as material_types_router
from .payment_methods.routes import router as payment_methods_router
from .pedimento_codes.routes import router as pedimento_codes_router
from .pedimento_regimens.routes import router as pedimento_regimens_router
from .sectors.routes import router as sectors_router
from .states.routes import router as states_router
from .trailer_types.routes import router as trailer_types_router
from .transport_modes.routes import router as transport_modes_router
@@ -81,11 +80,6 @@ router.include_router(
prefix="/reference_data",
tags=["public / reference_data / valuation_methods"],
)
router.include_router(
sectors_router,
prefix="/reference_data",
tags=["public / public / reference_data / sectors"],
)
router.include_router(
transport_modes_router,
prefix="/reference_data",

View File

@@ -1,9 +0,0 @@
from pydantic import BaseModel, ConfigDict, Field
class SectorDTO(BaseModel):
key: str = Field(..., min_length=1, max_length=8)
description: str
authorized: bool
model_config = ConfigDict(from_attributes=True)

View File

@@ -1,23 +0,0 @@
from core.database import Base
from sqlalchemy import Boolean, PrimaryKeyConstraint, SmallInteger, String
from sqlalchemy.orm import Mapped, mapped_column
class Sector(Base):
__tablename__ = "sectors" # GSectores
__table_args__ = (
PrimaryKeyConstraint("key", name="sectors_pkey"),
{"schema": "public", "extend_existing": True}, # opcional
)
key: Mapped[str] = mapped_column(
String(8), nullable=False) # clave del sector
description: Mapped[str] = mapped_column(
String(150), nullable=False
) # descripción oficial (en español)
authorized: Mapped[bool] = mapped_column(
Boolean
) # True = autorizado, False = no autorizado
def __repr__(self):
return f"<Sector(key={self.key}, description={self.description}, authorized={self.authorized})>"

View File

@@ -1,56 +0,0 @@
from typing import Any, Dict, Optional
from core.database import get_core_db
from core.security import get_current_user
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import or_
from sqlalchemy.orm import Session
from .dto import SectorDTO
from .models import Sector
router = APIRouter(prefix="/sectors")
@router.get("/", response_model=Dict[str, Any])
def list_sectors(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"),
search: Optional[str] = Query(None, description="Término de búsqueda"),
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user),
):
skip = (page - 1) * page_size
query = db.query(Sector)
if search:
search_filter = or_(
Sector.key.ilike(f"%{search}%"),
Sector.description.ilike(f"%{search}%")
)
query = query.filter(search_filter)
total = query.count()
# Add deterministic sort order
query = query.order_by(Sector.key)
items = query.offset(skip).limit(page_size).all()
return {
"items": [SectorDTO.model_validate(obj) for obj in items],
"total": total,
"page": page,
"page_size": page_size,
}
@router.get("/{key}", response_model=SectorDTO)
def get_sector(
key: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user),
):
obj = db.query(Sector).filter(Sector.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
return obj

View File

@@ -1,55 +0,0 @@
seed = [
("I", "INDUSTRIA ELECTRICA", "0"),
("II", "INDUSTRIA ELECTRONICA", "0"),
(
"IIa",
"PARA LOS BIENES A QUE SE REFIERE LA FRACCION II, INCISO a) o b), DE ARTICULO 4to DE ESTE DECRETO.",
"0",
),
(
"IIb",
"PARA LOS BIENES A QUE SE REFIERE LA FRACCION II, INCISO b), DE ARTICULO 4to DE ESTE DECRETO.",
"0",
),
("III", "INDUSTRIA DEL MUEBLE", "0"),
("IV", "INDUSTRIA DEL JUGUETE, JUEGOS DE RECREO Y ARTICULOS DEPORTIVOS", "0"),
("IX", "INDUSTRIA DE MAQUINARIA AGRICOLA", "0"),
("V", "INDUSTRIA DEL CALZADO", "0"),
("VI", "INDUSTRIA MINERA Y METALURGICA", "0"),
("VII", "INDUSTRIA DE BIENES DE CAPITAL", "0"),
("VIII", "INDUSTRIA FOTOGRAFICA", "0"),
("X", "INDUSTRIAS DIVERSAS", "0"),
("XI", "INDUSTRIA QUIMICA", "0"),
("XII", "INDUSTRIAS DE MANUFACTURAS DEL CAUCHO Y PLASTICOS", "0"),
("XIII", "INDUSTRIA SIDERURGICA", "0"),
("XIV", "INDUSTRIA DE PRODUCTOS FARMOQUIMICOS, MEDICAMENTOS Y EQUIPO MEDICO", "0"),
("XIX", "INDUSTRIA AUTOMOTRIZ Y DE AUTOPARTES", "0"),
("XIXa", "INDUSTRIA AUTOMOTRIZ Y DE AUTOPARTES", "0"),
("XIXb", "INDUSTRIA AUTOMOTRIZ Y DE AUTOPARTES", "0"),
(
"XV",
"INDUSTRIA DEL TRANSPORTE, EXCEPTO EL SECTOR DE LA INDUSTRIA AUTOMOTRIZ Y DE AUTOPARTES",
"0",
),
(
"XVa",
"INDUSTRIA DEL TRANSPORTE, EXCEPTO EL SECTOR DE LA INDUSTRIA AUTOMOTRIZ Y DE AUTOPARTES.",
"0",
),
(
"XVb",
"INDUSTRIA DEL TRANSPORTE, EXCEPTO EL SECTOR DE LA INDUSTRIA AUTOMOTRIZ Y DE AUTOPARTES.",
"0",
),
("XVI", "INDUSTRIA DEL PAPEL Y CARTON", "0"),
("XVII", "INDUSTRIA DE LA MADERA", "0"),
("XVIII", "INDUSTRIA DEL CUERO Y PIELES", "0"),
("XX", "INDUSTRIA TEXTIL Y DE LA CONFECCION", "0"),
("XXa", "INDUSTRIA TEXTIL Y DE LA CONFECCION", "0"),
("XXb", "INDUSTRIA TEXTIL Y DE LA CONFECCION", "0"),
("XXc", "INDUSTRIA TEXTIL Y DE LA CONFECCION", "0"),
("XXd", "INDUSTRIA TEXTIL Y DE LA CONFECCION", "0"),
("XXe", "INDUSTRIA TEXTIL Y DE LA CONFECCION", "0"),
("XXI", "INDUSTRIA DE CHOCOLATES, DULCES Y SIMILARES", "0"),
("XXII", "INDUSTRIA DEL CAFE", "0"),
]

View File

@@ -1,40 +0,0 @@
import pytest
from api.v1.modules.public.reference_data.sectors.routes import router
from fastapi import FastAPI
from fastapi.testclient import TestClient
app = FastAPI()
app.include_router(router)
client = TestClient(app)
@pytest.mark.usefixtures("client", "access_token")
def test_list_sectors(client, access_token):
headers = {"Authorization": f"Bearer {access_token}"}
response = client.get("/sectors/", headers=headers)
assert response.status_code == 200
assert "items" in response.json()
assert "page" in response.json()
assert "page_size" in response.json()
@pytest.mark.usefixtures("client", "access_token")
def test_get_sector_not_found(client, access_token):
headers = {"Authorization": f"Bearer {access_token}"}
response = client.get("/sectors/invalid_key", headers=headers)
assert response.status_code == 404
def test_create_sector_forbidden():
response = client.post("/sectors/", json={"key": "TST", "description": "Test"})
assert response.status_code in (403, 405, 404)
def test_update_sector_forbidden():
response = client.put("/sectors/TST", json={"key": "TST", "description": "Test"})
assert response.status_code in (403, 405, 404)
def test_delete_sector_forbidden():
response = client.delete("/sectors/TST")
assert response.status_code in (403, 405, 404)

View File

@@ -24,7 +24,7 @@ from api.v1.modules.public.reference_data.pedimento_regimens.models import Regim
from api.v1.modules.public.reference_data.code_pedimento_regimens.models import (
CodePedimentoRegimen,
)
from api.v1.modules.public.reference_data.sectors.models import Sector
from api.v1.modules.a76.general_catalogs.sectors.models import Sector
from api.v1.modules.public.reference_data.states.models import State
from api.v1.modules.public.reference_data.transport_modes.models import TransportMode
from api.v1.modules.public.reference_data.transport_types.models import TransportType
@@ -221,7 +221,6 @@ from api.v1.modules.public.reference_data.pedimento_codes.models import Pediment
from api.v1.modules.public.reference_data.pedimento_regimens.models import (
RegimenPedimento,
)
from api.v1.modules.public.reference_data.sectors.models import Sector
from api.v1.modules.public.reference_data.states.models import State
from api.v1.modules.public.reference_data.transport_modes.models import TransportMode
from api.v1.modules.public.reference_data.transport_types.models import TransportType