This article is relevant if you working to automate the posting of customer deposits to invoices in NetSuite and you need SuiteScript reference information.
Background
NetSuite offers a way to post customer deposits (appropriately as liabilities) received by customers typically for advanced payments before goods are delivered. I like to think of these similar to retainers commonly used in professional services organizations, such as attorney firms. Smartly, NetSuite will automatically apply a customer deposit to a freshly generated (unpaid) invoice if it both transaction documents (the customer deposit and the invoice) is connected to a common Sales Order.
However, while the Sales Order connection is convenient, it also can be restrictive. In my article last week, Applying NetSuite Sales Order Customer Deposits on Independent Invoices, I demonstrated a trick to apply Customer Deposits to Invoices not connected to a Sales Order.
As I have been studying how to increase my firm’s billing operations, which in many respects, may resemble a staffing firm as we heavily use NetSuite Advanced Projects the Timesheet as the basis for accounting for services, I began to see ways that the Sales Order was cumbersome to work with. While subject to another article, what I had to do is break the connection, in general, to the Sales Order as an organizing transactional concept.
Once you don’t have a Sales Order between your time entries and your invoice work, then NetSuite’s automatic customer deposit application no longer functions. What I needed was to preserve that automatic function so that unpaid invoices could be immediately paid based on monies (deposits) on account.
Automating Application of Customer Deposits to Open Invoices
Early in my work to automate this function, I thought I would try to apply a customer payment to the invoice. There is a transform function that will get the payment record in play. In this case, I would use the “Deposits” sublist to apply payment to the invoice. While this works in the user interface, it does not behave the same way via SuiteScript. I could see the deposit lines but I could not get them to actually apply. I speculate that applying a deposit from the Customer Payment screen actually does another transform behind the scenes.
As I inspected the record structures, I could see there is a record called a Deposit Application which effectively allows a many-to-many (M:M) relationship between Customer Deposits and Invoices. NetSuite does not provide a user interface (UI) to create one of these deposit application records from scratch. To create one, you always start from a Customer Deposit record.
Although there is a reference in the SuiteScript Record Browser, I was frustrated as there is no documentation on how to really work with this record. Per the NetSuite Help documentation, there is no Tranform support Deposit Application record. Yet, unwilling to concede, I found a clue by inspecting the URL for the Deposit Application and I could see “transform” as one of the parameters (side note: always watch what is happening in the URL as it is a clue to how the system is built). With some trial-and-error, I was able to figure out what I think is an undocumented feature to get what I needed.
SuiteScript Reference for Working with Customer Deposit Application Records
The following function was being called in an invoice AfterSubmit UserEvent. I have added comments to help illustrate what is happening. As of the time of this article, this transform function does not appear to support the respective record types; as such, use with care.
function applyDeposits(invId, cusId){ //invoice id and customer id var func = 'applyDeposits '; var depositbalance = nlapiLookupField('customer', cusId, 'depositbalance') //if there are no monies to apply, avoid doing work if (depositbalance > 0){ //find all the related open deposit records var filters = new Array(); filters[0] = new nlobjSearchFilter('entity', null, 'anyof', cusId); //indicates not full applied filters[1] = new nlobjSearchFilter('status', null, 'noneof', 'CustDep:C'); filters[2] = new nlobjSearchFilter('mainline', null, 'is', 'T'); //don't try to get those deposits hard linked to sales orders filters[3] = new nlobjSearchFilter('salesorder', null, 'anyof', '@NONE@'); var columns = new Array(); columns[0] = new nlobjSearchColumn('internalid').setSort(false); //hunt for the records var records = nlapiSearchRecord('customerdeposit', null, filters, columns); if (!records){ nlapiLogExecution('DEBUG', func + 'Found no deposit records; but they were expected.'); return }; nlapiLogExecution('DEBUG', func + ' starting deposit application work'); for ( var r = 0; r < records.length; r++ ) { //transform below does not appear documented; but works as expected var deposit = nlapiTransformRecord('customerdeposit', records[r].getId(), 'depositapplication'); deposit.setFieldValue('trandate', nlapiDateToString(new Date())); deposit.setFieldValue('memo', 'Applied Invoice: ' + new Date()); //walk the invoice list that we want to apply; find the invoice we are working on var a = deposit.getLineItemCount('apply'); for (var i = 1; i <= a; i++){ if ( deposit.getLineItemValue('apply', 'internalid', i) == invId ){ nlapiLogExecution('DEBUG', func + 'working on invoice line:' + i, deposit.getLineItemValue('apply', 'refnum', i)); //find the related line and mark it on; appears safe to apply as much as you can; NetSuite appears to // handle if there is insufficient funds and it will match the amount of the invoice deposit.setLineItemValue('apply', 'amount', i, deposit.getLineItemValue('apply', 'total', i)); deposit.setLineItemValue('apply', 'apply', i, 'T'); }; }; nlapiSubmitRecord(deposit); }; }; };
Demand More from Your NetSuite Business System
NetSuite was designed to be optimized for business requirements. The platform opens up your space for innovation which can streamline your business operation. If you would like to get more out of NetSuite, let’s have a conversation.
How to create the postings BE GAAP for inventory
Next to asset account and vendor account
Extra posting 3 é 609 account
Thanks
Hello Hilde,
I don’t believe I can offer you thinking. I have no background in BE GAAP requirements. However, if you can point me to an explanation of the outcome, I may be able to comment.
Marty
Hi Marty, This looks like pretty close to what I was looking for, but instead of customer deposits I need the script to apply an unapplied payments / credit memos to new invoices. Do you have any experience using something similar with those two records?
Thanks,
Gabe
Hi Gabriel,
Yes, we are experts in the customer deposit area but we have done extensive work with unapplied payments and auto applying credit memos. If you can describe the way you want things applied, we can script it.
Marty
Hi Marty,
To set the JE as approved, can be do it by default on creation or should be when it is updated? So far It seems I can set the credit list as the JE is available only when it has been approved. Thanks
Hello Edgar,
Have you seen this article which discusses automating journal entries?
https://blog.prolecto.com/2013/05/01/how-to-script-to-automate-netsuite-journal-entries/
Marty
Hi Marty,
In the scenario that both the bill and bill payment or invoice and payment are all recorded as Journal Entries, is there a way to mass apply them to each other to close them out?
Hi Amy,
Yes, via script you could produce that application using a Mass Update. So long as you can emulate the process with the UI, you should be able to script it. We have done this for clients where they have many old records that were not properly applied.
Marty
Hi Marty,
Can we create the invoice from the billable expense record?
You can set a billable expense with the name of a customer / project and then, when creating invoices, the billable expense line will become a candidate to invoice during the next invoice attempt for that customer / project.
Hello! I came here because I was looking for automate the creation of a customer deposit when a new sale is entered with some specific custom fields.
I connected my e-commerce to net suite and we are saving the PayPal data like transaction ID and other stuff in custom fields in a new sales order.
The thing is, once I create and save this sale order, can we automatically create a customer deposit using in information stored in my fields?
Thank you Marty
Yes, if you are using NetSuite Sales orders, then when you created the Customer Deposit, reference the Sales Order. It is native. This will then link the sales order and subsequent invoices will automatically be paid from the customer deposit.
In this article use case, we have no sales orders so we need a script to auto-apply to invoices.
Marty
Marty, thank you for your reply.
Sales orders are created automatically. But I didn’t understand once they are created how do we automatically create a customer deposit if we detect that a specific custom fields of that order is filled out (fields with PayPal information)
Is that possible? Where do I configure this?
Thank you so much
Hello Enrique,
Please read this article to help orient you with out of the box options to drive a customer deposit creation from a sales order:
https://blog.prolecto.com/2016/10/02/using-netsuite-payment-methods-to-drive-customer-deposits/
Also, in our Customer Deposit Generator, we have a mechanism to automatically create customer deposits based on payment methods when NetSuite’s native approach does not work. The script is relatively simple to implement.
Marty
Marty.
I am trying to run the script in this article and Netsuite returns SSS_MISSING_REQD_ARGUMENT ‘ID’ error.
Any idea why?
David,
The code may need to be enhanced to check for null ID situations being passed to the function.
Marty
Thank you for your reply Marty
Hi Marty,
Hope you are doing good !
My question is below.
How many records i can check in deposit record. Can you please help me duo to i have 35k+ records need to check inside the deposit record, is it posible?
Hello Brus,
I am not sure of limitations; but I would not be surprised if that many lines may have problems. I am generally nervous about transactions that have more than 1,000 lines.
Marty
While transforming Invoice into Customer payment using script, rather than posting to Bank account system is posting it to Undeposited funds account. Tried setting ‘undepfunds’ as ‘F’ worked in Sandbox but not in Production. Any comments/suggestions here?
Hello Avinash,
I recommend you let payment methods drive the selection of Undeposited Funds vs. specific accounts. This way you won’t have issues with the logic possibly being off due to internal IDs.
Marty