Skip to content

Commit 78b2768

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(quickbooks): reject incomplete batch responses
1 parent 3a89100 commit 78b2768

2 files changed

Lines changed: 60 additions & 3 deletions

File tree

apps/sim/tools/quickbooks/batch.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,25 @@ export const quickBooksBatchTool: ToolConfig<QuickBooksBatchParams, QuickBooksBa
5555
body: (params) => buildQuickBooksBatchBody(params.batch),
5656
},
5757

58-
transformResponse: async (response) => {
58+
transformResponse: async (response, params) => {
59+
if (!params) throw new Error('QuickBooks batch parameters are required')
5960
const data = await parseQuickBooksJson(response)
61+
const requestItems = buildQuickBooksBatchBody(params.batch).BatchItemRequest
62+
const batchItems = data.BatchItemResponse
63+
64+
if (!Array.isArray(batchItems) || batchItems.length === 0) {
65+
throw new Error('QuickBooks batch response did not include any item responses')
66+
}
67+
if (Array.isArray(requestItems) && batchItems.length !== requestItems.length) {
68+
throw new Error(
69+
`QuickBooks batch response returned ${batchItems.length} of ${requestItems.length} item responses`
70+
)
71+
}
72+
6073
return {
6174
success: true,
6275
output: {
63-
batchItems: Array.isArray(data.BatchItemResponse) ? data.BatchItemResponse : [],
76+
batchItems,
6477
time: typeof data.time === 'string' ? data.time : null,
6578
},
6679
}

apps/sim/tools/quickbooks/generic_operations.test.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,12 @@ describe('QuickBooks generic operations', () => {
852852
const result = await quickBooksBatchTool.transformResponse?.(response, {
853853
accessToken: 'token',
854854
realmId: '123145',
855-
batch: { BatchItemRequest: [] },
855+
batch: {
856+
BatchItemRequest: [
857+
{ bId: 'vendor-query', Query: 'SELECT * FROM Vendor' },
858+
{ bId: 'bad-update', Vendor: { Id: '1', SyncToken: '0' }, operation: 'update' },
859+
],
860+
},
856861
})
857862

858863
expect(result?.output).toEqual({
@@ -863,4 +868,43 @@ describe('QuickBooks generic operations', () => {
863868
time: '2026-01-20T10:00:00-08:00',
864869
})
865870
})
871+
872+
it('rejects successful QuickBooks batch responses with missing or incomplete items', async () => {
873+
const params = {
874+
accessToken: 'token',
875+
realmId: '123145',
876+
batch: {
877+
BatchItemRequest: [
878+
{ bId: 'vendor-query', Query: 'SELECT * FROM Vendor' },
879+
{ bId: 'bill-query', Query: 'SELECT * FROM Bill' },
880+
],
881+
},
882+
}
883+
884+
await expect(
885+
quickBooksBatchTool.transformResponse?.(
886+
new Response(JSON.stringify({ time: '2026-01-20T10:00:00-08:00' }), { status: 200 }),
887+
params
888+
)
889+
).rejects.toThrow('QuickBooks batch response did not include any item responses')
890+
891+
await expect(
892+
quickBooksBatchTool.transformResponse?.(
893+
new Response(JSON.stringify({ BatchItemResponse: [] }), { status: 200 }),
894+
params
895+
)
896+
).rejects.toThrow('QuickBooks batch response did not include any item responses')
897+
898+
await expect(
899+
quickBooksBatchTool.transformResponse?.(
900+
new Response(
901+
JSON.stringify({
902+
BatchItemResponse: [{ bId: 'vendor-query', QueryResponse: { Vendor: [{ Id: '1' }] } }],
903+
}),
904+
{ status: 200 }
905+
),
906+
params
907+
)
908+
).rejects.toThrow('QuickBooks batch response returned 1 of 2 item responses')
909+
})
866910
})

0 commit comments

Comments
 (0)