Time: 30 minutes | Level: Some SuiteScript helps
You will learn: How to post a short morning summary to Slack on a schedule.
You will need: A sandbox and a webhook for the channel that should get the digest.
Alerts tell you when something happens. A digest tells you where things stand. A short summary posted every morning gives the whole team the same picture before the day starts. It also replaces the “does anyone know how many orders are still open?” question.
What we are building
A message like this, posted to #finance-daily at 7:30 every weekday morning:
Good morning! Your NetSuite snapshot
Overdue invoices: 14 totalling $38,420.00
Sales orders waiting for approval: 6
Open purchase orders past their due date: 3
How it works
- A Scheduled Script runs at the time you choose.
- It runs a few searches and adds up the results.
- It builds a message and posts it to a Slack webhook.
The script
/**
* @NApiVersion 2.1
* @NScriptType ScheduledScript
*
* Posts a daily NetSuite snapshot to Slack.
*/
define(['N/search', 'N/https', 'N/runtime', 'N/log'],
(search, https, runtime, log) => {
// Count and total overdue invoices.
const overdueInvoices = () => {
const s = search.create({
type: search.Type.INVOICE,
filters: [
['mainline', 'is', 'T'], 'AND',
['status', 'anyof', 'CustInvc:A'], 'AND', // Open
['duedate', 'before', 'today']
],
columns: [
search.createColumn({ name: 'internalid', summary: search.Summary.COUNT }),
search.createColumn({ name: 'amountremaining', summary: search.Summary.SUM })
]
});
const row = s.run().getRange({ start: 0, end: 1 })[0];
return {
count: Number(row.getValue({ name: 'internalid', summary: search.Summary.COUNT })) || 0,
total: Number(row.getValue({ name: 'amountremaining', summary: search.Summary.SUM })) || 0
};
};
// Count sales orders that are pending approval.
const ordersPendingApproval = () => {
const s = search.create({
type: search.Type.SALES_ORDER,
filters: [
['mainline', 'is', 'T'], 'AND',
['status', 'anyof', 'SalesOrd:A'] // Pending Approval
],
columns: [ search.createColumn({ name: 'internalid', summary: search.Summary.COUNT }) ]
});
const row = s.run().getRange({ start: 0, end: 1 })[0];
return Number(row.getValue({ name: 'internalid', summary: search.Summary.COUNT })) || 0;
};
const execute = () => {
try {
const webhookUrl = runtime.getCurrentScript().getParameter({ name: 'custscript_slack_digest_webhook' });
if (!webhookUrl) { log.error('Digest skipped', 'No webhook URL set'); return; }
const inv = overdueInvoices();
const orders = ordersPendingApproval();
const money = (n) => '$' + n.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
const payload = {
text: 'Your NetSuite snapshot',
blocks: [
{ type: 'header', text: { type: 'plain_text', text: 'Good morning! Your NetSuite snapshot' } },
{
type: 'section',
fields: [
{ type: 'mrkdwn', text: '*Overdue invoices*\n' + inv.count + ' totalling ' + money(inv.total) },
{ type: 'mrkdwn', text: '*Orders waiting for approval*\n' + orders }
]
},
{ type: 'context', elements: [ { type: 'mrkdwn', text: 'Posted automatically by NetSuite' } ] }
]
};
const res = https.post({
url: webhookUrl,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (res.code !== 200) log.error('Digest failed', res.code + ' ' + res.body);
} catch (e) {
log.error('Digest error', e.name + ': ' + e.message);
}
};
return { execute };
});
The status codes CustInvc:A (open invoice) and SalesOrd:A (pending approval) are standard search values. Account settings such as approval routing can change which statuses apply, so confirm them in a saved search in your own account first.
Deploy and schedule it
- Upload the file and create a Scheduled Script record.
- Add a script parameter
custscript_slack_digest_webhook(Free-Form Text) for the webhook URL. - Create a deployment. On the Schedule subtab, choose Single Event or Daily Event, set the start time (for example 7:30 AM), and repeat every day.
- To skip weekends, choose Weekly and tick Monday to Friday.
- Set Status to Scheduled for it to run automatically (or Not Scheduled if you want to run it manually while testing).
- Use Save & Execute to run it once immediately and check Slack.
Schedules run in the time zone set for the deployment or account, so double-check the time you actually get.
Tips for a good digest
- Keep it short. Three to six numbers is plenty. People stop reading long digests.
- Show what needs action, not everything. “6 orders waiting for approval” is useful; “1,842 total orders” is not.
- Add links. A button that opens the matching saved search turns a number into a next step.
- Highlight problems. You might add a red circle emoji when overdue amounts pass a threshold.
- Use several digests for several audiences. Finance, warehouse and sales each want different numbers in their own channels.
Bigger volumes
Searches with thousands of rows need more care than a summary search. For long lists, use a saved search with runPaged or a Map/Reduce script, and post only the top ten with a link to the full list.
What is next
You now have alerts, approvals, lookups and digests. Let us zoom out for a list of practical ways Slack streamlines NetSuite processes.