import callerId from 'caller-id';
import { ShopIdService } from 'cpb-api';
import { isArray } from 'cpb-common';
import Datastore from 'cpb-datastore';
import Shopify from 'cpb-shopify';
export const KIND_SHOPIFY_RECURRING_APPLICATION_CHARGE = 'shopify_recurring_application_charges';
export const KIND_SHOPIFY_CURRENT_APPLICATION_CHARGE = 'shopify_current_application_charge';
/**
* ### Recurring Application Charges
* @module cpb-shopify/charge
* @type {{settings: {kind: string}, getActiveChargesMonthlyTotal({test: boolean}=): Promise<number>, get(*=): Promise<Object[]>, save(*): Promise<void>,
* list({shopName: string, shopID: number}): Promise<{expired: Array(), active: undefined, shopName: string, shopID: number}>}}
*/
export const Charge = {
settings: {
kind: KIND_SHOPIFY_RECURRING_APPLICATION_CHARGE,
kindActiveCharge: 'shopify_current_application_charge',
kindTestCharge: 'shopify_current_test_application_charge',
},
/**
* ### Get All Recurring Application Charges from Shopify
* @param {string} shopName
* @param {number} [shopID] - if supplied no shopID lookup would be performed
* @param fetch
* @return {Promise<{shopName: string, shopID: number}>} charges - charge information
*/
async list({ shopName, shopID } = {}, fetch) {
let client,
id = shopID,
name = shopName;
//
if (!id || !name) {
const o = await ShopIdService.getIdName(id || name);
id = o.id;
name = o.name;
}
if (!id) {
console.error(`[shopify/charge][${shopName}] ERROR_GET_SHOPID`, callerId.getDetailedString());
// return;
}
const result = {
shopID: id,
shopName: name,
},
saveResult = [];
let charges;
try {
if (fetch) {
client = await Shopify.connect({ shopName: name });
charges = await client.recurringApplicationCharge.list();
}
} catch (error) {
console.error(`[shopify/charge][${id},${name}][${callerId.getDetailedString()}] ERROR_SHOPIFY_CONNECT`, { error });
result.error = error;
charges = [];
}
if (!charges || !charges.length) charges = await Datastore.query({ kind: this.settings.kind, filter: { shopName } });
if (!charges) {
console.warn(`[shopify/charge/list][${shopID}, ${shopName}][${callerId.getDetailedString()}] ERROR_NO_CHARGES`);
charges = [];
}
console.info(`[shopify/charge/list][${id},${name}] length:${charges.length}`);
for (const charge of charges) {
charge.shopName = name;
charge.shopID = id;
result[charge.status] = result[charge.status] || [];
result[charge.status].push(charge);
if (fetch) this.save(charge); //saveResult.push();
}
// Promise.all(saveResult).catch(console.error);
return result;
},
/***
* ### Save The Charge Information into the Datastore into following kinds:
* * `shopify_recurring_application_charges` - all charges for all shops. Keyed by **shopName+chargeID**
* * `shopify_current_application_charge` - current production charges. Keyed by **shopName**
* * `shopify_current_test_application_charge` - current test charges. Keyed by **shopName**
* @param charge
* @return {Promise<void>}
*/
// async
save(charge) {
if (!charge) throw new TypeError('!charge');
const charges = isArray(charge) ? charge : [charge],
kindAllCharges = this.settings.kind,
kindActiveCharge = this.settings.kindActiveCharge, //'shopify_current_application_charge',
kindTestCharge = this.settings.kindTestCharge; // 'shopify_current_test_application_charge';
for (const data of charges) {
console.log(`[shopify/charge/index][${data.shopName}] saveCharge::${data.status} - ${data.id}`);
if (!data.shopID || !data.shopName) throw new TypeError('MISSING_SHOP_ID_OR_NAME');
// only active charges
if (data.status === 'active')
Datastore.save({
kind: data.test === true ? kindTestCharge : kindActiveCharge,
data,
key: Datastore.datastore.key([data.test === true ? kindTestCharge : kindActiveCharge, [charge.shopName, charge.id].join()]),
useEmulator: process.env.USE_EMULATOR_DATASTORE,
}).catch(console.error);
// all charge info
Datastore.save({
kind: kindAllCharges,
data,
key: Datastore.datastore.key([kindAllCharges, [charge.shopName, charge.id].join()]),
useEmulator: process.env.USE_EMULATOR_DATASTORE,
}).catch(console.error);
}
},
/**
* ### Get Monthly Total For Active Charges
* @param {?boolean} [test=undefined] - calculate for test installs
* @returns {Promise<number>} total - monthly active charges total
*/
async getActiveChargesMonthlyTotal({ test } = {}) {
const kind = test ? this.settings.kindTestCharge : this.settings.kindActiveCharge,
querySettings = { kind, selector: 'capped_amount' },
data = await Datastore.query(querySettings);
// console.debug(data);
const total = data.map(i => +i.capped_amount).reduce((previous, current) => previous + current);
// for (const charge of data) total += +charge.capped_amount;
return Math.round(total * 100) / 100;
},
async get(filter, fetch) {
console.debug(`[cpb-shopify/charge/get]`, { filter, fetch });
return await this.list(filter, fetch).catch(console.error);
},
async getActiveCharge(idOrName, fetch) {
if (!idOrName) throw new TypeError('!idOrName');
const { name: shopName } = await ShopIdService.getIdName(idOrName),
querySettings = {
kind: this.settings.kind,
useEmulator: process.env.USE_EMULATOR_DATASTORE,
filter: { shopName, status: 'active' },
};
console.debug(`[cpb-shopify/charge.getActiveCharge]`, querySettings);
const charges = await this.get(querySettings.filter, fetch);
console.debug(`[shopify/charge/getActiveCharge]`, charges.active);
return (charges.active || [])[0];
},
};
export default Charge;