GaboDataScientist's picture
Update app.py
ec7b947 verified
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()