Merge pull request 'feat: Implement Ventanilla Única (VU) management for customs brokers, including API, UI, and data model updates, and add a new state selection dialog.' (#161) from feature/broker-catalogue into development

Reviewed-on: ADUANASOFT/anexo76#161
This commit is contained in:
2026-02-24 21:40:32 +00:00
9 changed files with 871 additions and 78 deletions

View File

@@ -43,6 +43,7 @@ class CustomsBrokerResponseDTO(CustomsBrokerBaseDTO):
broker_key: str
tenant_id: int
company_id: int
vu: Optional["CustomsBrokerVUCreateDTO"] = None
class Config:
from_attributes = True
@@ -75,25 +76,25 @@ class CustomsBrokerDTO(BaseModel):
class CustomsBrokerVUCreateDTO(BaseModel):
certificate_path: Optional[str]
key_path: Optional[str]
access_key: Optional[str]
fiel_format: Optional[str]
signature_read_path: Optional[str]
archive_path: Optional[str]
fiel_access_key: Optional[str]
web_service_user: Optional[str]
web_service_access_key: Optional[str]
vu_email: Optional[str]
vu_figure_type: Optional[str]
xml_files_path: Optional[str]
query_tax_id: Optional[str]
doda_certificate_path: Optional[str]
doda_key_path: Optional[str]
doda_web_service_user: Optional[str]
doda_web_service_access_key: Optional[str]
doda_fiel_access_key: Optional[str]
doda_xml_files_path: Optional[str]
certificate_path: Optional[str] = None
key_path: Optional[str] = None
access_key: Optional[str] = None
fiel_format: Optional[str] = None
signature_read_path: Optional[str] = None
archive_path: Optional[str] = None
fiel_access_key: Optional[str] = None
web_service_user: Optional[str] = None
web_service_access_key: Optional[str] = None
vu_email: Optional[str] = None
vu_figure_type: Optional[str] = None
xml_files_path: Optional[str] = None
query_tax_id: Optional[str] = None
doda_certificate_path: Optional[str] = None
doda_key_path: Optional[str] = None
doda_web_service_user: Optional[str] = None
doda_web_service_access_key: Optional[str] = None
doda_fiel_access_key: Optional[str] = None
doda_xml_files_path: Optional[str] = None
class Config:
from_attributes = True
@@ -102,15 +103,15 @@ class CustomsBrokerVUCreateDTO(BaseModel):
class CustomsBrokerPersonnelDTO(BaseModel):
broker_key: str = Field(..., max_length=5, pattern=r"^[a-zA-Z0-9]+$")
line: int
name: Optional[str]
tax_id: Optional[str]
personal_id: Optional[str]
position: Optional[str]
name: Optional[str] = None
tax_id: Optional[str] = None
personal_id: Optional[str] = None
position: Optional[str] = None
license: Optional[str] = Field(None, max_length=4, pattern=r"^\d*$")
first_name: Optional[str]
last_name: Optional[str]
middle_name: Optional[str]
email: Optional[str]
first_name: Optional[str] = None
last_name: Optional[str] = None
middle_name: Optional[str] = None
email: Optional[str] = None
class Config:
from_attributes = True

View File

@@ -32,7 +32,7 @@ class CustomsBroker(Base, TenantScopedMixin, TimestampMixin):
contact = Column(String(80), nullable=True)
vu = relationship(
"CustomsBrokerVU", back_populates="customs_broker", cascade="all, delete"
"CustomsBrokerVU", back_populates="customs_broker", cascade="all, delete", uselist=False
)
personnel = relationship(
"CustomsBrokerPersonnel", back_populates="customs_broker", cascade="all, delete"

View File

@@ -76,7 +76,8 @@ class CustomsBrokerVUService:
def get_by_broker_key(db: Session, broker_key: str):
return (
db.query(models.CustomsBrokerVU)
.filter(models.CustomsBrokerVU.broker_key == broker_key)
.join(models.CustomsBroker)
.filter(models.CustomsBroker.broker_key == broker_key)
.first()
)
@@ -90,13 +91,28 @@ class CustomsBrokerVUService:
@staticmethod
def update_vu(db: Session, broker_key: str, vu_data: dto.CustomsBrokerVUCreateDTO):
vu = CustomsBrokerVUService.get_by_broker_key(db, broker_key)
# We need the custom broker ID to insert a new VU
broker = db.query(models.CustomsBroker).filter(models.CustomsBroker.broker_key == broker_key).first()
if not broker:
return None
vu = db.query(models.CustomsBrokerVU).filter(models.CustomsBrokerVU.customs_broker_id == broker.id).first()
if vu:
for key, value in vu_data.dict(exclude_unset=True).items():
# Update existing
for key, value in vu_data.model_dump(exclude_unset=True).items():
setattr(vu, key, value)
db.commit()
db.refresh(vu)
return vu
return vu
else:
# Create new
new_vu_data = vu_data.model_dump()
new_vu = models.CustomsBrokerVU(customs_broker_id=broker.id, **new_vu_data)
db.add(new_vu)
db.commit()
db.refresh(new_vu)
return new_vu
@staticmethod
def delete_vu(db: Session, broker_key: str):
@@ -112,16 +128,22 @@ class CustomsBrokerPersonnelService:
def get_by_broker_key_and_line(db: Session, broker_key: str, line: int):
return (
db.query(models.CustomsBrokerPersonnel)
.join(models.CustomsBroker)
.filter(
models.CustomsBrokerPersonnel.broker_key == broker_key,
models.CustomsBroker.broker_key == broker_key,
models.CustomsBrokerPersonnel.line == line,
)
.first()
)
@staticmethod
def create_personnel(db: Session, personnel_data: dto.CustomsBrokerPersonnelDTO):
new_personnel = models.CustomsBrokerPersonnel(**personnel_data.dict())
def create_personnel(db: Session, broker_key: str, personnel_data: dto.CustomsBrokerPersonnelDTO):
broker = db.query(models.CustomsBroker).filter(models.CustomsBroker.broker_key == broker_key).first()
if not broker:
return None
new_personnel_data = personnel_data.model_dump()
new_personnel = models.CustomsBrokerPersonnel(customs_broker_id=broker.id, **new_personnel_data)
db.add(new_personnel)
db.commit()
db.refresh(new_personnel)
@@ -138,7 +160,7 @@ class CustomsBrokerPersonnelService:
db, broker_key, line
)
if personnel:
for key, value in personnel_data.dict(exclude_unset=True).items():
for key, value in personnel_data.model_dump(exclude_unset=True).items():
setattr(personnel, key, value)
db.commit()
db.refresh(personnel)