import gradio as gr import pandas as pd import tempfile import os import uuid import shutil os.makedirs("outputs", exist_ok=True) # Carpeta pública para los resultados def procesar_bases(file1, file2): try: # Leer archivos dff = pd.read_excel(file1, engine='openpyxl') dfp = pd.read_excel(file2, engine='openpyxl') # --- Existing code from the provided script starts here --- # FASE 1: FACTURAS dff_expanded=dff.copy() dff_expanded[['FORMA DE PAGO','CANAL','MES','AÑO','UNIDADES']]=None dff_expanded=dff_expanded[['ID', 'FORMA DE PAGO','COMPANIA','CANAL', 'RFC', 'RAZON SOCIAL', 'CP', 'CORREO ELECTRONICO', 'REGIMEN FISCAL', 'METODO DE PAGO', 'FECHA PAGO', 'USO CFDI', 'ES RESICO', 'FECHA FACT.', 'MES', 'AÑO', 'OBSERVACIONES', 'EJECUTIVO ID SOl', 'EJECUTIVO SOL', 'EJECUTIVO ID EMITE', 'EJECUTIVO EMITE', 'EJECUTIVO FECHA EMITE', 'SUBTOTAL', 'RETENCIONES', 'DESCUENTO', 'IVA', 'TOTAL', 'UUID', 'UUID REL', 'ESTATUS', 'SERIE', 'FOLIO', 'UNIDADES','FOLIO COMPLEMENTO']] # 2.- Agrego la columna CANAL dff_expanded['CANAL'] = 'DIRECTO' # Valor por defecto dff_expanded.loc[dff_expanded['SERIE'] == 'AFM', 'CANAL'] = 'ASEGURADORA' dff_expanded['FECHA FACT.'] = pd.to_datetime(dff_expanded['FECHA FACT.'], format='%d/%m/%Y', errors='coerce') # Extract the year and month dff_expanded['AÑO'] = dff_expanded['FECHA FACT.'].dt.year dff_expanded['MES'] = dff_expanded['FECHA FACT.'].dt.month # FASE 2: PARTIDAS #1.- Extraemos la información de la columna "CONCEPTO" def split_concepto(row): parts = row['CONCEPTO'].split(':') return parts # Aplicar la función a cada fila del DataFrame dfp_expanded = dfp.copy() # Crear una copia para evitar modificar el original dfp_expanded['concepto_split'] = dfp.apply(split_concepto, axis=1) # Obtener el máximo número de partes para crear las nuevas columnas max_parts = dfp_expanded['concepto_split'].apply(len).max() # Crear nuevas columnas para cada parte del concepto for i in range(max_parts): dfp_expanded[f'concepto_{i+1}'] = dfp_expanded['concepto_split'].apply(lambda x: x[i] if len(x) > i else None) # Eliminar la columna 'concepto_split' dfp_expanded = dfp_expanded.drop('concepto_split', axis=1) #- Quitamos las columnas que nos estorban y les cambiamos el nombre a las que nos funcionan dfp_expanded_final=dfp_expanded[['ID FACTURA','concepto_2','concepto_5','concepto_8','concepto_11','concepto_13','concepto_14','ORDEN ASOCIADA', 'ORDEN ASOCIADA ID', 'ORDEN ASOCIADA EJEC ID', 'ORDEN ASOCIADA EJECUTIVO','ORDEN ASOCIADA NEGOCIO', 'ORDEN ASOCIADA TIPO NEGOCIO','ORDEN ASOCIADA ESTATUS', 'CUENTA CONTABLE', 'CODIGO PRODUCTO', 'CANTIDAD', 'MEDIDA', 'CODIGO UNIDAD', 'PRECIO UNITARIO', 'PARCIAL']] dfp_expanded_final = dfp_expanded_final.rename(columns={'concepto_2': 'VIN', 'concepto_5':'RECIBO','concepto_8':'SOLUCION','concepto_11':'CONCEPTO','concepto_13':'PERIODO SERVICIO','concepto_14':'ULT SERVICIO CUBIERTO'}) empty_concepto_2 = dfp_expanded_final[(dfp_expanded_final['VIN'].isnull()) | (dfp_expanded_final['VIN'] == '')] # 3.- Quitamos esas facturas de la tabla que vamos a manipular dfp_expanded_final = dfp_expanded_final[dfp_expanded_final['VIN'].notnull()] #Quito los espacios en los valores de la columna RECIBO dfp_expanded_final['RECIBO'] = dfp_expanded_final['RECIBO'].str.strip() dfp_expanded_final['FORMA DE PAGO'] = 'MENSUAL' # Default value dfp_expanded_final.loc[dfp_expanded_final['RECIBO'] == '1/1', 'FORMA DE PAGO'] = 'CONTADO' dfp_expanded_final['ORDEN NEGOCIO'] = 'OTRO' # Valor por defecto dfp_expanded_final.loc[dfp_expanded_final['ORDEN ASOCIADA NEGOCIO'] == 'MOVIMIENTO', 'ORDEN NEGOCIO'] = 'MOVIMIENTO' dfp_expanded_final.loc[dfp_expanded_final['ORDEN ASOCIADA NEGOCIO'].isin(['NUEVO', 'RECUPERADO NUEVO']), 'ORDEN NEGOCIO'] = 'NUEVO' dfp_expanded_final.loc[dfp_expanded_final['ORDEN ASOCIADA NEGOCIO'].isin(['RENOVACIÓN','RENOVACION','RECUPERADO RENOVACIÓN','RECUPERADO RENOVACION','RENOVACI�N']), 'ORDEN NEGOCIO'] = 'RENOVACION' dfp_expanded_final=pd.merge(dfp_expanded_final,dff_expanded[['ID','CANAL','FECHA FACT.','MES', 'AÑO','COMPANIA','RAZON SOCIAL','FOLIO']],left_on='ID FACTURA',right_on='ID',how='left') dfp_expanded_final=dfp_expanded_final[['ID FACTURA','CANAL','FORMA DE PAGO', 'FECHA FACT.','COMPANIA','FOLIO','RAZON SOCIAL','VIN', 'RECIBO', 'SOLUCION', 'CONCEPTO', 'PERIODO SERVICIO', 'ULT SERVICIO CUBIERTO', 'ORDEN ASOCIADA','ORDEN ASOCIADA ID', 'ORDEN ASOCIADA EJEC ID','ORDEN ASOCIADA EJECUTIVO','ORDEN NEGOCIO','ORDEN ASOCIADA NEGOCIO', 'ORDEN ASOCIADA TIPO NEGOCIO', 'ORDEN ASOCIADA ESTATUS','CUENTA CONTABLE', 'CODIGO PRODUCTO', 'CANTIDAD', 'MEDIDA','CODIGO UNIDAD', 'PRECIO UNITARIO', 'PARCIAL','MES', 'AÑO']] #FASE 3: FACTURAS dff_expanded = dff_expanded.drop(columns=['FORMA DE PAGO']) # Group by 'ID FACTURA' and get the unique payment methods payment_methods_per_invoice = dfp_expanded_final.groupby('ID FACTURA')['FORMA DE PAGO'].unique() # Create a new DataFrame with 'ID FACTURA' and the preferred payment method facturas_forma_pago = pd.DataFrame({ 'ID FACTURA': payment_methods_per_invoice.index, 'FORMA DE PAGO': payment_methods_per_invoice.values}) # Function to select the preferred payment method def select_payment_method(payment_methods): if 'MENSUAL' in payment_methods: return 'MENSUAL' else: return payment_methods[0] # Return the first payment method if 'MENSUAL' is not present # Apply the function to select the preferred payment method facturas_forma_pago['FORMA DE PAGO'] = facturas_forma_pago['FORMA DE PAGO'].apply(select_payment_method) # Perform the vlookup operation dff_expanded = pd.merge(dff_expanded, facturas_forma_pago[['ID FACTURA', 'FORMA DE PAGO']], left_on='ID', right_on='ID FACTURA', how='left') # Fill NaN values in 'FORMA DE PAGO' with 'CONTADO' dff_expanded['FORMA DE PAGO'] = dff_expanded['FORMA DE PAGO'].fillna('CONTADO') base_unidades = dfp_expanded_final['CANTIDAD'].groupby(dfp_expanded_final['ID FACTURA']).sum() dff_expanded = dff_expanded.drop(columns=['UNIDADES']) dff_expanded['UNIDADES']=pd.merge(dff_expanded,base_unidades.reset_index(),left_on='ID',right_on='ID FACTURA',how='left')['CANTIDAD'] # Fill NaN values in 'UNIDADES' column with 0 dff_expanded['UNIDADES'] = dff_expanded['UNIDADES'].fillna(0) dff_expanded_final=dff_expanded[['ID','FORMA DE PAGO','COMPANIA', 'CANAL', 'RFC', 'RAZON SOCIAL', 'CP', 'CORREO ELECTRONICO', 'REGIMEN FISCAL', 'METODO DE PAGO', 'FECHA PAGO', 'USO CFDI', 'ES RESICO', 'FECHA FACT.', 'MES', 'AÑO', 'OBSERVACIONES', 'EJECUTIVO ID SOl', 'EJECUTIVO SOL', 'EJECUTIVO ID EMITE', 'EJECUTIVO EMITE', 'EJECUTIVO FECHA EMITE', 'SUBTOTAL', 'RETENCIONES', 'DESCUENTO', 'IVA', 'TOTAL', 'UUID', 'UUID REL', 'ESTATUS', 'SERIE', 'FOLIO','UNIDADES','FOLIO COMPLEMENTO']] # --- Existing code ends here --- uid = uuid.uuid4().hex output1_path = f"outputs/facturas_limpias_{uid}.xlsx" output2_path = f"outputs/partidas_limpias_{uid}.xlsx" output3_path = f"outputs/partidas_manuales_{uid}.xlsx" dff_expanded_final.to_excel(output1_path, index=False, engine='openpyxl') dfp_expanded_final.to_excel(output2_path, index=False, engine='openpyxl') empty_concepto_2.to_excel(output3_path, index=False, engine='openpyxl') # Devolver rutas relativas (Gradio las convertirá en URLs públicas si usas static_dir="outputs") return output1_path, output2_path, output3_path except Exception as e: error_file = f"outputs/error_{uuid.uuid4().hex}.txt" with open(error_file, "w") as f: f.write("Error:\n" + str(e)) return error_file, None, None # Interfaz Gradio gr.Interface( fn=procesar_bases, inputs=[ gr.File(label="Sube en formato Excel la base Facturas", type="filepath"), gr.File(label="Sube en formato Excel la base Partidas", type="filepath") ], outputs=[ gr.File(label="Base Facturas Limpias"), gr.File(label="Base Partidas Limpias"), gr.File(label="Base Partidas Manuales") ], title="Limpieza de la base Facturas y Partidas", description="Instrucciones: Sube dos archivos de Excel. El primero debe ser la base de 'Facturas', el segundo la base de 'Partidas'. El sistema devuelve tres archivos procesados." ).launch()