Skip to content

FlowSync-Consulting/batch-transaction-search

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 

Repository files navigation

Batch Transaction Search Pattern

Zero-code reusable transaction search tool for NetSuite supporting 100+ batch lookups

Overview

A single reusable Suitelet that searches multiple transaction records at once using script parameters. No code changes required when adding new transaction types.

Problem

Users need to look up details for 100+ transaction document numbers, but NetSuite's saved search interface requires entering values one at a time:

  • Manual Process: Enter each document number individually → Click Search → Copy results
  • Time Cost: 30-60 seconds per lookup = 50+ minutes for 100 transactions
  • Repetitive Development: Building a separate search tool for each transaction type (Item Fulfillments, Transfer Orders, Sales Orders) is wasteful

Solution: Parameter-Driven Reusability

A single Suitelet script serves every transaction type through deployment parameters:

┌─────────────────────────┐
│   Single Suitelet       │
│   (One Script File)     │
└───────────┬─────────────┘
            │
    ┌───────┴───────┬───────────┬─────────────┐
    │               │           │             │
Deployment 1    Deployment 2  Deployment 3  Deployment N
IF Search       TO Search     SO Search     Any Type
  ↓               ↓             ↓             ↓
Parameters:    Parameters:   Parameters:   Parameters:
- Search ID    - Search ID   - Search ID   - Search ID
- Type Label   - Type Label  - Type Label  - Type Label
- Field Name   - Field Name  - Field Name  - Field Name

Key Insight: The search logic is identical across transaction types. Only the saved search ID and display labels change.

Architecture

Script Parameters

Parameter Purpose Example
Saved Search ID Which search to load and filter customsearch4376
Transaction Type Display label for UI Item Fulfillment
Page Title Browser title Wholesale IF Lookup
Document Field Which field to filter on tranid (default)

User Workflow

  1. Paste - User pastes 100+ document numbers into textarea (commas, spaces, newlines, OR-separated)
  2. Submit - Click Submit button
  3. Results - See table with all matching transactions

Implementation Pattern

/**
 * @NApiVersion 2.1
 * @NScriptType Suitelet
 */
define(['N/search', 'N/runtime', 'N/ui/serverWidget'],
    function(search, runtime, serverWidget) {

        function onRequest(context) {
            const script = runtime.getCurrentScript();

            // Read deployment parameters
            const savedSearchId = script.getParameter({ name: 'custscript_search_id' });
            const transactionType = script.getParameter({ name: 'custscript_transaction_type' });
            const pageTitle = script.getParameter({ name: 'custscript_page_title' });
            const documentField = script.getParameter({ name: 'custscript_document_field' }) || 'tranid';

            if (context.request.method === 'GET') {
                const form = buildSearchForm(pageTitle, transactionType);
                context.response.writePage(form);
            } else {
                const inputText = context.request.parameters.custpage_input;
                const documentNumbers = parseInput(inputText);
                const results = searchTransactions(savedSearchId, documentField, documentNumbers);
                const form = buildResultsForm(pageTitle, transactionType, results);
                context.response.writePage(form);
            }
        }

        function parseInput(inputText) {
            // Split on commas, spaces, newlines, OR operators
            return inputText
                .split(/[,\s|]+/)
                .map(s => s.trim())
                .filter(s => s.length > 0);
        }

        function searchTransactions(savedSearchId, fieldId, documentNumbers) {
            const searchObj = search.load({ id: savedSearchId });

            // Use anyof operator for batch filtering
            searchObj.filters.push(search.createFilter({
                name: fieldId,
                operator: search.Operator.ANYOF,
                values: documentNumbers
            }));

            const results = [];
            searchObj.run().each(function(result) {
                results.push(result);
                return true; // Continue iteration
            });

            return results;
        }

        return { onRequest };
    }
);

Key Techniques

1. anyof Operator for Batch Filtering

Instead of running 100 separate searches, use the anyof operator to match multiple values in a single query:

search.createFilter({
    name: 'tranid',
    operator: search.Operator.ANYOF,
    values: ['IF12345', 'IF12346', 'IF12347', ...] // Up to 200 values
});

2. Dynamic Column Loading

Read column definitions directly from the saved search, so admins can modify columns without touching code:

function getColumnsFromSearch(searchObj) {
    const columns = [];
    searchObj.columns.forEach(col => {
        columns.push({
            id: col.name,
            label: col.label || col.name,
            type: 'TEXT' // Or determine from search metadata
        });
    });
    return columns;
}

3. Flexible Input Parsing

Accept any delimiter format users naturally use:

function parseInput(inputText) {
    // Handles: "IF001, IF002, IF003"
    // Handles: "IF001 IF002 IF003"
    // Handles: "IF001\nIF002\nIF003"
    // Handles: "IF001 OR IF002 OR IF003"
    return inputText
        .split(/[,\s|]+/)
        .map(s => s.trim())
        .filter(s => s.length > 0);
}

Deployment Examples

Deployment 1: Item Fulfillment Lookup

Parameters:

  • Saved Search ID: customsearch_if_lookup
  • Transaction Type: Item Fulfillment
  • Page Title: Wholesale IF Lookup
  • Document Field: tranid

URL: https://1234567.app.netsuite.com/app/site/hosting/scriptlet.nl?script=123&deploy=1

Deployment 2: Transfer Order Lookup

Parameters:

  • Saved Search ID: customsearch_to_lookup
  • Transaction Type: Transfer Order
  • Page Title: TO Batch Search
  • Document Field: tranid

URL: https://1234567.app.netsuite.com/app/site/hosting/scriptlet.nl?script=123&deploy=2

Code Changes Required: ZERO

Real-World Impact

Before:

  • 100 transaction lookups = 50+ minutes of manual work
  • Separate tools needed for each transaction type
  • 3 hours of development per transaction type

After:

  • 100 transaction lookups = 60 seconds (60x faster)
  • Single script serves all transaction types
  • 5 minutes to deploy new transaction type (create deployment + set parameters)

Reusability Score: 5/5 - Script works for ANY transaction type with zero modifications

Limitations

  • NetSuite limits anyof operator to ~1,000 values per filter
  • Search governance units consumed based on result volume
  • Large result sets may require pagination

Testing

Unit Tests

// Test input parsing
test('parseInput handles comma-separated values', () => {
    const input = 'IF001, IF002, IF003';
    const result = parseInput(input);
    expect(result).toEqual(['IF001', 'IF002', 'IF003']);
});

// Test multiple delimiters
test('parseInput handles mixed delimiters', () => {
    const input = 'IF001, IF002 IF003\nIF004|IF005';
    const result = parseInput(input);
    expect(result).toEqual(['IF001', 'IF002', 'IF003', 'IF004', 'IF005']);
});

Integration Tests

  1. Create test saved search with known transactions
  2. Paste known document numbers
  3. Verify all expected results appear
  4. Verify no unexpected results

Best Practices

  1. Limit result columns - Fewer columns = faster searches and lower governance
  2. Add pagination - For searches returning 1,000+ results
  3. Cache saved search objects - Reduce script governance on repeated searches
  4. Validate input - Reject suspiciously large input (10,000+ values)
  5. Log failures - Track which document numbers returned no results

License

MIT License - See LICENSE file for details

Related Patterns

About

Parameter-driven reusable transaction search tool supporting 100+ batch lookups with zero code changes for new transaction types

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors