Saltar a contenido

Módulo de Pagos a Proveedores — Análisis y pruebas de Service Layer

Estado: Completado (2026-07-07). Pruebas A–F ejecutadas; única escritura no probada: adjunto (AttachmentEntry) en draft/pago outgoing — mecanismo idéntico al de cobros, riesgo bajo. Reabierto 2026-08-06: prueba B7 pendiente (persistencia de la cuenta destino en el draft), requisito del reintento de carga bancaria — doc 04 §5b D2. Ambiente: Service Layer de desarrollo (SAP_SERVICE_LAYER_URL del .env, DB ZZ_COMPU_3). Objetivo: validar qué entidades del Service Layer participan en la solución y qué campos necesitamos de cada una, antes del diseño técnico. Documento previo: 01-requerimientos.md

Convenciones de las pruebas

  • Todo documento de prueba se crea con Remarks: "PRUEBA OMS - pagos proveedores" para poder identificarlo y limpiarlo.
  • Al final de cada prueba que cree documentos, se eliminan (DELETE de drafts) o se cancelan (Cancel) los documentos generados.

Plan de pruebas

A. Conectividad

# Prueba Estado
A1 Login con credenciales del .env ✅ OK (2026-07-07, sesión 30 min)

B. Solicitud de pago (PaymentDrafts outgoing)

# Prueba Qué valida
B1 POST /PaymentDrafts con DocObjectCode: bopot_OutgoingPayments, DocType: rSupplier, proveedor y transferencia Que el borrador outgoing se crea; campos mínimos requeridos
B2 Draft con PaymentInvoices contra factura de compra Nombre del InvoiceType (¿it_PurchaseInvoice?); pago parcial y total; comportamiento si el monto supera el saldo
B3 GET /PaymentDrafts filtrado por DocObjectCode outgoing Listado de solicitudes
B4 PATCH /PaymentDrafts(id) completando datos bancarios Paso de "aprobación" (Def. 6 del doc 01)
B5 POST /PaymentDrafts(id)/SaveDraftToDocument Que el draft outgoing se convierte en VendorPayments
B6 DELETE /PaymentDrafts(id) Borrado de la solicitud (Def. 5)
B7 POST/PATCH de PayToBankCode/PayToBankAccountNo/PayToBankBranch/IsPayToBank en un draft outgoing Que la cuenta destino del proveedor sea persistible en el draft — requisito del reintento de carga bancaria (doc 04 §5b D2). Los campos existen en VendorPayments (C1); falta confirmar escritura en drafts y herencia en la conversión. Fallback si no: UDF U_BPBankAcctKey

C. Pago efectuado (VendorPayments)

# Prueba Qué valida
C1 Estructura de VendorPayments (metadata / GET de un pago existente) Campos disponibles; si existen los UDFs de trazabilidad (U_SalesPersonID u otro) en pagos emitidos y en drafts (Def. 9)
C2 POST /VendorPayments directo contra factura Flujo de pago ya efectuado (Def. 10)
C3 Consultar el asiento generado (TransId → JournalEntries) Que el pago efectuado produce el asiento contable
C4 AttachmentEntry en draft/pago outgoing Soporte de comprobante adjunto
C5 Series de numeración disponibles para VendorPayments y drafts outgoing Equivalente al Series: 146 de cobros

D. Anticipos (PurchaseDownPayments)

# Prueba Qué valida
D1 POST /PurchaseDownPayments con DownPaymentType: dptRequest Solicitud de anticipo a proveedor (Def. 4)
D2 $batch: anticipo + draft de pago referenciándolo con $1 Que el patrón batch de cobros funciona en compras; nombre del InvoiceType (¿it_PurchaseDownPayment?)
D3 Cancelación en batch (DELETE draft + Cancel anticipo) Reversa transaccional

E. Extractos bancarios (BankPages)

