This code processes subscription data by categorizing rate plans into product types and extracting account-specific information, including the latest charges and contact details.
npm run import -- "zuora eloqua mapper"
var moment = require('moment');
var _ = require('lodash');
var chrono = require('chrono-node');
function mapRatePlanToProduct(description) {
description = description.toLowerCase();
if(description.includes('trial'))
return 'trial';
else if (description.includes('volume') || description.includes('discount'))
return 'discount';
else if (description.includes('cloud') && !description.includes('trial'))
return 'actpremiumcloud';
else if (description.includes('premium') && !description.includes('cloud')
&& !description.includes('trial') && !description.includes('support'))
return 'actpremium';
else if (description.includes('pro') && !description.includes('support'))
return 'actpro';
else if (description.includes('support'))
return 'support';
else if (description.includes('handheld') || description.includes('contact'))
return 'handheld';
else if (description.includes('aem'))
return 'aem';
else if (description.includes('password'))
return 'password';
else if (description.includes('training'))
return 'training';
else throw new Error('product not recognized ' + description);
}
function mapDataToFields(records) {
var uniqueIds = _.groupBy(records, r => r['Account.Id']);
return Object.keys(uniqueIds).map(k => {
const rpcs = _.groupBy(uniqueIds[k], r => r['RatePlanCharge.Id']);
const charges = Object.keys(rpcs).map(k => _.sortBy(rpcs[k], r => r['RatePlanCharge.Version']).pop());
const record = {};
charges.sort((a, b) =>
chrono.parseDate(b['Subscription.TermEndDate']).getTime()
- chrono.parseDate(a['Subscription.TermEndDate']).getTime());
// contact information
const contact = charges.filter(charge => charge['SoldToContact.WorkEmail'] || charge['BillToContact.WorkEmail'])[0]
if(typeof contact === 'undefined') {
console.log('No contact information for ' + JSON.stringify(charges));
return;
}
record['EmailAddress'] = contact['SoldToContact.WorkEmail'] || contact['BillToContact.WorkEmail'];
record['State'] = contact['SoldToContact.State'];
record['Country'] = contact['SoldToContact.Country'];
record['Currency'] = contact['Account.Currency'];
// primary product
const actProduct = charges.filter(p => {
const pname = mapRatePlanToProduct(p['ProductRatePlan.Name']);
return pname === 'actpremiumcloud' || pname === 'actpremium' || pname === 'actpro' || pname === 'trial'
})[0];
if(typeof actProduct !== 'undefined') {
record['ActProduct'] = mapRatePlanToProduct(actProduct['ProductRatePlan.Name']);
record['Quantity'] = actProduct['RatePlanCharge.Quantity'];
} else {
record['ActProduct'] = 'Unknown';
record['Quantity'] = 0;
}
// discounts!
const discount = charges.filter(p => {
const pname = mapRatePlanToProduct(p['ProductRatePlan.Name']);
return pname === 'discount'
})[0];
if(typeof discount !== 'undefined') {
record['Discount'] = discount['ProductRatePlan.Name'];
} else {
record['Discount'] = '';
}
// support
const support = charges.filter(charge => {
return mapRatePlanToProduct(charge['ProductRatePlan.Name']) === 'support'
})[0];
if(typeof support !== 'undefined') {
record['Support'] = support['ProductRatePlan.Name'];
record['SupportQuantity'] = support['RatePlanCharge.Quantity'];
} else {
record['Support'] = 'Unknown';
record['SupportQuantity'] = 0;
}
// subscription
const renewal = chrono.parseDate(charges[0]['Subscription.TermEndDate']);
record['RenewalsStatus'] = charges[0]['Subscription.Status'];
record['RenewalDate'] = moment(renewal).format('YYYY-MM-DD');
// card expiration
const expiration = new Date();
expiration.setDate(1);
expiration.setMonth(parseInt(charges[0]['DefaultPaymentMethod.CreditCardExpirationMonth']) - 1);
expiration.setYear(parseInt(charges[0]['DefaultPaymentMethod.CreditCardExpirationYear']));
record['CardExpiration'] = moment(expiration).format('YYYY-MM-DD');
//record['Last4DigitsOfCard'] = ((/([0-9]+)/ig).exec(charges[0]['DefaultPaymentMethod.CreditCardMaskNumber']) || [])[1];
// account data
record['RepName'] = charges[0]['Account.renewalRep__c'];
record['RORName'] = charges[0]['Account.resellerofRecord__c'];
record['RORNumber'] = ((/([0-9]+)/ig).exec(charges[0]['Account.resellerofRecord__c']) || [])[1];
record['AccountId'] = charges[0]['Account.Id'];
return record;
}).filter(r => typeof r !== 'undefined');
}
module.exports = {
mapDataToFields,
mapRatePlanToProduct
};
const moment = require('moment');
const _ = require('lodash');
const chrono = require('chrono-node');
/**
* Maps a rate plan description to a product type.
*
* @param {string} description - The rate plan description to map.
* @returns {string} The product type (e.g. 'trial', 'discount', etc.).
*/
function mapRatePlanToProduct(description) {
description = description.toLowerCase();
const typeMap = {
'trial': (d) => d.includes('trial'),
'discount': (d) => d.includes('volume') || d.includes('discount'),
'actpremiumcloud': (d) => d.includes('cloud') &&!d.includes('trial'),
'actpremium': (d) => d.includes('premium') &&!d.includes('cloud') &&!d.includes('trial') &&!d.includes('support'),
'actpro': (d) => d.includes('pro') &&!d.includes('support'),
'support': (d) => d.includes('support'),
'handheld': (d) => d.includes('handheld') || d.includes('contact'),
'aem': (d) => d.includes('aem'),
'password': (d) => d.includes('password'),
'training': (d) => d.includes('training'),
};
for (const [key, f] of Object.entries(typeMap)) {
if (f(description)) return key;
}
throw new Error(`Product not recognized: ${description}`);
}
/**
* Maps data to fields for a list of records.
*
* @param {object[]} records - The list of records to map.
* @returns {object[]} The mapped records.
*/
function mapDataToFields(records) {
const uniqueIds = _.groupBy(records, 'Account.Id');
return Object.keys(uniqueIds)
.map((k) => {
const rpcs = _.groupBy(uniqueIds[k], 'RatePlanCharge.Id');
const charges = Object.keys(rpcs)
.map((k) => _.sortBy(rpcs[k], (r) => r['RatePlanCharge.Version']).pop());
const record = {};
// Sort by expiration date
charges.sort((a, b) =>
chrono.parseDate(b['Subscription.TermEndDate']).getTime()
- chrono.parseDate(a['Subscription.TermEndDate']).getTime()
);
// Contact information
const contact = charges
.filter((charge) => charge['SoldToContact.WorkEmail'] || charge['BillToContact.WorkEmail'])
.shift();
if (!contact) {
console.log('No contact information for:', JSON.stringify(charges));
return;
}
record['EmailAddress'] = contact['SoldToContact.WorkEmail'] || contact['BillToContact.WorkEmail'];
record['State'] = contact['SoldToContact.State'];
record['Country'] = contact['SoldToContact.Country'];
record['Currency'] = contact['Account.Currency'];
// Primary product
const actProduct = charges.find((p) => [
'actpremiumcloud',
'actpremium',
'actpro',
'trial',
].includes(mapRatePlanToProduct(p['ProductRatePlan.Name'])));
if (actProduct) {
record['ActProduct'] = mapRatePlanToProduct(actProduct['ProductRatePlan.Name']);
record['Quantity'] = actProduct['RatePlanCharge.Quantity'];
} else {
record['ActProduct'] = 'Unknown';
record['Quantity'] = 0;
}
// Discounts
const discount = charges.find((p) => mapRatePlanToProduct(p['ProductRatePlan.Name']) === 'discount');
if (discount) {
record['Discount'] = discount['ProductRatePlan.Name'];
} else {
record['Discount'] = '';
}
// Support
const support = charges.find((charge) => mapRatePlanToProduct(charge['ProductRatePlan.Name']) ==='support');
if (support) {
record['Support'] = support['ProductRatePlan.Name'];
record['SupportQuantity'] = support['RatePlanCharge.Quantity'];
} else {
record['Support'] = 'Unknown';
record['SupportQuantity'] = 0;
}
// Subscription
const renewal = chrono.parseDate(charges[0]['Subscription.TermEndDate']);
record['RenewalsStatus'] = charges[0]['Subscription.Status'];
record['RenewalDate'] = moment(renewal).format('YYYY-MM-DD');
// Card expiration
const expiration = new Date();
expiration.setDate(1);
expiration.setMonth(parseInt(charges[0]['DefaultPaymentMethod.CreditCardExpirationMonth']) - 1);
expiration.setYear(parseInt(charges[0]['DefaultPaymentMethod.CreditCardExpirationYear']));
record['CardExpiration'] = moment(expiration).format('YYYY-MM-DD');
// Account data
record['RepName'] = charges[0]['Account.renewalRep__c'];
record['RORName'] = charges[0]['Account.resellerofRecord__c'];
record['RORNumber'] = ((/([0-9]+)/ig).exec(charges[0]['Account.resellerofRecord__c']) || [])[1];
record['AccountId'] = charges[0]['Account.Id'];
return record;
})
.filter((r) =>!_.isNil(r));
}
module.exports = {
mapDataToFields,
mapRatePlanToProduct,
};
This code snippet defines two functions for processing data likely retrieved from a database, possibly related to subscriptions or billing.
1. mapRatePlanToProduct(description)
:
description
string (presumably from a rate plan) as input.if
and else if
statements to map the description to a product category (e.g., "trial", "discount", "actpremiumcloud", etc.).2. mapDataToFields(records)
:
records
(likely objects containing subscription data) as input.Account.Id
using _.groupBy
from Lodash.Account.Id
and further groups the records by RatePlanCharge.Id
.RatePlanCharge
for each group (based on RatePlanCharge.Version
).record
for each account, containing the latest charges sorted by Subscription.TermEndDate
in descending order.SoldToContact.WorkEmail
or BillToContact.WorkEmail
) and logs a message if no contact information is found.In essence:
This code snippet processes subscription data, categorizes rate plans into product types, and extracts relevant information for each account, including the latest charges and contact details.