💼 Business Problem
As projects mature, completed project tasks often remain open, and projects themselves stay active even after all tasks are finished. This causes:
- Inaccurate project dashboards and resource reports
- Overstated “active project” counts
- Time or expenses accidentally booked to closed work
Managing projects in NetSuite can get messy when tasks and jobs remain open long after completion. This SuiteScript 2.1 example shows how to automatically close completed projects and tasks, helping your PMO maintain clean dashboards, improve reporting accuracy, and prevent accidental time entry on finished work. It’s one of the simplest yet most impactful NetSuite automations you can deploy for project management efficiency.
Goal:
Automatically identify and close:
- Tasks with status “Completed” but not marked “Closed”
- Projects where all tasks are closed and 100% complete
🧠 Approach
We’ll use a Scheduled Script (or Map/Reduce for large accounts) that:
- Searches for Project Tasks with Status = Completed and not Closed → sets Status = Closed.
- For each Project, checks if all tasks are closed; if yes → sets Project Status = Closed.
- Runs nightly (or weekly).
- Optionally emails a summary to the PMO team.
This approach ensures your Project module remains clean without manual maintenance.
🔧 Saved Search Setup
1️⃣ Project Task Search — “Completed Not Closed”
Type: Project Task
Criteria:
- Status = Completed
- % Complete = 100
- Is Closed = F
Results: Internal ID, Project, Status, % Complete
ID Example: customsearch_tasks_completed_notclosed
2️⃣ Project Search (optional)
If you’d like to close the Project automatically, the script can find all related tasks using the Project internal ID.
🧩 SuiteScript 2.1 — Scheduled Script
/**
* @NApiVersion 2.1
* @NScriptType ScheduledScript
* Title: SCH | Auto-Close Completed Projects & Tasks
* Author: The NetSuite Pro
*/
define(['N/search','N/record','N/log','N/runtime','N/email'], (search, record, log, runtime, email) => {
const TASK_SEARCH_ID = 'customsearch_tasks_completed_notclosed';
function execute() {
try {
const closedTasks = autoCloseTasks();
const closedProjects = autoCloseProjects(closedTasks);
// Optional summary email
const summary = `
<h3>Auto-Close Summary</h3>
<p>Closed Tasks: ${closedTasks.length}</p>
<p>Closed Projects: ${closedProjects.length}</p>
`;
email.send({
author: runtime.getCurrentUser().id,
recipients: 'pmo@yourcompany.com',
subject: 'NetSuite Project Auto-Close Summary',
body: summary
});
} catch (e) {
log.error('Execution Error', e);
}
}
function autoCloseTasks() {
const ids = [];
const s = search.load({ id: TASK_SEARCH_ID });
s.run().each(r => {
const id = r.getValue('internalid');
const proj = r.getValue('project');
try {
record.submitFields({
type: 'projecttask',
id,
values: { status: 'CLOSED' },
options: { enableSourcing: false, ignoreMandatoryFields: true }
});
ids.push({ taskId: id, projectId: proj });
} catch (e) {
log.error(`Failed closing task ${id}`, e);
}
return true;
});
return ids;
}
function autoCloseProjects(closedTasks) {
const closedProjects = [];
const uniqueProjects = [...new Set(closedTasks.map(t => t.projectId).filter(Boolean))];
uniqueProjects.forEach(projId => {
try {
if (allTasksClosed(projId)) {
record.submitFields({
type: 'job', // project record type
id: projId,
values: { entitystatus: 'CLOSED' }, // or your internal ID for “Closed”
options: { enableSourcing: false, ignoreMandatoryFields: true }
});
closedProjects.push(projId);
}
} catch (e) {
log.error(`Failed closing project ${projId}`, e);
}
});
return closedProjects;
}
function allTasksClosed(projectId) {
const taskSearch = search.create({
type: 'projecttask',
filters: [['project','anyof',projectId],'AND',['status','noneof',['CLOSED']]],
columns: ['internalid']
});
const result = taskSearch.runPaged({ pageSize: 1 }).count;
return result === 0;
}
return { execute };
});
✅ Testing Checklist
- Create a few Project Tasks with status = Completed (not closed).
- Create a Project with all tasks at 100% complete.
- Run the Scheduled Script manually → tasks and projects should now show as Closed.
- Check the summary email to confirm counts.
- Verify that users can no longer log time or expenses to closed tasks.
🧩 Optional Enhancements
| Enhancement | Description |
|---|---|
| Email per project | Notify Project Manager when their project is closed. |
| Auto-Archive Files | Move completed project files to an archive folder. |
| Add SuiteAnalytics report | Track how many projects auto-closed monthly. |
| Include % complete logic | Only close projects with 100% progress. |
| Auto-flag stale tasks | Add logic to close tasks older than X days in “Completed” status. |
📌 Summary
| Goal | Result |
|---|---|
| Automatically close completed tasks & projects | ✅ Clean dashboards |
| Prevent time/expense on finished work | ✅ Improved accuracy |
| Reduce manual PMO cleanup | ✅ Fully automated nightly run |