# Prueba Qué valida
E1 Estructura de BankPages (GET con filtros) Campos; cómo se identifican los egresos (débito vs. crédito)
E2 Filtrado por cuenta bancaria (PYG / USD) y por no conciliados Consulta que usará Tesorería en la aprobación (Def. 6)
E3 PATCH /BankPages(...) asignando CardCode Vinculación del extracto al proveedor, como hace cobros

F. Datos maestros

# Prueba Qué valida
F1 BusinessPartners con CardType eq 'S' + BPBankAccounts Datos del proveedor para la solicitud y para la transferencia vía banco (Def. 2)
F2 Facturas de compra abiertas por proveedor (PurchaseInvoices) Fuente de las facturas a pagar; saldo pendiente para la regla parcial/total (Def. 4)
F3 ChartOfAccounts cuentas de banco por moneda (AcctCurrency) Selección de cuenta PYG/USD según moneda del pago (Def. 6)

Resultados

(se irán registrando aquí a medida que se ejecuten las pruebas)

A1 — Login (2026-07-07) ✅

POST /Login con CompanyDB, UserName, Password del .env → HTTP 200, cookie B1SESSION, timeout de sesión 30 min. Nota: el valor de SAP_SL_PASSWORD está entre comillas en el .env; hay que quitarlas al construir el body (dotenv lo hace automáticamente en el backend).

F1 — Proveedores y cuentas bancarias (2026-07-07) ✅

  • Filtro por tipo: CardType eq 'cSupplier' (enum del SL v2; no 'S'). 940 proveedores en la DB de desarrollo.
  • Campos de cabecera útiles: CardCode, CardName, FederalTaxID (RUC), Currency, DefaultBankCode, HouseBank.
  • BPBankAccounts[] (cuentas bancarias del proveedor, para la transferencia): BankCode, Branch, AccountNo, AccountName, Country, IBAN. Ejemplo verificado: PL0066 (FASTRAX SA, USD) con cuenta en banco UBBRPYPX.
  • ⚠️ La mayoría de los proveedores en dev no tiene cuentas bancarias cargadas (0 de los primeros 500). El mantenimiento de BPBankAccounts será un prerequisito operativo para la integración de transferencias.

F2 — Facturas de compra abiertas (2026-07-07) ✅

GET /PurchaseInvoices?$filter=DocumentStatus eq 'bost_Open' and Cancelled eq 'tNO' funciona. Campos para la solicitud: DocEntry, DocNum, CardCode, DocDate, DocDueDate, DocTotal, PaidToDate (saldo = DocTotal - PaidToDate), DocCurrency. Candidata para pruebas de escritura: DocEntry 24193 (PL0066, USD 36.386, abierta).

F3 — Cuentas de banco por moneda (2026-07-07) ✅

