Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer peopleโ€™s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer peopleโ€™s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The NetSuite Pro

The NetSuite Pro Logo The NetSuite Pro Logo

The NetSuite Pro Navigation

  • Home
  • About Us
  • Tutorials
    • NetSuite Scripting
    • NetSuite Customization
    • NetSuite Integration
    • NetSuite Advanced PDF Templates
    • NetSuite Reporting & Analytics Guide
    • Real-World NetSuite Examples
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask A Question
  • Home
  • About Us
  • Tutorials
    • NetSuite Scripting
    • NetSuite Customization
    • NetSuite Integration
    • NetSuite Advanced PDF Templates
    • NetSuite Reporting & Analytics Guide
    • Real-World NetSuite Examples
  • Blog
  • Contact Us
Home/ Real-World NetSuite Examples/Auto-Creating Purchase Orders from Sales Orders

Auto-Creating Purchase Orders from Sales Orders

๐Ÿ’ผ Business problem

Many distribution or drop-ship companies handle hundreds of customer orders per day. Each time an SO is approved, the purchasing team must manually create matching POs for vendors.
This is repetitive, error-prone, and slows fulfillment.

Goal:
Automatically create one or more POs from each qualifying SO, grouped by vendor and subsidiary.


๐Ÿง  Approach overview

When to run:

  • Nightly or hourly Map/Reduce script
  • Optional User Event (beforeSubmit or afterSubmit) for real-time generation

How it works:

  1. Fetch all Sales Orders where:
    • Status = Pending Fulfillment or Approved
    • Custom checkbox โ€œPO Createdโ€ = false
  2. For each order:
    • Loop through item lines
    • Group by vendor
    • Build one PO per vendor
    • Link PO to SO via createdfrom or a custom field
    • Mark โ€œPO Createdโ€ = true to prevent duplicates

๐Ÿงพ Prerequisites

ComponentDetails
Custom Fieldcustbody_po_created (Checkbox, default = F)
Saved Searchcustomsearch_so_pending_po
Filters: Type = Sales Order Status = Pending Fulfillment custbody_po_created = F
PermissionsScript Deployment role needs Create/Edit for Purchase Order and Sales Order

๐Ÿงฉ Map/Reduce Script (SuiteScript 2.1)

/**
 * @NApiVersion 2.1
 * @NScriptType MapReduceScript
 * Title: MR | Auto-Create POs from Sales Orders
 * Author: The NetSuite Pro
 */
define(['N/search','N/record','N/log'], (search, record, log) => {

  const SEARCH_ID = 'customsearch_so_pending_po';
  const FIELD_PO_CREATED = 'custbody_po_created';

  const getInputData = () => search.load({ id: SEARCH_ID });

  const map = ctx => {
    const soId = JSON.parse(ctx.value).id;
    ctx.write({ key: soId, value: soId });
  };

  const reduce = ctx => {
    const soId = ctx.key;
    try {
      const so = record.load({ type: record.Type.SALES_ORDER, id: soId });
      const subsidiary = so.getValue('subsidiary');
      const entity = so.getValue('entity');

      // Collect lines by vendor
      const vendorMap = {};
      const lineCount = so.getLineCount('item');

      for (let i = 0; i < lineCount; i++) {
        const itemId = so.getSublistValue({ sublistId:'item', fieldId:'item', line:i });
        const qty = so.getSublistValue({ sublistId:'item', fieldId:'quantity', line:i });
        const rate = so.getSublistValue({ sublistId:'item', fieldId:'rate', line:i });
        const vendor = so.getSublistValue({ sublistId:'item', fieldId:'povendor', line:i }); // built-in vendor mapping field

        if (!vendor) continue;
        if (!vendorMap[vendor]) vendorMap[vendor] = [];
        vendorMap[vendor].push({ itemId, qty, rate });
      }

      Object.keys(vendorMap).forEach(vendorId => {
        const po = record.create({
          type: record.Type.PURCHASE_ORDER,
          isDynamic: true
        });
        po.setValue('entity', vendorId);
        po.setValue('subsidiary', subsidiary);
        po.setValue('custbody_linked_salesorder', soId); // optional custom field

        vendorMap[vendorId].forEach(line => {
          po.selectNewLine({ sublistId: 'item' });
          po.setCurrentSublistValue({ sublistId:'item', fieldId:'item', value:line.itemId });
          po.setCurrentSublistValue({ sublistId:'item', fieldId:'quantity', value:line.qty });
          po.setCurrentSublistValue({ sublistId:'item', fieldId:'rate', value:line.rate });
          po.commitLine({ sublistId:'item' });
        });

        const poId = po.save({ enableSourcing:true, ignoreMandatoryFields:false });
        log.audit('PO Created', { vendorId, poId, soId });
      });

      // Flag SO as processed
      record.submitFields({
        type: record.Type.SALES_ORDER,
        id: soId,
        values: { [FIELD_PO_CREATED]: true }
      });

    } catch (e) {
      log.error(`SO ${soId} failed`, e);
    }
  };

  const summarize = summary => {
    log.audit('Auto-PO Summary', {
      usage: summary.usage,
      yields: summary.yields,
      concurrency: summary.concurrency
    });
  };

  return { getInputData, map, reduce, summarize };
});

