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
}
}
);