.
This commit is contained in:
parent
a951be5b87
commit
634d04dc10
28
.env
28
.env
@ -1,5 +1,6 @@
|
|||||||
ENVIRONMENT = development
|
ENVIRONMENT = development
|
||||||
LOCAL_TZ = Europe/Madrid
|
LOCAL_TZ = Europe/Madrid
|
||||||
|
LAST_RUN_PATH = ./app.last_run.txt
|
||||||
#LOG_PATH = ./app.log
|
#LOG_PATH = ./app.log
|
||||||
|
|
||||||
#DESARROLLO ACANA
|
#DESARROLLO ACANA
|
||||||
@ -9,20 +10,6 @@ FACTUGES_DATABASE = C:\Codigo Acana\Output\Debug\Database\FACTUGES.FDB
|
|||||||
FACTUGES_USER = sysdba
|
FACTUGES_USER = sysdba
|
||||||
FACTUGES_PASSWORD = masterkey
|
FACTUGES_PASSWORD = masterkey
|
||||||
|
|
||||||
# PRODUCCION RODAX FACTUGES FIREBIRD
|
|
||||||
#FACTUGES_HOST = 192.168.0.101
|
|
||||||
#FACTUGES_PORT = 3050
|
|
||||||
#FACTUGES_DATABASE = C:\FactuGES\FACTUGES.FDB
|
|
||||||
#FACTUGES_USER = sysdba
|
|
||||||
#FACTUGES_PASSWORD = masterkey
|
|
||||||
|
|
||||||
# PRODUCCION RODAX MYSQL
|
|
||||||
#UECKO_MYSQL_HOST = 192.168.0.250
|
|
||||||
#UECKO_MYSQL_PORT = 3306
|
|
||||||
#UECKO_MYSQL_DATABASE = rodax_db
|
|
||||||
#UECKO_MYSQL_USER = rodax_usr
|
|
||||||
#UECKO_MYSQL_PASSWORD = supersecret
|
|
||||||
|
|
||||||
#DESARROLLO
|
#DESARROLLO
|
||||||
UECKO_MYSQL_HOST = localhost
|
UECKO_MYSQL_HOST = localhost
|
||||||
UECKO_MYSQL_PORT = 3306
|
UECKO_MYSQL_PORT = 3306
|
||||||
@ -35,25 +22,16 @@ CTE_COMPANY_ID = '019a9667-6a65-767a-a737-48234ee50a3a'
|
|||||||
CTE_SERIE = 'F25/'
|
CTE_SERIE = 'F25/'
|
||||||
CTE_STATUS_INVOICE = 'issued'
|
CTE_STATUS_INVOICE = 'issued'
|
||||||
CTE_IS_PROFORMA = 0
|
CTE_IS_PROFORMA = 0
|
||||||
CTE_STATUS_VERIFACTU = 'pendiente'
|
CTE_STATUS_VERIFACTU = 'Pendiente'
|
||||||
CTE_LANGUAGE_CODE = 'es' #En uecko vendrá de su ficha
|
CTE_LANGUAGE_CODE = 'es' #En uecko vendrá de su ficha
|
||||||
CTE_COUNTRY_CODE = 'es' #En uecko vendrá de su ficha
|
CTE_COUNTRY_CODE = 'es' #En uecko vendrá de su ficha
|
||||||
CTE_IS_COMPANY = 1
|
CTE_IS_COMPANY = 1
|
||||||
|
|
||||||
#CONFIGURACION RODAX
|
|
||||||
#CTE_COMPANY_ID = '5e4dc5b3-96b9-4968-9490-14bd032fec5f'
|
|
||||||
#CTE_SERIE = 'F25/'
|
|
||||||
#CTE_STATUS_INVOICE = 'approved'
|
|
||||||
#CTE_IS_PROFORMA = 1
|
|
||||||
#CTE_STATUS_VERIFACTU = 'Pendiente'
|
|
||||||
|
|
||||||
|
|
||||||
VERIFACTU_BASE_URL = https://api.verifacti.com/
|
VERIFACTU_BASE_URL = https://api.verifacti.com/
|
||||||
VERIFACTU_API_KEY = vf_test_ei8WYAvEq5dhSdEyQVjgCS8NZaNpEK2BljSHSUXf+Y0=
|
VERIFACTU_API_KEY = vf_test_ei8WYAvEq5dhSdEyQVjgCS8NZaNpEK2BljSHSUXf+Y0=
|
||||||
VERIFACTU_NIFS_API_KEY = vfn_osYpNdqSzAdTAHpazXG2anz4F3o0gfbSb5FFrCBZcno=
|
VERIFACTU_NIFS_API_KEY = vfn_osYpNdqSzAdTAHpazXG2anz4F3o0gfbSb5FFrCBZcno=
|
||||||
|
|
||||||
|
|
||||||
#BREVO_API_KEY = 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
|
#BREVO_API_KEY = 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
|
||||||
#BREVO_EMAIL_TEMPLATE = 1
|
#BREVO_EMAIL_TEMPLATE = 1
|
||||||
#MAIL_FROM = 'no-reply@presupuestos.uecko.com'
|
#MAIL_FROM = 'no-reply@presupuestos.uecko.com'
|
||||||
#MAIL_TO = 'soporte@rodax-software.com'
|
#MAIL_TO = 'soporte@rodax-software.com'
|
||||||
@ -1,57 +0,0 @@
|
|||||||
ENVIRONMENT = production
|
|
||||||
LOCAL_TZ = Europe/Madrid
|
|
||||||
#LOG_PATH = /var/log/uecko_sync_app/uecko_sync_app.log
|
|
||||||
|
|
||||||
FACTUGES_HOST = 83.48.36.692
|
|
||||||
FACTUGES_PORT = 3050
|
|
||||||
FACTUGES_DATABASE = D:\RODAX\FACTUGES\BD\FACTUGES_FABRICA.FDB
|
|
||||||
FACTUGES_USER = sysdba
|
|
||||||
FACTUGES_PASSWORD = abeto2010
|
|
||||||
|
|
||||||
# DESARROLLO ALISO FACTUGES FIREBIRD
|
|
||||||
#FACTUGES_HOST = 192.168.0.105
|
|
||||||
#FACTUGES_PORT = 3050
|
|
||||||
#FACTUGES_DATABASE = C:\Codigo Acana\Output\Debug\Database\FACTUGES.FDB
|
|
||||||
#FACTUGES_USER = sysdba
|
|
||||||
#FACTUGES_PASSWORD = masterkey
|
|
||||||
|
|
||||||
# PRODUCCION RODAX FACTUGES FIREBIRD
|
|
||||||
#FACTUGES_HOST = 192.168.0.101
|
|
||||||
#FACTUGES_PORT = 3050
|
|
||||||
#FACTUGES_DATABASE = C:\FactuGES\FACTUGES.FDB
|
|
||||||
#FACTUGES_USER = sysdba
|
|
||||||
#FACTUGES_PASSWORD = masterkey
|
|
||||||
|
|
||||||
# PRODUCCION RODAX MYSQL
|
|
||||||
#UECKO_MYSQL_HOST = 192.168.0.250
|
|
||||||
#UECKO_MYSQL_PORT = 3306
|
|
||||||
#UECKO_MYSQL_DATABASE = rodax_db
|
|
||||||
#UECKO_MYSQL_USER = rodax_usr
|
|
||||||
#UECKO_MYSQL_PASSWORD = supersecret
|
|
||||||
|
|
||||||
UECKO_MYSQL_HOST = mariadb2
|
|
||||||
UECKO_MYSQL_PORT = 3306
|
|
||||||
UECKO_MYSQL_DATABASE = uecko
|
|
||||||
UECKO_MYSQL_USER = uecko
|
|
||||||
UECKO_MYSQL_PASSWORD = u8Ax5Nw3%sjd
|
|
||||||
|
|
||||||
|
|
||||||
BREVO_API_KEY = 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
|
|
||||||
BREVO_EMAIL_TEMPLATE = 1
|
|
||||||
MAIL_FROM = 'no-reply@presupuestos.uecko.com'
|
|
||||||
MAIL_TO = 'pedidos@uecko.com'
|
|
||||||
|
|
||||||
VERIFACTU_BASE_URL = https://api.verifacti.com/
|
|
||||||
VERIFACTU_API_KEY = vf_test_kY9FoI86dH+g1a5hmEnb/0YcLTlMFlu+tpp9iMZp020=
|
|
||||||
VERIFACTU_NIFS_API_KEY = vfn_osYpNdqSzAdTAHpazXG2anz4F3o0gfbSb5FFrCBZcno=
|
|
||||||
|
|
||||||
#VERIFACTU_RODAX_TEST_API_KEY = vf_test_C03HL2F0X5OXSDRunjNFoMxD4IrRfK3kCC8PfcvCENI=
|
|
||||||
#VERIFACTU_RODAX_PROD_API_KEY = vf_prod_yfjonNPv2E4Fij+5J0hct0zCgUeFYT2dZzb23UZlM+Q=
|
|
||||||
|
|
||||||
#VERIFACTU_ALISO_TEST_API_KEY = vf_test_ei8WYAvEq5dhSdEyQVjgCS8NZaNpEK2BljSHSUXf+Y0=
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
33
.env.production.sync.factuges
Normal file
33
.env.production.sync.factuges
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
ENVIRONMENT = development
|
||||||
|
LOCAL_TZ = Europe/Madrid
|
||||||
|
LAST_RUN_PATH = ./app.last_run.txt
|
||||||
|
#LOG_PATH = ./app.log
|
||||||
|
|
||||||
|
#DESARROLLO ACANA
|
||||||
|
FACTUGES_HOST = 192.168.0.105
|
||||||
|
FACTUGES_PORT = 3050
|
||||||
|
FACTUGES_DATABASE = C:\Codigo Acana\Output\Debug\Database\FACTUGES.FDB
|
||||||
|
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
|
||||||
|
|
||||||
|
#CONFIGURACION ACANA
|
||||||
|
CTE_COMPANY_ID = '019a9667-6a65-767a-a737-48234ee50a3a'
|
||||||
|
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
|
||||||
|
|
||||||
|
#BREVO_API_KEY = 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
|
||||||
|
#BREVO_EMAIL_TEMPLATE = 1
|
||||||
|
#MAIL_FROM = 'no-reply@presupuestos.uecko.com'
|
||||||
|
#MAIL_TO = 'soporte@rodax-software.com'
|
||||||
21
.env_V
Normal file
21
.env_V
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
ENVIRONMENT = 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
|
||||||
|
|
||||||
|
VERIFACTU_BASE_URL = https://api.verifacti.com/
|
||||||
|
VERIFACTU_API_KEY = vf_test_ei8WYAvEq5dhSdEyQVjgCS8NZaNpEK2BljSHSUXf+Y0=
|
||||||
|
VERIFACTU_NIFS_API_KEY = vfn_osYpNdqSzAdTAHpazXG2anz4F3o0gfbSb5FFrCBZcno=
|
||||||
|
|
||||||
|
|
||||||
|
#BREVO_API_KEY = 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
|
||||||
|
#BREVO_EMAIL_TEMPLATE = 1
|
||||||
|
#MAIL_FROM = 'no-reply@presupuestos.uecko.com'
|
||||||
|
#MAIL_TO = 'soporte@rodax-software.com'
|
||||||
1
app.last_run.txt
Normal file
1
app.last_run.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
2025-11-27 18:58:46
|
||||||
1
app/__version_sync_verifactu__.py
Normal file
1
app/__version_sync_verifactu__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
__version__ = "1.0.0"
|
||||||
@ -10,6 +10,7 @@ def load_config():
|
|||||||
return {
|
return {
|
||||||
'ENVIRONMENT': os.getenv('ENVIRONMENT'),
|
'ENVIRONMENT': os.getenv('ENVIRONMENT'),
|
||||||
'LOCAL_TZ': os.getenv('LOCAL_TZ', 'Europe/Madrid'),
|
'LOCAL_TZ': os.getenv('LOCAL_TZ', 'Europe/Madrid'),
|
||||||
|
'LAST_RUN_PATH': os.getenv('LAST_RUN_PATH'),
|
||||||
# 'LOG_PATH': os.getenv('LOG_PATH', 'app.log'),
|
# 'LOG_PATH': os.getenv('LOG_PATH', 'app.log'),
|
||||||
|
|
||||||
'FACTUGES_HOST': os.getenv('FACTUGES_HOST'),
|
'FACTUGES_HOST': os.getenv('FACTUGES_HOST'),
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from .db_connection import get_factuges_connection
|
from .db_connection import get_factuges_connection
|
||||||
from .db_connection import get_mysql_connection
|
from .db_connection import get_mysql_connection
|
||||||
from .sync_invoices import sync_invoices
|
from .sync_invoices_factuges import sync_invoices_factuges
|
||||||
from .sync_invoices_verifactu import sync_invoices_verifactu
|
from .sync_invoices_verifactu import sync_invoices_verifactu
|
||||||
|
|||||||
@ -121,14 +121,16 @@ SELECT_FACTUGES_FACTURAS_CLIENTE = (
|
|||||||
f"LEFT JOIN TIPOS_IVA AS ti ON fac.ID_TIPO_IVA = ti.ID "
|
f"LEFT JOIN TIPOS_IVA AS ti ON fac.ID_TIPO_IVA = ti.ID "
|
||||||
f"LEFT JOIN FACTURAS_CLIENTE_DETALLES as facdet ON fac.ID = facdet.ID_FACTURA "
|
f"LEFT JOIN FACTURAS_CLIENTE_DETALLES as facdet ON fac.ID = facdet.ID_FACTURA "
|
||||||
f"WHERE "
|
f"WHERE "
|
||||||
f"(fac.VERIFACTU > 0) "
|
f"(fac.VERIFACTU = 1) "
|
||||||
f"AND (fac.ID_VERIFACTU is null)"
|
f"AND (fac.ID_VERIFACTU is null)"
|
||||||
f"ORDER BY (fac.ID)"
|
f"ORDER BY (fac.ID)"
|
||||||
)
|
)
|
||||||
|
|
||||||
UPDATE_FACTUGES_LINK = (
|
UPDATE_FACTUGES_LINK = (
|
||||||
"UPDATE FACTURAS_CLIENTE "
|
"UPDATE FACTURAS_CLIENTE "
|
||||||
"SET ID_VERIFACTU=? "
|
"SET VERIFACTU=?, "
|
||||||
|
"ID_VERIFACTU=?, "
|
||||||
|
"VERIFACTU_NOTES =? "
|
||||||
"WHERE ID=?"
|
"WHERE ID=?"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,10 @@ from uuid6 import uuid7
|
|||||||
from config import load_config
|
from config import load_config
|
||||||
from . import sql_sentences as SQL
|
from . import sql_sentences as SQL
|
||||||
from . import normalizations as NORMALIZA
|
from . import normalizations as NORMALIZA
|
||||||
|
from utils import validar_nif
|
||||||
|
|
||||||
|
|
||||||
def sync_invoices(conn_factuges, conn_mysql, last_execution_date):
|
def sync_invoices_factuges(conn_factuges, conn_mysql, last_execution_date):
|
||||||
config = load_config()
|
config = load_config()
|
||||||
|
|
||||||
# LIMPIAMOS LAS FACTURAS DE FACTUGES QUE HAYAN SIDO ELIMINADAS DEL PROGRAMA NUEVO DE FACTURACION, PARA QUE PUEDAN SER MODIFICADAS
|
# LIMPIAMOS LAS FACTURAS DE FACTUGES QUE HAYAN SIDO ELIMINADAS DEL PROGRAMA NUEVO DE FACTURACION, PARA QUE PUEDAN SER MODIFICADAS
|
||||||
@ -67,7 +68,7 @@ def sync_invoices(conn_factuges, conn_mysql, last_execution_date):
|
|||||||
conn_mysql, tuplas_seleccionadas, conn_factuges, config)
|
conn_mysql, tuplas_seleccionadas, conn_factuges, config)
|
||||||
else:
|
else:
|
||||||
logging.info(
|
logging.info(
|
||||||
"There are no new FACTURAS rows since the last run.")
|
"There are NOT new FACTURAS rows since the last run.")
|
||||||
|
|
||||||
|
|
||||||
def sync_delete_invoices(conn_factuges, ids_verifactu_deleted, config):
|
def sync_delete_invoices(conn_factuges, ids_verifactu_deleted, config):
|
||||||
@ -101,6 +102,8 @@ def sync_invoices_from_FACTUGES(conn_mysql, filas, conn_factuges, config):
|
|||||||
cursor_FactuGES = None
|
cursor_FactuGES = None
|
||||||
factuges_id_anterior = None
|
factuges_id_anterior = None
|
||||||
num_fac_procesed = 0
|
num_fac_procesed = 0
|
||||||
|
customer_valid = True
|
||||||
|
invoice_id = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cursorMySQL = conn_mysql.cursor()
|
cursorMySQL = conn_mysql.cursor()
|
||||||
@ -120,47 +123,56 @@ def sync_invoices_from_FACTUGES(conn_mysql, filas, conn_factuges, config):
|
|||||||
factuges_id = int(factura_detalle['ID_FACTURA'])
|
factuges_id = int(factura_detalle['ID_FACTURA'])
|
||||||
if factuges_id_anterior is None or factuges_id_anterior != factuges_id:
|
if factuges_id_anterior is None or factuges_id_anterior != factuges_id:
|
||||||
|
|
||||||
# Comprobamos si existe el cliente del primer item de la factura
|
# Validamos que el cif de la factura exista en la AEAT si no es así no se hace la sincro de la factura
|
||||||
customer_id = get_or_create_customer(
|
sync_result = 1
|
||||||
cursorMySQL,
|
customer_valid = validar_nif(customer_fields["tin"], customer_fields["name"], config)
|
||||||
config['CTE_COMPANY_ID'],
|
if customer_valid:
|
||||||
str(factura_detalle["ID_CLIENTE"]),
|
# Comprobamos si existe el cliente del primer item de la factura
|
||||||
customer_fields,
|
customer_id = get_or_create_customer(
|
||||||
)
|
cursorMySQL,
|
||||||
|
config['CTE_COMPANY_ID'],
|
||||||
|
str(factura_detalle["ID_CLIENTE"]),
|
||||||
|
customer_fields,
|
||||||
|
)
|
||||||
|
|
||||||
# ---- forma de pago
|
# ---- forma de pago
|
||||||
pm_id = get_or_create_payment_method(
|
pm_id = get_or_create_payment_method(
|
||||||
cursorMySQL,
|
cursorMySQL,
|
||||||
str(factura_detalle["ID_FORMA_PAGO"]),
|
str(factura_detalle["ID_FORMA_PAGO"]),
|
||||||
str(factura_detalle["DES_FORMA_PAGO"]),
|
str(factura_detalle["DES_FORMA_PAGO"]),
|
||||||
)
|
)
|
||||||
# campos pendiente de revisar en un futuro
|
# campos pendiente de revisar en un futuro
|
||||||
# xxxxxxx = str(factura_detalle['ID_FORMA_PAGO']) según este id se debe de guardar en la factura los vencimiento asociados a la forma de pago
|
# xxxxxxx = str(factura_detalle['ID_FORMA_PAGO']) según este id se debe de guardar en la factura los vencimiento asociados a la forma de pago
|
||||||
|
|
||||||
# ---- cabecera factura
|
# ---- cabecera factura
|
||||||
invoice_id = insert_invoice_header(cursorMySQL, customer_fields, header_invoice_fields, customer_id, pm_id, str(
|
invoice_id = insert_invoice_header(cursorMySQL, customer_fields, header_invoice_fields, customer_id, pm_id, str(
|
||||||
factura_detalle["DES_FORMA_PAGO"]), config
|
factura_detalle["DES_FORMA_PAGO"]), config
|
||||||
)
|
)
|
||||||
|
|
||||||
# ---- impuestos cabecera
|
# ---- impuestos cabecera
|
||||||
insert_header_taxes_if_any(
|
insert_header_taxes_if_any(
|
||||||
cursorMySQL, invoice_id, factura_detalle['IVA'], factura_detalle['RECARGO_EQUIVALENCIA'], header_invoice_fields)
|
cursorMySQL, invoice_id, factura_detalle['IVA'], factura_detalle['RECARGO_EQUIVALENCIA'], header_invoice_fields)
|
||||||
|
|
||||||
# ---- registro verifactu
|
# ---- registro verifactu
|
||||||
insert_verifactu_record(
|
insert_verifactu_record(
|
||||||
cursorMySQL, header_invoice_fields, invoice_id, config)
|
cursorMySQL, header_invoice_fields, invoice_id, config)
|
||||||
|
|
||||||
|
else:
|
||||||
|
sync_result = 2
|
||||||
|
cadena = (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(cadena)
|
||||||
|
|
||||||
# Guardamos en Factuges el id de la customer_invoice
|
# Guardamos en Factuges el id de la customer_invoice
|
||||||
logging.info(
|
logging.info(
|
||||||
f"Updating FACTURAS_CLIENTE {invoice_id} {factuges_id}")
|
f"Updating FACTURAS_CLIENTE {sync_result} {invoice_id} {factuges_id} {cadena}")
|
||||||
cursor_FactuGES.execute(
|
cursor_FactuGES.execute(SQL.UPDATE_FACTUGES_LINK, (sync_result, invoice_id, cadena, factuges_id))
|
||||||
SQL.UPDATE_FACTUGES_LINK, (invoice_id, factuges_id))
|
|
||||||
num_fac_procesed += 1
|
num_fac_procesed += 1
|
||||||
|
|
||||||
# Insertamos detalles y taxes correspondientes siempre
|
# Insertamos detalles y taxes correspondientes siempre que hayamos insertado cabecera
|
||||||
# Siempre insertamos la línea
|
if customer_valid:
|
||||||
insert_item_and_taxes(cursorMySQL, invoice_id,
|
insert_item_and_taxes(cursorMySQL, invoice_id, details_invoice_fields)
|
||||||
details_invoice_fields)
|
|
||||||
|
|
||||||
# Asignamos el id factura anterior para no volver a inserta cabecera
|
# Asignamos el id factura anterior para no volver a inserta cabecera
|
||||||
factuges_id_anterior = factuges_id
|
factuges_id_anterior = factuges_id
|
||||||
@ -240,7 +252,7 @@ def insert_invoice_header(cur: str, cf: Dict[str, Any], hif: Dict[str, Any], cus
|
|||||||
"""
|
"""
|
||||||
invoice_id = str(uuid7())
|
invoice_id = str(uuid7())
|
||||||
|
|
||||||
logging.info("Inserting invoice %s %s %s %s",
|
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'])
|
invoice_id, hif.get('reference'), hif.get('invoice_date'), hif.get('operation_date'), config['CTE_STATUS_INVOICE'])
|
||||||
cur.execute(
|
cur.execute(
|
||||||
SQL.INSERT_INVOICE,
|
SQL.INSERT_INVOICE,
|
||||||
@ -298,8 +310,7 @@ def insert_item_and_taxes(cur, invoice_id: str, fields: Dict[str, Any]) -> None:
|
|||||||
"""
|
"""
|
||||||
item_id = str(uuid7())
|
item_id = str(uuid7())
|
||||||
|
|
||||||
logging.info("Inserting item %s pos=%s qty=%s",
|
# logging.info("Inserting item %s pos=%s qty=%s", item_id, fields.get('position'), fields.get('quantity_value'))
|
||||||
item_id, fields.get('position'), fields.get('quantity_value'))
|
|
||||||
cur.execute(
|
cur.execute(
|
||||||
SQL.INSERT_INVOICE_ITEM,
|
SQL.INSERT_INVOICE_ITEM,
|
||||||
(item_id, invoice_id, fields.get('position'), fields.get('description'), fields.get('quantity_value'),
|
(item_id, invoice_id, fields.get('position'), fields.get('description'), fields.get('quantity_value'),
|
||||||
@ -1,12 +1,12 @@
|
|||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
import __version__
|
|
||||||
|
|
||||||
|
from __version_sync_factuges__ import __version__
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from dateutil import tz
|
from dateutil import tz
|
||||||
from config import setup_logging, load_config
|
from config import setup_logging, load_config
|
||||||
from db import get_mysql_connection, get_factuges_connection, sync_invoices, sync_invoices_verifactu
|
from db import get_mysql_connection, get_factuges_connection, sync_invoices_factuges
|
||||||
from utils import obtener_fecha_ultima_ejecucion, actualizar_fecha_ultima_ejecucion, log_system_metrics, send_orders_mail, limpiar_cadena
|
from utils import obtener_fecha_ultima_ejecucion, actualizar_fecha_ultima_ejecucion, log_system_metrics, send_orders_mail
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@ -19,8 +19,8 @@ def main():
|
|||||||
# Logging
|
# Logging
|
||||||
setup_logging()
|
setup_logging()
|
||||||
|
|
||||||
logging.info("== START ==")
|
logging.info("== START SYNC FACTUGES ==")
|
||||||
logging.info(f"Version: {__version__.__version__}")
|
logging.info(f"Version: {__version__}")
|
||||||
logging.info(f"Environment: {config['ENVIRONMENT']}")
|
logging.info(f"Environment: {config['ENVIRONMENT']}")
|
||||||
log_system_metrics()
|
log_system_metrics()
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ def main():
|
|||||||
conn_mysql = None
|
conn_mysql = None
|
||||||
try:
|
try:
|
||||||
# Obtener la fecha de la última ejecución del programa
|
# Obtener la fecha de la última ejecución del programa
|
||||||
last_execution_date_utc = obtener_fecha_ultima_ejecucion()
|
last_execution_date_utc = obtener_fecha_ultima_ejecucion(config['LAST_RUN_PATH'])
|
||||||
last_execution_date_local_tz = last_execution_date_utc.astimezone(
|
last_execution_date_local_tz = last_execution_date_utc.astimezone(
|
||||||
tz=local_tz).strftime("%Y-%m-%d %H:%M:%S")
|
tz=local_tz).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
@ -41,31 +41,19 @@ def main():
|
|||||||
conn_factuges = get_factuges_connection(config)
|
conn_factuges = get_factuges_connection(config)
|
||||||
conn_mysql = get_mysql_connection(config)
|
conn_mysql = get_mysql_connection(config)
|
||||||
|
|
||||||
# Sync invoices
|
# Sincronizamos
|
||||||
logging.info(
|
logging.info(
|
||||||
f">>>>>>>>>>> Sync invoices FactuGES escritorio to FactuGES web")
|
f">>>>>>>>>>> INI Sync invoices FactuGES escritorio to FactuGES web")
|
||||||
sync_invoices(conn_factuges, conn_mysql, last_execution_date_local_tz)
|
sync_invoices_factuges(conn_factuges, conn_mysql, last_execution_date_local_tz)
|
||||||
|
|
||||||
# Confirmar los cambios
|
# Confirmar los cambios
|
||||||
conn_mysql.commit()
|
conn_mysql.commit()
|
||||||
conn_factuges.commit()
|
conn_factuges.commit()
|
||||||
conn_factuges.close()
|
conn_factuges.close()
|
||||||
conn_mysql.close()
|
conn_mysql.close()
|
||||||
logging.info(f"FIN Sync FactuGES web >>>>>>>>>>")
|
logging.info(f">>>>>>>>>>> FIN Sync invoices FactuGES escritorio to FactuGES web")
|
||||||
|
|
||||||
# ESTO OTRO DEBERIA SER OTRA TRANSACCION POR LO QUE HACEMOS NUEVA CONEXION
|
actualizar_fecha_ultima_ejecucion(config['LAST_RUN_PATH'])
|
||||||
# Vamos que deberia ir en otro lado
|
|
||||||
conn_mysql = get_mysql_connection(config)
|
|
||||||
|
|
||||||
# Sync Verifactu
|
|
||||||
logging.info(
|
|
||||||
f">>>>>>>>>> Sync facturas emitidas en FactuGES web to Verifactu")
|
|
||||||
sync_invoices_verifactu(conn_mysql, last_execution_date_local_tz)
|
|
||||||
conn_mysql.commit()
|
|
||||||
conn_mysql.close()
|
|
||||||
logging.info(f"FIN Sync Verifactu >>>>>>>>>>")
|
|
||||||
|
|
||||||
# actualizar_fecha_ultima_ejecucion()
|
|
||||||
|
|
||||||
# Enviar email
|
# Enviar email
|
||||||
# send_orders_mail(inserted_orders)
|
# send_orders_mail(inserted_orders)
|
||||||
81
app/sync_verifactu_main.py
Normal file
81
app/sync_verifactu_main.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from __version_sync_factuges__ import __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
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
# Cargar la configuración
|
||||||
|
config = load_config()
|
||||||
|
|
||||||
|
local_tz = tz.gettz(config['LOCAL_TZ'])
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
setup_logging()
|
||||||
|
|
||||||
|
logging.info("== START SYNC VERIFACTU ==")
|
||||||
|
logging.info(f"Version: {__version__}")
|
||||||
|
logging.info(f"Environment: {config['ENVIRONMENT']}")
|
||||||
|
log_system_metrics()
|
||||||
|
|
||||||
|
conn_factuges = None
|
||||||
|
conn_mysql = None
|
||||||
|
try:
|
||||||
|
# Obtener la fecha de la última ejecución del programa
|
||||||
|
last_execution_date_utc = obtener_fecha_ultima_ejecucion()
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Abrimos conexión con una única transacción para que todo esté controlado
|
||||||
|
conn_mysql = get_mysql_connection(config)
|
||||||
|
|
||||||
|
# Sync Verifactu
|
||||||
|
logging.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")
|
||||||
|
|
||||||
|
actualizar_fecha_ultima_ejecucion()
|
||||||
|
|
||||||
|
# Enviar email
|
||||||
|
# send_orders_mail(inserted_orders)
|
||||||
|
|
||||||
|
logging.info("== END (0) ==")
|
||||||
|
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) ==")
|
||||||
|
|
||||||
|
if conn_mysql is not None:
|
||||||
|
conn_mysql.rollback()
|
||||||
|
|
||||||
|
if conn_factuges is not None:
|
||||||
|
conn_factuges.rollback()
|
||||||
|
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if conn_factuges:
|
||||||
|
conn_factuges.close()
|
||||||
|
if conn_mysql:
|
||||||
|
conn_mysql.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@ -1,21 +1,60 @@
|
|||||||
|
from __future__ import annotations
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from dateutil import tz
|
from typing import Optional
|
||||||
|
import os
|
||||||
|
|
||||||
# Función para obtener la fecha de la última ejecución del programa desde un archivo de texto
|
DEFAULT_PATH = "./last_execution.txt"
|
||||||
|
FMT = "%Y-%m-%d %H:%M:%S"
|
||||||
|
|
||||||
|
|
||||||
def obtener_fecha_ultima_ejecucion():
|
def obtener_fecha_ultima_ejecucion(
|
||||||
|
path: str = DEFAULT_PATH,
|
||||||
|
*,
|
||||||
|
fallback: Optional[datetime] = None,
|
||||||
|
) -> datetime:
|
||||||
|
"""
|
||||||
|
Lee la última fecha de ejecución desde `path` y la devuelve como aware (UTC).
|
||||||
|
Si no existe o hay error de parseo, devuelve `fallback` (por defecto 2024-01-01 UTC).
|
||||||
|
"""
|
||||||
|
if fallback is None:
|
||||||
|
fallback = datetime(2024, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open('./last_execution.txt', 'r', encoding="utf8") as f:
|
with open(path, "r", encoding="utf8") as f:
|
||||||
fecha_str = f.read().strip()
|
fecha_str = f.read().strip()
|
||||||
return datetime.strptime(fecha_str, '%Y-%m-%d %H:%M:%S').astimezone(tz=tz.UTC)
|
# Se guarda como texto sin tz; interpretamos como UTC
|
||||||
|
dt_naive = datetime.strptime(fecha_str, FMT)
|
||||||
|
return dt_naive.replace(tzinfo=timezone.utc)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
# Si el archivo no existe, se asume que el programa nunca se ha ejecutado antes
|
return fallback
|
||||||
return datetime(2024, 1, 1, 0, 0, 0).astimezone(tz=tz.UTC)
|
except ValueError:
|
||||||
|
# Formato inválido en el archivo -> usar fallback
|
||||||
# Función para actualizar la fecha de la última ejecución del programa en el archivo de texto
|
return fallback
|
||||||
|
|
||||||
|
|
||||||
def actualizar_fecha_ultima_ejecucion():
|
def actualizar_fecha_ultima_ejecucion(
|
||||||
with open('./last_execution.txt', 'w', encoding="utf8") as f:
|
path: str = DEFAULT_PATH,
|
||||||
f.write(datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S'))
|
*,
|
||||||
|
momento: Optional[datetime] = None,
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Escribe en `path` la fecha/hora (UTC) en formato YYYY-MM-DD HH:MM:SS.
|
||||||
|
Si `momento` es None, usa ahora en UTC.
|
||||||
|
Crea directorios intermedios si no existen.
|
||||||
|
"""
|
||||||
|
if momento is None:
|
||||||
|
momento = datetime.now(timezone.utc)
|
||||||
|
else:
|
||||||
|
# Normalizamos a UTC si viene con tz; si es naive, asumimos UTC
|
||||||
|
if momento.tzinfo is None:
|
||||||
|
momento = momento.replace(tzinfo=timezone.utc)
|
||||||
|
else:
|
||||||
|
momento = momento.astimezone(timezone.utc)
|
||||||
|
|
||||||
|
# Asegurar carpeta si `path` incluye directorios
|
||||||
|
folder = os.path.dirname(os.path.abspath(path))
|
||||||
|
if folder and not os.path.exists(folder):
|
||||||
|
os.makedirs(folder, exist_ok=True)
|
||||||
|
|
||||||
|
with open(path, "w", encoding="utf8") as f:
|
||||||
|
f.write(momento.strftime(FMT))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user