Mejoras de sesion: estabilizacion, IA, Nexus Yonke y marketplace B2B
- F0 blindaje: Redis/Celery, pg_hba sin trust LAN, secretos a env 600, backups, webhook auth, jobs muertos - F1 caja: bugs POS, reembolsos al corte, apartados, CFDI, topes de descuento en cotizacion/apartado - F2/F7 IA de catalogo: autocategorizacion, dedup de SKUs con embeddings, OCR de facturas, descripciones, claves SAT, limpieza de fitment - F3 IA en el flujo: vision Yonke, preguntas MeLi, venta cruzada, anomalias, sinonimos, busqueda semantica (rerank/embeddings) - F4/F8 escala y cartera: /metrics+Prometheus+Grafana, pool, score de credito, churn, metricas multi-tenant - Nexus Yonke (M1-M6): modelo de datos 1-de-1, alta por donador, vitrina publica, MeLi usado, consignacion, garantia por dias, reportes, etiquetas - Marketplace B2B entre yonkes (catalogo + pedidos cross-tenant) - Seguridad: auth en /api/admin/* (35 endpoints), alertas por tenant - Migraciones v4.27/v4.28; timers expire-demos y rollup-metrics
This commit is contained in:
72
scripts/process_cfdi_queues.py
Normal file
72
scripts/process_cfdi_queues.py
Normal file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Process pending CFDI stamping queues for all tenants (Facturapi).
|
||||
|
||||
Called by systemd timer every 2 minutes so pending invoices stamp without
|
||||
anyone pressing a button. Each round first enqueues the missing payment
|
||||
complements (REP) of PPD invoices and the credit notes of returns.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'pos'))
|
||||
|
||||
import psycopg2 # noqa: E402
|
||||
|
||||
MASTER_DB = os.environ.get('MASTER_DB_NAME', 'nexus_autoparts')
|
||||
|
||||
|
||||
def main():
|
||||
from services.cfdi_queue import enqueue_pending_complements, process_queue
|
||||
|
||||
master = psycopg2.connect(dbname=MASTER_DB)
|
||||
mcur = master.cursor()
|
||||
mcur.execute("SELECT id, db_name FROM tenants WHERE is_active = true ORDER BY id")
|
||||
tenants = mcur.fetchall()
|
||||
mcur.close()
|
||||
master.close()
|
||||
|
||||
for tenant_id, db_name in tenants:
|
||||
try:
|
||||
conn = psycopg2.connect(dbname=db_name)
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
SELECT key, value FROM tenant_config
|
||||
WHERE key IN ('cfdi_facturapi_key', 'cfdi_facturapi_org_id',
|
||||
'facturapi_secret_key', 'facturapi_org_id')
|
||||
""")
|
||||
tcfg = {k: v for k, v in cur.fetchall()}
|
||||
cur.close()
|
||||
|
||||
if not tcfg.get('cfdi_facturapi_key') and not tcfg.get('facturapi_secret_key'):
|
||||
conn.close()
|
||||
continue # tenant has no CFDI configured
|
||||
|
||||
# Enqueue missing payment complements (REP) and credit notes first;
|
||||
# they only need the tenant DB, not the Facturapi API.
|
||||
try:
|
||||
enqueue_pending_complements(conn)
|
||||
except Exception as e:
|
||||
conn.rollback()
|
||||
print(f'[{db_name}] complement sync ERROR: {str(e)[:200]}', flush=True)
|
||||
|
||||
# Quick check: are there pending items?
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT count(*) FROM cfdi_queue WHERE status IN ('pending','failed')")
|
||||
pending = cur.fetchone()[0]
|
||||
cur.close()
|
||||
if not pending:
|
||||
conn.close()
|
||||
continue
|
||||
|
||||
result = process_queue(conn, tcfg)
|
||||
conn.close()
|
||||
print(f'[{db_name}] processed={result.get("processed")} '
|
||||
f'stamped={result.get("stamped")} failed={result.get("failed")}', flush=True)
|
||||
except Exception as e:
|
||||
print(f'[{db_name}] ERROR: {str(e)[:200]}', flush=True)
|
||||
print('CFDI queue round complete.', flush=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user