diff --git a/README.md b/README.md index acc724b..eb7de7f 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ Esto crea el comando factuges-sync disponible en tu entorno virtual. El código carga automáticamente: * environment/dev.env cuando ENV=dev -* Variables del contenedor en producción (ENV=prod) +* Variables del contenedor en producción (ENV=production) Por tanto, **en desarrollo**: @@ -122,5 +122,5 @@ Build: Cron job: ```bash -*/5 * * * * docker run --rm -e ENV=prod -e SYNC_MODE=factuges myimage:latest +*/5 * * * * docker run --rm -e ENV=production -e SYNC_MODE=factuges myimage:latest ``` diff --git a/app.last_run.txt b/app.last_run.txt index 0833840..1b2374d 100644 --- a/app.last_run.txt +++ b/app.last_run.txt @@ -1 +1 @@ -2025-11-30 09:07:15 \ No newline at end of file +2025-11-30 18:28:15 \ No newline at end of file diff --git a/app/__version_sync_factuges__.py b/app/__version_sync_factuges__.py deleted file mode 100644 index 1c11a6e..0000000 --- a/app/__version_sync_factuges__.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "1.0.0" diff --git a/app/__version_sync_verifactu__.py b/app/__version_sync_verifactu__.py deleted file mode 100644 index 1c11a6e..0000000 --- a/app/__version_sync_verifactu__.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "1.0.0" diff --git a/app/cli.py b/app/cli.py index 08b70e5..2679221 100644 --- a/app/cli.py +++ b/app/cli.py @@ -28,7 +28,7 @@ def main(): print("Error: debes indicar modo: 'factuges' o 'verifactu'") sys.exit(1) - if os.getenv("ENV") == "dev": + if os.getenv("ENV") == "developement": print("Running in development mode (no docker)") module = ( diff --git a/app/config/__init__.py b/app/config/__init__.py index b3bddb7..889fd27 100644 --- a/app/config/__init__.py +++ b/app/config/__init__.py @@ -1,3 +1,4 @@ -from .settings import load_config -from .setup_logging import setup_logging -from .setup_brevo import setup_brevo \ No newline at end of file +from .settings import load_config, log_config +from .version import get_package_version +from .setup_logger import create_logger, logger +from .setup_brevo import setup_brevo diff --git a/app/config/settings.py b/app/config/settings.py index 122db16..75a705c 100644 --- a/app/config/settings.py +++ b/app/config/settings.py @@ -1,7 +1,7 @@ -import logging import os from os.path import join, dirname from typing import Any, Dict, Optional +from .setup_logger import logger from dotenv import load_dotenv @@ -23,16 +23,16 @@ def load_config() -> Dict[str, Any]: Carga la configuración desde variables de entorno. - En dev: carga dev.env y luego valida. - - En prod: NO carga ningún .env, solo usa entorno del sistema/contendor. + - En production: NO carga ningún .env, solo usa entorno del sistema/contendor. - Si falta alguna variable requerida -> RuntimeError. """ - env = os.getenv("ENV", "dev") + env = os.getenv("ENV", "development") - if env == "dev": + if env == "development": dotenv_path = join(dirname(__file__), "../../enviroment/dev.env") load_dotenv(dotenv_path) - elif env == "prod": + elif env == "production": # En producción NO se carga archivo .env # Las variables vienen del contenedor (docker run -e VAR=...) pass @@ -42,7 +42,6 @@ def load_config() -> Dict[str, Any]: config: Dict[str, Any] = { # Opcionales (con valor por defecto) "ENV": env, - "ENVIRONMENT": os.getenv("ENVIRONMENT", env), "LOCAL_TZ": os.getenv("LOCAL_TZ", "Europe/Madrid"), "LAST_RUN_PATH": _required("LAST_RUN_PATH"), @@ -54,11 +53,11 @@ def load_config() -> Dict[str, Any]: "FACTUGES_PASSWORD": _required("FACTUGES_PASSWORD"), # UECKO MySQL (requeridas salvo puerto) - "UECKO_MYSQL_HOST": _required("UECKO_MYSQL_HOST"), - "UECKO_MYSQL_PORT": os.getenv("UECKO_MYSQL_PORT", "3306"), - "UECKO_MYSQL_DATABASE": _required("UECKO_MYSQL_DATABASE"), - "UECKO_MYSQL_USER": _required("UECKO_MYSQL_USER"), - "UECKO_MYSQL_PASSWORD": _required("UECKO_MYSQL_PASSWORD"), + "FWEB_MYSQL_HOST": _required("FWEB_MYSQL_HOST"), + "FWEB_MYSQL_PORT": os.getenv("FWEB_MYSQL_PORT", "3306"), + "FWEB_MYSQL_DATABASE": _required("FWEB_MYSQL_DATABASE"), + "FWEB_MYSQL_USER": _required("FWEB_MYSQL_USER"), + "FWEB_MYSQL_PASSWORD": _required("FWEB_MYSQL_PASSWORD"), # Constantes/CTE (requeridas) "CTE_COMPANY_ID": _required("CTE_COMPANY_ID"), @@ -79,3 +78,14 @@ def load_config() -> Dict[str, Any]: } return config + + +def log_config(config: dict) -> None: + """Loguea la configuración con una clave por línea.""" + lines = ["Loaded configuration:"] + for key in sorted(config.keys()): + value = config[key] + if any(t in key.lower() for t in ("pass", "password", "api_key", "token", "secret")): + value = "***" + lines.append(f" {key} = {value!r}") + logger.info("\n".join(lines)) diff --git a/app/config/setup_logger.py b/app/config/setup_logger.py new file mode 100644 index 0000000..4e3af06 --- /dev/null +++ b/app/config/setup_logger.py @@ -0,0 +1,55 @@ +import logging +import sys +import os +from logging.handlers import RotatingFileHandler +from pathlib import Path + + +def create_logger( + name: str = "factuges-sync", + *, + level: int = logging.INFO, + log_path: str | None = None, +) -> logging.Logger: + """ + Crea un logger: + - SIEMPRE stdout (Docker-friendly) + - SOLO EN PRODUCCIÓN añade RotatingFileHandler si log_path no es None + """ + + logger = logging.getLogger(name) + logger.setLevel(level) + + # No duplicar handlers si ya existe el logger + if logger.handlers: + return logger + + formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") + + # ------------------------------------------------------------------ + # 1) Consola → SIEMPRE (para docker logs) + # ------------------------------------------------------------------ + h_console = logging.StreamHandler(sys.stdout) + h_console.setFormatter(formatter) + logger.addHandler(h_console) + + # ------------------------------------------------------------------ + # 2) Fichero → SOLO en prod + si se define log_path + # ------------------------------------------------------------------ + environment = os.getenv("ENV", "development") + if environment == "production" and log_path: + Path(log_path).parent.mkdir(parents=True, exist_ok=True) + h_file = RotatingFileHandler( + log_path, + maxBytes=5 * 1024 * 1024, + backupCount=15, + encoding="utf8", + ) + h_file.setFormatter(formatter) + logger.addHandler(h_file) + + return logger + + +# logger "global" ya creado +logger = create_logger() diff --git a/app/config/setup_logging.py b/app/config/setup_logging.py deleted file mode 100644 index b90a010..0000000 --- a/app/config/setup_logging.py +++ /dev/null @@ -1,18 +0,0 @@ -import logging -import sys -from logging.handlers import RotatingFileHandler - -def setup_logging(): - logging.basicConfig(stream=sys.stdout, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') - - -def setup_rotating_logging(log_path): - # Rotación de logs con un tamaño máximo de 5 MB y mantiene 15 archivos de backup - handler = RotatingFileHandler(log_path, maxBytes=5*1024*1024, backupCount=15, encoding="utf8") - - # Configuración básica de logging - logging.basicConfig( - handlers=[handler], - level=logging.INFO, - format='%(asctime)s - %(levelname)s - %(message)s' - ) diff --git a/app/config/version.py b/app/config/version.py new file mode 100644 index 0000000..1b96e11 --- /dev/null +++ b/app/config/version.py @@ -0,0 +1,8 @@ +from importlib.metadata import version, PackageNotFoundError + + +def get_package_version() -> str: + try: + return version("factuges-sync") # nombre del paquete en [metadata].name + except PackageNotFoundError: + return "unknown" diff --git a/app/db/db_connection.py b/app/db/db_connection.py index c398d85..d1640fa 100644 --- a/app/db/db_connection.py +++ b/app/db/db_connection.py @@ -1,6 +1,6 @@ import fdb import mysql.connector -import logging +from app.config import logger def get_factuges_connection(config): @@ -13,32 +13,32 @@ def get_factuges_connection(config): password=config['FACTUGES_PASSWORD'], charset='UTF8' ) - logging.info( + logger.info( f"Conexión a la base de datos FactuGES establecida: {config['FACTUGES_HOST']} with database:{config['FACTUGES_DATABASE']} - using user:{config['FACTUGES_USER']}") return conn except Exception as e: - logging.error("Error al conectar a la base de datos FactuGES.") - logging.error( + logger.error("Error al conectar a la base de datos FactuGES.") + logger.error( f"(ERROR) Failed to establish connection to: {config['FACTUGES_HOST']} with database:{config['FACTUGES_DATABASE']} - using user:{config['FACTUGES_USER']}") - logging.error(str(e)) + logger.error(str(e)) raise e def get_mysql_connection(config): try: conn = mysql.connector.connect( - host=config['UECKO_MYSQL_HOST'], - port=config['UECKO_MYSQL_PORT'], - database=config['UECKO_MYSQL_DATABASE'], - user=config['UECKO_MYSQL_USER'], - password=config['UECKO_MYSQL_PASSWORD'] + host=config['FWEB_MYSQL_HOST'], + port=config['FWEB_MYSQL_PORT'], + database=config['FWEB_MYSQL_DATABASE'], + user=config['FWEB_MYSQL_USER'], + password=config['FWEB_MYSQL_PASSWORD'] ) - logging.info( - f"Conexión a la base de datos MySQL establecida a: {config['UECKO_MYSQL_HOST']} with database:{config['UECKO_MYSQL_DATABASE']} - using user:{config['UECKO_MYSQL_USER']}") + logger.info( + f"Conexión a la base de datos MySQL establecida a: {config['FWEB_MYSQL_HOST']} with database:{config['FWEB_MYSQL_DATABASE']} - using user:{config['FWEB_MYSQL_USER']}") return conn except Exception as e: - logging.error("Error al conectar a la base de datos MySQL.") - logging.error( - f"(ERROR) Failed to establish connection to: {config['UECKO_MYSQL_HOST']} with database:{config['UECKO_MYSQL_DATABASE']} - using user:{config['UECKO_MYSQL_USER']}") - logging.error(str(e)) + logger.error("Error al conectar a la base de datos MySQL.") + logger.error( + f"(ERROR) Failed to establish connection to: {config['FWEB_MYSQL_HOST']} with database:{config['FWEB_MYSQL_DATABASE']} - using user:{config['FWEB_MYSQL_USER']}") + logger.error(str(e)) raise e diff --git a/app/db/normalizations.py b/app/db/normalizations.py index 01c51ac..6ccde4b 100644 --- a/app/db/normalizations.py +++ b/app/db/normalizations.py @@ -1,4 +1,4 @@ -import logging +from app.config import logger from datetime import date from app.config import load_config import textwrap diff --git a/app/db/sync_invoices_factuges.py b/app/db/sync_invoices_factuges.py index e815b59..9f0af0e 100644 --- a/app/db/sync_invoices_factuges.py +++ b/app/db/sync_invoices_factuges.py @@ -1,4 +1,4 @@ -import logging +from app.config import logger from typing import Dict, Any from uuid6 import uuid7 from app.config import load_config @@ -21,20 +21,20 @@ def sync_invoices_factuges(conn_factuges, conn_mysql, last_execution_date): # Crear un conjunto con los IDs [0] de los customer_inovices que debo liberar en FactuGES, porque han sido eliminadas en programa de facturación nuevo ids_verifactu_deleted = {str(fila[0]) for fila in filas} - # logging.info(f"Customer invoices rows to be deleted: {len(ids_verifactu_deleted)}") + # logger.info(f"Customer invoices rows to be deleted: {len(ids_verifactu_deleted)}") # Verificar si hay filas en el resultado if ids_verifactu_deleted: sync_delete_invoices(conn_factuges, ids_verifactu_deleted, config) else: - logging.info( + logger.info( f"There are NOT customer invoices deleted since the last run") except Exception as e: if cursor_mysql is not None: cursor_mysql.close() - logging.error(f"(ERROR) Failed to fetch from database:{ - config['UECKO_MYSQL_DATABASE']} - using user:{config['UECKO_MYSQL_USER']}") - logging.error(e) + logger.error(f"(ERROR) Failed to fetch from database:{ + config['FWEB_MYSQL_DATABASE']} - using user:{config['FWEB_MYSQL_USER']}") + logger.error(e) raise e # BUSCAMOS FACTURAS ENVIADAS A VERIFACTU EN FACTUGES, PARA SUBIRLAS AL NUEVO PROGRAMA DE FACTURACIÓN @@ -48,9 +48,9 @@ def sync_invoices_factuges(conn_factuges, conn_mysql, last_execution_date): except Exception as e: if cursor_FactuGES is not None: cursor_FactuGES.close() - logging.error(f"(ERROR) Failed to fetch from database:{ - config['FACTUGES_DATABASE']} - using user:{config['FACTUGES_USER']}") - logging.error(e) + logger.error(f"(ERROR) Failed to fetch from database:{ + config['FACTUGES_DATABASE']} - using user:{config['FACTUGES_USER']}") + logger.error(e) raise e # Obtener los nombres de las columnas @@ -67,7 +67,7 @@ def sync_invoices_factuges(conn_factuges, conn_mysql, last_execution_date): sync_invoices_from_FACTUGES( conn_mysql, tuplas_seleccionadas, conn_factuges, config) else: - logging.info( + logger.info( "There are NOT new FACTURAS rows since the last run.") @@ -78,15 +78,15 @@ def sync_delete_invoices(conn_factuges, ids_verifactu_deleted, config): try: cursor_FactuGES = conn_factuges.cursor() if ids_verifactu_deleted: - logging.info(f"Liberate factuGES: {ids_verifactu_deleted}") + logger.info(f"Liberate factuGES: {ids_verifactu_deleted}") cursor_FactuGES.executemany(SQL.LIMPIAR_FACTUGES_LINK, [( id_verifactu,) for id_verifactu in ids_verifactu_deleted]) else: - logging.info("No articles to delete.") + logger.info("No articles to delete.") except Exception as e: # Escribir el error en el archivo de errores - logging.error(str(e)) + logger.error(str(e)) raise e # Re-lanzar la excepción para detener el procesamiento finally: # Cerrar la conexión @@ -96,7 +96,7 @@ def sync_delete_invoices(conn_factuges, ids_verifactu_deleted, config): def sync_invoices_from_FACTUGES(conn_mysql, filas, conn_factuges, config): # Insertaremos cada factura existente en las filas a la nueva estructura de tablas del programa nuevo de facturacion. - # logging.info(f"FACTURAS_CLIENTE_DETALLE rows to be processed: {len(filas)}") + # logger.info(f"FACTURAS_CLIENTE_DETALLE rows to be processed: {len(filas)}") cursorMySQL = None cursor_FactuGES = None @@ -163,10 +163,10 @@ def sync_invoices_from_FACTUGES(conn_mysql, filas, conn_factuges, config): sync_notes = (f">>> Factura {header_invoice_fields['reference']} no cumple requisitos para ser mandada a Verifactu: " f">>>>>> El NIF/NOMBRE ({customer_fields['tin']}/{customer_fields['name']}) no está registrado en la AEAT. " f"El NIF/CIF debe estar registrado en la AEAT y el nombre debe ser suficientemente parecido al nombre registrado en la AEAT") - logging.info(sync_notes) + logger.info(sync_notes) # Guardamos en Factuges el id de la customer_invoice - logging.info( + logger.info( f"Updating FACTURAS_CLIENTE {sync_result} {invoice_id} {factuges_id} {sync_notes}") cursor_FactuGES.execute(SQL.UPDATE_FACTUGES_LINK, (sync_result, invoice_id, sync_notes, factuges_id)) num_fac_procesed += 1 @@ -178,12 +178,12 @@ def sync_invoices_from_FACTUGES(conn_mysql, filas, conn_factuges, config): # Asignamos el id factura anterior para no volver a inserta cabecera factuges_id_anterior = factuges_id - logging.info( + logger.info( f"FACTURAS_CLIENTE rows to be processed: {str(num_fac_procesed)}") except Exception as e: # Escribir el error en el archivo de errores - logging.error(str(e)) + logger.error(str(e)) raise e # Re-lanzar la excepción para detener el procesamiento finally: @@ -202,8 +202,8 @@ def get_or_create_customer(cur, company_id: str, factuges_customer_id: str, fiel row = cur.fetchone() if not row or not row[0]: customer_id = str(uuid7()) - logging.info("Inserting customer %s %s %s", - factuges_customer_id, fields["tin"], fields["name"]) + logger.info("Inserting customer %s %s %s", + factuges_customer_id, fields["tin"], fields["name"]) cur.execute( SQL.INSERT_CUSTOMER, ( @@ -215,7 +215,7 @@ def get_or_create_customer(cur, company_id: str, factuges_customer_id: str, fiel ) return customer_id customer_id = str(row[0]) - logging.info("Updating customer %s %s", factuges_customer_id, customer_id) + logger.info("Updating customer %s %s", factuges_customer_id, customer_id) cur.execute( SQL.UPDATE_CUSTOMER, ( @@ -236,13 +236,13 @@ def get_or_create_payment_method(cur, factuges_payment_id: str, description: str row = cur.fetchone() if not row or not row[0]: pm_id = str(uuid7()) - logging.info("Inserting payment method %s %s %s", - factuges_payment_id, pm_id, description) + logger.info("Inserting payment method %s %s %s", + factuges_payment_id, pm_id, description) cur.execute(SQL.INSERT_PAYMENT_METHOD, (pm_id, description, factuges_payment_id)) return pm_id pm_id = str(row[0]) - logging.info("Payment method exists %s -> %s", factuges_payment_id, pm_id) + logger.info("Payment method exists %s -> %s", factuges_payment_id, pm_id) return pm_id @@ -253,8 +253,8 @@ def insert_invoice_header(cur: str, cf: Dict[str, Any], hif: Dict[str, Any], cus """ invoice_id = str(uuid7()) - logging.info("Inserting invoice %s %s %s %s %s", - invoice_id, hif.get('reference'), hif.get('invoice_date'), hif.get('operation_date'), config['CTE_STATUS_INVOICE']) + logger.info("Inserting invoice %s %s %s %s %s", + invoice_id, hif.get('reference'), hif.get('invoice_date'), hif.get('operation_date'), config['CTE_STATUS_INVOICE']) cur.execute( SQL.INSERT_INVOICE, ( @@ -279,8 +279,8 @@ def insert_verifactu_record(cur: str, hif: Dict[str, Any], invoice_id: str, conf """ id = str(uuid7()) - logging.info("Inserting verifactu record %s %s %s", - id, hif.get('reference'), hif.get('invoice_date')) + logger.info("Inserting verifactu record %s %s %s", + id, hif.get('reference'), hif.get('invoice_date')) cur.execute( SQL.INSERT_VERIFACTU_RECORD, ( @@ -311,7 +311,7 @@ def insert_item_and_taxes(cur, invoice_id: str, fields: Dict[str, Any]) -> None: """ item_id = str(uuid7()) - # logging.info("Inserting item %s pos=%s qty=%s", item_id, fields.get('position'), fields.get('quantity_value')) + # logger.info("Inserting item %s pos=%s qty=%s", item_id, fields.get('position'), fields.get('quantity_value')) cur.execute( SQL.INSERT_INVOICE_ITEM, (item_id, invoice_id, fields.get('position'), fields.get('description'), fields.get('quantity_value'), @@ -321,7 +321,7 @@ def insert_item_and_taxes(cur, invoice_id: str, fields: Dict[str, Any]) -> None: ) ) - # logging.info("Inserting item tax %s code=%s base=%s tax=%s", + # logger.info("Inserting item tax %s code=%s base=%s tax=%s", # item_id, fields.get('tax_code'), fields.get('total_value'), fields.get('tax_amount')) # cur.execute( # SQL.INSERT_INVOICE_ITEM_TAX, (str(uuid7()), item_id, fields.get('tax_code'), diff --git a/app/db/sync_invoices_verifactu.py b/app/db/sync_invoices_verifactu.py index fc05612..1db328d 100644 --- a/app/db/sync_invoices_verifactu.py +++ b/app/db/sync_invoices_verifactu.py @@ -1,4 +1,4 @@ -import logging +from app.config import logger from typing import Dict, Any, Tuple, Optional, List, Iterable from app.config import load_config from decimal import Decimal @@ -26,22 +26,22 @@ def sync_invoices_verifactu(conn_mysql, last_execution_date): tuplas_seleccionadas.append(tupla) # invoices_to_verifactu = {str(fila[0]) for fila in filas} - logging.info( + logger.info( f"Customer invoices rows to be send Verifactu: {len(tuplas_seleccionadas)}") # Verificar si hay filas en el resultado if tuplas_seleccionadas: enviar_datos(tuplas_seleccionadas, cursor_mysql, config) - logging.info(f"Ok send Verifactu") + logger.info(f"Ok send Verifactu") else: - logging.info(f"There are no rows to send") + logger.info(f"There are no rows to send") except Exception as error: if cursor_mysql is not None: cursor_mysql.close() - logging.error( - f"(ERROR) Failed to fetch from database:{config['UECKO_MYSQL_DATABASE']} - using user:{config['UECKO_MYSQL_USER']}") - logging.error(error) + logger.error( + f"(ERROR) Failed to fetch from database:{config['FWEB_MYSQL_DATABASE']} - using user:{config['FWEB_MYSQL_USER']}") + logger.error(error) raise error @@ -61,9 +61,9 @@ def enviar_datos(invoices_to_verifactu, cursor_mysql, config): # preparamos nueva factura ok, respuesta = preparar_factura(fila) if not ok: - logging.info( + logger.info( f"ERROR >>>>>> Factura {fila['reference']} no cumple requisitos para ser mandada a Verifactu:") - logging.info( + logger.info( f">>>>>> Faltan campos requeridos: {respuesta}") factura = None continue @@ -71,9 +71,9 @@ def enviar_datos(invoices_to_verifactu, cursor_mysql, config): ok, linea = preparar_linea(fila) if not ok: - logging.info( + logger.info( f"ERROR >>>>>> Factura {factura.get('reference')} no cumple requisitos para ser mandada a Verifactu:") - logging.info(f">>>>>> Faltan campos requeridos: {linea}") + logger.info(f">>>>>> Faltan campos requeridos: {linea}") factura = None else: factura["lineas"].append(linea) @@ -82,7 +82,7 @@ def enviar_datos(invoices_to_verifactu, cursor_mysql, config): except Exception as e: # Escribir el error en el archivo de errores - logging.error(str(e)) + logger.error(str(e)) raise e # Re-lanzar la excepción para detener el procesamiento @@ -95,29 +95,29 @@ def procesar_factura_verifactu( if factura != None: # Creamos registro de factura en verifactu if factura.get('uuid') == '': - # logging.info(f"Send to create Verifactu: {factura}") + # logger.info(f"Send to create Verifactu: {factura}") respuesta = crear_factura(factura, config) if respuesta.get("status") == 200 and respuesta.get("ok"): data = respuesta.get("data") qr_verifactu = f"data:image/png;base64,{data.get('qr', '')}" cursor_mysql.execute(SQL.update_verifactu_records_with_invoiceId, (data.get("estado"), data.get( "uuid"), data.get("url"), qr_verifactu, factura.get("id"))) - logging.info( + logger.info( f">>> Factura {factura.get("reference")} registrada en Verifactu") return True else: - logging.info( + logger.info( f">>> Factura {factura.get("reference")} enviada a Verifactu con error {respuesta}") return False # Actualizamos registro de factura en verifactu else: - # logging.info(f"Send to update Verifactu: {factura}") + # logger.info(f"Send to update Verifactu: {factura}") respuesta = estado_factura(factura.get('uuid'), config) if respuesta.get("status") == 200 and respuesta.get("ok"): data = respuesta.get("data") cursor_mysql.execute(SQL.update_verifactu_records_with_uuid, (data.get( 'estado'), data.get('operacion'), factura.get('uuid'))) - logging.info( + logger.info( f">>> Factura {factura.get("reference")} actualizado registro de Verifactu") return True else: diff --git a/app/sync_factuges_main.py b/app/sync_factuges_main.py index c8fb486..914ecca 100644 --- a/app/sync_factuges_main.py +++ b/app/sync_factuges_main.py @@ -1,28 +1,32 @@ import sys -import logging -from app.__version_sync_factuges__ import __version__ +from app.config import get_package_version from datetime import datetime from dateutil import tz -from app.config import setup_logging, load_config +from app.config import create_logger, load_config, log_config from app.db import get_mysql_connection, get_factuges_connection, sync_invoices_factuges -from app.utils import obtener_fecha_ultima_ejecucion, actualizar_fecha_ultima_ejecucion, log_system_metrics, send_orders_mail +from app.utils import obtener_fecha_ultima_ejecucion, actualizar_fecha_ultima_ejecucion def main(): - # Cargar la configuración config = load_config() - + version = get_package_version() local_tz = tz.gettz(config['LOCAL_TZ']) # Logging - setup_logging() + logger = create_logger( + name="factuges-sync", + log_path="/app/logs/sync_factuges.log", # Solo lo genera en producción + ) - logging.info("== START SYNC FACTUGES ==") - logging.info(f"Version: {__version__}") - logging.info(f"Environment: {config['ENVIRONMENT']}") - log_system_metrics() + logger.info("============================================================") + logger.info(" FACTUGES Sync FactuGES - START ") + logger.info(" Version: %s", version) + logger.info(" UTC Now: %s", datetime.utcnow().isoformat()) + logger.info(" Environment: {config['ENV']}") + + log_config(config) conn_factuges = None conn_mysql = None @@ -32,17 +36,17 @@ def main(): last_execution_date_local_tz = last_execution_date_utc.astimezone( tz=local_tz).strftime("%Y-%m-%d %H:%M:%S") - logging.info("Last execution (UTC): %s", - last_execution_date_utc.strftime("%Y-%m-%d %H:%M:%S %Z")) - logging.info("Last execution (Local time): %s", - last_execution_date_local_tz) + logger.info("Last execution (UTC): %s", + last_execution_date_utc.strftime("%Y-%m-%d %H:%M:%S %Z")) + logger.info("Last execution (Local time): %s", + last_execution_date_local_tz) # Abrimos conexiones con una única transacción para que todo esté controlado conn_factuges = get_factuges_connection(config) conn_mysql = get_mysql_connection(config) # Sincronizamos - logging.info( + logger.info( f">>>>>>>>>>> INI Sync invoices FactuGES escritorio to FactuGES web") sync_invoices_factuges(conn_factuges, conn_mysql, last_execution_date_local_tz) @@ -51,21 +55,23 @@ def main(): conn_factuges.commit() conn_factuges.close() conn_mysql.close() - logging.info(f">>>>>>>>>>> FIN Sync invoices FactuGES escritorio to FactuGES web") + logger.info(f">>>>>>>>>>> FIN Sync invoices FactuGES escritorio to FactuGES web") actualizar_fecha_ultima_ejecucion(config['LAST_RUN_PATH']) # Enviar email # send_orders_mail(inserted_orders) - logging.info("== END (0) ==") + logger.info("== END (0) ==") + logger.info("============================================================") sys.exit(0) except Exception as e: - logging.error("Se ha producido un error en la última ejecución.") - logging.error(e) - logging.error("Traceback:", exc_info=True) - logging.info("== END (1) ==") + logger.error("Se ha producido un error en la última ejecución.") + logger.error(e) + logger.error("Traceback:", exc_info=True) + logger.info("== END (1) ==") + logger.info("============================================================") if conn_mysql is not None: conn_mysql.rollback() diff --git a/app/sync_verifactu_main.py b/app/sync_verifactu_main.py index 7a2d257..621bbd5 100644 --- a/app/sync_verifactu_main.py +++ b/app/sync_verifactu_main.py @@ -1,28 +1,33 @@ import sys -import logging -from app.__version_sync_factuges__ import __version__ +from app.config import get_package_version from datetime import datetime from dateutil import tz -from config import setup_logging, load_config -from db import get_mysql_connection, get_factuges_connection, sync_invoices_verifactu -from utils import obtener_fecha_ultima_ejecucion, actualizar_fecha_ultima_ejecucion, log_system_metrics, send_orders_mail +from app.config import create_logger, load_config, log_config +from app.db import get_mysql_connection, get_factuges_connection, sync_invoices_verifactu +from app.utils import obtener_fecha_ultima_ejecucion, actualizar_fecha_ultima_ejecucion def main(): # Cargar la configuración config = load_config() - + version = get_package_version() local_tz = tz.gettz(config['LOCAL_TZ']) # Logging - setup_logging() + logger = create_logger( + name="factuges-sync", + log_path="/app/logs/sync_verifactu.log", # Solo lo genera en producción + ) - logging.info("== START SYNC VERIFACTU ==") - logging.info(f"Version: {__version__}") - logging.info(f"Environment: {config['ENVIRONMENT']}") - log_system_metrics() + logger.info("============================================================") + logger.info(" FACTUGES Sync Verifactu - START ") + logger.info(" Version: %s", version) + logger.info(" UTC Now: %s", datetime.utcnow().isoformat()) + logger.info(" Environment: {config['ENV']}") + + log_config(config) conn_factuges = None conn_mysql = None @@ -32,35 +37,37 @@ def main(): last_execution_date_local_tz = last_execution_date_utc.astimezone( tz=local_tz).strftime("%Y-%m-%d %H:%M:%S") - logging.info("Last execution (UTC): %s", - last_execution_date_utc.strftime("%Y-%m-%d %H:%M:%S %Z")) - logging.info("Last execution (Local time): %s", - last_execution_date_local_tz) + logger.info("Last execution (UTC): %s", + last_execution_date_utc.strftime("%Y-%m-%d %H:%M:%S %Z")) + logger.info("Last execution (Local time): %s", + last_execution_date_local_tz) # Abrimos conexión con una única transacción para que todo esté controlado conn_mysql = get_mysql_connection(config) # Sync Verifactu - logging.info( + logger.info( f">>>>>>>>>> INI Sync facturas emitidas to Verifactu") sync_invoices_verifactu(conn_mysql, last_execution_date_local_tz) conn_mysql.commit() conn_mysql.close() - logging.info(f">>>>>>>>>> FIN Sync facturas emitidas to Verifactu") + logger.info(f">>>>>>>>>> FIN Sync facturas emitidas to Verifactu") actualizar_fecha_ultima_ejecucion() # Enviar email # send_orders_mail(inserted_orders) - logging.info("== END (0) ==") + logger.info("== END (0) ==") + logger.info("============================================================") sys.exit(0) except Exception as e: - logging.error("Se ha producido un error en la última ejecución.") - logging.error(e) - logging.error("Traceback:", exc_info=True) - logging.info("== END (1) ==") + logger.error("Se ha producido un error en la última ejecución.") + logger.error(e) + logger.error("Traceback:", exc_info=True) + logger.info("== END (1) ==") + logger.info("============================================================") if conn_mysql is not None: conn_mysql.rollback() diff --git a/app/utils/__init__.py b/app/utils/__init__.py index c591e2b..2fb3a4e 100644 --- a/app/utils/__init__.py +++ b/app/utils/__init__.py @@ -1,5 +1,4 @@ from .last_execution_helper import actualizar_fecha_ultima_ejecucion, obtener_fecha_ultima_ejecucion -from .log_system_metrics import log_system_metrics from .password import hashPassword from .send_orders_mail import send_orders_mail from .text_converter import text_converter, limpiar_cadena diff --git a/app/utils/log_system_metrics.py b/app/utils/log_system_metrics.py deleted file mode 100644 index e200091..0000000 --- a/app/utils/log_system_metrics.py +++ /dev/null @@ -1,9 +0,0 @@ -import psutil -import logging - -def log_system_metrics(): - cpu_usage = psutil.cpu_percent(interval=1) - memory_usage = psutil.virtual_memory().percent - - logging.info(f'CPU Usage: {cpu_usage}%') - logging.info(f'Memory Usage: {memory_usage}%') diff --git a/app/utils/send_orders_mail.py b/app/utils/send_orders_mail.py index 2955e42..127fedd 100644 --- a/app/utils/send_orders_mail.py +++ b/app/utils/send_orders_mail.py @@ -1,4 +1,4 @@ -import logging +from app.config import logger import brevo_python from brevo_python.rest import ApiException @@ -25,6 +25,6 @@ def send_orders_mail(inserted_orders): }, ) api_response = api_instance.send_transac_email(send_smtp_email) - logging.info(msg=api_response) + logger.info(msg=api_response) except ApiException as e: - logging.error(msg=e) + logger.error(msg=e) diff --git a/app/utils/send_rest_api.py b/app/utils/send_rest_api.py index be3165f..1e16cee 100644 --- a/app/utils/send_rest_api.py +++ b/app/utils/send_rest_api.py @@ -1,5 +1,5 @@ import requests -import logging +from app.config import logger from typing import Optional, Dict, Any, Tuple @@ -51,10 +51,10 @@ def estado_factura(uuid_str: str, return {"ok": False, "status": resp.status_code, "error": f"HTTP {resp.status_code}", "raw": resp.text} except requests.RequestException as e: - logging.error("Error de conexión con la API Verifacti: %s", e) + logger.error("Error de conexión con la API Verifacti: %s", e) return False, None, str(e) except ValueError as e: - logging.error("Respuesta no es JSON válido: %s", e) + logger.error("Respuesta no es JSON válido: %s", e) return False, None, "Respuesta no es JSON válido" @@ -83,7 +83,7 @@ def crear_factura(payload, if resp.status_code == 200: try: data = resp.json() - # logging.info(data) + # logger.info(data) except ValueError: return {"ok": False, "status": 200, "error": "Respuesta 200 sin JSON válido", "raw": resp.text} return {"ok": True, "status": 200, "data": data} @@ -106,10 +106,10 @@ def crear_factura(payload, return {"ok": False, "status": resp.status_code, "error": f"HTTP {resp.status_code}", "raw": resp.text} except requests.RequestException as e: - logging.error("Error de conexión con la API Verifacti: %s", e) + logger.error("Error de conexión con la API Verifacti: %s", e) return False, None, str(e) except ValueError as e: - logging.error("Respuesta no es JSON válido: %s", e) + logger.error("Respuesta no es JSON válido: %s", e) return False, None, "Respuesta no es JSON válido" @@ -140,18 +140,18 @@ def validar_nif( resp = requests.post( url, json=payload, headers=headers, timeout=timeout) if resp.status_code != 200: - logging.info(f"ERRRRRROOOOOOORRRRR LLAMADA REST API") + logger.info(f"ERRRRRROOOOOOORRRRR LLAMADA REST API") # return False, None, f"HTTP {resp.status_code}: {resp.text}" data = resp.json() resultado = data.get("resultado", "NO IDENTIFICADO") - logging.info(f"Resultado Verifacti: {resultado}") + logger.info(f"Resultado Verifacti: {resultado}") return resultado == "IDENTIFICADO" except requests.RequestException as e: - logging.error("Error de conexión con la API Verifacti: %s", e) + logger.error("Error de conexión con la API Verifacti: %s", e) return False, None, str(e) except ValueError as e: - logging.error("Respuesta no es JSON válido: %s", e) + logger.error("Respuesta no es JSON válido: %s", e) return False, None, "Respuesta no es JSON válido" diff --git a/app/utils/tax_catalog_helper.py b/app/utils/tax_catalog_helper.py index 1bc5194..514e553 100644 --- a/app/utils/tax_catalog_helper.py +++ b/app/utils/tax_catalog_helper.py @@ -1,4 +1,4 @@ -import logging +from app.config import logger import json from decimal import Decimal from typing import Any, Dict, Iterable, Optional, Tuple diff --git a/app/utils/text_converter.py b/app/utils/text_converter.py index 22c6296..7321cc5 100644 --- a/app/utils/text_converter.py +++ b/app/utils/text_converter.py @@ -1,5 +1,5 @@ -import logging import re +from app.config import logger def text_converter(texto, charset_destino='ISO8859_1', longitud_maxima=None): @@ -24,18 +24,18 @@ def text_converter(texto, charset_destino='ISO8859_1', longitud_maxima=None): # Si se especifica una longitud máxima, truncar el texto if longitud_maxima and len(texto_convertido) > longitud_maxima: - logging.warning( + logger.warning( f"El texto ha sido truncado de {len(texto_convertido)} a {longitud_maxima} caracteres.") texto_convertido = texto_convertido[:longitud_maxima] return texto_convertido except UnicodeEncodeError as e: - logging.error( + logger.error( f"Error al convertir texto a {charset_destino}: {str(e)}") return "" except Exception as e: - logging.error(f"Error inesperado al convertir texto: {str(e)}") + logger.error(f"Error inesperado al convertir texto: {str(e)}") return "" diff --git a/docker-compose.yml b/docker-compose.yml index 1b7a400..7f80931 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,17 +1,41 @@ services: - uecko_sync: - container_name: uecko_sync_app:v1.0.8 - env_file: ".env.production" - build: . - #volumes: - #- logs:/var/log/uecko_sync_app - networks: - - presupuestador-uecko_private - restart: unless-stopped + factuges_sync: + image: "factuges-sync-factuges:acana-latest" + container_name: "factuges-sync-factuges-acana" + restart: "no" + environment: + ENV: "prod" + LOCAL_TZ: "Europe/Madrid" + LAST_RUN_PATH: "${LAST_RUN_PATH}" -#volumes: -# logs: + FACTUGES_HOST: "${FACTUGES_HOST}" + FACTUGES_PORT: "${FACTUGES_PORT}" + FACTUGES_DATABASE: "${FACTUGES_DATABASE}" + FACTUGES_USER: "${FACTUGES_USER}" + FACTUGES_PASSWORD: "${FACTUGES_PASSWORD}" -networks: - presupuestador-uecko_private: - external: true + FWEB_MYSQL_HOST: "db" + FWEB_MYSQL_PORT: "${DB_PORT}" + FWEB_MYSQL_DATABASE: "${DB_NAME}" + FWEB_MYSQL_USER: "${DB_USER}" + FWEB_MYSQL_PASSWORD: "${DB_PASS}" + + CTE_COMPANY_ID: "${CTE_COMPANY_ID}" + CTE_SERIE: "${CTE_SERIE}" + CTE_STATUS_INVOICE: "${CTE_STATUS_INVOICE}" + CTE_IS_PROFORMA: "${CTE_IS_PROFORMA}" + CTE_STATUS_VERIFACTU: "${CTE_STATUS_VERIFACTU}" + CTE_LANGUAGE_CODE: "${CTE_LANGUAGE_CODE}" + CTE_COUNTRY_CODE: "${CTE_COUNTRY_CODE}" + CTE_IS_COMPANY: "${CTE_IS_COMPANY}" + CTE_SYNC_RESULT_OK: "${CTE_SYNC_RESULT_OK}" + CTE_SYNC_RESULT_FAIL: "${CTE_SYNC_RESULT_FAIL}" + depends_on: + db: + condition: service_healthy + networks: + - internal + - edge + volumes: + - ./volumes/db_sync/logs:/app/logs + - ./volumes/db_sync/last_run_factuges.ini:/app/last_run_factuges.ini:rw \ No newline at end of file diff --git a/enviroment/.env b/enviroment/.env index 55daaec..eb32565 100644 --- a/enviroment/.env +++ b/enviroment/.env @@ -1,4 +1,4 @@ -ENVIRONMENT = development +ENV = development LOCAL_TZ = Europe/Madrid LAST_RUN_PATH = ./app.last_run.txt #LOG_PATH = ./app.log @@ -25,11 +25,11 @@ CTE_COMPANY_ID = '019a9667-6a65-767a-a737-48234ee50a3a' VERIFACTU_API_KEY = vf_test_C03HL2F0X5OXSDRunjNFoMxD4IrRfK3kCC8PfcvCENI= #DESARROLLO -UECKO_MYSQL_HOST = localhost -UECKO_MYSQL_PORT = 3306 -UECKO_MYSQL_DATABASE = uecko_erp_sync -UECKO_MYSQL_USER = rodax -UECKO_MYSQL_PASSWORD = rodax +FWEB_MYSQL_HOST = localhost +FWEB_MYSQL_PORT = 3306 +FWEB_MYSQL_DATABASE = uecko_erp_sync +FWEB_MYSQL_USER = rodax +FWEB_MYSQL_PASSWORD = rodax CTE_SERIE = 'F25/' CTE_STATUS_INVOICE = 'issued' diff --git a/enviroment/.env.development b/enviroment/.env.development index 2d69569..72e99d7 100644 --- a/enviroment/.env.development +++ b/enviroment/.env.development @@ -1,6 +1,6 @@ -ENVIRONMENT = development +ENV = development LOCAL_TZ = Europe/Madrid #LOG_PATH = ./app.log @@ -18,17 +18,17 @@ FACTUGES_CONTRATO_TIPO_DETALLE = "Concepto" FACTUGES_NOMBRE_TARIFA = TARIFA 2024 FACTUGES_PRECIO_PUNTO = 3.31 -PRO_UECKO_MYSQL_HOST = 192.168.0.250 -PRO_UECKO_MYSQL_PORT = 3306 -PRO_UECKO_MYSQL_DATABASE = factuges_db -PRO_UECKO_MYSQL_USER = root -PRO_UECKO_MYSQL_PASSWORD = rootpass +PRO_FWEB_MYSQL_HOST = 192.168.0.250 +PRO_FWEB_MYSQL_PORT = 3306 +PRO_FWEB_MYSQL_DATABASE = factuges_db +PRO_FWEB_MYSQL_USER = root +PRO_FWEB_MYSQL_PASSWORD = rootpass -DEV_UECKO_MYSQL_HOST = 192.168.0.104 -DEV_UECKO_MYSQL_PORT = 3306 -DEV_UECKO_MYSQL_DATABASE = uecko_erp_sync -DEV_UECKO_MYSQL_USER = rodax -DEV_UECKO_MYSQL_PASSWORD = rodax +DEV_FWEB_MYSQL_HOST = 192.168.0.104 +DEV_FWEB_MYSQL_PORT = 3306 +DEV_FWEB_MYSQL_DATABASE = uecko_erp_sync +DEV_FWEB_MYSQL_USER = rodax +DEV_FWEB_MYSQL_PASSWORD = rodax BREVO_API_KEY = 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 diff --git a/enviroment/.env.production.sync.factuges b/enviroment/.env.production.sync.factuges index b7f9581..2c95d7d 100644 --- a/enviroment/.env.production.sync.factuges +++ b/enviroment/.env.production.sync.factuges @@ -1,4 +1,4 @@ -ENVIRONMENT = development +ENV = development LOCAL_TZ = Europe/Madrid LAST_RUN_PATH = ./app.last_run.txt #LOG_PATH = ./app.log @@ -11,11 +11,11 @@ FACTUGES_USER = sysdba FACTUGES_PASSWORD = masterkey #DESARROLLO -UECKO_MYSQL_HOST = localhost -UECKO_MYSQL_PORT = 3306 -UECKO_MYSQL_DATABASE = uecko_erp_sync -UECKO_MYSQL_USER = rodax -UECKO_MYSQL_PASSWORD = rodax +FWEB_MYSQL_HOST = localhost +FWEB_MYSQL_PORT = 3306 +FWEB_MYSQL_DATABASE = uecko_erp_sync +FWEB_MYSQL_USER = rodax +FWEB_MYSQL_PASSWORD = rodax #CONFIGURACION ACANA CTE_COMPANY_ID = '019a9667-6a65-767a-a737-48234ee50a3a' diff --git a/enviroment/.env_V b/enviroment/.env_V index ddb143d..344631a 100644 --- a/enviroment/.env_V +++ b/enviroment/.env_V @@ -1,14 +1,14 @@ -ENVIRONMENT = development +ENV = development LOCAL_TZ = Europe/Madrid LAST_RUN_PATH = ./app.last_run.txt #LOG_PATH = ./app.log #DESARROLLO -UECKO_MYSQL_HOST = localhost -UECKO_MYSQL_PORT = 3306 -UECKO_MYSQL_DATABASE = uecko_erp_sync -UECKO_MYSQL_USER = rodax -UECKO_MYSQL_PASSWORD = rodax +FWEB_MYSQL_HOST = localhost +FWEB_MYSQL_PORT = 3306 +FWEB_MYSQL_DATABASE = uecko_erp_sync +FWEB_MYSQL_USER = rodax +FWEB_MYSQL_PASSWORD = rodax VERIFACTU_BASE_URL = https://api.verifacti.com/ VERIFACTU_API_KEY = vf_test_ei8WYAvEq5dhSdEyQVjgCS8NZaNpEK2BljSHSUXf+Y0= diff --git a/enviroment/acana.env b/enviroment/acana.env new file mode 100644 index 0000000..b646a11 --- /dev/null +++ b/enviroment/acana.env @@ -0,0 +1,30 @@ +ENV = development +LOCAL_TZ = Europe/Madrid +LAST_RUN_PATH = /usr/share/factuges-app/last_run.txt + +FACTUGES_HOST = acana.mywire.org +FACTUGES_PORT = 63050 +FACTUGES_DATABASE = D:\Rodax\BD\FACTUGES.FDB +FACTUGES_USER = sysdba +FACTUGES_PASSWORD = masterkey +CTE_COMPANY_ID = '019a9667-6a65-767a-a737-48234ee50a3a' +VERIFACTU_API_KEY = vf_test_ei8WYAvEq5dhSdEyQVjgCS8NZaNpEK2BljSHSUXf+Y0= + +FWEB_MYSQL_HOST = db +FWEB_MYSQL_PORT = 3306 +FWEB_MYSQL_DATABASE = factuges_acana +FWEB_MYSQL_USER = acana +FWEB_MYSQL_PASSWORD = r@U8%GJ+2e/AWR + +CTE_SERIE = 'F25/' +CTE_STATUS_INVOICE = 'issued' +CTE_IS_PROFORMA = 0 +CTE_STATUS_VERIFACTU = 'Pendiente' +CTE_LANGUAGE_CODE = 'es' #En uecko vendrá de su ficha +CTE_COUNTRY_CODE = 'es' #En uecko vendrá de su ficha +CTE_IS_COMPANY = 1 +CTE_SYNC_RESULT_OK = 1 +CTE_SYNC_RESULT_FAIL = 2 + +VERIFACTU_BASE_URL = https://api.verifacti.com/ +VERIFACTU_NIFS_API_KEY = vfn_osYpNdqSzAdTAHpazXG2anz4F3o0gfbSb5FFrCBZcno= diff --git a/enviroment/dev.env b/enviroment/dev.env index dabd2d5..3b06498 100644 --- a/enviroment/dev.env +++ b/enviroment/dev.env @@ -1,4 +1,4 @@ -ENVIRONMENT = development +ENV = development LOCAL_TZ = Europe/Madrid LAST_RUN_PATH = ./app.last_run.txt #LOG_PATH = ./app.log @@ -25,11 +25,11 @@ CTE_COMPANY_ID = '019a9667-6a65-767a-a737-48234ee50a3a' VERIFACTU_API_KEY = vf_test_C03HL2F0X5OXSDRunjNFoMxD4IrRfK3kCC8PfcvCENI= #DESARROLLO -UECKO_MYSQL_HOST = localhost -UECKO_MYSQL_PORT = 3306 -UECKO_MYSQL_DATABASE = uecko_erp_sync -UECKO_MYSQL_USER = rodax -UECKO_MYSQL_PASSWORD = rodax +FWEB_MYSQL_HOST = localhost +FWEB_MYSQL_PORT = 3306 +FWEB_MYSQL_DATABASE = uecko_erp_sync +FWEB_MYSQL_USER = rodax +FWEB_MYSQL_PASSWORD = rodax CTE_SERIE = 'F25/' CTE_STATUS_INVOICE = 'issued' diff --git a/enviroment/prod.env b/enviroment/prod.env deleted file mode 100644 index 6c21ba2..0000000 --- a/enviroment/prod.env +++ /dev/null @@ -1,4 +0,0 @@ -DB_HOST=prod-db -DB_USER=prod_user -DB_PASS=supersecret -RUN_INTERVAL_MINUTES=5 \ No newline at end of file diff --git a/scripts/cronjob b/scripts/cronjob index bf43463..68fbae7 100644 --- a/scripts/cronjob +++ b/scripts/cronjob @@ -2,12 +2,12 @@ # Sincronización FactuGES → cada 5 minutos */5 * * * * docker run --rm \ - -e ENV=prod \ + -e ENV=production \ factuges-sync-factuges:acme-latest \ >> /var/log/factuges-sync/factuges.log 2>&1 # Sincronización Verifactu → cada 7 minutos */7 * * * * docker run --rm \ - -e ENV=prod \ + -e ENV=production \ factuges-sync-verifactu:acme-latest \ >> /var/log/factuges-sync/verifactu.log 2>&1 diff --git a/scripts/deploy-cron.sh b/scripts/deploy-cron.sh index 6952c7f..b0304cf 100755 --- a/scripts/deploy-cron.sh +++ b/scripts/deploy-cron.sh @@ -23,13 +23,13 @@ cat > "$CRON_FILE" <> /var/log/factuges-sync/factuges.log 2>&1 # Sincronización Verifactu → cada 7 minutos */7 * * * * docker run --rm \ - -e ENV=prod \ + -e ENV=production \ factuges-sync-verifactu:${COMPANY}-latest \ >> /var/log/factuges-sync/verifactu.log 2>&1 EOF diff --git a/setup.cfg b/setup.cfg index 489e165..6977bdd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = factuges-sync -version = 0.1.0 +version = 0.0.15 description = ETL job to sync data from legacy DB to MariaDB author = Rodax Software author_email = info@rodax-software.com