Skip to content

Instantly share code, notes, and snippets.

@endihunter
Created November 8, 2022 14:10
Show Gist options
  • Save endihunter/ecba910bc984bf1671bbcabd730101b3 to your computer and use it in GitHub Desktop.
Save endihunter/ecba910bc984bf1671bbcabd730101b3 to your computer and use it in GitHub Desktop.
Loyalty Orchestration Merchant Inclusion Flow
function main() {
// IMPORT loyalty accounts from merchant SQ1
importLoyaltyAccounts('SQ1');
// IMPORT loyalty accounts from merchant SQ2
importLoyaltyAccounts('SQ2');
// throttler that limits the # of requests up to 20rps to LoyaltyAPI and up to 100rps for FS application
// throttler will pause requests either if # or requests to LoyaltyAPI exis
// throttler is a chain of limiters:
// 1st level limiter limits requests to APIs (Loyalty, Customer, etc...) = 20RPS
// 2nd level limiter limits requests to FS app = 100RPS
const appThrottler = new Throttler(100);
// Requests added to loyaltyThrottler must follow the 20 per LoyaltyAPi and 100 per App rate limits.
const loyaltyThrottler = (new Throttler(20)).chain(appLimiter);
// Requests added to customersThrottler must follow the 15 per CustomerAPi and 100 per App rate limits.
const customersThrottler = (new Throttler(15)).chain(appLimiter);
// walk through imported accounts
// 1. create loyalty account if it missing in one of merchants
// 2. adjust points if the same loyalty account exists in both merchants: SQ1 & SQ2
const accounts = retrieveLoyaltyAccountsIterator(['SQ1', 'SQ2'])
for account in [...accounts]
// check if loyalty account exists in corresponding Merchant (no API calls)
const source = getLoyaltyAccount(account, 'SQ1');
const target = getLoyaltyAccount(account, 'SQ2');
// loyalty account exists in 'SQ1' -> replicate to 'SQ2'
if (source && !target) {
return replicateLoyaltyAccount(account, 'SQ2', source.balance);
}
// loyalty account exists in 'SQ2' -> replicate to 'SQ1'
if (target && !source) {
return replicateLoyaltyAccount(account, 'SQ1', target.balance);
}
// loyalty account exists in both square merchants -> calculate and adjust new balance
return adjustBalances(account, 'SQ1', 'SQ2');
endfor
}
function replicateLoyaltyAccount(account, targetMerchantId, balance) {
// since the time difference between calls to importLoyaltyAccounts() and current function may be significant
// we call LoyaltyApi in order to make sure there is no loyalty account created during this time range
// note: in order to reduce the Nr of API calls, we're considering to reverse the sequence,
// from: search -> on404(create)
// to: try(create) -> catch(retrieve), there is very low chance to hit the catch branch
let loyaltyAccount = loyaltyThrottler.schedule(() => LoyaltyApi.searchLoyaltyAccounts(account.phoneNumber));
if (!loyaltyAccount) {
const customer = replicatePaymentCustomer(account);
loyaltyAccount = loyaltyThrottler.schedule(() => LoyaltyApi.createLoyaltyAccount({ ...account, customerId: customer.id }));
}
if (balance !== loyaltyAccount.balance) {
const diff = balance - loyaltyAccount.balance;
loyaltyThrottler.schedule(() => LoyaltyApi.adjustPoints(loyaltyAccount, diff));
}
}
function adjustBalances(account, aMerchantId, bMerchantId) {
const balance = calculateNewBalance(account, aMerchantId, bMerchantId);
loyaltyThrottler.schedule(() => LoyaltyApi.adjustPoints(accountA, balance));
loyaltyThrottler.schedule(() => LoyaltyApi.adjustPoints(accountB, balance));
}
// replicate the Customer associated with loyalty account
function replicatePaymentCustomer(sourceLoyaltyAccount, sourceMerchantId, targetMerchantId) {
// get the original customer, assiciated with source loyalty account
const aCustomer = customersThrottler.schedule(() => CustomerApi.retrieveCustomer(sourceMerchantId, sourceLoyaltyAccount.customerId));
// replicate customer to target square merchant
return customersThrottler.schedule(() => CustomerApi.createPaymentCustomer(
targetMerchantId,
pick(sourceCustomer, 'givenName, familyName, nickname, companyName, emailAddress, address, phoneNumber, birthday, referenceId, note')
));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment