@fabrix/spool-cart
Version:
Spool - eCommerce Spool for Fabrix
446 lines (445 loc) • 16.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const errors_1 = require("@fabrix/spool-sequelize/dist/errors");
const common_1 = require("@fabrix/fabrix/dist/common");
const spool_sequelize_1 = require("@fabrix/spool-sequelize");
const lodash_1 = require("lodash");
const queryDefaults_1 = require("../utils/queryDefaults");
const enums_1 = require("../../enums");
const enums_2 = require("../../enums");
class FulfillmentResolver extends spool_sequelize_1.SequelizeResolver {
findByIdDefault(id, options = {}) {
options = this.app.services.SequelizeService.mergeOptionDefaults(queryDefaults_1.Fulfillment.default(this.app), options);
return this.findById(id, options);
}
findAndCountDefault(options = {}) {
options = this.app.services.SequelizeService.mergeOptionDefaults(queryDefaults_1.Fulfillment.default(this.app), options);
return this.findAndCountAll(options);
}
resolveByInstance(cart, options = {}) {
return Promise.resolve(cart);
}
resolveById(cart, options = {}) {
return this.findById(cart.id, options)
.then(resUser => {
if (!resUser && options.reject !== false) {
throw new errors_1.ModelError('E_NOT_FOUND', `Cart ${cart.id} not found`);
}
return resUser;
});
}
resolveByToken(cart, options = {}) {
return this.findOne(lodash_1.defaultsDeep({
where: {
token: cart.token
}
}, options))
.then(resUser => {
if (!resUser && options.reject !== false) {
throw new errors_1.ModelError('E_NOT_FOUND', `Cart token ${cart.token} not found`);
}
return resUser;
});
}
resolveByNumber(cart, options = {}) {
return this.findById(cart, options)
.then(resUser => {
if (!resUser && options.reject !== false) {
throw new errors_1.ModelError('E_NOT_FOUND', `Cart ${cart.token} not found`);
}
return resUser;
});
}
resolveByString(cart, options = {}) {
return this.findOne(lodash_1.defaultsDeep({
where: {
token: cart
}
}, options))
.then(resUser => {
if (!resUser && options.reject !== false) {
throw new errors_1.ModelError('E_NOT_FOUND', `Cart ${cart} not found`);
}
return resUser;
});
}
resolve(cart, options = {}) {
const resolvers = {
'instance': cart instanceof this.instance,
'id': !!(cart && lodash_1.isObject(cart) && cart.id),
'token': !!(cart && lodash_1.isObject(cart) && cart.token),
'number': !!(cart && lodash_1.isNumber(cart)),
'string': !!(cart && lodash_1.isString(cart))
};
const type = Object.keys(resolvers).find((key) => resolvers[key]);
switch (type) {
case 'instance': {
return this.resolveByInstance(cart, options);
}
case 'id': {
return this.resolveById(cart, options);
}
case 'token': {
return this.resolveByToken(cart, options);
}
case 'number': {
return this.resolveByNumber(cart, options);
}
case 'string': {
return this.resolveByString(cart, options);
}
default: {
const err = new Error(`Unable to resolve Cart ${cart}`);
return Promise.reject(err);
}
}
}
}
exports.FulfillmentResolver = FulfillmentResolver;
class Fulfillment extends common_1.FabrixModel {
static get resolver() {
return FulfillmentResolver;
}
static config(app, Sequelize) {
return {
options: {
underscored: true,
enums: {
FULFILLMENT_STATUS: enums_1.FULFILLMENT_STATUS,
FULFILLMENT_SERVICE: enums_2.FULFILLMENT_SERVICE
},
scopes: {
live: {
where: {
live_mode: true
}
},
none: {
where: {
status: enums_1.FULFILLMENT_STATUS.NONE
}
},
pending: {
where: {
status: enums_1.FULFILLMENT_STATUS.PENDING
}
},
sent: {
where: {
status: enums_1.FULFILLMENT_STATUS.SENT
}
},
partial: {
where: {
status: enums_1.FULFILLMENT_STATUS.PARTIAL
}
},
fulfilled: {
where: {
status: enums_1.FULFILLMENT_STATUS.FULFILLED
}
},
cancelled: {
where: {
status: enums_1.FULFILLMENT_STATUS.CANCELLED
}
},
},
hooks: {
beforeCreate: [
(fulfillment, options) => {
return app.services.FulfillmentService.beforeCreate(fulfillment, options)
.catch(err => {
return Promise.reject(err);
});
}
],
beforeUpdate: [
(fulfillment, options) => {
return app.services.FulfillmentService.beforeUpdate(fulfillment, options)
.catch(err => {
return Promise.reject(err);
});
}
],
afterCreate: [
(fulfillment, options) => {
return app.services.FulfillmentService.afterCreate(fulfillment, options)
.catch(err => {
return Promise.reject(err);
});
}
],
afterUpdate: [
(fulfillment, options) => {
return app.services.FulfillmentService.afterUpdate(fulfillment, options)
.catch(err => {
return Promise.reject(err);
});
}
]
}
}
};
}
static schema(app, Sequelize) {
return {
order_id: {
type: Sequelize.INTEGER,
allowNull: false
},
receipt: {
type: Sequelize.TEXT
},
status: {
type: Sequelize.ENUM,
values: lodash_1.values(enums_1.FULFILLMENT_STATUS),
defaultValue: enums_1.FULFILLMENT_STATUS.PENDING
},
total_items: {
type: Sequelize.INTEGER,
defaultValue: 0
},
total_fulfilled: {
type: Sequelize.INTEGER,
defaultValue: 0
},
total_sent_to_fulfillment: {
type: Sequelize.INTEGER,
defaultValue: 0
},
total_cancelled: {
type: Sequelize.INTEGER,
defaultValue: 0
},
total_pending_fulfillments: {
type: Sequelize.INTEGER,
defaultValue: 0
},
status_url: {
type: Sequelize.STRING
},
has_shipping: {
type: Sequelize.BOOLEAN,
defaultValue: false
},
service: {
type: Sequelize.STRING,
defaultValue: enums_2.FULFILLMENT_SERVICE.MANUAL
},
tracking_company: {
type: Sequelize.STRING
},
tracking_number: {
type: Sequelize.STRING
},
extras: {
type: Sequelize.JSONB,
defaultValue: {}
},
live_mode: {
type: Sequelize.BOOLEAN,
defaultValue: app.config.get('cart.live_mode')
},
sent_at: {
type: Sequelize.DATE
},
fulfilled_at: {
type: Sequelize.DATE
},
cancelled_at: {
type: Sequelize.DATE
}
};
}
static associate(models) {
models.Fulfillment.belongsTo(models.Order, {
foreignKey: 'order_id',
});
models.Fulfillment.hasMany(models.OrderItem, {
as: 'order_items',
foreignKey: 'fulfillment_id',
});
}
}
exports.Fulfillment = Fulfillment;
Fulfillment.prototype.pending = function () {
return this;
};
Fulfillment.prototype.none = function () {
return this;
};
Fulfillment.prototype.partial = function () {
return this;
};
Fulfillment.prototype.sent = function () {
this.sent_at = new Date(Date.now());
this.status = enums_1.FULFILLMENT_STATUS.SENT;
return this;
};
Fulfillment.prototype.fulfilled = function () {
this.fulfilled_at = new Date(Date.now());
this.status = enums_1.FULFILLMENT_STATUS.FULFILLED;
return this;
};
Fulfillment.prototype.cancelled = function () {
this.cancelled_at = new Date(Date.now());
this.status = enums_1.FULFILLMENT_STATUS.CANCELLED;
return this;
};
Fulfillment.prototype.fulfillUpdate = function (data = {}, options = {}) {
return this.resolveOrderItems({
transaction: options.transaction || null,
reload: options.reload || null
})
.then(() => {
this.status = data.status || this.status;
this.status_url = data.status_url || this.status_url;
this.tracking_company = data.tracking_company || this.tracking_company;
this.tracking_number = data.tracking_number || this.tracking_number;
this.extras = data.extras || this.extras;
this.receipt = data.receipt || this.receipt;
return this.sequelize.Promise.mapSeries(this.order_items, item => {
item.fulfillment_status = this.status;
return item.save({
fields: ['fulfillment_status'],
transaction: options.transaction || null
});
});
})
.then(() => {
return this.saveFulfillmentStatus({ transaction: options.transaction || null });
});
};
Fulfillment.prototype.reconcileFulfillmentStatus = function (options = {}) {
return this.resolveFulfillmentStatus({
transaction: options.transaction || null,
reload: options.reload || null
})
.then(() => {
if (this.changed('status')) {
return this.getOrder({ transaction: options.transaction || null });
}
else {
return null;
}
})
.then(resOrder => {
if (resOrder) {
return resOrder.saveFulfillmentStatus({ transaction: options.transaction || null });
}
else {
return null;
}
})
.then(resOrder => {
if (resOrder) {
return resOrder.saveStatus({ transaction: options.transaction || null });
}
else {
return null;
}
})
.then(() => {
return this;
});
};
Fulfillment.prototype.resolveFulfillmentStatus = function (options = {}) {
if (!this.id) {
return Promise.resolve(this);
}
return this.resolveOrderItems({
transaction: options.transaction || null,
reload: options.reload || null
})
.then(() => {
this.setFulfillmentStatus();
return this;
});
};
Fulfillment.prototype.resolveOrderItems = function (options) {
if (this.order_items
&& this.order_items.every(i => i instanceof this.app.models['OrderItem'].instance)
&& options.reload !== true) {
return Promise.resolve(this);
}
else {
return this.getOrder_items({ transaction: options.transaction || null })
.then(orderItems => {
orderItems = orderItems || [];
this.order_items = orderItems;
this.setDataValue('order_items', orderItems);
this.set('order_items', orderItems);
return this;
});
}
};
Fulfillment.prototype.saveFulfillmentStatus = function (options = {}) {
return this.resolveFulfillmentStatus({
transaction: options.transaction || null,
reload: options.reload || null
})
.then(() => {
return this.save({ transaction: options.transaction || null });
});
};
Fulfillment.prototype.setFulfillmentStatus = function () {
if (!this.order_items) {
throw new Error('Fulfillment.setFulfillmentStatus requires order_items to be populated');
}
let fulfillmentStatus = enums_1.FULFILLMENT_STATUS.PENDING;
let totalFulfillments = 0;
let totalPartialFulfillments = 0;
let totalSentFulfillments = 0;
let totalNonFulfillments = 0;
let totalPendingFulfillments = 0;
let totalCancelledFulfillments = 0;
let totalQty = 0;
this.order_items.forEach(item => {
totalQty = totalQty + item.quantity;
if (item.fulfillment_status === enums_1.FULFILLMENT_STATUS.FULFILLED) {
totalFulfillments = totalFulfillments + item.quantity;
}
else if (item.fulfillment_status === enums_1.FULFILLMENT_STATUS.PARTIAL) {
totalPartialFulfillments = totalPartialFulfillments + item.quantity;
}
else if (item.fulfillment_status === enums_1.FULFILLMENT_STATUS.SENT) {
totalSentFulfillments = totalSentFulfillments + item.quantity;
}
else if (item.fulfillment_status === enums_1.FULFILLMENT_STATUS.PENDING) {
totalPendingFulfillments = totalPendingFulfillments + item.quantity;
}
else if (item.fulfillment_status === enums_1.FULFILLMENT_STATUS.NONE) {
totalNonFulfillments = totalNonFulfillments + item.quantity;
}
else if (item.fulfillment_status === enums_1.FULFILLMENT_STATUS.CANCELLED) {
totalCancelledFulfillments = totalCancelledFulfillments + item.quantity;
}
});
if (totalFulfillments === totalQty && totalQty > 0) {
fulfillmentStatus = enums_1.FULFILLMENT_STATUS.FULFILLED;
}
else if (totalSentFulfillments === totalQty && totalQty > 0) {
fulfillmentStatus = enums_1.FULFILLMENT_STATUS.SENT;
}
else if (totalPartialFulfillments > 0 && totalQty > 0) {
fulfillmentStatus = enums_1.FULFILLMENT_STATUS.PARTIAL;
}
else if (totalPendingFulfillments === totalQty && totalQty > 0) {
fulfillmentStatus = enums_1.FULFILLMENT_STATUS.PENDING;
}
else if (totalNonFulfillments === totalQty && totalQty > 0) {
fulfillmentStatus = enums_1.FULFILLMENT_STATUS.NONE;
}
else if (totalCancelledFulfillments === totalQty && totalQty > 0) {
fulfillmentStatus = enums_1.FULFILLMENT_STATUS.CANCELLED;
}
this.has_shipping = this.order_items.some(i => i.requires_shipping === true);
this.status = fulfillmentStatus;
this.total_items = totalQty;
this.total_fulfilled = totalFulfillments;
this.total_sent_to_fulfillment = totalSentFulfillments;
this.total_pending_fulfillments = totalPendingFulfillments;
this.total_cancelled = totalCancelledFulfillments;
return this;
};