| import gradio as gr |
| import pandas as pd |
| import tempfile |
| import os |
| import uuid |
| import shutil |
|
|
| os.makedirs("outputs", exist_ok=True) |
|
|
| def procesar_bases(file1, file2): |
| try: |
| |
| dff = pd.read_excel(file1, engine='openpyxl') |
| dfp = pd.read_excel(file2, engine='openpyxl') |
|
|
| |
| |
| 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']] |
|
|
| |
| dff_expanded['CANAL'] = 'DIRECTO' |
| 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') |
| |
| dff_expanded['AÑO'] = dff_expanded['FECHA FACT.'].dt.year |
| dff_expanded['MES'] = dff_expanded['FECHA FACT.'].dt.month |
|
|
| |
| |
| def split_concepto(row): |
| parts = row['CONCEPTO'].split(':') |
| return parts |
|
|
| |
| dfp_expanded = dfp.copy() |
| dfp_expanded['concepto_split'] = dfp.apply(split_concepto, axis=1) |
|
|
| |
| max_parts = dfp_expanded['concepto_split'].apply(len).max() |
|
|
| |
| 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) |
|
|
|
|
| |
| dfp_expanded = dfp_expanded.drop('concepto_split', axis=1) |
|
|
| |
| 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'] == '')] |
| |
| dfp_expanded_final = dfp_expanded_final[dfp_expanded_final['VIN'].notnull()] |
| |
| dfp_expanded_final['RECIBO'] = dfp_expanded_final['RECIBO'].str.strip() |
| dfp_expanded_final['FORMA DE PAGO'] = 'MENSUAL' |
| dfp_expanded_final.loc[dfp_expanded_final['RECIBO'] == '1/1', 'FORMA DE PAGO'] = 'CONTADO' |
|
|
| dfp_expanded_final['ORDEN NEGOCIO'] = 'OTRO' |
| 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']] |
|
|
| |
| dff_expanded = dff_expanded.drop(columns=['FORMA DE PAGO']) |
| |
| payment_methods_per_invoice = dfp_expanded_final.groupby('ID FACTURA')['FORMA DE PAGO'].unique() |
|
|
| |
| facturas_forma_pago = pd.DataFrame({ |
| 'ID FACTURA': payment_methods_per_invoice.index, |
| 'FORMA DE PAGO': payment_methods_per_invoice.values}) |
|
|
| |
| def select_payment_method(payment_methods): |
| if 'MENSUAL' in payment_methods: |
| return 'MENSUAL' |
| else: |
| return payment_methods[0] |
|
|
|
|
| |
| facturas_forma_pago['FORMA DE PAGO'] = facturas_forma_pago['FORMA DE PAGO'].apply(select_payment_method) |
|
|
| |
| dff_expanded = pd.merge(dff_expanded, facturas_forma_pago[['ID FACTURA', 'FORMA DE PAGO']], left_on='ID', right_on='ID FACTURA', how='left') |
| |
| 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'] |
| |
| 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']] |
|
|
|
|
|
|
| |
| 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') |
|
|
| |
| 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 |
|
|
| |
| 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() |