feat: Implement multi-tenancy support in middleware and security layers
- Enhanced TenantMiddleware to validate tenant information from JWT tokens. - Added LicenseValidationMiddleware to check tenant licenses before processing requests. - Updated security utilities to extract tenant information from tokens and validate company access. - Introduced CompanyStore to manage active company state and handle company switching in the frontend. - Modified API routes to include company_id in requests for better resource management. - Improved logging and error handling throughout the middleware and API layers. - Updated frontend components to reflect changes in company management and selection. - Added new API route for fetching user's companies with proper authentication handling.
This commit is contained in:
@@ -2,6 +2,7 @@ from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class CodePedimentoRegimenDTO(BaseModel):
|
||||
id: Optional[int] = None
|
||||
pedimento_code: str = Field(..., min_length=1, max_length=3)
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from sqlalchemy import String, Integer, ForeignKey, ForeignKeyConstraint, PrimaryKeyConstraint
|
||||
from sqlalchemy import (
|
||||
String,
|
||||
Integer,
|
||||
ForeignKey,
|
||||
ForeignKeyConstraint,
|
||||
PrimaryKeyConstraint,
|
||||
)
|
||||
from sqlalchemy.orm import mapped_column, Mapped, relationship
|
||||
from core.database import Base
|
||||
|
||||
@@ -7,29 +13,36 @@ if TYPE_CHECKING:
|
||||
from ..pedimento_codes.models import PedimentoCode
|
||||
from ..pedimento_regimens.models import RegimenPedimento
|
||||
|
||||
|
||||
class CodePedimentoRegimen(Base):
|
||||
__tablename__ = "code_pedimento_regimens" #GClavePedRegimen
|
||||
__tablename__ = "code_pedimento_regimens" # GClavePedRegimen
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(['pedimento_code'], ['public.pedimento_codes.code'], name='fk_codeped'),
|
||||
ForeignKeyConstraint(['regimen_code'], ['public.pedimento_regimens.code'], name='fk_regimenped'),
|
||||
PrimaryKeyConstraint('id', name='clave_pedimento_regimens_pkey'),
|
||||
{"schema": "public"}
|
||||
ForeignKeyConstraint(
|
||||
["pedimento_code"], ["public.pedimento_codes.code"], name="fk_codeped"
|
||||
),
|
||||
ForeignKeyConstraint(
|
||||
["regimen_code"], ["public.pedimento_regimens.code"], name="fk_regimenped"
|
||||
),
|
||||
PrimaryKeyConstraint("id", name="clave_pedimento_regimens_pkey"),
|
||||
{"schema": "public"},
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer)
|
||||
pedimento_code: Mapped[str] = mapped_column(String(3), nullable=False)
|
||||
regimen_code: Mapped[Optional[str]] = mapped_column(String(3), nullable=False)
|
||||
type_code: Mapped[Optional[str]] = mapped_column(String(1)) # si aplica un tipo de relación
|
||||
type_code: Mapped[Optional[str]] = mapped_column(
|
||||
String(1)
|
||||
) # si aplica un tipo de relación
|
||||
|
||||
# Relaciones ORM
|
||||
#GClavePed
|
||||
pedimento: Mapped['PedimentoCode'] = relationship(
|
||||
'PedimentoCode', back_populates='regimens'
|
||||
# GClavePed
|
||||
pedimento: Mapped["PedimentoCode"] = relationship(
|
||||
"PedimentoCode", back_populates="regimens"
|
||||
)
|
||||
#GRegimenPed
|
||||
regimen: Mapped[Optional['RegimenPedimento']] = relationship(
|
||||
'RegimenPedimento', back_populates='claves_pedimento'
|
||||
# GRegimenPed
|
||||
regimen: Mapped[Optional["RegimenPedimento"]] = relationship(
|
||||
"RegimenPedimento", back_populates="claves_pedimento"
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<ClavePedimentoRegimen(pedimento={self.pedimento_code}, regimen={self.regimen_code}, type={self.type_code})>"
|
||||
return f"<ClavePedimentoRegimen(pedimento={self.pedimento_code}, regimen={self.regimen_code}, type={self.type_code})>"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -16,7 +15,7 @@ def list_code_pedimento_regimens(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(CodePedimentoRegimen)
|
||||
@@ -26,25 +25,27 @@ def list_code_pedimento_regimens(
|
||||
"items": [CodePedimentoRegimenDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{id}", response_model=CodePedimentoRegimenDTO)
|
||||
def get_code_pedimento_regimen(
|
||||
id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(CodePedimentoRegimen).filter(CodePedimentoRegimen.id == id).first()
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return CodePedimentoRegimenDTO.model_validate(obj)
|
||||
|
||||
|
||||
@router.post("/", response_model=CodePedimentoRegimenDTO, status_code=201)
|
||||
def create_code_pedimento_regimen(
|
||||
data: CodePedimentoRegimenDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = CodePedimentoRegimen(**data.model_dump())
|
||||
db.add(obj)
|
||||
@@ -52,12 +53,13 @@ def create_code_pedimento_regimen(
|
||||
db.refresh(obj)
|
||||
return CodePedimentoRegimenDTO.model_validate(obj)
|
||||
|
||||
|
||||
@router.put("/{id}", response_model=CodePedimentoRegimenDTO)
|
||||
def update_code_pedimento_regimen(
|
||||
id: int,
|
||||
data: CodePedimentoRegimenDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(CodePedimentoRegimen).filter(CodePedimentoRegimen.id == id).first()
|
||||
if not obj:
|
||||
@@ -68,11 +70,12 @@ def update_code_pedimento_regimen(
|
||||
db.refresh(obj)
|
||||
return CodePedimentoRegimenDTO.model_validate(obj)
|
||||
|
||||
|
||||
@router.delete("/{id}", status_code=204)
|
||||
def delete_code_pedimento_regimen(
|
||||
id: int,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(CodePedimentoRegimen).filter(CodePedimentoRegimen.id == id).first()
|
||||
if not obj:
|
||||
|
||||
@@ -33,8 +33,8 @@ seed = [
|
||||
("H1", "EXD", "E"),
|
||||
("H8", "EXD", "E"),
|
||||
("I1", "EXD", "E"),
|
||||
#("J1", "EXD", "E"),
|
||||
#("J2", "EXD", "E"),
|
||||
# ("J1", "EXD", "E"),
|
||||
# ("J2", "EXD", "E"),
|
||||
("K1", "EXD", "E"),
|
||||
("K2", "EXD", "E"),
|
||||
("K3", "EXD", "E"),
|
||||
@@ -53,7 +53,7 @@ seed = [
|
||||
("A1", "IMD", "I"),
|
||||
("A3", "IMD", "I"),
|
||||
("C1", "IMD", "I"),
|
||||
#("C2", "IMD", "I"),
|
||||
# ("C2", "IMD", "I"),
|
||||
("C3", "IMD", "I"),
|
||||
("D1", "IMD", "I"),
|
||||
("F3", "IMD", "I"),
|
||||
@@ -78,19 +78,19 @@ seed = [
|
||||
("V9", "IMD", "I"),
|
||||
("VF", "IMD", "I"),
|
||||
("VU", "IMD", "I"),
|
||||
#("A2", "ITE", "I"),
|
||||
#("A8", "ITE", "I"),
|
||||
#("AA", "ITE", "I"),
|
||||
# ("A2", "ITE", "I"),
|
||||
# ("A8", "ITE", "I"),
|
||||
# ("AA", "ITE", "I"),
|
||||
("AF", "ITE", "I"),
|
||||
("E1", "ITE", "I"),
|
||||
("E3", "ITE", "I"),
|
||||
#("H3", "ITE", "I"),
|
||||
# ("H3", "ITE", "I"),
|
||||
("IN", "ITE", "I"),
|
||||
("R1", "ITE", "I"),
|
||||
("V1", "ITE", "I"),
|
||||
("A6", "ITR", "I"),
|
||||
#("A7", "ITR", "I"),
|
||||
#("A9", "ITR", "I"),
|
||||
# ("A7", "ITR", "I"),
|
||||
# ("A9", "ITR", "I"),
|
||||
("AD", "ITR", "I"),
|
||||
("AF", "ITR", "I"),
|
||||
("AJ", "ITR", "I"),
|
||||
@@ -104,7 +104,7 @@ seed = [
|
||||
("BP", "ITR", "I"),
|
||||
("E2", "ITR", "I"),
|
||||
("E4", "ITR", "I"),
|
||||
#("H3", "ITR", "I"),
|
||||
# ("H3", "ITR", "I"),
|
||||
("R1", "ITR", "I"),
|
||||
("V1", "ITR", "I"),
|
||||
("V4", "ITR", "I"),
|
||||
@@ -120,5 +120,5 @@ seed = [
|
||||
("T3", "TRA", "I"),
|
||||
("T6", "TRA", "E"),
|
||||
("T7", "TRA", "I"),
|
||||
("T9", "TRA", "I")
|
||||
]
|
||||
("T9", "TRA", "I"),
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_code_pedimento_regimens(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,28 @@ def test_list_code_pedimento_regimens(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_code_pedimento_regimen_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/code-pedimento-regimens/999999", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_code_pedimento_regimen_forbidden():
|
||||
response = client.post("/code-pedimento-regimens/", json={"id": 999999, "description": "Test"})
|
||||
response = client.post(
|
||||
"/code-pedimento-regimens/", json={"id": 999999, "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_code_pedimento_regimen_forbidden():
|
||||
response = client.put("/code-pedimento-regimens/999999", json={"id": 999999, "description": "Test"})
|
||||
response = client.put(
|
||||
"/code-pedimento-regimens/999999", json={"id": 999999, "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_code_pedimento_regimen_forbidden():
|
||||
response = client.delete("/code-pedimento-regimens/999999")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -3,11 +3,13 @@ from fastapi.testclient import TestClient
|
||||
from api.v1.modules.public.reference_data.transport_types.routes import router
|
||||
from fastapi import FastAPI
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def access_token():
|
||||
# Reemplaza este token por uno válido generado por Keycloak
|
||||
return "aqui-va-tu-token-valido"
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def client():
|
||||
app = FastAPI()
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
|
||||
|
||||
class ContainerDTO(BaseModel):
|
||||
key: str = Field(..., min_length=1, max_length=3)
|
||||
description: str
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -2,15 +2,20 @@ from sqlalchemy import String, PrimaryKeyConstraint
|
||||
from sqlalchemy.orm import mapped_column, Mapped
|
||||
from core.database import Base
|
||||
|
||||
|
||||
class Container(Base):
|
||||
__tablename__ = "containers" #GContenedores
|
||||
__tablename__ = "containers" # GContenedores
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("key", name="containers_pkey"),
|
||||
{"schema": "public"} # opcional
|
||||
{"schema": "public"}, # opcional
|
||||
)
|
||||
|
||||
key: Mapped[str] = mapped_column(String(3), nullable=False) # mantiene ceros iniciales
|
||||
description: Mapped[str] = mapped_column(String(500), nullable=False) # descripción legal en español
|
||||
key: Mapped[str] = mapped_column(
|
||||
String(3), nullable=False
|
||||
) # mantiene ceros iniciales
|
||||
description: Mapped[str] = mapped_column(
|
||||
String(500), nullable=False
|
||||
) # descripción legal en español
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Container(key={self.key}, description={self.description})>"
|
||||
return f"<Container(key={self.key}, description={self.description})>"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -11,13 +10,12 @@ from typing import Any, Dict
|
||||
router = APIRouter(prefix="/containers")
|
||||
|
||||
|
||||
|
||||
@router.get("/", response_model=Dict[str, Any])
|
||||
async def list_containers(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(Container)
|
||||
@@ -27,23 +25,27 @@ async def list_containers(
|
||||
"items": [ContainerDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@router.get("/{key}", response_model=ContainerDTO)
|
||||
async def get_container(key: str, db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user)):
|
||||
async def get_container(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(Container).filter(Container.key == key).first()
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.post("/", response_model=ContainerDTO, status_code=201)
|
||||
async def create_container(
|
||||
data: ContainerDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = Container(**data.dict())
|
||||
db.add(obj)
|
||||
@@ -51,13 +53,13 @@ async def create_container(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.put("/{key}", response_model=ContainerDTO)
|
||||
async def update_container(
|
||||
key: str,
|
||||
data: ContainerDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(Container).filter(Container.key == key).first()
|
||||
if not obj:
|
||||
@@ -68,12 +70,12 @@ async def update_container(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.delete("/{key}", status_code=204)
|
||||
async def delete_container(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(Container).filter(Container.key == key).first()
|
||||
if not obj:
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
seed = [
|
||||
("1", "CONTENEDOR ESTANDAR 20' (STANDARD CONTAINER 20')."),
|
||||
("2", "CONTENEDOR ESTANDAR 40' (STANDARD CONTAINER 40')."),
|
||||
("3", "CONTENEDOR ESTANDAR DE CUBO ALTO 40' (HIGH CUBE STANDARD CONTAINER 40')."),
|
||||
("4", "CONTENEDOR TAPA DURA 20’ (HARDTOP CONTAINER 20')."),
|
||||
("5", "CONTENEDOR TAPA DURA 40’ (HARDTOP CONTAINER 40')."),
|
||||
("6", "CONTENEDOR TAPA ABIERTA 20’ (OPEN TOP CONTAINER 20')."),
|
||||
("7", "CONTENEDOR TAPA ABIERTA 40' (OPEN TOP CONTAINER 40')."),
|
||||
("8", "FLAT 20' (FLAT 20')."),
|
||||
("9", "FLAT 40' (FLAT 40')."),
|
||||
("1", "CONTENEDOR ESTANDAR 20' (STANDARD CONTAINER 20')."),
|
||||
("2", "CONTENEDOR ESTANDAR 40' (STANDARD CONTAINER 40')."),
|
||||
("3", "CONTENEDOR ESTANDAR DE CUBO ALTO 40' (HIGH CUBE STANDARD CONTAINER 40')."),
|
||||
("4", "CONTENEDOR TAPA DURA 20’ (HARDTOP CONTAINER 20')."),
|
||||
("5", "CONTENEDOR TAPA DURA 40’ (HARDTOP CONTAINER 40')."),
|
||||
("6", "CONTENEDOR TAPA ABIERTA 20’ (OPEN TOP CONTAINER 20')."),
|
||||
("7", "CONTENEDOR TAPA ABIERTA 40' (OPEN TOP CONTAINER 40')."),
|
||||
("8", "FLAT 20' (FLAT 20')."),
|
||||
("9", "FLAT 40' (FLAT 40')."),
|
||||
("10", "PLATAFORMA 20' (PLATFORM 20')."),
|
||||
("11", "PLATAFORMA 40' (PLATFORM 40')."),
|
||||
("12", "CONTENEDOR VENTILADO 20’ (VENTILATED CONTAINER 20')."),
|
||||
@@ -15,9 +15,12 @@ seed = [
|
||||
("14", "CONTENEDOR TERMICO 40' (INSULATED CONTAINER 40')."),
|
||||
("15", "CONTENEDOR REFRIGERANTE 20’ (REFRIGERATED CONTAINER 20')."),
|
||||
("16", "CONTENEDOR REFRIGERANTE 40’ (REFRIGERATED CONTAINER 40')."),
|
||||
("17", "CONTENEDOR REFRIGERANTE CUBO ALTO 40’ (HIGH CUBE REFRIGERATED CONTAINER 40')."),
|
||||
(
|
||||
"17",
|
||||
"CONTENEDOR REFRIGERANTE CUBO ALTO 40’ (HIGH CUBE REFRIGERATED CONTAINER 40').",
|
||||
),
|
||||
("18", "CONTENEDOR CARGA A GRANEL 20’ (BULK CONTAINER 20')."),
|
||||
("19", "CONTENEDOR TIPO TANQUE 20’ (TANK CONTAINER 20')."),
|
||||
("19", "CONTENEDOR TIPO TANQUE 20’ (TANK CONTAINER 20')."),
|
||||
("20", "CONTENEDOR ESTANDAR 45' (STANDARD CONTAINER 45')."),
|
||||
("21", "CONTENEDOR ESTANDAR 48' (STANDARD CONTAINER 48')."),
|
||||
("22", "CONTENEDOR ESTANDAR 53' (STANDARD CONTAINER 53')."),
|
||||
@@ -27,7 +30,7 @@ seed = [
|
||||
("26", "SEMIRREMOLQUE CON RACKS PARA ENVASES DE BEBIDAS."),
|
||||
("27", "SEMIRREMOLQUE CUELLO DE GANZO."),
|
||||
("28", "SEMIRREMOLQUE TOLVA CUBIERTO."),
|
||||
("29", "SEMIRREMOLQUE TOLVA (ABIERTO)."),
|
||||
("29", "SEMIRREMOLQUE TOLVA (ABIERTO)."),
|
||||
("30", "AUTO-TOLVA CUBIERTO/DESCARGA NEUMATICA."),
|
||||
("31", "SEMIRREMOLQUE CHASIS."),
|
||||
("32", "SEMIRREMOLQUE AUTOCARGABLE (CON SISTEMA DE ELEVACION)."),
|
||||
@@ -37,7 +40,7 @@ seed = [
|
||||
("36", "PLATAFORMA DE 28’."),
|
||||
("37", "PLATAFORMA DE 45’."),
|
||||
("38", "PLATAFORMA DE 48’."),
|
||||
("39", "SEMIRREMOLQUE PARA TRANSPORTE DE CABALLOS."),
|
||||
("39", "SEMIRREMOLQUE PARA TRANSPORTE DE CABALLOS."),
|
||||
("40", "SEMIRREMOLQUE PARA TRANSPORTE DE GANADO."),
|
||||
("41", "SEMIRREMOLQUE TANQUE (LIQUIDOS)/SIN CALEFACCION/SIN AISLAR."),
|
||||
("42", "SEMIRREOLQUE TANQUE (LIQUIDOS)/CON CALEFACCION/SIN AISLAR."),
|
||||
@@ -47,7 +50,7 @@ seed = [
|
||||
("46", "SEMIRREMOLQUE TANQUE (GAS)/CON CALEFACCION/SIN AISLAR."),
|
||||
("47", "SEMIRREMOLQUE TANQUE (GAS)/SIN CALEFACCION/AISLADO."),
|
||||
("48", "SEMIRREMOLQUE TANQUE (GAS)/CON CALEFACCION/AISLADO."),
|
||||
("49", "SEMIRREMOLQUE TANQUE (QUIMICOS)/SIN CALEFACCION/SIN AISLAR."),
|
||||
("49", "SEMIRREMOLQUE TANQUE (QUIMICOS)/SIN CALEFACCION/SIN AISLAR."),
|
||||
("50", "SEMIRREMOLQUE TANQUE (QUIMICOS)/CON CALEFACCION/SIN AISLAR."),
|
||||
("51", "SEMIRREMOLQUE TANQUE (QUIMICOS)/SIN CALEFACCION/AISLADO."),
|
||||
("52", "SEMIRREMOLQUE TANQUE (QUIMICOS)/CON CALEFACCION/AISLADO."),
|
||||
@@ -68,4 +71,4 @@ seed = [
|
||||
("67", "CAMIÓN UNITARIO DE TRES EJES"),
|
||||
("68", "VEHÍCULOS CON CAPACIDAD DE CARGA DE HASTA 3.5. TONELADAS"),
|
||||
("69", "TRACTOCAMIÓN"),
|
||||
]
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_containers(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,24 @@ def test_list_containers(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_container_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/containers/invalid_key", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_container_forbidden():
|
||||
response = client.post("/containers/", json={"key": "TST", "description": "Test"})
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_container_forbidden():
|
||||
response = client.put("/containers/TST", json={"key": "TST", "description": "Test"})
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_container_forbidden():
|
||||
response = client.delete("/containers/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
|
||||
|
||||
class CountryDTO(BaseModel):
|
||||
m3_key: str = Field(..., min_length=1, max_length=3)
|
||||
mex_key: str = Field(..., min_length=1, max_length=2)
|
||||
@@ -9,4 +10,3 @@ class CountryDTO(BaseModel):
|
||||
description_en: str
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -2,19 +2,26 @@ from sqlalchemy import String, PrimaryKeyConstraint, Index
|
||||
from sqlalchemy.orm import mapped_column, Mapped
|
||||
from core.database import Base
|
||||
|
||||
|
||||
class Country(Base):
|
||||
__tablename__ = "countries" #GPaises
|
||||
__tablename__ = "countries" # GPaises
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("m3_key", name="countries_pkey"),
|
||||
Index("ak_country_ame", "ame_key", unique=True),
|
||||
{"schema": "public"} # opcional
|
||||
{"schema": "public"}, # opcional
|
||||
)
|
||||
|
||||
m3_key: Mapped[str] = mapped_column(String(3), nullable=False) # clave M3
|
||||
mex_key: Mapped[str] = mapped_column(String(2), nullable=False) # clave país México
|
||||
ame_key: Mapped[str] = mapped_column(String(2), nullable=False) # clave país América / regional
|
||||
description_es: Mapped[str] = mapped_column(String(50), nullable=False) # nombre oficial en español
|
||||
description_en: Mapped[str] = mapped_column(String(50), nullable=False) # nombre en inglés para UI
|
||||
m3_key: Mapped[str] = mapped_column(String(3), nullable=False) # clave M3
|
||||
mex_key: Mapped[str] = mapped_column(String(2), nullable=False) # clave país México
|
||||
ame_key: Mapped[str] = mapped_column(
|
||||
String(2), nullable=False
|
||||
) # clave país América / regional
|
||||
description_es: Mapped[str] = mapped_column(
|
||||
String(50), nullable=False
|
||||
) # nombre oficial en español
|
||||
description_en: Mapped[str] = mapped_column(
|
||||
String(50), nullable=False
|
||||
) # nombre en inglés para UI
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Country(m3_key={self.m3_key}, mex_key={self.mex_key}, ame_key={self.ame_key}, description_es={self.description_es}, description_en={self.description_en})>"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -11,13 +10,12 @@ from typing import Any, Dict
|
||||
router = APIRouter(prefix="/countries")
|
||||
|
||||
|
||||
|
||||
@router.get("/", response_model=Dict[str, Any])
|
||||
async def list_countries(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(Country)
|
||||
@@ -27,23 +25,27 @@ async def list_countries(
|
||||
"items": [CountryDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@router.get("/{m3_key}", response_model=CountryDTO)
|
||||
async def get_country(m3_key: str, db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user)):
|
||||
async def get_country(
|
||||
m3_key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(Country).filter(Country.m3_key == m3_key).first()
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.post("/", response_model=CountryDTO, status_code=201)
|
||||
async def create_country(
|
||||
data: CountryDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = Country(**data.dict())
|
||||
db.add(obj)
|
||||
@@ -51,13 +53,13 @@ async def create_country(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.put("/{m3_key}", response_model=CountryDTO)
|
||||
async def update_country(
|
||||
m3_key: str,
|
||||
data: CountryDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(Country).filter(Country.m3_key == m3_key).first()
|
||||
if not obj:
|
||||
@@ -68,12 +70,12 @@ async def update_country(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.delete("/{m3_key}", status_code=204)
|
||||
async def delete_country(
|
||||
m3_key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(Country).filter(Country.m3_key == m3_key).first()
|
||||
if not obj:
|
||||
|
||||
@@ -1,15 +1,45 @@
|
||||
seed = [
|
||||
("ABW", "A0", "AW", "Aruba (Territorio Holandes de Ultramar)", "Aruba (Netherlands Territory)"),
|
||||
("AFG", "A1", "AF", "Afganistan (Emirato Islamico De)", "Afghanistan (Islamic Emirate of)"),
|
||||
(
|
||||
"ABW",
|
||||
"A0",
|
||||
"AW",
|
||||
"Aruba (Territorio Holandes de Ultramar)",
|
||||
"Aruba (Netherlands Territory)",
|
||||
),
|
||||
(
|
||||
"AFG",
|
||||
"A1",
|
||||
"AF",
|
||||
"Afganistan (Emirato Islamico De)",
|
||||
"Afghanistan (Islamic Emirate of)",
|
||||
),
|
||||
("AGO", "A8", "AO", "Angola ( Republica De )", "Angola (People's Republic of )"),
|
||||
("AIA", "AI", "AI", "Anguila", "Anguilla"),
|
||||
("ALB", "A2", "AL", "Albania ( Republica De)", "Albania (People's Socialist Republic)"),
|
||||
(
|
||||
"ALB",
|
||||
"A2",
|
||||
"AL",
|
||||
"Albania ( Republica De)",
|
||||
"Albania (People's Socialist Republic)",
|
||||
),
|
||||
("AND", "A7", "AD", "Andorra (Principado De)", "Andorra (Principated of)"),
|
||||
("ANT", "B1", "AN", "Antillas Neerlandesas (Terr. Holandes de Ultramar)", "Antilles Netherlands"),
|
||||
(
|
||||
"ANT",
|
||||
"B1",
|
||||
"AN",
|
||||
"Antillas Neerlandesas (Terr. Holandes de Ultramar)",
|
||||
"Antilles Netherlands",
|
||||
),
|
||||
("ARE", "G6", "AE", "Emiratos Arabes Unidos", "United Arab Emirates"),
|
||||
("ARG", "B4", "AR", "Argentina ( Republica )", "Argentina (Republic of)"),
|
||||
("ARM", "AM", "AM", "Armenia (Republica De)", "Armenia (Republic of)"),
|
||||
("ATG", "A9", "AG", "Antigua Y Barbuda (Com. Britanica de Naciones)", "Antigua & Barbuda (Brithish Community)"),
|
||||
(
|
||||
"ATG",
|
||||
"A9",
|
||||
"AG",
|
||||
"Antigua Y Barbuda (Com. Britanica de Naciones)",
|
||||
"Antigua & Barbuda (Brithish Community)",
|
||||
),
|
||||
("AUS", "B5", "AU", "Australia ( Comunidad De )", "Australia (Community of)"),
|
||||
("AUT", "B6", "AT", "Austria ( Republica De )", "Austria (Republic of)"),
|
||||
("AZE", "AZ", "AZ", "Azerbaijan (Republica Azerbaijani)", "Azerbaijan"),
|
||||
@@ -17,7 +47,13 @@ seed = [
|
||||
("BEL", "C2", "BE", "Belgica ( Reino De )", "Belgium (Kingdom of)"),
|
||||
("BEN", "F9", "BJ", "Benin ( Republica De)", "Benin (People's Republic of)"),
|
||||
("BFA", "A6", "BF", "Burkina Faso", "Burkina Faso"),
|
||||
("BGD", "B9", "BD", "Bangladesh ( Republica Popular De )", "Bangladesh (People's Republic of)"),
|
||||
(
|
||||
"BGD",
|
||||
"B9",
|
||||
"BD",
|
||||
"Bangladesh ( Republica Popular De )",
|
||||
"Bangladesh (People's Republic of)",
|
||||
),
|
||||
("BGR", "D1", "BG", "Bulgaria ( Republica De )", "Bulgaria (Republic of)"),
|
||||
("BHR", "B8", "BH", "Bahrein ( Estado De )", "Bahrain (State of)"),
|
||||
("BHS", "B7", "BS", "Bahamas( Comunidad De Las )", "Bahamas (Community of the )"),
|
||||
@@ -26,20 +62,50 @@ seed = [
|
||||
("BLZ", "C3", "BZ", "Belice", "Belize"),
|
||||
("BMU", "C4", "BM", "Bermudas", "Bermuda"),
|
||||
("BOL", "C6", "BO", "Bolivia ( Republica De )", "Bolivia (Republic of)"),
|
||||
("BRA", "C8", "BR", "Brasil (Republica Federativa De)", "Brazil (Federative Republic of)"),
|
||||
("BRB", "C1", "BB", "Barbados (Comunidad Britanica de Naciones)", "Barbados (Brithish Community of Nations)"),
|
||||
(
|
||||
"BRA",
|
||||
"C8",
|
||||
"BR",
|
||||
"Brasil (Republica Federativa De)",
|
||||
"Brazil (Federative Republic of)",
|
||||
),
|
||||
(
|
||||
"BRB",
|
||||
"C1",
|
||||
"BB",
|
||||
"Barbados (Comunidad Britanica de Naciones)",
|
||||
"Barbados (Brithish Community of Nations)",
|
||||
),
|
||||
("BRN", "C9", "BN", "Brunei (Estado De)(Residencia de Paz)", "Brunei (State of)"),
|
||||
("BTN", "D3", "BT", "Butan (Reino De )", "Bhutan (Royal Goverment of)"),
|
||||
("BUR", "BU", "BU", "Burma ( Birmania )", "Burma (Birmany)"),
|
||||
("BWA", "C7", "BW", "Bostwana ( Republica De )", "Botswana (Republic of)"),
|
||||
("CAF", "CF", "RB", "Republica Centro Africana", "Central African Republic"),
|
||||
("CAN", "D9", "CA", "Canada", "Canada"),
|
||||
("CCK", "E3", "CC", "Cocos ( Keeling, Islas Australianas)", "Cocos Keeling Islands (Australian Island"),
|
||||
(
|
||||
"CCK",
|
||||
"E3",
|
||||
"CC",
|
||||
"Cocos ( Keeling, Islas Australianas)",
|
||||
"Cocos Keeling Islands (Australian Island",
|
||||
),
|
||||
("CHE", "U8", "CH", "Suiza (Confederacion)", "Switzerland (Confederation)"),
|
||||
("CHL", "F6", "CL", "Chile ( Republica De )", "Chile (Republic of)"),
|
||||
("CHN", "Z3", "CN", "China ( Republica Popular) Derogado", "China (People's Republic of)"),
|
||||
(
|
||||
"CHN",
|
||||
"Z3",
|
||||
"CN",
|
||||
"China ( Republica Popular) Derogado",
|
||||
"China (People's Republic of)",
|
||||
),
|
||||
("CIA", "E2", "VA", "Ciudad Del Vaticano ( Estado De La )", "Vatican City State"),
|
||||
("CIV", "F1", "CT", "Costa de Marfil (Republica De La)", "Ivory Coast (Republic of)"),
|
||||
(
|
||||
"CIV",
|
||||
"F1",
|
||||
"CT",
|
||||
"Costa de Marfil (Republica De La)",
|
||||
"Ivory Coast (Republic of)",
|
||||
),
|
||||
("CMR", "D8", "CM", "Camerun ( Republica Del )", "Cameroon (Republic of the)"),
|
||||
("COG", "E6", "CG", "Congo ( Republica Del )", " Congo (Republic of the)"),
|
||||
("COK", "E7", "CK", "Cook ( Islas )", "Cook Islands"),
|
||||
@@ -48,50 +114,134 @@ seed = [
|
||||
("CPV", "D4", "CV", "Cabo Verde ( Republica De )", "Cape Verde (Republic of)"),
|
||||
("CRI", "F2", "CR", "Costa Rica ( Republica De )", "Costa Rica (Republic of)"),
|
||||
("CUB", "F3", "CU", "Cuba ( Republica De )", "Cuba (Republic of)"),
|
||||
("CUR", "D0", "UR", "Curazao (Terr. Holandes De Ultramar)", "Curazao (Netherlands Territory)"),
|
||||
(
|
||||
"CUR",
|
||||
"D0",
|
||||
"UR",
|
||||
"Curazao (Terr. Holandes De Ultramar)",
|
||||
"Curazao (Netherlands Territory)",
|
||||
),
|
||||
("CXI", "N8", "CX", "Navidad ( Christmas ) ( Islas )", "Christmas Islands"),
|
||||
("CYM", "D6", "KY", "Caiman ( Islas )", "Cayman Islands"),
|
||||
("CYP", "F8", "CY", "Chipre ( Republica De )", "Cyprus (Island of)"),
|
||||
("CZE", "CZ", "CZ", "Republica Checa", "Czech Federative Republic"),
|
||||
("DEU", "A4", "DE", "Alemania ( Republica Federal De )", "Germany (Federal Republic of)"),
|
||||
(
|
||||
"DEU",
|
||||
"A4",
|
||||
"DE",
|
||||
"Alemania ( Republica Federal De )",
|
||||
"Germany (Federal Republic of)",
|
||||
),
|
||||
("DJI", "V4", "DJ", "Djibouti ( Republica De )", "Djibouti (Republic of)"),
|
||||
("DMA", "G2", "DM", "Dominica ( Comunidad De )", "Dominica (Community of)"),
|
||||
("DNK", "G1", "DK", "Dinamarca ( Reino De )", "Denmark (Kingdom of)"),
|
||||
("DOM", "S2", "DO", "Republica Dominicana", "Dominican Republic"),
|
||||
("DSM", "FM", "FM", "Estado Federado De Micronesia", "Micronesia Federated State of"),
|
||||
("DZA", "B3", "DZ", "Argelia ( Republica Democratica y Popular de) Dero", "Argelia (People's Democratic Republic)"),
|
||||
(
|
||||
"DSM",
|
||||
"FM",
|
||||
"FM",
|
||||
"Estado Federado De Micronesia",
|
||||
"Micronesia Federated State of",
|
||||
),
|
||||
(
|
||||
"DZA",
|
||||
"B3",
|
||||
"DZ",
|
||||
"Argelia ( Republica Democratica y Popular de) Dero",
|
||||
"Argelia (People's Democratic Republic)",
|
||||
),
|
||||
("ECU", "G3", "EC", "Ecuador ( Republica Del)", "Ecuador (Republic of the)"),
|
||||
("EGY", "G4", "EG", "Egipto ( Republica Arabe De )", "Egypt (Arab Republic of)"),
|
||||
("EMU", "EU", "EU", "Comunidad Europea", "European Economic Community"),
|
||||
("ERI", "ER", "ER", "Eritrea (Estado De)", "Eritrea (State of)"),
|
||||
("ESH", "EH", "EH", "Sahara Occidental (Rep. Arabe Saharavi Dem.)", "Western Sahara (Arab Democratic Rep.)"),
|
||||
(
|
||||
"ESH",
|
||||
"EH",
|
||||
"EH",
|
||||
"Sahara Occidental (Rep. Arabe Saharavi Dem.)",
|
||||
"Western Sahara (Arab Democratic Rep.)",
|
||||
),
|
||||
("ESP", "G7", "ES", "España ( Reino De )", "Spain (Kingdom of)"),
|
||||
("EST", "G0", "EE", "Estonia (Republica De)", "Estonia (Republic of)"),
|
||||
("ETH", "G9", "ET", "Etiopia ( Republica Democratica Federal)", "Ethiopia (Federal Democratic Republic)"),
|
||||
(
|
||||
"ETH",
|
||||
"G9",
|
||||
"ET",
|
||||
"Etiopia ( Republica Democratica Federal)",
|
||||
"Ethiopia (Federal Democratic Republic)",
|
||||
),
|
||||
("FIN", "H4", "FI", "Finlandia ( Republica De )", "Finland (Republic of)"),
|
||||
("FJI", "H1", "FJ", "Fidji (Republica De )", "Fiji Islands"),
|
||||
("FLK", "FK", "IV", "Islas Malvinas (R.U.)", "Malvine Islands"),
|
||||
("FRA", "H5", "FR", "Francia (Republica Francesa)", "France (Republic)"),
|
||||
("FXA", "TF", "TF", "Territorios Franceses Austriales y Antarticos", "French Territory of Antartic Austral"),
|
||||
(
|
||||
"FXA",
|
||||
"TF",
|
||||
"TF",
|
||||
"Territorios Franceses Austriales y Antarticos",
|
||||
"French Territory of Antartic Austral",
|
||||
),
|
||||
("GAB", "H6", "GA", "Gabonesa ( Republica )", "Gabonese Republic"),
|
||||
("GBR", "R9", "GB", "Reino Unido de la Gran Bretaña e Irlanda del Norte", "United Kingdom (Great Britain, Ireland N"),
|
||||
(
|
||||
"GBR",
|
||||
"R9",
|
||||
"GB",
|
||||
"Reino Unido de la Gran Bretaña e Irlanda del Norte",
|
||||
"United Kingdom (Great Britain, Ireland N",
|
||||
),
|
||||
("GEO", "GE", "GE", "Georgia (Republica De)", "Georgia (Republic of)"),
|
||||
("GHA", "H8", "GH", "Ghana ( Republica De )", "Ghana (Republic of)"),
|
||||
("GIB", "GI", "GI", "Gibraltar (R.U.)", "Gibraltar (U. K.)"),
|
||||
("GIN", "I8", "GN", "Guinea ( Republica De )", "Guinea (Republic of)"),
|
||||
("GLP", "I4", "GP", "Guadalupe (Departamento De)", "Guadeloupe (French Caribean Dependences)"),
|
||||
(
|
||||
"GLP",
|
||||
"I4",
|
||||
"GP",
|
||||
"Guadalupe (Departamento De)",
|
||||
"Guadeloupe (French Caribean Dependences)",
|
||||
),
|
||||
("GMB", "H7", "GM", "Gambia ( Republica De La)", "Gambia (Republic of)"),
|
||||
("GNB", "J1", "GW", "Guinea-Bissau ( Republica De )", "Guinea-Bissau (Republic of)"),
|
||||
("GNQ", "I9", "GQ", "Guinea Ecuatorial ( Republica De )", "Equatorial Guinea (Republic of)"),
|
||||
("GRC", "I2", "GR", "Grecia (Republica Helenica)", "Greece (Helenical Republic of)"),
|
||||
(
|
||||
"GNB",
|
||||
"J1",
|
||||
"GW",
|
||||
"Guinea-Bissau ( Republica De )",
|
||||
"Guinea-Bissau (Republic of)",
|
||||
),
|
||||
(
|
||||
"GNQ",
|
||||
"I9",
|
||||
"GQ",
|
||||
"Guinea Ecuatorial ( Republica De )",
|
||||
"Equatorial Guinea (Republic of)",
|
||||
),
|
||||
(
|
||||
"GRC",
|
||||
"I2",
|
||||
"GR",
|
||||
"Grecia (Republica Helenica)",
|
||||
"Greece (Helenical Republic of)",
|
||||
),
|
||||
("GRD", "I1", "GD", "Granada", "Grenada"),
|
||||
("GRL", "GL", "GL", "Groenlandia (Dinamarca)", "Greenland (Denmark)"),
|
||||
("GTM", "I6", "GT", "Guatemala ( Republica De )", "Guatemala (Republic of)"),
|
||||
("GUF", "I7", "GF", "Guyana Francesa", "French Guyana"),
|
||||
("GUM", "I5", "GU", "Guam ( E.U.A )", "Guam (U.S.A.)"),
|
||||
("GUY", "J2", "GY", "Guyana ( Republica Cooperativa De )", "Guyana (Cooperative Republic of)"),
|
||||
(
|
||||
"GUY",
|
||||
"J2",
|
||||
"GY",
|
||||
"Guyana ( Republica Cooperativa De )",
|
||||
"Guyana (Cooperative Republic of)",
|
||||
),
|
||||
("GZA", "GZ", "GZ", "Franja De Gaza", "Gaza Strip"),
|
||||
("HKG", "J6", "HK", "Hong Kong (Region Admiva. Especial de la Rep. )", "Hong Kong (Territory of)"),
|
||||
(
|
||||
"HKG",
|
||||
"J6",
|
||||
"HK",
|
||||
"Hong Kong (Region Admiva. Especial de la Rep. )",
|
||||
"Hong Kong (Territory of)",
|
||||
),
|
||||
("HND", "J5", "HN", "Honduras ( Republica De )", "Honduras (Republic of)"),
|
||||
("HRV", "HR", "HR", "Croacia (Republica De)", "Croatia (Republic of)"),
|
||||
("HTI", "J3", "HT", "Haiti ( Republica De )", "Haiti (Republic of)"),
|
||||
@@ -99,13 +249,25 @@ seed = [
|
||||
("IDN", "J9", "ID", "Indonesia ( Republica De )", "Indonesia (Republic of)"),
|
||||
("IND", "J8", "IN", "India ( Republica De)", "India (Republic of the)"),
|
||||
("IRL", "K3", "IE", "Irlanda ( Republica De )", "Ireland (Republic of)"),
|
||||
("IRN", "K2", "IR", "Iran ( Republica Islamica Del )", "Iran (Islamic Republic of)"),
|
||||
(
|
||||
"IRN",
|
||||
"K2",
|
||||
"IR",
|
||||
"Iran ( Republica Islamica Del )",
|
||||
"Iran (Islamic Republic of)",
|
||||
),
|
||||
("IRQ", "K1", "IQ", "Irak ( Republica De )", "Iraq (Republic of)"),
|
||||
("ISL", "K4", "IS", "Islandia ( Republica De )", "Iceland (Republic of)"),
|
||||
("ISR", "K5", "IL", "Israel ( Estado De )", "Israel (State of)"),
|
||||
("ITA", "K6", "IT", "Italia (Republica Italiana)", "Italy (Republic)"),
|
||||
("JAM", "K7", "JM", "Jamaica", "Jamaica"),
|
||||
("JOR", "L1", "JO", "Jordania ( Reino Hachemita De )", "Jordan (Hachemite Kingdom of)"),
|
||||
(
|
||||
"JOR",
|
||||
"L1",
|
||||
"JO",
|
||||
"Jordania ( Reino Hachemita De )",
|
||||
"Jordan (Hachemite Kingdom of)",
|
||||
),
|
||||
("JPN", "K9", "JP", "Japon", "Japan"),
|
||||
("KAZ", "KZ", "KZ", "Kazakhstan (Republica de)", "Kazakhstan"),
|
||||
("KCD", "Z9", "PD", "Paises No Declarados", "Not Declared Countries"),
|
||||
@@ -113,49 +275,133 @@ seed = [
|
||||
("KGZ", "KG", "KG", "Kyrgyzstan (Republica Kirgyzia)", "Kyrgyzstan"),
|
||||
("KHM", "D7", "KH", "Camboya (Reino de)", "Cambodia"),
|
||||
("KIR", "L0", "KI", "Kiribati (Republica de)", "Kiribati"),
|
||||
("KNA", "S9", "KN", "San Cristobal Y Nieves (Fed. de)(San Kitts-Nevis)", "St. Christopher - Nevis"),
|
||||
(
|
||||
"KNA",
|
||||
"S9",
|
||||
"KN",
|
||||
"San Cristobal Y Nieves (Fed. de)(San Kitts-Nevis)",
|
||||
"St. Christopher - Nevis",
|
||||
),
|
||||
("KOR", "E8", "KR", "Corea (Republica De)(Corea del Sur)", "Korea Republic of"),
|
||||
("KWT", "L3", "KW", "Kuwait (Estado de)", "kuwait"),
|
||||
("LAO", "L4", "LA", "Republica Democratica Popular Laos", "Laos (People's Democratic Republic of)"),
|
||||
(
|
||||
"LAO",
|
||||
"L4",
|
||||
"LA",
|
||||
"Republica Democratica Popular Laos",
|
||||
"Laos (People's Democratic Republic of)",
|
||||
),
|
||||
("LBN", "L7", "LB", "Libano (Republica de)", "Lebanon"),
|
||||
("LBR", "L8", "LR", "Liberia ( Republica De )", "Liberia (Republic of)"),
|
||||
("LBY", "L9", "LY", "Libia (Jamahiriya Libia Araba Pop. Soc.)", "Lybia (Arab Jamahiriya)"),
|
||||
(
|
||||
"LBY",
|
||||
"L9",
|
||||
"LY",
|
||||
"Libia (Jamahiriya Libia Araba Pop. Soc.)",
|
||||
"Lybia (Arab Jamahiriya)",
|
||||
),
|
||||
("LCA", "T4", "LC", "Santa Lucia", "Saint Lucia"),
|
||||
("LHM", "HM", "HM", "Islas Heard Y Mcdonald", "Heard & MacDonald Islands"),
|
||||
("LIE", "L5", "LI", "Liechtenstein (Principado de)", "Liechtenstein (Principated of)"),
|
||||
("LKA", "U4", "LK", "Sri Lanka ( Republica Democratica Soc.)", "Sri Lanka (Socialist Democratic Republic"),
|
||||
(
|
||||
"LIE",
|
||||
"L5",
|
||||
"LI",
|
||||
"Liechtenstein (Principado de)",
|
||||
"Liechtenstein (Principated of)",
|
||||
),
|
||||
(
|
||||
"LKA",
|
||||
"U4",
|
||||
"LK",
|
||||
"Sri Lanka ( Republica Democratica Soc.)",
|
||||
"Sri Lanka (Socialist Democratic Republic",
|
||||
),
|
||||
("LSO", "L6", "LS", "Lesotho ( Reino De )", "Lesotho (Kingdom of)"),
|
||||
("LTU", "Y2", "LT", "Lituania (Republica de)", "Lithuania"),
|
||||
("LUX", "M0", "LU", "Luxemburgo ( Gran Ducado De)", "Luxembourg (Great Ducated of)"),
|
||||
(
|
||||
"LUX",
|
||||
"M0",
|
||||
"LU",
|
||||
"Luxemburgo ( Gran Ducado De)",
|
||||
"Luxembourg (Great Ducated of)",
|
||||
),
|
||||
("LVA", "Y1", "LV", "Letonia (Republica de)", "Latvia"),
|
||||
("MAC", "M1", "MO", "Macao", "Macau"),
|
||||
("MAR", "M8", "MR", "Marruecos ( Reino De )", "Morocco (Kingdom of)"),
|
||||
("MCO", "N0", "MC", "Monaco (Principado De)", "Monaco (Principated of)"),
|
||||
("MDA", "MD", "MD", "Moldavia (Republica de)", "Moldova"),
|
||||
("MDG", "M2", "MG", "Madagascar ( Republica De)", "Madagascar (Democratic Republic of)"),
|
||||
(
|
||||
"MDG",
|
||||
"M2",
|
||||
"MG",
|
||||
"Madagascar ( Republica De)",
|
||||
"Madagascar (Democratic Republic of)",
|
||||
),
|
||||
("MDV", "M5", "MV", "Maldivas ( Republica De )", "Maldives (Republic of the)"),
|
||||
("MEX", "N3", "MX", "Mexico (Estados Unidos Mexicanos)", "Mexico"),
|
||||
("MHL", "MH", "MH", "Islas Marshall", "Marshall Islands"),
|
||||
("MKD", "MK", "MK", "Macedonia (Antigua Rep. Yugoslava De)", "Macedonia (Old Yugoslavian Republic)"),
|
||||
(
|
||||
"MKD",
|
||||
"MK",
|
||||
"MK",
|
||||
"Macedonia (Antigua Rep. Yugoslava De)",
|
||||
"Macedonia (Old Yugoslavian Republic)",
|
||||
),
|
||||
("MLI", "M6", "ML", "Mali ( Republica De )", "Mali (Republic of)"),
|
||||
("MLT", "M7", "MT", "Malta ( Republica De )", "Malta and Gozo (Republic of)"),
|
||||
("MMR", "C5", "MM", "Myanmar ( Union De )", "Myammar (Union of)"),
|
||||
("MNE", "ME", "ME", "Montenegro", ""),
|
||||
("MNG", "N4", "MN", "Mongolia", "Mongolia (People's Republic of)"),
|
||||
("MNP", "MP", "IM", "Islas Marianas Septentrionales", "Marianes Septentrional Islands"),
|
||||
("MOZ", "N6", "MZ", "Mozambique ( Republica De)", "Mozambique (People's Republic of)"),
|
||||
("MRT", "N2", "RT", "Mauritania ( Republica Islamica De )", "Mauritania (Islamic Republic of)"),
|
||||
(
|
||||
"MNP",
|
||||
"MP",
|
||||
"IM",
|
||||
"Islas Marianas Septentrionales",
|
||||
"Marianes Septentrional Islands",
|
||||
),
|
||||
(
|
||||
"MOZ",
|
||||
"N6",
|
||||
"MZ",
|
||||
"Mozambique ( Republica De)",
|
||||
"Mozambique (People's Republic of)",
|
||||
),
|
||||
(
|
||||
"MRT",
|
||||
"N2",
|
||||
"RT",
|
||||
"Mauritania ( Republica Islamica De )",
|
||||
"Mauritania (Islamic Republic of)",
|
||||
),
|
||||
("MSR", "N5", "MS", "Monserrat ( Isla )", "Montserrat Island"),
|
||||
("MTQ", "M9", "MQ", "Martinica (Departamento de) (Francia)", "Martinique (Department of)"),
|
||||
(
|
||||
"MTQ",
|
||||
"M9",
|
||||
"MQ",
|
||||
"Martinica (Departamento de) (Francia)",
|
||||
"Martinique (Department of)",
|
||||
),
|
||||
("MUS", "N1", "MU", "Mauricio ( Republica De )", "Mauritius (State of)"),
|
||||
("MWI", "M4", "MW", "Malawi ( Republica De )", "Malawi (Republic of)"),
|
||||
("MYS", "M3", "MY", "Malasia", "Malaysia (Federation of)"),
|
||||
("NAM", "P0", "NA", "Namibia ( Republica De )", "Namibia (Republic of)"),
|
||||
("NCA", "P7", "TE", "Terr. Frances Ultramar Nueva Caledonia", "French Territory of New Caledonia"),
|
||||
(
|
||||
"NCA",
|
||||
"P7",
|
||||
"TE",
|
||||
"Terr. Frances Ultramar Nueva Caledonia",
|
||||
"French Territory of New Caledonia",
|
||||
),
|
||||
("NCL", "NC", "NC", "Nueva Caledonia (Terr.Frances de Ultramar)", "New Caledonia"),
|
||||
("NER", "P2", "NE", "Niger ( Republica De)", "Niger (Federal Republic of)"),
|
||||
("NFK", "P5", "NF", "Norfolk ( Isla )", "Norfolk Island"),
|
||||
("NGA", "P3", "NG", "Nigeria ( Republica Federal De)", "Nigeria (Federal Republic of)"),
|
||||
(
|
||||
"NGA",
|
||||
"P3",
|
||||
"NG",
|
||||
"Nigeria ( Republica Federal De)",
|
||||
"Nigeria (Federal Republic of)",
|
||||
),
|
||||
("NIC", "P1", "NI", "Nicaragua ( Republica De )", "Nicaragua (Republic of)"),
|
||||
("NIU", "P4", "NU", "Nive ( Isla )", "Nive Island"),
|
||||
("NOR", "P6", "NO", "Noruega ( Reino De )", "Norway (Kingdom of)"),
|
||||
@@ -163,27 +409,81 @@ seed = [
|
||||
("NRU", "N7", "NR", "Nauru", "Nauru"),
|
||||
("NZL", "P9", "NZ", "Nueva Zelandia", "New Zealand"),
|
||||
("OMN", "Q2", "OM", "Oman (Sultanato De )", "Oman (Sultanate of)"),
|
||||
("PAK", "Q7", "PK", "Pakistan ( Republica Islamica De )", "Pakistan (Islamic Republic of)"),
|
||||
(
|
||||
"PAK",
|
||||
"Q7",
|
||||
"PK",
|
||||
"Pakistan ( Republica Islamica De )",
|
||||
"Pakistan (Islamic Republic of)",
|
||||
),
|
||||
("PAN", "Q8", "PA", "Panama ( Republica De )", "Panama (Republic of)"),
|
||||
("PCN", "R3", "PN", "Pitcairns ( Islas Dependencia Britanica )", "Pitcairn Island (Brithish Dependence)"),
|
||||
(
|
||||
"PCN",
|
||||
"R3",
|
||||
"PN",
|
||||
"Pitcairns ( Islas Dependencia Britanica )",
|
||||
"Pitcairn Island (Brithish Dependence)",
|
||||
),
|
||||
("PER", "R2", "PE", "Peru ( Republica Del )", "Peru (Republic of )"),
|
||||
("PHL", "H3", "PH", "Filipinas ( Republica De Las )", "Philippines (Republic of the)"),
|
||||
("PIK", "Q3", "PI", "Pacifico Islas Del ( Admon. E.U.A. )", "Pacific Islands (U.S.A. Administration)"),
|
||||
(
|
||||
"PHL",
|
||||
"H3",
|
||||
"PH",
|
||||
"Filipinas ( Republica De Las )",
|
||||
"Philippines (Republic of the)",
|
||||
),
|
||||
(
|
||||
"PIK",
|
||||
"Q3",
|
||||
"PI",
|
||||
"Pacifico Islas Del ( Admon. E.U.A. )",
|
||||
"Pacific Islands (U.S.A. Administration)",
|
||||
),
|
||||
("PLW", "PW", "PW", "Palau (Republica De)", "Palau (Republic of)"),
|
||||
("PNG", "P8", "PP", "Papua Nueva Guinea (Edo. Independiente de)", "Papua New Guinea (Independent State of)"),
|
||||
(
|
||||
"PNG",
|
||||
"P8",
|
||||
"PP",
|
||||
"Papua Nueva Guinea (Edo. Independiente de)",
|
||||
"Papua New Guinea (Independent State of)",
|
||||
),
|
||||
("POL", "R5", "PL", "Polonia ( Republica De )", "Poland (Republic of)"),
|
||||
("PRI", "R7", "PR", "Puerto Rico (Edo.Libre Asociado de la Com. de) Der", "Puerto Rico (Free Asociated State of)"),
|
||||
("PRK", "E9", "KP", "Corea ( Rep. Pop. Dem.de)(Corea del Norte)", "Korea (North)(People's Democratic Rep.of"),
|
||||
(
|
||||
"PRI",
|
||||
"R7",
|
||||
"PR",
|
||||
"Puerto Rico (Edo.Libre Asociado de la Com. de) Der",
|
||||
"Puerto Rico (Free Asociated State of)",
|
||||
),
|
||||
(
|
||||
"PRK",
|
||||
"E9",
|
||||
"KP",
|
||||
"Corea ( Rep. Pop. Dem.de)(Corea del Norte)",
|
||||
"Korea (North)(People's Democratic Rep.of",
|
||||
),
|
||||
("PRT", "R6", "PT", "Portugal (Republica Portuguesa)", "Portugal (Republic of)"),
|
||||
("PRY", "R1", "PY", "Paraguay ( Republica Del )", "Paraguay (Republic of)"),
|
||||
("PSE", "PS", "PS", "Palestina", ""),
|
||||
("PTY", "Z2", "ZO", "Zona Del Canal De Panama", "Zone of the Panama's Channel"),
|
||||
("PYF", "R4", "PF", "Polinesia Francesa", "French Polynesia"),
|
||||
("QAT", "R8", "QA", "Qatar ( Estado De )", "Qatar (State of)"),
|
||||
("REU", "S3", "RE", "Reunion (Departamento de la) ( Francia)", "Reunion Islands (French Department)"),
|
||||
(
|
||||
"REU",
|
||||
"S3",
|
||||
"RE",
|
||||
"Reunion (Departamento de la) ( Francia)",
|
||||
"Reunion Islands (French Department)",
|
||||
),
|
||||
("RKE", "E1", "RK", "Canal Islas del ( Islas Normandas )", "Channel Islands"),
|
||||
("ROM", "S5", "RO", "Rumania", "Romania (Republic of)"),
|
||||
("RUH", "NT", "NT", "Zona Neutral Iraq-Arabia Saudita", "Neutral Zone of Iraq - Saudi Arabia"),
|
||||
(
|
||||
"RUH",
|
||||
"NT",
|
||||
"NT",
|
||||
"Zona Neutral Iraq-Arabia Saudita",
|
||||
"Neutral Zone of Iraq - Saudi Arabia",
|
||||
),
|
||||
("RUS", "RU", "RU", "Rusia (Federacion Rusa)", "Russia (Federation)"),
|
||||
("RWA", "S6", "RW", "Republica Ruandesa", "Rwanda"),
|
||||
("SAU", "B2", "SA", "Arabia Saudita ( Reino De )", "Saudi Arabia (Kingdom of)"),
|
||||
@@ -191,21 +491,51 @@ seed = [
|
||||
("SEN", "T6", "SN", "Senegal ( Republica Del )", "Senegal (Republic of the)"),
|
||||
("SGP", "U1", "SG", "Singapur ( Republica De )", "Singapore (Republic of)"),
|
||||
("SHN", "T3", "SH", "Santa Elena", "St. Helena"),
|
||||
("SJM", "SJ", "SJ", "Islas Svalbard Y Jan Mayen (Noruega)", "Svalbard & Jan Mayen Islands"),
|
||||
("SLB", "SB", "SB", "Islas Salomon (Com. Britanica de Naciones)", "Solomon Islands (Brithish Community)"),
|
||||
(
|
||||
"SJM",
|
||||
"SJ",
|
||||
"SJ",
|
||||
"Islas Svalbard Y Jan Mayen (Noruega)",
|
||||
"Svalbard & Jan Mayen Islands",
|
||||
),
|
||||
(
|
||||
"SLB",
|
||||
"SB",
|
||||
"SB",
|
||||
"Islas Salomon (Com. Britanica de Naciones)",
|
||||
"Solomon Islands (Brithish Community)",
|
||||
),
|
||||
("SLE", "T8", "SL", "Sierra Leona ( Republica De )", "Sierra Leone (Republic of)"),
|
||||
("SLV", "G5", "SV", "El Salvador ( Republica De )", "El Salvador (Republic of)"),
|
||||
("SMR", "T0", "SM", "San Marino (Serenisima Republica De)", "San Marino (Republic of"),
|
||||
(
|
||||
"SMR",
|
||||
"T0",
|
||||
"SM",
|
||||
"San Marino (Serenisima Republica De)",
|
||||
"San Marino (Republic of",
|
||||
),
|
||||
("SOM", "U3", "SO", "Somalia", "Somalia (Democratic Republic of)"),
|
||||
("SPM", "T1", "PM", "San Pedro Y Miquelon", "St. Pierre and Miquelon"),
|
||||
("SRB", "RS", "RS", "Republica de Serbia", ""),
|
||||
("STP", "T5", "ST", "Santo Tome Y Principe (Rep. Democratica de)", "Sao Tome and Principe (Dem. Rep.)"),
|
||||
(
|
||||
"STP",
|
||||
"T5",
|
||||
"ST",
|
||||
"Santo Tome Y Principe (Rep. Democratica de)",
|
||||
"Sao Tome and Principe (Dem. Rep.)",
|
||||
),
|
||||
("SUR", "U9", "SR", "Suriname ( Republica De )", "Surinam (Republic of)"),
|
||||
("SVK", "SK", "SK", "Republica Eslovaca", "Slovakia (Republic)"),
|
||||
("SVN", "SI", "SI", "Eslovenia (Republica De)", "Slovenia (Republic of)"),
|
||||
("SWE", "U7", "SE", "Suecia ( Reino De )", "Sweden (Kingdom of)"),
|
||||
("SWZ", "V0", "SZ", "Swazilandia ( Reino De )", "Swaziland (Kingdom of)"),
|
||||
("SYC", "T7", "SC", "Seychelles (Republica De Las)", "Seychelles (Republic of the)"),
|
||||
(
|
||||
"SYC",
|
||||
"T7",
|
||||
"SC",
|
||||
"Seychelles (Republica De Las)",
|
||||
"Seychelles (Republic of the)",
|
||||
),
|
||||
("SYR", "U2", "SY", "Siria ( Republica Arabe )", "Syrian Arab Republic"),
|
||||
("TCA", "W3", "TC", "Turcas Y Caicos ( Islas )", "Turks and Caicos Islands"),
|
||||
("TCD", "F4", "TD", "Chad ( Republica De )", "Chad (Republic of)"),
|
||||
@@ -216,30 +546,102 @@ seed = [
|
||||
("TKM", "TM", "TM", "Turkmenistan (Republica De)", "Turkmenistan (Republic of)"),
|
||||
("TMP", "TP", "TP", "Timor Oriental", "East Timor"),
|
||||
("TON", "TO", "TO", "Tonga (Reino De)", "Tonga (Kingdom of)"),
|
||||
("TTO", "W1", "TT", "Trinidad Y Tobago ( Republica De )", "Trinidad and Tobago (Republic of)"),
|
||||
(
|
||||
"TTO",
|
||||
"W1",
|
||||
"TT",
|
||||
"Trinidad Y Tobago ( Republica De )",
|
||||
"Trinidad and Tobago (Republic of)",
|
||||
),
|
||||
("TUN", "W2", "TN", "Tunez ( Republica De )", "Tunisia (Republic of)"),
|
||||
("TUR", "W4", "TR", "Turquia ( Republica De )", "Turkey (Republic of)"),
|
||||
("TUV", "TV", "TV", "Tuvalu (Comunidad Britanica de Naciones)", "Tuvalu (Brithish Community of Nations)"),
|
||||
(
|
||||
"TUV",
|
||||
"TV",
|
||||
"TV",
|
||||
"Tuvalu (Comunidad Britanica de Naciones)",
|
||||
"Tuvalu (Brithish Community of Nations)",
|
||||
),
|
||||
("TWN", "F7", "TW", "Taiwan (Republica de China)", "Taiwan"),
|
||||
("TZA", "V2", "TZ", "Tanzania ( Republica Unida De )", "Tanzania United Republic of"),
|
||||
(
|
||||
"TZA",
|
||||
"V2",
|
||||
"TZ",
|
||||
"Tanzania ( Republica Unida De )",
|
||||
"Tanzania United Republic of",
|
||||
),
|
||||
("UGA", "W5", "UG", "Uganda ( Republica De )", "Uganda (Republic of)"),
|
||||
("UKR", "UA", "UA", "Ucrania", "Ukraine"),
|
||||
("URY", "W7", "UY", "Uruguay ( Republica Oriental Del )", "Uruguay (Eastern Republic of the)"),
|
||||
(
|
||||
"URY",
|
||||
"W7",
|
||||
"UY",
|
||||
"Uruguay ( Republica Oriental Del )",
|
||||
"Uruguay (Eastern Republic of the)",
|
||||
),
|
||||
("USA", "G8", "US", "Estados Unidos de America", "United States of America"),
|
||||
("UZB", "Y4", "UZ", "Uzbejistan (Republica de)", "Uzbekistan (Republic)"),
|
||||
("VCT", "T2", "VC", "San Vicente Y Las Granadinas", "St. Vincent and the Grenadines"),
|
||||
(
|
||||
"VCT",
|
||||
"T2",
|
||||
"VC",
|
||||
"San Vicente Y Las Granadinas",
|
||||
"St. Vincent and the Grenadines",
|
||||
),
|
||||
("VEN", "W8", "VE", "Venezuela ( Republica De )", "Venezuela (Republic of)"),
|
||||
("VGB", "X2", "VG", "Virgenes Islas ( Britanicas )", "Virgin Islands (British)"),
|
||||
("VIR", "X3", "VI", "Virgenes Islas ( Norteamericanas )", "Virgin Islands (American)"),
|
||||
("VNM", "W9", "VN", "Vietnam ( Republica Socialista De )", "Vietnam (Socialist Republic of)"),
|
||||
(
|
||||
"VIR",
|
||||
"X3",
|
||||
"VI",
|
||||
"Virgenes Islas ( Norteamericanas )",
|
||||
"Virgin Islands (American)",
|
||||
),
|
||||
(
|
||||
"VNM",
|
||||
"W9",
|
||||
"VN",
|
||||
"Vietnam ( Republica Socialista De )",
|
||||
"Vietnam (Socialist Republic of)",
|
||||
),
|
||||
("VUT", "Q1", "VU", "Vanuatu", "Vanuatu"),
|
||||
("WLF", "WF", "WF", "Islas Wallis Y Futuna", "Wallis & Futuna Islands"),
|
||||
("WSM", "S8", "WS", "Samoa (Estado Independiente de)", "Western Samoa (Independent State)"),
|
||||
("XCH", "V3", "IO", "Territorios Britanicos Del Oceano Indico", "Brithish Territory of the Indic Ocean"),
|
||||
(
|
||||
"WSM",
|
||||
"S8",
|
||||
"WS",
|
||||
"Samoa (Estado Independiente de)",
|
||||
"Western Samoa (Independent State)",
|
||||
),
|
||||
(
|
||||
"XCH",
|
||||
"V3",
|
||||
"IO",
|
||||
"Territorios Britanicos Del Oceano Indico",
|
||||
"Brithish Territory of the Indic Ocean",
|
||||
),
|
||||
("YEM", "YE", "YE", "Yemen (Republica De)", "Yemen (Republic of)"),
|
||||
("YUG", "X8", "YU", "Yugoslavia (Republica Federal de)", "Yugoslavia (Federal Republic of)"),
|
||||
("ZAF", "U5", "ZA", "Sudafrica ( Republica De ) Derogado", "South Africa (Republic of)"),
|
||||
(
|
||||
"YUG",
|
||||
"X8",
|
||||
"YU",
|
||||
"Yugoslavia (Republica Federal de)",
|
||||
"Yugoslavia (Federal Republic of)",
|
||||
),
|
||||
(
|
||||
"ZAF",
|
||||
"U5",
|
||||
"ZA",
|
||||
"Sudafrica ( Republica De ) Derogado",
|
||||
"South Africa (Republic of)",
|
||||
),
|
||||
("ZMB", "Z1", "ZM", "Zambia ( Republica De )", "Zambia (Republic of)"),
|
||||
("ZWE", "S4", "ZW", "Zimbabwe ( Republica De )", "Zimbabwe (Republic of)"),
|
||||
("ZYA", "J4", "NL", "Paises Bajos ( Reino De Los )(Holanda)", "Netherlands (Kingdom of)(Holand)"),
|
||||
]
|
||||
(
|
||||
"ZYA",
|
||||
"J4",
|
||||
"NL",
|
||||
"Paises Bajos ( Reino De Los )(Holanda)",
|
||||
"Netherlands (Kingdom of)(Holand)",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_countries(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,26 @@ def test_list_countries(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_country_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/countries/invalid_key", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_country_forbidden():
|
||||
response = client.post("/countries/", json={"m3_key": "TST", "description": "Test"})
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_country_forbidden():
|
||||
response = client.put("/countries/TST", json={"m3_key": "TST", "description": "Test"})
|
||||
response = client.put(
|
||||
"/countries/TST", json={"m3_key": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_country_forbidden():
|
||||
response = client.delete("/countries/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
|
||||
|
||||
class CurrencyTypeDTO(BaseModel):
|
||||
code: str = Field(..., min_length=1, max_length=3)
|
||||
currency_name: str
|
||||
country_description: str
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -4,15 +4,21 @@ from core.database import Base
|
||||
|
||||
|
||||
class CurrencyType(Base):
|
||||
__tablename__ = "currency_types" #GTiposMoneda
|
||||
__tablename__ = "currency_types" # GTiposMoneda
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("code", name="currency_types_pkey"),
|
||||
{"schema": "public"} # opcional
|
||||
{"schema": "public"}, # opcional
|
||||
)
|
||||
|
||||
code: Mapped[str] = mapped_column(String(3), nullable=False) # código ISO o clave de moneda
|
||||
currency_name: Mapped[str] = mapped_column(String(15), nullable=False) # nombre de la moneda (por ejemplo: Peso, Dollar)
|
||||
country_description: Mapped[str] = mapped_column(String(50)) # país asociado o descripción del país
|
||||
code: Mapped[str] = mapped_column(
|
||||
String(3), nullable=False
|
||||
) # código ISO o clave de moneda
|
||||
currency_name: Mapped[str] = mapped_column(
|
||||
String(15), nullable=False
|
||||
) # nombre de la moneda (por ejemplo: Peso, Dollar)
|
||||
country_description: Mapped[str] = mapped_column(
|
||||
String(50)
|
||||
) # país asociado o descripción del país
|
||||
|
||||
def __repr__(self):
|
||||
return f"<CurrencyType(code={self.code}, currency_name={self.currency_name}, country_description={self.country_description})>"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -11,13 +10,12 @@ from typing import Any, Dict
|
||||
router = APIRouter(prefix="/currency-types")
|
||||
|
||||
|
||||
|
||||
@router.get("/", response_model=Dict[str, Any])
|
||||
async def list_currency_types(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(CurrencyType)
|
||||
@@ -27,23 +25,27 @@ async def list_currency_types(
|
||||
"items": [CurrencyTypeDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@router.get("/{code}", response_model=CurrencyTypeDTO)
|
||||
async def get_currency_type(code: str, db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user)):
|
||||
async def get_currency_type(
|
||||
code: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(CurrencyType).filter(CurrencyType.code == code).first()
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.post("/", response_model=CurrencyTypeDTO, status_code=201)
|
||||
async def create_currency_type(
|
||||
data: CurrencyTypeDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = CurrencyType(**data.dict())
|
||||
db.add(obj)
|
||||
@@ -51,13 +53,13 @@ async def create_currency_type(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.put("/{code}", response_model=CurrencyTypeDTO)
|
||||
async def update_currency_type(
|
||||
code: str,
|
||||
data: CurrencyTypeDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(CurrencyType).filter(CurrencyType.code == code).first()
|
||||
if not obj:
|
||||
@@ -68,12 +70,12 @@ async def update_currency_type(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.delete("/{code}", status_code=204)
|
||||
async def delete_currency_type(
|
||||
code: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(CurrencyType).filter(CurrencyType.code == code).first()
|
||||
if not obj:
|
||||
|
||||
@@ -93,4 +93,4 @@ seed = [
|
||||
("YUD", "DINAR", "YUGOSLAVIA"),
|
||||
("ZAR", "RAND", "UNION SUDAFRICANA"),
|
||||
("ZRZ", "FRANCO", "REPUBLICA DEMOCRATICA DEL CONGO"),
|
||||
]
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_currency_types(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,28 @@ def test_list_currency_types(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_currency_type_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/currency-types/invalid_code", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_currency_type_forbidden():
|
||||
response = client.post("/currency-types/", json={"code": "TST", "description": "Test"})
|
||||
response = client.post(
|
||||
"/currency-types/", json={"code": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_currency_type_forbidden():
|
||||
response = client.put("/currency-types/TST", json={"code": "TST", "description": "Test"})
|
||||
response = client.put(
|
||||
"/currency-types/TST", json={"code": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_currency_type_forbidden():
|
||||
response = client.delete("/currency-types/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
|
||||
|
||||
class CustomsSectionDTO(BaseModel):
|
||||
customs_code: str = Field(..., min_length=1, max_length=3)
|
||||
section_name: str
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -2,15 +2,16 @@ from sqlalchemy import String, PrimaryKeyConstraint
|
||||
from sqlalchemy.orm import mapped_column
|
||||
from core.database import Base
|
||||
|
||||
|
||||
class CustomsSection(Base):
|
||||
__tablename__ = "customs_sections" #GAduanaSec
|
||||
__tablename__ = "customs_sections" # GAduanaSec
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("customs_code", name="customs_code_pkey"),
|
||||
{"schema": "public"}
|
||||
{"schema": "public"},
|
||||
)
|
||||
|
||||
customs_code = mapped_column(String(3), nullable=False)
|
||||
section_name = mapped_column(String(255), nullable=False)
|
||||
section_name = mapped_column(String(255), nullable=False)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<CustomsSection(code={self.customs_code}, name={self.section_name })>"
|
||||
return f"<CustomsSection(code={self.customs_code}, name={self.section_name })>"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -16,7 +15,7 @@ def list_customs_sections(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(CustomsSection)
|
||||
@@ -26,21 +25,31 @@ def list_customs_sections(
|
||||
"items": [CustomsSectionDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{customs_code}", response_model=CustomsSectionDTO)
|
||||
def get_customs_section(customs_code: str, db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user)):
|
||||
obj = db.query(CustomsSection).filter(CustomsSection.customs_code == customs_code).first()
|
||||
def get_customs_section(
|
||||
customs_code: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
obj = (
|
||||
db.query(CustomsSection)
|
||||
.filter(CustomsSection.customs_code == customs_code)
|
||||
.first()
|
||||
)
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return obj
|
||||
|
||||
|
||||
@router.post("/", response_model=CustomsSectionDTO, status_code=201)
|
||||
def create_customs_section(
|
||||
data: CustomsSectionDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = CustomsSection(**data.dict())
|
||||
db.add(obj)
|
||||
@@ -48,14 +57,19 @@ def create_customs_section(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
@router.put("/{customs_code}", response_model=CustomsSectionDTO)
|
||||
def update_customs_section(
|
||||
customs_code: str,
|
||||
data: CustomsSectionDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(CustomsSection).filter(CustomsSection.customs_code == customs_code).first()
|
||||
obj = (
|
||||
db.query(CustomsSection)
|
||||
.filter(CustomsSection.customs_code == customs_code)
|
||||
.first()
|
||||
)
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
for field, value in data.dict().items():
|
||||
@@ -64,13 +78,18 @@ def update_customs_section(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
@router.delete("/{customs_code}", status_code=204)
|
||||
def delete_customs_section(
|
||||
customs_code: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(CustomsSection).filter(CustomsSection.customs_code == customs_code).first()
|
||||
obj = (
|
||||
db.query(CustomsSection)
|
||||
.filter(CustomsSection.customs_code == customs_code)
|
||||
.first()
|
||||
)
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
db.delete(obj)
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
seed = [
|
||||
("01", "AEROPUERTO INTERNACIONAL GENERAL JUAN N. ALVAREZ, ACAPULCO, GUERRERO."),
|
||||
("01", "AEROPUERTO INTERNACIONAL GENERAL JUAN N. ALVAREZ, ACAPULCO, GUERRERO."),
|
||||
("010", "ACAPULCO, ACAPULCO DE JUAREZ, GUERRERO."),
|
||||
("012", "AEROPUERTO INTERNACIONAL GENERAL JUAN N. ALVAREZ, ACAPULCO, GUERRERO."),
|
||||
("020", "AGUA PRIETA, AGUA PRIETA, SONORA."),
|
||||
("050", "SUBTENIENTE LOPEZ, SUBTENIENTE LOPEZ, QUINTANA ROO."),
|
||||
("051", "SUBTENIENTE LOPEZ II „CHACTEMAL“, OTHÓN P. BLANCO, CHETUMAL, QUINTANA ROO."),
|
||||
(
|
||||
"051",
|
||||
"SUBTENIENTE LOPEZ II „CHACTEMAL“, OTHÓN P. BLANCO, CHETUMAL, QUINTANA ROO.",
|
||||
),
|
||||
("060", "CIUDAD DEL CARMEN, CIUDAD DEL CARMEN, CAMPECHE."),
|
||||
("063", "SEYBAPLAYA, CHAMPOTON, CAMPECHE."),
|
||||
("070", "CIUDAD JUAREZ, CIUDAD JUAREZ, CHIHUAHUA."),
|
||||
@@ -15,8 +18,14 @@ seed = [
|
||||
("080", "COATZACOALCOS, COATZACOALCOS, VERACRUZ."),
|
||||
("110", "ENSENADA, ENSENADA, BAJA CALIFORNIA."),
|
||||
("120", "GUAYMAS, GUAYMAS, SONORA."),
|
||||
("121", "AEROPUERTO INTERNACIONAL GENERAL IGNACIO PESQUEIRA GARCIA, HERMOSILLO, SONORA."),
|
||||
("123", "CIUDAD OBREGON ADYACENTE AL AEROPUERTO DE CIUDAD OBREGON, CAJEME, SONORA."),
|
||||
(
|
||||
"121",
|
||||
"AEROPUERTO INTERNACIONAL GENERAL IGNACIO PESQUEIRA GARCIA, HERMOSILLO, SONORA.",
|
||||
),
|
||||
(
|
||||
"123",
|
||||
"CIUDAD OBREGON ADYACENTE AL AEROPUERTO DE CIUDAD OBREGON, CAJEME, SONORA.",
|
||||
),
|
||||
("140", "LA PAZ, LA PAZ, BAJA CALIFORNIA SUR."),
|
||||
("142", "SAN JOSE DEL CABO, LOS CABOS, BAJA CALIFORNIA SUR."),
|
||||
("143", "CABO SAN LUCAS, LOS CABOS, BAJA CALIFORNIA SUR."),
|
||||
@@ -25,7 +34,7 @@ seed = [
|
||||
("147", "PICHILINGÜE, LA PAZ, BAJA CALIFORNIA SUR."),
|
||||
("160", "MANZANILLO, MANZANILLO, COLIMA."),
|
||||
("161", "ARMERÍA, ARMERÍA, COLIMA."),
|
||||
("17", "AEROPUERTO INTERNACIONAL GENERAL SERVANDO CANALES, MATAMOROS, TAMAULIPAS."),
|
||||
("17", "AEROPUERTO INTERNACIONAL GENERAL SERVANDO CANALES, MATAMOROS, TAMAULIPAS."),
|
||||
("170", "MATAMOROS, MATAMOROS, TAMAULIPAS."),
|
||||
("171", "LUCIO BLANCO-LOS INDIOS, MATAMOROS, TAMAULIPAS."),
|
||||
("172", "SECCION ADUANERA FERROVIARIA DE MATAMOROS."),
|
||||
@@ -36,22 +45,31 @@ seed = [
|
||||
("192", "LOS ALGODONES, MEXICALI, BAJA CALIFORNIA."),
|
||||
("193", "SAN FELIPE, MEXICALI, BAJA CALIFORNIA."),
|
||||
("200", "MÉXICO, CIUDAD DE MÉXICO."),
|
||||
("202", "IMPORTACION Y EXPORTACION DE CONTENEDORES, DELEGACION AZCAPOTZALCO, CIUDAD DE MÉXICO."),
|
||||
(
|
||||
"202",
|
||||
"IMPORTACION Y EXPORTACION DE CONTENEDORES, DELEGACION AZCAPOTZALCO, CIUDAD DE MÉXICO.",
|
||||
),
|
||||
("220", "NACO, NACO, SONORA."),
|
||||
("230", "NOGALES, NOGALES, SONORA."),
|
||||
("231", "SASABE, SARIC, SONORA."),
|
||||
("24", "AEROPUERTO INTERNACIONAL DE NUEVO LAREDO „QUETZALCOATL“, NUEVO LAREDO, TAMAULIPAS."),
|
||||
(
|
||||
"24",
|
||||
"AEROPUERTO INTERNACIONAL DE NUEVO LAREDO „QUETZALCOATL“, NUEVO LAREDO, TAMAULIPAS.",
|
||||
),
|
||||
("240", "NUEVO LAREDO, NUEVO LAREDO, TAMAULIPAS."),
|
||||
("250", "OJINAGA, OJINAGA, CHIHUAHUA."),
|
||||
("260", "PUERTO PALOMAS, PUERTO PALOMAS, CHIHUAHUA."),
|
||||
("27", "RIO ESCONDIDO, NAVA, COAHUILA."),
|
||||
("27", "RIO ESCONDIDO, NAVA, COAHUILA."),
|
||||
("270", "PIEDRAS NEGRAS, PIEDRAS NEGRAS, COAHUILA."),
|
||||
("271", "AEROPUERTO INTERNACIONAL PLAN DE GUADALUPE, RAMOS ARIZPE, COAHUILA."),
|
||||
("280", "PROGRESO, PROGRESO, YUCATAN."),
|
||||
("282", "AEROPUERTO INTERNACIONAL LIC. MANUEL CRESCENCIO REJON, MERIDA, YUCATAN."),
|
||||
("300", "CIUDAD REYNOSA, CIUDAD REYNOSA, TAMAULIPAS."),
|
||||
("302", "LAS FLORES, RIO BRAVO, TAMAULIPAS."),
|
||||
("304", "AEROPUERTO INTERNACIONAL GENERAL. LUCIO BLANCO, CIUDAD REYNOSA, TAMAULIPAS."),
|
||||
(
|
||||
"304",
|
||||
"AEROPUERTO INTERNACIONAL GENERAL. LUCIO BLANCO, CIUDAD REYNOSA, TAMAULIPAS.",
|
||||
),
|
||||
("305", "RIO BRAVO-DONNA, RIO BRAVO, TAMAULIPAS."),
|
||||
("306", "ANZALDUAS, CIUDAD REYNOSA, TAMAULIPAS."),
|
||||
("310", "SALINA CRUZ, SALINA CRUZ, OAXACA."),
|
||||
@@ -59,7 +77,7 @@ seed = [
|
||||
("330", "SAN LUIS RIO COLORADO, SAN LUIS RIO COLORADO, SONORA."),
|
||||
("340", "CIUDAD MIGUEL ALEMAN, CIUDAD MIGUEL ALEMAN, TAMAULIPAS."),
|
||||
("342", "GUERRERO, GUERRERO, TAMAULIPAS."),
|
||||
("37", "AEROPUERTO INTERNACIONAL DE TAPACHULA, TAPACHULA, CHIAPAS."),
|
||||
("37", "AEROPUERTO INTERNACIONAL DE TAPACHULA, TAPACHULA, CHIAPAS."),
|
||||
("370", "CIUDAD HIDALGO, CIUDAD HIDALGO, CHIAPAS."),
|
||||
("372", "CIUDAD TALISMAN, TUXTLA CHICO, CHIAPAS."),
|
||||
("375", "PUERTO CHIAPAS, TAPACHULA, CHIAPAS."),
|
||||
@@ -67,27 +85,42 @@ seed = [
|
||||
("380", "TAMPICO, TAMPICO, TAMAULIPAS."),
|
||||
("390", "TECATE, TECATE, BAJA CALIFORNIA."),
|
||||
("400", "TIJUANA, TIJUANA, BAJA CALIFORNIA."),
|
||||
("402", "AEROPUERTO INTERNACIONAL GENERAL ABELARDO L. RODRIGUEZ, TIJUANA, BAJA CALIFORNIA."),
|
||||
(
|
||||
"402",
|
||||
"AEROPUERTO INTERNACIONAL GENERAL ABELARDO L. RODRIGUEZ, TIJUANA, BAJA CALIFORNIA.",
|
||||
),
|
||||
("420", "TUXPAN, TUXPAN DE RODRIGUEZ CANO, VERACRUZ."),
|
||||
("421", "TUXPAN, TUXPAN, VERACRUZ."),
|
||||
("430", "VERACRUZ, VERACRUZ, VERACRUZ."),
|
||||
("432", "AEROPUERTO INTERNACIONAL GENERAL HERIBERTO JARA CORONA, VERACRUZ, VERACRUZ."),
|
||||
(
|
||||
"432",
|
||||
"AEROPUERTO INTERNACIONAL GENERAL HERIBERTO JARA CORONA, VERACRUZ, VERACRUZ.",
|
||||
),
|
||||
("440", "CIUDAD ACUÑA, CIUDAD ACUÑA, COAHUILA."),
|
||||
("460", "TORREON, TORREON, COAHUILA."),
|
||||
("461", "AEROPUERTO DE TORREÓN, COAHUILA DE ZARAGOZA."),
|
||||
("462", "GOMEZ PALACIO, GOMEZ PALACIO, DURANGO."),
|
||||
("463", "AEROPUERTO INTERNACIONAL GENERAL GUADALUPE VICTORIA, DURANGO, DURANGO."),
|
||||
("470", "AEROPUERTO INTERNACIONAL DE LA CIUDAD DE MEXICO."),
|
||||
("471", "SATELITE, PARA IMPORTACION Y EXPORTACION POR VIA AEREA, AEROPUERTO INTERNACIONAL BENITO JUAREZ DE LA CIUDAD DE MEXICO."),
|
||||
("472", "CENTRO POSTAL MECANIZADO, POR VIA POSTAL Y POR TRAFICO AEREO, AEROPUERTO INTERNACIONAL BENITO JUAREZ DE LA CIUDAD DE MEXICO."),
|
||||
(
|
||||
"471",
|
||||
"SATELITE, PARA IMPORTACION Y EXPORTACION POR VIA AEREA, AEROPUERTO INTERNACIONAL BENITO JUAREZ DE LA CIUDAD DE MEXICO.",
|
||||
),
|
||||
(
|
||||
"472",
|
||||
"CENTRO POSTAL MECANIZADO, POR VIA POSTAL Y POR TRAFICO AEREO, AEROPUERTO INTERNACIONAL BENITO JUAREZ DE LA CIUDAD DE MEXICO.",
|
||||
),
|
||||
("480", "GUADALAJARA, TLACOMULCO DE ZUÑIGA, JALISCO."),
|
||||
("481", "PUERTO VALLARTA, PUERTO VALLARTA, JALISCO."),
|
||||
("484", "TERMINAL INTERMODAL FERROVIARIA, GUADALAJARA, JALISCO."),
|
||||
("50", "SONORA, PITIQUITO, SONORA."),
|
||||
("50", "SONORA, PITIQUITO, SONORA."),
|
||||
("500", "SONOYTA, SONOYTA, SONORA."),
|
||||
("501", "SAN EMETERIO, GENERAL PLUTARCO ELIAS CALLES, SONORA."),
|
||||
("510", "LAZARO CARDENAS, LAZARO CARDENAS, MICHOACAN."),
|
||||
("511", "AEROPUERTO INTERNACIONAL IXTAPA-ZIHUATANEJO, ZIHUATANEJO DE AZUETA, GUERRERO."),
|
||||
(
|
||||
"511",
|
||||
"AEROPUERTO INTERNACIONAL IXTAPA-ZIHUATANEJO, ZIHUATANEJO DE AZUETA, GUERRERO.",
|
||||
),
|
||||
("520", "MONTERREY, GENERAL MARIANO ESCOBEDO, NUEVO LEON."),
|
||||
("521", "AEROPUERTO INTERNACIONAL GENERAL MARIANO ESCOBEDO, APODACA, NUEVO LEON."),
|
||||
("523", "SALINAS VICTORIA A (TERMINAL FERROVIARIA), SALINAS VICTORIA, NUEVO LEON."),
|
||||
@@ -102,14 +135,23 @@ seed = [
|
||||
("651", "SAN CAYETANO MORELOS, TOLUCA, ESTADO DE MÉXICO"),
|
||||
("670", "CHIHUAHUA, CHIHUAHUA, CHIHUAHUA."),
|
||||
("671", "PARQUE INDUSTRIAL LAS AMERICAS, CHIHUAHUA, CHIHUAHUA."),
|
||||
("672", "AEROPUERTO INTERNACIONAL GENERAL ROBERTO FIERRO VILLALOBOS, CHIHUAHUA, CHIHUAHUA."),
|
||||
("73", "CHICALOTE, SAN FRANCISCO DE LOS ROMO, AGUASCALIENTES."),
|
||||
(
|
||||
"672",
|
||||
"AEROPUERTO INTERNACIONAL GENERAL ROBERTO FIERRO VILLALOBOS, CHIHUAHUA, CHIHUAHUA.",
|
||||
),
|
||||
("73", "CHICALOTE, SAN FRANCISCO DE LOS ROMO, AGUASCALIENTES."),
|
||||
("730", "AGUASCALIENTES, AGUASCALIENTES, AGUASCALIENTES."),
|
||||
("731", "PARQUE MULTIMODAL INTERPUERTO, SAN LUIS POTOSI, SAN LUIS POTOSI."),
|
||||
("732", "AEROPUERTO INTERNACIONAL GENERAL LEOBARDO C. RUIZ, EN CALERA ZACATECAS."),
|
||||
("733", "AEROPUERTO INTERNACIONAL PONCIANO ARRIAGA, SOLEDAD DE GRACIANO SANCHEZ, SAN LUIS POTOSI."),
|
||||
(
|
||||
"733",
|
||||
"AEROPUERTO INTERNACIONAL PONCIANO ARRIAGA, SOLEDAD DE GRACIANO SANCHEZ, SAN LUIS POTOSI.",
|
||||
),
|
||||
("734", "LA PILA-VILLA, VILLA DE REYES, SAN LUIS POTOSI."),
|
||||
("735", "AEROPUERTO INTERNACIONAL LIC. JESUS TERAN PEREDO, AGUASCALIENTES, AGUASCALIENTES."),
|
||||
(
|
||||
"735",
|
||||
"AEROPUERTO INTERNACIONAL LIC. JESUS TERAN PEREDO, AGUASCALIENTES, AGUASCALIENTES.",
|
||||
),
|
||||
("750", "PUEBLA, HEROICA PUEBLA DE ZARAGOZA, PUEBLA."),
|
||||
("751", "CUERNAVACA, JIUTEPEC, MORELOS."),
|
||||
("754", "AEROPUERTO INTERNACIONAL HERMANOS SERDAN, HUEJOTZINGO, PUEBLA."),
|
||||
@@ -117,9 +159,12 @@ seed = [
|
||||
("810", "ALTAMIRA, ALTAMIRA, TAMAULIPAS."),
|
||||
("820", "CIUDAD CAMARGO, CIUDAD CAMARGO, TAMAULIPAS."),
|
||||
("830", "DOS BOCAS, PARAISO, TABASCO."),
|
||||
("831", "AEROPUERTO INTERNACIONAL C.P.A. CARLOS ROVIROSA PEREZ, CIUDAD DE VILLAHERMOSA, CENTRO, TABASCO."),
|
||||
(
|
||||
"831",
|
||||
"AEROPUERTO INTERNACIONAL C.P.A. CARLOS ROVIROSA PEREZ, CIUDAD DE VILLAHERMOSA, CENTRO, TABASCO.",
|
||||
),
|
||||
("834", "EL CEIBO, TENOSIQUE, TABASCO."),
|
||||
("840", "GUANAJUATO, SILAO, GUANAJUATO."),
|
||||
("841", "CELAYA, CELAYA, GUANAJUATO."),
|
||||
("842", "AEROPUERTO INTERNACIONAL DE GUANAJUATO, SILAO, GUANAJUATO."),
|
||||
]
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_customs_sections(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,28 @@ def test_list_customs_sections(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_customs_section_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/customs-sections/invalid_code", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_customs_section_forbidden():
|
||||
response = client.post("/customs-sections/", json={"customs_code": "TST", "description": "Test"})
|
||||
response = client.post(
|
||||
"/customs-sections/", json={"customs_code": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_customs_section_forbidden():
|
||||
response = client.put("/customs-sections/TST", json={"customs_code": "TST", "description": "Test"})
|
||||
response = client.put(
|
||||
"/customs-sections/TST", json={"customs_code": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_customs_section_forbidden():
|
||||
response = client.delete("/customs-sections/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
|
||||
|
||||
class CustomsWarehouseDTO(BaseModel):
|
||||
key: str = Field(..., min_length=1, max_length=3)
|
||||
customs: str
|
||||
fiscalized_warehouse: str
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -2,16 +2,19 @@ from sqlalchemy import String, PrimaryKeyConstraint
|
||||
from sqlalchemy.orm import mapped_column, Mapped
|
||||
from core.database import Base
|
||||
|
||||
|
||||
class CustomsWarehouse(Base):
|
||||
__tablename__ = "customs_warehouses" #GRecintos
|
||||
__tablename__ = "customs_warehouses" # GRecintos
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("key", "customs", name="pk_customs_warehouse"),
|
||||
{"schema": "public"} # opcional
|
||||
{"schema": "public"}, # opcional
|
||||
)
|
||||
|
||||
key: Mapped[str] = mapped_column(String(3), nullable=False) # clave del recinto
|
||||
customs: Mapped[str] = mapped_column(String(100), nullable=False) # aduana asociada
|
||||
fiscalized_warehouse: Mapped[str] = mapped_column(String(1000)) # recintos fiscalizados (valor legal)
|
||||
key: Mapped[str] = mapped_column(String(3), nullable=False) # clave del recinto
|
||||
customs: Mapped[str] = mapped_column(String(100), nullable=False) # aduana asociada
|
||||
fiscalized_warehouse: Mapped[str] = mapped_column(
|
||||
String(1000)
|
||||
) # recintos fiscalizados (valor legal)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<CustomsWarehouse(key={self.key}, customs={self.customs}, fiscalized_warehouse={self.fiscalized_warehouse})>"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -16,7 +15,7 @@ def list_customs_warehouses(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(CustomsWarehouse)
|
||||
@@ -26,21 +25,32 @@ def list_customs_warehouses(
|
||||
"items": [CustomsWarehouseDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{key}/{customs}", response_model=CustomsWarehouseDTO)
|
||||
def get_customs_warehouse(key: str, customs: str, db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user)):
|
||||
obj = db.query(CustomsWarehouse).filter(CustomsWarehouse.key == key, CustomsWarehouse.customs == customs).first()
|
||||
def get_customs_warehouse(
|
||||
key: str,
|
||||
customs: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
obj = (
|
||||
db.query(CustomsWarehouse)
|
||||
.filter(CustomsWarehouse.key == key, CustomsWarehouse.customs == customs)
|
||||
.first()
|
||||
)
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return obj
|
||||
|
||||
|
||||
@router.post("/", response_model=CustomsWarehouseDTO, status_code=201)
|
||||
def create_customs_warehouse(
|
||||
data: CustomsWarehouseDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = CustomsWarehouse(**data.dict())
|
||||
db.add(obj)
|
||||
@@ -48,15 +58,20 @@ def create_customs_warehouse(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
@router.put("/{key}/{customs}", response_model=CustomsWarehouseDTO)
|
||||
def update_customs_warehouse(
|
||||
key: str,
|
||||
customs: str,
|
||||
data: CustomsWarehouseDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(CustomsWarehouse).filter(CustomsWarehouse.key == key, CustomsWarehouse.customs == customs).first()
|
||||
obj = (
|
||||
db.query(CustomsWarehouse)
|
||||
.filter(CustomsWarehouse.key == key, CustomsWarehouse.customs == customs)
|
||||
.first()
|
||||
)
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
for field, value in data.dict().items():
|
||||
@@ -65,14 +80,19 @@ def update_customs_warehouse(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
@router.delete("/{key}/{customs}", status_code=204)
|
||||
def delete_customs_warehouse(
|
||||
key: str,
|
||||
customs: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(CustomsWarehouse).filter(CustomsWarehouse.key == key, CustomsWarehouse.customs == customs).first()
|
||||
obj = (
|
||||
db.query(CustomsWarehouse)
|
||||
.filter(CustomsWarehouse.key == key, CustomsWarehouse.customs == customs)
|
||||
.first()
|
||||
)
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
db.delete(obj)
|
||||
|
||||
@@ -1,28 +1,68 @@
|
||||
seed = [
|
||||
("1 ", "Acapulco", "Administración Portuaria Integral de Acapulco, S.A. de C.V."),
|
||||
("10 ", "Aeropuerto Internacional de la Ciudad de México", "Cargo Service Center de México, S.A. de C.V."),
|
||||
("12 ", "Aeropuerto Internacional de la Ciudad de México", "DHL Express México, S.A. de C.V."),
|
||||
("14 ", "Aeropuerto Internacional de la Ciudad de México", "Lufthansa Cargo Servicios Logísticos de México, S.A. de C.V."),
|
||||
(
|
||||
"10 ",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"Cargo Service Center de México, S.A. de C.V.",
|
||||
),
|
||||
(
|
||||
"12 ",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"DHL Express México, S.A. de C.V.",
|
||||
),
|
||||
(
|
||||
"14 ",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"Lufthansa Cargo Servicios Logísticos de México, S.A. de C.V.",
|
||||
),
|
||||
("145", "México", "Ferrocarril y Terminal de Valle de México, S.A. de C.V."),
|
||||
("146", "Veracruz", "Cargill de México, S.A. de C.V."),
|
||||
("147", "Aeropuerto Internacional de la Ciudad de México", "Braniff Transport Carga, S.A. de C.V."),
|
||||
("148", "Nuevo Laredo", "Inspecciones Fitosanitarias y Aduaneras de Nuevo Laredo, S.A. de C.V."),
|
||||
(
|
||||
"147",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"Braniff Transport Carga, S.A. de C.V.",
|
||||
),
|
||||
(
|
||||
"148",
|
||||
"Nuevo Laredo",
|
||||
"Inspecciones Fitosanitarias y Aduaneras de Nuevo Laredo, S.A. de C.V.",
|
||||
),
|
||||
("149", "Nuevo Laredo", "PG Servicios de Logística, S.C."),
|
||||
("15 ", "Aeropuerto Internacional de la Ciudad de México", "Tramitadores Asociados de Aerocarga, S.A. de C.V."),
|
||||
(
|
||||
"15 ",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"Tramitadores Asociados de Aerocarga, S.A. de C.V.",
|
||||
),
|
||||
("150", "Piedras Negras", "Mercurio Cargo, S.A. de C.V."),
|
||||
("151", "Colombia", "S.R. Asesores Aduanales de Nuevo Laredo, S.C."),
|
||||
("154", "Monterrey", "Federal Express Holdings (México) y Compañía, S.N.C. de C.V."),
|
||||
(
|
||||
"154",
|
||||
"Monterrey",
|
||||
"Federal Express Holdings (México) y Compañía, S.N.C. de C.V.",
|
||||
),
|
||||
("155", "Ciudad Hidalgo", "Corporativo de Servicios del Sureste, S.A. de C.V."),
|
||||
("158", "Monterrey", "Aeropuerto de Monterrey, S.A. de C.V."),
|
||||
("16 ", "Aeropuerto Internacional de la Ciudad de México", "Transportación México Express, S.A. de C.V."),
|
||||
(
|
||||
"16 ",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"Transportación México Express, S.A. de C.V.",
|
||||
),
|
||||
("160", "Manzanillo", "Frigorífico de Manzanillo, S.A. de C.V."),
|
||||
("161", "Colombia", "Santos Esquivel y Compañía, S.C."),
|
||||
("162", "Guadalajara", "Ferrocarril Mexicano, S.A. de C.V."),
|
||||
("164", "Monterrey", "United Parcel Service de México, S.A. de C.V."),
|
||||
("165", "Aguascalientes", "Centros de Intercambio de Carga Express Estafeta, S.A. de C.V."),
|
||||
(
|
||||
"165",
|
||||
"Aguascalientes",
|
||||
"Centros de Intercambio de Carga Express Estafeta, S.A. de C.V.",
|
||||
),
|
||||
("166", "Altamira", "Administración Portuaria Integral de Altamira, S.A. de C.V."),
|
||||
("167", "Ciudad Juárez", "Accel, Recinto Fiscalizado, S.A. de C.V."),
|
||||
("17 ", "Aeropuerto Internacional de la Ciudad de México", "United Parcel Service de México, S.A. de C.V."),
|
||||
(
|
||||
"17 ",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"United Parcel Service de México, S.A. de C.V.",
|
||||
),
|
||||
("171", "Chihuahua", "Aeropuerto de Chihuahua, S.A. de C.V."),
|
||||
("172", "Veracruz", "Servicios Especiales Portuarios, S.A. de C.V."),
|
||||
("173", "Lázaro Cárdenas", "UTTSA, S.A. de C.V."),
|
||||
@@ -34,7 +74,11 @@ seed = [
|
||||
("179", "Altamira", "D.A. Hinojosa Terminal Multiusos, S.A. de C.V."),
|
||||
("18 ", "Aeropuerto Internacional de la Ciudad de México", "Varig de México, S.A."),
|
||||
("180", "Altamira", "Inmobiliaria Portuaria de Altamira, S.A. de C.V."),
|
||||
("182", "Veracruz", "Servicios, Maniobras y Almacenamientos de Veracruz, S.A. de C.V."),
|
||||
(
|
||||
"182",
|
||||
"Veracruz",
|
||||
"Servicios, Maniobras y Almacenamientos de Veracruz, S.A. de C.V.",
|
||||
),
|
||||
("184", "Progreso", "Terminal de Contenedores de Yucatán, S.A. de C.V."),
|
||||
("186", "Nuevo Laredo", "Logis Servicios Comerciales, S.A. de C.V."),
|
||||
("187", "Manzanillo", "Tecnoadministración del Pacífico, S.A. de C.V."),
|
||||
@@ -50,8 +94,16 @@ seed = [
|
||||
("203", "Altamira", "Grupo Castañeda, S.A. de C.V."),
|
||||
("204", "Monterrey", "Ferrocarril Mexicano, S.A. de C.V."),
|
||||
("210", "Querétaro", "Terminal Logistics, S.A. de C.V."),
|
||||
("211", "Aeropuerto Internacional de la Ciudad de México", "World Express Cargo de México, S.A. de C.V."),
|
||||
("212", "Piedras Negras", "Consultores de Logística en Comercio Exterior, S.A. de C.V."),
|
||||
(
|
||||
"211",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"World Express Cargo de México, S.A. de C.V.",
|
||||
),
|
||||
(
|
||||
"212",
|
||||
"Piedras Negras",
|
||||
"Consultores de Logística en Comercio Exterior, S.A. de C.V.",
|
||||
),
|
||||
("214", "Altamira", "Possehl México, S.A. de C.V."),
|
||||
("215", "Tampico", "Refitam, S.A. de C.V."),
|
||||
("217", "Veracruz", "SSA México, S.A. de C.V."),
|
||||
@@ -62,12 +114,20 @@ seed = [
|
||||
("222", "Matamoros", "Puerto Los Indios, S.A. de C.V."),
|
||||
("223", "Monterrey", "DHL Express México, S.A. de C.V."),
|
||||
("224", "Aguascalientes", "Nafta Rail, S.A. de C.V."),
|
||||
("225", "Altamira", "Integradora de Servicios, Transporte y Almacenaje, S.A. de C.V."),
|
||||
(
|
||||
"225",
|
||||
"Altamira",
|
||||
"Integradora de Servicios, Transporte y Almacenaje, S.A. de C.V.",
|
||||
),
|
||||
("226", "Nuevo Laredo", "DAF, Delivery After Frontier, S.A. de C.V."),
|
||||
("227", "Matamoros", "Profesionales Mexicanos del Comercio Exterior, S.C."),
|
||||
("228", "Guadalajara", "CLA Guadalajara, S.A. de C.V."),
|
||||
("229", "Manzanillo", "Maniobras Integradas del Puerto, S.A. de C.V."),
|
||||
("23 ", "Coatzacoalcos", "Administración Portuaria Integral de Coatzacoalcos, S.A. de C.V."),
|
||||
(
|
||||
"23 ",
|
||||
"Coatzacoalcos",
|
||||
"Administración Portuaria Integral de Coatzacoalcos, S.A. de C.V.",
|
||||
),
|
||||
("230", "Querétaro", "Terminal Intermodal Logística de Hidalgo, S.A.P.I. de C.V."),
|
||||
("231", "Lázaro Cárdenas", "Terminales Portuarias del Pacífico, S.A.P.I. de C.V."),
|
||||
("232", "Lázaro Cárdenas", "Arcelormittal Portuarios, S.A. de C.V."),
|
||||
@@ -83,34 +143,74 @@ seed = [
|
||||
("26 ", "Colombia", "Mex Securit, S.A. de C.V."),
|
||||
("27 ", "Ensenada", "Ensenada International Terminal, S.A. de C.V."),
|
||||
("28 ", "Guadalajara", "Almacenadora GWTC, S.A. de C.V."),
|
||||
("29 ", "Guadalajara", "Federal Express Holdings (México) y Compañía, S.N.C. de C.V."),
|
||||
("3 ", "Aeropuerto Internacional de la Ciudad de México", "Aerovías de México, S.A. de C.V."),
|
||||
(
|
||||
"29 ",
|
||||
"Guadalajara",
|
||||
"Federal Express Holdings (México) y Compañía, S.N.C. de C.V.",
|
||||
),
|
||||
(
|
||||
"3 ",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"Aerovías de México, S.A. de C.V.",
|
||||
),
|
||||
("30 ", "Guaymas", "Administración Portuaria Integral de Guaymas, S.A. de C.V."),
|
||||
("31 ", "Lázaro Cárdenas", "Administración Portuaria Integral de Lázaro Cárdenas, S.A. de C.V."),
|
||||
(
|
||||
"31 ",
|
||||
"Lázaro Cárdenas",
|
||||
"Administración Portuaria Integral de Lázaro Cárdenas, S.A. de C.V.",
|
||||
),
|
||||
("33 ", "Lázaro Cárdenas", "Aarhuskarlshamn México, S.A. de C.V."),
|
||||
("35 ", "Manzanillo", "Administración Portuaria Integral de Manzanillo, S.A. de C.V."),
|
||||
(
|
||||
"35 ",
|
||||
"Manzanillo",
|
||||
"Administración Portuaria Integral de Manzanillo, S.A. de C.V.",
|
||||
),
|
||||
("36 ", "Manzanillo", "Comercializadora La Junta, S.A. de C.V."),
|
||||
("38 ", "Manzanillo", "Operadora de la Cuenca del Pacífico, S.A. de C.V."),
|
||||
("39 ", "Manzanillo", "SSA México, S.A. de C.V."),
|
||||
("4 ", "Aeropuerto Internacional de la Ciudad de México", "AAACESA Almacenes Fiscalizados, S.A. de C.V."),
|
||||
(
|
||||
"4 ",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"AAACESA Almacenes Fiscalizados, S.A. de C.V.",
|
||||
),
|
||||
("40 ", "Manzanillo", "Terminal Internacional de Manzanillo, S.A. de C.V."),
|
||||
("42 ", "Mazatlán", "Administración Portuaria Integral de Mazatlán, S.A. de C.V."),
|
||||
("43 ", "Mazatlán", "Administración Portuaria Integral de Topolobampo, S.A. de C.V."),
|
||||
(
|
||||
"43 ",
|
||||
"Mazatlán",
|
||||
"Administración Portuaria Integral de Topolobampo, S.A. de C.V.",
|
||||
),
|
||||
("44 ", "Monterrey", "Braniff Air Freight and Company, S.A. de C.V."),
|
||||
("45 ", "Monterrey", "Kansas City Southern de México, S.A. de C.V."),
|
||||
("46 ", "Nogales", "Servicios de Almacén Fiscalizado de Nogales, S.A. de C.V."),
|
||||
("47 ", "Progreso", "Administración Portuaria Integral de Progreso, S.A. de C.V."),
|
||||
("49 ", "Progreso", "Grupo de Desarrollo del Sureste, S.A. de C.V."),
|
||||
("5 ", "Aeropuerto Internacional de la Ciudad de México", "México Cargo Handling, S.A. de C.V."),
|
||||
(
|
||||
"5 ",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"México Cargo Handling, S.A. de C.V.",
|
||||
),
|
||||
("50 ", "Progreso", "Multisur, S.A. de C.V."),
|
||||
("51 ", "Querétaro", "Servicios Integrales y Desarrollo GMG, S.A. de C.V."),
|
||||
("52 ", "Reynosa", "Recintos Fiscalizados de Noreste, S.A. de C.V."),
|
||||
("53 ", "Salina Cruz", "Administración Portuaria Integral de Salina Cruz, S.A. de C.V."),
|
||||
("54 ", "Cancún", "Administración Portuaria Integral de Quintana Roo, S.A. de C.V."),
|
||||
(
|
||||
"53 ",
|
||||
"Salina Cruz",
|
||||
"Administración Portuaria Integral de Salina Cruz, S.A. de C.V.",
|
||||
),
|
||||
(
|
||||
"54 ",
|
||||
"Cancún",
|
||||
"Administración Portuaria Integral de Quintana Roo, S.A. de C.V.",
|
||||
),
|
||||
("56 ", "Toluca", "Braniff Air Freight and Company, S.A. de C.V."),
|
||||
("57 ", "Toluca", "Federal Express Holdings (México) y Compañía, S.N.C. de C.V."),
|
||||
("59 ", "Tuxpan", "Administración Portuaria Integral de Tuxpan, S.A. de C.V."),
|
||||
("6 ", "Aeropuerto Internacional de la Ciudad de México", "American Airlines de México, S.A. de C.V."),
|
||||
(
|
||||
"6 ",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"American Airlines de México, S.A. de C.V.",
|
||||
),
|
||||
("60 ", "Tuxpan", "Fenoresinas, S.A. de C.V."),
|
||||
("61 ", "Tuxpan", "Terminal Marítima de Tuxpan, S.A. de C.V."),
|
||||
("62 ", "Tuxpan", "Terminales Marítimas Transunisa, S.A. de C.V."),
|
||||
@@ -118,8 +218,16 @@ seed = [
|
||||
("64 ", "Veracruz", "Almacenadora Golmex, S.A. de C.V."),
|
||||
("66 ", "Veracruz", "CIF Almacenajes y Servicios, S.A. de C.V."),
|
||||
("67 ", "Veracruz", "Corporación Integral de Comercio Exterior, S.A. de C.V."),
|
||||
("69 ", "Veracruz", "Internacional de Contenedores Asociados de Veracruz, S.A. de C.V."),
|
||||
("7 ", "Aeropuerto Internacional de la Ciudad de México", "Braniff Air Freight and Company, S.A. de C.V."),
|
||||
(
|
||||
"69 ",
|
||||
"Veracruz",
|
||||
"Internacional de Contenedores Asociados de Veracruz, S.A. de C.V.",
|
||||
),
|
||||
(
|
||||
"7 ",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"Braniff Air Freight and Company, S.A. de C.V.",
|
||||
),
|
||||
("71 ", "Veracruz", "Reparación Integral de Contenedores, S.A. de C.V."),
|
||||
("73 ", "Veracruz", "Terminales de Cargas Especializadas, S.A. de C.V."),
|
||||
("74 ", "Veracruz", "Vopak Terminals México, S.A. de C.V."),
|
||||
@@ -127,9 +235,17 @@ seed = [
|
||||
("76 ", "Manzanillo", "Cemex México, S.A. de C.V."),
|
||||
("77 ", "Manzanillo", "Corporación Multimodal, S.A. de C.V."),
|
||||
("78 ", "Ensenada", "Administración Portuaria Integral de Ensenada, S.A. de C.V."),
|
||||
("8 ", "Aeropuerto Internacional de la Ciudad de México", "Iberia de México, S.A."),
|
||||
(
|
||||
"8 ",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"Iberia de México, S.A.",
|
||||
),
|
||||
("81 ", "Tuxpan", "Frigoríficos Especializados de Tuxpan, S.A. de C.V."),
|
||||
("82 ", "Veracruz", "SSA México, S.A. de C.V."),
|
||||
("9 ", "Aeropuerto Internacional de la Ciudad de México", "Compañía Mexicana de Aviación, S.A. de C.V."),
|
||||
(
|
||||
"9 ",
|
||||
"Aeropuerto Internacional de la Ciudad de México",
|
||||
"Compañía Mexicana de Aviación, S.A. de C.V.",
|
||||
),
|
||||
("98 ", "Veracruz", "Corporación Portuaria de Veracruz, S.A. de C.V."),
|
||||
]
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_customs_warehouses(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,32 @@ def test_list_customs_warehouses(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_customs_warehouse_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/customs-warehouses/invalid_key/invalid_customs", headers=headers)
|
||||
response = client.get(
|
||||
"/customs-warehouses/invalid_key/invalid_customs", headers=headers
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_customs_warehouse_forbidden():
|
||||
response = client.post("/customs-warehouses/", json={"key": "TST", "customs": "TST", "description": "Test"})
|
||||
response = client.post(
|
||||
"/customs-warehouses/",
|
||||
json={"key": "TST", "customs": "TST", "description": "Test"},
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_customs_warehouse_forbidden():
|
||||
response = client.put("/customs-warehouses/TST/TST", json={"key": "TST", "customs": "TST", "description": "Test"})
|
||||
response = client.put(
|
||||
"/customs-warehouses/TST/TST",
|
||||
json={"key": "TST", "customs": "TST", "description": "Test"},
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_customs_warehouse_forbidden():
|
||||
response = client.delete("/customs-warehouses/TST/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
|
||||
|
||||
class IncotermDTO(BaseModel):
|
||||
code: str = Field(..., min_length=1, max_length=5)
|
||||
description_es: str
|
||||
|
||||
@@ -2,11 +2,12 @@ from sqlalchemy import String, PrimaryKeyConstraint
|
||||
from sqlalchemy.orm import mapped_column, Mapped
|
||||
from core.database import Base
|
||||
|
||||
|
||||
class Incoterm(Base):
|
||||
__tablename__ = "incoterms" #GIncoterm
|
||||
__tablename__ = "incoterms" # GIncoterm
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("code", name="incoterms_pkey"),
|
||||
{"schema": "public"}
|
||||
{"schema": "public"},
|
||||
)
|
||||
|
||||
code: Mapped[str] = mapped_column(String(5), nullable=False)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -11,13 +10,12 @@ from typing import Any, Dict
|
||||
router = APIRouter(prefix="/incoterms")
|
||||
|
||||
|
||||
|
||||
@router.get("/", response_model=Dict[str, Any])
|
||||
async def list_incoterms(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(Incoterm)
|
||||
@@ -27,23 +25,27 @@ async def list_incoterms(
|
||||
"items": [IncotermDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@router.get("/{key}", response_model=IncotermDTO)
|
||||
async def get_incoterm(key: str, db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user)):
|
||||
async def get_incoterm(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(Incoterm).filter(Incoterm.code == key).first()
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return IncotermDTO.model_validate(obj)
|
||||
|
||||
|
||||
|
||||
@router.post("/", response_model=IncotermDTO, status_code=201)
|
||||
async def create_incoterm(
|
||||
data: IncotermDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = Incoterm(**data.model_dump())
|
||||
db.add(obj)
|
||||
@@ -51,13 +53,13 @@ async def create_incoterm(
|
||||
db.refresh(obj)
|
||||
return IncotermDTO.model_validate(obj)
|
||||
|
||||
|
||||
|
||||
@router.put("/{key}", response_model=IncotermDTO)
|
||||
async def update_incoterm(
|
||||
key: str,
|
||||
data: IncotermDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(Incoterm).filter(Incoterm.code == key).first()
|
||||
if not obj:
|
||||
@@ -68,12 +70,12 @@ async def update_incoterm(
|
||||
db.refresh(obj)
|
||||
return IncotermDTO.model_validate(obj)
|
||||
|
||||
|
||||
|
||||
@router.delete("/{key}", status_code=204)
|
||||
async def delete_incoterm(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(Incoterm).filter(Incoterm.key == key).first()
|
||||
if not obj:
|
||||
|
||||
@@ -10,4 +10,4 @@ seed = [
|
||||
("FOB", "PUERTO DE EMBARQUE CONVENIDO", "FREE ON BOARD"),
|
||||
("CFR", "COSTO Y FLETE", "COST AND FREIGHT"),
|
||||
("CIF", "COSTO, SEGURO Y FLETE", "COST, INSURANCE AND FREIGHT"),
|
||||
]
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_incoterms(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,24 @@ def test_list_incoterms(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_incoterm_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/incoterms/invalid_key", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_incoterm_forbidden():
|
||||
response = client.post("/incoterms/", json={"key": "TST", "description": "Test"})
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_incoterm_forbidden():
|
||||
response = client.put("/incoterms/TST", json={"key": "TST", "description": "Test"})
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_incoterm_forbidden():
|
||||
response = client.delete("/incoterms/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -2,6 +2,7 @@ from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class InvoiceTypeDTO(BaseModel):
|
||||
key: str = Field(..., min_length=1, max_length=5)
|
||||
description: str
|
||||
|
||||
@@ -4,16 +4,20 @@ from core.database import Base
|
||||
|
||||
|
||||
class InvoiceType(Base):
|
||||
__tablename__ = "invoice_types" #GTiposFactura
|
||||
__tablename__ = "invoice_types" # GTiposFactura
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("key", name="invoice_types_pkey"),
|
||||
{"schema": "public"} # opcional
|
||||
{"schema": "public"}, # opcional
|
||||
)
|
||||
|
||||
key: Mapped[str] = mapped_column(String(5), nullable=False) # clave del tipo de factura
|
||||
description: Mapped[str] = mapped_column(String(50), nullable=False) # descripción oficial (en español)
|
||||
note: Mapped[str] = mapped_column(String(500)) # observación o comentario adicional
|
||||
type: Mapped[str] = mapped_column(String(15)) # tipo
|
||||
key: Mapped[str] = mapped_column(
|
||||
String(5), nullable=False
|
||||
) # clave del tipo de factura
|
||||
description: Mapped[str] = mapped_column(
|
||||
String(50), nullable=False
|
||||
) # descripción oficial (en español)
|
||||
note: Mapped[str] = mapped_column(String(500)) # observación o comentario adicional
|
||||
type: Mapped[str] = mapped_column(String(15)) # tipo
|
||||
|
||||
def __repr__(self):
|
||||
return f"<InvoiceType(key={self.key}, description={self.description}, origin_type={self.origin_type})>"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -16,7 +15,7 @@ def list_invoice_types(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(InvoiceType)
|
||||
@@ -26,21 +25,27 @@ def list_invoice_types(
|
||||
"items": [InvoiceTypeDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{key}", response_model=InvoiceTypeDTO)
|
||||
def get_invoice_type(key: str, db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user)):
|
||||
def get_invoice_type(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(InvoiceType).filter(InvoiceType.key == key).first()
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return InvoiceTypeDTO.model_validate(obj)
|
||||
|
||||
|
||||
@router.post("/", response_model=InvoiceTypeDTO, status_code=201)
|
||||
def create_invoice_type(
|
||||
data: InvoiceTypeDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = InvoiceType(**data.model_dump())
|
||||
db.add(obj)
|
||||
@@ -48,12 +53,13 @@ def create_invoice_type(
|
||||
db.refresh(obj)
|
||||
return InvoiceTypeDTO.model_validate(obj)
|
||||
|
||||
|
||||
@router.put("/{key}", response_model=InvoiceTypeDTO)
|
||||
def update_invoice_type(
|
||||
key: str,
|
||||
data: InvoiceTypeDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(InvoiceType).filter(InvoiceType.key == key).first()
|
||||
if not obj:
|
||||
@@ -64,11 +70,12 @@ def update_invoice_type(
|
||||
db.refresh(obj)
|
||||
return InvoiceTypeDTO.model_validate(obj)
|
||||
|
||||
|
||||
@router.delete("/{key}", status_code=204)
|
||||
def delete_invoice_type(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(InvoiceType).filter(InvoiceType.key == key).first()
|
||||
if not obj:
|
||||
|
||||
@@ -1,13 +1,38 @@
|
||||
seed = [
|
||||
("DONAC", "DONACION", "", "AMBOS"),
|
||||
("EXDEF", "EXPORTACION DEFINITIVA", "", "MATERIAL"),
|
||||
("MATDE", "MATERIA PRIMA O MATERIAL DEVUELTO", "ESTE PROCESO CONSISTE EN SOLO DESCARGAR LAS PARTES DADAS DE ALTA EN MATERIALES QUE SON RETORNADAS SIN NINGUNA MODIFICACION (A1)", "MATERIAL"),
|
||||
("NODES", "NO HACE DESCARGA", "ESTE PROCESO DE ACTUALIZACION CONSISTE EN EXPORTAR UNA MERCANCIA Y NO DESCARGAR, POR LO TANTO NO EXISTE REPORTE DE DESCARGAS Y NO AFECTA SALDOS.", "AMBOS"),
|
||||
("PTERM", "PRODUCTO TERMINADO Y VIRTUALES", "EL PRODUCTO TERMINADO Y VIRTUALES DESCARGARAN: 1) APARTIR DE LOS COMPONENTES DE CADA PRODUCTO TERMINADO REGISTRADO EN LAS PARTIDAS DE EXPORTACION. 2) POR PARTE, CON LAS OPCIONES DE PODER DESCARGAR POR SUSTITUTO Y POR CLASE EN CASO DE INSUFICIENCIAS DEL COMPONENTE.", "MATERIAL"),
|
||||
("REPAR", "REPARACION", "PROCESO QUE CONSISTE EN DOS ETAPAS: 1) DESCARGA EL PRODUCTO DE REPARACION QUE SE IMPORTO PARA REPARA, 2) DESCARGA EL LISTADO DE COMPONENTES QUE SE AGREGO AL PRODUCTO DE REPARACION", "MATERIAL"),
|
||||
(
|
||||
"MATDE",
|
||||
"MATERIA PRIMA O MATERIAL DEVUELTO",
|
||||
"ESTE PROCESO CONSISTE EN SOLO DESCARGAR LAS PARTES DADAS DE ALTA EN MATERIALES QUE SON RETORNADAS SIN NINGUNA MODIFICACION (A1)",
|
||||
"MATERIAL",
|
||||
),
|
||||
(
|
||||
"NODES",
|
||||
"NO HACE DESCARGA",
|
||||
"ESTE PROCESO DE ACTUALIZACION CONSISTE EN EXPORTAR UNA MERCANCIA Y NO DESCARGAR, POR LO TANTO NO EXISTE REPORTE DE DESCARGAS Y NO AFECTA SALDOS.",
|
||||
"AMBOS",
|
||||
),
|
||||
(
|
||||
"PTERM",
|
||||
"PRODUCTO TERMINADO Y VIRTUALES",
|
||||
"EL PRODUCTO TERMINADO Y VIRTUALES DESCARGARAN: 1) APARTIR DE LOS COMPONENTES DE CADA PRODUCTO TERMINADO REGISTRADO EN LAS PARTIDAS DE EXPORTACION. 2) POR PARTE, CON LAS OPCIONES DE PODER DESCARGAR POR SUSTITUTO Y POR CLASE EN CASO DE INSUFICIENCIAS DEL COMPONENTE.",
|
||||
"MATERIAL",
|
||||
),
|
||||
(
|
||||
"REPAR",
|
||||
"REPARACION",
|
||||
"PROCESO QUE CONSISTE EN DOS ETAPAS: 1) DESCARGA EL PRODUCTO DE REPARACION QUE SE IMPORTO PARA REPARA, 2) DESCARGA EL LISTADO DE COMPONENTES QUE SE AGREGO AL PRODUCTO DE REPARACION",
|
||||
"MATERIAL",
|
||||
),
|
||||
("SCRAP", "SCRAP", "", "AMBOS"),
|
||||
("VEMEX", "VENTAS EN MEXICO", "ESTE PROCESO CONSISTE EN LA VENTA EN EL MERCADO NACIONAL DE LOS PRODUCTOS.", "AMBOS"),
|
||||
("VIRTU", "VIRTUALES", "", "MATERIAL"),
|
||||
(
|
||||
"VEMEX",
|
||||
"VENTAS EN MEXICO",
|
||||
"ESTE PROCESO CONSISTE EN LA VENTA EN EL MERCADO NACIONAL DE LOS PRODUCTOS.",
|
||||
"AMBOS",
|
||||
),
|
||||
("VIRTU", "VIRTUALES", "", "MATERIAL"),
|
||||
("AFIJO", "ACTIVO FIJO", "", "ACTIVO FIJO"),
|
||||
("REEXP", "REEXPEDICION", "", "ACTIVO FIJO"),
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_invoice_types(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,28 @@ def test_list_invoice_types(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_invoice_type_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/invoice-types/invalid_key", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_invoice_type_forbidden():
|
||||
response = client.post("/invoice-types/", json={"key": "TST", "description": "Test"})
|
||||
response = client.post(
|
||||
"/invoice-types/", json={"key": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_invoice_type_forbidden():
|
||||
response = client.put("/invoice-types/TST", json={"key": "TST", "description": "Test"})
|
||||
response = client.put(
|
||||
"/invoice-types/TST", json={"key": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_invoice_type_forbidden():
|
||||
response = client.delete("/invoice-types/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
|
||||
|
||||
class MaterialTypeDTO(BaseModel):
|
||||
key: str = Field(..., min_length=1, max_length=10)
|
||||
type: str = Field(..., min_length=1, max_length=15)
|
||||
description: str
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -2,16 +2,19 @@ from sqlalchemy import String, PrimaryKeyConstraint
|
||||
from sqlalchemy.orm import mapped_column, Mapped
|
||||
from core.database import Base
|
||||
|
||||
|
||||
class MaterialType(Base):
|
||||
__tablename__ = "material_types" #STipoMat QTipoActFijo
|
||||
__tablename__ = "material_types" # STipoMat QTipoActFijo
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("key", name="material_types_pkey"),
|
||||
{"schema": "public"}
|
||||
{"schema": "public"},
|
||||
)
|
||||
|
||||
key: Mapped[str] = mapped_column(String(10), nullable=False) # clave del material
|
||||
type: Mapped[str] = mapped_column(String(15), nullable=False) # tipo
|
||||
description: Mapped[str] = mapped_column(String(256), nullable=False) # descripción oficial (en español)
|
||||
key: Mapped[str] = mapped_column(String(10), nullable=False) # clave del material
|
||||
type: Mapped[str] = mapped_column(String(15), nullable=False) # tipo
|
||||
description: Mapped[str] = mapped_column(
|
||||
String(256), nullable=False
|
||||
) # descripción oficial (en español)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<MaterialType(key={self.key}, type={self.type}, description={self.description})>"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -11,13 +10,12 @@ from typing import Any, Dict
|
||||
router = APIRouter(prefix="/material-types")
|
||||
|
||||
|
||||
|
||||
@router.get("/", response_model=Dict[str, Any])
|
||||
async def list_material_types(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(MaterialType)
|
||||
@@ -27,23 +25,27 @@ async def list_material_types(
|
||||
"items": [MaterialTypeDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@router.get("/{key}", response_model=MaterialTypeDTO)
|
||||
async def get_material_type(key: str, db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user)):
|
||||
async def get_material_type(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(MaterialType).filter(MaterialType.key == key).first()
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.post("/", response_model=MaterialTypeDTO, status_code=201)
|
||||
async def create_material_type(
|
||||
data: MaterialTypeDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = MaterialType(**data.dict())
|
||||
db.add(obj)
|
||||
@@ -51,13 +53,13 @@ async def create_material_type(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.put("/{key}", response_model=MaterialTypeDTO)
|
||||
async def update_material_type(
|
||||
key: str,
|
||||
data: MaterialTypeDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(MaterialType).filter(MaterialType.key == key).first()
|
||||
if not obj:
|
||||
@@ -68,12 +70,12 @@ async def update_material_type(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.delete("/{key}", status_code=204)
|
||||
async def delete_material_type(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(MaterialType).filter(MaterialType.key == key).first()
|
||||
if not obj:
|
||||
|
||||
@@ -32,5 +32,5 @@ seed = [
|
||||
("MAQEQ", "MAQUINARIA Y EQUIPO", "ACTIVO FIJO"),
|
||||
("MAQUI", "MAQUINARIA", "ACTIVO FIJO"),
|
||||
("REFAC", "REFACCIONES", "ACTIVO FIJO"),
|
||||
("TERR", "TERRRENOS" , "ACTIVO FIJO"),
|
||||
]
|
||||
("TERR", "TERRRENOS", "ACTIVO FIJO"),
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_material_types(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,28 @@ def test_list_material_types(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_material_type_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/material-types/invalid_key", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_material_type_forbidden():
|
||||
response = client.post("/material-types/", json={"key": "TST", "description": "Test"})
|
||||
response = client.post(
|
||||
"/material-types/", json={"key": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_material_type_forbidden():
|
||||
response = client.put("/material-types/TST", json={"key": "TST", "description": "Test"})
|
||||
response = client.put(
|
||||
"/material-types/TST", json={"key": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_material_type_forbidden():
|
||||
response = client.delete("/material-types/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
|
||||
|
||||
class PaymentMethodDTO(BaseModel):
|
||||
key: str = Field(..., min_length=1, max_length=2)
|
||||
description: str
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -2,11 +2,12 @@ from sqlalchemy import String, PrimaryKeyConstraint
|
||||
from sqlalchemy.orm import mapped_column, Mapped
|
||||
from core.database import Base
|
||||
|
||||
|
||||
class PaymentMethod(Base):
|
||||
__tablename__ = "payment_methods" #GFormaPago
|
||||
__tablename__ = "payment_methods" # GFormaPago
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("key", name="payment_methods_pkey"),
|
||||
{"schema": "public"} # opcional
|
||||
{"schema": "public"}, # opcional
|
||||
)
|
||||
|
||||
key: Mapped[str] = mapped_column(String(2), nullable=False)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -16,7 +15,7 @@ def list_payment_methods(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(PaymentMethod)
|
||||
@@ -26,21 +25,27 @@ def list_payment_methods(
|
||||
"items": [PaymentMethodDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{key}", response_model=PaymentMethodDTO)
|
||||
def get_payment_method(key: str, db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user)):
|
||||
def get_payment_method(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(PaymentMethod).filter(PaymentMethod.key == key).first()
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return obj
|
||||
|
||||
|
||||
@router.post("/", response_model=PaymentMethodDTO, status_code=201)
|
||||
def create_payment_method(
|
||||
data: PaymentMethodDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = PaymentMethod(**data.dict())
|
||||
db.add(obj)
|
||||
@@ -48,12 +53,13 @@ def create_payment_method(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
@router.put("/{key}", response_model=PaymentMethodDTO)
|
||||
def update_payment_method(
|
||||
key: str,
|
||||
data: PaymentMethodDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(PaymentMethod).filter(PaymentMethod.key == key).first()
|
||||
if not obj:
|
||||
@@ -64,11 +70,12 @@ def update_payment_method(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
@router.delete("/{key}", status_code=204)
|
||||
def delete_payment_method(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(PaymentMethod).filter(PaymentMethod.key == key).first()
|
||||
if not obj:
|
||||
|
||||
@@ -10,7 +10,10 @@ seed = [
|
||||
("18", "ESTIMULO FISCAL."),
|
||||
("19", "OTROS MEDIOS DE GARANTIA."),
|
||||
("2", "FIANZA."),
|
||||
("20", "DEROGADA. --- (PAGO CONFORME AL ARTICULO 7 DE LA LEY DE INGRESOS DE LA FEDERACION, VIGENTE)"),
|
||||
(
|
||||
"20",
|
||||
"DEROGADA. --- (PAGO CONFORME AL ARTICULO 7 DE LA LEY DE INGRESOS DE LA FEDERACION, VIGENTE)",
|
||||
),
|
||||
("21", "CRÉDITO EN IVA E IEPS."),
|
||||
("22", "GARANTÍA EN IVA E IEPS."),
|
||||
("4", "DEPOSITO EN CUENTA ADUANERA."),
|
||||
@@ -19,4 +22,4 @@ seed = [
|
||||
("7", "CARGO A PARTIDA PRESUPUESTAL GOBIERNO FEDERAL."),
|
||||
("8", "FRANQUICIA."),
|
||||
("9", "EXENTO DE PAGO."),
|
||||
]
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_payment_methods(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,28 @@ def test_list_payment_methods(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_payment_method_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/payment-methods/invalid_key", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_payment_method_forbidden():
|
||||
response = client.post("/payment-methods/", json={"key": "TST", "description": "Test"})
|
||||
response = client.post(
|
||||
"/payment-methods/", json={"key": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_payment_method_forbidden():
|
||||
response = client.put("/payment-methods/TST", json={"key": "TST", "description": "Test"})
|
||||
response = client.put(
|
||||
"/payment-methods/TST", json={"key": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_payment_method_forbidden():
|
||||
response = client.delete("/payment-methods/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -2,9 +2,9 @@ from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class PedimentoCodeDTO(BaseModel):
|
||||
code: str = Field(..., min_length=1, max_length=3)
|
||||
description: str
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -5,25 +5,23 @@ from core.database import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..code_pedimento_regimens.models import CodePedimentoRegimen
|
||||
|
||||
|
||||
|
||||
class PedimentoCode(Base):
|
||||
__tablename__ = "pedimento_codes" # GClavePed
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("code", name="pedimento_codes_pkey"),
|
||||
{"schema": "public"} # esquema del anexo 22
|
||||
{"schema": "public"}, # esquema del anexo 22
|
||||
)
|
||||
|
||||
code: Mapped[str] = mapped_column(String(3), nullable=False)
|
||||
code: Mapped[str] = mapped_column(String(3), nullable=False)
|
||||
description: Mapped[str] = mapped_column(String(250), nullable=False)
|
||||
|
||||
# Relación con los regímenes asociados
|
||||
#GClavePedRegimen
|
||||
regimens: Mapped[List['CodePedimentoRegimen']] = relationship(
|
||||
"CodePedimentoRegimen",
|
||||
uselist=True,
|
||||
back_populates="pedimento"
|
||||
# GClavePedRegimen
|
||||
regimens: Mapped[List["CodePedimentoRegimen"]] = relationship(
|
||||
"CodePedimentoRegimen", uselist=True, back_populates="pedimento"
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<PedimentoCode(code={self.code}, description={self.description})>"
|
||||
return f"<PedimentoCode(code={self.code}, description={self.description})>"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -16,7 +15,7 @@ def list_pedimento_codes(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(PedimentoCode)
|
||||
@@ -26,21 +25,27 @@ def list_pedimento_codes(
|
||||
"items": [PedimentoCodeDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{code}", response_model=PedimentoCodeDTO)
|
||||
def get_pedimento_code(code: str, db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user)):
|
||||
def get_pedimento_code(
|
||||
code: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(PedimentoCode).filter(PedimentoCode.code == code).first()
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return obj
|
||||
|
||||
|
||||
@router.post("/", response_model=PedimentoCodeDTO, status_code=201)
|
||||
def create_pedimento_code(
|
||||
data: PedimentoCodeDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = PedimentoCode(**data.dict())
|
||||
db.add(obj)
|
||||
@@ -48,12 +53,13 @@ def create_pedimento_code(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
@router.put("/{code}", response_model=PedimentoCodeDTO)
|
||||
def update_pedimento_code(
|
||||
code: str,
|
||||
data: PedimentoCodeDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(PedimentoCode).filter(PedimentoCode.code == code).first()
|
||||
if not obj:
|
||||
@@ -64,11 +70,12 @@ def update_pedimento_code(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
@router.delete("/{code}", status_code=204)
|
||||
def delete_pedimento_code(
|
||||
code: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(PedimentoCode).filter(PedimentoCode.code == code).first()
|
||||
if not obj:
|
||||
|
||||
@@ -3,27 +3,69 @@ seed = [
|
||||
("A3", "REGULARIZACION DE MERCANCIAS (IMPORTACION DEFINITIVA)."),
|
||||
("A4", "INTRODUCCION PARA DEPOSITO FISCAL (AGD)."),
|
||||
("A5", "INTRODUCCION A DEPOSITO FISCAL EN LOCAL AUTORIZADO."),
|
||||
("A6", "IMPORTACIÓN TEMPORAL DE BIENES DE ACTIVO FIJO POR PARTE DE EMPRESAS CON PITEX."),
|
||||
("AD", "IMPORTACIÓN TEMPORAL DE MERCANCIAS DESTINADAS A CONVENCIONES Y CONGRESOS INTERNACIONALES (ARTICULO 106, FRACCION III, INCISO A) DE LA LEY)."),
|
||||
(
|
||||
"A6",
|
||||
"IMPORTACIÓN TEMPORAL DE BIENES DE ACTIVO FIJO POR PARTE DE EMPRESAS CON PITEX.",
|
||||
),
|
||||
(
|
||||
"AD",
|
||||
"IMPORTACIÓN TEMPORAL DE MERCANCIAS DESTINADAS A CONVENCIONES Y CONGRESOS INTERNACIONALES (ARTICULO 106, FRACCION III, INCISO A) DE LA LEY).",
|
||||
),
|
||||
("AF", "IMPORTACION TEMPORAL DE BIENES DE ACTIVO FIJO (IMMEX)."),
|
||||
("AJ", "IMPORTACION Y EXPORTACION TEMPORAL DE ENVASES DE MERCANCIAS (ARTICULOS 106, FRACCION II, INCISO B) Y 116, FRACCION II, INCISO A) DE LA LEY)."),
|
||||
("BA", "IMPORTACION Y EXPORTACION TEMPORAL DE BIENES PARA SER RETORNADOS EN SU MISMO ESTADO. (ARTICULO 106, FRACCIONES II, INCISOS A) Y C), Y IV, INCISO B) DE LA LEY)."),
|
||||
(
|
||||
"AJ",
|
||||
"IMPORTACION Y EXPORTACION TEMPORAL DE ENVASES DE MERCANCIAS (ARTICULOS 106, FRACCION II, INCISO B) Y 116, FRACCION II, INCISO A) DE LA LEY).",
|
||||
),
|
||||
(
|
||||
"BA",
|
||||
"IMPORTACION Y EXPORTACION TEMPORAL DE BIENES PARA SER RETORNADOS EN SU MISMO ESTADO. (ARTICULO 106, FRACCIONES II, INCISOS A) Y C), Y IV, INCISO B) DE LA LEY).",
|
||||
),
|
||||
("BB", "EXPORTACION, IMPORTACION Y RETORNOS VIRTUALES."),
|
||||
("BC", "IMPORTACION Y EXPORTACION TEMPORAL DE MERCANCIAS DESTINADAS A EVENTOS CULTURALES O DEPORTIVOS (ARTICULO 106, FRACCION III, INCISO B DE LA LEY)."),
|
||||
("BD", "IMPORTACION Y EXPORTACION TEMPORAL DE EQUIPO PARA FILMACION (ARTICULOS 106, FRACCION III, INCISO C) Y 116, FRACCION II INCISO D) DE LA LEY)."),
|
||||
("BE", "IMPORTACION Y EXPORTACION TEMPORAL DE VEHICULOS DE PRUEBA (ARTICULO 106, FRACCION III, INCISO D) DE LA LEY)."),
|
||||
("BF", "EXPORTACION TEMPORAL DE MERCANCIAS DESTINADAS A EXPOSICIONES, CONVENCIONES O EVENTOS CULTURALES O DEPORTIVOS (ARTICULO 116, FRACCION III DE LA LEY)."),
|
||||
("BH", "IMPORTACION TEMPORAL DE CONTENEDORES, AVIONES, HELICOPTEROS, EMBARCACIONES Y CARROS DE FERROCARRIL (ARTICULO 106, FRACCION V, INCISOS A), B) Y E) DE LA LEY)."),
|
||||
(
|
||||
"BC",
|
||||
"IMPORTACION Y EXPORTACION TEMPORAL DE MERCANCIAS DESTINADAS A EVENTOS CULTURALES O DEPORTIVOS (ARTICULO 106, FRACCION III, INCISO B DE LA LEY).",
|
||||
),
|
||||
(
|
||||
"BD",
|
||||
"IMPORTACION Y EXPORTACION TEMPORAL DE EQUIPO PARA FILMACION (ARTICULOS 106, FRACCION III, INCISO C) Y 116, FRACCION II INCISO D) DE LA LEY).",
|
||||
),
|
||||
(
|
||||
"BE",
|
||||
"IMPORTACION Y EXPORTACION TEMPORAL DE VEHICULOS DE PRUEBA (ARTICULO 106, FRACCION III, INCISO D) DE LA LEY).",
|
||||
),
|
||||
(
|
||||
"BF",
|
||||
"EXPORTACION TEMPORAL DE MERCANCIAS DESTINADAS A EXPOSICIONES, CONVENCIONES O EVENTOS CULTURALES O DEPORTIVOS (ARTICULO 116, FRACCION III DE LA LEY).",
|
||||
),
|
||||
(
|
||||
"BH",
|
||||
"IMPORTACION TEMPORAL DE CONTENEDORES, AVIONES, HELICOPTEROS, EMBARCACIONES Y CARROS DE FERROCARRIL (ARTICULO 106, FRACCION V, INCISOS A), B) Y E) DE LA LEY).",
|
||||
),
|
||||
("BI", "IMPORTACION TEMPORAL (ARTICULO 106, FRACCION III, INCISO E) DE LA LEY)."),
|
||||
("BM", "EXPORTACION TEMPORAL DE MERCANCIAS PARA SU TRANSFORMACION, ELABORACION O REPARACION (ARTICULO 117 DE LA LEY)."),
|
||||
("BO", "EXPORTACION TEMPORAL PARA REPARACION O SUSTITUCION Y RETORNO AL PAIS (IMMEX, RFE U OPERADOR ECONOMICO AUTORIZADO."),
|
||||
("BP", "IMPORTACION Y EXPORTACION TEMPORAL DE MUESTRAS O MUESTRARIOS (ARTICULOS 106, FRACCION II, INCISO D) Y 116, FRACCION II, INCISO C) DE LA LEY)."),
|
||||
(
|
||||
"BM",
|
||||
"EXPORTACION TEMPORAL DE MERCANCIAS PARA SU TRANSFORMACION, ELABORACION O REPARACION (ARTICULO 117 DE LA LEY).",
|
||||
),
|
||||
(
|
||||
"BO",
|
||||
"EXPORTACION TEMPORAL PARA REPARACION O SUSTITUCION Y RETORNO AL PAIS (IMMEX, RFE U OPERADOR ECONOMICO AUTORIZADO.",
|
||||
),
|
||||
(
|
||||
"BP",
|
||||
"IMPORTACION Y EXPORTACION TEMPORAL DE MUESTRAS O MUESTRARIOS (ARTICULOS 106, FRACCION II, INCISO D) Y 116, FRACCION II, INCISO C) DE LA LEY).",
|
||||
),
|
||||
("BR", "EXPORTACION TEMPORAL Y RETORNO DE MERCANCIAS FUNGIBLES."),
|
||||
("C1", "IMPORTACION DEFINITIVA A LA FRANJA FRONTERIZA NORTE Y REGION FRONTERIZA AL AMPARO DEL „DECRETO DE LA FRANJA O REGION FRONTERIZA“ (DOF 24/12/2008 Y SUS POSTERIORES MODIFICACIONES)."),
|
||||
(
|
||||
"C1",
|
||||
"IMPORTACION DEFINITIVA A LA FRANJA FRONTERIZA NORTE Y REGION FRONTERIZA AL AMPARO DEL „DECRETO DE LA FRANJA O REGION FRONTERIZA“ (DOF 24/12/2008 Y SUS POSTERIORES MODIFICACIONES).",
|
||||
),
|
||||
("C3", "EXTRACCION DE DEPOSITO FISCAL DE FRANJA O REGION FRONTERIZA (AGD)."),
|
||||
("CT", "PEDIMENTO COMPLEMENTARIO."),
|
||||
("D1", "RETORNO POR SUSTITUCION."),
|
||||
("E1", "EXTRACCION DE DEPOSITO FISCAL DE BIENES QUE SERAN SUJETOS A TRANSFORMACION, ELABORACION O REPARACION (AGD)."),
|
||||
(
|
||||
"E1",
|
||||
"EXTRACCION DE DEPOSITO FISCAL DE BIENES QUE SERAN SUJETOS A TRANSFORMACION, ELABORACION O REPARACION (AGD).",
|
||||
),
|
||||
("E2", "EXTRACCION DE DEPOSITO FISCAL DE BIENES DE ACTIVO FIJO (AGD)."),
|
||||
("E3", "EXTRACCION DE DEPOSITO FISCAL EN LOCAL AUTORIZADO (INSUMOS)."),
|
||||
("E4", "EXTRACCION DE DEPOSITO FISCAL EN LOCAL AUTORIZADO (ACTIVO FIJO)."),
|
||||
@@ -31,49 +73,112 @@ seed = [
|
||||
("F3", "EXTRACCION DE DEPOSITO FISCAL (IA)."),
|
||||
("F4", "CAMBIO DE REGIMEN DE INSUMOS O DE MERCANCIA EXPORTADA TEMPORALMENTE."),
|
||||
("F5", "CAMBIO DE REGIMEN DE MERCANCÍAS DE IMPORTACIÓN TEMPORAL A DEFINITIVA."),
|
||||
("F8", "INTRODUCCION Y EXTRACCION DE DEPOSITO FISCAL DE MERCANCIAS NACIONALES O NACIONALIZADAS EN TIENDAS LIBRES DE IMPUESTOS (DUTY FREE)."),
|
||||
("F9", "INTRODUCCION Y EXTRACCION DE DEPOSITO FISCAL DE MERCANCIAS EXTRANJERAS PARA EXPOSICION Y VENTA DE MERCANCIAS EN TIENDAS LIBRES DE IMPUESTOS (DUTY FREE)."),
|
||||
(
|
||||
"F8",
|
||||
"INTRODUCCION Y EXTRACCION DE DEPOSITO FISCAL DE MERCANCIAS NACIONALES O NACIONALIZADAS EN TIENDAS LIBRES DE IMPUESTOS (DUTY FREE).",
|
||||
),
|
||||
(
|
||||
"F9",
|
||||
"INTRODUCCION Y EXTRACCION DE DEPOSITO FISCAL DE MERCANCIAS EXTRANJERAS PARA EXPOSICION Y VENTA DE MERCANCIAS EN TIENDAS LIBRES DE IMPUESTOS (DUTY FREE).",
|
||||
),
|
||||
("G1", "EXTRACCION DE DEPOSITO FISCAL (AGD)."),
|
||||
("G2", "EXTRACCION DE DEPOSITO FISCAL EN LOCAL AUTORIZADO PARA SU IMPORTACION DEFINITIVA."),
|
||||
("G6", "INFORME DE EXTRACCION DE DEPOSITO FISCAL DE MERCANCIAS NACIONALES O NACIONALIZADAS VENDIDAS EN TIENDAS LIBRES DE IMPUESTOS (DUTY FREE)."),
|
||||
("G7", "INFORME DE EXTRACCION DE DEPOSITO FISCAL DE MERCANCIAS EXTRANJERAS VENDIDAS EN TIENDAS LIBRES DE IMPUESTOS (DUTY FREE)."),
|
||||
(
|
||||
"G2",
|
||||
"EXTRACCION DE DEPOSITO FISCAL EN LOCAL AUTORIZADO PARA SU IMPORTACION DEFINITIVA.",
|
||||
),
|
||||
(
|
||||
"G6",
|
||||
"INFORME DE EXTRACCION DE DEPOSITO FISCAL DE MERCANCIAS NACIONALES O NACIONALIZADAS VENDIDAS EN TIENDAS LIBRES DE IMPUESTOS (DUTY FREE).",
|
||||
),
|
||||
(
|
||||
"G7",
|
||||
"INFORME DE EXTRACCION DE DEPOSITO FISCAL DE MERCANCIAS EXTRANJERAS VENDIDAS EN TIENDAS LIBRES DE IMPUESTOS (DUTY FREE).",
|
||||
),
|
||||
("G8", "REINCORPORAR AL MERCADO NACIONAL (RFE)."),
|
||||
("G9", "TRANSFERENCIA DE MERCANCÍAS DE RECINTO FISCALIZADO ESTRATEGICO NO COLINDANTE CON LA ADUANA (RETIRO VIRTUAL PARA IMPORTACIÓN DEFINTIVA POR RESIDENTES EN TERRITORIO NACIONAL)."),
|
||||
(
|
||||
"G9",
|
||||
"TRANSFERENCIA DE MERCANCÍAS DE RECINTO FISCALIZADO ESTRATEGICO NO COLINDANTE CON LA ADUANA (RETIRO VIRTUAL PARA IMPORTACIÓN DEFINTIVA POR RESIDENTES EN TERRITORIO NACIONAL).",
|
||||
),
|
||||
("GC", "GLOBAL COMPLEMENTARIO."),
|
||||
("H1", "RETORNO DE MERCANCIAS EN SU MISMO ESTADO."),
|
||||
("H8", "RETORNO DE ENVASES."),
|
||||
("I1", "IMPORTACION, EXPORTACION Y RETORNO DE MERCANCIAS ELABORADAS, TRANSFORMADAS O REPARADAS."),
|
||||
("IN", "IMPORTACION TEMPORAL DE BIENES QUE SERAN SUJETOS A TRANSFORMACION, ELABORACION O REPARACION (IMMEX)."),
|
||||
("J3", "RETORNO Y EXPORTACION DE INSUMOS ELABORADOS O TRANSFORMADOS EN RECINTO FISCALIZADO."),
|
||||
(
|
||||
"I1",
|
||||
"IMPORTACION, EXPORTACION Y RETORNO DE MERCANCIAS ELABORADAS, TRANSFORMADAS O REPARADAS.",
|
||||
),
|
||||
(
|
||||
"IN",
|
||||
"IMPORTACION TEMPORAL DE BIENES QUE SERAN SUJETOS A TRANSFORMACION, ELABORACION O REPARACION (IMMEX).",
|
||||
),
|
||||
(
|
||||
"J3",
|
||||
"RETORNO Y EXPORTACION DE INSUMOS ELABORADOS O TRANSFORMADOS EN RECINTO FISCALIZADO.",
|
||||
),
|
||||
("J4", "RETORNO DE MERCANCIAS EXTRANJERAS (RFE)."),
|
||||
("K1", "DESISTIMIENTO DE REGIMEN Y RETORNO DE MERCANCIAS POR DEVOLUCION."),
|
||||
("K2", "EXTRACCION DE DEPOSITO FISCAL POR DESISTIMIENTO O TRANSFERENCIAS (AGD)."),
|
||||
("K3", "EXTRACCION DE DEPOSITO FISCAL EN LOCAL AUTORIZADO PARA RETORNO O TRANSFERENCIA."),
|
||||
(
|
||||
"K3",
|
||||
"EXTRACCION DE DEPOSITO FISCAL EN LOCAL AUTORIZADO PARA RETORNO O TRANSFERENCIA.",
|
||||
),
|
||||
("L1", "PEQUEÑA IMPORTACION DEFINITIVA."),
|
||||
("M1", "INTRODUCCION Y EXPORTACION DE INSUMOS."),
|
||||
("M2", "INTRODUCCION Y EXPORTACION DE MAQUINARIA Y EQUIPO."),
|
||||
("M3", "INTRODUCCION DE MERCANCIAS (RFE)."),
|
||||
("M4", "INTRODUCCION DE ACTIVO FIJO (RFE)."),
|
||||
("M5", "INTRODUCCION DE MERCANCIA NACIONAL O NACIONALIZADA (RFE)."),
|
||||
("P1", "REEXPEDICION DE MERCANCIAS DE FRANJA FRONTERIZA O REGION FRONTERIZA AL INTERIOR DEL PAIS."),
|
||||
(
|
||||
"P1",
|
||||
"REEXPEDICION DE MERCANCIAS DE FRANJA FRONTERIZA O REGION FRONTERIZA AL INTERIOR DEL PAIS.",
|
||||
),
|
||||
("R1", "RECTIFICACION DE PEDIMENTOS."),
|
||||
("RT", "RETORNO DE MERCANCIAS (IMMEX)."),
|
||||
("S2", "IMPORTACION Y EXPORTACION DE MERCANCIAS PARA RETORNAR EN SU MISMO ESTADO (ARTICULO 86 DE LA LEY)."),
|
||||
(
|
||||
"S2",
|
||||
"IMPORTACION Y EXPORTACION DE MERCANCIAS PARA RETORNAR EN SU MISMO ESTADO (ARTICULO 86 DE LA LEY).",
|
||||
),
|
||||
("T1", "IMPORTACION Y EXPORTACION POR EMPRESAS DE MENSAJERIA."),
|
||||
("T3", "TRANSITO INTERNO."),
|
||||
("T6", "TRANSITO INTERNACIONAL POR TERRITORIO EXTRANJERO."),
|
||||
("T7", "TRANSITO INTERNACIONAL POR TERRITORIO NACIONAL."),
|
||||
("T9", "TRANSITO INTERNACIONAL DE TRANSMIGRANTES."),
|
||||
("V1", "TRANSFERENCIAS DE MERCANCIAS (IMPORTACION TEMPORAL VIRTUAL; INTRODUCCION VIRTUAL A DEPOSITO FISCAL O A RECINTO FISCALIZADO ESTRATEGICO; RETORNO VIRTUAL; EXPORTACION VIRTUAL DE PROVEEDORES NACIONALES)."),
|
||||
("V2", "TRANSFERENCIAS DE MERCANCIAS IMPORTADAS CON CUENTA ADUANERA (EXPORTACION E IMPORTACION VIRTUAL)."),
|
||||
("V3", "EXTRACCION DE DEPOSITO FISCAL DE BIENES PARA SU RETORNO O EXPORTACION VIRTUAL (IA)."),
|
||||
("V4", "RETORNO VIRTUAL DERIVADO DE LA CONSTANCIA DE TRANSFERENCIA DE MERCANCIAS (IA)."),
|
||||
("V5", "TRANSFERENCIAS DE MERCANCIAS DE EMPRESAS CERTIFICADAS (RETORNO VIRTUAL PARA IMPORTACION DEFINITIVA)."),
|
||||
("V6", "TRANSFERENCIAS DE MERCANCIAS SUJETAS A CUPO (IMPORTACION DEFINITIVA Y RETORNO VIRTUAL)."),
|
||||
("V7", "TRANSFERENCIAS DEL SECTOR AZUCARERO (EXPORTACION VIRTUAL E IMPORTACION TEMPORAL VIRTUAL)."),
|
||||
("V8", "TRANSFERENCIA DE MERCANCIAS EN DEPOSITO FISCAL PARA LA EXPOSICION Y VENTA DE MERCANCIAS EXTRANJERAS, NACIONALES Y NACIONALIZADAS DE TIENDAS LIBRES DE IMPUESTOS (DUTY FREE)."),
|
||||
(
|
||||
"V1",
|
||||
"TRANSFERENCIAS DE MERCANCIAS (IMPORTACION TEMPORAL VIRTUAL; INTRODUCCION VIRTUAL A DEPOSITO FISCAL O A RECINTO FISCALIZADO ESTRATEGICO; RETORNO VIRTUAL; EXPORTACION VIRTUAL DE PROVEEDORES NACIONALES).",
|
||||
),
|
||||
(
|
||||
"V2",
|
||||
"TRANSFERENCIAS DE MERCANCIAS IMPORTADAS CON CUENTA ADUANERA (EXPORTACION E IMPORTACION VIRTUAL).",
|
||||
),
|
||||
(
|
||||
"V3",
|
||||
"EXTRACCION DE DEPOSITO FISCAL DE BIENES PARA SU RETORNO O EXPORTACION VIRTUAL (IA).",
|
||||
),
|
||||
(
|
||||
"V4",
|
||||
"RETORNO VIRTUAL DERIVADO DE LA CONSTANCIA DE TRANSFERENCIA DE MERCANCIAS (IA).",
|
||||
),
|
||||
(
|
||||
"V5",
|
||||
"TRANSFERENCIAS DE MERCANCIAS DE EMPRESAS CERTIFICADAS (RETORNO VIRTUAL PARA IMPORTACION DEFINITIVA).",
|
||||
),
|
||||
(
|
||||
"V6",
|
||||
"TRANSFERENCIAS DE MERCANCIAS SUJETAS A CUPO (IMPORTACION DEFINITIVA Y RETORNO VIRTUAL).",
|
||||
),
|
||||
(
|
||||
"V7",
|
||||
"TRANSFERENCIAS DEL SECTOR AZUCARERO (EXPORTACION VIRTUAL E IMPORTACION TEMPORAL VIRTUAL).",
|
||||
),
|
||||
(
|
||||
"V8",
|
||||
"TRANSFERENCIA DE MERCANCIAS EN DEPOSITO FISCAL PARA LA EXPOSICION Y VENTA DE MERCANCIAS EXTRANJERAS, NACIONALES Y NACIONALIZADAS DE TIENDAS LIBRES DE IMPUESTOS (DUTY FREE).",
|
||||
),
|
||||
("V9", "TRANSFERENCIAS DE MERCANCIAS POR DONACION"),
|
||||
("VD", "VIRTUALES DIVERSOS."),
|
||||
("VF", "IMPORTACION DEFINITIVA DE VEHICULOS USADOS A LA FRANJA O REGION FRONTERIZA NORTE."),
|
||||
("VU", "IMPORTACION DEFINITIVA DE VEHICULOS USADOS.")
|
||||
]
|
||||
(
|
||||
"VF",
|
||||
"IMPORTACION DEFINITIVA DE VEHICULOS USADOS A LA FRANJA O REGION FRONTERIZA NORTE.",
|
||||
),
|
||||
("VU", "IMPORTACION DEFINITIVA DE VEHICULOS USADOS."),
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_pedimento_codes(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,28 @@ def test_list_pedimento_codes(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_pedimento_code_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/pedimento-codes/invalid_code", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_pedimento_code_forbidden():
|
||||
response = client.post("/pedimento-codes/", json={"code": "TST", "description": "Test"})
|
||||
response = client.post(
|
||||
"/pedimento-codes/", json={"code": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_pedimento_code_forbidden():
|
||||
response = client.put("/pedimento-codes/TST", json={"code": "TST", "description": "Test"})
|
||||
response = client.put(
|
||||
"/pedimento-codes/TST", json={"code": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_pedimento_code_forbidden():
|
||||
response = client.delete("/pedimento-codes/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -2,6 +2,7 @@ from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
from typing import List
|
||||
|
||||
|
||||
class RegimenPedimentoDTO(BaseModel):
|
||||
code: str = Field(..., min_length=1, max_length=3)
|
||||
description: str
|
||||
|
||||
@@ -6,22 +6,25 @@ from core.database import Base
|
||||
if TYPE_CHECKING:
|
||||
from ..code_pedimento_regimens.models import CodePedimentoRegimen
|
||||
|
||||
|
||||
class RegimenPedimento(Base):
|
||||
__tablename__ = "pedimento_regimens" #GRegimenPed
|
||||
__tablename__ = "pedimento_regimens" # GRegimenPed
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("code", name="pedimento_regimens_pkey"),
|
||||
{"schema": "public"}
|
||||
{"schema": "public"},
|
||||
)
|
||||
|
||||
code: Mapped[str] = mapped_column(String(3), nullable=False) # código tipo "01", "31"
|
||||
description: Mapped[str] = mapped_column(String(100), nullable=False) # nombre legal en español
|
||||
code: Mapped[str] = mapped_column(
|
||||
String(3), nullable=False
|
||||
) # código tipo "01", "31"
|
||||
description: Mapped[str] = mapped_column(
|
||||
String(100), nullable=False
|
||||
) # nombre legal en español
|
||||
|
||||
# Relación con Claves de Pedimento
|
||||
#GClavePedRegimen
|
||||
claves_pedimento: Mapped[List['CodePedimentoRegimen']] = relationship(
|
||||
"CodePedimentoRegimen",
|
||||
uselist=True,
|
||||
back_populates="regimen"
|
||||
# GClavePedRegimen
|
||||
claves_pedimento: Mapped[List["CodePedimentoRegimen"]] = relationship(
|
||||
"CodePedimentoRegimen", uselist=True, back_populates="regimen"
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -16,7 +15,7 @@ def list_pedimento_regimens(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(RegimenPedimento)
|
||||
@@ -26,21 +25,27 @@ def list_pedimento_regimens(
|
||||
"items": [RegimenPedimentoDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{key}", response_model=RegimenPedimentoDTO)
|
||||
def get_pedimento_regimen(key: str, db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user)):
|
||||
def get_pedimento_regimen(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(RegimenPedimento).filter(RegimenPedimento.code == key).first()
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return RegimenPedimentoDTO.model_validate(obj)
|
||||
|
||||
|
||||
@router.post("/", response_model=RegimenPedimentoDTO, status_code=201)
|
||||
def create_pedimento_regimen(
|
||||
data: RegimenPedimentoDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = RegimenPedimento(**data.model_dump())
|
||||
db.add(obj)
|
||||
@@ -48,12 +53,13 @@ def create_pedimento_regimen(
|
||||
db.refresh(obj)
|
||||
return RegimenPedimentoDTO.model_validate(obj)
|
||||
|
||||
|
||||
@router.put("/{key}", response_model=RegimenPedimentoDTO)
|
||||
def update_pedimento_regimen(
|
||||
key: str,
|
||||
data: RegimenPedimentoDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(RegimenPedimento).filter(RegimenPedimento.code == key).first()
|
||||
if not obj:
|
||||
@@ -64,11 +70,12 @@ def update_pedimento_regimen(
|
||||
db.refresh(obj)
|
||||
return RegimenPedimentoDTO.model_validate(obj)
|
||||
|
||||
|
||||
@router.delete("/{key}", status_code=204)
|
||||
def delete_pedimento_regimen(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(RegimenPedimento).filter(RegimenPedimento.code == key).first()
|
||||
if not obj:
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
seed = [
|
||||
("DFI", "DEPOSITO FISCAL."),
|
||||
("ETE", "TEMPORALES DE EXPORTACION PARA ELABORACION, TRANSFORMACION O REPARACION."),
|
||||
("ETR", "TEMPORALES DE EXPORTACION PARA RETORNAR AL PAIS EN EL MISMO ESTADO."),
|
||||
("EXD", "DEFINITIVO DE EXPORTACIÓN."),
|
||||
("IMD", "DEFINITIVO DE IMPORTACIÓN."),
|
||||
("ITE", "TEMPORALES DE IMPORTACION PARA ELABORACION, TRANSFORMACION O REPARACION PARA EMPRESAS CON PROGRAMA I"),
|
||||
("ITR", "TEMPORALES DE IMPORTACION PARA RETORNAR AL EXTRANJERO EN EL MISMO ESTADO."),
|
||||
("RFE", "ELABORACION, TRANSFORMACION O REPARACION EN RECINTO FISCALIZADO."),
|
||||
("RFS", "RECINTO FISCALIZADO ESTRATEGICO."),
|
||||
("TRA", "TRANSITOS.")
|
||||
]
|
||||
("DFI", "DEPOSITO FISCAL."),
|
||||
("ETE", "TEMPORALES DE EXPORTACION PARA ELABORACION, TRANSFORMACION O REPARACION."),
|
||||
("ETR", "TEMPORALES DE EXPORTACION PARA RETORNAR AL PAIS EN EL MISMO ESTADO."),
|
||||
("EXD", "DEFINITIVO DE EXPORTACIÓN."),
|
||||
("IMD", "DEFINITIVO DE IMPORTACIÓN."),
|
||||
(
|
||||
"ITE",
|
||||
"TEMPORALES DE IMPORTACION PARA ELABORACION, TRANSFORMACION O REPARACION PARA EMPRESAS CON PROGRAMA I",
|
||||
),
|
||||
(
|
||||
"ITR",
|
||||
"TEMPORALES DE IMPORTACION PARA RETORNAR AL EXTRANJERO EN EL MISMO ESTADO.",
|
||||
),
|
||||
("RFE", "ELABORACION, TRANSFORMACION O REPARACION EN RECINTO FISCALIZADO."),
|
||||
("RFS", "RECINTO FISCALIZADO ESTRATEGICO."),
|
||||
("TRA", "TRANSITOS."),
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_pedimento_regimens(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,28 @@ def test_list_pedimento_regimens(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_pedimento_regimen_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/pedimento-regimens/invalid_key", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_pedimento_regimen_forbidden():
|
||||
response = client.post("/pedimento-regimens/", json={"code": "TST", "description": "Test"})
|
||||
response = client.post(
|
||||
"/pedimento-regimens/", json={"code": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_pedimento_regimen_forbidden():
|
||||
response = client.put("/pedimento-regimens/TST", json={"code": "TST", "description": "Test"})
|
||||
response = client.put(
|
||||
"/pedimento-regimens/TST", json={"code": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_pedimento_regimen_forbidden():
|
||||
response = client.delete("/pedimento-regimens/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Router principal de API v1
|
||||
Agrega todos los módulos de la aplicación
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from .pedimento_codes.routes import router as pedimento_codes_router
|
||||
@@ -26,20 +27,86 @@ from .incoterms.routes import router as incoterms_router
|
||||
router = APIRouter()
|
||||
|
||||
# Registrar módulos
|
||||
router.include_router(pedimento_codes_router, prefix="/refrence_data", tags=["public / refrence_data / pedimento_codes"])
|
||||
router.include_router(payment_methods_router, prefix="/refrence_data", tags=["public / refrence_data / payment_methods"])
|
||||
router.include_router(containers_router, prefix="/refrence_data", tags=["public / refrence_data / containers"])
|
||||
router.include_router(countries_router, prefix="/refrence_data", tags=["public / refrence_data / countries"])
|
||||
router.include_router(material_types_router, prefix="/refrence_data", tags=["public / refrence_data / material_types"])
|
||||
router.include_router(currency_types_router, prefix="/refrence_data", tags=["public / refrence_data / currency_types"])
|
||||
router.include_router(states_router, prefix="/refrence_data", tags=["public / refrence_data / states"])
|
||||
router.include_router(transport_types_router, prefix="/refrence_data", tags=["public / refrence_data / transport_types"])
|
||||
router.include_router(customs_warehouses_router, prefix="/refrence_data", tags=["public / refrence_data / customs_warehouses"])
|
||||
router.include_router(valuation_methods_router, prefix="/refrence_data", tags=["public / refrence_data / valuation_methods"])
|
||||
router.include_router(sectors_router, prefix="/refrence_data", tags=["public / public / refrence_data / sectors"])
|
||||
router.include_router(transport_modes_router, prefix="/refrence_data", tags=["public / refrence_data / transport_modes"])
|
||||
router.include_router(customs_sections_router, prefix="/refrence_data", tags=["public / refrence_data / customs_sections"])
|
||||
router.include_router(invoice_types_router, prefix="/refrence_data", tags=["public / refrence_data / invoice_types"])
|
||||
router.include_router(code_pedimento_regimens_router, prefix="/refrence_data", tags=["public / refrence_data / code_pedimento_regimens"])
|
||||
router.include_router(pedimento_regimens_router, prefix="/refrence_data", tags=["public / refrence_data / pedimento_regimens"])
|
||||
router.include_router(incoterms_router, prefix="/refrence_data", tags=["public / refrence_data / incoterms"])
|
||||
router.include_router(
|
||||
pedimento_codes_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / pedimento_codes"],
|
||||
)
|
||||
router.include_router(
|
||||
payment_methods_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / payment_methods"],
|
||||
)
|
||||
router.include_router(
|
||||
containers_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / containers"],
|
||||
)
|
||||
router.include_router(
|
||||
countries_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / countries"],
|
||||
)
|
||||
router.include_router(
|
||||
material_types_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / material_types"],
|
||||
)
|
||||
router.include_router(
|
||||
currency_types_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / currency_types"],
|
||||
)
|
||||
router.include_router(
|
||||
states_router, prefix="/refrence_data", tags=["public / refrence_data / states"]
|
||||
)
|
||||
router.include_router(
|
||||
transport_types_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / transport_types"],
|
||||
)
|
||||
router.include_router(
|
||||
customs_warehouses_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / customs_warehouses"],
|
||||
)
|
||||
router.include_router(
|
||||
valuation_methods_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / valuation_methods"],
|
||||
)
|
||||
router.include_router(
|
||||
sectors_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / public / refrence_data / sectors"],
|
||||
)
|
||||
router.include_router(
|
||||
transport_modes_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / transport_modes"],
|
||||
)
|
||||
router.include_router(
|
||||
customs_sections_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / customs_sections"],
|
||||
)
|
||||
router.include_router(
|
||||
invoice_types_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / invoice_types"],
|
||||
)
|
||||
router.include_router(
|
||||
code_pedimento_regimens_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / code_pedimento_regimens"],
|
||||
)
|
||||
router.include_router(
|
||||
pedimento_regimens_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / pedimento_regimens"],
|
||||
)
|
||||
router.include_router(
|
||||
incoterms_router,
|
||||
prefix="/refrence_data",
|
||||
tags=["public / refrence_data / incoterms"],
|
||||
)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
|
||||
|
||||
class SectorDTO(BaseModel):
|
||||
key: str = Field(..., min_length=1, max_length=8)
|
||||
description: str
|
||||
authorized: int
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -2,16 +2,21 @@ from sqlalchemy import String, SmallInteger, PrimaryKeyConstraint
|
||||
from sqlalchemy.orm import mapped_column, Mapped
|
||||
from core.database import Base
|
||||
|
||||
|
||||
class Sector(Base):
|
||||
__tablename__ = "sectors" #GSectores
|
||||
__tablename__ = "sectors" # GSectores
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("key", name="sectors_pkey"),
|
||||
{"schema": "public"} # opcional
|
||||
{"schema": "public"}, # 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[SmallInteger] = mapped_column(SmallInteger) # 1 = autorizado, 0 = no autorizado
|
||||
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[SmallInteger] = mapped_column(
|
||||
SmallInteger
|
||||
) # 1 = autorizado, 0 = no autorizado
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Sector(key={self.key}, description={self.description}, authorized={self.authorized})>"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -16,7 +15,7 @@ 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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(Sector)
|
||||
@@ -26,21 +25,27 @@ def list_sectors(
|
||||
"items": [SectorDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"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)):
|
||||
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
|
||||
|
||||
|
||||
@router.post("/", response_model=SectorDTO, status_code=201)
|
||||
def create_sector(
|
||||
data: SectorDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = Sector(**data.dict())
|
||||
db.add(obj)
|
||||
@@ -48,12 +53,13 @@ def create_sector(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
@router.put("/{key}", response_model=SectorDTO)
|
||||
def update_sector(
|
||||
key: str,
|
||||
data: SectorDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(Sector).filter(Sector.key == key).first()
|
||||
if not obj:
|
||||
@@ -64,11 +70,12 @@ def update_sector(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
@router.delete("/{key}", status_code=204)
|
||||
def delete_sector(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(Sector).filter(Sector.key == key).first()
|
||||
if not obj:
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
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"),
|
||||
(
|
||||
"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"),
|
||||
@@ -18,9 +26,21 @@ seed = [
|
||||
("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"),
|
||||
(
|
||||
"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"),
|
||||
@@ -32,4 +52,4 @@ seed = [
|
||||
("XXe", "INDUSTRIA TEXTIL Y DE LA CONFECCION", "0"),
|
||||
("XXI", "INDUSTRIA DE CHOCOLATES, DULCES Y SIMILARES", "0"),
|
||||
("XXII", "INDUSTRIA DEL CAFE", "0"),
|
||||
]
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ 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}"}
|
||||
@@ -16,20 +17,24 @@ def test_list_sectors(client, access_token):
|
||||
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)
|
||||
|
||||
@@ -2,6 +2,7 @@ from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class StateDTO(BaseModel):
|
||||
m3_key: str = Field(..., min_length=1, max_length=3)
|
||||
description: str
|
||||
@@ -9,4 +10,3 @@ class StateDTO(BaseModel):
|
||||
ame_key: Optional[str] = None
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -3,15 +3,18 @@ from sqlalchemy import String, PrimaryKeyConstraint
|
||||
from sqlalchemy.orm import mapped_column, Mapped
|
||||
from core.database import Base
|
||||
|
||||
|
||||
class State(Base):
|
||||
__tablename__ = "states" #GEstados
|
||||
__tablename__ = "states" # GEstados
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint('m3_key', 'description', name='states_pkey'),
|
||||
{"schema": "public"}
|
||||
PrimaryKeyConstraint("m3_key", "description", name="states_pkey"),
|
||||
{"schema": "public"},
|
||||
)
|
||||
|
||||
m3_key: Mapped[str] = mapped_column(String(3), nullable=False)
|
||||
description: Mapped[str] = mapped_column(String(50), nullable=False) # valor legal en español
|
||||
description: Mapped[str] = mapped_column(
|
||||
String(50), nullable=False
|
||||
) # valor legal en español
|
||||
mex_key: Mapped[Optional[str]] = mapped_column(String(3))
|
||||
ame_key: Mapped[Optional[str]] = mapped_column(String(2))
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -11,13 +10,12 @@ from typing import Any, Dict
|
||||
router = APIRouter(prefix="/states")
|
||||
|
||||
|
||||
|
||||
@router.get("/", response_model=Dict[str, Any])
|
||||
async def list_states(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(State)
|
||||
@@ -27,23 +25,27 @@ async def list_states(
|
||||
"items": [StateDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@router.get("/{m3_key}", response_model=StateDTO)
|
||||
async def get_state(m3_key: str, db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user)):
|
||||
async def get_state(
|
||||
m3_key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(State).filter(State.m3_key == m3_key).first()
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.post("/", response_model=StateDTO, status_code=201)
|
||||
async def create_state(
|
||||
data: StateDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
|
||||
obj = State(**data.dict())
|
||||
@@ -52,13 +54,13 @@ async def create_state(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.put("/{m3_key}", response_model=StateDTO)
|
||||
async def update_state(
|
||||
m3_key: str,
|
||||
data: StateDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
|
||||
obj = db.query(State).filter(State.m3_key == m3_key).first()
|
||||
@@ -70,12 +72,12 @@ async def update_state(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.delete("/{m3_key}", status_code=204)
|
||||
async def delete_state(
|
||||
m3_key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
|
||||
obj = db.query(State).filter(State.m3_key == m3_key).first()
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
seed = [
|
||||
|
||||
]
|
||||
seed = []
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_states(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,24 @@ def test_list_states(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_state_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/states/invalid_key", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_state_forbidden():
|
||||
response = client.post("/states/", json={"key": "TST", "description": "Test"})
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_state_forbidden():
|
||||
response = client.put("/states/TST", json={"key": "TST", "description": "Test"})
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_state_forbidden():
|
||||
response = client.delete("/states/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
|
||||
|
||||
class TransportModeDTO(BaseModel):
|
||||
key: str = Field(..., min_length=1, max_length=3)
|
||||
name: str
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -2,14 +2,15 @@ from sqlalchemy import String, PrimaryKeyConstraint
|
||||
from sqlalchemy.orm import mapped_column, Mapped
|
||||
from core.database import Base
|
||||
|
||||
|
||||
class TransportMode(Base):
|
||||
__tablename__ = "transport_modes" #GModTransporte
|
||||
__tablename__ = "transport_modes" # GModTransporte
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("key", name="transport_modes_pkey"),
|
||||
{"schema": "public"} # opcional
|
||||
{"schema": "public"}, # opcional
|
||||
)
|
||||
|
||||
key: Mapped[str] = mapped_column(String(3), nullable=False)
|
||||
key: Mapped[str] = mapped_column(String(3), nullable=False)
|
||||
name: Mapped[str] = mapped_column(String(30), nullable=False)
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -11,12 +10,11 @@ from typing import Any, Dict
|
||||
router = APIRouter(prefix="/transport-modes")
|
||||
|
||||
|
||||
|
||||
@router.get("/", response_model=Dict[str, Any])
|
||||
async def list_transport_modes(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db)
|
||||
db: Session = Depends(get_core_db),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(TransportMode)
|
||||
@@ -26,10 +24,10 @@ async def list_transport_modes(
|
||||
"items": [TransportModeDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@router.get("/{key}", response_model=TransportModeDTO)
|
||||
async def get_transport_mode(key: str, db: Session = Depends(get_core_db)):
|
||||
obj = db.query(TransportMode).filter(TransportMode.key == key).first()
|
||||
@@ -37,12 +35,12 @@ async def get_transport_mode(key: str, db: Session = Depends(get_core_db)):
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.post("/", response_model=TransportModeDTO, status_code=201)
|
||||
async def create_transport_mode(
|
||||
data: TransportModeDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
user=Depends(get_current_user)
|
||||
user=Depends(get_current_user),
|
||||
):
|
||||
obj = TransportMode(**data.dict())
|
||||
db.add(obj)
|
||||
@@ -50,13 +48,13 @@ async def create_transport_mode(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.put("/{key}", response_model=TransportModeDTO)
|
||||
async def update_transport_mode(
|
||||
key: str,
|
||||
data: TransportModeDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
user=Depends(get_current_user)
|
||||
user=Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(TransportMode).filter(TransportMode.key == key).first()
|
||||
if not obj:
|
||||
@@ -67,12 +65,10 @@ async def update_transport_mode(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.delete("/{key}", status_code=204)
|
||||
async def delete_transport_mode(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
user=Depends(get_current_user)
|
||||
key: str, db: Session = Depends(get_core_db), user=Depends(get_current_user)
|
||||
):
|
||||
obj = db.query(TransportMode).filter(TransportMode.key == key).first()
|
||||
if not obj:
|
||||
|
||||
@@ -9,4 +9,4 @@ seed = [
|
||||
("40", "AIR"),
|
||||
("41", "AIR CONTAINER"),
|
||||
("50", "MAIL"),
|
||||
]
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_transport_modes(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,28 @@ def test_list_transport_modes(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_transport_mode_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/transport-modes/invalid_key", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_transport_mode_forbidden():
|
||||
response = client.post("/transport-modes/", json={"key": "TST", "description": "Test"})
|
||||
response = client.post(
|
||||
"/transport-modes/", json={"key": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_transport_mode_forbidden():
|
||||
response = client.put("/transport-modes/TST", json={"key": "TST", "description": "Test"})
|
||||
response = client.put(
|
||||
"/transport-modes/TST", json={"key": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_transport_mode_forbidden():
|
||||
response = client.delete("/transport-modes/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
|
||||
|
||||
class TransportTypeDTO(BaseModel):
|
||||
transport_code: str = Field(..., min_length=1, max_length=2)
|
||||
description: str
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -4,14 +4,18 @@ from core.database import Base
|
||||
|
||||
|
||||
class TransportType(Base):
|
||||
__tablename__ = "transport_types" #GTiposTransporte
|
||||
__tablename__ = "transport_types" # GTiposTransporte
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("transport_code", name="transport_types_pkey"),
|
||||
{"schema": "public"}
|
||||
{"schema": "public"},
|
||||
)
|
||||
|
||||
transport_code: Mapped[str] = mapped_column(String(2), nullable=False) # código SAT o interno
|
||||
description: Mapped[str] = mapped_column(String(100), nullable=False) # descripción del medio de transporte
|
||||
transport_code: Mapped[str] = mapped_column(
|
||||
String(2), nullable=False
|
||||
) # código SAT o interno
|
||||
description: Mapped[str] = mapped_column(
|
||||
String(100), nullable=False
|
||||
) # descripción del medio de transporte
|
||||
|
||||
def __repr__(self):
|
||||
return f"<TransportType(code={self.transport_code}, description={self.description})>"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -15,7 +14,7 @@ router = APIRouter(prefix="/transport-types")
|
||||
def list_transport_types(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db)
|
||||
db: Session = Depends(get_core_db),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(TransportType)
|
||||
@@ -25,21 +24,27 @@ def list_transport_types(
|
||||
"items": [TransportTypeDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{transport_code}", response_model=TransportTypeDTO)
|
||||
def get_transport_type(transport_code: str, db: Session = Depends(get_core_db)):
|
||||
obj = db.query(TransportType).filter(TransportType.transport_code == transport_code).first()
|
||||
obj = (
|
||||
db.query(TransportType)
|
||||
.filter(TransportType.transport_code == transport_code)
|
||||
.first()
|
||||
)
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return obj
|
||||
|
||||
|
||||
@router.post("/", response_model=TransportTypeDTO, status_code=201)
|
||||
def create_transport_type(
|
||||
data: TransportTypeDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
user=Depends(get_current_user)
|
||||
user=Depends(get_current_user),
|
||||
):
|
||||
obj = TransportType(**data.dict())
|
||||
db.add(obj)
|
||||
@@ -47,14 +52,19 @@ def create_transport_type(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
@router.put("/{transport_code}", response_model=TransportTypeDTO)
|
||||
def update_transport_type(
|
||||
transport_code: str,
|
||||
data: TransportTypeDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
user=Depends(get_current_user)
|
||||
user=Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(TransportType).filter(TransportType.transport_code == transport_code).first()
|
||||
obj = (
|
||||
db.query(TransportType)
|
||||
.filter(TransportType.transport_code == transport_code)
|
||||
.first()
|
||||
)
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
for field, value in data.dict().items():
|
||||
@@ -63,13 +73,18 @@ def update_transport_type(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
@router.delete("/{transport_code}", status_code=204)
|
||||
def delete_transport_type(
|
||||
transport_code: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
user=Depends(get_current_user)
|
||||
user=Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(TransportType).filter(TransportType.transport_code == transport_code).first()
|
||||
obj = (
|
||||
db.query(TransportType)
|
||||
.filter(TransportType.transport_code == transport_code)
|
||||
.first()
|
||||
)
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
db.delete(obj)
|
||||
|
||||
@@ -19,4 +19,4 @@ seed = [
|
||||
("RV", "Recreation Vehicle (RV)"),
|
||||
("TR", "Semi Tracker"),
|
||||
("TV", "Van"),
|
||||
]
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_transport_types(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,28 @@ def test_list_transport_types(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_transport_type_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/transport-types/invalid_code", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_transport_type_forbidden():
|
||||
response = client.post("/transport-types/", json={"transport_code": "TST", "description": "Test"})
|
||||
response = client.post(
|
||||
"/transport-types/", json={"transport_code": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_transport_type_forbidden():
|
||||
response = client.put("/transport-types/TST", json={"transport_code": "TST", "description": "Test"})
|
||||
response = client.put(
|
||||
"/transport-types/TST", json={"transport_code": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_transport_type_forbidden():
|
||||
response = client.delete("/transport-types/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import ConfigDict
|
||||
|
||||
|
||||
class ValuationMethodDTO(BaseModel):
|
||||
key: str = Field(..., min_length=1, max_length=2)
|
||||
description: str
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -2,14 +2,15 @@ from sqlalchemy import String, PrimaryKeyConstraint
|
||||
from sqlalchemy.orm import mapped_column, Mapped
|
||||
from core.database import Base
|
||||
|
||||
|
||||
class ValuationMethod(Base):
|
||||
__tablename__ = "valuation_methods" #GMetValor
|
||||
__tablename__ = "valuation_methods" # GMetValor
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("key", name="valuation_methods_pkey"),
|
||||
{"schema": "public"}
|
||||
{"schema": "public"},
|
||||
)
|
||||
|
||||
key: Mapped[str] = mapped_column(String(2), nullable=False)
|
||||
key: Mapped[str] = mapped_column(String(2), nullable=False)
|
||||
description: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from core.database import get_core_db
|
||||
@@ -11,13 +10,12 @@ from typing import Any, Dict
|
||||
router = APIRouter(prefix="/valuation-methods")
|
||||
|
||||
|
||||
|
||||
@router.get("/", response_model=Dict[str, Any])
|
||||
async def list_valuation_methods(
|
||||
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"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
skip = (page - 1) * page_size
|
||||
query = db.query(ValuationMethod)
|
||||
@@ -27,23 +25,27 @@ async def list_valuation_methods(
|
||||
"items": [ValuationMethodDTO.model_validate(obj) for obj in items],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@router.get("/{key}", response_model=ValuationMethodDTO)
|
||||
async def get_valuation_method(key: str, db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user)):
|
||||
async def get_valuation_method(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
obj = db.query(ValuationMethod).filter(ValuationMethod.key == key).first()
|
||||
if not obj:
|
||||
raise HTTPException(status_code=404, detail="Not found")
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.post("/", response_model=ValuationMethodDTO, status_code=201)
|
||||
async def create_valuation_method(
|
||||
data: ValuationMethodDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = ValuationMethod(**data.dict())
|
||||
db.add(obj)
|
||||
@@ -51,13 +53,13 @@ async def create_valuation_method(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.put("/{key}", response_model=ValuationMethodDTO)
|
||||
async def update_valuation_method(
|
||||
key: str,
|
||||
data: ValuationMethodDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(ValuationMethod).filter(ValuationMethod.key == key).first()
|
||||
if not obj:
|
||||
@@ -68,12 +70,12 @@ async def update_valuation_method(
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@router.delete("/{key}", status_code=204)
|
||||
async def delete_valuation_method(
|
||||
key: str,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(has_role("admin"))
|
||||
current_user: dict = Depends(has_role("admin")),
|
||||
):
|
||||
obj = db.query(ValuationMethod).filter(ValuationMethod.key == key).first()
|
||||
if not obj:
|
||||
|
||||
@@ -6,4 +6,4 @@ seed = [
|
||||
("4", "VALOR DE PRECIO UNITARIO DE VENTA."),
|
||||
("5", "VALOR RECONSTRUIDO."),
|
||||
("6", "ULTIMO RECURSO"),
|
||||
]
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_list_valuation_methods(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
@@ -16,20 +17,28 @@ def test_list_valuation_methods(client, access_token):
|
||||
assert "page" in response.json()
|
||||
assert "page_size" in response.json()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("client", "access_token")
|
||||
def test_get_valuation_method_not_found(client, access_token):
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
response = client.get("/valuation-methods/invalid_key", headers=headers)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_create_valuation_method_forbidden():
|
||||
response = client.post("/valuation-methods/", json={"key": "TST", "description": "Test"})
|
||||
response = client.post(
|
||||
"/valuation-methods/", json={"key": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_update_valuation_method_forbidden():
|
||||
response = client.put("/valuation-methods/TST", json={"key": "TST", "description": "Test"})
|
||||
response = client.put(
|
||||
"/valuation-methods/TST", json={"key": "TST", "description": "Test"}
|
||||
)
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
|
||||
def test_delete_valuation_method_forbidden():
|
||||
response = client.delete("/valuation-methods/TST")
|
||||
assert response.status_code in (403, 405, 404)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Router principal de API v1
|
||||
Agrega todos los módulos de la aplicación
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from .reference_data.router import router as reference_data_router
|
||||
|
||||
Reference in New Issue
Block a user