Resum per importar fitxers CSV de comptabilitat a la base de dades `autonomo_contabilidad` amb Python
Aquest script en Python importa dades d'un fitxer CSV (com `compartit 3tr-2025 - VENDA.csv`) a la base de dades MySQL `autonomo_contabilidad`, utilitzant l'esquema de taules `wp_contabilidad_clientes`, `wp_contabilidad_empleados`, `wp_contabilidad_productos`, `wp_contabilidad_ventas` i `wp_contabilidad_detalles_venta`.
**Passos clau**:
1. **Configuració**:
- Instal·lar llibreries: `pip install pandas mysql-connector-python`.
- Configurar credencials a `db_config` (usuari, contrasenya, host, port).
- Especificar el camí del CSV (ex.: `C:\\Users\\joanp\\Documents\\compartit 3tr-2025 - VENDA.csv`).
2. **Processament del CSV**:
- Llegir el CSV amb `pandas`.
- Netejar columnes: convertir `import total` a float (eliminant ' €' i canviant ',' per '.'), i `data` a format `YYYY-MM-DD`.
- Assumir IVA del 21% per calcular `subtotal` i `iva_monto`.
3. **Inserció a la base de dades**:
- **Clients**: Inserir clients únics (`client`) a `wp_contabilidad_clientes`.
- **Empleats**: Inserir empleats únics (`empleat`) a `wp_contabilidad_empleados` amb NIF provisional (UUID).
- **Productes**: Inserir productes únics (`producte`) a `wp_contabilidad_productos` amb `protocol=''` (ajustar segons esquema).
- **Vendes**: Inserir vendes a `wp_contabilidad_ventas` amb `fecha`, `cliente_id`, `subtotal`, `iva_porcentaje`, `iva_monto`, `total`, i `metode pagament` a `notas`.
- **Detalls de vendes**: Inserir a `wp_contabilidad_detalles_venta` amb `venta_id`, `producto_id`, `cantidad=1`, `precio_unitario`, i `subtotal`.
4. **Gestió d'errors**:
- Utilitzar `try-except` per capturar errors de connexió, CSV o SQL.
- Afegir `cursor.fetchall()` i `buffered=True` per evitar errors com `Unread result found`.
- Comprovar l'existència de taules abans d'inserir.
import pandas as pd
import mysql.connector
from datetime import datetime
import uuid
import logging
# Configurar logging per rastrejar errors i progrés
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# Configuració de la connexió a la base de dades
db_config = {
'host': 'localhost', # Canvia si el teu host és diferent
'user': 'joan', # Substitueix amb el teu usuari de MySQL
'password': 'queMm88/g62123', # Substitueix amb la teva contrasenya de MySQL
'database': 'autonomo_contabilidad',
'port': 3306 # Canvia si utilitzes un port diferent
}
# Llegir el fitxer CSV
csv_file = 'C:\\Users\\joanp\\Documents\\compartit 3tr-2025 - VENDA.csv'
try:
df = pd.read_csv(csv_file)
logging.info(f"Fitxer CSV '{csv_file}' llegit correctament.")
except Exception as e:
logging.error(f"Error en llegir el fitxer CSV: {e}")
exit(1)
# Netejar i preprocessar les dades
def clean_currency(value):
try:
if isinstance(value, str):
return float(value.replace(' €', '').replace(',', '.'))
return float(value)
except Exception as e:
logging.error(f"Error en netejar valor monetari '{value}': {e}")
return 0.0
def clean_date(date_str):
try:
return datetime.strptime(date_str, '%d/%m/%Y').strftime('%Y-%m-%d')
except Exception as e:
logging.error(f"Error en netejar data '{date_str}': {e}")
return None
df['import total'] = df['import total'].apply(clean_currency)
df['data'] = df['data'].apply(clean_date)
# Eliminar files amb dates invàlides
df = df.dropna(subset=['data'])
logging.info(f"Total de files després de netejar dates: {len(df)}")
# Connectar a la base de dades
try:
conn = mysql.connector.connect(**db_config)
cursor = conn.cursor(buffered=True) # Afegim buffered=True per gestionar resultats
logging.info("Connexió a la base de dades establerta correctament.")
except mysql.connector.Error as e:
logging.error(f"Error en connectar a la base de dades: {e}")
exit(1)
# Comprovar si les taules existeixen
try:
cursor.execute("SHOW TABLES LIKE 'wp_contabilidad_productos'")
if not cursor.fetchone():
logging.error("La taula wp_contabilidad_productos no existeix. Assegura't que l'esquema està creat.")
cursor.close()
conn.close()
exit(1)
cursor.fetchall() # Consumir resultats pendents
except mysql.connector.Error as e:
logging.error(f"Error en comprovar taules: {e}")
cursor.close()
conn.close()
exit(1)
# Inserir clients únics
clients = df['client'].unique()
client_ids = {}
try:
for client in clients:
cursor.execute("SELECT id FROM wp_contabilidad_clientes WHERE nombre = %s", (client,))
result = cursor.fetchone()
cursor.fetchall() # Consumir qualsevol resultat pendent
if not result:
cursor.execute(
"INSERT INTO wp_contabilidad_clientes (nombre, fecha_creacion) VALUES (%s, NOW())",
(client,)
)
client_ids[client] = cursor.lastrowid
logging.info(f"Client '{client}' inserit amb ID {client_ids[client]}.")
else:
client_ids[client] = result[0]
except mysql.connector.Error as e:
logging.error(f"Error en inserir clients: {e}")
conn.rollback()
cursor.close()
conn.close()
exit(1)
# Inserir empleats únics
employees = df['empleat'].unique()
employee_ids = {}
try:
for employee in employees:
cursor.execute("SELECT id FROM wp_contabilidad_empleados WHERE nombre = %s", (employee,))
result = cursor.fetchone()
cursor.fetchall() # Consumir qualsevol resultat pendent
if not result:
cursor.execute(
"INSERT INTO wp_contabilidad_empleados (nombre, nif, fecha_creacion) VALUES (%s, %s, NOW())",
(employee, str(uuid.uuid4())[:20]) # Generar un NIF provisional
)
employee_ids[employee] = cursor.lastrowid
logging.info(f"Empleat '{employee}' inserit amb ID {employee_ids[employee]}.")
else:
employee_ids[employee] = result[0]
except mysql.connector.Error as e:
logging.error(f"Error en inserir empleats: {e}")
conn.rollback()
cursor.close()
conn.close()
exit(1)
# Inserir productes únics
products = df['producte'].unique()
product_ids = {}
default_category_id = 7 # ID de categoria per defecte segons l'esquema
try:
for product in products:
cursor.execute("SELECT id FROM wp_contabilidad_productos WHERE nombre = %s", (product,))
result = cursor.fetchone()
cursor.fetchall() # Consumir qualsevol resultat pendent
if not result:
cursor.execute(
"""
INSERT INTO wp_contabilidad_productos
(nombre, id_categoria_producto, precio, stock, protocol, created_at, updated_at)
VALUES (%s, %s, %s, %s, %s, NOW(), NOW())
""",
(product, default_category_id, 0.00, 0, '') # Afegim protocol com cadena buida
)
product_ids[product] = cursor.lastrowid
logging.info(f"Producte '{product}' inserit amb ID {product_ids[product]}.")
else:
product_ids[product] = result[0]
except mysql.connector.Error as e:
logging.error(f"Error en inserir productes: {e}")
conn.rollback()
cursor.close()
conn.close()
exit(1)
# Inserir vendes i detalls de vendes
try:
for index, row in df.iterrows():
# Calcular subtotal i IVA (assumim IVA del 21%)
total = row['import total']
iva_porcentaje = 21.00
subtotal = round(total / 1.21, 2)
iva_monto = round(total - subtotal, 2)
# Inserir a wp_contabilidad_ventas
cursor.execute(
"""
INSERT INTO wp_contabilidad_ventas
(fecha, cliente_id, subtotal, iva_porcentaje, iva_monto, total, notas, fecha_creacion, empleado_id)
VALUES (%s, %s, %s, %s, %s, %s, %s, NOW(), %s)
""",
(
row['data'],
client_ids[row['client']],
subtotal,
iva_porcentaje,
iva_monto,
total,
f"Metode de pagament: {row['metode pagament']}",
employee_ids[row['empleat']]
)
)
venta_id = cursor.lastrowid
logging.info(f"Venda inserida amb ID {venta_id} per al client {row['client']}.")
# Inserir a wp_contabilidad_detalles_venta
cursor.execute(
"""
INSERT INTO wp_contabilidad_detalles_venta
(venta_id, producto_id, cantidad, precio_unitario, subtotal)
VALUES (%s, %s, %s, %s, %s)
""",
(
venta_id,
product_ids[row['producte']],
1, # Assumim quantitat 1
subtotal,
subtotal
)
)
logging.info(f"Detall de venda inserit per al producte {row['producte']}.")
except mysql.connector.Error as e:
logging.error(f"Error en inserir vendes o detalls: {e}")
conn.rollback()
cursor.close()
conn.close()
exit(1)
# Confirmar canvis i tancar connexió
try:
conn.commit()
logging.info("Totes les dades s'han importat correctament a la base de dades.")
except mysql.connector.Error as e:
logging.error(f"Error en confirmar canvis: {e}")
conn.rollback()
finally:
cursor.close()
conn.close()
print("Importació completada amb èxit.")
**Notes**:
- Assegura't que l'esquema (`ESTRUCTURA.sql`) està aplicat.
- Ajusta `protocol` a `wp_contabilidad_productos` segons el tipus de dades requerit.
- Per a futurs fitxers, actualitza `csv_file` i verifica l'IVA o quantitats si varien.
Aquest resum és ideal per enganxar a un formulari amb camp Trix per documentar el procés. Si necessites més detalls o ajustos, pots ampliar el codi o consultar l'esquema complet!