Merge pull request 'catalogos' (#1) from catalogos into main

Reviewed-on: ADUANASOFT/anexo76#1
This commit is contained in:
2025-11-01 19:02:32 +00:00
39 changed files with 1251 additions and 20 deletions

View File

@@ -0,0 +1,11 @@
from pydantic import BaseModel, Field
from typing import Optional
class CodePedimentoRegimenDTO(BaseModel):
id: int
pedimento_code: str = Field(..., min_length=1, max_length=3)
regimen_code: Optional[str] = Field(None, min_length=1, max_length=3)
type_code: Optional[str] = Field(None, min_length=1, max_length=1)
class Config:
from_attributes = True

View File

@@ -0,0 +1,61 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import CodePedimentoRegimen
from .dto import CodePedimentoRegimenDTO
router = APIRouter(prefix="/code-pedimento-regimens", tags=["Code Pedimento Regimens"])
@router.get("/", response_model=list[CodePedimentoRegimenDTO])
def list_code_pedimento_regimens(db: Session = Depends(get_core_db)):
objs = db.query(CodePedimentoRegimen).all()
return [CodePedimentoRegimenDTO.model_validate(obj) for obj in objs]
@router.get("/{id}", response_model=CodePedimentoRegimenDTO)
def get_code_pedimento_regimen(id: int, db: Session = Depends(get_core_db)):
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"))
):
obj = CodePedimentoRegimen(**data.model_dump())
db.add(obj)
db.commit()
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"))
):
obj = db.query(CodePedimentoRegimen).filter(CodePedimentoRegimen.id == id).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
for field, value in data.model_dump().items():
setattr(obj, field, value)
db.commit()
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"))
):
obj = db.query(CodePedimentoRegimen).filter(CodePedimentoRegimen.id == id).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
db.delete(obj)
db.commit()
return None

View File

@@ -0,0 +1,9 @@
from pydantic import BaseModel, Field
class ContainerDTO(BaseModel):
key: str = Field(..., min_length=1, max_length=3)
description: str
class Config:
from_attributes = True

View File

