UNPKG

@fabrix/spool-cart

Version:

Spool - eCommerce Spool for Fabrix

531 lines (530 loc) 18.3 kB
"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 }); } };