Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
cabe393
feat: created the backbone for the card service (#3508)
oana-lolea Jul 7, 2025
f2676fa
feat: initialize POS service (#3509)
oana-lolea Jul 8, 2025
5a7afb8
feat(card-service): card payments table (#3514)
lengyel-arpad85 Jul 8, 2025
62bebbc
feat(pos): create merchants table (#3519)
lengyel-arpad85 Jul 8, 2025
3d145f2
typo
lengyel-arpad85 Jul 8, 2025
1e2a9f2
Docker compose fix (for slower PCs) on localenv (#3522)
oana-lolea Jul 8, 2025
4ab874d
feat: Added CardService client in rafiki backend (#3510)
zeppelin44 Jul 9, 2025
7905bb4
feat(pos): pos card services table (#3526)
lengyel-arpad85 Jul 9, 2025
705d7de
feat(card-service): introduce testcontainers for database and redis (…
beniaminmunteanu Jul 9, 2025
2a54638
feat(pos): merchants services (#3528)
lengyel-arpad85 Jul 10, 2025
35b3a78
feat: Integrate Redis client in Card Service for (requestId, posServi…
zeppelin44 Jul 10, 2025
86ce1bc
feat(pos): create merchant route (#3538)
lengyel-arpad85 Jul 10, 2025
2979a2a
feat(card-service): introduce AuditLogService (#3525)
beniaminmunteanu Jul 10, 2025
48425d0
fix(localenv): add required env vars to docker-compose (#3550)
njlie Jul 10, 2025
c77c9ba
feat(point-of-sale): POS Device service (#3548)
oana-lolea Jul 10, 2025
85007a9
feat(pos): RAF-1121-revoke merchant route (#3553)
beniaminmunteanu Jul 10, 2025
a8236fa
fix: (rafiki backend) Augment Wallet Address response with cardServic…
MiguelLescasJorgeSebastian Jul 10, 2025
9854a64
feat(point-of-sale): added route for registering a POS device (#3555)
oana-lolea Jul 11, 2025
4d73742
feat: bruno calls for creating merchant and registering POS device (#…
njlie Jul 11, 2025
9e84541
feat: [RAF-1083][POS Service]: Add GQL Client for Rafiki BE calls for…
zeppelin44 Jul 14, 2025
a5e7d13
feat(pos): device revoke (#3560)
beniaminmunteanu Jul 22, 2025
e980403
feat(backend): Raul/raf 1095 augment outgoing payments for card (#3539)
RaulBR Aug 4, 2025
195d912
feat(point-of-sale): service for obtaining walletAddress by its url f…
oana-lolea Aug 6, 2025
500137d
feat(card-service): add endpoints to initiate payment and receive pay…
dragosp1011 Aug 13, 2025
05ec5d9
fix(backend): made CARD_SERVICE_URL optional (#3600)
oana-lolea Aug 14, 2025
4bfe677
feat(point-of-sale): POST payment route (#3597)
oana-lolea Aug 18, 2025
f0c171e
feat(backend): publish webhooks to POS service if applicable (#3596)
njlie Aug 26, 2025
9bf016c
feat(point-of-sale): handle incoming payment completed webhooks from …
njlie Aug 26, 2025
b28a8de
feat(card-service): call outgoing payment creation during payment rou…
njlie Aug 27, 2025
a131fbc
fix(point-of-sale): added bruno script + added missing env variables …
oana-lolea Sep 17, 2025
b23b668
fix: match payment bodies for pos and card service (#3653)
oana-lolea Sep 18, 2025
ed7c5af
feat(backend): additional webhook events for outgoing payments (#3651)
sanducb Sep 23, 2025
70e9c68
feat(backend): Update handling of `OutgoingPaymentCardDetails` (#3658)
mkurapov Sep 23, 2025
f6024e3
feat: add integration test for pos-card flow (#3678)
oana-lolea Oct 13, 2025
61c4920
feat(point-of-sale): allow refunding incoming payments
njlie Nov 19, 2025
362b9d6
feat: WALLET_ADDRESS_NOT_FOUND_POLLING_ENABLED flag in backend (#3719)
mkurapov Oct 27, 2025
1eb43ae
feat: adding `card-service` and `point-of-sale` (#3715)
mkurapov Oct 31, 2025
97a823f
chore: fix rebase issues
njlie Nov 20, 2025
c58c04d
chore: fix more rebase issues
njlie Nov 20, 2025
1747ad6
fix: correct response and add bruno request
njlie Nov 21, 2025
cfcca07
feat: use incoming payment url in metadata
njlie Nov 21, 2025
a3bb863
feat: improve bruno entry
njlie Nov 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
meta {
name: Get Incoming Payments
type: http
seq: 4
seq: 2
}

get {
Expand All @@ -13,3 +13,11 @@ get {
params:query {
receiverWalletAddress: https://happy-life-bank-backend/accounts/pfry
}

script:post-response {
const body = res.getBody();

if (body?.result) {
bru.setEnvVar("refundIncomingPaymentId", body.result[0].id);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
meta {
name: Initiate Payment
type: http
seq: 3
seq: 1
}

post {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
meta {
name: Refund Incoming Payment
type: http
seq: 3
}

post {
url: http://localhost:4008/refund
body: json
auth: inherit
}

body:json {
{
"incomingPaymentId": "{{refundIncomingPaymentId}}",
"posWalletAddress": "https://happy-life-bank-backend/accounts/pfry"
}
}

settings {
encodeUrl: true
timeout: 0
}
10 changes: 9 additions & 1 deletion packages/point-of-sale/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import cors from '@koa/cors'
import {
GetPaymentsContext,
PaymentContext,
PaymentRoutes
PaymentRoutes,
RefundContext
} from './payments/routes'
import {
HandleWebhookContext,
Expand Down Expand Up @@ -89,6 +90,13 @@ export class App {
webhookHandlerRoutes.handleWebhook
)

// POST /refund
// Refund a payment
router.post<DefaultState, RefundContext>(
'/refund',
paymentRoutes.refundPayment
)

koa.use(cors())
koa.use(router.routes())

Expand Down
21 changes: 21 additions & 0 deletions packages/point-of-sale/src/graphql/generated/graphql.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { gql } from '@apollo/client'

export const CREATE_OUTGOING_PAYMENT_FROM_INCOMING_PAYMENT = gql`
mutation CreateOutgoingPaymentFromIncomingPayment(
$input: CreateOutgoingPaymentFromIncomingPaymentInput!
) {
createOutgoingPaymentFromIncomingPayment(input: $input) {
payment {
id
walletAddressId
createdAt
}
}
}
`
17 changes: 17 additions & 0 deletions packages/point-of-sale/src/graphql/mutations/createReceiver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { gql } from '@apollo/client'

export const CREATE_RECEIVER = gql`
mutation CreateReceiver($input: CreateReceiverInput!) {
createReceiver(input: $input) {
receiver {
id
metadata
incomingAmount {
value
assetCode
assetScale
}
}
}
}
`
16 changes: 16 additions & 0 deletions packages/point-of-sale/src/graphql/queries/getIncomingPayment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { gql } from '@apollo/client'

export const GET_INCOMING_PAYMENT = gql`
query GetIncomingPaymentSenderAndAmount($id: String!) {
incomingPayment(id: $id) {
id
url
senderWalletAddress
incomingAmount {
value
assetCode
assetScale
}
}
}
`
41 changes: 40 additions & 1 deletion packages/point-of-sale/src/payments/routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
GetPaymentsContext,
GetPaymentsQuery,
PaymentContext,
PaymentRoutes
PaymentRoutes,
RefundContext
} from './routes'
import { PaymentService } from './service'
import { CardServiceClient, Result } from '../card-service-client/client'
Expand Down Expand Up @@ -376,6 +377,32 @@ describe('Payment Routes', () => {
})
})
})

describe('refund payment', () => {
test('returns 200 when refunding incoming payment', async (): Promise<void> => {
const ctx = createRefundContext()
jest
.spyOn(paymentService, 'refundIncomingPayment')
.mockResolvedValueOnce({
id: v4()
})

await paymentRoutes.refundPayment(ctx)
expect(ctx.status).toEqual(200)
})

test('returns 400 if incoming payment refund fails', async (): Promise<void> => {
const ctx = createRefundContext()
const refundError = new Error('Failed to refund incoming payment')
jest
.spyOn(paymentService, 'refundIncomingPayment')
.mockRejectedValueOnce(refundError)

await paymentRoutes.refundPayment(ctx)
expect(ctx.status).toEqual(400)
expect(ctx.body).toEqual(refundError.message)
})
})
})

function createPaymentContext(bodyOverrides?: Record<string, unknown>) {
Expand Down Expand Up @@ -416,3 +443,15 @@ function createGetPaymentsContext(
query
})
}

function createRefundContext() {
return createContext<RefundContext>({
headers: { Accept: 'application/json' },
method: 'POST',
url: '/refund',
body: {
incomingPaymentId: v4(),
posWalletAddress: faker.internet.url()
}
})
}
36 changes: 35 additions & 1 deletion packages/point-of-sale/src/payments/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,23 @@ export type GetPaymentsContext = Exclude<AppContext, 'request'> & {
request: GetPaymentsRequest
}

export interface RefundRequestBody {
incomingPaymentId: string
posWalletAddress: string
}

export type RefundRequest = Exclude<AppContext['request'], 'body'> & {
body: RefundRequestBody
}

export type RefundContext = Exclude<AppContext, ['request']> & {
request: RefundRequest
}

export interface PaymentRoutes {
getPayments(ctx: GetPaymentsContext): Promise<void>
payment(ctx: PaymentContext): Promise<void>
refundPayment(ctx: RefundContext): Promise<void>
}

export function createPaymentRoutes(deps_: ServiceDependencies): PaymentRoutes {
Expand All @@ -85,7 +99,8 @@ export function createPaymentRoutes(deps_: ServiceDependencies): PaymentRoutes {

return {
payment: (ctx: PaymentContext) => payment(deps, ctx),
getPayments: (ctx: GetPaymentsContext) => getPayments(deps, ctx)
getPayments: (ctx: GetPaymentsContext) => getPayments(deps, ctx),
refundPayment: (ctx: RefundContext) => refundPayment(deps, ctx)
}
}

Expand Down Expand Up @@ -184,6 +199,25 @@ async function payment(
}
}

async function refundPayment(
deps: ServiceDependencies,
ctx: RefundContext
): Promise<void> {
const { incomingPaymentId, posWalletAddress } = ctx.request.body
try {
await deps.paymentService.refundIncomingPayment(
incomingPaymentId,
posWalletAddress
)
ctx.status = 200
return
} catch (err) {
ctx.status = 400
ctx.body = (err as Error).message
return
}
}

async function waitForIncomingPaymentEvent(
config: IAppConfig,
deferred: Deferred<WebhookBody>
Expand Down
Loading
Loading