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_URLdel.env, DBZZ_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 bancoUBBRPYPX.- ⚠️ La mayoría de los proveedores en dev no tiene cuentas bancarias cargadas (0 de los
primeros 500). El mantenimiento de
BPBankAccountsserá 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 tienenCreditAmount > 0. - El
Memode egresos traebeneficiario | RUC/CI | banco destino | cuenta | fecha-hora— útil para matching con el proveedor. Referencees 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) y111402(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. porTransferReferenceo por el siguiente DocNum de la serie; misma limitación que hoy tiene cobros, que respondedocEntry: null).- El
VendorPaymentcreado (DocEntry 25707, DocNum 19292, serie 24) cerró la factura (bost_Close,PaidToDateactualizado). - Asiento contable verificado:
JournalEntriesconOriginal = <DocEntry del pago>yOriginalJournal = '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¶
- 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. - Valores confirmados para el diseño:
bopot_OutgoingPayments,rSupplier, serie 24,it_PurchaseInvoice,it_PurchaseDownPayment, endpointVendorPayments,PurchaseDownPayments, asiento víaOriginal/OriginalJournal = ttVendorPayment. - Validaciones que asume el OMS (SAP no las hace): monto aplicado ≤ saldo de la factura;
obligatoriedad de al menos un
PaymentInvoice. U_SalesPersonIDdisponible en drafts yVendorPaymentspara trazabilidad de origen.- Pendientes para producción: cuenta/extracto USD (no existen en dev) y carga de
BPBankAccountsde 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). |