@fabrix/spool-cart
Version:
Spool - eCommerce Spool for Fabrix
531 lines (530 loc) • 18.3 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 enums_1 = require("../../enums");
const enums_2 = require("../../enums");
const enums_3 = require("../../enums");
class OrderItemResolver extends spool_sequelize_1.SequelizeResolver {
resolve(item, options = {}) {
const OrderItemModel = this;
if (item instanceof OrderItemModel.instance) {
return Promise.resolve(item);
}
else if (item && lodash_1.isObject(item) && item.id) {
return OrderItemModel.findById(item.id, options)
.then(resOrderItem => {
if (!resOrderItem) {
throw new errors_1.ModelError('E_NOT_FOUND', `Order ${item.id} not found`);
}
return resOrderItem;
});
}
else if (item && (lodash_1.isString(item) || lodash_1.isNumber(item))) {
return OrderItemModel.findById(item, options)
.then(resOrderItem => {
if (!resOrderItem) {
throw new errors_1.ModelError('E_NOT_FOUND', `Order ${item} not found`);
}
return resOrderItem;
});
}
else {
const err = new Error('Unable to resolve Order Item');
return Promise.reject(err);
}
}
}
exports.OrderItemResolver = OrderItemResolver;
class OrderItem extends common_1.FabrixModel {
static get resolver() {
return OrderItemResolver;
}
static config(app, Sequelize) {
return {
options: {
underscored: true,
enums: {
INTERVALS: enums_1.INTERVALS,
FULFILLMENT_STATUS: enums_2.FULFILLMENT_STATUS,
FULFILLMENT_SERVICE: enums_3.FULFILLMENT_SERVICE
},
scopes: {
live: {
where: {
live_mode: true
}
}
},
hooks: {
beforeCreate: [
(orderItem, options) => {
return app.services.OrderService.itemBeforeCreate(orderItem, options)
.catch(err => {
return Promise.reject(err);
});
}
],
beforeSave: [
(orderItem, options) => {
return app.services.OrderService.itemBeforeSave(orderItem, options)
.catch(err => {
return Promise.reject(err);
});
}
],
beforeUpdate: [
(orderItem, options) => {
return app.services.OrderService.itemBeforeUpdate(orderItem, options)
.catch(err => {
return Promise.reject(err);
});
}
],
afterCreate: [
(orderItem, options) => {
return app.services.OrderService.itemAfterCreate(orderItem, options)
.catch(err => {
return Promise.reject(err);
});
}
],
afterUpdate: [
(orderItem, options) => {
return app.services.OrderService.itemAfterUpdate(orderItem, options)
.catch(err => {
return Promise.reject(err);
});
}
],
afterDestroy: [
(orderItem, options) => {
return app.services.OrderService.itemAfterDestroy(orderItem, options)
.catch(err => {
return Promise.reject(err);
});
}
]
}
}
};
}
static schema(app, Sequelize) {
return {
order_id: {
type: Sequelize.INTEGER,
allowNull: false
},
customer_id: {
type: Sequelize.INTEGER,
},
fulfillment_id: {
type: Sequelize.INTEGER,
},
product_id: {
type: Sequelize.INTEGER,
allowNull: false
},
product_handle: {
type: Sequelize.STRING,
allowNull: false
},
variant_id: {
type: Sequelize.INTEGER,
allowNull: false
},
subscription_id: {
type: Sequelize.INTEGER,
},
refund_id: {
type: Sequelize.INTEGER,
},
gift_card_id: {
type: Sequelize.INTEGER,
},
shop_id: {
type: Sequelize.INTEGER,
},
option: {
type: Sequelize.JSONB,
defaultValue: {}
},
fulfillable_quantity: {
type: Sequelize.INTEGER,
defaultValue: 0
},
max_quantity: {
type: Sequelize.INTEGER,
defaultValue: -1
},
fulfillment_service: {
type: Sequelize.STRING,
defaultValue: enums_3.FULFILLMENT_SERVICE.MANUAL
},
fulfillment_status: {
type: Sequelize.ENUM,
values: lodash_1.values(enums_2.FULFILLMENT_STATUS),
defaultValue: enums_2.FULFILLMENT_STATUS.PENDING
},
grams: {
type: Sequelize.INTEGER,
defaultValue: 0
},
compare_at_price: {
type: Sequelize.INTEGER,
defaultValue: 0
},
price: {
type: Sequelize.INTEGER,
defaultValue: 0
},
calculated_price: {
type: Sequelize.INTEGER,
defaultValue: 0
},
price_per_unit: {
type: Sequelize.INTEGER,
defaultValue: 0
},
quantity: {
type: Sequelize.INTEGER
},
requires_taxes: {
type: Sequelize.BOOLEAN,
defaultValue: true
},
requires_shipping: {
type: Sequelize.BOOLEAN,
defaultValue: true
},
requires_subscription: {
type: Sequelize.BOOLEAN,
defaultValue: true
},
subscription_interval: {
type: Sequelize.INTEGER,
defaultValue: 0
},
subscription_unit: {
type: Sequelize.ENUM,
values: lodash_1.values(enums_1.INTERVALS),
defaultValue: enums_1.INTERVALS.NONE
},
sku: {
type: Sequelize.STRING
},
type: {
type: Sequelize.STRING
},
title: {
type: Sequelize.STRING
},
variant_title: {
type: Sequelize.STRING
},
vendor_id: {
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
gift_card: {
type: Sequelize.BOOLEAN
},
properties: {
type: Sequelize.JSONB,
defaultValue: {}
},
property_pricing: {
type: Sequelize.JSONB,
defaultValue: {}
},
taxable: {
type: Sequelize.BOOLEAN
},
tax_code: {
type: Sequelize.STRING,
defaultValue: 'P000000'
},
discounted_lines: {
type: Sequelize.JSONB,
defaultValue: []
},
coupon_lines: {
type: Sequelize.JSONB,
defaultValue: []
},
shipping_lines: {
type: Sequelize.JSONB,
defaultValue: []
},
tax_lines: {
type: Sequelize.JSONB,
defaultValue: []
},
total_discounts: {
type: Sequelize.INTEGER,
defaultValue: 0
},
total_coupons: {
type: Sequelize.INTEGER,
defaultValue: 0
},
total_shipping: {
type: Sequelize.INTEGER,
defaultValue: 0
},
total_taxes: {
type: Sequelize.INTEGER,
defaultValue: 0
},
average_shipping: {
type: Sequelize.INTEGER,
defaultValue: 0
},
exclude_payment_types: {
type: Sequelize.JSONB,
defaultValue: []
},
images: {
type: Sequelize.JSONB,
defaultValue: []
},
live_mode: {
type: Sequelize.BOOLEAN,
defaultValue: app.config.get('cart.live_mode')
}
};
}
static associate(models) {
models.OrderItem.belongsTo(models.Order, {
foreignKey: 'order_id'
});
models.OrderItem.belongsTo(models.Customer, {
foreignKey: 'customer_id'
});
models.OrderItem.belongsTo(models.Fulfillment, {
foreignKey: 'fulfillment_id'
});
models.OrderItem.belongsTo(models.Product, {
foreignKey: 'product_id'
});
models.OrderItem.belongsTo(models.ProductVariant, {
foreignKey: 'variant_id'
});
models.OrderItem.belongsTo(models.Vendor, {
foreignKey: 'vendor_id'
});
models.OrderItem.belongsTo(models.Refund, {
foreignKey: 'refund_id'
});
models.OrderItem.belongsTo(models.Shop, {
foreignKey: 'shop_id',
});
models.OrderItem.belongsTo(models.GiftCard, {
foreignKey: 'gift_card_id'
});
models.OrderItem.belongsToMany(models.Discount, {
as: 'discounts',
through: {
model: models.ItemDiscount,
unique: false,
scope: {
model: 'order_item'
}
},
foreignKey: 'model_id',
constraints: false
});
models.OrderItem.hasOne(models.Metadata, {
as: 'metadata',
foreignKey: 'order_item_id'
});
}
}
exports.OrderItem = OrderItem;
OrderItem.prototype.resetDefaults = function () {
this.calculated_price = 0;
this.total_discounts = 0;
this.total_shipping = 0;
this.total_coupons = 0;
this.total_taxes = 0;
return this;
};
OrderItem.prototype.addShipping = function (shipping, options = {}) {
return this;
};
OrderItem.prototype.removeShipping = function (shipping, options = {}) {
return this;
};
OrderItem.prototype.setItemsShippingLines = function (shippingedLine) {
let shippingesLines = [];
let totalShippinges = 0;
if (shippingedLine) {
shippingedLine.shipping_lines = shippingedLine.shipping_lines || [];
shippingedLine.shipping_lines.map(line => {
line.id = this.id;
return line;
});
totalShippinges = shippingedLine.shipping_lines.forEach(line => {
totalShippinges = totalShippinges + line.price;
});
shippingesLines = [...shippingesLines, ...shippingedLine.shipping_lines];
}
this.shipping_lines = shippingesLines;
return this.setShippingLines(shippingesLines);
};
OrderItem.prototype.setShippingLines = function (lines = []) {
this.total_shipping = 0;
this.shipping_lines = lines;
this.shipping_lines.forEach(line => {
this.total_shipping = this.total_shipping + line.price;
});
return this;
};
OrderItem.prototype.setItemsTaxLines = function (taxedLine) {
let taxesLines = [];
let totalTaxes = 0;
if (taxedLine) {
taxedLine.tax_lines = taxedLine.tax_lines || [];
taxedLine.tax_lines.map(line => {
line.id = this.id;
return line;
});
totalTaxes = taxedLine.tax_lines.forEach(line => {
totalTaxes = totalTaxes + line.price;
});
taxesLines = [...taxesLines, ...taxedLine.tax_lines];
}
this.tax_lines = taxesLines;
return this.setTaxLines(taxesLines);
};
OrderItem.prototype.setTaxLines = function (lines = []) {
this.total_tax = 0;
this.tax_lines = lines;
this.tax_lines.forEach(line => {
this.total_tax = this.total_tax + line.price;
});
return this;
},
OrderItem.prototype.setProperties = function (prev) {
if (this.properties && prev) {
for (const l in prev.properties) {
if (prev.properties.hasOwnProperty(l)) {
this.price = this.price - (prev.properties[l].price || 0);
this.price_per_unit = this.price_per_unit - (prev.properties[l].price || 0);
}
}
for (const l in this.properties) {
if (this.properties.hasOwnProperty(l)) {
this.price = this.price + (this.properties[l].price || 0);
this.price_per_unit = this.price_per_unit + (this.properties[l].price || 0);
}
}
}
return this;
};
OrderItem.prototype.setTotals = function () {
return this;
};
OrderItem.prototype.recalculate = function (options = {}) {
if (this.changed('price')
|| this.changed('quantity')
|| this.changed('properties')
|| this.changed('discounted_lines')
|| this.changed('coupon_lines')
|| this.changed('tax_lines')
|| this.changed('coupon_lines')) {
let totalDiscounts = 0;
let totalShipping = 0;
let totalTaxes = 0;
let totalCoupons = 0;
if (this.changed('properties')) {
this.setProperties(this.previous('properties'));
}
this.discounted_lines = this.discounted_lines || [];
this.discounted_lines.map(line => {
totalDiscounts = totalDiscounts + (line.price || 0);
return line;
});
this.coupon_lines = this.coupon_lines || [];
this.coupon_lines.map(line => {
totalCoupons = totalCoupons + (line.price || 0);
if (line.line) {
line.line = this.id;
}
return line;
});
this.shipping_lines = this.shipping_lines || [];
this.shipping_lines.map(line => {
totalShipping = totalShipping + (line.price || 0);
if (line.line) {
delete line.line;
line.id = this.id;
}
return line;
});
this.tax_lines = this.tax_lines || [];
this.tax_lines.map(line => {
totalTaxes = totalTaxes + (line.price || 0);
if (line.line) {
delete line.line;
line.id = this.id;
}
return line;
});
const calculatedPrice = Math.max(0, (this.price_per_unit * this.quantity) - totalDiscounts - totalCoupons);
this.calculated_price = calculatedPrice;
this.total_discounts = totalDiscounts;
this.total_shipping = totalShipping;
this.total_coupons = totalCoupons;
this.total_taxes = totalTaxes;
return Promise.resolve(this);
}
else {
return Promise.resolve(this);
}
};
OrderItem.prototype.reconcileFulfillment = function (options = {}) {
if (this.isNewRecord && !this.fulfillment_id) {
return this.save({ transaction: options.transaction || null })
.then(() => {
return this.app.services.FulfillmentService.addOrCreateFulfillmentItem(this, { transaction: options.transaction || null });
})
.then(() => {
return this;
});
}
else if (!this.isNewRecord && this.quantity === 0) {
return this.save({ transaction: options.transaction || null })
.then(() => {
return this.app.services.FulfillmentService.removeFulfillmentItem(this, { transaction: options.transaction || null });
})
.then(() => {
return this;
});
}
else if (!this.isNewRecord && this.changed('quantity') && (this.quantity > this.previous('quantity'))) {
return this.save({ transaction: options.transaction || null })
.then(() => {
return this.app.services.FulfillmentService.updateFulfillmentItem(this, { transaction: options.transaction || null });
})
.then(() => {
return this;
});
}
else if (!this.isNewRecord && this.changed('quantity') && (this.quantity < this.previous('quantity'))) {
return this.save({ transaction: options.transaction || null })
.then(() => {
return this.app.services.FulfillmentService.removeFulfillmentItem(this, { transaction: options.transaction || null });
})
.then(() => {
return this;
});
}
else {
return this.save({ transaction: options.transaction || null });
}
};