Skip to content

Commit b191f44

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
refactor netsuite tool definitions
1 parent 7d113fd commit b191f44

31 files changed

Lines changed: 2731 additions & 808 deletions

apps/docs/content/docs/en/integrations/netsuite.mdx

Lines changed: 313 additions & 74 deletions
Large diffs are not rendered by default.

apps/sim/blocks/blocks/netsuite.ts

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,153 @@ export const NetSuiteBlock: BlockConfig<NetSuiteResponse> = {
154154
integrationType: IntegrationType.Commerce,
155155
bgColor: '#FFFFFF',
156156
icon: NetSuiteIcon,
157+
canvasPresentation: {
158+
defaultTitle: 'Oracle NetSuite',
159+
sentences: {
160+
byOperation: {
161+
netsuite_list_records: [
162+
{ text: 'List records from', field: 'recordType', core: true },
163+
{ text: ', matching', field: 'q' },
164+
{ text: ', up to', field: 'limit', after: 'records' },
165+
{ text: ', starting at offset', field: 'offset' },
166+
],
167+
netsuite_get_record: [
168+
{ text: 'Read', field: 'recordType', core: true },
169+
{ text: 'record', field: 'recordId', core: true },
170+
{ text: ', returning', field: 'fields' },
171+
{ text: ', expanding', field: 'expand' },
172+
{ text: ', with subresources', field: 'expandSubResources' },
173+
],
174+
netsuite_create_record: [
175+
{ text: 'Create', field: 'recordType', core: true },
176+
{ text: 'record with', field: 'body' },
177+
],
178+
netsuite_update_record: [
179+
{ text: 'Update', field: 'recordType', core: true },
180+
{ text: 'record', field: 'recordId', core: true },
181+
{ text: ', setting', field: 'body' },
182+
{ text: ', replacing sublists', field: 'replace' },
183+
],
184+
netsuite_upsert_record: [
185+
{ text: 'Upsert', field: 'recordType', core: true },
186+
{ text: 'record by external ID', field: 'externalId', core: true },
187+
{ text: ', setting', field: 'body' },
188+
{ text: ', replacing sublists', field: 'replace' },
189+
],
190+
netsuite_delete_record: [
191+
{ text: 'Delete', field: 'recordType', core: true },
192+
{ text: 'record', field: 'recordId', core: true },
193+
],
194+
netsuite_get_subresource: [
195+
{ text: 'Read subresource', field: 'subresourcePath', core: true },
196+
{ text: 'from', field: 'recordType' },
197+
{ text: 'record', field: 'recordId' },
198+
],
199+
netsuite_get_record_form: [
200+
{ text: 'Get the form for', field: 'recordType', core: true },
201+
{ text: 'record', field: 'recordId' },
202+
{ text: ', prefilled with', field: 'body' },
203+
{ text: ', returning', field: 'fields' },
204+
{ text: ', expanding', field: 'expand' },
205+
{ text: ', with subresources', field: 'expandSubResources' },
206+
],
207+
netsuite_get_select_options: [
208+
{ text: 'Get select options for', field: 'fields', core: true },
209+
{ text: 'on', field: 'recordType' },
210+
{ text: 'record', field: 'recordId' },
211+
{ text: ', matching', field: 'q' },
212+
{ text: ', using', field: 'body' },
213+
{ text: ', up to', field: 'limit', after: 'options' },
214+
{ text: ', starting at offset', field: 'offset' },
215+
],
216+
netsuite_attach_record: [
217+
{ text: 'Attach', field: 'relatedType', core: true },
218+
{ text: 'ID', field: 'relatedId', core: true },
219+
{ text: 'to', field: 'recordType' },
220+
{ text: 'record', field: 'recordId' },
221+
{ text: ', with role ID', field: 'roleId' },
222+
{ text: ', or role external ID', field: 'roleExternalId' },
223+
],
224+
netsuite_detach_record: [
225+
{ text: 'Detach', field: 'relatedType', core: true },
226+
{ text: 'ID', field: 'relatedId', core: true },
227+
{ text: 'from', field: 'recordType' },
228+
{ text: 'record', field: 'recordId' },
229+
],
230+
netsuite_execute_action: [
231+
{ text: 'Run action', field: 'action', core: true },
232+
{ text: 'on', field: 'recordType' },
233+
{ text: 'record', field: 'recordId' },
234+
{ text: ', with', field: 'body' },
235+
],
236+
netsuite_transform_record: [
237+
{ text: 'Transform', field: 'recordType', core: true },
238+
{ text: 'record', field: 'recordId', core: true },
239+
{ text: 'into', field: 'targetRecordType' },
240+
{ text: ', with', field: 'body' },
241+
],
242+
netsuite_batch_get_records: [
243+
{ text: 'Retrieve a batch of', field: 'recordType', core: true },
244+
{ text: 'records', field: 'ids', core: true },
245+
{ text: ', returning', field: 'fields' },
246+
{ text: ', expanding', field: 'expand' },
247+
{ text: ', with subresources', field: 'expandSubResources' },
248+
{ text: ', using idempotency key', field: 'idempotencyKey' },
249+
],
250+
netsuite_batch_create_records: [
251+
{ text: 'Create a batch of', field: 'recordType', core: true },
252+
{ text: 'records', field: 'items', core: true },
253+
{ text: ', using idempotency key', field: 'idempotencyKey' },
254+
],
255+
netsuite_batch_update_records: [
256+
{ text: 'Update a batch of', field: 'recordType', core: true },
257+
{ text: 'records', field: 'items', core: true },
258+
{ text: ', using idempotency key', field: 'idempotencyKey' },
259+
],
260+
netsuite_batch_upsert_records: [
261+
{ text: 'Upsert a batch of', field: 'recordType', core: true },
262+
{ text: 'records', field: 'items', core: true },
263+
{ text: ', using idempotency key', field: 'idempotencyKey' },
264+
],
265+
netsuite_batch_delete_records: [
266+
{ text: 'Delete a batch of', field: 'recordType', core: true },
267+
{ text: 'records', field: 'ids', core: true },
268+
{ text: ', using idempotency key', field: 'idempotencyKey' },
269+
],
270+
netsuite_execute_suiteql: [
271+
{ text: 'Run SuiteQL', field: 'query', core: true },
272+
{ text: ', up to', field: 'limit', after: 'rows' },
273+
{ text: ', starting at offset', field: 'offset' },
274+
],
275+
netsuite_list_datasets: [
276+
'List SuiteAnalytics datasets',
277+
{ text: ', up to', field: 'limit', after: 'datasets' },
278+
{ text: ', starting at offset', field: 'offset' },
279+
],
280+
netsuite_execute_dataset: [
281+
{ text: 'Execute SuiteAnalytics dataset', field: 'datasetId', core: true },
282+
{ text: ', up to', field: 'limit', after: 'rows' },
283+
{ text: ', starting at offset', field: 'offset' },
284+
],
285+
netsuite_list_record_types: ['List available record types'],
286+
netsuite_get_record_metadata: [
287+
{ text: 'Get metadata for', field: 'recordType', core: true },
288+
{ text: ', in format', field: 'format' },
289+
],
290+
netsuite_get_async_status: [
291+
{ text: 'Get async job', field: 'jobId', core: true },
292+
{ text: 'view', field: 'view' },
293+
{ text: 'for task', field: 'statusTaskId' },
294+
],
295+
netsuite_get_async_result: [
296+
{ text: 'Get result from async job', field: 'jobId', core: true },
297+
{ text: 'for task', field: 'resultTaskId', core: true },
298+
],
299+
netsuite_get_server_time: ['Get NetSuite server time'],
300+
netsuite_get_governance_limits: ['Get NetSuite governance limits'],
301+
},
302+
},
303+
},
157304
subBlocks: [
158305
{
159306
id: 'operation',

apps/sim/lib/integrations/integrations.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13816,7 +13816,7 @@
1381613816
},
1381713817
{
1381813818
"name": "Get Governance Limits",
13819-
"description": "Retrieve REST web-services concurrency limits for the NetSuite account and integration."
13819+
"description": "Retrieve REST web-services concurrency limits for the NetSuite account and integration; NetSuite requires an Administrator role."
1382013820
}
1382113821
],
1382213822
"operationCount": 27,
Lines changed: 95 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,65 @@
1-
import type { NetSuiteAttachParams } from '@/tools/netsuite/types'
1+
import type { NetSuiteAttachParams, NetSuiteResponse } from '@/tools/netsuite/types'
22
import {
33
buildRecordPath,
4-
createNetSuiteTool,
4+
executeNetSuiteRequest,
55
normalizeRelatedType,
66
optionalTrim,
7-
RECORD_ID_PARAM,
8-
RECORD_TYPE_PARAM,
97
} from '@/tools/netsuite/utils'
8+
import type { ToolConfig } from '@/tools/types'
109

11-
export const netsuiteAttachRecordTool = createNetSuiteTool<NetSuiteAttachParams>({
10+
export const netsuiteAttachRecordTool: ToolConfig<NetSuiteAttachParams, NetSuiteResponse> = {
1211
id: 'netsuite_attach_record',
1312
name: 'NetSuite Attach Record or File',
1413
description: 'Attach a contact or file to another NetSuite record.',
14+
version: '1.0.0',
1515
params: {
16-
recordType: RECORD_TYPE_PARAM,
17-
recordId: RECORD_ID_PARAM,
16+
accountId: {
17+
type: 'string',
18+
required: true,
19+
visibility: 'user-only',
20+
description: 'NetSuite account ID, including any sandbox or release-preview suffix',
21+
},
22+
clientId: {
23+
type: 'string',
24+
required: true,
25+
visibility: 'user-only',
26+
description: 'Client ID of the NetSuite OAuth 2.0 integration record',
27+
},
28+
certificateId: {
29+
type: 'string',
30+
required: true,
31+
visibility: 'user-only',
32+
description: 'Certificate ID from OAuth 2.0 Client Credentials (M2M) Setup',
33+
},
34+
privateKey: {
35+
type: 'string',
36+
required: true,
37+
visibility: 'user-only',
38+
description:
39+
'3072- or 4096-bit RSA PEM private key matching the certificate uploaded to NetSuite',
40+
},
41+
recordType: {
42+
type: 'string',
43+
required: true,
44+
visibility: 'user-or-llm',
45+
description: 'NetSuite REST record type script ID, such as customer or salesOrder',
46+
},
47+
recordId: {
48+
type: 'string',
49+
required: true,
50+
visibility: 'user-or-llm',
51+
description: 'NetSuite internal ID or an external-ID reference beginning with eid:',
52+
},
1853
relatedType: {
1954
type: 'string',
2055
required: true,
2156
visibility: 'user-or-llm',
2257
description: 'Related resource type: contact or file',
2358
},
2459
relatedId: {
25-
...RECORD_ID_PARAM,
60+
type: 'string',
61+
required: true,
62+
visibility: 'user-or-llm',
2663
description: 'Internal or external ID of the contact or file',
2764
},
2865
roleId: {
@@ -38,30 +75,54 @@ export const netsuiteAttachRecordTool = createNetSuiteTool<NetSuiteAttachParams>
3875
description: 'Optional contact role external ID',
3976
},
4077
},
41-
buildRequest: (params) => {
42-
const relatedType = normalizeRelatedType(params.relatedType)
43-
const roleId = optionalTrim(params.roleId)
44-
const roleExternalId = optionalTrim(params.roleExternalId)
45-
if (roleId && roleExternalId) {
46-
throw new Error('Provide either a contact role ID or external ID, not both')
47-
}
48-
if (relatedType === 'file' && (roleId || roleExternalId)) {
49-
throw new Error('Contact roles cannot be provided when attaching a file')
50-
}
51-
return {
52-
method: 'POST',
53-
path: buildRecordPath(
54-
{ value: params.recordType, label: 'Record type' },
55-
{ value: params.recordId, label: 'Record ID' },
56-
{ value: '!attach', label: 'Attach operation' },
57-
{ value: relatedType, label: 'Related type' },
58-
{ value: params.relatedId, label: 'Related ID' }
59-
),
60-
body: roleId
61-
? { role: { id: roleId } }
62-
: roleExternalId
63-
? { role: { externalId: roleExternalId } }
64-
: {},
65-
}
78+
request: { url: () => '', method: 'POST', headers: () => ({}) },
79+
directExecution: (params, signal) =>
80+
executeNetSuiteRequest(
81+
params,
82+
() => {
83+
const relatedType = normalizeRelatedType(params.relatedType)
84+
const roleId = optionalTrim(params.roleId)
85+
const roleExternalId = optionalTrim(params.roleExternalId)
86+
if (roleId && roleExternalId) {
87+
throw new Error('Provide either a contact role ID or external ID, not both')
88+
}
89+
if (relatedType === 'file' && (roleId || roleExternalId)) {
90+
throw new Error('Contact roles cannot be provided when attaching a file')
91+
}
92+
return {
93+
method: 'POST',
94+
path: buildRecordPath(
95+
{ value: params.recordType, label: 'Record type' },
96+
{ value: params.recordId, label: 'Record ID' },
97+
{ value: '!attach', label: 'Attach operation' },
98+
{ value: relatedType, label: 'Related type' },
99+
{ value: params.relatedId, label: 'Related ID' }
100+
),
101+
body: roleId
102+
? { role: { id: roleId } }
103+
: roleExternalId
104+
? { role: { externalId: roleExternalId } }
105+
: {},
106+
}
107+
},
108+
signal
109+
),
110+
outputs: {
111+
status: { type: 'number', description: 'HTTP status returned by NetSuite' },
112+
data: {
113+
type: 'json',
114+
description: 'NetSuite response body; record fields are account-specific and dynamic',
115+
nullable: true,
116+
},
117+
location: {
118+
type: 'string',
119+
description: 'Created resource or asynchronous job location returned by NetSuite',
120+
optional: true,
121+
},
122+
jobId: {
123+
type: 'string',
124+
description: 'Asynchronous job ID parsed from the Location header',
125+
optional: true,
126+
},
66127
},
67-
})
128+
}

0 commit comments

Comments
 (0)