@superglue/cli 1.1.107 → 1.1.108
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/cli.js +14 -8
- package/dist/skills/superglue/SKILL.md +1 -0
- package/dist/skills/superglue/references/suitecloud.md +188 -0
- package/package.json +1 -1
- package/skills/superglue/SKILL.md +1 -0
- package/skills/superglue/references/suitecloud.md +188 -0
|
@@ -25,6 +25,7 @@ Read these on demand — they are authoritative for their topic and kept in sync
|
|
|
25
25
|
| `sg skill redis` | Redis command syntax, connection URLs, key type handling |
|
|
26
26
|
| `sg skill mongodb` | MongoDB connection URLs (mongodb:// / mongodb+srv://), CRUD operations, Extended JSON, aggregation |
|
|
27
27
|
| `sg skill sftp-smb` | SFTP, FTP, and SMB operations, file upload/download semantics, path handling |
|
|
28
|
+
| `sg skill suitecloud` | NetSuite SuiteCloud deploys: custom fields, record types, scripts; validate, preview, deploy |
|
|
28
29
|
| `sg skill file-handling` | File detection, parsing, `file::` reference syntax, lazy base64 access, transform-produced files |
|
|
29
30
|
| `sg skill access-rules` | RBAC roles, resource grants, and tool/system permissions (enterprise only) |
|
|
30
31
|
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# SuiteCloud
|
|
2
|
+
|
|
3
|
+
The `suitecloud://` protocol changes NetSuite account structure: custom fields, custom record types, custom lists, forms, workflows, saved searches, roles, and scripts. The NetSuite REST API and SuiteScript cannot create these. It deploys SuiteCloud projects (SDF) to the account. Use it on the NetSuite system, next to its HTTP steps.
|
|
4
|
+
|
|
5
|
+
## Step Configuration
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
{
|
|
9
|
+
type: "request",
|
|
10
|
+
systemId: "netsuite",
|
|
11
|
+
url: "suitecloud://1234567-sb1.app.netsuite.com",
|
|
12
|
+
body: '{"operation": "validate", "files": {"Objects/custentity_sg_contract_end.xml": "<entitycustomfield ...>"}}'
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`method`, `headers`, `queryParams`, and `pagination` are HTTP-only fields. Omit them.
|
|
17
|
+
|
|
18
|
+
Every operation also runs as a single call:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
sg system call --system-id netsuite \
|
|
22
|
+
--url "suitecloud://1234567-sb1.app.netsuite.com" \
|
|
23
|
+
--body '{"operation": "listObjects", "objectTypes": ["entitycustomfield"]}'
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Fields
|
|
27
|
+
|
|
28
|
+
| Field | Required | Notes |
|
|
29
|
+
| ---------- | ---------- | -------------------------------------------------------------------------------------------------------- |
|
|
30
|
+
| `url` | yes | `suitecloud://<account>.app.netsuite.com`. No path, port, or credentials. |
|
|
31
|
+
| `body` | yes | JSON string with `operation` and the operation's inputs |
|
|
32
|
+
| `systemId` | yes | The NetSuite system. Its OAuth sign-in is used for the login. |
|
|
33
|
+
| `modify` | tool steps | `false` for reads, `true` for `deploy`. `deploy` changes the live account. `sg system call` has no flag. |
|
|
34
|
+
|
|
35
|
+
`<account>` is the account ID in host form: lowercase, with `_` written as `-` (`1234567_SB1` becomes `1234567-sb1`). It is the same prefix as the host of the system's REST URL.
|
|
36
|
+
|
|
37
|
+
### Login
|
|
38
|
+
|
|
39
|
+
The step logs in with the system's NetSuite OAuth token, the same one the REST steps use. It runs as the user and role that connected NetSuite. The role needs the permissions **Log in using OAuth 2.0 Access Tokens**, **REST Web Services**, and **SuiteCloud Development Framework**; the standard Developer role has them. The integration record needs **REST Web Services** and **RESTlets** checked, and the sign-in needs the scopes `rest_webservices` and `restlets`. Nothing else is stored on the credential.
|
|
40
|
+
|
|
41
|
+
## Operations
|
|
42
|
+
|
|
43
|
+
| Operation | Inputs | Result |
|
|
44
|
+
| --------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
45
|
+
| `listObjects` | optional `objectTypes` (array), `scriptIdContains` | Custom objects in the account: type and script ID |
|
|
46
|
+
| `importObjects` | `objectType`, `scriptIds` (array) | `files`: map of `Objects/<scriptid>.xml` to XML, plus `data.failedImports` |
|
|
47
|
+
| `validate` | `files` | NetSuite's validation of the project. Changes nothing. |
|
|
48
|
+
| `preview` | `files` | The changes a deploy would make. Changes nothing. |
|
|
49
|
+
| `deploy` | `files`, step `modify: true` | Applies the project to the account |
|
|
50
|
+
| `callRestlet` | `scriptId`, `deployId`, optional `method`, `params`, `body` | The JSON response of the RESTlet |
|
|
51
|
+
|
|
52
|
+
A failed operation fails the step with NetSuite's error messages. `importObjects` succeeds as long as NetSuite answers: each object that could not be exported is listed in `data.failedImports` with NetSuite's message, and `files` holds only the exported ones. Objects locked by an installed bundle or SuiteApp fail with "You cannot download the XML file for this object because it is locked", and some workflows fail with "Inconsistent workflow data". `listObjects` does not show which objects are locked; `appId` is `null` for them too. When an import returns no files, pick another object of the same type.
|
|
53
|
+
|
|
54
|
+
## Project Files
|
|
55
|
+
|
|
56
|
+
`files` maps a project path to the file content. Paths are relative and must stay inside the project.
|
|
57
|
+
|
|
58
|
+
| Path | Content |
|
|
59
|
+
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
60
|
+
| `Objects/<scriptid>.xml` | One custom object. The file name must equal the object's `scriptid`. |
|
|
61
|
+
| `FileCabinet/SuiteScripts/<f>` | Script and other File Cabinet files |
|
|
62
|
+
| `manifest.xml` | NetSuite requires it. When you leave it out, the step adds one that declares the features its objects need (see below). |
|
|
63
|
+
| `deploy.xml` | NetSuite requires it. When you leave it out, the step adds Oracle's default: `~/FileCabinet/SuiteScripts/*` and `~/Objects/*`. |
|
|
64
|
+
|
|
65
|
+
In `deploy.xml`, each `path` starts with `~` (the project root), is case-sensitive, and can use `*` for all files in a folder. The element order is `configuration`, `files`, `objects`, and NetSuite processes the paths in sequence. Supply your own `deploy.xml` for files outside `FileCabinet/SuiteScripts/`. A project with files only in other folders fails without one.
|
|
66
|
+
|
|
67
|
+
NetSuite refuses a project whose objects need a feature the manifest does not declare. The default manifest adds `SERVERSIDESCRIPTING` for server script objects (`restlet`, `suitelet`, `usereventscript`, `scheduledscript`, `mapreducescript`, `workflowactionscript`, `massupdatescript`, `portlet`, `bundleinstallationscript`) and `WORKFLOW` for a `workflow`, read from each object's root element. Client scripts and custom record types need no feature. Supply your own `manifest.xml` when validation names another feature:
|
|
68
|
+
|
|
69
|
+
```xml
|
|
70
|
+
<manifest projecttype="ACCOUNTCUSTOMIZATION">
|
|
71
|
+
<projectname>superglue</projectname>
|
|
72
|
+
<frameworkversion>1.0</frameworkversion>
|
|
73
|
+
<dependencies>
|
|
74
|
+
<features>
|
|
75
|
+
<feature required="true">CUSTOMRECORDS</feature>
|
|
76
|
+
</features>
|
|
77
|
+
</dependencies>
|
|
78
|
+
</manifest>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Example object, a date field on customers:
|
|
82
|
+
|
|
83
|
+
```xml
|
|
84
|
+
<entitycustomfield scriptid="custentity_sg_contract_end">
|
|
85
|
+
<label>Contract End Date</label>
|
|
86
|
+
<fieldtype>DATE</fieldtype>
|
|
87
|
+
<appliestocustomer>T</appliestocustomer>
|
|
88
|
+
<storevalue>T</storevalue>
|
|
89
|
+
</entitycustomfield>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Each object type has a fixed script ID prefix, for example `custentity_` (entity field), `custbody_` (transaction body field), `custcol_` (transaction line field), `custitem_` (item field), `customrecord_` (record type), `custrecord_` (field on a custom record type), `customlist_` (list), `customsearch_` (saved search), `customworkflow_` (workflow), `customscript_` (script), `customdeploy_` (script deployment). Oracle's XML reference lists every type and field: https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/SDFxml.html
|
|
93
|
+
|
|
94
|
+
## Workflow
|
|
95
|
+
|
|
96
|
+
1. `listObjects` to see what exists.
|
|
97
|
+
2. `importObjects` for one existing object of the type you need. Use its XML as the pattern. Do not write an unfamiliar object type from memory.
|
|
98
|
+
3. Write the files and run `validate`. Fix every error and repeat.
|
|
99
|
+
4. Run `preview` and show the user the planned changes.
|
|
100
|
+
5. Run `deploy`. In a saved tool, set `modify: true` on the step.
|
|
101
|
+
6. Verify the result with SuiteQL or `listObjects`.
|
|
102
|
+
|
|
103
|
+
## Workflow Objects
|
|
104
|
+
|
|
105
|
+
Source: Oracle's SDF XML reference for the `workflow` object (https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/SDFxml_2086367724.html) and "Workflows as XML Definitions". Full example: https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_1506974279.html
|
|
106
|
+
|
|
107
|
+
A workflow (SuiteFlow) is one file, `Objects/customworkflow_<name>.xml`, with the root element `<workflow scriptid="customworkflow_<name>">`. A `scriptid` can have up to 40 characters. The object depends on the `WORKFLOW` feature, and the SuiteFlow feature must be on in the account. When a value needs a feature that the manifest does not list, the validation log names the feature.
|
|
108
|
+
|
|
109
|
+
| Field | Required | Values and default |
|
|
110
|
+
| --------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
111
|
+
| `name` | yes | |
|
|
112
|
+
| `recordtypes` | yes | Standard record type, `[scriptid=customrecord_x]`, or a custom transaction type. Separate several values with a pipe. |
|
|
113
|
+
| `releasestatus` | no | `NOTINITIATING` (default), `TESTING`, `RELEASED`, `SUSPENDED`. `NOTRUNNING` is the old name of `NOTINITIATING`. |
|
|
114
|
+
| `keephistory` | no | `ONLYWHENTESTING` (default), `ALWAYS`, `NEVER` |
|
|
115
|
+
| `initoncreate`, `initonvieworupdate` | no | `T` or `F` (default) |
|
|
116
|
+
| `inittriggertype` | no | `BEFORELOAD`, `BEFORESUBMIT`, `AFTERSUBMIT` |
|
|
117
|
+
| `initsavedsearchcondition`, `initsavedsearchfilter` | no | Saved search reference |
|
|
118
|
+
| `isinactive`, `islogenabled`, `runasadmin` | no | `T` or `F` (default) |
|
|
119
|
+
| `description`, `initcontexts`, `initeventtypes` | no | |
|
|
120
|
+
|
|
121
|
+
Structured fields of `workflow`: `initcondition`, `recurrence` (for a schedule, with dates and times in UTC and ISO format), `workflowcustomfields`, and `workflowstates`.
|
|
122
|
+
|
|
123
|
+
States hold the logic. This block is shortened from Oracle's example, which lists more fields for each action and transition:
|
|
124
|
+
|
|
125
|
+
```xml
|
|
126
|
+
<workflowstates>
|
|
127
|
+
<workflowstate scriptid="workflowstate_entry">
|
|
128
|
+
<name>State 1: Entry</name>
|
|
129
|
+
<donotexitworkflow>F</donotexitworkflow>
|
|
130
|
+
<workflowactions triggertype="ONENTRY">
|
|
131
|
+
<setfieldvalueaction scriptid="workflowaction_setpendingvalue">
|
|
132
|
+
<field>[scriptid=custbody_approvalstatus]</field>
|
|
133
|
+
<valuetype>STATIC</valuetype>
|
|
134
|
+
</setfieldvalueaction>
|
|
135
|
+
</workflowactions>
|
|
136
|
+
<workflowtransitions>
|
|
137
|
+
<workflowtransition scriptid="workflowtransition_hassupervisor">
|
|
138
|
+
<tostate>[scriptid=customworkflow_approvals.workflowstate_approvalpending]</tostate>
|
|
139
|
+
<triggertype>ONENTRY</triggertype>
|
|
140
|
+
</workflowtransition>
|
|
141
|
+
</workflowtransitions>
|
|
142
|
+
</workflowstate>
|
|
143
|
+
</workflowstates>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
- `workflowstate`: `scriptid` and `name` are required. Optional: `description`, `donotexitworkflow`, `positionx`, `positiony`. Structured fields: `workflowactions`, `workflowstatecustomfields`, `workflowtransitions`.
|
|
147
|
+
- `workflowactions` can occur several times in a state. Its `triggertype` attribute is required: `ONENTRY`, `ONEXIT`, `BEFORELOAD`, `BEFORESUBMIT`, `AFTERSUBMIT`, `SCHEDULED`, `BEFOREUSEREDIT`, `BEFOREFIELDEDIT`, `AFTERFIELDEDIT`, `AFTERFIELDSOURCING`, or `BEFOREUSERSUBMIT`.
|
|
148
|
+
- Action elements: `addbuttonaction`, `removebuttonaction`, `confirmaction`, `showmessageaction`, `returnusererroraction`, `setfieldvalueaction`, `setfieldmandatoryaction`, `setdisplaylabelaction`, `setdisplaytypeaction`, `lockrecordaction`, `createrecordaction`, `createlineaction`, `transformrecordaction`, `gotorecordaction`, `gotopageaction`, `sendemailaction`, `sendcampaignemailaction`, `subscribetorecordaction`, `initiateworkflowaction`, `customaction`. Groups: `workflowactiongroup`, `workflowsublistactiongroup`. Each action needs its own `scriptid`.
|
|
149
|
+
- `workflowtransition`: `scriptid` and `tostate` are required. Optional: `triggertype` (`ONENTRY`, `BEFORELOAD`, `BEFORESUBMIT`, `AFTERSUBMIT`, `SCHEDULED`), `buttonaction` (a reference to an `addbuttonaction`), `conditionsavedsearch`, `contexttypes`, `eventtypes`, `scheduledelay`, `scheduletimeunit`, `waitforworkflow`, `waitforworkflowstate`, and `initcondition`.
|
|
150
|
+
- References use the full script ID path. State: `[scriptid=customworkflow_approvals.workflowstate_approved]`. Button: `[scriptid=customworkflow_approvals.workflowstate_approvalpending.workflowaction_approvebutton]`. Custom field: `[scriptid=custbody_approvalstatus]`. Standard fields use codes such as `STDBODYSALESREP`.
|
|
151
|
+
|
|
152
|
+
Conditions (`initcondition`) have a required `type`, an optional `formula`, and optional `parameters`:
|
|
153
|
+
|
|
154
|
+
- `FORMULA`: the `formula` element holds the text in `CDATA`, for example `<![CDATA[{supervisor} is not null]]>`.
|
|
155
|
+
- `VISUAL_BUILDER`: the formula uses quoted names, and the `parameters` list gives each name a `value`. Each `name` must appear in the formula. Oracle says to build complex conditions in the NetSuite UI and import the workflow, not to write them by hand.
|
|
156
|
+
- To delete a condition, deploy it with an empty `formula`. Removing the `initcondition` block does not delete it in the account.
|
|
157
|
+
- Imported workflows can contain `[ACCOUNT_SPECIFIC_VALUE]`. Replace each one with a valid value before a deploy.
|
|
158
|
+
|
|
159
|
+
Oracle's example deploys three files together: the workflow, the custom list it uses (`customlist_approvalstatuses`), and the transaction body field that uses the list (`custbody_approvalstatus`).
|
|
160
|
+
|
|
161
|
+
## Preferences and Other SuiteScript-Only Changes
|
|
162
|
+
|
|
163
|
+
Some changes need SuiteScript that runs inside NetSuite, for example company and accounting preferences (`N/config`). A deploy cannot make these changes, but it can install the script that does:
|
|
164
|
+
|
|
165
|
+
1. Deploy a RESTlet with a `suitecloud://` deploy. The project needs the script file under `FileCabinet/SuiteScripts/` and a `restlet` object under `Objects/`. The deployment `status` is `TESTING` by default, which runs the script for the script owner and the specified audience. `RELEASED` runs it for all specified audience members. The audience fields include `allroles`, `audslctrole`, and `allemployees`. Deploy with `status` `TESTING` and `allemployees` `T` first and call it; switch to `RELEASED` with an explicit audience after it works. NetSuite can drop audience flags on the first deploy of a script, so import the script object after the deploy and check the stored deployment before you call it. Import an existing RESTlet with `importObjects` and use it as the pattern.
|
|
166
|
+
2. Call the RESTlet with the `callRestlet` operation and the script ID and deployment ID from the project, for example `customscript_sg_prefs` and `customdeploy_sg_prefs`. `method` selects the RESTlet entry point: `POST` (default) and `PUT` send `body` as JSON; `GET` and `DELETE` send `params` as query parameters and take no `body`. `params` is an object of string, number, or boolean values and is added to the URL for every method. An empty or `null` response means the RESTlet has no entry point for that method. A RESTlet has 5,000 governance units per call. NetSuite stops the script with `SSS_USAGE_LIMIT_EXCEEDED` when they run out, so keep each call small and check `runtime.getCurrentScript().getRemainingUsage()` in loops.
|
|
167
|
+
|
|
168
|
+
Read the current value before you change it, and tell the user when a setting cannot be undone.
|
|
169
|
+
|
|
170
|
+
## Common Pitfalls
|
|
171
|
+
|
|
172
|
+
- A deploy adds and updates objects. It never deletes them. Removing an object needs the NetSuite UI.
|
|
173
|
+
- Some changes cannot be undone, for example enabling a feature or changing a field's type after data exists. Tell the user before the deploy.
|
|
174
|
+
- The file name and the `scriptid` attribute must match, and the prefix must fit the object type.
|
|
175
|
+
- A script object needs `name`, `scriptfile`, and `scriptdeployments`. `scriptfile` must be a `.js` file, written as `[/SuiteScripts/<file>.js]`. Each `scriptdeployment` needs `status`; server script deployments also need `title`, which client script deployments ignore. Script IDs start with `customscript_` and deployment IDs with `customdeploy_`. Oracle's RESTlet example: https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_160514060027.html
|
|
176
|
+
- Preferences such as accounting preferences are not project objects. A deploy cannot set them. Use the RESTlet route above.
|
|
177
|
+
- Deploy to a sandbox account first when the user has one.
|
|
178
|
+
- A sandbox refresh removes the sign-in. The user reconnects NetSuite in superglue after each refresh.
|
|
179
|
+
|
|
180
|
+
## Error Recovery
|
|
181
|
+
|
|
182
|
+
1. **"SuiteCloud needs the NetSuite OAuth sign-in"**: the system has no OAuth token. The user connects NetSuite with OAuth first. Link the setup guide https://superglue.ai/docs/guides/netsuite-suitecloud/ and stop.
|
|
183
|
+
2. **401 or "Invalid login attempt"**: the token has expired or the sign-in lacks a scope. NetSuite refresh tokens last seven days, so the user reconnects NetSuite in superglue. If the `restlets` scope is missing, the user reconnects after the scope was added. NetSuite records the failure detail in the Login Audit Trail under **Setup > Users/Roles > User Management > View Login Audit Trail**.
|
|
184
|
+
3. **Validation errors**: read each message. "The manifest must define the X feature as required" means add `<feature required="true">X</feature>` to `manifest.xml`. For other errors, compare the XML with an imported object of the same type.
|
|
185
|
+
4. **Permission errors on validate, preview, or deploy**: report NetSuite's message to the user verbatim.
|
|
186
|
+
5. **`INSUFFICIENT_PERMISSION` from `callRestlet`**: the deployment's audience does not include the connected user and role. Import the script object to see the stored `status` and audience, then redeploy with `status` `TESTING` and `allemployees` `T`.
|
|
187
|
+
6. **429, `CONCURRENCY_LIMIT_EXCEEDED`, or `SSS_REQUEST_LIMIT_EXCEEDED`**: the account's concurrency limit is in use. NetSuite allows 15 concurrent requests by default, shared by REST, SOAP, and RESTlets, and rejects extra requests instead of queuing them. Run NetSuite steps one after another and retry after a short wait.
|
|
188
|
+
7. **`SSS_USAGE_LIMIT_EXCEEDED` from `callRestlet`**: the RESTlet used its 5,000 governance units. Split the work into smaller calls.
|
package/package.json
CHANGED
|
@@ -25,6 +25,7 @@ Read these on demand — they are authoritative for their topic and kept in sync
|
|
|
25
25
|
| `sg skill redis` | Redis command syntax, connection URLs, key type handling |
|
|
26
26
|
| `sg skill mongodb` | MongoDB connection URLs (mongodb:// / mongodb+srv://), CRUD operations, Extended JSON, aggregation |
|
|
27
27
|
| `sg skill sftp-smb` | SFTP, FTP, and SMB operations, file upload/download semantics, path handling |
|
|
28
|
+
| `sg skill suitecloud` | NetSuite SuiteCloud deploys: custom fields, record types, scripts; validate, preview, deploy |
|
|
28
29
|
| `sg skill file-handling` | File detection, parsing, `file::` reference syntax, lazy base64 access, transform-produced files |
|
|
29
30
|
| `sg skill access-rules` | RBAC roles, resource grants, and tool/system permissions (enterprise only) |
|
|
30
31
|
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# SuiteCloud
|
|
2
|
+
|
|
3
|
+
The `suitecloud://` protocol changes NetSuite account structure: custom fields, custom record types, custom lists, forms, workflows, saved searches, roles, and scripts. The NetSuite REST API and SuiteScript cannot create these. It deploys SuiteCloud projects (SDF) to the account. Use it on the NetSuite system, next to its HTTP steps.
|
|
4
|
+
|
|
5
|
+
## Step Configuration
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
{
|
|
9
|
+
type: "request",
|
|
10
|
+
systemId: "netsuite",
|
|
11
|
+
url: "suitecloud://1234567-sb1.app.netsuite.com",
|
|
12
|
+
body: '{"operation": "validate", "files": {"Objects/custentity_sg_contract_end.xml": "<entitycustomfield ...>"}}'
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`method`, `headers`, `queryParams`, and `pagination` are HTTP-only fields. Omit them.
|
|
17
|
+
|
|
18
|
+
Every operation also runs as a single call:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
sg system call --system-id netsuite \
|
|
22
|
+
--url "suitecloud://1234567-sb1.app.netsuite.com" \
|
|
23
|
+
--body '{"operation": "listObjects", "objectTypes": ["entitycustomfield"]}'
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Fields
|
|
27
|
+
|
|
28
|
+
| Field | Required | Notes |
|
|
29
|
+
| ---------- | ---------- | -------------------------------------------------------------------------------------------------------- |
|
|
30
|
+
| `url` | yes | `suitecloud://<account>.app.netsuite.com`. No path, port, or credentials. |
|
|
31
|
+
| `body` | yes | JSON string with `operation` and the operation's inputs |
|
|
32
|
+
| `systemId` | yes | The NetSuite system. Its OAuth sign-in is used for the login. |
|
|
33
|
+
| `modify` | tool steps | `false` for reads, `true` for `deploy`. `deploy` changes the live account. `sg system call` has no flag. |
|
|
34
|
+
|
|
35
|
+
`<account>` is the account ID in host form: lowercase, with `_` written as `-` (`1234567_SB1` becomes `1234567-sb1`). It is the same prefix as the host of the system's REST URL.
|
|
36
|
+
|
|
37
|
+
### Login
|
|
38
|
+
|
|
39
|
+
The step logs in with the system's NetSuite OAuth token, the same one the REST steps use. It runs as the user and role that connected NetSuite. The role needs the permissions **Log in using OAuth 2.0 Access Tokens**, **REST Web Services**, and **SuiteCloud Development Framework**; the standard Developer role has them. The integration record needs **REST Web Services** and **RESTlets** checked, and the sign-in needs the scopes `rest_webservices` and `restlets`. Nothing else is stored on the credential.
|
|
40
|
+
|
|
41
|
+
## Operations
|
|
42
|
+
|
|
43
|
+
| Operation | Inputs | Result |
|
|
44
|
+
| --------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
45
|
+
| `listObjects` | optional `objectTypes` (array), `scriptIdContains` | Custom objects in the account: type and script ID |
|
|
46
|
+
| `importObjects` | `objectType`, `scriptIds` (array) | `files`: map of `Objects/<scriptid>.xml` to XML, plus `data.failedImports` |
|
|
47
|
+
| `validate` | `files` | NetSuite's validation of the project. Changes nothing. |
|
|
48
|
+
| `preview` | `files` | The changes a deploy would make. Changes nothing. |
|
|
49
|
+
| `deploy` | `files`, step `modify: true` | Applies the project to the account |
|
|
50
|
+
| `callRestlet` | `scriptId`, `deployId`, optional `method`, `params`, `body` | The JSON response of the RESTlet |
|
|
51
|
+
|
|
52
|
+
A failed operation fails the step with NetSuite's error messages. `importObjects` succeeds as long as NetSuite answers: each object that could not be exported is listed in `data.failedImports` with NetSuite's message, and `files` holds only the exported ones. Objects locked by an installed bundle or SuiteApp fail with "You cannot download the XML file for this object because it is locked", and some workflows fail with "Inconsistent workflow data". `listObjects` does not show which objects are locked; `appId` is `null` for them too. When an import returns no files, pick another object of the same type.
|
|
53
|
+
|
|
54
|
+
## Project Files
|
|
55
|
+
|
|
56
|
+
`files` maps a project path to the file content. Paths are relative and must stay inside the project.
|
|
57
|
+
|
|
58
|
+
| Path | Content |
|
|
59
|
+
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
60
|
+
| `Objects/<scriptid>.xml` | One custom object. The file name must equal the object's `scriptid`. |
|
|
61
|
+
| `FileCabinet/SuiteScripts/<f>` | Script and other File Cabinet files |
|
|
62
|
+
| `manifest.xml` | NetSuite requires it. When you leave it out, the step adds one that declares the features its objects need (see below). |
|
|
63
|
+
| `deploy.xml` | NetSuite requires it. When you leave it out, the step adds Oracle's default: `~/FileCabinet/SuiteScripts/*` and `~/Objects/*`. |
|
|
64
|
+
|
|
65
|
+
In `deploy.xml`, each `path` starts with `~` (the project root), is case-sensitive, and can use `*` for all files in a folder. The element order is `configuration`, `files`, `objects`, and NetSuite processes the paths in sequence. Supply your own `deploy.xml` for files outside `FileCabinet/SuiteScripts/`. A project with files only in other folders fails without one.
|
|
66
|
+
|
|
67
|
+
NetSuite refuses a project whose objects need a feature the manifest does not declare. The default manifest adds `SERVERSIDESCRIPTING` for server script objects (`restlet`, `suitelet`, `usereventscript`, `scheduledscript`, `mapreducescript`, `workflowactionscript`, `massupdatescript`, `portlet`, `bundleinstallationscript`) and `WORKFLOW` for a `workflow`, read from each object's root element. Client scripts and custom record types need no feature. Supply your own `manifest.xml` when validation names another feature:
|
|
68
|
+
|
|
69
|
+
```xml
|
|
70
|
+
<manifest projecttype="ACCOUNTCUSTOMIZATION">
|
|
71
|
+
<projectname>superglue</projectname>
|
|
72
|
+
<frameworkversion>1.0</frameworkversion>
|
|
73
|
+
<dependencies>
|
|
74
|
+
<features>
|
|
75
|
+
<feature required="true">CUSTOMRECORDS</feature>
|
|
76
|
+
</features>
|
|
77
|
+
</dependencies>
|
|
78
|
+
</manifest>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Example object, a date field on customers:
|
|
82
|
+
|
|
83
|
+
```xml
|
|
84
|
+
<entitycustomfield scriptid="custentity_sg_contract_end">
|
|
85
|
+
<label>Contract End Date</label>
|
|
86
|
+
<fieldtype>DATE</fieldtype>
|
|
87
|
+
<appliestocustomer>T</appliestocustomer>
|
|
88
|
+
<storevalue>T</storevalue>
|
|
89
|
+
</entitycustomfield>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Each object type has a fixed script ID prefix, for example `custentity_` (entity field), `custbody_` (transaction body field), `custcol_` (transaction line field), `custitem_` (item field), `customrecord_` (record type), `custrecord_` (field on a custom record type), `customlist_` (list), `customsearch_` (saved search), `customworkflow_` (workflow), `customscript_` (script), `customdeploy_` (script deployment). Oracle's XML reference lists every type and field: https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/SDFxml.html
|
|
93
|
+
|
|
94
|
+
## Workflow
|
|
95
|
+
|
|
96
|
+
1. `listObjects` to see what exists.
|
|
97
|
+
2. `importObjects` for one existing object of the type you need. Use its XML as the pattern. Do not write an unfamiliar object type from memory.
|
|
98
|
+
3. Write the files and run `validate`. Fix every error and repeat.
|
|
99
|
+
4. Run `preview` and show the user the planned changes.
|
|
100
|
+
5. Run `deploy`. In a saved tool, set `modify: true` on the step.
|
|
101
|
+
6. Verify the result with SuiteQL or `listObjects`.
|
|
102
|
+
|
|
103
|
+
## Workflow Objects
|
|
104
|
+
|
|
105
|
+
Source: Oracle's SDF XML reference for the `workflow` object (https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/SDFxml_2086367724.html) and "Workflows as XML Definitions". Full example: https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_1506974279.html
|
|
106
|
+
|
|
107
|
+
A workflow (SuiteFlow) is one file, `Objects/customworkflow_<name>.xml`, with the root element `<workflow scriptid="customworkflow_<name>">`. A `scriptid` can have up to 40 characters. The object depends on the `WORKFLOW` feature, and the SuiteFlow feature must be on in the account. When a value needs a feature that the manifest does not list, the validation log names the feature.
|
|
108
|
+
|
|
109
|
+
| Field | Required | Values and default |
|
|
110
|
+
| --------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
111
|
+
| `name` | yes | |
|
|
112
|
+
| `recordtypes` | yes | Standard record type, `[scriptid=customrecord_x]`, or a custom transaction type. Separate several values with a pipe. |
|
|
113
|
+
| `releasestatus` | no | `NOTINITIATING` (default), `TESTING`, `RELEASED`, `SUSPENDED`. `NOTRUNNING` is the old name of `NOTINITIATING`. |
|
|
114
|
+
| `keephistory` | no | `ONLYWHENTESTING` (default), `ALWAYS`, `NEVER` |
|
|
115
|
+
| `initoncreate`, `initonvieworupdate` | no | `T` or `F` (default) |
|
|
116
|
+
| `inittriggertype` | no | `BEFORELOAD`, `BEFORESUBMIT`, `AFTERSUBMIT` |
|
|
117
|
+
| `initsavedsearchcondition`, `initsavedsearchfilter` | no | Saved search reference |
|
|
118
|
+
| `isinactive`, `islogenabled`, `runasadmin` | no | `T` or `F` (default) |
|
|
119
|
+
| `description`, `initcontexts`, `initeventtypes` | no | |
|
|
120
|
+
|
|
121
|
+
Structured fields of `workflow`: `initcondition`, `recurrence` (for a schedule, with dates and times in UTC and ISO format), `workflowcustomfields`, and `workflowstates`.
|
|
122
|
+
|
|
123
|
+
States hold the logic. This block is shortened from Oracle's example, which lists more fields for each action and transition:
|
|
124
|
+
|
|
125
|
+
```xml
|
|
126
|
+
<workflowstates>
|
|
127
|
+
<workflowstate scriptid="workflowstate_entry">
|
|
128
|
+
<name>State 1: Entry</name>
|
|
129
|
+
<donotexitworkflow>F</donotexitworkflow>
|
|
130
|
+
<workflowactions triggertype="ONENTRY">
|
|
131
|
+
<setfieldvalueaction scriptid="workflowaction_setpendingvalue">
|
|
132
|
+
<field>[scriptid=custbody_approvalstatus]</field>
|
|
133
|
+
<valuetype>STATIC</valuetype>
|
|
134
|
+
</setfieldvalueaction>
|
|
135
|
+
</workflowactions>
|
|
136
|
+
<workflowtransitions>
|
|
137
|
+
<workflowtransition scriptid="workflowtransition_hassupervisor">
|
|
138
|
+
<tostate>[scriptid=customworkflow_approvals.workflowstate_approvalpending]</tostate>
|
|
139
|
+
<triggertype>ONENTRY</triggertype>
|
|
140
|
+
</workflowtransition>
|
|
141
|
+
</workflowtransitions>
|
|
142
|
+
</workflowstate>
|
|
143
|
+
</workflowstates>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
- `workflowstate`: `scriptid` and `name` are required. Optional: `description`, `donotexitworkflow`, `positionx`, `positiony`. Structured fields: `workflowactions`, `workflowstatecustomfields`, `workflowtransitions`.
|
|
147
|
+
- `workflowactions` can occur several times in a state. Its `triggertype` attribute is required: `ONENTRY`, `ONEXIT`, `BEFORELOAD`, `BEFORESUBMIT`, `AFTERSUBMIT`, `SCHEDULED`, `BEFOREUSEREDIT`, `BEFOREFIELDEDIT`, `AFTERFIELDEDIT`, `AFTERFIELDSOURCING`, or `BEFOREUSERSUBMIT`.
|
|
148
|
+
- Action elements: `addbuttonaction`, `removebuttonaction`, `confirmaction`, `showmessageaction`, `returnusererroraction`, `setfieldvalueaction`, `setfieldmandatoryaction`, `setdisplaylabelaction`, `setdisplaytypeaction`, `lockrecordaction`, `createrecordaction`, `createlineaction`, `transformrecordaction`, `gotorecordaction`, `gotopageaction`, `sendemailaction`, `sendcampaignemailaction`, `subscribetorecordaction`, `initiateworkflowaction`, `customaction`. Groups: `workflowactiongroup`, `workflowsublistactiongroup`. Each action needs its own `scriptid`.
|
|
149
|
+
- `workflowtransition`: `scriptid` and `tostate` are required. Optional: `triggertype` (`ONENTRY`, `BEFORELOAD`, `BEFORESUBMIT`, `AFTERSUBMIT`, `SCHEDULED`), `buttonaction` (a reference to an `addbuttonaction`), `conditionsavedsearch`, `contexttypes`, `eventtypes`, `scheduledelay`, `scheduletimeunit`, `waitforworkflow`, `waitforworkflowstate`, and `initcondition`.
|
|
150
|
+
- References use the full script ID path. State: `[scriptid=customworkflow_approvals.workflowstate_approved]`. Button: `[scriptid=customworkflow_approvals.workflowstate_approvalpending.workflowaction_approvebutton]`. Custom field: `[scriptid=custbody_approvalstatus]`. Standard fields use codes such as `STDBODYSALESREP`.
|
|
151
|
+
|
|
152
|
+
Conditions (`initcondition`) have a required `type`, an optional `formula`, and optional `parameters`:
|
|
153
|
+
|
|
154
|
+
- `FORMULA`: the `formula` element holds the text in `CDATA`, for example `<![CDATA[{supervisor} is not null]]>`.
|
|
155
|
+
- `VISUAL_BUILDER`: the formula uses quoted names, and the `parameters` list gives each name a `value`. Each `name` must appear in the formula. Oracle says to build complex conditions in the NetSuite UI and import the workflow, not to write them by hand.
|
|
156
|
+
- To delete a condition, deploy it with an empty `formula`. Removing the `initcondition` block does not delete it in the account.
|
|
157
|
+
- Imported workflows can contain `[ACCOUNT_SPECIFIC_VALUE]`. Replace each one with a valid value before a deploy.
|
|
158
|
+
|
|
159
|
+
Oracle's example deploys three files together: the workflow, the custom list it uses (`customlist_approvalstatuses`), and the transaction body field that uses the list (`custbody_approvalstatus`).
|
|
160
|
+
|
|
161
|
+
## Preferences and Other SuiteScript-Only Changes
|
|
162
|
+
|
|
163
|
+
Some changes need SuiteScript that runs inside NetSuite, for example company and accounting preferences (`N/config`). A deploy cannot make these changes, but it can install the script that does:
|
|
164
|
+
|
|
165
|
+
1. Deploy a RESTlet with a `suitecloud://` deploy. The project needs the script file under `FileCabinet/SuiteScripts/` and a `restlet` object under `Objects/`. The deployment `status` is `TESTING` by default, which runs the script for the script owner and the specified audience. `RELEASED` runs it for all specified audience members. The audience fields include `allroles`, `audslctrole`, and `allemployees`. Deploy with `status` `TESTING` and `allemployees` `T` first and call it; switch to `RELEASED` with an explicit audience after it works. NetSuite can drop audience flags on the first deploy of a script, so import the script object after the deploy and check the stored deployment before you call it. Import an existing RESTlet with `importObjects` and use it as the pattern.
|
|
166
|
+
2. Call the RESTlet with the `callRestlet` operation and the script ID and deployment ID from the project, for example `customscript_sg_prefs` and `customdeploy_sg_prefs`. `method` selects the RESTlet entry point: `POST` (default) and `PUT` send `body` as JSON; `GET` and `DELETE` send `params` as query parameters and take no `body`. `params` is an object of string, number, or boolean values and is added to the URL for every method. An empty or `null` response means the RESTlet has no entry point for that method. A RESTlet has 5,000 governance units per call. NetSuite stops the script with `SSS_USAGE_LIMIT_EXCEEDED` when they run out, so keep each call small and check `runtime.getCurrentScript().getRemainingUsage()` in loops.
|
|
167
|
+
|
|
168
|
+
Read the current value before you change it, and tell the user when a setting cannot be undone.
|
|
169
|
+
|
|
170
|
+
## Common Pitfalls
|
|
171
|
+
|
|
172
|
+
- A deploy adds and updates objects. It never deletes them. Removing an object needs the NetSuite UI.
|
|
173
|
+
- Some changes cannot be undone, for example enabling a feature or changing a field's type after data exists. Tell the user before the deploy.
|
|
174
|
+
- The file name and the `scriptid` attribute must match, and the prefix must fit the object type.
|
|
175
|
+
- A script object needs `name`, `scriptfile`, and `scriptdeployments`. `scriptfile` must be a `.js` file, written as `[/SuiteScripts/<file>.js]`. Each `scriptdeployment` needs `status`; server script deployments also need `title`, which client script deployments ignore. Script IDs start with `customscript_` and deployment IDs with `customdeploy_`. Oracle's RESTlet example: https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_160514060027.html
|
|
176
|
+
- Preferences such as accounting preferences are not project objects. A deploy cannot set them. Use the RESTlet route above.
|
|
177
|
+
- Deploy to a sandbox account first when the user has one.
|
|
178
|
+
- A sandbox refresh removes the sign-in. The user reconnects NetSuite in superglue after each refresh.
|
|
179
|
+
|
|
180
|
+
## Error Recovery
|
|
181
|
+
|
|
182
|
+
1. **"SuiteCloud needs the NetSuite OAuth sign-in"**: the system has no OAuth token. The user connects NetSuite with OAuth first. Link the setup guide https://superglue.ai/docs/guides/netsuite-suitecloud/ and stop.
|
|
183
|
+
2. **401 or "Invalid login attempt"**: the token has expired or the sign-in lacks a scope. NetSuite refresh tokens last seven days, so the user reconnects NetSuite in superglue. If the `restlets` scope is missing, the user reconnects after the scope was added. NetSuite records the failure detail in the Login Audit Trail under **Setup > Users/Roles > User Management > View Login Audit Trail**.
|
|
184
|
+
3. **Validation errors**: read each message. "The manifest must define the X feature as required" means add `<feature required="true">X</feature>` to `manifest.xml`. For other errors, compare the XML with an imported object of the same type.
|
|
185
|
+
4. **Permission errors on validate, preview, or deploy**: report NetSuite's message to the user verbatim.
|
|
186
|
+
5. **`INSUFFICIENT_PERMISSION` from `callRestlet`**: the deployment's audience does not include the connected user and role. Import the script object to see the stored `status` and audience, then redeploy with `status` `TESTING` and `allemployees` `T`.
|
|
187
|
+
6. **429, `CONCURRENCY_LIMIT_EXCEEDED`, or `SSS_REQUEST_LIMIT_EXCEEDED`**: the account's concurrency limit is in use. NetSuite allows 15 concurrent requests by default, shared by REST, SOAP, and RESTlets, and rejects extra requests instead of queuing them. Run NetSuite steps one after another and retry after a short wait.
|
|
188
|
+
7. **`SSS_USAGE_LIMIT_EXCEEDED` from `callRestlet`**: the RESTlet used its 5,000 governance units. Split the work into smaller calls.
|