POC de pago dividido: petición de App Builder orchestrator AI
Utilice esta página para copiar el aviso completo que genera el proyecto split-payment-orchestrator: el consumidor de eventos de E/S de payment-orchestrator, payment-accept y payment-declina acciones web, el tablero de demostración y el cliente REST de Commerce.
Cómo utilizar este indicador
Copie todo desde INICIO DEL MENSAJE hasta Final del mensaje en el cursor (con Claude) o directamente en Claude. Ejecute la solicitud desde el directorio split-payment-orchestrator/ (la raíz del proyecto de App Builder).
Antes de ejecutar
- Finalizar POC de pago dividido: requisitos previos y configuración del entorno.
- Tenga preparados su POC de pagos divididos de: variables de entorno y el archivo
.enven el proyecto.
El indicador
INICIO DEL MENSAJE
Está generando una aplicación Adobe App Builder completa para organizar pagos divididos en Adobe Commerce. Esta aplicación recibe eventos de E/S de Commerce, procesa las decisiones de pago divididas y vuelve a llamar a Commerce a través de REST.
Proyecto: split-payment-orchestrator
Tiempo de ejecución: Node.js 18
Dependencias de clave: @adobe/aio-sdk ^6.0.0, got ^11.8.6, oauth-1.0a ^2.2.6
Genere todos los archivos enumerados a continuación. La aplicación debe funcionar con Adobe I/O Runtime (aio app deploy).
Estructura de archivo para generar
split-payment-orchestrator/
├── package.json
├── app.config.yaml
├── .env.example
└── actions/
├── payment-orchestrator/
│ ├── index.js ← I/O Event entry point
│ ├── commerce-client.js
│ ├── threshold.js
│ ├── cash-payment.js
│ ├── order-update.js
│ └── store-credit.js ← Deprecated stub; kept for reference
├── payment-accept/
│ └── index.js
├── payment-decline/
│ └── index.js
└── demo-dashboard/
└── index.js
package.json
{
"name": "split-payment-orchestrator",
"version": "1.0.0",
"private": true,
"description": "Adobe App Builder action — split payment PoC orchestrator",
"engines": { "node": ">=18" },
"scripts": {
"deploy": "NODE_OPTIONS=--disable-warning=DEP0040 aio app deploy",
"aio": "NODE_OPTIONS=--disable-warning=DEP0040 aio"
},
"dependencies": {
"@adobe/aio-sdk": "^6.0.0",
"@adobe/exc-app": "^1.5.9",
"got": "^11.8.6",
"oauth-1.0a": "^2.2.6"
}
}
app.config.yaml
Defina cuatro acciones en el paquete split_payment_orchestrator:
payment-orchestrator
web: "no"(solo déclencheur de eventos de E/S; no se puede llamar directamente a través de HTTP)runtime: nodejs:18require-adobe-auth: true,final: true- Entradas del entorno:
LOG_LEVEL,COMMERCE_BASE_URL,COMMERCE_CONSUMER_KEY,COMMERCE_CONSUMER_SECRET,COMMERCE_ACCESS_TOKEN,COMMERCE_ACCESS_TOKEN_SECRET,PAYMENT_THRESHOLD
payment-accept
web: "yes"(acción web HTTP — invocable por panel o ERP)runtime: nodejs:18require-adobe-auth: true,final: true- Mismas entradas de credenciales de Commerce (sin
PAYMENT_THRESHOLD)
payment-decline
web: "yes"runtime: nodejs:18require-adobe-auth: true,final: true- Mismas entradas de credenciales de Commerce
demo-dashboard
web: "yes"runtime: nodejs:18require-adobe-auth: falseEl panel de ← es de acceso público (protegido solamente porDEMO_UI_SECRETsi está configurado)- Entradas: todas las credenciales de Commerce +
DEMO_UI_SECRET,DEMO_UI_BASE_URL
Registro de eventos (en events.registrations):
Split payment — sales order place before:
description: Invokes payment-orchestrator when an order is about to be placed
events_of_interest:
- provider_metadata: dx_commerce_events
event_codes:
- com.adobe.commerce.observer.sales_order_place_before
runtime_action: split_payment_orchestrator/payment-orchestrator
actions/payment-orchestrator/commerce-client.js
Cliente REST de OAuth 1.0a compartido para Adobe Commerce. Implementa:
createCommerceClient(params, logger) — devuelve { request, baseUrl }
- Lee
COMMERCE_BASE_URL,COMMERCE_CONSUMER_KEY,COMMERCE_CONSUMER_SECRET,COMMERCE_ACCESS_TOKEN,COMMERCE_ACCESS_TOKEN_SECRETdeparams - Se inicia si falta alguna credencial
- Utiliza
oauth-1.0aconHMAC-SHA256(Node.jscrypto.createHmac) - Usa
got@11(nogot@12+— el proyecto usa CJS) conprefixUrl = ${baseUrl}/rest/V1/ - Agrega el encabezado
Authorizationa través del vínculobeforeRequest request(method, path, options): normaliza la ruta de acceso (elimina las líneas que preceden a/), devuelve{ statusCode, body }throwHttpErrors: false: nunca activa 4xx/5xx; siempre devuelve el código de estado
actions/payment-orchestrator/threshold.js
evaluateThreshold({ orderTotal, storeCreditAmount, cashAmount, params, logger }) — devuelve { pass: boolean, reason: string }
Lógica:
- Leer
params.PAYMENT_THRESHOLD; analizar como flotante; predeterminado:100si falta, NaN o ≤ 0 - Si
orderTotal > threshold: devuelve{ pass: false, reason: 'PAYMENT_THRESHOLD_EXCEEDED' } - Si
Math.abs((storeCreditAmount + cashAmount) - orderTotal) > 0.02: devuelve{ pass: false, reason: 'SPLIT_AMOUNT_MISMATCH' } - De lo contrario: devuelve
{ pass: true, reason: '' }
actions/payment-orchestrator/cash-payment.js
recordCashPending({ commerce, orderId, cashAmount, logger }) — devuelve { ok: boolean, error? }
-
Llamadas
POST orders/${orderId}/commentscon:code language-json { "statusHistory": { "comment": "Cash payment of $X.XX pending. Awaiting admin confirmation.", "entity_name": "order", "parent_id": "<orderId>", "is_visible_on_front": true, "is_customer_notified": false, "status": "pending_payment" } } -
Devuelve
{ ok: true }en 2xx; devuelve{ ok: false, error: { code, message } }en caso contrario -
Se ajusta en try/catch; devuelve un objeto de error, nunca lo arroja
actions/payment-orchestrator/order-update.js
updateOrderAfterOrchestration({ commerce, orderId, success, detail, logger }) — devuelve { ok: boolean, error? }
- Si
success: publica un comentario de historial"Split payment orchestration completed. Order awaiting cash confirmation." - Si
!success: publica"Payment could not be processed. Please try again or contact support."— nunca incluirdetailen el comentario visible para el cliente; registredetailsolo internamente - Devuelve
{ ok: boolean, error? }— nunca lanza
actions/payment-orchestrator/store-credit.js
applyStoreCredit({ commerce, cartId, amount, logger }): implementación obsoleta sin operación
Incluya este archivo con un aviso de JSDoc @deprecated que explique:
El orquestador ya no aplica crédito de almacén a través de REST. El crédito de tienda se aplica al cierre de compra en el módulo Commerce PHP (
PlaceOrderPlugin) usandoBalanceManagementInterface::apply(), que requiere un carro de compras activo. Para el momento en que App Builder reciba el evento de E/S, el carro de compras estará inactivo. Este archivo se conserva como referencia o para flujos personalizados en los que el crédito de tienda se aplica después del pedido.
Mantenga una implementación en funcionamiento (la misma forma que otros módulos) para que los desarrolladores puedan estudiar el patrón, pero márquelo claramente como no utilizado en el flujo actual.
actions/payment-orchestrator/index.js
Punto de entrada de evento de E/S. Implementa async function main(params).
Extracción de carga útil:
Los eventos de Adobe Commerce I/O pueden entregar la carga útil de varias formas. Extraiga el objeto de valor del pedido comprobando estas rutas en orden:
params.__ow_body(analizar cadena JSON si es necesario) →.event.data.valueparams.data.valueparams.valueparams.body.event.data.value- Volver a
params
Extracción de campo del valor:
-
orderId = value.entity_id || value.id -
orderTotal = parseFloat(value.grand_total ?? value.base_grand_total ?? value.subtotal ?? '0') -
Dividir importes de
value.extension_attributes(comprobar tantoextension_attributescomoextensionAttributes):storeCredit = parseFloat(ext.split_store_credit_amount ?? value.split_store_credit_amount ?? '0')cash = parseFloat(ext.split_cash_amount ?? value.split_cash_amount ?? '0')
Flujo:
- Extraer valor; si falta
orderId, registrar error y devolver{ statusCode: 200, body: { ok: false, message: PUBLIC_ERROR } } - Llamar a
evaluateThreshold(...): si falla, registrar y devolver las mismas 200 respuestas - Llamar a
createCommerceClient(params, logger): si falla, devuelve el error 200 - Si
storeCredit > 0, registra que el crédito de almacén se aplicó al finalizar la compra (no se necesita llamada REST) - Llamar a
recordCashPending(...): si falla, llame aupdateOrderAfterOrchestration(..., success: false)y devuelva el error 200 - Llamar a
updateOrderAfterOrchestration(..., success: true) - Devolver
{ statusCode: 200, body: { ok: true, message: 'processed' } }
Importante: Devolver siempre statusCode: 200: I/O Runtime reintentará las respuestas que no sean 200, lo que causaría el procesamiento de pedidos duplicados. Los errores se registran en el cuerpo del mensaje.
Constante PUBLIC_ERROR: "Payment could not be processed. Please try again or contact support." — se usa para todos los mensajes de error externos.
actions/payment-accept/index.js
Acción web HTTP. Llamadas POST /V1/split-payment/orders/:orderId/cash-received.
Resolución de ID de pedido: Compruebe params.orderId, después params.payload.orderId y después params.__ow_body (JSON analizado). Devuelve 400 si falta.
Flujo:
- Resolver
orderId; devolver 400 si falta - Cliente de comercio de inicio; devolución 500 si falla
- Llamar a
POST split-payment/orders/${orderId}/cash-receivedcon cuerpo JSON vacío - If 2xx: return
{ statusCode: 200, body: { ok: true, orderId, message: 'accepted' } } - Si error: registrar y devolver
{ statusCode: 200, body: { ok: false, message: PUBLIC_ERROR } }
actions/payment-decline/index.js
Acción web HTTP. El mismo patrón que payment-accept pero llama a POST /V1/split-payment/orders/:orderId/cash-decline.
Devolver { ok: true, orderId, message: 'declined' } si se realizó correctamente.
actions/demo-dashboard/index.js
Panel del operador de demostración independiente. Sirve como panel de control de HTML para listar pedidos de efectivo pendientes y activar acciones de aceptación/rechazo. Se trata de una acción web única que sirve tanto a la interfaz de usuario de HTML como a una API de JSON.
Seguridad:
- Comprobación
DEMO_UI_SECRETopcional: si se establece, se requiere el parámetro de consulta?secret=<value>o el encabezadox-demo-secreten todas las solicitudes. Devuelve 401 si falta/es incorrecto. - Registrar una advertencia si
DEMO_UI_SECRETno está establecido (el panel no está protegido)
Enrutamiento (basado en método HTTP + ruta/cuerpo):
La acción recibe todas las solicitudes. Determinar la intención desde:
params.__ow_method(GET/POST) yparams.__ow_patho parámetros de acciónGETsin acción → servir el panel de HTMLGETcon el parámetroaction=list→ devolver una lista JSON de pedidos pendientesPOSTconaction=acceptyorderId→ la lógicapayment-acceptde la llamada (o en línea de la llamada REST de Commerce)POSTconaction=declineyorderId→ la lógicapayment-decline
Recuperando pedidos pendientes:
- Llamar a
GET orders?searchCriteria[pageSize]=50desde Commerce REST - Filtre a pedidos en los que
extension_attributes.split_cash_status === 'pending'AND order no está en estado terminal (complete,closed,canceled,cancelled) - Ordenar más reciente-primero en la memoria
- Devolver hasta 20 (configurables mediante el parámetro
limit)
Panel de HTML:
El tablero es una cadena de HTML devuelta con Content-Type: text/html. Debería:
- Enumerar pedidos de efectivo pendientes en una tabla: Número de pedido (increment_id), entity_id, nombre del cliente, importe de efectivo, importe de crédito de almacén, fecha
- Proporcione los botones Accept y Decline para cada pedido que llame al punto de conexión de API de la acción
- Mostrar respuestas de éxito/error en línea
- Incluir un botón de actualización
- Tener el estilo suficiente para poder utilizarla (CSS mínimo está bien; no hay dependencias de CDN externas para evitar problemas de CORS en tiempo de ejecución)
- Mostrar un banner de advertencia si
DEMO_UI_SECRETno está establecido
Error al mostrar en la IU:
Cuando falle una llamada de REST de Commerce, incluya el estado HTTP y una breve descripción del cuerpo del error de Commerce (sanear: eliminar las etiquetas de HTML, truncar a 500 caracteres). No exponga las credenciales.
Response helpers:
function jsonResponse(statusCode, obj, extraHeaders = {}) { ... }
function htmlResponse(html) { ... }
.env.example
# Commerce REST base URL — no trailing slash
COMMERCE_BASE_URL=
# OAuth 1.0a integration credentials (Admin → System → Integrations)
COMMERCE_CONSUMER_KEY=
COMMERCE_CONSUMER_SECRET=
COMMERCE_ACCESS_TOKEN=
COMMERCE_ACCESS_TOKEN_SECRET=
# PoC threshold — must match split_payment/general/threshold in Commerce (default: 100)
PAYMENT_THRESHOLD=100
LOG_LEVEL=info
# Demo dashboard optional shared secret
DEMO_UI_SECRET=
DEMO_UI_BASE_URL=
Deploy Command
After generating all files, from the split-payment-orchestrator/ directory:
npm install
cp .env.example .env
# Edit .env with your credentials
aio app deploy
After deployment, note the action URLs printed by aio app deploy. The demo-dashboard URL is where you access the operator dashboard.
End of prompt
Recursos de POC de pagos fraccionados relacionados
- Crear un POC de pagos divididos: Herramientas de App Builder e IA
- Crear un POC de pago dividido: demostración completa de App Builder
- POC de pagos divididos: decisiones de arquitectura y diseño
- POC de pagos divididos: requisitos previos y configuración del entorno
- POC de pagos divididos: referencia de variables de entorno
- POC de pago dividido: petición de API del módulo Commerce
- POC de pago dividido: petición de App Builder orchestrator AI
- POC de pagos divididos: petición de API de la extensión de IU de Experience Cloud
- POC de pago fraccionado: guía de prueba y verificación
- POC de pagos divididos: pasos siguientes después de la prueba de concepto
- Split payment POC: referencia rápida del tutorial para autores