@quadcore-lib/payments-server
v0.1.1
Published
Pagos con **proveedor intercambiable** (MercadoPago/Stripe/…). **El monto es autoritativo de la orden**: el cliente envía solo `orderId`; el `amount` y la `currency` se derivan de `OrderEntity.total` (no se aceptan del request). Trae un `MockPaymentProvid
Downloads
65
Readme
@quadcore-lib/payments-server
Pagos con proveedor intercambiable (MercadoPago/Stripe/…). El monto es autoritativo de la orden: el cliente envía solo orderId; el amount y la currency se derivan de OrderEntity.total (no se aceptan del request). Trae un MockPaymentProvider para desarrollo.
Uso
QuadcorePaymentsModule.forRoot({ provider: new MiProviderMercadoPago() }); // o sin provider => Mock (solo dev)Implementá PaymentProvider (createPayment, verifyWebhook) para tu pasarela real, o usá @quadcore-lib/payments-mercadopago (MercadoPagoProvider, ya incluido en el monorepo).
Endpoints
| Método | Ruta | Acceso | Descripción |
|---|---|---|---|
| POST | /payments | público | Iniciar pago de una orden. Body: orderId, description?, metadata?. El monto sale de la orden, no del cliente. Devuelve el pago. |
| POST | /payments/webhook | público | Callback del proveedor; actualiza el estado del pago. |
| GET | /payments | admin | Listado paginado. |
| GET | /payments/:id | admin | Un pago. |
Entidad PaymentEntity (payments)
id, orderId, provider, providerPaymentId?, amount (de la orden), currency, status (pending/approved/rejected/refunded), metadata?, timestamps.
Depende de
@quadcore-lib/orders-serverpara leerOrderEntity.total.
Seguridad del webhook
POST /payments/webhook valida la firma HMAC-SHA256 sobre el raw body (req.rawBody, habilitado en bootstrapQuadcoreApp). La validación la hace el PaymentProvider vía verifyWebhook(rawBody, signature, headers) — headers trae todos los headers del request, por si tu provider necesita algo más que la firma (ej. MercadoPago exige también x-request-id en el manifest firmado).
MockPaymentProvider es fail-closed: sin webhookSecret configurado rechaza todos los webhooks (401). Con secret, valida la firma via timingSafeEqual. No lo uses en producción (aprueba cualquier pago en createPayment).
El id del pago puede cambiar entre createPayment y el webhook
Algunos providers (MercadoPago: preferencia vs. pago real) generan un id distinto al crear el pago del que reportan en el webhook. PaymentsService.handleWebhook contempla esto: si WebhookResult.providerPaymentId no matchea ningún PaymentEntity existente, y el provider mandó orderId, busca por orderId y adopta el providerPaymentId nuevo (así los próximos webhooks de ese mismo pago sí matchean directo). Si tu provider siempre usa el mismo id de punta a punta, este fallback nunca se activa — no hace falta hacer nada especial.
// Development: fail-closed sin secret
QuadcorePaymentsModule.forRoot();
// Staging: validar firma real con el Mock
QuadcorePaymentsModule.forRoot({
provider: new MockPaymentProvider({ webhookSecret: process.env.MOCK_WEBHOOK_SECRET }),
});
// Producción: tu provider real
QuadcorePaymentsModule.forRootAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => new MercadoPagoProvider(config.get('MP_ACCESS_TOKEN')),
});Notificaciones automáticas al cambiar de estado (opcional)
QuadcorePaymentsModule.forRoot({ eventEmitter }) (o forRootAsync({ ..., eventEmitter })) emite PAYMENT_STATUS_CHANGED (de @quadcore-lib/core-server) cada vez que un webhook cambia el estado de un pago. Mismo mecanismo que orders-server — ver su README y el de @quadcore-lib/notifications-server (autoNotify). Pasále la MISMA instancia de eventEmitter a los tres módulos.
Migraciones
Este paquete trae sus migraciones de TypeORM en dist/src/migrations/*.js (se compilan junto al resto). Ver la guía completa (setup del DataSource, cómo combinarlas con las de otros paquetes, synchronize en dev vs. prod) en el README de @quadcore-lib/core-server, sección "Migraciones de DB".
