@fabrix/spool-cart
Version:
Spool - eCommerce Spool for Fabrix
322 lines (321 loc) • 11 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const common_1 = require("@fabrix/fabrix/dist/common");
const spool_sequelize_1 = require("@fabrix/spool-sequelize");
const errors_1 = require("@fabrix/spool-sequelize/dist/errors");
const lodash_1 = require("lodash");
const shortId = require("shortid");
class SourceResolver extends spool_sequelize_1.SequelizeResolver {
batch(options, batch) {
const self = this;
options.limit = options.limit || 100;
options.offset = options.offset || 0;
options.regressive = options.regressive || false;
const recursiveQuery = function (options) {
let count = 0;
return self.findAndCountAll(options)
.then(results => {
count = results.count;
return batch(results.rows);
})
.then(batched => {
if (count >= (options.regressive ? options.limit : options.offset + options.limit)) {
options.offset = options.regressive ? 0 : options.offset + options.limit;
return recursiveQuery(options);
}
else {
return Promise.resolve();
}
});
};
return recursiveQuery(options);
}
resolveByInstance(source, options = {}) {
return Promise.resolve(source);
}
resolveById(source, options = {}) {
return this.findById(source.id, options)
.then(resUser => {
if (!resUser && options.reject !== false) {
throw new errors_1.ModelError('E_NOT_FOUND', `Source ${source.id} not found`);
}
return resUser;
});
}
resolveByToken(source, options = {}) {
return this.findOne(this.app.services.SequelizeService.mergeOptionDefaults(options, {
where: {
token: source.token
}
}))
.then(resUser => {
if (!resUser && options.reject !== false) {
throw new errors_1.ModelError('E_NOT_FOUND', `Source token ${source.token} not found`);
}
return resUser;
});
}
resolveByNumber(source, options = {}) {
return this.findById(source, options)
.then(resUser => {
if (!resUser && options.reject !== false) {
throw new errors_1.ModelError('E_NOT_FOUND', `Source ${source.token} not found`);
}
return resUser;
});
}
resolveByString(source, options = {}) {
return this.findOne(this.app.services.SequelizeService.mergeOptionDefaults(options, {
where: {
token: source
}
}))
.then(resUser => {
if (!resUser && options.reject !== false) {
throw new errors_1.ModelError('E_NOT_FOUND', `Source ${source} not found`);
}
return resUser;
});
}
resolve(source, options = {}) {
const resolvers = {
'instance': source instanceof this.instance,
'id': !!(source && lodash_1.isObject(source) && source.id),
'token': !!(source && lodash_1.isObject(source) && source.token),
'number': !!(source && lodash_1.isNumber(source)),
'string': !!(source && lodash_1.isString(source))
};
const type = Object.keys(resolvers).find((key) => resolvers[key]);
switch (type) {
case 'instance': {
return this.resolveByInstance(source, options);
}
case 'id': {
return this.resolveById(source, options);
}
case 'token': {
return this.resolveByToken(source, options);
}
case 'number': {
return this.resolveByNumber(source, options);
}
case 'string': {
return this.resolveByString(source, options);
}
default: {
const err = new Error(`Unable to resolve Source ${source}`);
return Promise.reject(err);
}
}
}
}
exports.SourceResolver = SourceResolver;
class Source extends common_1.FabrixModel {
static get resolver() {
return SourceResolver;
}
static config(app, Sequelize) {
return {
options: {
underscored: true,
scopes: {
live: {
where: {
live_mode: true
}
}
},
hooks: {
beforeCreate: [
(values, options) => {
if (!values.token) {
values.token = `source_${shortId.generate()}`;
}
}
],
afterCreate: [
(values, options) => {
return app.services.AccountService.afterSourceCreate(values)
.catch(err => {
return Promise.reject(err);
});
}
],
afterDestroy: [
(values, options) => {
return app.services.AccountService.afterSourceDestroy(values)
.catch(err => {
return Promise.reject(err);
});
}
]
}
}
};
}
static schema(app, Sequelize) {
return {
customer_id: {
type: Sequelize.INTEGER,
allowNull: false
},
account_id: {
type: Sequelize.INTEGER,
allowNull: true
},
token: {
type: Sequelize.STRING,
unique: true
},
gateway: {
type: Sequelize.STRING,
defaultValue: 'payment_processor'
},
account_foreign_key: {
type: Sequelize.STRING,
allowNull: false
},
account_foreign_id: {
type: Sequelize.STRING,
allowNull: false
},
foreign_key: {
type: Sequelize.STRING,
allowNull: false
},
foreign_id: {
type: Sequelize.STRING,
allowNull: false
},
is_default: {
type: Sequelize.BOOLEAN,
defaultValue: false
},
payment_details: {
type: Sequelize.JSONB,
defaultValue: {}
},
live_mode: {
type: Sequelize.BOOLEAN,
defaultValue: app.config.get('cart.live_mode')
}
};
}
static associate(models) {
models.Source.belongsTo(models.Account, {});
models.Source.belongsTo(models.Customer, {});
models.Source.hasMany(models.Transaction, {
as: 'transactions',
});
}
}
exports.Source = Source;
Source.prototype.getBrand = function () {
let brand = this.gateway;
if (this.payment_details && this.payment_details.credit_card_company) {
brand = this.payment_details.credit_card_company;
}
return brand;
};
Source.prototype.getType = function () {
let type;
switch (this.payment_details.type) {
case 'credit_card':
type = 'Credit Card';
break;
case 'debit_card':
type = 'Debit Card';
break;
default:
type = 'Payment Method';
}
return type;
};
Source.prototype.getLast4 = function () {
let last4 = '****';
if (this.payment_details && this.payment_details.credit_card_last4) {
last4 = this.payment_details.credit_card_last4;
}
return last4;
};
Source.prototype.getExpiration = function () {
let expiration = 'MM/YYYY';
if (this.payment_details
&& this.payment_details.credit_card_exp_year
&& this.payment_details.credit_card_exp_month) {
expiration = `${this.payment_details.credit_card_exp_month}/${this.payment_details.credit_card_exp_year}`;
}
return expiration;
};
Source.prototype.notifyCustomer = function (preNotification, options = {}) {
options = options || {};
if (this.customer_id) {
return this.resolveCustomer({
attributes: ['id', 'email', 'company', 'first_name', 'last_name', 'full_name'],
transaction: options.transaction || null,
reload: options.reload || null
})
.then(() => {
if (this.Customer && this.Customer instanceof this.app.models['Customer'].instance) {
return this.Customer.notifyUsers(preNotification, { transaction: options.transaction || null });
}
else {
return;
}
})
.then(() => {
return this;
});
}
else {
return Promise.resolve(this);
}
};
Source.prototype.resolveCustomer = function (options = {}) {
if (this.Customer
&& this.Customer instanceof this.app.models['Customer'].instance
&& options.reload !== true) {
return Promise.resolve(this);
}
else if (!this.customer_id) {
return Promise.resolve(this);
}
else {
return this.getCustomer({ transaction: options.transaction || null })
.then(_customer => {
_customer = _customer || null;
this.Customer = _customer;
this.setDataValue('Customer', _customer);
this.set('Customer', _customer);
return this;
});
}
};
Source.prototype.sendExpiredEmail = function (options = {}) {
return this.app.emails.Source.expired(this, {
send_email: this.app.config.get('cart.emails.sourceExpired')
}, {
transaction: options.transaction || null
})
.then(email => {
return this.notifyCustomer(email, { transaction: options.transaction || null });
})
.catch(err => {
this.app.log.error(err);
return;
});
};
Source.prototype.sendWillExpireEmail = function (options = {}) {
return this.app.emails.Source.willExpire(this, {
send_email: this.app.config.get('cart.emails.sourceWillExpire')
}, {
transaction: options.transaction || null
})
.then(email => {
return this.notifyCustomer(email, { transaction: options.transaction || null });
})
.catch(err => {
this.app.log.error(err);
return;
});
};