feature/migraciones-id-transportes
This commit is contained in:
@@ -512,15 +512,29 @@ def validate_common(
|
||||
|
||||
if invoice.logistics:
|
||||
if invoice.logistics.carrier_id:
|
||||
carrier_exists = (
|
||||
db.query(Transporter)
|
||||
.filter(
|
||||
Transporter.id == invoice.logistics.carrier_id,
|
||||
Transporter.tenant_id == tenant_id,
|
||||
Transporter.company_id == company_id,
|
||||
# `carrier_id` is the frontend/export key (string). Prefer validating by the internal int
|
||||
# when present, otherwise validate by `transporter_key`.
|
||||
if getattr(invoice.logistics, "carrier_int_id", None) is not None:
|
||||
carrier_exists = (
|
||||
db.query(Transporter)
|
||||
.filter(
|
||||
Transporter.transporter_id
|
||||
== invoice.logistics.carrier_int_id,
|
||||
Transporter.tenant_id == tenant_id,
|
||||
Transporter.company_id == company_id,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
carrier_exists = (
|
||||
db.query(Transporter)
|
||||
.filter(
|
||||
Transporter.transporter_key == invoice.logistics.carrier_id,
|
||||
Transporter.tenant_id == tenant_id,
|
||||
Transporter.company_id == company_id,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if not carrier_exists:
|
||||
errors.add_error(
|
||||
field="logistics.carrier_id",
|
||||
|
||||
@@ -563,9 +563,15 @@ class InvoiceLogistics(Base, TenantScopedMixin, TimestampMixin):
|
||||
carrier_id: Mapped[Optional[str]] = mapped_column(
|
||||
String(10)
|
||||
) # TRANSPORTISTA / Transportista
|
||||
carrier_int_id: Mapped[Optional[int]] = mapped_column(
|
||||
BigInteger, ForeignKey("a76.transporter.transporter_id"), nullable=True
|
||||
) # Internal surrogate ID for Transporter (by transporter_key)
|
||||
transport_id: Mapped[Optional[str]] = mapped_column(
|
||||
String(10)
|
||||
) # NUMTRAILER / Transportista
|
||||
transport_int_id: Mapped[Optional[int]] = mapped_column(
|
||||
BigInteger, ForeignKey("a76.vehicle.vehicle_id"), nullable=True
|
||||
) # Internal surrogate ID for Vehicle (by vehicle_key)
|
||||
transport_us_id: Mapped[Optional[str]] = mapped_column(
|
||||
String(10)
|
||||
) # TRANSPORTISTAAME / Transportista americano
|
||||
@@ -601,6 +607,9 @@ class InvoiceLogistics(Base, TenantScopedMixin, TimestampMixin):
|
||||
trailer_num: Mapped[Optional[str]] = mapped_column(
|
||||
String(20)
|
||||
) # NUMTRAILER / Número de trailer
|
||||
trailer_int_id: Mapped[Optional[int]] = mapped_column(
|
||||
BigInteger, ForeignKey("a76.trailer.trailer_id"), nullable=True
|
||||
) # Internal surrogate ID for Trailer (by trailer_number)
|
||||
seal_number: Mapped[Optional[str]] = mapped_column(
|
||||
String(15)
|
||||
) # PRECINTO / Precinto
|
||||
|
||||
@@ -299,9 +299,14 @@ class InvoiceFinancialsBase(BaseModel):
|
||||
|
||||
class InvoiceLogisticsBase(BaseModel):
|
||||
"""Base fields for Logistics"""
|
||||
|
||||
carrier_id: Optional[str] = Field(None, max_length=10, description="Carrier ID")
|
||||
carrier_id: Optional[str] = Field(None, max_length=10, description="Carrier code (front-end key)")
|
||||
carrier_int_id: Optional[int] = Field(
|
||||
None, description="Internal carrier integer ID (mapped from carrier_id key)"
|
||||
)
|
||||
transport_id: Optional[str] = Field(None, max_length=10, description="Transport ID")
|
||||
transport_int_id: Optional[int] = Field(
|
||||
None, description="Internal vehicle integer ID (mapped from transport_id key)"
|
||||
)
|
||||
transport_us_id: Optional[str] = Field(
|
||||
None, max_length=10, description="US transport ID"
|
||||
)
|
||||
@@ -329,6 +334,9 @@ class InvoiceLogisticsBase(BaseModel):
|
||||
trailer_num: Optional[str] = Field(
|
||||
None, max_length=20, description="Trailer number"
|
||||
)
|
||||
trailer_int_id: Optional[int] = Field(
|
||||
None, description="Internal trailer integer ID (mapped from trailer_num key)"
|
||||
)
|
||||
seal_number: Optional[str] = Field(None, max_length=15, description="Seal number")
|
||||
guide_number: Optional[str] = Field(None, max_length=20, description="Guide number")
|
||||
bill_number: Optional[str] = Field(None, max_length=15, description="Bill number")
|
||||
|
||||
@@ -15,6 +15,87 @@ from api.v1.modules.a76.items.models import LineItem
|
||||
from . import models, schemas
|
||||
|
||||
|
||||
def _autofill_transport_int_ids(
|
||||
db: Session,
|
||||
logistics_target,
|
||||
tenant_id: int,
|
||||
company_id: int,
|
||||
) -> None:
|
||||
"""
|
||||
Ensures invoice logistics internal int IDs are populated when their string codes exist.
|
||||
|
||||
The frontend and exports/imports keep using the string keys/codes (carrier_id, transport_id, trailer_num),
|
||||
but internally we also persist integer surrogate IDs for fast/consistent joins.
|
||||
"""
|
||||
|
||||
# Local imports to avoid circular dependencies.
|
||||
from api.v1.modules.a76.transportation.transporters.models import Transporter
|
||||
from api.v1.modules.a76.transportation.vehicles.models import Vehicle
|
||||
from api.v1.modules.a76.transportation.trailers.models import Trailer
|
||||
|
||||
def _get(field: str):
|
||||
if isinstance(logistics_target, dict):
|
||||
return logistics_target.get(field)
|
||||
return getattr(logistics_target, field, None)
|
||||
|
||||
def _set(field: str, value):
|
||||
if isinstance(logistics_target, dict):
|
||||
logistics_target[field] = value
|
||||
else:
|
||||
setattr(logistics_target, field, value)
|
||||
|
||||
carrier_code = _get("carrier_id")
|
||||
carrier_int_id = _get("carrier_int_id")
|
||||
if carrier_code and carrier_int_id is None:
|
||||
transporter_obj = (
|
||||
db.query(Transporter)
|
||||
.filter(Transporter.transporter_key == carrier_code)
|
||||
.first()
|
||||
)
|
||||
if not transporter_obj:
|
||||
# Minimal insert so mapping doesn't end up NULL.
|
||||
transporter_obj = Transporter(
|
||||
transporter_key=carrier_code,
|
||||
tenant_id=tenant_id,
|
||||
company_id=company_id,
|
||||
)
|
||||
db.add(transporter_obj)
|
||||
db.flush()
|
||||
_set("carrier_int_id", transporter_obj.transporter_id)
|
||||
|
||||
transport_code = _get("transport_id")
|
||||
transport_int_id = _get("transport_int_id")
|
||||
if transport_code and transport_int_id is None:
|
||||
vehicle_obj = (
|
||||
db.query(Vehicle).filter(Vehicle.vehicle_key == transport_code).first()
|
||||
)
|
||||
if not vehicle_obj:
|
||||
vehicle_obj = Vehicle(
|
||||
vehicle_key=transport_code,
|
||||
tenant_id=tenant_id,
|
||||
company_id=company_id,
|
||||
)
|
||||
db.add(vehicle_obj)
|
||||
db.flush()
|
||||
_set("transport_int_id", vehicle_obj.vehicle_id)
|
||||
|
||||
trailer_code = _get("trailer_num")
|
||||
trailer_int_id = _get("trailer_int_id")
|
||||
if trailer_code and trailer_int_id is None:
|
||||
trailer_obj = (
|
||||
db.query(Trailer).filter(Trailer.trailer_number == trailer_code).first()
|
||||
)
|
||||
if not trailer_obj:
|
||||
trailer_obj = Trailer(
|
||||
trailer_number=trailer_code,
|
||||
tenant_id=tenant_id,
|
||||
company_id=company_id,
|
||||
)
|
||||
db.add(trailer_obj)
|
||||
db.flush()
|
||||
_set("trailer_int_id", trailer_obj.trailer_id)
|
||||
|
||||
|
||||
def _get_current_username() -> str:
|
||||
"""Helper to get current username from context or fallback to System"""
|
||||
try:
|
||||
@@ -282,6 +363,12 @@ class InvoiceService:
|
||||
logistics_dict["invoice_id"] = new_invoice.id
|
||||
logistics_dict["tenant_id"] = tenant_id
|
||||
logistics_dict["company_id"] = company_id
|
||||
_autofill_transport_int_ids(
|
||||
db,
|
||||
logistics_dict,
|
||||
tenant_id=tenant_id,
|
||||
company_id=company_id,
|
||||
)
|
||||
new_logistics = models.InvoiceLogistics(**logistics_dict)
|
||||
db.add(new_logistics)
|
||||
|
||||
@@ -444,11 +531,23 @@ class InvoiceService:
|
||||
if value == "":
|
||||
value = None
|
||||
setattr(invoice.logistics, key, value)
|
||||
_autofill_transport_int_ids(
|
||||
db,
|
||||
invoice.logistics,
|
||||
tenant_id=tenant_id,
|
||||
company_id=company_id,
|
||||
)
|
||||
else:
|
||||
logistics_dict = invoice_data.logistics.model_dump()
|
||||
logistics_dict["invoice_id"] = invoice.id
|
||||
logistics_dict["tenant_id"] = tenant_id
|
||||
logistics_dict["company_id"] = company_id
|
||||
_autofill_transport_int_ids(
|
||||
db,
|
||||
logistics_dict,
|
||||
tenant_id=tenant_id,
|
||||
company_id=company_id,
|
||||
)
|
||||
new_logistics = models.InvoiceLogistics(**logistics_dict)
|
||||
db.add(new_logistics)
|
||||
|
||||
|
||||
@@ -6071,8 +6071,30 @@ def _do_insert_valid_rows(job_id: str, model_target: str, job_type_override: Opt
|
||||
transport_type = TransportType(transport_str)
|
||||
except ValueError:
|
||||
transport_type = TransportType.NONE
|
||||
|
||||
carrier_code = row_norm.get('CLAVE TRANSPORTISTA') or None
|
||||
carrier_int_id = None
|
||||
if carrier_code:
|
||||
# Internal int mapping for carrier_code -> transporter_id
|
||||
from api.v1.modules.a76.transportation.transporters.models import Transporter
|
||||
|
||||
carrier_obj = (
|
||||
session.query(Transporter)
|
||||
.filter(Transporter.transporter_key == carrier_code)
|
||||
.first()
|
||||
)
|
||||
if not carrier_obj:
|
||||
carrier_obj = Transporter(
|
||||
transporter_key=carrier_code,
|
||||
tenant_id=tenant_id,
|
||||
company_id=company_id,
|
||||
)
|
||||
session.add(carrier_obj)
|
||||
session.flush()
|
||||
carrier_int_id = carrier_obj.transporter_id
|
||||
logistics = InvoiceLogistics(
|
||||
carrier_id=(row_norm.get('CLAVE TRANSPORTISTA') or None),
|
||||
carrier_id=carrier_code,
|
||||
carrier_int_id=carrier_int_id,
|
||||
driver_name=(row_norm.get('NOMBRE CONDUCTOR') or None),
|
||||
transport_type=transport_type,
|
||||
transport_num=(row_norm.get('NUMERO TRANSPORTE') or None),
|
||||
|
||||
@@ -298,7 +298,13 @@ class ConsolidadoImportacionMexService:
|
||||
|
||||
if logistics:
|
||||
# 1. Transporter (CAAT / SCAC)
|
||||
if logistics.carrier_id:
|
||||
if logistics.carrier_int_id is not None:
|
||||
transporter_obj = (
|
||||
db.query(Transporter)
|
||||
.filter(Transporter.transporter_id == logistics.carrier_int_id)
|
||||
.first()
|
||||
)
|
||||
elif logistics.carrier_id:
|
||||
transporter_obj = (
|
||||
db.query(Transporter)
|
||||
.filter(Transporter.transporter_key == logistics.carrier_id)
|
||||
@@ -342,11 +348,18 @@ class ConsolidadoImportacionMexService:
|
||||
|
||||
# 2. Vehicle (Placas Tracto) - Try transport_id first
|
||||
if logistics.transport_id:
|
||||
veh_obj = (
|
||||
db.query(Vehicle)
|
||||
.filter(Vehicle.vehicle_key == logistics.transport_id)
|
||||
.first()
|
||||
)
|
||||
if logistics.transport_int_id is not None:
|
||||
veh_obj = (
|
||||
db.query(Vehicle)
|
||||
.filter(Vehicle.vehicle_id == logistics.transport_int_id)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
veh_obj = (
|
||||
db.query(Vehicle)
|
||||
.filter(Vehicle.vehicle_key == logistics.transport_id)
|
||||
.first()
|
||||
)
|
||||
if veh_obj:
|
||||
placas_val = veh_obj.plate_number or placas_val
|
||||
elif (
|
||||
@@ -362,11 +375,18 @@ class ConsolidadoImportacionMexService:
|
||||
|
||||
# 3. Trailer (Placas Remolque)
|
||||
if logistics.trailer_num:
|
||||
trl_obj = (
|
||||
db.query(Trailer)
|
||||
.filter(Trailer.trailer_number == logistics.trailer_num)
|
||||
.first()
|
||||
)
|
||||
if logistics.trailer_int_id is not None:
|
||||
trl_obj = (
|
||||
db.query(Trailer)
|
||||
.filter(Trailer.trailer_id == logistics.trailer_int_id)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
trl_obj = (
|
||||
db.query(Trailer)
|
||||
.filter(Trailer.trailer_number == logistics.trailer_num)
|
||||
.first()
|
||||
)
|
||||
if trl_obj:
|
||||
placas_remolque_val = trl_obj.plate_number or ""
|
||||
|
||||
|
||||
@@ -175,8 +175,16 @@ class ConsolidadoImportacionMexService:
|
||||
|
||||
if logistics:
|
||||
# 1. Transporter (CAAT / SCAC)
|
||||
if logistics.carrier_id:
|
||||
transporter_obj = db.query(Transporter).filter(Transporter.transporter_key == logistics.carrier_id).first()
|
||||
if logistics.carrier_int_id is not None:
|
||||
transporter_obj = (
|
||||
db.query(Transporter)
|
||||
.filter(Transporter.transporter_id == logistics.carrier_int_id)
|
||||
.first()
|
||||
)
|
||||
elif logistics.carrier_id:
|
||||
transporter_obj = db.query(Transporter).filter(
|
||||
Transporter.transporter_key == logistics.carrier_id
|
||||
).first()
|
||||
if transporter_obj:
|
||||
caat_val = transporter_obj.caat_code or ""
|
||||
scac_val = transporter_obj.transport_code or "" # Mapping transport_code to SCAC
|
||||
@@ -213,7 +221,16 @@ class ConsolidadoImportacionMexService:
|
||||
|
||||
# 2. Vehicle (Placas Tracto) - Try transport_id first
|
||||
if logistics.transport_id:
|
||||
veh_obj = db.query(Vehicle).filter(Vehicle.vehicle_key == logistics.transport_id).first()
|
||||
if logistics.transport_int_id is not None:
|
||||
veh_obj = (
|
||||
db.query(Vehicle)
|
||||
.filter(Vehicle.vehicle_id == logistics.transport_int_id)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
veh_obj = db.query(Vehicle).filter(
|
||||
Vehicle.vehicle_key == logistics.transport_id
|
||||
).first()
|
||||
if veh_obj:
|
||||
placas_val = veh_obj.plate_number or placas_val
|
||||
elif logistics.vehicle_num: # Fallback to vehicle_num if populated and transport_id failed/empty
|
||||
@@ -223,7 +240,16 @@ class ConsolidadoImportacionMexService:
|
||||
|
||||
# 3. Trailer (Placas Remolque)
|
||||
if logistics.trailer_num:
|
||||
trl_obj = db.query(Trailer).filter(Trailer.trailer_number == logistics.trailer_num).first()
|
||||
if logistics.trailer_int_id is not None:
|
||||
trl_obj = (
|
||||
db.query(Trailer)
|
||||
.filter(Trailer.trailer_id == logistics.trailer_int_id)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
trl_obj = db.query(Trailer).filter(
|
||||
Trailer.trailer_number == logistics.trailer_num
|
||||
).first()
|
||||
if trl_obj:
|
||||
placas_remolque_val = trl_obj.plate_number or ""
|
||||
|
||||
|
||||
@@ -317,7 +317,17 @@ class FacturaImportacionMexService:
|
||||
|
||||
if logistics:
|
||||
# 1. Transporter (CAAT / SCAC)
|
||||
if logistics.carrier_id:
|
||||
if logistics.carrier_int_id is not None:
|
||||
transporter_obj = (
|
||||
db.query(Transporter)
|
||||
.filter(Transporter.transporter_id == logistics.carrier_int_id)
|
||||
.first()
|
||||
)
|
||||
if transporter_obj:
|
||||
caat_val = transporter_obj.caat_code or ""
|
||||
scac_val = transporter_obj.transport_code or ""
|
||||
transportista_val = transporter_obj.name or logistics.carrier_id
|
||||
elif logistics.carrier_id:
|
||||
transporter_obj = (
|
||||
db.query(Transporter)
|
||||
.filter(Transporter.transporter_key == logistics.carrier_id)
|
||||
@@ -332,11 +342,18 @@ class FacturaImportacionMexService:
|
||||
|
||||
# 2. Vehicle (Placas Tracto) - Try transport_id first
|
||||
if logistics.transport_id:
|
||||
veh_obj = (
|
||||
db.query(Vehicle)
|
||||
.filter(Vehicle.vehicle_key == logistics.transport_id)
|
||||
.first()
|
||||
)
|
||||
if logistics.transport_int_id is not None:
|
||||
veh_obj = (
|
||||
db.query(Vehicle)
|
||||
.filter(Vehicle.vehicle_id == logistics.transport_int_id)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
veh_obj = (
|
||||
db.query(Vehicle)
|
||||
.filter(Vehicle.vehicle_key == logistics.transport_id)
|
||||
.first()
|
||||
)
|
||||
if veh_obj:
|
||||
placas_val = veh_obj.plate_number or placas_val
|
||||
elif (
|
||||
@@ -352,11 +369,18 @@ class FacturaImportacionMexService:
|
||||
|
||||
# 3. Trailer (Placas Remolque)
|
||||
if logistics.trailer_num:
|
||||
trl_obj = (
|
||||
db.query(Trailer)
|
||||
.filter(Trailer.trailer_number == logistics.trailer_num)
|
||||
.first()
|
||||
)
|
||||
if logistics.trailer_int_id is not None:
|
||||
trl_obj = (
|
||||
db.query(Trailer)
|
||||
.filter(Trailer.trailer_id == logistics.trailer_int_id)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
trl_obj = (
|
||||
db.query(Trailer)
|
||||
.filter(Trailer.trailer_number == logistics.trailer_num)
|
||||
.first()
|
||||
)
|
||||
if trl_obj:
|
||||
placas_remolque_val = trl_obj.plate_number or ""
|
||||
|
||||
|
||||
@@ -166,8 +166,16 @@ class FacturaImportacionMexService:
|
||||
|
||||
if logistics:
|
||||
# 1. Transporter (CAAT / SCAC)
|
||||
if logistics.carrier_id:
|
||||
transporter_obj = db.query(Transporter).filter(Transporter.transporter_key == logistics.carrier_id).first()
|
||||
if logistics.carrier_int_id is not None:
|
||||
transporter_obj = (
|
||||
db.query(Transporter)
|
||||
.filter(Transporter.transporter_id == logistics.carrier_int_id)
|
||||
.first()
|
||||
)
|
||||
elif logistics.carrier_id:
|
||||
transporter_obj = db.query(Transporter).filter(
|
||||
Transporter.transporter_key == logistics.carrier_id
|
||||
).first()
|
||||
if transporter_obj:
|
||||
caat_val = transporter_obj.caat_code or ""
|
||||
scac_val = transporter_obj.transport_code or "" # Mapping transport_code to SCAC
|
||||
@@ -175,7 +183,16 @@ class FacturaImportacionMexService:
|
||||
|
||||
# 2. Vehicle (Placas Tracto) - Try transport_id first
|
||||
if logistics.transport_id:
|
||||
veh_obj = db.query(Vehicle).filter(Vehicle.vehicle_key == logistics.transport_id).first()
|
||||
if logistics.transport_int_id is not None:
|
||||
veh_obj = (
|
||||
db.query(Vehicle)
|
||||
.filter(Vehicle.vehicle_id == logistics.transport_int_id)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
veh_obj = db.query(Vehicle).filter(
|
||||
Vehicle.vehicle_key == logistics.transport_id
|
||||
).first()
|
||||
if veh_obj:
|
||||
placas_val = veh_obj.plate_number or placas_val
|
||||
elif logistics.vehicle_num: # Fallback to vehicle_num if populated and transport_id failed/empty
|
||||
@@ -185,7 +202,16 @@ class FacturaImportacionMexService:
|
||||
|
||||
# 3. Trailer (Placas Remolque)
|
||||
if logistics.trailer_num:
|
||||
trl_obj = db.query(Trailer).filter(Trailer.trailer_number == logistics.trailer_num).first()
|
||||
if logistics.trailer_int_id is not None:
|
||||
trl_obj = (
|
||||
db.query(Trailer)
|
||||
.filter(Trailer.trailer_id == logistics.trailer_int_id)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
trl_obj = db.query(Trailer).filter(
|
||||
Trailer.trailer_number == logistics.trailer_num
|
||||
).first()
|
||||
if trl_obj:
|
||||
placas_remolque_val = trl_obj.plate_number or ""
|
||||
|
||||
|
||||
@@ -317,7 +317,17 @@ class FacturaImportacionUsaService:
|
||||
|
||||
if logistics:
|
||||
# 1. Transporter (CAAT / SCAC)
|
||||
if logistics.carrier_id:
|
||||
if logistics.carrier_int_id is not None:
|
||||
transporter_obj = (
|
||||
db.query(Transporter)
|
||||
.filter(Transporter.transporter_id == logistics.carrier_int_id)
|
||||
.first()
|
||||
)
|
||||
if transporter_obj:
|
||||
caat_val = transporter_obj.caat_code or ""
|
||||
scac_val = transporter_obj.transport_code or ""
|
||||
transportista_val = transporter_obj.name or logistics.carrier_id
|
||||
elif logistics.carrier_id:
|
||||
transporter_obj = (
|
||||
db.query(Transporter)
|
||||
.filter(Transporter.transporter_key == logistics.carrier_id)
|
||||
@@ -325,18 +335,23 @@ class FacturaImportacionUsaService:
|
||||
)
|
||||
if transporter_obj:
|
||||
caat_val = transporter_obj.caat_code or ""
|
||||
scac_val = (
|
||||
transporter_obj.transport_code or ""
|
||||
) # Mapping transport_code to SCAC
|
||||
scac_val = transporter_obj.transport_code or ""
|
||||
transportista_val = transporter_obj.name or logistics.carrier_id
|
||||
|
||||
# 2. Vehicle (Plates)
|
||||
if logistics.transport_id:
|
||||
veh_obj = (
|
||||
db.query(Vehicle)
|
||||
.filter(Vehicle.vehicle_key == logistics.transport_id)
|
||||
.first()
|
||||
)
|
||||
if logistics.transport_int_id is not None:
|
||||
veh_obj = (
|
||||
db.query(Vehicle)
|
||||
.filter(Vehicle.vehicle_id == logistics.transport_int_id)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
veh_obj = (
|
||||
db.query(Vehicle)
|
||||
.filter(Vehicle.vehicle_key == logistics.transport_id)
|
||||
.first()
|
||||
)
|
||||
if veh_obj:
|
||||
placas_val = veh_obj.plate_number or placas_val
|
||||
elif logistics.vehicle_num:
|
||||
@@ -350,11 +365,18 @@ class FacturaImportacionUsaService:
|
||||
|
||||
# 3. Trailer
|
||||
if logistics.trailer_num:
|
||||
trl_obj = (
|
||||
db.query(Trailer)
|
||||
.filter(Trailer.trailer_number == logistics.trailer_num)
|
||||
.first()
|
||||
)
|
||||
if logistics.trailer_int_id is not None:
|
||||
trl_obj = (
|
||||
db.query(Trailer)
|
||||
.filter(Trailer.trailer_id == logistics.trailer_int_id)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
trl_obj = (
|
||||
db.query(Trailer)
|
||||
.filter(Trailer.trailer_number == logistics.trailer_num)
|
||||
.first()
|
||||
)
|
||||
if trl_obj:
|
||||
placas_remolque_val = trl_obj.plate_number or ""
|
||||
|
||||
|
||||
@@ -186,8 +186,18 @@ class PackingListService:
|
||||
|
||||
if logistics:
|
||||
# 1. Transporter (CAAT / SCAC)
|
||||
if logistics.carrier_id:
|
||||
transporter_obj = db.query(Transporter).filter(Transporter.transporter_key == logistics.carrier_id).first()
|
||||
if logistics.carrier_int_id is not None:
|
||||
transporter_obj = (
|
||||
db.query(Transporter)
|
||||
.filter(Transporter.transporter_id == logistics.carrier_int_id)
|
||||
.first()
|
||||
)
|
||||
elif logistics.carrier_id:
|
||||
transporter_obj = (
|
||||
db.query(Transporter)
|
||||
.filter(Transporter.transporter_key == logistics.carrier_id)
|
||||
.first()
|
||||
)
|
||||
if transporter_obj:
|
||||
caat_val = transporter_obj.caat_code or ""
|
||||
scac_val = transporter_obj.transport_code or ""
|
||||
@@ -195,7 +205,18 @@ class PackingListService:
|
||||
|
||||
# 2. Vehicle (Placas Tracto)
|
||||
if logistics.transport_id:
|
||||
veh_obj = db.query(Vehicle).filter(Vehicle.vehicle_key == logistics.transport_id).first()
|
||||
if logistics.transport_int_id is not None:
|
||||
veh_obj = (
|
||||
db.query(Vehicle)
|
||||
.filter(Vehicle.vehicle_id == logistics.transport_int_id)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
veh_obj = (
|
||||
db.query(Vehicle)
|
||||
.filter(Vehicle.vehicle_key == logistics.transport_id)
|
||||
.first()
|
||||
)
|
||||
if veh_obj:
|
||||
placas_val = veh_obj.plate_number or placas_val
|
||||
elif logistics.vehicle_num:
|
||||
@@ -205,7 +226,18 @@ class PackingListService:
|
||||
|
||||
# 3. Trailer (Placas Remolque)
|
||||
if logistics.trailer_num:
|
||||
trl_obj = db.query(Trailer).filter(Trailer.trailer_number == logistics.trailer_num).first()
|
||||
if logistics.trailer_int_id is not None:
|
||||
trl_obj = (
|
||||
db.query(Trailer)
|
||||
.filter(Trailer.trailer_id == logistics.trailer_int_id)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
trl_obj = (
|
||||
db.query(Trailer)
|
||||
.filter(Trailer.trailer_number == logistics.trailer_num)
|
||||
.first()
|
||||
)
|
||||
if trl_obj:
|
||||
placas_remolque_val = trl_obj.plate_number or ""
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ from pydantic import BaseModel
|
||||
|
||||
class DriverBaseDTO(BaseModel):
|
||||
transporter_key: str
|
||||
driver_id: Optional[int] = None
|
||||
line: int
|
||||
driver_name: Optional[str] = None
|
||||
license_number: Optional[str] = None
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
|
||||
from core.database import Base
|
||||
from sqlalchemy import Column, ForeignKey, ForeignKeyConstraint, Integer, String
|
||||
from sqlalchemy import BigInteger, Column, ForeignKey, ForeignKeyConstraint, Integer, String
|
||||
|
||||
|
||||
class Driver(Base, TenantScopedMixin, TimestampMixin):
|
||||
@@ -16,6 +16,8 @@ class Driver(Base, TenantScopedMixin, TimestampMixin):
|
||||
nullable=False,
|
||||
)
|
||||
line = Column(Integer, primary_key=True, nullable=False)
|
||||
# Internal integer surrogate ID. The frontend continues to use transporter_key/line.
|
||||
driver_id = Column(BigInteger, nullable=False, unique=True, index=True)
|
||||
driver_name = Column(String(80), nullable=True)
|
||||
license_number = Column(String(29), nullable=True)
|
||||
express_line_id = Column(String(17), nullable=True)
|
||||
|
||||
@@ -5,6 +5,7 @@ from pydantic import BaseModel, Field
|
||||
|
||||
class TrailerBaseDTO(BaseModel):
|
||||
trailer_number: str = Field(..., description="Trailer number (primary identifier)")
|
||||
trailer_id: Optional[int] = Field(None, description="Internal trailer integer ID")
|
||||
ace_trailer_number: Optional[str] = None
|
||||
trailer_type_key: Optional[str] = None
|
||||
seal: Optional[str] = None
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
|
||||
from core.database import Base
|
||||
from sqlalchemy import Column, ForeignKey, ForeignKeyConstraint, String
|
||||
from sqlalchemy import BigInteger, Column, ForeignKey, ForeignKeyConstraint, String
|
||||
|
||||
|
||||
class Trailer(Base, TenantScopedMixin, TimestampMixin):
|
||||
@@ -10,6 +10,8 @@ class Trailer(Base, TenantScopedMixin, TimestampMixin):
|
||||
)
|
||||
|
||||
trailer_number = Column(String(20), primary_key=True, nullable=False)
|
||||
# Internal integer identifier (surrogate). The frontend continues to use trailer_number.
|
||||
trailer_id = Column(BigInteger, nullable=False, unique=True, index=True)
|
||||
ace_trailer_number = Column(String(10), nullable=True)
|
||||
trailer_type_key = Column(
|
||||
String(2), ForeignKey("public.trailer_type.trailer_type_key"), nullable=True
|
||||
|
||||
@@ -5,6 +5,7 @@ from pydantic import BaseModel, Field
|
||||
|
||||
class TransporterBaseDTO(BaseModel):
|
||||
transporter_key: str = Field(..., description="Transporter key (primary identifier)")
|
||||
transporter_id: Optional[int] = Field(None, description="Internal transporter integer ID")
|
||||
name: Optional[str] = None
|
||||
short_name: Optional[str] = None
|
||||
responsible: Optional[str] = None
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
|
||||
from core.database import Base
|
||||
from sqlalchemy import Column, ForeignKeyConstraint, String
|
||||
from sqlalchemy import BigInteger, Column, ForeignKeyConstraint, String
|
||||
|
||||
|
||||
class Transporter(Base, TenantScopedMixin, TimestampMixin):
|
||||
@@ -10,6 +10,8 @@ class Transporter(Base, TenantScopedMixin, TimestampMixin):
|
||||
)
|
||||
|
||||
transporter_key = Column(String(23), primary_key=True, nullable=False)
|
||||
# Internal integer identifier (surrogate). The frontend continues to use transporter_key.
|
||||
transporter_id = Column(BigInteger, nullable=False, unique=True, index=True)
|
||||
name = Column(String(256), nullable=True)
|
||||
short_name = Column(String(10), nullable=True)
|
||||
responsible = Column(String(100), nullable=True)
|
||||
|
||||
@@ -5,6 +5,7 @@ from pydantic import BaseModel, Field
|
||||
|
||||
class VehicleBaseDTO(BaseModel):
|
||||
vehicle_key: str = Field(..., description="Vehicle key (primary identifier)")
|
||||
vehicle_id: Optional[int] = Field(None, description="Internal vehicle integer ID")
|
||||
ace_vehicle_key: Optional[str] = None
|
||||
transporter_key: Optional[str] = None
|
||||
transport_identifier: Optional[str] = None
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
|
||||
from core.database import Base
|
||||
from sqlalchemy import DECIMAL, Column, Integer, String
|
||||
from sqlalchemy import DECIMAL, Column, Integer, BigInteger, String
|
||||
|
||||
|
||||
class Vehicle(Base, TenantScopedMixin, TimestampMixin):
|
||||
@@ -10,6 +10,8 @@ class Vehicle(Base, TenantScopedMixin, TimestampMixin):
|
||||
)
|
||||
|
||||
vehicle_key = Column(String(14), primary_key=True, nullable=False)
|
||||
# Internal integer identifier (surrogate). The frontend continues to use vehicle_key.
|
||||
vehicle_id = Column(BigInteger, nullable=False, unique=True, index=True)
|
||||
ace_vehicle_key = Column(String(10), nullable=True)
|
||||
transporter_key = Column(String(23), nullable=True)
|
||||
transport_identifier = Column(String(30), nullable=True)
|
||||
|
||||
Reference in New Issue
Block a user