se agrega fallback OWTR y calculo de fecha de vencimiento por condicion de pago

- hana_manager.get_delivery ahora busca en ODLN y, si no encuentra, en OWTR
- sapb1_manager resuelve StockTransfers -> Orders (via U_IDC_NUMOV) para
  validar precios de flete cuando la guia es un traslado de inventario
- se corrige el orden de parametros tipo/serie/numero (sin cruces) en
  get_delivery, get_delivery_notes y _get_delivery_entries
- se agrega sapb1_manager.obtener_condicion_pago (BusinessPartners +
  PaymentTermsTypes) y pipeline._calcular_fecha_vencimiento para que
  DocDueDate del draft sea fecha de contabilizacion + dias de la condicion
  de pago del proveedor
- se agrega variante de regex para "VALOR REFER" truncado en sunat_schema.py
- se actualiza documentacion (docs/) reflejando estos cambios

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
georgeandClaude Sonnet 5 committed 2026-09-10 13:21:04 -05:00
1 parent 6b0ed6f519
commit 15e3b5079c
231 files changed
+21421 -475

No files matched your search

+71 -70
View File
@@ -12,22 +12,24 @@ def init_db() -> None:
Inicializa la base de datos SQLite y crea la tabla de correos si no existe.
"""
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
# Crear tabla con id como llave primaria para evitar duplicados
cursor.execute('''
CREATE TABLE IF NOT EXISTS emails (
id TEXT PRIMARY KEY,
fecha TEXT,
sender TEXT,
subject TEXT,
has_attach INTEGER,
fecha_descarga TEXT
)
''')
conn.commit()
conn.close()
try:
cursor = conn.cursor()
# Crear tabla con id como llave primaria para evitar duplicados
cursor.execute('''
CREATE TABLE IF NOT EXISTS emails (
id TEXT PRIMARY KEY,
fecha TEXT,
sender TEXT,
subject TEXT,
has_attach INTEGER,
fecha_descarga TEXT
)
''')
conn.commit()
finally:
conn.close()
# ============================================================================
def save_emails(emails_list: list[dict]) -> int:
@@ -39,35 +41,36 @@ def save_emails(emails_list: list[dict]) -> int:
return 0
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
from datetime import datetime
fecha_ahora = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Mapear lista de diccionarios a tuplas para executemany
# has_attach se guarda como 1 (True) o 0 (False)
data = [
(
e['id'],
e['fecha'],
e['sender'],
e['subject'],
1 if e['has_attach'] else 0,
fecha_ahora
)
for e in emails_list
]
# INSERT OR IGNORE evita errores si el ID ya existe
cursor.executemany('''
INSERT OR IGNORE INTO emails (id, fecha, sender, subject, has_attach, fecha_descarga)
VALUES (?, ?, ?, ?, ?, ?)
''', data)
conn.commit()
rows_affected = cursor.rowcount
conn.close()
return rows_affected
try:
cursor = conn.cursor()
from datetime import datetime
fecha_ahora = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Mapear lista de diccionarios a tuplas para executemany
# has_attach se guarda como 1 (True) o 0 (False)
data = [
(
e['id'],
e['fecha'],
e['sender'],
e['subject'],
1 if e['has_attach'] else 0,
fecha_ahora
)
for e in emails_list
]
# INSERT OR IGNORE evita errores si el ID ya existe
cursor.executemany('''
INSERT OR IGNORE INTO emails (id, fecha, sender, subject, has_attach, fecha_descarga)
VALUES (?, ?, ?, ?, ?, ?)
''', data)
conn.commit()
return cursor.rowcount
finally:
conn.close()
# ============================================================================
def get_existing_ids(ids_list: list[str]) -> list[str]:
@@ -78,19 +81,21 @@ def get_existing_ids(ids_list: list[str]) -> list[str]:
return []
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
existing_ids = []
# Procesar por lotes para evitar límites de parámetros en SQLite
for i in range(0, len(ids_list), 900):
chunk = ids_list[i:i + 900]
placeholders = ','.join(['?'] * len(chunk))
query = f"SELECT id FROM emails WHERE id IN ({placeholders})"
cursor.execute(query, chunk)
existing_ids.extend([row[0] for row in cursor.fetchall()])
conn.close()
return existing_ids
try:
cursor = conn.cursor()
existing_ids = []
# Procesar por lotes para evitar límites de parámetros en SQLite
for i in range(0, len(ids_list), 900):
chunk = ids_list[i:i + 900]
placeholders = ','.join(['?'] * len(chunk))
query = f"SELECT id FROM emails WHERE id IN ({placeholders})"
cursor.execute(query, chunk)
existing_ids.extend([row[0] for row in cursor.fetchall()])
return existing_ids
finally:
conn.close()
# ============================================================================
def delete_email_by_id(email_id: str) -> bool:
@@ -102,15 +107,11 @@ def delete_email_by_id(email_id: str) -> bool:
return False
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
cursor.execute("DELETE FROM emails WHERE id = ?", (email_id,))
conn.commit()
rows_affected = cursor.rowcount
conn.close()
return rows_affected > 0
# ============================================================================
if __name__ == "__main__":
delete_email_by_id("AAMkADljMzNhYmQwLTQyMjgtNDY2My05ZDUwLWEzNTBiNDZhZjFlMwBGAAAAAAB386nfKhkcTbYV6pPUJ245BwBdNWALkxgeSJ3BdBRukthBAAAAAAEMAABdNWALkxgeSJ3BdBRukthBAAAtOXesAAA=")
try:
cursor = conn.cursor()
cursor.execute("DELETE FROM emails WHERE id = ?", (email_id,))
conn.commit()
return cursor.rowcount > 0
finally:
conn.close()
# ============================================================================