Skip to main content

Attaching Files to NetSuite Records

Learn how to attach files to purchase orders, invoices, and other NetSuite records using the SOAP attach action.

Prerequisites

  • NetSuite connector configured with soap and fileCabinet resources enabled
  • File uploaded to File Cabinet (see uploading files)

Basic File Attachment

Attach a file to a purchase order:

from abstra.connectors import run_connection_action

# Assuming you have:
# - file_id: ID of uploaded file
# - po_id: ID of purchase order

result = run_connection_action(
"netsuite",
"attach",
{
"attachTo": {
"type": "purchaseOrder",
"internalId": po_id
},
"attachedRecord": {
"type": "file",
"internalId": file_id
}
}
)

if result['data']['success']:
print(f"✓ Attached file {file_id} to PO {po_id}")

Supported Record Types

Transactions

# Invoice
run_connection_action("netsuite", "attach", {
"attachTo": {"type": "invoice", "internalId": "12345"},
"attachedRecord": {"type": "file", "internalId": file_id}
})

# Vendor Bill
run_connection_action("netsuite", "attach", {
"attachTo": {"type": "vendorBill", "internalId": "67890"},
"attachedRecord": {"type": "file", "internalId": file_id}
})

# Sales Order
run_connection_action("netsuite", "attach", {
"attachTo": {"type": "salesOrder", "internalId": "11111"},
"attachedRecord": {"type": "file", "internalId": file_id}
})

# Cash Sale
run_connection_action("netsuite", "attach", {
"attachTo": {"type": "cashSale", "internalId": "22222"},
"attachedRecord": {"type": "file", "internalId": file_id}
})

Entities

# Customer
run_connection_action("netsuite", "attach", {
"attachTo": {"type": "customer", "internalId": "33333"},
"attachedRecord": {"type": "file", "internalId": file_id}
})

# Vendor
run_connection_action("netsuite", "attach", {
"attachTo": {"type": "vendor", "internalId": "44444"},
"attachedRecord": {"type": "file", "internalId": file_id}
})

# Employee
run_connection_action("netsuite", "attach", {
"attachTo": {"type": "employee", "internalId": "55555"},
"attachedRecord": {"type": "file", "internalId": file_id}
})

Complete Workflow: Upload and Attach

Upload a file and immediately attach it:

from abstra.connectors import run_connection_action
import base64

# Step 1: Upload file
with open("contract.pdf", "rb") as f:
file_content = base64.b64encode(f.read()).decode('utf-8')

file_result = run_connection_action(
"netsuite",
"add_file",
{
"name": "contract.pdf",
"content": file_content,
"fileType": "PDF"
}
)
file_id = file_result['data']['id']
print(f"✓ Uploaded file: {file_id}")

# Step 2: Attach to purchase order
attach_result = run_connection_action(
"netsuite",
"attach",
{
"attachTo": {
"type": "purchaseOrder",
"internalId": "501628"
},
"attachedRecord": {
"type": "file",
"internalId": file_id
}
}
)

if attach_result['data']['success']:
print(f"✓ File attached to PO")

Attach Multiple Files

Attach several files to one record:

def attach_files_to_record(record_type, record_id, file_ids):
"""Attach multiple files to a single record"""
results = []

for file_id in file_ids:
result = run_connection_action(
"netsuite",
"attach",
{
"attachTo": {
"type": record_type,
"internalId": record_id
},
"attachedRecord": {
"type": "file",
"internalId": file_id
}
}
)

results.append({
"file_id": file_id,
"success": result['data']['success']
})

if result['data']['success']:
print(f"✓ Attached file {file_id}")
else:
print(f"❌ Failed to attach file {file_id}")

return results

# Usage
file_ids = ["654321", "654322", "654323"]
attach_files_to_record("purchaseOrder", "501628", file_ids)

Attach Same File to Multiple Records

Share one file across multiple records:

def attach_file_to_records(file_id, record_type, record_ids):
"""Attach one file to multiple records"""
results = []

for record_id in record_ids:
result = run_connection_action(
"netsuite",
"attach",
{
"attachTo": {
"type": record_type,
"internalId": record_id
},
"attachedRecord": {
"type": "file",
"internalId": file_id
}
}
)

results.append({
"record_id": record_id,
"success": result['data']['success']
})

if result['data']['success']:
print(f"✓ Attached to {record_type} {record_id}")

return results

# Usage - attach policy document to all vendors
vendor_ids = ["100", "101", "102"]
attach_file_to_records("654321", "vendor", vendor_ids)

Practical Examples

Attach Invoice to Purchase Order

from abstra.connectors import run_connection_action
from datetime import datetime
import base64

# Create PO
po_result = run_connection_action("netsuite", "post_purchase_order", {
"data": {
"entity": {"id": "123"},
"subsidiary": {"id": "1"},
"tranDate": datetime.now().strftime("%Y-%m-%d"),
# ... other PO fields
}
})
po_id = po_result['data']['id']