๐Ÿงฎ Deployment Parameters

ParameterDescriptionExample
Saved Search IDWhich SO search to usecustomsearch_so_pending_po
Subsidiary FilterOptional if multi-sub account2
Log Only ModeDry run without creating POF

โš™๏ธ Scheduling

  • Frequency: every hour or nightly at midnight
  • Governance: ~15 usage per PO creation; safe for hundreds per run
  • Best practice: run on off-peak hours to avoid contention with manual purchasing

โœ… Testing Checklist

  1. Create a Sales Order with items having vendor values.
  2. Run the script manually via Map/Reduce deployment โ†’ Submit Script.
  3. Confirm POs appear under each vendor; check โ€œCreated Fromโ€ link.
  4. Ensure custbody_po_created = T after run.
  5. Try again โ†’ script should skip the same SO (safety check).

๐Ÿงฉ Optional Enhancements

EnhancementDescription
Email NotificationEmail buyer or vendor after PO creation.
Drop-Ship LogicOnly generate PO if item is marked as Drop Ship.
Vendor ApprovalAuto-approve POs under $500 limit.
Custom Field MappingCopy fields from SO to PO (e.g., project, terms, ship date).
Combine Multiple SOsGroup items by vendor across different SOs if same subsidiary.

๐Ÿง  Lessons Learned

  • Always flag processed SOs to avoid duplicates.
  • Vendor field (povendor) must exist on the item record.
  • For large volumes, consider batching by subsidiary or location.
  • Add robust logging and notifications for easy monitoring.

๐Ÿ” Summary

GoalOutcome
Automate manual PO creationโœ”๏ธ Reduced time per order by > 90%
Eliminate errors & duplicatesโœ”๏ธ Safe with custom flag
Improve vendor turnaroundโœ”๏ธ PO instantly generated on SO approval

Share
  • Facebook

Leave a ReplyCancel reply

Sidebar

Ask A Question

Stats

  • Questions 6
  • Answers 6
  • Best Answers 0
  • Users 2
  • Popular
  • Answers
  • Rocky

    Issue in running a client script in NetSuite SuiteScript 2.0 ...

    • 1 Answer
  • admin

    How can I send an email with an attachment in ...

    • 1 Answer
  • admin

    How do I avoid SSS_USAGE_LIMIT_EXCEEDED in a Map/Reduce script?

    • 1 Answer
  • admin
    admin added an answer The issue is usually caused by following Wrong script file… September 14, 2025 at 10:33 pm
  • admin
    admin added an answer Steps to send an Invoice PDF by email: define(['N/email', 'N/render',… August 28, 2025 at 3:05 am
  • admin
    admin added an answer This error means your script hit NetSuiteโ€™s governance usage limit… August 28, 2025 at 3:02 am

Top Members

Rocky

Rocky

  • 1 Question
  • 22 Points
Begginer
admin

admin

  • 5 Questions
  • 2 Points

Trending Tags

clientscript netsuite scripting suitescript

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help

Footer

© 2025 The NetSuite Pro. All Rights Reserved