Autoship (Flow-2): Order Generation

Solution documented here: https://jobinandjismi.in/wp-admin/post.php?post=26914&action=edit

/**
 * @NApiVersion 2.x
 * @NScriptType MapReduceScript
 * @NModuleScope SameAccount
 * 
 * REVISION HISTORY
 * ***********************************************************************************************************************************************
 *
 * Revision 1.0 ${01/02/2023} : Script diluted to only have sales order generation. So Second generation line record creation is moved to another 
 * MR script. This is to handle erroneous genration of second set of line records for primary line records without a SO reference.
 * 
 */

define( [ 'N/record', 'N/search', './moment.js' ],

    /**
     * @param {record} record
     * @param {search} search
     */
    function ( record, search, moment )
    {

        /* CUSTOM RECORD IDS */
        const _AUTOSHIP_MASTER_RECORD = "customrecord_vv_autoship_customer";
        const _AUTOSHIP_LINE_RECORD = "customrecord_vv_autoship_record";
        /* CUSTOM RECORD IDS */

        /* SO RECORD FIELDS */
        const _SO_ITEM = "item";
        const _SO_DISCOUNT_ITEM = "custcol_autoship_line_discount_item";
        const _SO_RATE = "rate";
        const _SO_DATE = "trandate"
        const _SO_AMOUNT = "amount";
        const _SO_QUANTITY = "quantity";
        const _SO_INTERVAL = "custcol_vv_so_line_autoship_interval";
        const _SO_FREQUENCY = "custcol_vv_so_line_autoship_frequency";
        const _SO_IS_RX_ITEM = "custcol_vv_is_rx_item";
        const _SO_VET_AUTH = "custcol_vvs_vetauth";
        const _SO_AUTOSHIP_ITEM = "custcol_vv_so_line_autoship_item";
        const _SO_AUTOSHIP_CREATED = "custcol_vv_so_line_autoship_created";
        const _SO_PRESCRIPTION = "custcol_vv_so_prescription";
        const _SO_VET = "custcol_vv_so_vet";
        const _SO_PET = "custcol_vv_so_pet";
        const _SO_LINE_UNIQUE_KEY = "lineuniquekey";
        const _SO_INITIAL_AUTOSHIP_LINE = "custcol_vv_so_initial_autoship_line";
        const _SO_DATE_PRESC_LINKED = "custcol_vv_ue_date_linked";
        const _SO_LINKED_AUTO_SHIP_LINE = "custcol_vv_linked_autoship_line"; //added per task 176811172
        const _SO_PRESCRIPTION_ITEM = "custcol_vv_prescription_item_id"; //added per task 176811172
        const _SO_INSTRUCTIONS = "custbody_vv_webstore_instructions.CUSTRECORD_VV_AUTOSHIP_SOREF"; //added per task 176099397
        const _SO_INITIAL_SHIP_METHOD = "custcol_vv_ship_method_initial"
        const _SO_PAYMENT_OPTION = "paymentoption"
        const _SO_STATUS = "orderstatus"
        const _SO_CATALOG_TYE = "custbody_catalog_name"
        const _SO_ORDER_TYPE = "custbody_sales_attribution"
        //const _SO_DISCOUNT_ITEM = "item.CUSTRECORD_VV_AUTOSHIP_SOREF"; //added per task 176099397

        const _SO_IS_AUTOSHIP_GENERATED = 'custbody_autoshipgenerated' //INTRODUCED FLAGGING IN FIELD SO TO UNDERSTAND THE SO IS CREATED FROM AUTOSHIP, for story https://www.pivotaltracker.com/story/show/181989624
        /* SO RECORD FIELDS */

        /* CUSTOM RECORD FIELDS */
        const _CR_AUTOSHIP_MASTER_CUSTOMER = "custrecord_vv_autoship_customer";
        const _CR_ITEM = "custrecord_vv_autoship_item"
        const _CR_DISCOUNT_ITEM = "custrecord_vv_discountitem"
        const _CR_QUANTITY = "custrecord_vv_autoship_quantity"
        const _CR_FREQUENCY = "custrecord_vv_autoship_freq"
        const _CR_RATE = "custrecord_vv_autoship_rate"
        const _CR_AMOUNT = "custrecord_vv_autoship_amount"
        const _CR_INTERVAL = "custrecord_vv_autoship_interval"
        const _CR_TERMINATE = "custrecord_vv_autoship_terminate"
        const _CR_RX_ITEM = "custrecord_vv_autoship_rxitem"
        const _CR_AUTOSHIP_CUSTOMER = "custrecord_vv_autoship_customer_id"
        const _CR_SO_REFERENCE = "custrecord_vv_autoship_soref"
        const _CR_ADD_ON = "custrecord_vv_autoship_addon"
        const _CR_AUTO_SHIP_DATE = "custrecord_vv_autoship_date"
        const _CR_NEXT_SHIP_DATE = "custrecord_vv_autoship_nextshipdate"
        const _CR_PET = "custrecord_vv_autoship_pet"
        const _CR_PRESCRIPTION = "custrecord_vv_autoship_prescription"
        const _CR_VET = "custrecord_vv_autoship_vet"
        const _CR_VET_AUTH = "custrecord_vv_autoship_vetauthmaster"
        const _CR_RX_ORDER_STATUS = "custrecord_vv_autoship_rxorderstatus"
        const _CR_LINE_UNIQUE_KEY = "custrecord_vv_autoship_line_unique_key";
        const _CR_IS_AUTOSHIP_ITEM = "custrecord_vv_is_autoship_item";
        const _CR_SHIPPING_ADDRESS = "custrecord_vv_autoship_shipping_address";
        const _CR_PAYMENT_CARD_TOKEN = "custrecord_vv_payment_card_token";
        /* CUSTOM RECORD FIELDS */

        const _APPROVED = "2";
        const _UPS_GROUND = "263746"
        const _PENDING_FULFILLMENT = 'B'
        const _ORDER_TYPE_WEB = 3
        const _CATALOG_TYPE_WEB = 4

        function getInputData ()
        {
            return search.load( { id: "customsearch_vv_autoship_today_2" } ) // SEARCH: VVS Autoship Date Test (**DO NOT DELETE - USED IN SCRIPT**).
        }

        /**
         * Executes when the map entry point is triggered and applies to each key/value pair.
         * @param {MapSummary} context - Data collection containing the key/value pairs to process through the map stage
         * @since 2015.1
         */
        function map ( context )
        {
            try
            {
                log.debug( "Context Value", JSON.stringify( JSON.parse( context.value ) ) );

                var contextVal = JSON.parse( context.value );

                var objTemp = {
                    strAutoShipLineId: context.key,
                    strItem: contextVal.values[ _CR_ITEM ].value,
                    strDscntItem: contextVal.values[ _CR_DISCOUNT_ITEM ].value,
                    flQuantity: parseFloat( contextVal.values[ _CR_QUANTITY ] ) || 0,
                    intFrequency: parseInt( contextVal.values[ _CR_FREQUENCY ] ),
                    strInterval: contextVal.values[ _CR_INTERVAL ].value,
                    boolAddOn: contextVal.values[ _CR_ADD_ON ] == "F" ? false : true,
                    dtTrandate: contextVal.values[ _CR_NEXT_SHIP_DATE ],
                    strVet: contextVal.values[ _CR_VET ].value,
                    strPet: contextVal.values[ _CR_PET ].value,
                    strVetAuth: contextVal.values[ _CR_VET_AUTH ].value,
                    boolRXItem: contextVal.values[ _CR_RX_ITEM ] == "F" ? false : true,
                    boolIsAutoShip: contextVal.values[ _CR_IS_AUTOSHIP_ITEM ] == "F" ? false : true,
                    strSORef: contextVal.values[ _CR_SO_REFERENCE ].value || null,
                    strPrescriptionId: contextVal.values[ _CR_PRESCRIPTION ].value || null,
                    strShippingAddress: contextVal.values[ _CR_SHIPPING_ADDRESS ].value || null,
                    strInstructions: contextVal.values[ _SO_INSTRUCTIONS ],
                    dtAutoTrandate: contextVal.values[ _CR_AUTO_SHIP_DATE ],
                    stRate: contextVal.values[ _CR_RATE ],
                    paymentToken: contextVal.values[ _CR_PAYMENT_CARD_TOKEN ].value || null
                };

                log.debug( "objTemp", JSON.stringify( objTemp ) );

                context.write( contextVal.values[ "custrecord_vv_autoship_customer.CUSTRECORD_VV_AUTOSHIP_CUSTOMER_ID" ].value, objTemp )
            } catch ( e )
            {
                log.debug( "Err", e )
                log.error( "Err", e )
            }

        }

        /**
         * Executes when the reduce entry point is triggered and applies to each group.
         * @param {ReduceSummary} context - Data collection containing the groups to process through the reduce stage
         * @since 2015.1
         */
        function reduce ( context )
        {
            log.debug( "Customer ID = " + context.key );
            try
            {
                log.debug( "ENTER createSalesOrderAndUpdateAutoShipLineRecord" )
                createSalesOrderAndUpdateAutoShipLineRecord( context );

            } catch ( e )
            {
                log.debug( "ENTERED ERROR REDUCE", e )
                log.error( "ENTERED ERROR REDUCE", e );
                try
                {
                    createSalesOrderAndUpdateAutoShipLineRecord( context );

                }
                catch ( err )
                {
                    log.debug( "Error in reduce", err )
                    log.error( "Error in reduce", err )
                }

            }
        }

        function createSalesOrderAndUpdateAutoShipLineRecord ( context )
        {
            try
            {
                var objAutoShipsByShipAddress = {};
                //group the SOs with different shipping addresses
                for ( var index = 0; index < context.values.length; index++ )
                {
                    var objData = JSON.parse( context.values[ index ] );

                    if ( !objAutoShipsByShipAddress.hasOwnProperty( objData.strShippingAddress ) )
                    {
                        log.debug( "objData1", objData )
                        // log.debug( "objData1.strShippingAddress", objData.strShippingAddress )
                        objAutoShipsByShipAddress[ objData.strShippingAddress ] = [];
                    }
                    log.debug( "objData2", objData )
                    //log.debug( "objData2.strShippingAddress", objData.strShippingAddress )
                    objAutoShipsByShipAddress[ objData.strShippingAddress ].push( objData );
                }

                var autoshipIdArray = [];
                for ( var itr in objAutoShipsByShipAddress )
                {
                    log.debug( "itr", itr )
                    var stSalesOrderRec = record.create( { type: record.Type.SALES_ORDER, defaultValues: { entity: context.key } } );
                    stSalesOrderRec.setValue( { fieldId: "shipaddresslist", value: itr } );

                    //INTRODUCED FLAGGING IN FIELD SO TO UNDERSTAND THE SO IS CREATED FROM AUTOSHIP

                    stSalesOrderRec.setValue( { fieldId: _SO_IS_AUTOSHIP_GENERATED, value: true } );
                    stSalesOrderRec.setValue( { fieldId: _SO_STATUS, value: _PENDING_FULFILLMENT } );
                    stSalesOrderRec.setValue( { fieldId: _SO_CATALOG_TYE, value: _CATALOG_TYPE_WEB } );
                    stSalesOrderRec.setValue( { fieldId: _SO_ORDER_TYPE, value: _ORDER_TYPE_WEB } );

                    for ( var index = 0; index < objAutoShipsByShipAddress[ itr ].length; index++ )
                    {
                        var arrAutoShips = objAutoShipsByShipAddress[ itr ]
                        if ( index == 0 )
                        {
                            stSalesOrderRec.setValue( { fieldId: "custbody_vv_webstore_instructions", value: arrAutoShips[ index ].strInstructions } );
                        }
                        log.debug( "arrAutoShips[ index ].paymentToken", arrAutoShips[ index ].paymentToken )

                        if ( arrAutoShips[ index ].paymentToken )
                        {
                            stSalesOrderRec.setValue( { fieldId: _SO_PAYMENT_OPTION, value: arrAutoShips[ index ].paymentToken } );
                        }

                        //set transaction date = AUTO SHIP DATE (A1)
                        var autoshipDate = arrAutoShips[ index ].dtAutoTrandate
                        if ( autoshipDate )
                        {
                            log.debug( "dtAutoTrandate- autoshipDate", autoshipDate )

                            var newautoshipDate = moment( autoshipDate ).format( "M/D/YYYY" )
                            log.debug( "dtAutoTrandate- newautoshipDate", newautoshipDate )

                            stSalesOrderRec.setValue( { fieldId: _SO_DATE, value: new Date( autoshipDate ) } );
                        }

                        stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_ITEM, value: arrAutoShips[ index ].strItem, line: index } )
                        stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_DISCOUNT_ITEM, value: arrAutoShips[ index ].strDscntItem || null, line: index } ) /
                            stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_QUANTITY, value: arrAutoShips[ index ].flQuantity, line: index } )
                        stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_RATE, value: arrAutoShips[ index ].stRate, line: index } )
                        stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_FREQUENCY, value: arrAutoShips[ index ].intFrequency, line: index } )
                        stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_INTERVAL, value: arrAutoShips[ index ].strInterval, line: index } )

                        if ( arrAutoShips[ index ].boolRXItem )
                        {
                            stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_PET, value: arrAutoShips[ index ].strPet, line: index } )
                            stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_VET, value: arrAutoShips[ index ].strVet, line: index } )
                            stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_VET_AUTH, value: arrAutoShips[ index ].strVetAuth, line: index } )
                        }

                        stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_AUTOSHIP_ITEM, value: arrAutoShips[ index ].boolIsAutoShip, line: index } )
                        stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_LINKED_AUTO_SHIP_LINE, value: arrAutoShips[ index ].strAutoShipLineId, line: index } ) //added per task 176811172
                        //PG 10/27/2021 Task ID: #180052385 https://www.pivotaltracker.com/n/projects/2344928/stories/180052385/comments/227616719
                        //if the ship method is set for this sales order, then use that, else set to UPS Ground.
                        if ( stSalesOrderRec.getSublistValue( { sublistId: "item", fieldId: "custcol_vv_ship_method", line: index } ) )
                        {
                            stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_INITIAL_SHIP_METHOD, value: stSalesOrderRec.getSublistValue( { sublistId: "item", fieldId: "custcol_vv_ship_method", line: index } ), line: index } )
                        } else
                        {
                            stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_INITIAL_SHIP_METHOD, value: _UPS_GROUND, line: index } )
                        }

                        //means this doesn't came from an SO/this came from a future dated autoship
                        //use Sales order reference to determine whether it is a future dated autoship line
                        //if it is a future dated autoship line, we should set the initial autoship line on the SO so that it
                        //doesnt create another autoship line and the user event will update the line unique key + SO reference + next ship date
                        if ( arrAutoShips[ index ].strSORef === "" || arrAutoShips[ index ].strSORef === null )
                        {
                            stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_PRESCRIPTION, value: arrAutoShips[ index ].strPrescriptionId, line: index } )
                            /** ADDED PG 3/30/2021 
                             * Include the prescription item id on the sales order line for task #177272483
                            */
                            if ( arrAutoShips[ index ].strPrescriptionId != null && arrAutoShips[ index ].strPrescriptionId != "" )
                            {
                                stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_PRESCRIPTION_ITEM, value: getPrescriptionItem( arrAutoShips[ index ].strPrescriptionId, arrAutoShips[ index ].strItem ), line: index } )
                            }
                            /** ADDED PG END */
                            stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_DATE_PRESC_LINKED, value: new Date(), line: index } ) //KKJS 02-15-21
                            stSalesOrderRec.setSublistValue( { sublistId: "item", fieldId: _SO_INITIAL_AUTOSHIP_LINE, value: arrAutoShips[ index ].strAutoShipLineId, line: index } )
                        }

                        log.debug( "objAutoShipsByShipAddress", JSON.stringify( arrAutoShips[ index ] ) )

                    }
                    var stSalesOrderId = stSalesOrderRec.save( { ignoreMandatoryFields: true } );
                    log.debug( "SALES ORDER CREATED = " + stSalesOrderId )

                    if ( stSalesOrderId )
                    {
                        log.debug( "autoshipIdArray", autoshipIdArray )
                    }
                }
                return autoshipIdArray;
            } catch ( Err )
            {
                log.debug( "Error@createSalesOrderAndUpdateAutoShipLineRecord", Err )
                log.error( "Error@createSalesOrderAndUpdateAutoShipLineRecord", Err )
            }
        }


        function summarize ( summary )
        {
            log.debug( "EXECUTION FINISHED", "TIME ELAPSED = " + ( summary.seconds / 60 ) + " min(s)" );
        }

        function getPrescriptionItem ( strPrescriptionId, strItem )
        {
            try
            {
                var strPrescriptionItemId = "";

                var objSearch = search.create( {
                    type: "customrecord_vv_prescription_item",
                    filters: [
                        [ "custrecord_vv_prescription_id", "anyof", strPrescriptionId ],
                        "AND",
                        [ "custrecord_vv_item_name", "anyof", strItem ]
                    ],
                    columns: [
                        search.createColumn( { name: "internalid", label: "Internal ID" } )
                    ]
                } );

                //get only the first one
                objSearch.run().each( function ( res )
                {
                    strPrescriptionItemId = res.id
                    return false;
                } );

                return strPrescriptionItemId

            } catch ( e )
            {
                log.debug( "Error@getPrescriptionItem", e )
                log.error( "Error@getPrescriptionItem", e )
            }
        }

        return {
            getInputData: getInputData,
            map: map,
            reduce: reduce,
            summarize: summarize
        }
    }
);

Leave a comment

Your email address will not be published. Required fields are marked *