NetSuite Python Report - Quick Debug Cheatsheet
Quick Start
# 1. Setup
pip install jupyter pandas xlsxwriter numpy
# 2. Start Jupyter
jupyter notebook
# 3. Open aging_report_dev.ipynb
Export Data from NetSuite
Method 1: Browser Console
// Run in browser console after Suitelet loads data
console.log(JSON.stringify(agingData, null, 2));
// Copy output and save to .json file
Method 2: Download Button (add to HTML)
function downloadTestData() {
const blob = new Blob([JSON.stringify(agingData, null, 2)], {type: 'application/json'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'test_data.json';
a.click();
}
Method 3: Suitelet Debug Files
// Uncomment in your Suitelet
var fileObj = file.create({
name: 'debug_data.json',
fileType: file.Type.PLAINTEXT,
contents: JSON.stringify(mainResult, null, 2),
folder: 4742 // Your folder ID
});
fileObj.save();
Common Debug Points
Check Data Structure
print(f"Records: {len(data)}")
print(f"Columns: {list(data[0].keys())}")
pd.DataFrame(data).info()
Check for Nulls
df = pd.DataFrame(data)
print(df.isnull().sum())
df = df.fillna(0) # Fix nulls
Verify Calculations
# Add debug column
df['_debug_total'] = df['col1'] + df['col2']
print(df[['col1', 'col2', '_debug_total']])
Check Excel Row Positions
print(f"AR: rows {ar_row_start} to {ar_row_end}")
print(f"AP: rows {ap_row_start} to {ap_row_end}")
Pyodide ↔ JavaScript Bridge
Pass Data to Python
// JavaScript
window.myData = JSON.stringify(dataArray).replaceAll(null, 'null');
# Python (Pyodide)
from js import myData
data = json.loads(myData)
Return File to JavaScript
# Python
import base64
bio = io.BytesIO()
# ... create Excel ...
bio.seek(0)
base64.b64encode(bio.getvalue()).decode() # Returns to JS
// JavaScript
const bytesData = pyodide.runPython(`...`);
const arrayBuffer = base64ToArrayBuffer(bytesData);
saveByteArray('report.xlsx', arrayBuffer);
xlsxwriter Quick Reference
Formats
bold_fmt = workbook.add_format({'bold': True})
currency_fmt = workbook.add_format({'num_format': '#,##0'})
border_fmt = workbook.add_format({'top': 1, 'left': 1, 'bottom': 1, 'right': 1})
center_fmt = workbook.add_format({'align': 'center', 'valign': 'vcenter'})
Common Operations
worksheet.write(row, col, value, format)
worksheet.merge_range(r1, c1, r2, c2, value, format)
worksheet.set_column(col, col, width)
worksheet.conditional_format(xl_range(r1, c1, r2, c2), {'type': 'no_errors', 'format': fmt})
Common Errors & Fixes
| Error | Cause | Fix |
|---|---|---|
KeyError: 'rownumber' | Column doesn't exist | Check with 'rownumber' in df.columns first |
TypeError: NaN | Null values | Use df.fillna(0) |
Index out of range | Wrong row calculation | Verify ar_row_start, ar_row_end |
Merge error | Overlapping ranges | Check merge coordinates |
| Pyodide hangs | Large data | Process in chunks |
Project Structure
project/
├── suitelet/
│ ├── report_sl.js # Suitelet
│ └── report.html # HTML template
├── notebooks/
│ └── report_dev.ipynb # Jupyter development
├── test_data/
│ └── sample.json # Test data
└── test_output/
└── test_report.xlsx # Generated reports
Debug Workflow
1. Export real data → JSON file
↓
2. Load in Jupyter → Develop logic
↓
3. Test Excel output → Verify formatting
↓
4. Copy to HTML → Port to Pyodide
↓
5. Test in browser → Final verification
↓
6. Deploy to NetSuite