23maverick23
5/16/2016 - 1:53 PM

NSOA: Create Invoice Holdback (form, afterSave)

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 + '%');
}