Skip to content

Commit 64f660b

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(quickbooks): validate master data inputs
1 parent 5f8f819 commit 64f660b

9 files changed

Lines changed: 87 additions & 18 deletions

File tree

apps/sim/tools/generated/tool-metadata.ts

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

apps/sim/tools/quickbooks/create_customer.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
buildQuickBooksEntityUrl,
1515
getQuickBooksToolHeaders,
1616
optionalQuickBooksString,
17+
parseQuickBooksAddress,
1718
quickBooksEmailAddress,
1819
quickBooksPhoneNumber,
1920
requiredQuickBooksString,
@@ -116,8 +117,8 @@ export const quickbooksCreateCustomerTool: ToolConfig<
116117
FamilyName: optionalQuickBooksString(params.familyName),
117118
PrimaryEmailAddr: quickBooksEmailAddress(params.primaryEmail),
118119
PrimaryPhone: quickBooksPhoneNumber(params.primaryPhone),
119-
BillAddr: params.billingAddress,
120-
ShipAddr: params.shippingAddress,
120+
BillAddr: parseQuickBooksAddress(params.billingAddress, 'billingAddress'),
121+
ShipAddr: parseQuickBooksAddress(params.shippingAddress, 'shippingAddress'),
121122
Taxable: params.taxable,
122123
}),
123124
retry: { enabled: false },

apps/sim/tools/quickbooks/create_vendor.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
buildQuickBooksEntityUrl,
1212
getQuickBooksToolHeaders,
1313
optionalQuickBooksString,
14+
parseQuickBooksAddress,
1415
quickBooksEmailAddress,
1516
quickBooksPhoneNumber,
1617
requiredQuickBooksString,
@@ -119,7 +120,7 @@ export const quickbooksCreateVendorTool: ToolConfig<
119120
FamilyName: optionalQuickBooksString(params.familyName),
120121
PrimaryEmailAddr: quickBooksEmailAddress(params.primaryEmail),
121122
PrimaryPhone: quickBooksPhoneNumber(params.primaryPhone),
122-
BillAddr: params.billingAddress,
123+
BillAddr: parseQuickBooksAddress(params.billingAddress, 'billingAddress'),
123124
PrintOnCheckName: optionalQuickBooksString(params.printOnCheckName),
124125
AcctNum: optionalQuickBooksString(params.accountNumber),
125126
Vendor1099: params.vendor1099,

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

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,69 @@ describe('QuickBooks customer and vendor mutations', () => {
575575
expect(() => parseQuickBooksAddress('{}', 'billingAddress')).toThrow('at least one')
576576
})
577577

578+
it('rejects malformed addresses in direct mutation tool calls', () => {
579+
expect(() =>
580+
quickbooksCreateCustomerTool.request.body!({
581+
...authParams,
582+
displayName: 'Sanitized Customer',
583+
billingAddress: 'not-an-object' as never,
584+
})
585+
).toThrow('billingAddress must be valid JSON')
586+
587+
expect(() =>
588+
quickbooksUpdateCustomerTool.request.body!({
589+
...authParams,
590+
customerId: '12',
591+
syncToken: '3',
592+
shippingAddress: [] as never,
593+
})
594+
).toThrow('shippingAddress must be a JSON object')
595+
596+
expect(() =>
597+
quickbooksCreateVendorTool.request.body!({
598+
...authParams,
599+
displayName: 'Sanitized Vendor',
600+
billingAddress: { unknown: 'value' } as never,
601+
})
602+
).toThrow('billingAddress contains unsupported field')
603+
604+
expect(() =>
605+
quickbooksUpdateVendorTool.request.body!({
606+
...authParams,
607+
vendorId: '21',
608+
syncToken: '4',
609+
billingAddress: {} as never,
610+
})
611+
).toThrow('billingAddress must contain at least one supported address field')
612+
})
613+
614+
it('treats omitted active status as unchanged in direct update calls', () => {
615+
expect(
616+
quickbooksUpdateCustomerTool.request.body!({
617+
...authParams,
618+
customerId: '12',
619+
syncToken: '3',
620+
companyName: 'Updated Company',
621+
})
622+
).toEqual({
623+
Id: '12',
624+
SyncToken: '3',
625+
sparse: true,
626+
CompanyName: 'Updated Company',
627+
})
628+
629+
for (const tool of [
630+
quickbooksUpdateCustomerTool,
631+
quickbooksUpdateVendorTool,
632+
quickbooksUpdateItemTool,
633+
]) {
634+
expect(tool.params.activeStatus).toMatchObject({
635+
required: false,
636+
default: 'unchanged',
637+
})
638+
}
639+
})
640+
578641
it('removes vendor tax identifiers from mutation output', async () => {
579642
const response = {
580643
Vendor: {

apps/sim/tools/quickbooks/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ export interface QuickBooksUpdateCustomerParams
250250
customerId: string
251251
syncToken: string
252252
displayName?: string
253-
activeStatus: QuickBooksActiveStatus
253+
activeStatus?: QuickBooksActiveStatus
254254
}
255255

256256
export interface QuickBooksCreateVendorParams extends QuickBooksAuthParams {
@@ -271,7 +271,7 @@ export interface QuickBooksUpdateVendorParams
271271
vendorId: string
272272
syncToken: string
273273
displayName?: string
274-
activeStatus: QuickBooksActiveStatus
274+
activeStatus?: QuickBooksActiveStatus
275275
}
276276

277277
export type QuickBooksWritableItemType = 'service' | 'non_inventory'
@@ -294,7 +294,7 @@ export interface QuickBooksUpdateItemParams
294294
syncToken: string
295295
name?: string
296296
incomeAccountId?: string
297-
activeStatus: QuickBooksActiveStatus
297+
activeStatus?: QuickBooksActiveStatus
298298
}
299299

300300
export interface QuickBooksCompanyInfoResponse extends ToolResponse {

apps/sim/tools/quickbooks/update_customer.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
buildQuickBooksEntityUrl,
1616
getQuickBooksToolHeaders,
1717
optionalQuickBooksString,
18+
parseQuickBooksAddress,
1819
quickBooksActiveValue,
1920
quickBooksEmailAddress,
2021
quickBooksPhoneNumber,
@@ -113,10 +114,10 @@ export const quickbooksUpdateCustomerTool: ToolConfig<
113114
},
114115
activeStatus: {
115116
type: 'string',
116-
required: true,
117+
required: false,
117118
visibility: 'user-or-llm',
118119
default: 'unchanged',
119-
description: 'Keep, activate, or deactivate the customer',
120+
description: 'Customer status change: unchanged, active, or inactive',
120121
},
121122
},
122123
oauth: {
@@ -140,8 +141,8 @@ export const quickbooksUpdateCustomerTool: ToolConfig<
140141
FamilyName: optionalQuickBooksString(params.familyName),
141142
PrimaryEmailAddr: quickBooksEmailAddress(params.primaryEmail),
142143
PrimaryPhone: quickBooksPhoneNumber(params.primaryPhone),
143-
BillAddr: params.billingAddress,
144-
ShipAddr: params.shippingAddress,
144+
BillAddr: parseQuickBooksAddress(params.billingAddress, 'billingAddress'),
145+
ShipAddr: parseQuickBooksAddress(params.shippingAddress, 'shippingAddress'),
145146
Taxable: params.taxable,
146147
Active: quickBooksActiveValue(params.activeStatus),
147148
}) as Record<string, unknown>

