mirror of
https://github.com/jambonz/jambonz-api-server.git
synced 2026-11-09 04:49:01 +00:00
merge of features from hosted branch (#7)
major merge of features from the hosted branch that was created temporarily during the initial launch of jambonz.org
This commit is contained in:
1 parent
ab7c69c0e8
commit
ed51d8b13f
105 files changed
+10330
-1601
No files matched your search
@@ -1,10 +1,57 @@
|
||||
const debug = require('debug')('jambonz:api-server');
|
||||
const Model = require('./model');
|
||||
const {getMysqlConnection} = require('../db');
|
||||
const {promisePool} = require('../db');
|
||||
const uuid = require('uuid').v4;
|
||||
const {encrypt} = require('../utils/encrypt-decrypt');
|
||||
|
||||
const retrieveSql = `SELECT * from accounts acc
|
||||
LEFT JOIN webhooks AS rh
|
||||
ON acc.registration_hook_sid = rh.webhook_sid`;
|
||||
|
||||
const insertPendingAccountSubscriptionSql = `INSERT account_subscriptions
|
||||
(account_subscription_sid, account_sid, pending, stripe_subscription_id,
|
||||
stripe_payment_method_id, last4, exp_month, exp_year, card_type)
|
||||
VALUES (?,?,1,?,?,?,?,?,?)`;
|
||||
|
||||
const activateSubscriptionSql = `UPDATE account_subscriptions
|
||||
SET pending=0, effective_start_date = CURRENT_TIMESTAMP, stripe_subscription_id = ?
|
||||
WHERE account_subscription_sid = ?
|
||||
AND pending=1`;
|
||||
|
||||
const queryPendingSubscriptionSql = `SELECT * FROM account_subscriptions
|
||||
WHERE account_sid = ?
|
||||
AND effective_end_date IS NULL
|
||||
AND pending=1`;
|
||||
|
||||
const deactivateSubscriptionSql = `UPDATE account_subscriptions
|
||||
SET pending=1, pending_reason = ?
|
||||
WHERE account_sid = ?
|
||||
AND effective_end_date IS NULL
|
||||
AND pending=0`;
|
||||
|
||||
const updatePaymentInfoSql = `UPDATE account_subscriptions
|
||||
SET last4 = ?, exp_month = ?, exp_year = ?, card_type = ?
|
||||
WHERE account_sid = ?
|
||||
AND effective_end_date IS NULL`;
|
||||
|
||||
const insertAccountProductsSql = `INSERT account_products
|
||||
(account_product_sid, account_subscription_sid, product_sid, quantity)
|
||||
VALUES (?,?,?,?);
|
||||
`;
|
||||
|
||||
const replaceOldSubscriptionSql = `UPDATE account_subscriptions
|
||||
SET effective_end_date = CURRENT_TIMESTAMP, change_reason = ?
|
||||
WHERE account_sid = ?
|
||||
AND effective_end_date IS NULL
|
||||
AND account_subscription_sid <> ?`;
|
||||
|
||||
const retrieveActiveSubscriptionSql = `SELECT *
|
||||
FROM account_subscriptions
|
||||
WHERE account_sid = ?
|
||||
AND effective_end_date IS NULL
|
||||
AND pending = 0`;
|
||||
|
||||
function transmogrifyResults(results) {
|
||||
return results.map((row) => {
|
||||
const obj = row.acc;
|
||||
@@ -73,6 +120,111 @@ class Account extends Model {
|
||||
});
|
||||
}
|
||||
|
||||
static async updateStripeCustomerId(sid, customerId) {
|
||||
await promisePool.execute(
|
||||
'UPDATE accounts SET stripe_customer_id = ? WHERE account_sid = ?',
|
||||
[customerId, sid]);
|
||||
}
|
||||
|
||||
static async getSubscription(sid) {
|
||||
const [r] = await promisePool.execute(retrieveActiveSubscriptionSql, [sid]);
|
||||
debug(r, `Account.getSubscription ${sid}`);
|
||||
return r.length > 0 ? r[0] : null;
|
||||
}
|
||||
|
||||
static async deactivateSubscription(logger, account_sid, reason) {
|
||||
logger.debug('deactivateSubscription');
|
||||
|
||||
/**
|
||||
* Two cases:
|
||||
* (1) A subscription renewal fails. In this case we deactivate subscription
|
||||
* and the customer is down until they provide payment.
|
||||
* (2) A customer adds capacity during the month, and the pro-rated amount fails.
|
||||
* In this case, we leave the new subscription in a pending state
|
||||
* The customer continues (for the rest of the month at least) at
|
||||
* previous capacity levels.
|
||||
*/
|
||||
const [r] = await promisePool.query(queryPendingSubscriptionSql, account_sid);
|
||||
if (r.length > 0) {
|
||||
/* leave new subscription pending */
|
||||
await promisePool.execute(
|
||||
'UPDATE account_subscriptions set pending_reason = ? WHERE account_subscription_sid = ?',
|
||||
[reason, r[0].account_subscription_sid]);
|
||||
logger.debug('deactivateSubscription - leave pending subscription in pending state');
|
||||
}
|
||||
else {
|
||||
/* deactivate their current active subscription */
|
||||
const [r] = await promisePool.execute(deactivateSubscriptionSql, [reason, account_sid]);
|
||||
logger.debug('deactivateSubscription - deactivated subscription; customer will not have service');
|
||||
return 1 == r.affectedRows;
|
||||
}
|
||||
}
|
||||
|
||||
static async activateSubscription(logger, account_sid, subscription_id, reason) {
|
||||
logger.debug('activateSubscription');
|
||||
|
||||
const [r] = await promisePool.query(queryPendingSubscriptionSql, account_sid);
|
||||
if (0 === r.length) return false;
|
||||
|
||||
const [r2] = await promisePool.execute(activateSubscriptionSql,
|
||||
[subscription_id, r[0].account_subscription_sid]);
|
||||
if (0 === r2.affectedRows) return false;
|
||||
|
||||
/* disable the old subscription, if any */
|
||||
const [r3] = await promisePool.execute(replaceOldSubscriptionSql, [
|
||||
reason, account_sid, r[0].account_subscription_sid]);
|
||||
debug(r3, 'Account.activateSubscription - replaced old subscription');
|
||||
|
||||
/* update account.plan to paid, if it isnt already */
|
||||
await promisePool.execute(
|
||||
'UPDATE accounts SET plan_type = \'paid\' WHERE account_sid = ?',
|
||||
[account_sid]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static async updatePaymentInfo(logger, account_sid, pm) {
|
||||
const {card} = pm;
|
||||
const last4_encrypted = encrypt(card.last4);
|
||||
await promisePool.execute(updatePaymentInfoSql,
|
||||
[last4_encrypted, card.exp_month, card.exp_year, card.brand, account_sid]);
|
||||
}
|
||||
|
||||
static async provisionPendingSubscription(logger, account_sid, products, payment_method, subscription_id) {
|
||||
logger.debug('provisionPendingSubscription');
|
||||
const account_subscription_sid = uuid();
|
||||
const {id, card} = payment_method;
|
||||
|
||||
/* add a row to account_subscription */
|
||||
let last4_encrypted = null;
|
||||
if (card) {
|
||||
last4_encrypted = encrypt(card.last4);
|
||||
}
|
||||
const [r] = await promisePool.execute(insertPendingAccountSubscriptionSql, [
|
||||
account_subscription_sid,
|
||||
account_sid,
|
||||
subscription_id || null,
|
||||
id,
|
||||
last4_encrypted,
|
||||
card ? card.exp_month : null,
|
||||
card ? card.exp_year : null,
|
||||
card ? card.brand : null
|
||||
]);
|
||||
debug(r, 'Account.activateSubscription - insert account_subscriptions');
|
||||
if (r.affectedRows !== 1) {
|
||||
throw new Error(`failed inserting account_subscriptions for accunt_sid ${account_sid}`);
|
||||
}
|
||||
|
||||
/* add a row for each product to account_products */
|
||||
await Promise.all(products.map((product) => {
|
||||
const {product_sid, quantity} = product;
|
||||
const account_products_sid = uuid();
|
||||
return promisePool.execute(insertAccountProductsSql, [
|
||||
account_products_sid, account_subscription_sid, product_sid, quantity
|
||||
]);
|
||||
}));
|
||||
return account_subscription_sid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Account.table = 'accounts';
|
||||
@@ -103,6 +255,30 @@ Account.fields = [
|
||||
{
|
||||
name: 'device_calling_application_sid',
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: 'is_active',
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
name: 'created_at',
|
||||
type: 'date',
|
||||
},
|
||||
{
|
||||
name: 'plan_type',
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: 'stripe_customer_id',
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: 'webhook_secret',
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: 'disable_cdrs',
|
||||
type: 'number',
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
Reference in new issue
Block a user