ChartOfAccounts con Category eq 1 devuelve 7 cuentas. Relevantes: - 111401 — Banco Continental CC Gs. — AcctCurrency: "##" (multimoneda) - 111402 — Banco Itaú C.C. Gs. — "##" - Resto: cajas de ahorro GS (Itaú, Atlas, Ueno, Financiera Pyo Japonesa, Tienda Naranja). - ⚠️ No existe una cuenta contable exclusiva USD en Categoría 1 en dev. La selección PYG/USD (Def. 6 del doc 01) deberá validarse contra producción; AcctCurrency es el campo discriminador (## = multimoneda).

E1/E2 — BankPages (2026-07-07) ✅

  • Estructura por fila (clave compuesta AccountCode + Sequence): AccountName, Reference (nro. de ticket/transacción del banco), DueDate, Memo, DebitAmount, CreditAmount, CardCode/CardName (asignables), PaymentCreated, BankMatch, DataSource.
  • Convención de egresos confirmada: DebitAmount gt 0 (transferencias salientes a terceros); los ingresos tienen CreditAmount > 0.
  • El Memo de egresos trae beneficiario | RUC/CI | banco destino | cuenta | fecha-hora — útil para matching con el proveedor.
  • Reference es el número de comprobante de la transacción bancaria. ⚠️ No confundir con el número de ticket de la carga de la operación (son valores distintos; la relación entre ambos se resuelve vía consulta por ticket — doc 03 §G4b).
  • En dev solo hay extracto de 111401 (Continental Gs., datos 2026) y 111402 (Itaú, datos 2024). No hay cuenta USD con extracto en dev.
  • Pendiente E3 (PATCH de CardCode) para la fase de escritura.

C1 — Estructura de VendorPayments (2026-07-07) ✅

Analizado el último pago real (DocEntry 25698, Serie 24): - DocType: rSupplier, DocObjectCode: bopot_OutgoingPayments — mismos valores que usará el draft. - U_SalesPersonID existe en VendorPayments → la trazabilidad de origen (Def. 9) está soportada con el mismo UDF que usa cobros. - Medios de pago: mismas estructuras que incoming — CashSum/CashAccount, TransferSum/TransferAccount/TransferReference/TransferDate, PaymentCreditCards[], PaymentChecks[] (el pago analizado fue con cheque manual en USD; existen UDFs de cheque diferido: U_ProcChequeDif, U_BancoChequeDif, U_NumChequeDif, etc.). - PaymentInvoices[] con InvoiceType: 'it_PurchaseInvoice' (responde la duda de B2) e InstallmentId (mismo esquema de cuotas que cobros). - AttachmentEntry disponible (C4 parcialmente respondida; falta probar escritura). - Existe la colección Payments_ApprovalRequests (framework de aprobaciones nativo de SAP) — a explorar como trazabilidad de la aprobación. - Campos PayToBankCode/PayToBankAccountNo/PayToBankBranch e IsPayToBank — candidatos para registrar la cuenta destino de la transferencia al proveedor.

C5 — Series (2026-07-07) ✅

SeriesService_GetDocumentSeries para el objeto 46 (VendorPayments): una única serie, Series: 24 "Primario", desbloqueada, próximo número 19292. Es el equivalente del Series: 146 que cobros hardcodea para incoming.

B1/B3 — Crear y listar drafts outgoing (2026-07-07) ✅

POST /PaymentDrafts con DocObjectCode: bopot_OutgoingPayments, DocType: rSupplier, Series: 24, transferencia (TransferSum/TransferAccount/TransferDate/TransferReference) y PaymentInvoices con it_PurchaseInvoice → HTTP 201 (draft de prueba DocEntry 1107). El listado con $filter=DocObjectCode eq 'bopot_OutgoingPayments' funciona. ⚠️ PaymentDrafts no tiene propiedad DocumentStatus; el estado pendiente se deriva de Cancelled eq 'tNO' (igual que asume cobros).

B2b — Sobrepago (2026-07-07) ⚠️ hallazgo crítico

Draft aplicando GS 600.000 contra una factura con saldo GS 550.000: - POST /PaymentDrafts → 201 (aceptado). - SaveDraftToDocument → 204 (convertido sin error). - Resultado en el pago final: SAP recorta SumApplied al saldo (550.000) y deja el excedente (50.000) como pago a cuenta del proveedor. No hay error ni aviso.

Conclusión: la regla "inferior o igual al saldo, nunca superior" (Def. 4 del doc 01) debe validarla el OMS contra DocTotal - PaidToDate; SAP no la aplica. El pago a cuenta resultante es indeseable porque no se reconcilia automáticamente: a diferencia del anticipo (PurchaseDownPayment), no existe documento aplicable después contra una factura, y el excedente queda como saldo a conciliar manualmente.

B4 — PATCH del draft (2026-07-07) ✅

PATCH /PaymentDrafts(id) con datos bancarios (TransferReference, TransferDate, Remarks) → 204 y cambios verificados. Igual que el paso de aprobación de cobros.

B5/C2/C3 — Conversión, pago y asiento (2026-07-07) ✅

  • POST /PaymentDrafts(id)/SaveDraftToDocument → 204 sin body (el DocEntry del pago creado hay que buscarlo aparte, p. ej. por TransferReference o por el siguiente DocNum de la serie; misma limitación que hoy tiene cobros, que responde docEntry: null).
  • El VendorPayment creado (DocEntry 25707, DocNum 19292, serie 24) cerró la factura (bost_Close, PaidToDate actualizado).
  • Asiento contable verificado: JournalEntries con Original = <DocEntry del pago> y OriginalJournal = 'ttVendorPayment' (JdtNum 399068): acredita el banco (111401) y debita la cuenta del proveedor (211101). Memo: "Outgoing Payments - <CardCode>".
  • POST /VendorPayments(id)/Cancel → 204; la factura se reabre (bost_Open, PaidToDate: 0). (El OMS no expondrá esta operación — Def. 5 — pero funciona.)
  • Tras la conversión el draft queda con Cancelled: 'tYES' → sale del listado de pendientes automáticamente.

B6 — DELETE del draft (2026-07-07) ✅

DELETE /PaymentDrafts(id) → 204 y el draft se elimina físicamente (GET posterior: not found). Coincide con el borrado de solicitudes de cobros (Def. 5).

D1/D2/D3 — Anticipo a proveedor en batch (2026-07-07) ✅

El patrón $batch de cobros funciona idéntico en compras, al primer intento: - Changeset transaccional: POST /PurchaseDownPayments (DownPaymentType: 'dptRequest', DocType: 'dDocument_Service', línea con ItemDescription + PriceAfterVAT, sin AccountCode explícito) con Content-ID: 1 + POST /PaymentDrafts cuyo PaymentInvoices[0].DocEntry es el literal $1. - InvoiceType: 'it_PurchaseDownPayment' aceptado y verificado en el draft creado (anticipo DocEntry 106 + draft DocEntry 1109 vinculado). - Reversa transaccional D3: DELETE PaymentDrafts + POST PurchaseDownPayments(id)/Cancel en un changeset → ambos 204; anticipo Cancelled: tYES, draft eliminado.

E3 — PATCH de BankPages (2026-07-07) ✅

PATCH /BankPages(AccountCode='111401',Sequence=NNNN) con {CardCode} → 204; SAP completa CardName automáticamente. Clave compuesta igual que usa cobros. Nota: al revertir CardCode a null, CardName queda residual; hay que limpiarlo con un PATCH aparte si se corrige una asignación.

Conclusiones de la fase de pruebas

  1. El circuito completo outgoing funciona en Service Layer con los mismos mecanismos que cobros: draft → PATCH → SaveDraftToDocument → VendorPayment + asiento; anticipos vía $batch con $1; borrado/cancelación transaccional; BankPages con clave compuesta.
  2. Valores confirmados para el diseño: bopot_OutgoingPayments, rSupplier, serie 24, it_PurchaseInvoice, it_PurchaseDownPayment, endpoint VendorPayments, PurchaseDownPayments, asiento vía Original/OriginalJournal = ttVendorPayment.
  3. Validaciones que asume el OMS (SAP no las hace): monto aplicado ≤ saldo de la factura; obligatoriedad de al menos un PaymentInvoice.
  4. U_SalesPersonID disponible en drafts y VendorPayments para trazabilidad de origen.
  5. Pendientes para producción: cuenta/extracto USD (no existen en dev) y carga de BPBankAccounts de proveedores.

Historial

Fecha Cambio
2026-07-07 Plan de pruebas inicial (grupos A–F) y resultado de A1.
2026-07-07 Resultados de lecturas: F1, F2, F3, E1/E2, C1, C5. Confirmados it_PurchaseInvoice, U_SalesPersonID en VendorPayments, egresos = DebitAmount > 0, serie 24.
2026-07-07 Pruebas de escritura B1–B6, C2/C3, D1–D3, E3. Circuito outgoing completo validado; hallazgo: SAP no valida sobrepago (recorta y deja pago a cuenta). Documentos de prueba limpiados.
2026-08-06 Prueba B7 agregada (pendiente): escritura de PayToBank* en drafts outgoing para persistir la cuenta destino del proveedor — habilita el reintento de carga bancaria (doc 04 §5b).