# Upload invoice
with open("vendor_invoice.pdf", "rb") as f:
content = base64.b64encode(f.read()).decode('utf-8')

file_result = run_connection_action("netsuite", "add_file", {
"name": f"invoice_po_{po_id}.pdf",
"content": content,
"fileType": "PDF"
})
file_id = file_result['data']['id']

# Attach invoice to PO
run_connection_action("netsuite", "attach", {
"attachTo": {"type": "purchaseOrder", "internalId": po_id},
"attachedRecord": {"type": "file", "internalId": file_id}
})

print(f"✓ Created PO {po_id} with attached invoice")

Attach Supporting Documents to Customer

import base64

customer_id = "12345"
documents = [
{"file": "contract.pdf", "type": "PDF"},
{"file": "id_document.jpg", "type": "JPGIMAGE"},
{"file": "bank_statement.pdf", "type": "PDF"}
]

for doc in documents:
# Upload
with open(doc['file'], "rb") as f:
content = base64.b64encode(f.read()).decode('utf-8')

file_result = run_connection_action("netsuite", "add_file", {
"name": doc['file'],
"content": content,
"fileType": doc['type']
})

# Attach
run_connection_action("netsuite", "attach", {
"attachTo": {"type": "customer", "internalId": customer_id},
"attachedRecord": {"type": "file", "internalId": file_result['data']['id']}
})

print(f"✓ Attached {doc['file']} to customer {customer_id}")

Error Handling

Always include error handling:

def safe_attach(record_type, record_id, file_id):
"""Safely attach file with error handling"""
try:
result = run_connection_action(
"netsuite",
"attach",
{
"attachTo": {
"type": record_type,
"internalId": str(record_id)
},
"attachedRecord": {
"type": "file",
"internalId": str(file_id)
}
}
)

if result.get('status') == 'error':
return {
"success": False,
"error": result.get('message', 'Unknown error')
}

return {
"success": result['data']['success'],
"response": result['data']
}

except Exception as e:
return {
"success": False,
"error": str(e)
}

# Usage
result = safe_attach("purchaseOrder", "123456", "654321")
if result['success']:
print("✓ File attached successfully")
else:
print(f"❌ Attachment failed: {result['error']}")

Best Practices

Naming Convention

Name files to reflect their purpose:

# Good: Descriptive names
f"po_{po_id}_contract_signed.pdf"
f"invoice_{vendor_id}_{date}.pdf"
f"customer_{customer_id}_id_verification.jpg"

# Bad: Generic names
"document.pdf"
"file1.pdf"

Verify Before Attaching

Check that records exist:

# Verify PO exists before attaching
po_check = run_connection_action("netsuite", "query", {
"query": f"SELECT id FROM Transaction WHERE id = {po_id} AND type = 'PurchOrd'"
})

if po_check['data']['items']:
# PO exists, proceed with attachment
run_connection_action("netsuite", "attach", {
"attachTo": {"type": "purchaseOrder", "internalId": po_id},
"attachedRecord": {"type": "file", "internalId": file_id}
})
else:
print(f"❌ PO {po_id} not found")

Batch Processing

Process attachments in batches:

import time

def batch_attach(attachments, batch_size=10, delay=1):
"""
Process attachments in batches
attachments: list of {"record_type", "record_id", "file_id"}
"""
results = []

for i in range(0, len(attachments), batch_size):
batch = attachments[i:i + batch_size]
print(f"Processing batch {i//batch_size + 1}...")

for attachment in batch:
result = run_connection_action("netsuite", "attach", {
"attachTo": {
"type": attachment['record_type'],
"internalId": attachment['record_id']
},
"attachedRecord": {
"type": "file",
"internalId": attachment['file_id']
}
})
results.append(result)

# Delay between batches
if i + batch_size < len(attachments):
time.sleep(delay)

return results

Troubleshooting

"Action attach not found"

Enable the soap resource:

  1. Go to NetSuite connection settings
  2. Check soap checkbox
  3. Save connection

"Invalid record reference"

Verify record exists and type is correct:

# Check record exists
result = run_connection_action("netsuite", "query", {
"query": f"SELECT id, type FROM Transaction WHERE id = {record_id}"
})

if result['data']['items']:
record = result['data']['items'][0]
print(f"Record {record_id} is type: {record['type']}")
else:
print(f"Record {record_id} not found")

"Permission denied"

Ensure your NetSuite role has:

  • File Cabinet > View permission
  • Attach Files to Records permission

Record Type Reference

Common NetSuite record types for attach action:

Record TypeParameter Value
Purchase OrderpurchaseOrder
Sales OrdersalesOrder
Invoiceinvoice
Vendor BillvendorBill
Cash SalecashSale
Customercustomer
Vendorvendor
Employeeemployee
Expense ReportexpenseReport
Journal EntryjournalEntry

Next Steps

Resources