From af9be8d0b5f0c5b363619de9e671cc2c38f719f6 Mon Sep 17 00:00:00 2001 From: Galindo97 Date: Tue, 24 Feb 2026 09:23:07 -0600 Subject: [PATCH] feat: Refine invoice report queries to handle empty concatenated transport data and adjust subpartida logic for peso calculation. --- .../movements/invoices/services/export.py | 74 +++++++++---------- .../invoices/services/export_repair.py | 6 +- .../invoices/services/query_builders.py | 16 ++-- .../movements/invoices/services/temporary.py | 4 +- 4 files changed, 50 insertions(+), 50 deletions(-) diff --git a/backend/api/v1/modules/a76/reports/movements/invoices/services/export.py b/backend/api/v1/modules/a76/reports/movements/invoices/services/export.py index 17ceb6f9..de65c9db 100644 --- a/backend/api/v1/modules/a76/reports/movements/invoices/services/export.py +++ b/backend/api/v1/modules/a76/reports/movements/invoices/services/export.py @@ -64,13 +64,13 @@ class ExportService: for row in results: factura = row[0] # C1 - FacturaExpo - tipo_mov = row[15] # C34 - TipoFactura + tipo_mov = row[14] # C34 - TipoFactura # Skip cancelled if not included if not filters.include_cancelled and row[3] != 'AC': # C6 - Estatus continue - consecutivo = row[16] # C35 - Consecutivo + consecutivo = row[15] # C35 - Consecutivo # Totals come directly from GROUP BY query (no N+1 problem) def to_float(val): @@ -78,10 +78,10 @@ class ExportService: try: return float(val) except (ValueError, TypeError): return 0.0 - total_me = to_float(row[24]) # total_me from SUM aggregation - total_mn = to_float(row[25]) # total_mn from SUM aggregation - sum_value_usd = to_float(row[27]) - sum_value_mxn = to_float(row[28]) + total_me = to_float(row[23]) # total_me from SUM aggregation + total_mn = to_float(row[24]) # total_mn from SUM aggregation + sum_value_usd = to_float(row[26]) + sum_value_mxn = to_float(row[27]) total_me = sum_value_usd if sum_value_usd > 0 else total_me total_mn = sum_value_mxn if sum_value_mxn > 0 else total_mn @@ -92,9 +92,9 @@ class ExportService: db_name=filters.database_name, valor_me=total_me, valor_mn=total_mn, - tipo_cambio_db=row[19], # C48 - TipoCambio - fecha_pago=row[8], # C11 - Fecha_Pago - fecha_inicio=row[6], # C9 - Fecha_Inicio + tipo_cambio_db=row[18], # C48 - TipoCambio + fecha_pago=row[7], # C11 - Fecha_Pago + fecha_inicio=row[6], # C10 - Fecha_Inicio (mapped previously to C9) tipo_pedimento='', # Not in aggregated query currency_type=filters.currency_type.value, exchange_rate_type=filters.exchange_rate_type.value, @@ -107,7 +107,7 @@ class ExportService: rectified_pedimento = DatabaseHelper.get_rectification_pedimento( db, row[1], # C2 - PedimentoExpo - row[26], # C54 - PedRectifica + row[25], # C54 - PedRectifica filters.is_shelter ) @@ -126,19 +126,19 @@ class ExportService: ValorMPTemp=valor_comercial, ValorComercialMN=valor_comercial, TipoCambio=tipo_cambio, - ValorAgre=0.0, + ValorAgre=to_float(row[28]), TipoExpo='EXPO DEF', PedimentoR1=rectified_pedimento, - EDocument=row[17], # C40 - EDocument - NumOperacionVU=row[18], # C41 - NumOperacionVU + EDocument=row[16], # C40 - EDocument + NumOperacionVU=row[17], # C41 - NumOperacionVU BaseDeDatos=filters.database_name, NumGafUni=driver_badge, - UsuarioCap=row[21], # C50 - UsuarioCap - UsuarioAcr=row[22], # C51 - UsuarioAct - Fecha_Pago=parse_yyyymmdd_date(row[8]), # C11 - Fecha_Pago - NumCaja=row[23], # C53 - Transporte + NumTrasporte + UsuarioCap=row[20], # C50 - UsuarioCap + UsuarioAcr=row[21], # C51 - UsuarioAct + Fecha_Pago=parse_yyyymmdd_date(row[7]), # C11 - Fecha_Pago + NumCaja=row[22], # C53 - Transporte + NumTrasporte Pedimento18='', # Not in aggregated query - AduanaCru=row[14], # C33 - Aduana_Cruce + AduanaCru=row[13], # C33 - Aduana_Cruce Lote='' # Not in aggregated query ) @@ -231,9 +231,9 @@ class ExportService: met_trans=met_trans ) - # Set peso values based on subpartida flag - peso_neto_final = row[24] if row[37] == 'P' else 0 # C25 - PesoNeto - peso_bruto_final = row[25] if row[37] == 'P' else 0 # C26 - PesoBruto + # Set peso values (material_type is typically 'PT' or 'MP', not just 'P') + peso_neto_final = row[24] if row[37] != 'S' else 0 # C25 - PesoNeto + peso_bruto_final = row[25] if row[37] != 'S' else 0 # C26 - PesoBruto # Get series information series_info = DatabaseHelper.get_series_info_export( @@ -253,7 +253,7 @@ class ExportService: # Build detailed movement item movement = MovementItemDetailed( - Linea=row[39], # C42 - LineaExpo + Linea=row[41], # C42 - LineaExpo Factura=row[0], # C1 - FacturaExpo Pedimento=row[1], # C2 - PedimentoExpo FechaFactura=row[2], # C3 - FechaFactura @@ -289,26 +289,26 @@ class ExportService: Sector=row[30], # C31 - Sector PaisOrigen=row[31], # C32 - PaisOrigen Aduana=customs_name, - Advalorem=row[27], # C30 - Advalorem + Advalorem=row[29], # C30 - Advalorem TipoExpo='EXPO DEF', PedimentoR1=rectified_pedimento, - EDocument=row[37], # C40 - EDocument - NumOperacionVU=row[38], # C41 - NumOperacionVU + EDocument=row[39], # C40 - EDocument + NumOperacionVU=row[40], # C41 - NumOperacionVU Series=series_info, - Marca=StringHelper.clean_text(row[40]), # C43 - Marca - Modelo=StringHelper.clean_text(row[41]), # C44 - Modelo - FraccionAmericana=row[42], # C45 - FraccionAme - ECCN=row[43], # C46 - ECCN - FechaEmision=parse_yyyymmdd_date(row[46]) if row[46] else None, # C49 - FechaEmision + Marca=StringHelper.clean_text(row[42]), # C43 - Marca + Modelo=StringHelper.clean_text(row[43]), # C44 - Modelo + FraccionAmericana=row[44], # C45 - FraccionAme + ECCN=row[45], # C46 - ECCN + FechaEmision=parse_yyyymmdd_date(row[48]) if row[48] else None, # C49 - FechaEmision BaseDeDatos=filters.database_name, NumGafUni=driver_badge, - UsuarioCap=row[47], # C50 - UsuarioCap - UsuarioAcr=row[48], # C51 - UsuarioAct - Transportista=row[49], # C52 - Carrier ID (derived from log.transport_id) - NumCaja=row[50], # C53 - log.transport_id || log.transport_num - Pedimento18=row[51], # C54 - empty - AduanaCru=row[30], # C33 - Aduana_Cruce - Lote=row[52] if len(row) > 52 else '' # C55 - Lote + UsuarioCap=row[49], # C50 - UsuarioCap + UsuarioAcr=row[50], # C51 - UsuarioAct + Transportista=row[51], # C52 - Carrier ID (derived from log.transport_id) + NumCaja=row[52], # C53 - log.transport_id || log.transport_num + Pedimento18=row[53], # C54 - empty + AduanaCru=row[32], # C33 - Aduana_Cruce + Lote=row[54] if len(row) > 54 else '' # C55 - Lote ) diff --git a/backend/api/v1/modules/a76/reports/movements/invoices/services/export_repair.py b/backend/api/v1/modules/a76/reports/movements/invoices/services/export_repair.py index 98b33a0f..63704ddd 100644 --- a/backend/api/v1/modules/a76/reports/movements/invoices/services/export_repair.py +++ b/backend/api/v1/modules/a76/reports/movements/invoices/services/export_repair.py @@ -155,7 +155,7 @@ class ExportRepairService: ValorMPTemp=valor_comercial, ValorComercialMN=valor_comercial, TipoCambio=tipo_cambio, - ValorAgre=0.0, + ValorAgre=to_float(row[29]), TipoExpo='EXPO REP', PedimentoR1=pedimento_r1, EDocument=row[16], # C40 - EDocument ← FIXED (was 17) @@ -245,8 +245,8 @@ class ExportRepairService: db, filters.database_name, row[32] # C33 - Aduana_Cruce ) - # Calculate values (only for main partidas 'P') - if row[37] == 'P': # C38 - EsSubPartida + # Set peso values based on subpartida flag (allow 'PT', 'MP', etc. but block 'S') + if row[37] != 'S': # C38 - EsSubPartida valor_comercial, tipo_cambio = ExchangeRateCalculator.calculate_for_partida( db=db, db_name=filters.database_name, diff --git a/backend/api/v1/modules/a76/reports/movements/invoices/services/query_builders.py b/backend/api/v1/modules/a76/reports/movements/invoices/services/query_builders.py index 6e14c659..7b2d7fdb 100644 --- a/backend/api/v1/modules/a76/reports/movements/invoices/services/query_builders.py +++ b/backend/api/v1/modules/a76/reports/movements/invoices/services/query_builders.py @@ -41,7 +41,7 @@ class TemporaryImportQueries: COALESCE(ih.capture_user, '') AS C52, COALESCE(ih.who_updated, '') AS C53, COALESCE(log.carrier_id, '') AS C54, - COALESCE(log.transport_num || ' ' || log.license_plate, '') AS C55, + COALESCE(NULLIF(CONCAT_WS(' ', log.transport_num, log.license_plate), ''), '') AS C55, '' AS C56, '' AS C57, '' AS C58, @@ -147,7 +147,7 @@ class TemporaryImportQueries: COALESCE(ih.capture_user, '') AS C52, COALESCE(ih.who_updated, '') AS C53, COALESCE(log.carrier_id, '') AS C54, - COALESCE(log.transport_num || ' ' || log.license_plate, '') AS C55, + COALESCE(NULLIF(CONCAT_WS(' ', log.transport_num, log.license_plate), ''), '') AS C55, '' AS C56, COALESCE(ld.lot, '') AS C57, '' AS C58, @@ -255,7 +255,7 @@ class DefinitiveImportQueries: COALESCE(TO_CHAR(ih.emission_date, 'YYYYMMDD'), '') AS C52, COALESCE(ih.capture_user, '') AS C53, COALESCE(ih.who_updated, '') AS C54, - COALESCE(log.transport_id || ' ' || log.transport_num, '') AS C56, + COALESCE(NULLIF(CONCAT_WS(' ', log.transport_id, log.transport_num), ''), '') AS C56, '' AS C57, '' AS C58, '' AS C59, @@ -354,7 +354,7 @@ class DefinitiveImportQueries: COALESCE(ih.capture_user, '') AS C52, COALESCE(ih.who_updated, '') AS C53, COALESCE(log.carrier_id, '') AS C54, - COALESCE(log.transport_id || ' ' || log.transport_num, '') AS C55, + COALESCE(NULLIF(CONCAT_WS(' ', log.transport_id, log.transport_num), ''), '') AS C55, '' AS C56, COALESCE(ld.lot, '') AS C57, '' AS C58, @@ -683,7 +683,7 @@ class ExportQueries: COALESCE(TO_CHAR(ih.emission_date, 'YYYYMMDD'), '') AS C49, COALESCE(ih.capture_user, '') AS C50, COALESCE(ih.who_updated, '') AS C51, - COALESCE(log.transport_id || ' ' || log.transport_num, '') AS C53, + COALESCE(NULLIF(CONCAT_WS(' ', log.transport_id, log.transport_num), ''), '') AS C53, COALESCE(fin.value_me, 0) AS total_me, COALESCE(fin.value_mn, 0) AS total_mn, COALESCE( @@ -777,7 +777,7 @@ class ExportQueries: ih.capture_user AS C50, -- [49] ih.who_updated AS C51, -- [50] '' AS C52, -- [51] - COALESCE(log.transport_id || ' ' || log.transport_num, '') AS C53, -- [52] NumCaja + COALESCE(NULLIF(CONCAT_WS(' ', log.transport_id, log.transport_num), ''), '') AS C53, -- [52] NumCaja '' AS C54, -- [53] Pedimento18 COALESCE(ld.lot, '') AS C55, -- [54] Lote '' AS C56, -- [55] TipoPedimentoTransporte @@ -894,7 +894,7 @@ class ExportRepairQueries: COALESCE(ih.capture_user, '') AS C50, COALESCE(ih.who_updated, '') AS C51, COALESCE(log.carrier_id, '') AS C52, - COALESCE(log.transport_id || ' ' || log.transport_num, '') AS C53, + COALESCE(NULLIF(CONCAT_WS(' ', log.transport_id, log.transport_num), ''), '') AS C53, COALESCE(fin.value_me, 0) AS total_me, COALESCE(fin.value_mn, 0) AS total_mn, COALESCE( @@ -994,7 +994,7 @@ class ExportRepairQueries: COALESCE(ih.capture_user, '') AS C50, COALESCE(ih.who_updated, '') AS C51, COALESCE(log.carrier_id, '') AS C52, - COALESCE(log.transport_id || ' ' || log.transport_num, '') AS C53, + COALESCE(NULLIF(CONCAT_WS(' ', log.transport_id, log.transport_num), ''), '') AS C53, '' AS C54, COALESCE(ld.lot, '') AS C55, '' AS C56, diff --git a/backend/api/v1/modules/a76/reports/movements/invoices/services/temporary.py b/backend/api/v1/modules/a76/reports/movements/invoices/services/temporary.py index 40ae067c..1e3faa70 100644 --- a/backend/api/v1/modules/a76/reports/movements/invoices/services/temporary.py +++ b/backend/api/v1/modules/a76/reports/movements/invoices/services/temporary.py @@ -285,8 +285,8 @@ class TemporaryImportService: # Assign the properly converted commercial value directly valor_comercial_mn = float(valor_comercial) - # Set peso values based on subpartida flag - if row[39] == 'P': # C40 - EsSubPartida + # Set peso values based on subpartida flag (allow 'PT', 'MP', etc. but block 'S') + if row[39] != 'S': # C40 - EsSubPartida peso_neto = float(row[28]) if row[28] else 0.0 # C29 peso_bruto = float(row[29]) if row[29] else 0.0 # C30 else: