Integration Test Cases
Integration patterns for QuickMart Supplies - connecting NetSuite to external systems.
Integration Patterns Overview
INTEGRATION PATTERNS - QuickMart Architecture
===============================================================================
+-------------+ +-------------+ +-------------+ +-------------+
| SHOPIFY | | POS | | WAREHOUSE | | ACCOUNTING |
| (Store) | | (Retail) | | (App) | | (System) |
+------+------+ +------+------+ +------+------+ +------+------+
| | | |
| POST | GET | |
| (orders) | (stock/loyalty) | |
v v | |
+------+-------------------+-------------------+-------------------+------+
| NETSUITE |
| |
| RECEIVE EXPOSE PUSH OUT PULL IN |
| (RESTlet POST) (RESTlet GET) (User Event) (Scheduled)|
| |
| - Create SO - Stock Query - Send to WH - Exchange |
| - Create Payment - Loyalty Lookup - Send Invoice Rates |
| - Send Alerts - Catalog |
+-------------------------------------------------------------------------+
Pattern Comparison
| Pattern | Direction | Trigger | Script Types | Use Case |
|---|---|---|---|---|
| Push Out | NS → External | Event-driven | User Event, Scheduled | Send orders to warehouse |
| Pull In | External → NS | Scheduled | Scheduled, Map/Reduce | Fetch exchange rates |
| Receive | External → NS | On-demand | RESTlet POST | Shopify sends order |
| Expose | NS → External | On-demand | RESTlet GET | POS queries stock |
Test Case #27: Push Out - Send Order to Warehouse
Pattern: PUSH OUT (Event-Driven)
Objective: When a Sales Order is approved, automatically send order details to external warehouse system.
Scenario
David (Warehouse) uses a mobile app to manage picking. When orders are approved in NetSuite, they should appear in his app immediately.
Architecture
PUSH OUT FLOW
-------------------------------------------------------------------------------
NetSuite Warehouse App
+------------------+ +------------------+
| | HTTP POST | |
| Sales Order | -----------------> | Orders Queue |
| Status: Approved | JSON Payload | |
| | | -> Pick List |
| User Event: | Response: 200 OK | -> Mobile App |
| afterSubmit | <----------------- | |
| | | |
+------------------+ +------------------+
Implementation
Test Steps
- Prerequisite: Warehouse API endpoint available (or mock server)
- Create Sales Order with items
- Change status to "Pending Fulfillment"
- Save the order
- Verify:
- Check Integration Log custom record
- Confirm order appears in warehouse system
- Response code: 200
Expected Payload
{
"orderId": "SO-12345",
"nsInternalId": 56789,
"customer": "ABC Corporation",
"shipAddress": "123 Main St, City, ST 12345",
"priority": true,
"lines": [
{
"item": "Printer Paper A4",
"quantity": 20,
"location": "Warehouse 1"
},
{
"item": "Ink Cartridge HP",
"quantity": 5,
"location": "Warehouse 1"
}
]
}
Error Handling
| Scenario | Expected Behavior |
|---|---|
| API timeout | Log error, retry later via scheduled job |
| API returns 400 | Log validation error, alert admin |
| API returns 500 | Log server error, queue for retry |
Test Case #28: Push Out - Send Invoice to Accounting
Pattern: PUSH OUT (Scheduled)
Objective: Send invoices to external accounting system nightly.
Architecture
PUSH OUT - BATCH FLOW
-------------------------------------------------------------------------------
NetSuite Accounting System
+------------------+ +------------------+
| | | |
| Invoices | Scheduled Script | Journal Entries |
| (Created Today) | runs at 11 PM | |
| | -----------------> | |
| Search: | POST /api/invoices | |
| date = today | (batch) | |
| | | |
+------------------+ +------------------+
Script Configuration
/**
* @NApiVersion 2.1
* @NScriptType ScheduledScript
*
* QuickMart - Push Invoices to Accounting
* Runs: Daily at 11:00 PM
*/
define(['N/search', 'N/https', 'N/log', 'N/record'], function(search, https, log, record) {
const ACCOUNTING_API = 'https://accounting.quickmart.com/api/invoices';
function execute(context) {
var invoices = findTodaysInvoices();
if (invoices.length === 0) {
log.audit('No Invoices', 'No invoices to push today');
return;
}
var payload = { invoices: invoices };
try {
var response = https.post({
url: ACCOUNTING_API,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
log.audit('Push Complete', 'Sent ' + invoices.length + ' invoices');
} catch (e) {
log.error('Push Failed', e.message);
}
}
function findTodaysInvoices() {
var invoices = [];
var today = new Date();
search.create({
type: search.Type.INVOICE,
filters: [
['trandate', 'on', 'today'],
'AND',
['mainline', 'is', 'T']
],
columns: ['tranid', 'entity', 'total', 'duedate']
}).run().each(function(result) {
invoices.push({
invoiceNumber: result.getValue('tranid'),
customer: result.getText('entity'),
amount: result.getValue('total'),
dueDate: result.getValue('duedate')
});
return true;
});
return invoices;
}
return { execute: execute };
});
Test Steps
- Create several invoices during the day
- Wait for scheduled script to run (or run manually)
- Verify: Integration log shows successful push
Test Case #29: Pull In - Fetch Exchange Rates
Pattern: PULL IN (Scheduled)
Objective: Fetch daily exchange rates from external API and update NetSuite.
Architecture
PULL IN FLOW
-------------------------------------------------------------------------------
External API NetSuite
+------------------+ +------------------+
| | | |
| Exchange API | Scheduled Script | Currency Rates |
| (exchangerate.io)| runs at 7 AM | |
| | <----------------- | |
| GET /latest | | Search/Update |
| | -----------------> | Currency Records |
| JSON Response | | |
| | | |
+------------------+ +------------------+
Implementation
Test Steps
- Configure scheduled script with API URL
- Run script manually for testing
- Verify: Exchange rates updated in NetSuite
Sample API Response
{
"base": "USD",
"date": "2024-03-15",
"rates": {
"EUR": 0.92,
"GBP": 0.79,
"SGD": 1.35,
"IDR": 15650
}
}
Test Case #30: Pull In - Import Supplier Catalog
Pattern: PULL IN (Map/Reduce for High Volume)
Objective: Import 5,000+ items from supplier catalog API.
Why Map/Reduce?
GOVERNANCE LIMITS
-------------------------------------------------------------------------------
Scheduled Script: 10,000 usage units
Map/Reduce Script: 10,000 units per stage (50,000+ total)
Automatic restart on timeout
For 5,000+ items: Use Map/Reduce!
Architecture
PULL IN - HIGH VOLUME
-------------------------------------------------------------------------------
Supplier API NetSuite
+------------------+ +------------------+
| | | |
| Catalog API | getInputData() | Items |
| /api/catalog | <----------------- | (5,000+ records) |
| | GET all items | |
| Returns: | | map(): Parse |
| 5,000 items | | reduce(): Update |
| | | each item |
+------------------+ +------------------+
Implementation
Test Case #31: Receive - Orders from Shopify
Pattern: RECEIVE (RESTlet POST)
Objective: Receive and process orders from Shopify webhooks.
Scenario
Lisa (Admin) currently copies orders manually from Shopify. This RESTlet receives orders automatically.
Architecture
RECEIVE FLOW
-------------------------------------------------------------------------------
Shopify NetSuite
+------------------+ +------------------+
| | | |
| New Order | Webhook POST | RESTlet |
| Created | -----------------> | |
| | JSON: Order Data | 1. Find Customer |
| Trigger: | | 2. Create SO |
| Order Created | Response: 200 | 3. Add Lines |
| | <----------------- | 4. Return ID |
| | {success: true} | |
+------------------+ +------------------+
Implementation
Shopify Webhook Configuration
Shopify Admin > Settings > Notifications > Webhooks
Event: Order Creation
Format: JSON
URL: https://<account>.restlets.api.netsuite.com/app/site/hosting/restlet.nl
?script=XXX&deploy=1
Headers:
Authorization: NLAuth nlauth_account=XXX, nlauth_email=XXX, nlauth_signature=XXX
Test Steps
- Deploy RESTlet with deployment ID
- Configure Shopify webhook to call RESTlet
- Place test order on Shopify
- Verify: Sales Order created in NetSuite
Sample Webhook Payload (Simplified)
{
"order_id": "SHOP-98765",
"customer_email": "customer@example.com",
"customer_name": "Jane Smith",
"priority": false,
"line_items": [
{
"sku": "PAPER-A4",
"quantity": 5,
"price": 12.00
}
],
"shipping_address": {
"address1": "456 Oak Ave",
"city": "Springfield",
"zip": "12345"
}
}
Expected Response
{
"success": true,
"netsuite_order_id": 12345,
"message": "Order created successfully"
}
Test Case #32: Receive - Payments from POS
Pattern: RECEIVE (RESTlet POST)
Objective: Receive payment transactions from POS system.
Architecture
RECEIVE - PAYMENT FLOW
-------------------------------------------------------------------------------
POS System NetSuite
+------------------+ +------------------+
| | | |
| Payment | POST | RESTlet |
| Completed | -----------------> | |
| | invoice_number | 1. Find Invoice |
| Cashier clicks | amount | 2. Transform to |
| "Complete" | payment_method | Payment |
| | | 3. Apply to Inv |
| | Response | |
| | <----------------- | |
+------------------+ {payment_id: 123} +------------------+
Implementation
Test Steps
- Create Invoice in NetSuite (e.g., INV-00100)
- POST payment to RESTlet:
{
"invoice_number": "INV-00100",
"amount": 150.00,
"payment_method": 5,
"reference": "POS-TXN-789"
} - Verify: Customer Payment created, Invoice marked paid
Test Case #33: Expose - Stock Availability Query
Pattern: EXPOSE (RESTlet GET)
Objective: Allow external systems to query real-time stock levels.
Scenario
E-commerce website needs to show "In Stock" or "Out of Stock" before customer adds to cart.
Architecture
EXPOSE FLOW
-------------------------------------------------------------------------------
E-commerce Site NetSuite
+------------------+ +------------------+
| | | |
| Product Page | GET | RESTlet |
| (needs stock) | -----------------> | |
| | ?sku=PAPER-A4 | 1. Search Item |
| Show: | | 2. Get Inventory |
| "150 in stock" | Response | 3. Return JSON |
| | <----------------- | |
+------------------+ {available: 150} +------------------+
Implementation
Test Steps
- Deploy RESTlet
- Call with item SKU:
GET /restlet?script=XXX&deploy=1&sku=PAPER-A4 - Verify: Response contains accurate stock levels
Sample Request/Response
Request:
GET ?script=XXX&deploy=1&sku=PAPER-A4
Response:
{
"item_id": "12345",
"sku": "PAPER-A4",
"name": "A4 Printer Paper 500 sheets",
"available": 150,
"on_hand": 200,
"on_order": 50
}
Test Case #34: Expose - Customer Loyalty Lookup
Pattern: EXPOSE (RESTlet GET)
Objective: Allow POS to look up customer loyalty data for in-store discounts.
Scenario
Mike (Sales) rings up a customer at the register. POS needs to check if they're a loyalty member and what discount they get.
Architecture
EXPOSE - LOYALTY FLOW
-------------------------------------------------------------------------------
POS System NetSuite
+------------------+ +------------------+
| | | |
| Customer at | GET | RESTlet |
| Register | -----------------> | |
| | ?email=x@email.com | 1. Find Customer |
| "Your loyalty | | 2. Get Loyalty |
| discount: 10%" | Response | Record |
| | <----------------- | 3. Return JSON |
+------------------+ {tier: Gold, ...} +------------------+
Implementation
Test Steps
- Create Customer with email: test@example.com
- Create Loyalty record: Gold tier, 1500 points
- Call RESTlet:
GET ?script=XXX&deploy=1&email=test@example.com - Verify: Response shows tier and discount
Sample Response
{
"found": true,
"customer_id": 789,
"customer_name": "ABC Corporation",
"loyalty": {
"tier": 3,
"tier_name": "Gold",
"points": 1500,
"total_spent": 15000.00,
"discount_percent": 10
}
}
Test Case #35: Push Out - Fulfillment Status to Shopify
Pattern: PUSH OUT (Event-Driven)
Objective: When an order is fulfilled in NetSuite, update the Shopify order status.
Scenario
Customers expect real-time shipping updates. When fulfillment is completed in NetSuite, Shopify should show the order as fulfilled.
Architecture
PUSH OUT - FULFILLMENT STATUS
-------------------------------------------------------------------------------
NetSuite Shopify
+------------------+ +------------------+
| | HTTP PUT | |
| Item Fulfillment | -----------------> | Order Status |
| (Created) | /orders/{id}.json | -> Fulfilled |
| User Event: | | |
| afterSubmit | <----------------- | Response: 200 OK |
+------------------+ +------------------+
Implementation
Test Steps
- Ensure Sales Order has
custbody_external_order_idpopulated - Create Item Fulfillment in NetSuite
- Verify: Shopify order shows Fulfilled status
- Verify: Integration log entry created (optional)
Integration Security Checklist
| Security Measure | Description | Implementation |
|---|---|---|
| Authentication | Verify caller identity | NLAuth, Token-Based Auth |
| Authorization | Check permissions | Role-based access, IP whitelist |
| Validation | Validate input data | Check required fields, types |
| Rate Limiting | Prevent abuse | Track call frequency |
| Logging | Audit trail | Integration Log custom record |
| Error Handling | Graceful failures | Try/catch, meaningful errors |
Authentication Example
// Token-Based Authentication (TBA)
// Configured in: Setup > Integration > Manage Integrations
// OAuth 1.0 Headers (set by calling system):
// Authorization: OAuth
// oauth_consumer_key="...",
// oauth_token="...",
// oauth_signature="...",
// oauth_signature_method="HMAC-SHA256",
// oauth_timestamp="...",
// oauth_nonce="...",
// oauth_version="1.0"
Integration Log Record
For tracking all integration calls, create a custom record:
Custom Record: Integration Log
ID: customrecord_integration_log
Fields:
+-----------------+-----------+----------------------------------+
| Field | Type | Purpose |
+-----------------+-----------+----------------------------------+
| Name | Auto | Auto-generated |
| Pattern | List | PUSH_OUT, PULL_IN, RECEIVE, etc. |
| Status | List | SUCCESS, ERROR, PENDING |
| Direction | List | INBOUND, OUTBOUND |
| Endpoint | URL | API URL called |
| Request Body | Text Area | Outbound payload (truncated) |
| Response Body | Text Area | Response received (truncated) |
| Error Message | Text Area | Error details if failed |
| Related Record | Text | SO ID, Invoice ID, etc. |
| Timestamp | DateTime | When call was made |
+-----------------+-----------+----------------------------------+