.
This commit is contained in:
parent
a032383be3
commit
a8e4f76df2
@ -7,6 +7,7 @@ from app.utils import (
|
|||||||
create_invoice_header,
|
create_invoice_header,
|
||||||
insert_invoice_REST_API_FACTUGES,
|
insert_invoice_REST_API_FACTUGES,
|
||||||
insert_item_and_taxes,
|
insert_item_and_taxes,
|
||||||
|
validar_nif_verifacti,
|
||||||
)
|
)
|
||||||
|
|
||||||
from . import normalizations as NORMALIZA
|
from . import normalizations as NORMALIZA
|
||||||
@ -58,10 +59,15 @@ def sync_invoices_from_FACTUGES(conn_mysql, filas, conn_factuges, config):
|
|||||||
cursorMySQL = None
|
cursorMySQL = None
|
||||||
cursor_FactuGES = None
|
cursor_FactuGES = None
|
||||||
factuges_id_anterior = None
|
factuges_id_anterior = None
|
||||||
|
tin_anterior = None
|
||||||
num_fac_procesed = 0
|
num_fac_procesed = 0
|
||||||
customer_valid = True
|
customer_valid = False
|
||||||
invoice_id: str | None = None
|
invoice_id: str | None = None
|
||||||
factura_payload: dict | None = None
|
factura_payload: dict | None = None
|
||||||
|
sync_result: str | None = None
|
||||||
|
sync_notes: str | None = None
|
||||||
|
sync_result_anterior: str | None = None
|
||||||
|
sync_notes_anterior: str | None = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cursorMySQL = conn_mysql.cursor()
|
cursorMySQL = conn_mysql.cursor()
|
||||||
@ -79,27 +85,52 @@ def sync_invoices_from_FACTUGES(conn_mysql, filas, conn_factuges, config):
|
|||||||
)
|
)
|
||||||
|
|
||||||
factuges_id = int(facturas["ID"])
|
factuges_id = int(facturas["ID"])
|
||||||
if factuges_id_anterior is None or factuges_id_anterior != factuges_id:
|
logger.info(">>>PASO")
|
||||||
# Validamos que el cif de la factura exista en la AEAT si no es así no se hace la sincro de la factura
|
logger.info(str(factuges_id_anterior))
|
||||||
|
logger.info(str(factuges_id))
|
||||||
|
|
||||||
|
# --- Si cambia la factura, primero persistimos la anterior
|
||||||
|
if factuges_id_anterior is not None and factuges_id_anterior != factuges_id:
|
||||||
|
if factura_payload is not None:
|
||||||
|
logger.info(">>>> Se cambia de factura y vamos a insertar la anterior")
|
||||||
|
|
||||||
|
resultado_rest = insert_invoice_REST_API_FACTUGES(factura_payload)
|
||||||
|
logger.info(resultado_rest)
|
||||||
|
num_fac_procesed += 1
|
||||||
|
|
||||||
|
if not resultado_rest.get("ok"):
|
||||||
|
logger.info(resultado_rest.get("error"))
|
||||||
|
else:
|
||||||
|
data = resultado_rest.get("data") or {}
|
||||||
|
invoice_id = data.get("proforma_id")
|
||||||
|
|
||||||
|
logger.info("Updating FACTURAS_CLIENTE %s %s %s",
|
||||||
|
sync_result_anterior, invoice_id, factuges_id_anterior,)
|
||||||
|
cursor_FactuGES.execute(
|
||||||
|
SQL.UPDATE_FACTUGES_LINK,
|
||||||
|
(
|
||||||
|
sync_result_anterior,
|
||||||
|
invoice_id,
|
||||||
|
sync_notes_anterior,
|
||||||
|
factuges_id_anterior,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
factura_payload = None
|
||||||
|
|
||||||
|
# --- Si no hay payload, estamos arrancando una nueva factura
|
||||||
|
if factura_payload is None:
|
||||||
sync_result = int(config["CTE_SYNC_RESULT_OK"])
|
sync_result = int(config["CTE_SYNC_RESULT_OK"])
|
||||||
sync_notes = None
|
sync_notes = None
|
||||||
customer_valid = True # validar_nif_verifacti(
|
|
||||||
# customer_fields["tin"], customer_fields["name"], config
|
|
||||||
# )
|
|
||||||
|
|
||||||
if customer_valid:
|
# Validamos que el cif de la factura exista en la AEAT si no es así no se hace la sincro de la factura
|
||||||
|
if tin_anterior is None or tin_anterior != customer_fields["tin"]:
|
||||||
|
logger.info("VALIDO NIF>>>>>>>>>>>")
|
||||||
|
customer_valid = validar_nif_verifacti(
|
||||||
|
customer_fields["tin"], customer_fields["name"], config)
|
||||||
|
tin_anterior = customer_fields["tin"]
|
||||||
|
|
||||||
# ---- cabecera factura
|
if not customer_valid:
|
||||||
factura_payload = create_invoice_header(
|
|
||||||
customer_fields, header_invoice_fields, facturas["ID_FORMA_PAGO"], str(facturas["DES_FORMA_PAGO"]))
|
|
||||||
# ---- detalles factura
|
|
||||||
factura_payload["items"].append(insert_item_and_taxes(details_invoice_fields))
|
|
||||||
logger.info(f"PAYLOAD {factura_payload}")
|
|
||||||
# InsertamosREST
|
|
||||||
Resultado_REST = insert_invoice_REST_API_FACTUGES(factura_payload)
|
|
||||||
logger.info(Resultado_REST)
|
|
||||||
|
|
||||||
else:
|
|
||||||
sync_result = int(config["CTE_SYNC_RESULT_FAIL"])
|
sync_result = int(config["CTE_SYNC_RESULT_FAIL"])
|
||||||
sync_notes = (
|
sync_notes = (
|
||||||
f">>> Factura {header_invoice_fields['reference']} no cumple requisitos para ser mandada a Verifactu: "
|
f">>> Factura {header_invoice_fields['reference']} no cumple requisitos para ser mandada a Verifactu: "
|
||||||
@ -107,21 +138,50 @@ def sync_invoices_from_FACTUGES(conn_mysql, filas, conn_factuges, config):
|
|||||||
f"El NIF/CIF debe estar registrado en la AEAT y el nombre debe ser suficientemente parecido al nombre 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"
|
||||||
)
|
)
|
||||||
logger.info(sync_notes)
|
logger.info(sync_notes)
|
||||||
|
cursor_FactuGES.execute(SQL.UPDATE_FACTUGES_LINK, (sync_result,
|
||||||
|
invoice_id, sync_notes, factuges_id),)
|
||||||
|
continue
|
||||||
|
|
||||||
num_fac_procesed += 1
|
# ---- cabecera factura
|
||||||
|
logger.info("Creo cabecera>>>>>>")
|
||||||
|
factura_payload = create_invoice_header(
|
||||||
|
customer_fields, header_invoice_fields, facturas["ID_FORMA_PAGO"], str(facturas["DES_FORMA_PAGO"]))
|
||||||
|
|
||||||
# Guardamos en Factuges el id de la customer_invoice
|
# Guardamos el estado asociado al payload actual
|
||||||
logger.info(
|
sync_result_anterior = sync_result
|
||||||
f"Updating FACTURAS_CLIENTE {sync_result} {invoice_id} {factuges_id} {sync_notes}: ")
|
sync_notes_anterior = sync_notes
|
||||||
# cursor_FactuGES.execute(
|
|
||||||
# SQL.UPDATE_FACTUGES_LINK,
|
|
||||||
# (sync_result, invoice_id, sync_notes, factuges_id),
|
|
||||||
# )
|
|
||||||
|
|
||||||
# Asignamos el id factura anterior para no volver a inserta cabecera
|
# ---- detalles factura
|
||||||
factuges_id_anterior = factuges_id
|
logger.info("Creo detalle>>>>")
|
||||||
|
factura_payload["items"].append(insert_item_and_taxes(details_invoice_fields))
|
||||||
|
# Asignamos el id factura anterior para no volver a inserta cabecera
|
||||||
|
factuges_id_anterior = factuges_id
|
||||||
|
|
||||||
logger.info(f"FACTURAS_CLIENTE rows to be processed: {str(num_fac_procesed)}")
|
# --- Insertar última factura pendiente
|
||||||
|
if factura_payload is not None:
|
||||||
|
logger.info(">>>> Última factura y vamos a insertar")
|
||||||
|
|
||||||
|
resultado_rest = insert_invoice_REST_API_FACTUGES(factura_payload)
|
||||||
|
logger.info(resultado_rest)
|
||||||
|
num_fac_procesed += 1
|
||||||
|
|
||||||
|
if not resultado_rest.get("ok"):
|
||||||
|
logger.info(resultado_rest.get("error"))
|
||||||
|
else:
|
||||||
|
data = resultado_rest.get("data") or {}
|
||||||
|
invoice_id = data.get("proforma_id")
|
||||||
|
|
||||||
|
cursor_FactuGES.execute(
|
||||||
|
SQL.UPDATE_FACTUGES_LINK,
|
||||||
|
(
|
||||||
|
sync_result_anterior,
|
||||||
|
invoice_id,
|
||||||
|
sync_notes_anterior,
|
||||||
|
factuges_id_anterior,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info("FACTURAS_CLIENTE rows to be processed: %s", num_fac_procesed)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Escribir el error en el archivo de errores
|
# Escribir el error en el archivo de errores
|
||||||
@ -136,6 +196,57 @@ def sync_invoices_from_FACTUGES(conn_mysql, filas, conn_factuges, config):
|
|||||||
cursor_FactuGES.close()
|
cursor_FactuGES.close()
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
if factuges_id_anterior is not None and factuges_id_anterior != factuges_id:
|
||||||
|
logger.info(">>>>Se cambia de factura y vamos a insertar")
|
||||||
|
# InsertamosREST
|
||||||
|
Resultado_REST = insert_invoice_REST_API_FACTUGES(factura_payload)
|
||||||
|
logger.info(Resultado_REST)
|
||||||
|
num_fac_procesed += 1
|
||||||
|
|
||||||
|
if not Resultado_REST.get("ok"):
|
||||||
|
# Solo informamos en logger porque al cliente final este error no le interesa saldría la causa en notes de FactuGES antiguo
|
||||||
|
logger.info(Resultado_REST.get("error"))
|
||||||
|
else:
|
||||||
|
logger.info(Resultado_REST)
|
||||||
|
data = Resultado_REST.get("data")
|
||||||
|
invoice_id = data.get("proforma_id")
|
||||||
|
# Guardamos en Factuges el id de la customer_invoice
|
||||||
|
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),)
|
||||||
|
|
||||||
|
# Quitamos payload de la factura insertada
|
||||||
|
factura_payload = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if factura_payload is not None:
|
||||||
|
logger.info(">>>>Ultima factura y vamos a insertar")
|
||||||
|
# InsertamosREST
|
||||||
|
Resultado_REST = insert_invoice_REST_API_FACTUGES(factura_payload)
|
||||||
|
logger.info(Resultado_REST)
|
||||||
|
num_fac_procesed += 1
|
||||||
|
|
||||||
|
if not Resultado_REST.get("ok"):
|
||||||
|
# Solo informamos en logger porque al cliente final este error no le interesa saldría la causa en notes de FactuGES antiguo
|
||||||
|
logger.info(Resultado_REST.get("error"))
|
||||||
|
else:
|
||||||
|
logger.info(Resultado_REST)
|
||||||
|
data = Resultado_REST.get("data")
|
||||||
|
invoice_id = data.get("proforma_id")
|
||||||
|
# Guardamos en Factuges el id de la customer_invoice
|
||||||
|
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),)
|
||||||
|
|
||||||
|
logger.info(f"FACTURAS_CLIENTE rows to be processed: {str(num_fac_procesed)}")
|
||||||
|
factura_payload = None
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
def insert_verifactu_record(
|
def insert_verifactu_record(
|
||||||
cur: str, hif: Dict[str, Any], invoice_id: str, config) -> str:
|
cur: str, hif: Dict[str, Any], invoice_id: str, config) -> str:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -15,7 +15,7 @@ def create_invoice_header(
|
|||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"id": str(uuid7()),
|
"id": str(uuid7()),
|
||||||
"factuges_id": hif.get("factuges_id"),
|
"factuges_id": str(hif.get("factuges_id")),
|
||||||
"company_id": hif.get("company_id"),
|
"company_id": hif.get("company_id"),
|
||||||
"is_proforma": hif.get("is_proforma"),
|
"is_proforma": hif.get("is_proforma"),
|
||||||
"status": hif.get("status"),
|
"status": hif.get("status"),
|
||||||
@ -27,13 +27,13 @@ def create_invoice_header(
|
|||||||
"notes": none_to_empty(hif.get("notes")),
|
"notes": none_to_empty(hif.get("notes")),
|
||||||
"language_code": cf.get("language_code"),
|
"language_code": cf.get("language_code"),
|
||||||
|
|
||||||
"subtotal_amount_value": none_to_empty(hif.get("subtotal_amount_value")),
|
"subtotal_amount_value": str(none_to_empty(hif.get("subtotal_amount_value"))),
|
||||||
"global_discount_percentage": none_to_empty(hif.get("discount_percentage_val")),
|
"global_discount_percentage": str(none_to_empty(hif.get("discount_percentage_val"))),
|
||||||
"discount_amount_value": none_to_empty(hif.get("discount_amount_value")),
|
"discount_amount_value": str(none_to_empty(hif.get("discount_amount_value"))),
|
||||||
"taxable_amount_value": hif.get("taxable_amount_value"),
|
"taxable_amount_value": str(hif.get("taxable_amount_value")),
|
||||||
"taxes_amount_value": hif.get("taxes_amount_value"),
|
"taxes_amount_value": str(hif.get("taxes_amount_value")),
|
||||||
"total_amount_value": hif.get("total_amount_value"),
|
"total_amount_value": str(hif.get("total_amount_value")),
|
||||||
"payment_method_id": payment_method_id,
|
"payment_method_id": str(payment_method_id),
|
||||||
"payment_method_description": payment_method_description,
|
"payment_method_description": payment_method_description,
|
||||||
|
|
||||||
"customer": {
|
"customer": {
|
||||||
@ -52,7 +52,7 @@ def create_invoice_header(
|
|||||||
"mobile_secondary": none_to_empty(cf["mobile_secondary"]),
|
"mobile_secondary": none_to_empty(cf["mobile_secondary"]),
|
||||||
"email_primary": none_to_empty(cf["email_primary"]),
|
"email_primary": none_to_empty(cf["email_primary"]),
|
||||||
"email_secondary": none_to_empty(cf["email_secondary"]),
|
"email_secondary": none_to_empty(cf["email_secondary"]),
|
||||||
"website": cf["website"],
|
"website": str(none_to_empty(cf["website"])),
|
||||||
},
|
},
|
||||||
|
|
||||||
"items": [],
|
"items": [],
|
||||||
@ -65,24 +65,24 @@ def insert_item_and_taxes(fields) -> Dict[str, Any]:
|
|||||||
return {
|
return {
|
||||||
"item_id": str(uuid7()),
|
"item_id": str(uuid7()),
|
||||||
"position": str(fields.get("position")),
|
"position": str(fields.get("position")),
|
||||||
"description": fields.get("description"),
|
"description": str(none_to_empty(fields.get("description"))),
|
||||||
"quantity_value": str(fields.get("quantity_value")),
|
"quantity_value": str(none_to_empty(fields.get("quantity_value"))),
|
||||||
"unit_value": str(fields.get("unit_value")),
|
"unit_value": str(none_to_empty(fields.get("unit_value"))),
|
||||||
"subtotal_amount_value": fields.get("subtotal_amount_value"),
|
"subtotal_amount_value": str(fields.get("subtotal_amount_value")),
|
||||||
"item_discount_percentage_value": none_to_empty(fields.get("item_discount_percentage_value")),
|
"item_discount_percentage_value": str(none_to_empty(fields.get("item_discount_percentage_value"))),
|
||||||
"item_discount_amount_value": none_to_empty(fields.get("item_discount_amount_value")),
|
"item_discount_amount_value": str(none_to_empty(fields.get("item_discount_amount_value"))),
|
||||||
"global_discount_percentage_value": none_to_empty(fields.get("global_discount_percentage_value")),
|
"global_discount_percentage_value": str(none_to_empty(fields.get("global_discount_percentage_value"))),
|
||||||
"global_discount_amount_value": none_to_empty(fields.get("global_discount_amount_value")),
|
"global_discount_amount_value": str(none_to_empty(fields.get("global_discount_amount_value"))),
|
||||||
"total_discount_amount_value": fields.get("total_discount_amount_value"),
|
"total_discount_amount_value": str(fields.get("total_discount_amount_value")),
|
||||||
"taxable_amount_value": fields.get("taxable_amount_value"),
|
"taxable_amount_value": str(fields.get("taxable_amount_value")),
|
||||||
"total_value": fields.get("total_value"),
|
"total_value": str(fields.get("total_value")),
|
||||||
"iva_code": fields.get("iva_code"),
|
"iva_code": str(fields.get("iva_code")),
|
||||||
"iva_percentage_value": str(fields.get("iva_percentage_value")),
|
"iva_percentage_value": str(str(fields.get("iva_percentage_value"))),
|
||||||
"iva_amount_value": fields.get("iva_amount_value"),
|
"iva_amount_value": str(fields.get("iva_amount_value")),
|
||||||
"rec_code": none_to_empty(fields.get("rec_code")),
|
"rec_code": str(none_to_empty(fields.get("rec_code"))),
|
||||||
"rec_percentage_value": none_to_empty(fields.get("rec_percentage_value")),
|
"rec_percentage_value": str(none_to_empty(fields.get("rec_percentage_value"))),
|
||||||
"rec_amount_value": fields.get("rec_amount_value"),
|
"rec_amount_value": str(fields.get("rec_amount_value")),
|
||||||
"taxes_amount_value": fields.get("taxes_amount_value"),
|
"taxes_amount_value": str(fields.get("taxes_amount_value")),
|
||||||
}
|
}
|
||||||
|
|
||||||
# logger.info("Inserting item tax %s code=%s base=%s tax=%s",
|
# logger.info("Inserting item tax %s code=%s base=%s tax=%s",
|
||||||
|
|||||||
@ -4,6 +4,9 @@ import requests
|
|||||||
|
|
||||||
from app.config import logger
|
from app.config import logger
|
||||||
|
|
||||||
|
SUCCESS_CODES = {200, 201}
|
||||||
|
VALIDATION_ERROR_CODES = {400, 422}
|
||||||
|
|
||||||
|
|
||||||
def estado_factura(uuid_str: str,
|
def estado_factura(uuid_str: str,
|
||||||
config,
|
config,
|
||||||
@ -142,13 +145,11 @@ def validar_nif_verifacti(
|
|||||||
resp = requests.post(
|
resp = requests.post(
|
||||||
url, json=payload, headers=headers, timeout=timeout)
|
url, json=payload, headers=headers, timeout=timeout)
|
||||||
if resp.status_code != 200:
|
if resp.status_code != 200:
|
||||||
logger.info("ERRRRRROOOOOOORRRRR LLAMADA REST API")
|
return False, None, f"HTTP {resp.status_code}: {resp.text}"
|
||||||
# return False, None, f"HTTP {resp.status_code}: {resp.text}"
|
|
||||||
|
|
||||||
data = resp.json()
|
data = resp.json()
|
||||||
resultado = data.get("resultado", "NO IDENTIFICADO")
|
resultado = data.get("resultado", "NO IDENTIFICADO")
|
||||||
logger.info(f"Resultado Verifacti: {resultado}")
|
logger.info(f"Resultado Verifacti: {resultado}")
|
||||||
|
|
||||||
return resultado == "IDENTIFICADO"
|
return resultado == "IDENTIFICADO"
|
||||||
|
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
@ -177,26 +178,30 @@ def insert_invoice_REST_API_FACTUGES(
|
|||||||
"nombre": nombre,
|
"nombre": nombre,
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
logger.info("-----------------------------------------------------------------------------")
|
||||||
|
logger.info(payload)
|
||||||
|
logger.info("-----------------------------------------------------------------------------")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
resp = requests.post(
|
resp = requests.post(
|
||||||
url, json=payload, headers=headers, timeout=timeout)
|
url, json=payload, headers=headers, timeout=timeout)
|
||||||
|
|
||||||
if resp.status_code == 200:
|
if resp.status_code in SUCCESS_CODES:
|
||||||
|
location = resp.headers.get("Location")
|
||||||
try:
|
try:
|
||||||
data = resp.json()
|
data = resp.json()
|
||||||
logger.info(data)
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return {"ok": False, "status": 200, "error": "Respuesta 200 sin JSON válido", "raw": resp.text}
|
data = None
|
||||||
return {"ok": True, "status": 200, "data": data}
|
return {"ok": True, "status": resp.status_code, "data": data, "location": location}
|
||||||
|
|
||||||
if resp.status_code == 400:
|
if resp.status_code in VALIDATION_ERROR_CODES:
|
||||||
try:
|
try:
|
||||||
body = resp.json()
|
body = resp.json()
|
||||||
msg = body.get(
|
msg = (body.get("title") + str(body.get("errors"))
|
||||||
"error") or "Error de validación (400) sin detalle"
|
or f"Error de validación ({resp.status_code}) sin detalle")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
msg = f"Error de validación (400): {resp.text}"
|
msg = f"Error de validación (400): {resp.text}"
|
||||||
return {"ok": False, "status": 400, "error": msg}
|
return {"ok": False, "status": resp.status_code, "error": msg}
|
||||||
|
|
||||||
# Otros códigos: devuelve mensaje genérico, intenta extraer JSON si existe
|
# Otros códigos: devuelve mensaje genérico, intenta extraer JSON si existe
|
||||||
try:
|
try:
|
||||||
@ -207,7 +212,7 @@ def insert_invoice_REST_API_FACTUGES(
|
|||||||
return {"ok": False, "status": resp.status_code, "error": f"HTTP {resp.status_code}", "raw": resp.text}
|
return {"ok": False, "status": resp.status_code, "error": f"HTTP {resp.status_code}", "raw": resp.text}
|
||||||
|
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
logger.error("Error de conexión con la API Verifacti: %s", e)
|
logger.error("Error de conexión con la API Factuges: %s", e)
|
||||||
return {"ok": False, "status": 500, "error": str(e)}
|
return {"ok": False, "status": 500, "error": str(e)}
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logger.error("Respuesta no es JSON válido: %s", e)
|
logger.error("Respuesta no es JSON válido: %s", e)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user