@@ -0,0 +1,60 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import Container
from .dto import ContainerDTO
router = APIRouter(prefix="/containers", tags=["Containers"])
@router.get("/", response_model=list[ContainerDTO])
def list_containers(db: Session = Depends(get_core_db)):
return db.query(Container).all()
@router.get("/{key}", response_model=ContainerDTO)
def get_container(key: str, db: Session = Depends(get_core_db)):
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)
def create_container(
data: ContainerDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = Container(**data.dict())
db.add(obj)
db.commit()
db.refresh(obj)
return obj
@router.put("/{key}", response_model=ContainerDTO)
def update_container(
key: str,
data: ContainerDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(Container).filter(Container.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
for field, value in data.dict().items():
setattr(obj, field, value)
db.commit()
db.refresh(obj)
return obj
@router.delete("/{key}", status_code=204)
def delete_container(
key: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(Container).filter(Container.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
db.delete(obj)
db.commit()
return None

View File

@@ -0,0 +1,12 @@
from pydantic import BaseModel, Field
class CountryDTO(BaseModel):
m3_key: str = Field(..., min_length=1, max_length=3)
mex_key: str = Field(..., min_length=1, max_length=2)
ame_key: str = Field(..., min_length=1, max_length=2)
description_es: str
description_en: str
class Config:
from_attributes = True

View File

@@ -0,0 +1,60 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import Country
from .dto import CountryDTO
router = APIRouter(prefix="/countries", tags=["Countries"])
@router.get("/", response_model=list[CountryDTO])
def list_countries(db: Session = Depends(get_core_db)):
return db.query(Country).all()
@router.get("/{m3_key}", response_model=CountryDTO)
def get_country(m3_key: str, db: Session = Depends(get_core_db)):
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)
def create_country(
data: CountryDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = Country(**data.dict())
db.add(obj)
db.commit()
db.refresh(obj)
return obj
@router.put("/{m3_key}", response_model=CountryDTO)
def update_country(
m3_key: str,
data: CountryDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(Country).filter(Country.m3_key == m3_key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
for field, value in data.dict().items():
setattr(obj, field, value)
db.commit()
db.refresh(obj)
return obj
@router.delete("/{m3_key}", status_code=204)
def delete_country(
m3_key: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(Country).filter(Country.m3_key == m3_key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
db.delete(obj)
db.commit()
return None

View File

@@ -0,0 +1,10 @@
from pydantic import BaseModel, Field
class CurrencyTypeDTO(BaseModel):
code: str = Field(..., min_length=1, max_length=3)
currency_name: str
country_description: str
class Config:
from_attributes = True

View File

@@ -0,0 +1,60 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import CurrencyType
from .dto import CurrencyTypeDTO
router = APIRouter(prefix="/currency-types", tags=["Currency Types"])
@router.get("/", response_model=list[CurrencyTypeDTO])
def list_currency_types(db: Session = Depends(get_core_db)):
return db.query(CurrencyType).all()
@router.get("/{code}", response_model=CurrencyTypeDTO)
def get_currency_type(code: str, db: Session = Depends(get_core_db)):
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)
def create_currency_type(
data: CurrencyTypeDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = CurrencyType(**data.dict())
db.add(obj)
db.commit()
db.refresh(obj)
return obj
@router.put("/{code}", response_model=CurrencyTypeDTO)
def update_currency_type(
code: str,
data: CurrencyTypeDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(CurrencyType).filter(CurrencyType.code == code).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
for field, value in data.dict().items():
setattr(obj, field, value)
db.commit()
db.refresh(obj)
return obj
@router.delete("/{code}", status_code=204)
def delete_currency_type(
code: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(CurrencyType).filter(CurrencyType.code == code).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
db.delete(obj)
db.commit()
return None

View File

@@ -0,0 +1,9 @@
from pydantic import BaseModel, Field
class CustomsSectionDTO(BaseModel):
customs_code: str = Field(..., min_length=1, max_length=3)
section_name: str
class Config:
from_attributes = True

View File

@@ -0,0 +1,60 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import CustomsSection
from .dto import CustomsSectionDTO
router = APIRouter(prefix="/customs-sections", tags=["Customs Sections"])
@router.get("/", response_model=list[CustomsSectionDTO])
def list_customs_sections(db: Session = Depends(get_core_db)):
return db.query(CustomsSection).all()
@router.get("/{customs_code}", response_model=CustomsSectionDTO)
def get_customs_section(customs_code: str, db: Session = Depends(get_core_db)):
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"))
):
obj = CustomsSection(**data.dict())
db.add(obj)
db.commit()
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"))
):
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():
setattr(obj, field, value)
db.commit()
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"))
):
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)
db.commit()
return None

View File

@@ -0,0 +1,10 @@
from pydantic import BaseModel, Field
class CustomsWarehouseDTO(BaseModel):
key: str = Field(..., min_length=1, max_length=3)
customs: str
fiscalized_warehouse: str
class Config:
from_attributes = True

View File

@@ -0,0 +1,62 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import CustomsWarehouse
from .dto import CustomsWarehouseDTO
router = APIRouter(prefix="/customs-warehouses", tags=["Customs Warehouses"])
@router.get("/", response_model=list[CustomsWarehouseDTO])
def list_customs_warehouses(db: Session = Depends(get_core_db)):
return db.query(CustomsWarehouse).all()
@router.get("/{key}/{customs}", response_model=CustomsWarehouseDTO)
def get_customs_warehouse(key: str, customs: str, db: Session = Depends(get_core_db)):
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"))
):
obj = CustomsWarehouse(**data.dict())
db.add(obj)
db.commit()
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"))
):
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():
setattr(obj, field, value)
db.commit()
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"))
):
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)
db.commit()
return None

View File

@@ -0,0 +1,9 @@
from pydantic import BaseModel, Field
class IncotermDTO(BaseModel):
code: str = Field(..., min_length=1, max_length=5)
description_es: str
description_en: str
class Config:
from_attributes = True

View File

@@ -0,0 +1,61 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import Incoterm
from .dto import IncotermDTO
router = APIRouter(prefix="/incoterms", tags=["Incoterms"])
@router.get("/", response_model=list[IncotermDTO])
def list_incoterms(db: Session = Depends(get_core_db)):
objs = db.query(Incoterm).all()
return [IncotermDTO.model_validate(obj) for obj in objs]
@router.get("/{key}", response_model=IncotermDTO)
def get_incoterm(key: str, db: Session = Depends(get_core_db)):
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)
def create_incoterm(
data: IncotermDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = Incoterm(**data.model_dump())
db.add(obj)
db.commit()
db.refresh(obj)
return IncotermDTO.model_validate(obj)
@router.put("/{key}", response_model=IncotermDTO)
def update_incoterm(
key: str,
data: IncotermDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(Incoterm).filter(Incoterm.code == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
for field, value in data.model_dump().items():
setattr(obj, field, value)
db.commit()
db.refresh(obj)
return IncotermDTO.model_validate(obj)
@router.delete("/{key}", status_code=204)
def delete_incoterm(
key: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(Incoterm).filter(Incoterm.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
db.delete(obj)
db.commit()
return None

View File

@@ -0,0 +1,11 @@
from pydantic import BaseModel, Field
from typing import Optional
class InvoiceTypeDTO(BaseModel):
key: str = Field(..., min_length=1, max_length=5)
description: str
note: Optional[str] = None
type: Optional[str] = None
class Config:
from_attributes = True

View File

@@ -0,0 +1,61 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import InvoiceType
from .dto import InvoiceTypeDTO
router = APIRouter(prefix="/invoice-types", tags=["Invoice Types"])
@router.get("/", response_model=list[InvoiceTypeDTO])
def list_invoice_types(db: Session = Depends(get_core_db)):
objs = db.query(InvoiceType).all()
return [InvoiceTypeDTO.model_validate(obj) for obj in objs]
@router.get("/{key}", response_model=InvoiceTypeDTO)
def get_invoice_type(key: str, db: Session = Depends(get_core_db)):
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"))
):
obj = InvoiceType(**data.model_dump())
db.add(obj)
db.commit()
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"))
):
obj = db.query(InvoiceType).filter(InvoiceType.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
for field, value in data.model_dump().items():
setattr(obj, field, value)
db.commit()
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"))
):
obj = db.query(InvoiceType).filter(InvoiceType.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
db.delete(obj)
db.commit()
return None

View File

@@ -0,0 +1,10 @@
from pydantic import BaseModel, Field
class MaterialTypeDTO(BaseModel):
key: str = Field(..., min_length=1, max_length=10)
type: str = Field(..., min_length=1, max_length=15)
description: str
class Config:
from_attributes = True

View File

@@ -0,0 +1,60 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import MaterialType
from .dto import MaterialTypeDTO
router = APIRouter(prefix="/material-types", tags=["Material Types"])
@router.get("/", response_model=list[MaterialTypeDTO])
def list_material_types(db: Session = Depends(get_core_db)):
return db.query(MaterialType).all()
@router.get("/{key}", response_model=MaterialTypeDTO)
def get_material_type(key: str, db: Session = Depends(get_core_db)):
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)
def create_material_type(
data: MaterialTypeDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = MaterialType(**data.dict())
db.add(obj)
db.commit()
db.refresh(obj)
return obj
@router.put("/{key}", response_model=MaterialTypeDTO)
def update_material_type(
key: str,
data: MaterialTypeDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(MaterialType).filter(MaterialType.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
for field, value in data.dict().items():
setattr(obj, field, value)
db.commit()
db.refresh(obj)
return obj
@router.delete("/{key}", status_code=204)
def delete_material_type(
key: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(MaterialType).filter(MaterialType.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
db.delete(obj)
db.commit()
return None

View File

@@ -0,0 +1,9 @@
from pydantic import BaseModel, Field
class PaymentMethodDTO(BaseModel):
key: str = Field(..., min_length=1, max_length=2)
description: str
class Config:
from_attributes = True

View File

@@ -0,0 +1,60 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import PaymentMethod
from .dto import PaymentMethodDTO
router = APIRouter(prefix="/payment-methods", tags=["Payment Methods"])
@router.get("/", response_model=list[PaymentMethodDTO])
def list_payment_methods(db: Session = Depends(get_core_db)):
return db.query(PaymentMethod).all()
@router.get("/{key}", response_model=PaymentMethodDTO)
def get_payment_method(key: str, db: Session = Depends(get_core_db)):
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"))
):
obj = PaymentMethod(**data.dict())
db.add(obj)
db.commit()
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"))
):
obj = db.query(PaymentMethod).filter(PaymentMethod.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
for field, value in data.dict().items():
setattr(obj, field, value)
db.commit()
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"))
):
obj = db.query(PaymentMethod).filter(PaymentMethod.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
db.delete(obj)
db.commit()
return None

View File

@@ -0,0 +1,10 @@
from pydantic import BaseModel, Field
from typing import Optional
class PedimentoCodeDTO(BaseModel):
code: str = Field(..., min_length=1, max_length=3)
description: str
class Config:
from_attributes = True

View File

@@ -0,0 +1,60 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import PedimentoCode
from .dto import PedimentoCodeDTO
router = APIRouter(prefix="/pedimento-codes", tags=["Pedimento Codes"])
@router.get("/", response_model=list[PedimentoCodeDTO])
def list_pedimento_codes(db: Session = Depends(get_core_db)):
return db.query(PedimentoCode).all()
@router.get("/{code}", response_model=PedimentoCodeDTO)
def get_pedimento_code(code: str, db: Session = Depends(get_core_db)):
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"))
):
obj = PedimentoCode(**data.dict())
db.add(obj)
db.commit()
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"))
):
obj = db.query(PedimentoCode).filter(PedimentoCode.code == code).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
for field, value in data.dict().items():
setattr(obj, field, value)
db.commit()
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"))
):
obj = db.query(PedimentoCode).filter(PedimentoCode.code == code).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
db.delete(obj)
db.commit()
return None

View File

@@ -0,0 +1,9 @@
from pydantic import BaseModel, Field
from typing import List
class RegimenPedimentoDTO(BaseModel):
code: str = Field(..., min_length=1, max_length=3)
description: str
class Config:
from_attributes = True

View File

@@ -0,0 +1,61 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import RegimenPedimento
from .dto import RegimenPedimentoDTO
router = APIRouter(prefix="/pedimento-regimens", tags=["Pedimento Regimens"])
@router.get("/", response_model=list[RegimenPedimentoDTO])
def list_pedimento_regimens(db: Session = Depends(get_core_db)):
objs = db.query(RegimenPedimento).all()
return [RegimenPedimentoDTO.model_validate(obj) for obj in objs]
@router.get("/{key}", response_model=RegimenPedimentoDTO)
def get_pedimento_regimen(key: str, db: Session = Depends(get_core_db)):
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"))
):
obj = RegimenPedimento(**data.model_dump())
db.add(obj)
db.commit()
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"))
):
obj = db.query(RegimenPedimento).filter(RegimenPedimento.code == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
for field, value in data.model_dump().items():
setattr(obj, field, value)
db.commit()
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"))
):
obj = db.query(RegimenPedimento).filter(RegimenPedimento.code == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
db.delete(obj)
db.commit()
return None

View File

@@ -0,0 +1,10 @@
from pydantic import BaseModel, Field
class SectorDTO(BaseModel):
key: str = Field(..., min_length=1, max_length=8)
description: str
authorized: int
class Config:
from_attributes = True

View File

@@ -0,0 +1,60 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import Sector
from .dto import SectorDTO
router = APIRouter(prefix="/sectors", tags=["Sectors"])
@router.get("/", response_model=list[SectorDTO])
def list_sectors(db: Session = Depends(get_core_db)):
return db.query(Sector).all()
@router.get("/{key}", response_model=SectorDTO)
def get_sector(key: str, db: Session = Depends(get_core_db)):
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"))
):
obj = Sector(**data.dict())
db.add(obj)
db.commit()
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"))
):
obj = db.query(Sector).filter(Sector.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
for field, value in data.dict().items():
setattr(obj, field, value)
db.commit()
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"))
):
obj = db.query(Sector).filter(Sector.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
db.delete(obj)
db.commit()
return None

View File

@@ -0,0 +1,12 @@
from pydantic import BaseModel, Field
from typing import Optional
class StateDTO(BaseModel):
m3_key: str = Field(..., min_length=1, max_length=3)
description: str
mex_key: Optional[str] = None
ame_key: Optional[str] = None
class Config:
from_attributes = True

View File

@@ -0,0 +1,60 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import State
from .dto import StateDTO
router = APIRouter(prefix="/states", tags=["States"])
@router.get("/", response_model=list[StateDTO])
def list_states(db: Session = Depends(get_core_db)):
return db.query(State).all()
@router.get("/{m3_key}", response_model=StateDTO)
def get_state(m3_key: str, db: Session = Depends(get_core_db)):
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)
def create_state(
data: StateDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = State(**data.dict())
db.add(obj)
db.commit()
db.refresh(obj)
return obj
@router.put("/{m3_key}", response_model=StateDTO)
def update_state(
m3_key: str,
data: StateDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(State).filter(State.m3_key == m3_key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
for field, value in data.dict().items():
setattr(obj, field, value)
db.commit()
db.refresh(obj)
return obj
@router.delete("/{m3_key}", status_code=204)
def delete_state(
m3_key: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(State).filter(State.m3_key == m3_key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
db.delete(obj)
db.commit()
return None

View File

@@ -0,0 +1,9 @@
from pydantic import BaseModel, Field
class TransportModeDTO(BaseModel):
key: str = Field(..., min_length=1, max_length=3)
name: str
class Config:
from_attributes = True

View File

@@ -0,0 +1,60 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import TransportMode
from .dto import TransportModeDTO
router = APIRouter(prefix="/transport-modes", tags=["Transport Modes"])
@router.get("/", response_model=list[TransportModeDTO])
def list_transport_modes(db: Session = Depends(get_core_db)):
return db.query(TransportMode).all()
@router.get("/{key}", response_model=TransportModeDTO)
def get_transport_mode(key: str, db: Session = Depends(get_core_db)):
obj = db.query(TransportMode).filter(TransportMode.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
return obj
@router.post("/", response_model=TransportModeDTO, status_code=201)
def create_transport_mode(
data: TransportModeDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = TransportMode(**data.dict())
db.add(obj)
db.commit()
db.refresh(obj)
return obj
@router.put("/{key}", response_model=TransportModeDTO)
def update_transport_mode(
key: str,
data: TransportModeDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(TransportMode).filter(TransportMode.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
for field, value in data.dict().items():
setattr(obj, field, value)
db.commit()
db.refresh(obj)
return obj
@router.delete("/{key}", status_code=204)
def delete_transport_mode(
key: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(TransportMode).filter(TransportMode.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
db.delete(obj)
db.commit()
return None

View File

@@ -0,0 +1,9 @@
from pydantic import BaseModel, Field
class TransportTypeDTO(BaseModel):
transport_code: str = Field(..., min_length=1, max_length=2)
description: str
class Config:
from_attributes = True

View File

@@ -0,0 +1,60 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import TransportType
from .dto import TransportTypeDTO
router = APIRouter(prefix="/transport-types", tags=["Transport Types"])
@router.get("/", response_model=list[TransportTypeDTO])
def list_transport_types(db: Session = Depends(get_core_db)):
return db.query(TransportType).all()
@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()
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),
current_user: dict = Depends(has_role("admin"))
):
obj = TransportType(**data.dict())
db.add(obj)
db.commit()
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),
current_user: dict = Depends(has_role("admin"))
):
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():
setattr(obj, field, value)
db.commit()
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),
current_user: dict = Depends(has_role("admin"))
):
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)
db.commit()
return None

View File

@@ -0,0 +1,9 @@
from pydantic import BaseModel, Field
class ValuationMethodDTO(BaseModel):
key: str = Field(..., min_length=1, max_length=2)
description: str
class Config:
from_attributes = True

View File

@@ -0,0 +1,60 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import has_role
from .models import ValuationMethod
from .dto import ValuationMethodDTO
router = APIRouter(prefix="/valuation-methods", tags=["Valuation Methods"])
@router.get("/", response_model=list[ValuationMethodDTO])
def list_valuation_methods(db: Session = Depends(get_core_db)):
return db.query(ValuationMethod).all()
@router.get("/{key}", response_model=ValuationMethodDTO)
def get_valuation_method(key: str, db: Session = Depends(get_core_db)):
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)
def create_valuation_method(
data: ValuationMethodDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = ValuationMethod(**data.dict())
db.add(obj)
db.commit()
db.refresh(obj)
return obj
@router.put("/{key}", response_model=ValuationMethodDTO)
def update_valuation_method(
key: str,
data: ValuationMethodDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(ValuationMethod).filter(ValuationMethod.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
for field, value in data.dict().items():
setattr(obj, field, value)
db.commit()
db.refresh(obj)
return obj
@router.delete("/{key}", status_code=204)
def delete_valuation_method(
key: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(has_role("admin"))
):
obj = db.query(ValuationMethod).filter(ValuationMethod.key == key).first()
if not obj:
raise HTTPException(status_code=404, detail="Not found")
db.delete(obj)
db.commit()
return None

View File

@@ -7,6 +7,24 @@ from fastapi import APIRouter
# Importar routers de módulos
from .modules.a76.auth import router as auth_router
from .modules.a76.tenants import router as tenants_router
from .modules.public.reference_data.pedimento_codes.routes import router as pedimento_codes_router
from .modules.public.reference_data.payment_methods.routes import router as payment_methods_router
from .modules.public.reference_data.containers.routes import router as containers_router
from .modules.public.reference_data.countries.routes import router as countries_router
from .modules.public.reference_data.material_types.routes import router as material_types_router
from .modules.public.reference_data.currency_types.routes import router as currency_types_router
from .modules.public.reference_data.states.routes import router as states_router
from .modules.public.reference_data.transport_types.routes import router as transport_types_router
from .modules.public.reference_data.customs_warehouses.routes import router as customs_warehouses_router
from .modules.public.reference_data.valuation_methods.routes import router as valuation_methods_router
from .modules.public.reference_data.sectors.routes import router as sectors_router
from .modules.public.reference_data.transport_modes.routes import router as transport_modes_router
from .modules.public.reference_data.customs_sections.routes import router as customs_sections_router
from .modules.public.reference_data.invoice_types.routes import router as invoice_types_router
from .modules.public.reference_data.code_pedimento_regimens.routes import router as code_pedimento_regimens_router
from .modules.public.reference_data.pedimento_regimens.routes import router as pedimento_regimens_router
from .modules.public.reference_data.incoterms.routes import router as incoterms_router
from .modules.a76.licenses import router as licenses_router
# Router principal
@@ -16,8 +34,27 @@ router = APIRouter()
router.include_router(auth_router)
router.include_router(tenants_router)
router.include_router(licenses_router)
router.include_router(pedimento_codes_router)
router.include_router(payment_methods_router)
router.include_router(containers_router)
router.include_router(countries_router)
router.include_router(material_types_router)
router.include_router(currency_types_router)
router.include_router(states_router)
router.include_router(transport_types_router)
router.include_router(customs_warehouses_router)
router.include_router(valuation_methods_router)
router.include_router(sectors_router)
router.include_router(transport_modes_router)
router.include_router(customs_sections_router)
router.include_router(invoice_types_router)
router.include_router(code_pedimento_regimens_router)
router.include_router(pedimento_regimens_router)
router.include_router(incoterms_router)
# Health check
@router.get("/status")
def status():
"""Health check de la API"""

View File

@@ -162,7 +162,7 @@ services:
- KEYCLOAK_REALM=${KEYCLOAK_REALM:-master}
- KEYCLOAK_CLIENT_ID=${KEYCLOAK_CLIENT_ID:-anexo76-backend}
- KEYCLOAK_CLIENT_SECRET=${KEYCLOAK_CLIENT_SECRET:-dev-secret}
- CORS_ORIGINS=http://localhost:5173,http://localhost:3000
- CORS_ORIGINS=http://localhost:5180,http://localhost:3000
ports:
- "8000:8000"
depends_on:
@@ -215,7 +215,7 @@ services:
- PUBLIC_KEYCLOAK_CLIENT_ID=${KEYCLOAK_FRONTEND_CLIENT_ID:-anexo76-frontend}
- VITE_HMR_HOST=localhost
ports:
- "5173:5173"
- "5180:5180"
depends_on:
backend:
condition: service_healthy
@@ -229,7 +229,7 @@ services:
restart: unless-stopped
command: ["pnpm", "run", "dev", "--", "--host", "0.0.0.0"]
healthcheck:
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:5173/ || exit 1"]
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:5180/ || exit 1"]
interval: 15s
timeout: 5s
retries: 5

View File

@@ -24,7 +24,7 @@ COPY . .
# RUN pnpm run build
# Exponer puerto
EXPOSE 5173
EXPOSE 5180
# Comando por defecto (desarrollo)
CMD ["pnpm", "run", "dev", "--", "--host", "0.0.0.0"]

View File

@@ -5,7 +5,7 @@ import { sveltekit } from '@sveltejs/kit/vite';
export default defineConfig({
server: {
port: 5173, // fija el puerto
port: 5180, // fija el puerto
host: true, // escucha en 0.0.0.0
},
plugins: [

View File

@@ -25,7 +25,7 @@ wait_for_healthy() {
echo -e "${BLUE}Esperando a que ${service} esté saludable...${NC}"
while [ $attempt -le $max_attempts ]; do
if docker-compose ps | grep "$service" | grep -q "healthy"; then
if docker compose ps | grep "$service" | grep -q "healthy"; then
echo -e "${GREEN}${service} está saludable${NC}"
return 0
fi
@@ -36,7 +36,7 @@ wait_for_healthy() {
echo -e "${RED}${service} no estuvo disponible después de $max_attempts intentos${NC}"
echo "Logs del servicio:"
docker-compose logs --tail=50 "$service"
docker compose logs --tail=50 "$service"
return 1
}
@@ -47,7 +47,7 @@ if ! command -v docker &> /dev/null; then
exit 1
fi
if ! command -v docker-compose &> /dev/null; then
if ! command -v docker compose &> /dev/null; then
echo -e "${RED}✗ Docker Compose no está instalado. Por favor instala Docker Compose primero.${NC}"
exit 1
fi
@@ -92,14 +92,14 @@ echo ""
# 3. Limpiar contenedores previos si existen
echo -e "${BLUE}[3/7] Limpiando contenedores previos...${NC}"
docker-compose down 2>/dev/null || true
docker compose down 2>/dev/null || true
echo -e "${GREEN}✓ Contenedores previos limpiados${NC}"
echo ""
# 4. Iniciar PostgreSQL databases
echo -e "${BLUE}[4/7] Iniciando bases de datos PostgreSQL...${NC}"
echo "Esto puede tardar 30-60 segundos..."
docker-compose up -d postgres-a76 postgres-keycloak
docker compose up -d postgres-a76 postgres-keycloak
if wait_for_healthy "postgres-a76" && wait_for_healthy "postgres-keycloak"; then
echo -e "${GREEN}✓ Bases de datos PostgreSQL iniciadas y saludables${NC}"
@@ -112,7 +112,7 @@ echo ""
# 5. Iniciar Keycloak
echo -e "${BLUE}[5/7] Iniciando Keycloak...${NC}"
echo "Esto puede tardar 60-90 segundos..."
docker-compose up -d keycloak
docker compose up -d keycloak
if wait_for_healthy "keycloak"; then
echo -e "${GREEN}✓ Keycloak iniciado y saludable${NC}"
@@ -125,14 +125,14 @@ echo ""
# 6. Iniciar Backend
echo -e "${BLUE}[6/7] Iniciando Backend FastAPI...${NC}"
echo "Esto puede tardar 30-60 segundos..."
docker-compose up -d backend
docker compose up -d backend
if wait_for_healthy "backend"; then
echo -e "${GREEN}✓ Backend iniciado y saludable${NC}"
else
echo -e "${RED}✗ Error iniciando Backend${NC}"
echo "Verificando logs..."
docker-compose logs --tail=50 backend
docker compose logs --tail=50 backend
exit 1
fi
echo ""
@@ -140,7 +140,7 @@ echo ""
# 7. Iniciar Frontend
echo -e "${BLUE}[7/7] Iniciando Frontend SvelteKit...${NC}"
echo "Esto puede tardar 30-45 segundos..."
docker-compose up -d frontend
docker compose up -d frontend
if wait_for_healthy "frontend"; then
echo -e "${GREEN}✓ Frontend iniciado y saludable${NC}"
@@ -155,7 +155,7 @@ echo -e "${GREEN} ✓ Instalación Completada${NC}"
echo "========================================="
echo ""
echo "Servicios disponibles:"
echo -e " ${GREEN}${NC} Frontend: ${BLUE}http://localhost:5173${NC}"
echo -e " ${GREEN}${NC} Frontend: ${BLUE}http://localhost:5180${NC}"
echo -e " ${GREEN}${NC} Backend: ${BLUE}http://localhost:8000${NC}"
echo -e " ${GREEN}${NC} API Docs: ${BLUE}http://localhost:8000/docs${NC}"
echo -e " ${GREEN}${NC} Keycloak: ${BLUE}http://localhost:8080${NC}"
@@ -173,11 +173,11 @@ echo " • Usuario: demo"
echo " • Password: demo123"
echo ""
echo "Comandos útiles:"
echo " • Ver logs: docker-compose logs -f"
echo " • Ver logs servicio: docker-compose logs -f [servicio]"
echo " • Estado servicios: docker-compose ps"
echo " • Detener todo: docker-compose down"
echo " • Detener y limpiar: docker-compose down -v"
echo " • Ver logs: docker compose logs -f"
echo " • Ver logs servicio: docker compose logs -f [servicio]"
echo " • Estado servicios: docker compose ps"
echo " • Detener todo: docker compose down"
echo " • Detener y limpiar: docker compose down -v"
echo ""
echo -e "${GREEN}¡Disfruta desarrollando con Anexo76!${NC}"
echo ""