apps/sim/tools/quickbooks/update_item.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,10 @@ export const quickbooksUpdateItemTool: ToolConfig<
103103
},
104104
activeStatus: {
105105
type: 'string',
106-
required: true,
106+
required: false,
107107
visibility: 'user-or-llm',
108108
default: 'unchanged',
109-
description: 'Keep, activate, or deactivate the item',
109+
description: 'Item status change: unchanged, active, or inactive',
110110
},
111111
},
112112
oauth: {

apps/sim/tools/quickbooks/update_vendor.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
buildQuickBooksEntityUrl,
1313
getQuickBooksToolHeaders,
1414
optionalQuickBooksString,
15+
parseQuickBooksAddress,
1516
quickBooksActiveValue,
1617
quickBooksEmailAddress,
1718
quickBooksPhoneNumber,
@@ -116,10 +117,10 @@ export const quickbooksUpdateVendorTool: ToolConfig<
116117
},
117118
activeStatus: {
118119
type: 'string',
119-
required: true,
120+
required: false,
120121
visibility: 'user-or-llm',
121122
default: 'unchanged',
122-
description: 'Keep, activate, or deactivate the vendor',
123+
description: 'Vendor status change: unchanged, active, or inactive',
123124
},
124125
},
125126
oauth: {
@@ -143,7 +144,7 @@ export const quickbooksUpdateVendorTool: ToolConfig<
143144
FamilyName: optionalQuickBooksString(params.familyName),
144145
PrimaryEmailAddr: quickBooksEmailAddress(params.primaryEmail),
145146
PrimaryPhone: quickBooksPhoneNumber(params.primaryPhone),
146-
BillAddr: params.billingAddress,
147+
BillAddr: parseQuickBooksAddress(params.billingAddress, 'billingAddress'),
147148
PrintOnCheckName: optionalQuickBooksString(params.printOnCheckName),
148149
AcctNum: optionalQuickBooksString(params.accountNumber),
149150
Vendor1099: params.vendor1099,

apps/sim/tools/quickbooks/utils.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,10 @@ export function parseQuickBooksAddress(
306306
return result
307307
}
308308

309-
export function quickBooksActiveValue(activeStatus: QuickBooksActiveStatus): boolean | undefined {
310-
if (activeStatus === 'unchanged') return undefined
309+
export function quickBooksActiveValue(
310+
activeStatus: QuickBooksActiveStatus | undefined
311+
): boolean | undefined {
312+
if (activeStatus === undefined || activeStatus === 'unchanged') return undefined
311313
if (activeStatus === 'active') return true
312314
if (activeStatus === 'inactive') return false
313315
throw new Error(`Unsupported QuickBooks active status: ${String(activeStatus)}`)

0 commit comments

Comments
 (0)