feat: fixes estructuras SCAII partidas y encabezado (requerimiento Marisol)

- Fracción arancelaria 10 dígitos (Fraccion+SubdivisionFraccion)
- LINEA = SecuenciaFraccion del R551
- Peso neto/bruto calculado desde PesoBrutoMercancia R501 con distribución proporcional
- UM mapeada al catálogo SCAII (22 claves)
- NUMERO FACTURA formato SS-PPPP-NNNNNNN en partidas y encabezado
- NOT EXISTS en encabezado para excluir pedimentos rectificados (R701)
- DISTINCT en encabezado_facturas_ds y cat_pedimentos_ds para evitar duplicados

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-22 17:48:51 -05:00
parent 71ef0b390a
commit 4c85daf0f2

View File

@@ -17848,7 +17848,7 @@
" substr(HR.\"SeccionAduanera\", 1, 2) || '-' ||\n",
" HR.\"Patente\" || '-' || HR.\"Pedimento\")\n",
" )\n",
" SELECT\n",
" SELECT DISTINCT\n",
" (substr(Q1.\"FechaPagoReal\", 3, 2) || '-' ||\n",
" substr(Q1.\"SeccionAduanera\", 1, 2) || '-' ||\n",
" Q1.\"Patente\" || '-' || Q1.\"Pedimento\") AS \"PEDIMENTO\",\n",
@@ -17908,7 +17908,7 @@
" operacion tomado de Registro501 que lo origino.\n",
" Migrado de generar_estructuracatScaf.php.\"\"\"\n",
" sql = \"\"\"\n",
" SELECT\n",
" SELECT DISTINCT\n",
" (substr(Q1.\"FechaPagoReal\", 3, 2) || '-' ||\n",
" substr(Q1.\"SeccionAduanera\", 1, 2) || '-' ||\n",
" Q1.\"Patente\" || '-' || Q1.\"Pedimento\") AS \"PEDIMENTO\",\n",
@@ -18069,17 +18069,8 @@
" substr(Q1.\"SeccionAduanera\", 1, 2) || '-' ||\n",
" Q1.\"Patente\" || '-' || Q1.\"Pedimento\") AS \"PEDIMENTO\",\n",
" '1' AS \"REMESA\",\n",
" CASE WHEN EXISTS (\n",
" SELECT 1 FROM historial_rect H\n",
" WHERE (substr(H.\"FechaOperacionAnterior\", 3, 2) || '-' ||\n",
" substr(H.\"SeccionAduaneraAnterior\", 1, 2) || '-' ||\n",
" H.\"PatenteAnterior\" || '-' || H.\"PedimentoAnterior\")\n",
" = (substr(Q1.\"FechaPagoReal\", 3, 2) || '-' ||\n",
" substr(Q1.\"SeccionAduanera\", 1, 2) || '-' ||\n",
" Q1.\"Patente\" || '-' || Q1.\"Pedimento\")\n",
" ) THEN Q1.\"Pedimento\" || '-' || 'R1'\n",
" ELSE Q1.\"Pedimento\" || '-' || Q1.\"ClaveDocumento\"\n",
" END AS \"NUMERO FACTURA\",\n",
" (substr(Q1.\"SeccionAduanera\", 1, 2) || '-' ||\n",
" Q1.\"Patente\" || '-' || Q1.\"Pedimento\") AS \"NUMERO FACTURA\",\n",
" Q1.\"FechaPagoReal\" AS \"FECHA FACTURA\",\n",
" Q1.\"TipoCambio\" AS \"TIPO DE CAMBIO\",\n",
" '1' AS \"CLAVE PROVEEDOR\",\n",
@@ -18114,9 +18105,9 @@
" WHERE (substr(Q1.\"FechaPagoReal\", 3, 2) || '-' ||\n",
" substr(Q1.\"SeccionAduanera\", 1, 2) || '-' ||\n",
" Q1.\"Patente\" || '-' || Q1.\"Pedimento\")\n",
" = (substr(R7.\"FechaPagoReal\", 3, 2) || '-' ||\n",
" = (substr(R7.\"FechaOperacionAnterior\", 3, 2) || '-' ||\n",
" substr(R7.\"SeccionAduaneraAnterior\", 1, 2) || '-' ||\n",
" R7.\"PatenteAnterior\" || '-' || R7.\"Pedimento\")\n",
" R7.\"PatenteAnterior\" || '-' || R7.\"PedimentoAnterior\")\n",
" )\n",
" ORDER BY Q1.\"FechaPagoReal\" ASC\n",
" \"\"\"\n",
@@ -18198,9 +18189,30 @@
"# ============================================================\n",
"\n",
"_UM_MAP_551 = {\n",
" 1: 'KGS', 2: 'GR', 3: 'CM', 4: 'CM2', 5: 'BD FT', 6: 'PZA',\n",
" 7: 'CBZA',8: 'LT', 9: 'PAR', 12:'JGO',14:'TON', 17:'DEC',\n",
" 18:'CIEN',19:'DOCE',20:'CAJA',21:'BTL',22:'CARAT'\n",
" # Catalogo de Unidades de Medida (clave numerica -> sigla SCAII)\n",
" # Fuente: Catalogo de UM de la Aduana Mexicana\n",
" 1: 'KGS', # Kilo\n",
" 2: 'GR', # Gramo\n",
" 3: 'MT', # Metro Lineal\n",
" 4: 'M2', # Metro Cuadrado\n",
" 5: 'M3', # Metro Cubico\n",
" 6: 'PZA', # Pieza\n",
" 7: 'PZA', # Cabeza\n",
" 8: 'LT', # Litro\n",
" 9: 'PAR', # Par\n",
" 10: '', # Kilowatt (sin UM SCAII)\n",
" 11: 'MILLR', # Millar\n",
" 12: 'JGO', # Juego\n",
" 13: '', # Kilowatt/Hora (sin UM SCAII)\n",
" 14: 'TON', # Tonelada\n",
" 15: 'BARR', # Barril\n",
" 16: '', # Gramo Neto (sin UM SCAII)\n",
" 17: 'DEC', # Decenas\n",
" 18: 'CIEN', # Cientos\n",
" 19: 'DOCE', # Docenas\n",
" 20: 'CAJA', # Caja\n",
" 21: 'PZA', # Botella\n",
" 22: 'CARAT', # Carat\n",
"}\n",
"\n",
"\n",
@@ -18330,6 +18342,7 @@
" Q1.\"Pedimento\" AS pedimento,\n",
" Q1.\"SeccionAduanera\" AS seccion_aduanera,\n",
" Q1.\"Fraccion\" AS fraccion,\n",
" Q1.\"SubdivisionFraccion\" AS subdivision_fraccion,\n",
" Q1.\"SecuenciaFraccion\" AS secuencia_fraccion,\n",
" Q1.\"DescripcionMercancia\" AS descripcion_mercancia,\n",
" Q1.\"PrecioUnitario\" AS precio_unitario,\n",
@@ -18356,6 +18369,11 @@
" AND R501i.\"Pedimento\" = Q1.\"Pedimento\"\n",
" AND R501i.\"SeccionAduanera\" = Q1.\"SeccionAduanera\"\n",
" LIMIT 1) AS tipo_cambio_501,\n",
" (SELECT R501i.\"PesoBrutoMercancia\" FROM \"Registro501\" R501i\n",
" WHERE R501i.\"Patente\" = Q1.\"Patente\"\n",
" AND R501i.\"Pedimento\" = Q1.\"Pedimento\"\n",
" AND R501i.\"SeccionAduanera\" = Q1.\"SeccionAduanera\"\n",
" LIMIT 1) AS peso_bruto_501,\n",
" CASE WHEN EXISTS (\n",
" SELECT 1 FROM \"Registro701\" R7\n",
" WHERE (substr(Q1.\"FechaPagoReal\", 3, 2) || '-' ||\n",
@@ -18378,7 +18396,7 @@
" # Dedupe defensivo: si el Registro551 se cargo N veces, no multiplicar partidas\n",
" antes = len(df)\n",
" df = df.drop_duplicates(\n",
" subset=['patente', 'pedimento', 'seccion_aduanera', 'fraccion', 'secuencia_fraccion'],\n",
" subset=['patente', 'pedimento', 'seccion_aduanera', 'fraccion', 'subdivision_fraccion', 'secuencia_fraccion'],\n",
" keep='first').reset_index(drop=True)\n",
" dups = antes - len(df)\n",
" if dups > 0:\n",
@@ -18505,7 +18523,11 @@
" lambda r: 'R1' if r['rectificado'] == 1\n",
" else (r['clave_documento_501'] or r['clave_documento_551'] or ''),\n",
" axis=1)\n",
" df['factura'] = df['pedimento'].astype(str).str.zfill(7).str[-7:] + '-' + df['clave_eff'].fillna('')\n",
" # NUMERO FACTURA = pedimento a 15 digitos: SS-PPPP-NNNNNNN (sin clave)\n",
" df['ped_15'] = (df['seccion_aduanera'].astype(str).str[:2]\n",
" + '-' + df['patente'].astype(str).str.zfill(4)\n",
" + '-' + df['pedimento'].astype(str).str.zfill(7).str[-7:])\n",
" df['factura'] = df['ped_15']\n",
" df['linea_seq'] = df.groupby('factura').cumcount() + 1\n",
"\n",
" prog.done('Asignacion completa')\n",
@@ -18525,20 +18547,58 @@
" df['costo_unitario_calc'] = ((_vd - (_va * _tc)) / _qty).round(6)\n",
" df['costo_unitario_calc'] = df['costo_unitario_calc'].fillna(0.0)\n",
"\n",
" # Fraccion arancelaria a 10 digitos = Fraccion (8) + SubdivisionFraccion (2)\n",
" df['fraccion_10'] = (df['fraccion'].fillna('').astype(str).str.strip().str.zfill(8)\n",
" + df['subdivision_fraccion'].fillna('').astype(str).str.strip().str.zfill(2))\n",
"\n",
" # LINEA viene de SecuenciaFraccion del Registro551 (no secuencial)\n",
" df['linea_551'] = pd.to_numeric(df['secuencia_fraccion'], errors='coerce').fillna(0).astype(int)\n",
"\n",
" # =========================================================\n",
" # PESO NETO / PESO BRUTO\n",
" # Logica:\n",
" # - Si UnidadMedidaTarifa == 1 (KGS): peso = CantidadUMTarifa\n",
" # - Si no: prorrateo del peso bruto del 501 que sobra despues de los KGS\n",
" # 1. peso_bruto_501 - sum(CantidadUMTarifa donde UMT=1) = kgs_restantes\n",
" # 2. peso_unitario = kgs_restantes / sum(CantidadUMTarifa donde UMT!=1)\n",
" # 3. peso_partida = peso_unitario * CantidadUMTarifa de la partida\n",
" # =========================================================\n",
" _ped_key = (df['patente'].astype(str) + '|' +\n",
" df['pedimento'].astype(str) + '|' +\n",
" df['seccion_aduanera'].astype(str))\n",
" df['_ped_key'] = _ped_key\n",
" _qty_tar = pd.to_numeric(df['cantidad_um_tarifa'], errors='coerce').fillna(0.0)\n",
" _umt = pd.to_numeric(df['unidad_medida_tarifa'], errors='coerce').fillna(0).astype(int)\n",
" df['_qty_tar_num'] = _qty_tar\n",
" df['_umt_int'] = _umt\n",
" df['_es_kgs'] = (_umt == 1)\n",
" # Sumas por pedimento\n",
" _agg_kgs = df.groupby('_ped_key').apply(lambda g: g.loc[g['_es_kgs'], '_qty_tar_num'].sum())\n",
" _agg_otras = df.groupby('_ped_key').apply(lambda g: g.loc[~g['_es_kgs'], '_qty_tar_num'].sum())\n",
" df['_sum_kgs'] = df['_ped_key'].map(_agg_kgs).fillna(0.0)\n",
" df['_sum_otras'] = df['_ped_key'].map(_agg_otras).fillna(0.0)\n",
" _peso_bruto_501 = pd.to_numeric(df['peso_bruto_501'], errors='coerce').fillna(0.0)\n",
" _kgs_rest = (_peso_bruto_501 - df['_sum_kgs']).clip(lower=0)\n",
" _peso_unit = np.where(df['_sum_otras'] > 0, _kgs_rest / df['_sum_otras'], 0.0)\n",
" df['peso_calc'] = np.where(df['_es_kgs'], _qty_tar, _peso_unit * _qty_tar).round(3)\n",
" # Limpieza columnas temporales\n",
" df.drop(columns=['_ped_key', '_qty_tar_num', '_umt_int', '_es_kgs', '_sum_kgs', '_sum_otras'],\n",
" inplace=True)\n",
"\n",
" out = pd.DataFrame({\n",
" 'NUMERO FACTURA': df['factura'],\n",
" 'FECHA PAGO REAL': df['fecha_pago_real'],\n",
" 'LINEA': df['linea_seq'],\n",
" 'LINEA': df['linea_551'],\n",
" 'NUMERO DE PARTE': df['NUMERO_PARTE'],\n",
" 'CANTIDAD IMPORTADA': df['cantidad_um_comercial'],\n",
" 'UNIDAD DE MEDIDA': df['um_sigla'],\n",
" 'COSTO UNITARIO': df['costo_unitario_calc'],\n",
" 'PESO NETO': '',\n",
" 'PESO BRUTO': '',\n",
" 'PESO NETO': df['peso_calc'],\n",
" 'PESO BRUTO': df['peso_calc'],\n",
" 'CANTIDAD BULTOS': df['cantidad_um_tarifa'],\n",
" 'CLAVE BULTOS': df['unidad_medida_tarifa'],\n",
" 'PAIS ORIGEN': df['pais_origen_destino'],\n",
" 'FRACCION ARANCELARIA': df['fraccion'],\n",
" 'FRACCION ARANCELARIA': df['fraccion_10'],\n",
" 'PREFERENCIA ARANCELARIA':'',\n",
" 'SECTOR': '',\n",
" 'FRACCION AMERICANA': '',\n",