diff --git a/app/app.ipynb b/app/app.ipynb index 4d5da44..24ae5c0 100644 --- a/app/app.ipynb +++ b/app/app.ipynb @@ -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",