Meditrack Subscription Map/Reduce script

Type Record Subscription created:

Mpa/Reduce Script after creating deploy it.

After Deploying it we need to scedule it:

/**
 * @NApiVersion 2.1
 * @NScriptType MapReduceScript
 */
define(['N/search', 'N/record', 'N/runtime', 'N/format', 'N/log', 'N/email'], function (search, record, runtime, format, log, email) {


    function getInputData() {
        try {
            // Get today's date
            var today = new Date();
            var formattedDate = format.format({ value: today, type: format.Type.DATE });
            log.debug('formattedDate', formattedDate);


            // Create a combined search for subscriptions that need initializing or billing today
            return search.create({
                type: "customrecord_meditrack_subscription",
                filters: [
                    ["custrecord_activation_date", "isempty", ""],
                    "or",
                    ["custrecord_next_billing_date", "on", formattedDate]
                ],
                columns: [
                    search.createColumn({ name: "id", label: "ID" }),
                    search.createColumn({ name: "custrecord_subscription_customer", label: "Customer" }),
                    search.createColumn({ name: "custrecord_subscription_item", label: "Item" }),
                    search.createColumn({ name: "custrecord_activation_date", label: "Activation Date" })
                ]
            });
        } catch (e) {
            log.error("Error in getInputData", e);
            return [];
        }
    }


    function map(context) {
        var searchResult = JSON.parse(context.value);
        context.write({
            key: searchResult.id,
            value: searchResult
        });
    }


    function reduce(context) {
        try {
            log.debug("Context", context);
            var searchResult = JSON.parse(context.values[0]);
            log.debug("Search Result", searchResult);


            var recordId = searchResult.id;
            var customerId = searchResult.values.custrecord_subscription_customer.value;
            var activationDate = searchResult.values.custrecord_activation_date;
            log.debug("Record ID", recordId);
            log.debug("Customer ID", customerId);
            log.debug("Activation Date", activationDate);


            if (!customerId) {
                log.error("Missing Customer ID", "Subscription record " + recordId + " has no customer associated.");
                return;
            }


            // Run the saved search to check for the customer's default credit card state and addresses
            var customerSearchObj = search.create({
                type: "customer",
                filters: [
                    ["internalid", "anyof", customerId],
                    "AND",
                    ["ccdefault", "is", "T"]
                ],
                columns: [
                    search.createColumn({ name: "ccdefault", label: "Default Credit Card" }),
                    search.createColumn({ name: "ccstate", label: "Credit Card State" }),
                    search.createColumn({ name: "isdefaultbilling", label: "Default Billing Address" }),
                    search.createColumn({ name: "isdefaultshipping", label: "Default Shipping Address" })
                ]
            });
            var searchResultCount = customerSearchObj.runPaged().count;
            log.debug("customerSearchObj result count", searchResultCount);


            var ccStateExpired = false;
            var hasDefaultBilling = false;
            var hasDefaultShipping = false;


            customerSearchObj.run().each(function (result) {
                var ccState = result.getValue({ name: "ccstate" });
                var defaultBilling = result.getValue({ name: "isdefaultbilling" });
                var defaultShipping = result.getValue({ name: "isdefaultshipping" });
                log.debug("Credit Card State", ccState);
                log.debug("Default Billing Address", defaultBilling);
                log.debug("Default Shipping Address", defaultShipping);


                if (ccState === "4") {
                    ccStateExpired = true;
                }
                if (defaultBilling === true) {
                    hasDefaultBilling = true;
                }
                if (defaultShipping === true) {
                    hasDefaultShipping = true;
                }
                return true; // .run().each has a limit of 4,000 results
            });


            var meditrackRecord = record.load({
                type: 'customrecord_meditrack_subscription',
                id: recordId
            });


            var holdReason = 'No default credit card or credit card is expired or missing default billing/shipping address.';
            if (searchResultCount === 0 || ccStateExpired || !hasDefaultBilling || !hasDefaultShipping) {
                meditrackRecord.setValue({
                    fieldId: 'custrecord_status',
                    value: '4' // status indicating missing or invalid credit card information or addresses
                });
                meditrackRecord.setValue({
                    fieldId: 'custrecord_hold_reason',
                    value: holdReason
                });
                meditrackRecord.save();


                // Send email to the customer
                var customerRecord = record.load({
                    type: record.Type.CUSTOMER,
                    id: customerId
                });
                var customerEmail = customerRecord.getValue({ fieldId: 'email' });


                var processedCustomers = runtime.getCurrentScript().getParameter({ name: 'custscript_processed_customers' }) || [];


                if (customerEmail && !processedCustomers.includes(customerId)) {
                    email.send({
                        author: '1768',
                        recipients: customerEmail,
                        subject: 'Subscription Cancellation Notice',
                        body: 'Dear Customer,<br/><br/>Your Medi-Track subscription has been cancelled due to the following reason:<br/>' + holdReason + '<br/><br/>Please update your payment and address information for enabling subscription in the future.<br/><br/>Thank you.'
                    });
                    log.debug('Email Sent', 'Subscription cancellation email sent to Customer ID: ' + customerId);


                    // Add to processed customers list
                    processedCustomers.push(customerId);
                    runtime.getCurrentScript().setParameter({ name: 'custscript_processed_customers', value: processedCustomers });
                } else if (!customerEmail) {
                    log.error('Email Not Sent', 'No email address found for Customer ID: ' + customerId);
                }


                log.error('Invalid Payment Information or Address', 'No default credit card, credit card is expired, or missing default billing/shipping address for Customer ID: ' + customerId);
                return;
            }


            var currentDate = new Date();
            var nextBillingDate = new Date();
            nextBillingDate.setDate(nextBillingDate.getDate() + 30);


            if (!activationDate) {
                // Initialize the subscription record
                meditrackRecord.setValue({
                    fieldId: 'custrecord_activation_date',
                    value: currentDate
                });
                meditrackRecord.setValue({
                    fieldId: 'custrecord_last_billing_date',
                    value: currentDate
                });
                meditrackRecord.setValue({
                    fieldId: 'custrecord_next_billing_date',
                    value: nextBillingDate
                });
                meditrackRecord.setValue({
                    fieldId: 'custrecord_subscription_item',
                    value: 2207 // static item value
                });
                log.debug('Subscription Initialized', 'Record ID: ' + recordId);
            }


            var status = meditrackRecord.getValue({ fieldId: 'custrecord_status' });
            log.debug('status', status);
            // Check if the subscription status is 4, if so, skip sales order creation
            if (status === '2' || status === '4') {
                log.debug("Skipping Sales Order Creation", "Subscription record " + recordId + " has a status of InActive or Cancelled.");
                return;
            }


            // Create a sales order for the subscription
            var salesOrder = record.create({
                type: record.Type.SALES_ORDER,
                isDynamic: true
            });
            salesOrder.setValue({ fieldId: 'entity', value: customerId });
            salesOrder.setValue({ fieldId: 'trandate', value: currentDate });
            salesOrder.selectNewLine({ sublistId: 'item' });
            salesOrder.setCurrentSublistValue({
                sublistId: 'item',
                fieldId: 'item',
                value: 2207 // static item value
            });
            salesOrder.setCurrentSublistValue({
                sublistId: 'item',
                fieldId: 'quantity',
                value: 1
            });
            salesOrder.commitLine({ sublistId: 'item' });
            var salesOrderId = salesOrder.save({ ignoreMandatoryFields: true });
            log.debug('Sales Order Created', 'Sales Order ID: ' + salesOrderId);


            // Update the subscription record for the next billing cycle
            meditrackRecord.setValue({
                fieldId: 'custrecord_last_billing_date',
                value: currentDate
            });
            nextBillingDate = new Date();
            nextBillingDate.setDate(nextBillingDate.getDate() + 30);
            meditrackRecord.setValue({
                fieldId: 'custrecord_next_billing_date',
                value: nextBillingDate
            });


            // Create a subscription order record
            var subscriptionOrderRecord = record.create({
                type: 'customrecord_subscription_orders'
            });
            subscriptionOrderRecord.setValue({
                fieldId: 'custrecord_sub_link',
                value: recordId
            });
            subscriptionOrderRecord.setValue({
                fieldId: 'custrecord_sales_orders',
                value: salesOrderId
            });
            var subscriptionOrderRecordId = subscriptionOrderRecord.save();
            log.debug('Subscription Order Record Created', 'Subscription Order Record ID: ' + subscriptionOrderRecordId);


            // Set the status to active for both conditions
            meditrackRecord.setValue({
                fieldId: 'custrecord_status',
                value: '1' // active status
            });
            meditrackRecord.setValue({
                fieldId: 'custrecord_hold_reason',
                value: ''
            });
            meditrackRecord.save();


            // Verify that the status was set correctly
            meditrackRecord = record.load({
                type: 'customrecord_meditrack_subscription',
                id: recordId
            });
            var statusValue = meditrackRecord.getValue({ fieldId: 'custrecord_status' });
            log.debug('Updated Status', 'Status Value: ' + statusValue);


        } catch (e) {
            log.error("Error in reduce", e);
        }
    }


    function summarize(summary) {
        log.audit('Summary', summary);
    }


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

Leave a comment

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