diff --git a/localenv/cloud-nine-wallet/docker-compose.yml b/localenv/cloud-nine-wallet/docker-compose.yml index dd3e66e7e9..64f82dfcdf 100644 --- a/localenv/cloud-nine-wallet/docker-compose.yml +++ b/localenv/cloud-nine-wallet/docker-compose.yml @@ -156,6 +156,7 @@ services: KEY_ID: 7097F83B-CB84-469E-96C6-2141C72E22C0 OPERATOR_TENANT_ID: 438fa74a-fa7d-4317-9ced-dde32ece1787 CARD_SERVICE_URL: 'http://cloud-nine-wallet-card-service:3007' + CARD_WEBHOOK_SERVICE_URL: 'http://cloud-nine-wallet-card-service:3007/payment-event' depends_on: - shared-database - shared-redis diff --git a/packages/backend/src/open_payments/payment/outgoing/service.ts b/packages/backend/src/open_payments/payment/outgoing/service.ts index ecaf61c125..7d3f9ce6e9 100644 --- a/packages/backend/src/open_payments/payment/outgoing/service.ts +++ b/packages/backend/src/open_payments/payment/outgoing/service.ts @@ -264,7 +264,7 @@ async function cancelOutgoingPayment( : {}) } }) - .withGraphFetched('quote') + .withGraphFetched('[quote, cardDetails]') const asset = await deps.assetService.get(payment.quote.assetId) if (asset) payment.quote.asset = asset @@ -719,7 +719,7 @@ async function fundPayment( tenantId }) .forUpdate() - .withGraphFetched('quote') + .withGraphFetched('[quote, cardDetails]') if (!payment) return FundingError.UnknownPayment const asset = await deps.assetService.get(payment.quote.assetId) diff --git a/packages/card-service/src/app.ts b/packages/card-service/src/app.ts index 402fc09ab4..72740a6fb6 100644 --- a/packages/card-service/src/app.ts +++ b/packages/card-service/src/app.ts @@ -9,10 +9,12 @@ import cors from '@koa/cors' import { createValidatorMiddleware, HttpMethod } from '@interledger/openapi' import { PaymentContext } from './payment/types' import { PaymentEventContext } from './payment/types' +import { PaymentRoutes } from './payment/routes' export interface AppServices { logger: Promise config: Promise + paymentRoutes: Promise } export type AppContainer = IocContract diff --git a/packages/point-of-sale/src/card-service-client/client.test.ts b/packages/point-of-sale/src/card-service-client/client.test.ts index 60900c72d0..cfcfb2dc05 100644 --- a/packages/point-of-sale/src/card-service-client/client.test.ts +++ b/packages/point-of-sale/src/card-service-client/client.test.ts @@ -28,9 +28,9 @@ describe('CardServiceClient', () => { expect(nock.isDone()).toBeTruthy() }) - const createPaymentResponse = (result?: Result): PaymentResponse => ({ + const createPaymentResponse = (resultCode?: Result): PaymentResponse => ({ requestId: 'requestId', - result: result ?? Result.APPROVED + result: { code: resultCode || Result.APPROVED } }) const options: SendPaymentArgs = { @@ -46,20 +46,15 @@ describe('CardServiceClient', () => { } } - describe('returns the result', () => { - it.each` - result | code - ${Result.APPROVED} | ${HttpStatusCode.Ok} - ${Result.CARD_EXPIRED} | ${HttpStatusCode.Unauthorized} - ${Result.INVALID_SIGNATURE} | ${HttpStatusCode.Unauthorized} - `('when the result is $result', async (response) => { - nock(CARD_SERVICE_URL) - .post('/payment') - .reply(response.code, createPaymentResponse(response.result)) - expect(await client.sendPayment(CARD_SERVICE_URL, options)).toBe( - response.result - ) - }) + test('returns the result', async () => { + const resultCode = Result.APPROVED + nock(CARD_SERVICE_URL) + .post('/payment') + .reply(201, createPaymentResponse(resultCode)) + + await expect(client.sendPayment(CARD_SERVICE_URL, options)).resolves.toBe( + resultCode + ) }) test('throws when there is no payload data', async () => { diff --git a/packages/point-of-sale/src/card-service-client/client.ts b/packages/point-of-sale/src/card-service-client/client.ts index 1073f473fb..1308b44564 100644 --- a/packages/point-of-sale/src/card-service-client/client.ts +++ b/packages/point-of-sale/src/card-service-client/client.ts @@ -37,13 +37,14 @@ interface ServiceDependencies extends BaseService { export enum Result { APPROVED = 'approved', - CARD_EXPIRED = 'card_expired', INVALID_SIGNATURE = 'invalid_signature' } export type PaymentResponse = { requestId: string - result: Result + result: { + code: Result + } } // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types @@ -97,14 +98,14 @@ async function sendPayment( HttpStatusCode.NotFound ) } - return payment.result + return payment.result.code } catch (error) { deps.logger.debug(error) if (error instanceof CardServiceClientError) throw error if (error instanceof AxiosError) { if (isPaymentResponse(error.response?.data)) { - return error.response.data.result + return error.response.data.result.code } throw new CardServiceClientError( error.response?.data ?? 'Unknown Axios error', diff --git a/packages/point-of-sale/src/payments/routes.test.ts b/packages/point-of-sale/src/payments/routes.test.ts index 9a7ef52f76..dc916ee766 100644 --- a/packages/point-of-sale/src/payments/routes.test.ts +++ b/packages/point-of-sale/src/payments/routes.test.ts @@ -69,18 +69,6 @@ describe('Payment Routes', () => { expect(webhookWaitMap.get('incoming-payment-url')).toBeUndefined() }) - test('returns 401 with result card_expired or invalid_signature', async () => { - const ctx = createPaymentContext() - mockPaymentService() - jest - .spyOn(cardServiceClient, 'sendPayment') - .mockResolvedValueOnce(Result.CARD_EXPIRED) - - await paymentRoutes.payment(ctx) - expect(ctx.response.body).toBe(Result.CARD_EXPIRED) - expect(ctx.status).toBe(401) - }) - test('returns cardService error code when thrown', async () => { const ctx = createPaymentContext() mockPaymentService()