From d7a0ed0a83fd75da5bec0afaae1f25c904b16080 Mon Sep 17 00:00:00 2001 From: aiirvizionz Date: Tue, 21 Jul 2026 16:11:39 -0600 Subject: [PATCH] fix(payment-square): validate refund amount money --- .../targets/payment-square/src/index.test.ts | 39 +++++++++++++++++++ packages/targets/payment-square/src/index.ts | 4 +- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/packages/targets/payment-square/src/index.test.ts b/packages/targets/payment-square/src/index.test.ts index 8dd6e5fc..b79573ee 100644 --- a/packages/targets/payment-square/src/index.test.ts +++ b/packages/targets/payment-square/src/index.test.ts @@ -119,4 +119,43 @@ describe('payment-square target adapter', () => { expect(fetchMock).not.toHaveBeenCalled(); }); + + it('refunds payments with validated amount money', async () => { + const fetchMock = vi.fn().mockResolvedValue({ + ok: true, + json: async () => ({ refund: { id: 'refund_123' } }), + }); + vi.stubGlobal('fetch', fetchMock); + + await target.build(fakeBuildContext({ + secret: makeVault({ SQUARE_ACCESS_TOKEN: 'square-token' }), + }) as any, { + command: 'refund', + args: { paymentId: 'pay_123', amount: 500, currency: 'usd', reason: 'duplicate' }, + }); + + expect(fetchMock).toHaveBeenCalledWith('https://connect.squareup.com/v2/refunds', expect.objectContaining({ + method: 'POST', + })); + const body = JSON.parse(String(fetchMock.mock.calls[0]![1].body)); + expect(body).toMatchObject({ + payment_id: 'pay_123', + amount_money: { amount: 500, currency: 'USD' }, + reason: 'duplicate', + }); + }); + + it('rejects invalid refund amounts before calling Square', async () => { + const fetchMock = vi.fn(); + vi.stubGlobal('fetch', fetchMock); + + await expect(target.build(fakeBuildContext({ + secret: makeVault({ SQUARE_ACCESS_TOKEN: 'square-token' }), + }) as any, { + command: 'refund', + args: { paymentId: 'pay_123', amount: 1.5, currency: 'USD' }, + })).rejects.toThrow('amount must be a positive integer'); + + expect(fetchMock).not.toHaveBeenCalled(); + }); }); diff --git a/packages/targets/payment-square/src/index.ts b/packages/targets/payment-square/src/index.ts index ef718fa3..d4a0549e 100644 --- a/packages/targets/payment-square/src/index.ts +++ b/packages/targets/payment-square/src/index.ts @@ -93,13 +93,15 @@ export default defineTarget({ } case 'refund': { const id = requireText(config.args?.paymentId, 'paymentId'); + const amount = requirePositiveInteger(config.args?.amount, 'amount'); + const currency = requireCurrency(config.args?.currency); ctx.log(`square: refunding payment ${id}`); const data = await sq('/refunds', { method: 'POST', body: JSON.stringify({ idempotency_key: `sh1pt-${Date.now()}`, payment_id: id, - amount_money: config.args?.amount, + amount_money: { amount, currency }, reason: (config.args?.reason as string) || 'requested_by_customer', }), });