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