- 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>
141 lines
5.0 KiB
Python
141 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
|
import os
|
|
import sys
|
|
import json
|
|
from datetime import datetime, date
|
|
from hdbcli import dbapi
|
|
from dotenv import load_dotenv
|
|
|
|
# ============================================================================
|
|
# CONFIGURACIÓN
|
|
# ============================================================================
|
|
|
|
# Cargar variables de entorno desde .env (ruta absoluta: no depende del
|
|
# directorio de trabajo desde el que se lance el proceso)
|
|
load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), ".env"))
|
|
|
|
# Configuración de la API
|
|
HANA_HOST = os.getenv("HANA_SERVER", "")
|
|
HANA_PORT = int(os.getenv("HANA_PORT", 30015))
|
|
HANA_USER = os.getenv("HANA_USER", "")
|
|
HANA_PASSWORD = os.getenv("HANA_PASSWORD", "")
|
|
HANA_SCHEMA = os.getenv("HANA_SCHEMA", "")
|
|
|
|
# ============================================================================
|
|
def get_connection():
|
|
"""Crea y retorna una conexión a SAP HANA."""
|
|
try:
|
|
conn = dbapi.connect(
|
|
address=HANA_HOST,
|
|
port=HANA_PORT,
|
|
user=HANA_USER,
|
|
password=HANA_PASSWORD
|
|
)
|
|
return conn
|
|
except Exception as e:
|
|
print(f" ❌ Error conectando a HANA: {e}")
|
|
return None
|
|
|
|
# ============================================================================
|
|
def get_delivery(tipo: str, serie: str, numero: str) -> list:
|
|
"""
|
|
Consulta la tabla ODLN en SAP HANA para obtener DeliveryNotes.
|
|
Si no encuentra el tipo, serie y número en ODLN, busca en OWTR
|
|
(Traslados de Inventario) como fallback.
|
|
|
|
Args:
|
|
tipo: Código de tipo de documento SUNAT, ej. "09"/"31" (U_BPP_MDTD).
|
|
serie: Serie del documento, ej. "T001" (U_BPP_MDSD).
|
|
numero: Número del documento (se busca con LIKE).
|
|
|
|
Returns:
|
|
list[dict] — Lista con DocEntry, DocNum, CardCode, CardName, Tabla.
|
|
"Tabla" indica en qué tabla se encontró el registro ("ODLN" u
|
|
"OWTR"), para que el llamador sepa qué endpoint de Service Layer
|
|
usar (DeliveryNotes o StockTransfers).
|
|
"""
|
|
connection = get_connection()
|
|
if not connection:
|
|
return []
|
|
|
|
try:
|
|
results = _query_delivery_table(connection, "ODLN", tipo, serie, numero)
|
|
if results:
|
|
return results
|
|
return _query_delivery_table(connection, "OWTR", tipo, serie, numero)
|
|
finally:
|
|
connection.close()
|
|
|
|
# ============================================================================
|
|
def _query_delivery_table(connection, tabla: str, tipo: str, serie: str, numero: str) -> list:
|
|
"""Ejecuta la consulta de tipo/serie/número contra la tabla indicada (ODLN u OWTR)."""
|
|
schema = HANA_SCHEMA
|
|
query = f'''SELECT "DocEntry", "DocNum", "CardCode", "CardName"
|
|
FROM "{schema}"."{tabla}"
|
|
WHERE "CANCELED" = 'N'
|
|
AND "U_BPP_MDTD" = ?
|
|
AND "U_BPP_MDSD" = ?
|
|
AND "U_BPP_MDCD" LIKE ?'''
|
|
|
|
pattern = f"%{numero}%"
|
|
|
|
cursor = None
|
|
try:
|
|
cursor = connection.cursor()
|
|
cursor.execute(query, (tipo, serie, pattern))
|
|
columns = [column[0] for column in cursor.description]
|
|
results = []
|
|
for row in cursor.fetchall():
|
|
registro = dict(zip(columns, row))
|
|
registro["Tabla"] = tabla
|
|
results.append(registro)
|
|
return results
|
|
except Exception as e:
|
|
print(f" ❌ Error en consulta HANA get_delivery ({tabla}): {e}")
|
|
return []
|
|
finally:
|
|
if cursor:
|
|
cursor.close()
|
|
|
|
# ============================================================================
|
|
def obtener_valor_referencial(serie: str, numero: str) -> float:
|
|
"""
|
|
Ejecuta el stored procedure Sp_ObtenerValorReferencial en SAP HANA para
|
|
obtener el valor referencial de una guía de remisión (tipo 09).
|
|
|
|
Args:
|
|
serie: Serie de la guía de remisión (ej. "T001").
|
|
numero: Número de la guía de remisión (ej. "132800").
|
|
|
|
Returns:
|
|
float — Columna ``ValorReferencial`` del primer registro devuelto
|
|
por el SP, o 0.0 si no hay resultados o si ocurre un error.
|
|
"""
|
|
schema = HANA_SCHEMA
|
|
query = f'CALL "{schema}"."Sp_ObtenerValorReferencial"(?, ?)'
|
|
|
|
connection = get_connection()
|
|
if not connection:
|
|
return 0.0
|
|
|
|
cursor = None
|
|
try:
|
|
cursor = connection.cursor()
|
|
cursor.execute(query, (serie, numero))
|
|
columns = [column[0] for column in cursor.description]
|
|
row = cursor.fetchone()
|
|
if not row:
|
|
return 0.0
|
|
valor = dict(zip(columns, row)).get("ValorReferencial")
|
|
return float(valor) if valor is not None else 0.0
|
|
except Exception as e:
|
|
print(f" ❌ Error en consulta HANA obtener_valor_referencial: {e}")
|
|
return 0.0
|
|
finally:
|
|
if cursor:
|
|
cursor.close()
|
|
if connection:
|
|
connection.close()
|
|
|
|
# ============================================================================
|