NSOA: Create Invoice Holdback (form, afterSave)
/**
* Copyright NetSuite, Inc. 2014 All rights reserved.
* The following code is a demo prototype. Due to time constraints of a demo,
* the code may contain bugs, may not accurately reflect user requirements
* and may not be the best approach. Actual implementation should not reuse
* this code without due verification.
*
* Calculate a holdback amount for an invoice using a project custom field.
* Apply that holdback charge to the current invoice, and also create an
* off-setting charge that sits in a holdback stage until it is ready to
* be invoiced.
*
* Version Date Author Remarks
* 1.00 24 Sep 2015 Ryan Morrissey
*
*/
function createInvoiceHoldback() {
// get the newly saved invoice
var invoice = NSOA.form.getNewRecord(),
hold = invoice.inv_holdback__c,
holdAmtRaw = invoice.inv_holdback_amt__c;
// workaround b/c currency custom fields
// include a 3 digit ISO code after the
// currency amount
var re = /([\d\.,]+)-.\w/; // will pull digits before -ISO
var holdAmt = holdAmtRaw.match(re)[1];
// only proceed if checkbox is checked
// and holdback amount is not populated
if (hold == '1' && holdAmt == '0.00' || holdAmt == '0,00') {
// get the project id from one of the
// charges on the invoice, since it
// is not available from oaInvoice table
var slip = new NSOA.record.oaSlip();
slip.invoiceid = invoice.id;
var slipRead = {
type : 'Slip',
method : 'equal to',
fields : 'id,projectid',
attributes : [
{
name : 'limit',
value : '1'
}
],
objects : [slip]
};
NSOA.wsapi.disableFilterSet(true);
var slipResults = NSOA.wsapi.read(slipRead);
// if something went wrong finding a slip,
// abort the script
if (!slipResults || !slipResults[0].objects) {
NSOA.meta.log('error', 'Unable to find a slip with invoice id ' + newr.id);
return;
}
// get project id from slip and use it
// to lookup the holdback amount and
// service item
var project = new NSOA.record.oaProject();
project.id = slipResults[0].objects[0].projectid;
var projectRead = {
type : 'Project',
method : 'equal to',
fields : 'id,customerid,prj_holdback_percent__c,prj_holdback_service__c',
attributes : [
{
name : 'limit',
value : '1'
}
],
objects : [project]
};
NSOA.wsapi.disableFilterSet(true);
var projectResults = NSOA.wsapi.read(projectRead);
if (!projectResults || !projectResults[0].objects) {
NSOA.meta.log('error', 'Unable to find a project with id ' + newr.id);
return;
}
/**
* Now that we have information about the
* invoice and the project, we can
* calculate the holdback amounts and
* create the offsetting holdback charges.
*/
var prjRec = projectResults[0].objects[0],
holdbackDecimal = prjRec.prj_holdback_percent__c || 0.1,
holdbackPercent = convertDecimalToPercentage(holdbackDecimal),
holdbackService = prjRec.prj_holdback_service__c || 14,
customerId = prjRec.customerid,
projectId = prjRec.id,
invoiceId = invoice.id,
date = invoice.date,
currency = invoice.currency,
invTotal = invoice.total,
stageReady = '1',
stageHold = '4',
type = 'F',
holdbackAmt = round(invTotal * holdbackDecimal, 2);
// create negative holdback charge in
// "invoice ready" stage and attach
// to invoice
var slipReady = new NSOA.record.oaSlip();
slipReady.date = date;
slipReady.currency = currency;
slipReady.type = type;
slipReady.customerid = customerId;
slipReady.projectid = projectId;
slipReady.rate = holdbackAmt; // make this positive
slipReady.quantity = '-1'; // make this negative
slipReady.cost = -holdbackAmt; // make this negative
slipReady.total = -holdbackAmt; // make this negative
slipReady.invoiceid = invoiceId;
slipReady.slip_stageid = stageReady;
slipReady.categoryid = holdbackService;
slipReady.description = 'Holdback of ' + holdbackPercent + ' applied.';
// create positive holdback charge in
// "holdback" stage
var slipHold = new NSOA.record.oaSlip();
slipHold.date = date;
slipHold.currency = currency;
slipHold.type = type;
slipHold.customerid = customerId;
slipHold.projectid = projectId;
slipHold.rate = holdbackAmt;
slipHold.quantity = '1';
slipHold.cost = holdbackAmt;
slipHold.total = holdbackAmt;
slipHold.slip_stageid = stageHold;
slipHold.categoryid = holdbackService;
slipHold.description = 'Holdback of ' + holdbackPercent + ' applied.';
// update invoice with holdback amount
// and leave checkbox checked for audit
var invoiceUpdate = new NSOA.record.oaInvoice();
invoiceUpdate.id = invoice.id;
invoiceUpdate.inv_original_amt__c = invTotal;
invoiceUpdate.inv_holdback_amt__c = holdbackAmt;
// create the 2 charge records
NSOA.wsapi.disableFilterSet(true);
var newSlips = NSOA.wsapi.add([slipReady, slipHold]);
// check for errors creating new charges
if (!newSlips || !newSlips[0].id || !newSlips[1].id) {
NSOA.meta.log('error', 'Unable to create holdback charges!');
return;
}
// update the invoice if everything was successful
NSOA.wsapi.disableFilterSet(true);
var newInvoice = NSOA.wsapi.modify([{name: 'update_custom', value: '1'}], [invoiceUpdate]);
}
}
/**
* Rounds a number to the nearest specified decimal places
* @param number
* @param decimals
* @returns {Number}
*/
function round(number, decimals) {
if (isNaN(number) || isNaN(decimals)) {
return;
}
return (Math.round(number * Math.pow(10, 2)) / Math.pow(10, 2)).toFixed(decimals);
}
/**
* Converts a decimal number to percentage
* @param {String} sPercentage
* @returns
*/
function convertDecimalToPercentage(sDecimal) {
return (sDecimal * 100 + '%');
}