Fix NetSuite Vendor Prepayment TDS Application Issue
Learn how to resolve NetSuite's vendor prepayment TDS application issue, preventing compliance exposure and ensuring accurate trade payables tie-out.

On this page
When a Vendor Prepayment with TDS deducted at the advance stage gets applied against a Vendor Bill in NetSuite India Localization, only the Basic + GST portion applies. The TDS leg remains stranded on the vendor account, the advance never fully clears, and TDS gets double-counted, once on the prepayment and again on the bill. This breaks the vendor sub-ledger tie-out to trade payables and creates a compliance exposure that surfaces in every period-end reconciliation.
The Mechanics Behind the Stranded TDS
In a standard SuiteTax India implementation, a Vendor Prepayment records three components: the basic amount, the GST liability, and the TDS deducted under Section 194C/194J. When you later create a Vendor Bill for the same expense and apply the prepayment, the application logic only matches the basic and GST lines. The TDS line from the prepayment has no corresponding reversal entry in the application transaction, so it stays open on the vendor ledger.
Worked example (simplified): Advance: Basic ₹100, TDS ₹10, Bank out ₹90. Bill: Expense ₹100, GST ₹18, TDS ₹10. Expected: Application reverses the advance TDS ₹10, net payable on Bill = ₹18, advance fully knocked off. Actual: Only ₹90 (Basic + GST) applies. The ₹10 TDS leg remains open on the vendor.
The control here is the Vendor Prepayment Application record, it must generate a reversing TDS line when the advance and bill fall in the same TDS period. Without it, your auditors will flag the unreconciled vendor balance.
Scenario Rules That Determine the Fix
The correct TDS treatment depends on the period relationship between the prepayment and the bill:
| Scenario | Required Behavior |
|---|---|
| Same TDS period (advance and bill in same quarter) | Application must reverse the advance TDS leg so TDS isn't charged twice |
| Different period (advance TDS already deposited for closed period) | Do NOT reverse in the application; handle double deduction via TDS return adjustment |
| No TDS on the Bill | No reversal required; advance TDS stands as final deduction |
Your configuration must enforce these rules automatically. Manual journal entries to clear stranded TDS defeat the audit trail and reintroduce the spreadsheet workaround.
Native Configuration Checklist
Before building custom logic, verify these SuiteTax India settings. Exact navigation paths vary by account configuration, use the global search (Alt+G) for "TDS Setup" if the menu path differs:
- TDS Section Mapping, Confirm the prepayment and bill use the same TDS section (e.g., 194C for contracts, 194J for professional fees). Mismatched sections prevent auto-reversal.
- TDS Period Alignment, At Setup > Accounting > Accounting Periods, ensure the TDS quarter (Q1–Q4) aligns with your posting periods. The application reversal only triggers when both transactions fall in the same TDS quarter.
- Vendor Prepayment Form, On the custom Vendor Prepayment form (if customized), verify the TDS Details subtab includes the TDS Amount and TDS Rate fields populated from the vendor's TDS master at Lists > Relationships > Vendors > TDS Details. Field IDs for these values are account-specific; confirm them in the Record Browser or via the NetSuite Connector field ID reference.
- Apply Prepayment Preference, At Setup > Accounting > Preferences > Vendor Prepayments, confirm Allow Partial Application is enabled. This doesn't fix TDS but permits partial knock-off while you resolve the reversal logic.
If all above are correct and the TDS leg still strands, the gap is in the application posting logic, a known limitation in the standard India Localization SuiteApp.
Customization Approach: SuiteScript 2.1 User Event Script
The cleanest fix is a User Event script on the Vendor Prepayment Application record (vendorprepaymentapplication) that inserts the reversing TDS line when conditions are met. This keeps the audit trail intact and avoids manual JEs.
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
* @NModuleScope SameAccount
*/
define(['N/record', 'N/search', 'N/runtime'],
(record, search, runtime) => {
// FIELD IDs ARE ACCOUNT-SPECIFIC — VERIFY IN YOUR SANDBOX FIRST
// Use the Records Browser (Alt+Shift+R) or the [NetSuite Connector field ID guide](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_162611905808.html)
const TDS_FIELDS = {
amount: 'custbody_tds_amount', // Example: custom body field for TDS Amount
rate: 'custbody_tds_rate', // Example: custom body field for TDS Rate
section: 'custbody_tds_section', // Example: custom body field for TDS Section
period: 'custbody_tds_period' // Example: custom body field for TDS Period
};
function beforeSubmit(context) {
if (context.type !== context.UserEventType.CREATE &&
context.type !== context.UserEventType.EDIT) return;
const appRec = context.newRecord;
const prepaymentId = appRec.getValue('prepayment');
const billId = appRec.getValue('bill');
if (!prepaymentId || !billId) return;
const prepayment = record.load({
type: record.Type.VENDOR_PREPAYMENT,
id: prepaymentId
});
const bill = record.load({
type: record.Type.VENDOR_BILL,
id: billId
});
const prepayTDS = prepayment.getValue(TDS_FIELDS.amount) || 0;
const billTDS = bill.getValue(TDS_FIELDS.amount) || 0;
// Same TDS section & same TDS quarter = reverse advance TDS
const sameSection = prepayment.getValue(TDS_FIELDS.section) ===
bill.getValue(TDS_FIELDS.section);
const sameQuarter = prepayment.getValue(TDS_FIELDS.period) ===
bill.getValue(TDS_FIELDS.period);
if (prepayTDS > 0 && billTDS > 0 && sameSection && sameQuarter) {
// Insert reversing TDS line on the application sublist
const lineCount = appRec.getLineCount({ sublistId: 'apply' });
for (let i = 0; i < lineCount; i++) {
if (appRec.getSublistValue({ sublistId: 'apply', fieldId: 'apply', line: i })) {
// TDS reversal field on apply sublist is typically custom
const reversalField = 'custcol_tds_reversal_amount'; // VERIFY THIS FIELD ID
if (appRec.getSublistField({ sublistId: 'apply', fieldId: reversalField, line: i })) {
appRec.setSublistValue({
sublistId: 'apply',
fieldId: reversalField,
line: i,
value: -prepayTDS // negative = reversal
});
}
break;
}
}
}
}
return { beforeSubmit };
});Deploy this script Before Submit on the vendorprepaymentapplication record with Execute As Role: Administrator. Test in Sandbox with these steps:
- Create Vendor Prepayment: Basic ₹100, TDS ₹10 (Section 194C, Q1 FY25).
- Create Vendor Bill: Expense ₹100, GST ₹18, TDS ₹10 (same Section 194C, Q1 FY25).
- Apply prepayment to bill via the Apply Prepayment action on the Vendor Bill.
- Open the resulting Vendor Prepayment Application record. Verify the TDS reversal line shows -10.
- Run the Vendor Prepayment Application report, the advance should show Fully Applied with zero balance.
Edge Cases That Break the Automation
| Edge Case | Handling |
|---|---|
| Partial application (prepayment > bill) | Script must prorate TDS reversal: reversal = prepayTDS * (appliedAmount / prepayTotal) |
| Multiple TDS sections on one bill | Loop through bill expense lines; match each to prepayment TDS section |
| Advance TDS already deposited (Form 26Q filed) | Add a Do Not Reverse TDS checkbox on the Vendor Prepayment form; script skips reversal when checked |
| Service vs. Material items | TDS section differs (194J vs 194C); script uses section match, so it works for both |
From an audit perspective, the script's
beforeSubmitexecution leaves a clean system note: "TDS reversal auto-applied per Section 194C Q1 FY25." Your auditors will thank you. For details on system note structure, see the System Notes Guide.
Validation Before Production
Run this SuiteQL in Analytics > SuiteQL to confirm zero stranded TDS across vendors. Adjust field names to match your account's actual TDS field IDs:
SELECT v.entityid AS vendor, v.companyname,
SUM(CASE WHEN t.type = 'Vendor Prepayment' THEN t.custbody_tds_amount ELSE 0 END) AS prepay_tds,
SUM(CASE WHEN t.type = 'Vendor Prepayment Application' THEN t.custbody_tds_reversal_amount ELSE 0 END) AS app_reversal_tds,
SUM(t.custbody_tds_amount) AS net_tds_balance
FROM transaction t
JOIN vendor v ON t.entity = v.id
WHERE t.custbody_tds_amount IS NOT NULL
AND t.trandate >= '2025-04-01'
GROUP BY v.entityid, v.companyname
HAVING ABS(SUM(t.custbody_tds_amount)) > 0.01
ORDER BY net_tds_balance DESC;Any row returned = a vendor with unreconciled TDS. Fix the script logic or the data before period close.
What to Check Next
If the SuiteScript deployment resolves the same-period reversal but your team still sees stranded TDS on cross-period advances, the next step is a Scheduled Script that runs monthly to generate a TDS Reconciliation Report, mapping each advance TDS to its bill application or Form 26Q deposit. That report becomes your control evidence for the quarterly TDS return filing.


