UNPKG

@fabrix/spool-cart

Version:

Spool - eCommerce Spool for Fabrix

447 lines (446 loc) 15.9 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 queryDefaults_1 = require("../utils/queryDefaults"); const enums_1 = require("../../enums"); const enums_2 = require("../../enums"); const enums_3 = require("../../enums"); const enums_4 = require("../../enums"); class ProductVariantResolver extends spool_sequelize_1.SequelizeResolver { findByIdDefault(id, options = {}) { options = this.app.services.SequelizeService.mergeOptionDefaults(options, queryDefaults_1.ProductVariant.default(this.app)); return this.findById(id, options); } findAllDefault(options = {}) { options = this.app.services.SequelizeService.mergeOptionDefaults(queryDefaults_1.ProductVariant.default(this.app), options); return this.findAll(options); } resolve(variant, options = {}) { const Variant = this; if (variant instanceof Variant.instance) { return Promise.resolve(variant); } else if (variant && lodash_1.isObject(variant) && variant.id) { return Variant.findById(variant.id, options) .then(resVariant => { if (!resVariant && options.reject !== false) { throw new errors_1.ModelError('E_NOT_FOUND', `Variant ${variant.id} not found`); } return resVariant || variant; }); } else if (variant && lodash_1.isObject(variant) && variant.sku) { return Variant.findOne(lodash_1.defaultsDeep({ where: { sku: variant.sku } }, options)) .then(resVariant => { if (!resVariant && options.reject !== false) { throw new errors_1.ModelError('E_NOT_FOUND', `Variant ${variant.sku} not found`); } return resVariant || variant; }); } else if (variant && lodash_1.isNumber(variant)) { return Variant.findById(variant, options) .then(resVariant => { if (!resVariant && options.reject !== false) { throw new errors_1.ModelError('E_NOT_FOUND', `Variant ${variant} not found`); } return resVariant || variant; }); } else if (variant && lodash_1.isString(variant)) { return Variant.findOne(lodash_1.defaultsDeep({ where: { sku: variant } }, options)) .then(resVariant => { if (!resVariant && options.reject !== false) { throw new errors_1.ModelError('E_NOT_FOUND', `Variant ${variant} not found`); } return resVariant || variant; }); } else { if (options.reject !== false) { const err = new Error(`Unable to resolve Variant ${variant}`); return Promise.reject(err); } else { return Promise.resolve(variant); } } } } exports.ProductVariantResolver = ProductVariantResolver; class ProductVariant extends common_1.FabrixModel { static get resolver() { return ProductVariantResolver; } static config(app, Sequelize) { return { options: { underscored: true, enums: { UNITS: enums_1.UNITS, INTERVALS: enums_2.INTERVALS, INVENTORY_POLICY: enums_3.INVENTORY_POLICY, VARIANT_DEFAULTS: enums_4.VARIANT_DEFAULTS, }, scopes: { live: { where: { live_mode: true } } }, hooks: { beforeValidate: [ (productVariant, options) => { if (!productVariant.calculated_price && productVariant.price) { productVariant.calculated_price = productVariant.price; } } ], beforeCreate: [ (productVariant, options) => { return app.services.ProductService.beforeVariantCreate(productVariant, options) .catch(err => { return Promise.reject(err); }); } ], beforeUpdate: [ (productVariant, options) => { return app.services.ProductService.beforeVariantUpdate(productVariant, options) .catch(err => { return Promise.reject(err); }); } ] } } }; } static schema(app, Sequelize) { return { product_id: { type: Sequelize.INTEGER, unique: 'productvariant_sku', }, sku: { type: Sequelize.STRING, unique: 'productvariant_sku', allowNull: false, set: function (val) { this.setDataValue('sku', app.services.ProxyCartService.sku(val)); } }, title: { type: Sequelize.STRING }, type: { type: Sequelize.STRING }, option: { type: Sequelize.JSONB, defaultValue: {} }, property_pricing: { type: Sequelize.JSONB, defaultValue: {} }, barcode: { type: Sequelize.STRING }, price: { type: Sequelize.INTEGER, defaultValue: 0 }, calculated_price: { type: Sequelize.VIRTUAL(Sequelize.INTEGER), defaultValue: 0 }, compare_at_price: { type: Sequelize.INTEGER, defaultValue: 0 }, currency: { type: Sequelize.STRING, defaultValue: enums_4.VARIANT_DEFAULTS.CURRENCY }, discounted_lines: { type: Sequelize.JSONB, defaultValue: [] }, total_discounts: { type: Sequelize.INTEGER, defaultValue: 0 }, total_orders: { type: Sequelize.INTEGER, defaultValue: 0 }, fulfillment_service: { type: Sequelize.STRING, defaultValue: enums_4.VARIANT_DEFAULTS.FULFILLMENT_SERVICE }, position: { type: Sequelize.INTEGER, defaultValue: 1 }, published: { type: Sequelize.BOOLEAN, defaultValue: enums_4.VARIANT_DEFAULTS.PUBLISHED }, published_at: { type: Sequelize.DATE }, unpublished_at: { type: Sequelize.DATE }, available: { type: Sequelize.BOOLEAN, defaultValue: enums_4.VARIANT_DEFAULTS.AVAILABLE }, requires_shipping: { type: Sequelize.BOOLEAN, defaultValue: enums_4.VARIANT_DEFAULTS.REQUIRES_SHIPPING }, requires_taxes: { type: Sequelize.BOOLEAN, defaultValue: enums_4.VARIANT_DEFAULTS.REQUIRES_TAX }, requires_subscription: { type: Sequelize.BOOLEAN, defaultValue: enums_4.VARIANT_DEFAULTS.REQUIRES_SUBSCRIPTION }, subscription_interval: { type: Sequelize.INTEGER, defaultValue: enums_4.VARIANT_DEFAULTS.SUBSCRIPTION_INTERVAL }, subscription_unit: { type: Sequelize.ENUM, values: lodash_1.values(enums_2.INTERVALS), defaultValue: enums_4.VARIANT_DEFAULTS.SUBSCRIPTION_UNIT }, inventory_management: { type: Sequelize.BOOLEAN, defaultValue: enums_4.VARIANT_DEFAULTS.INVENTORY_MANAGEMENT }, inventory_policy: { type: Sequelize.ENUM, values: lodash_1.values(enums_3.INVENTORY_POLICY), defaultValue: enums_4.VARIANT_DEFAULTS.INVENTORY_POLICY }, inventory_quantity: { type: Sequelize.INTEGER, defaultValue: enums_4.VARIANT_DEFAULTS.INVENTORY_QUANTITY }, inventory_lead_time: { type: Sequelize.INTEGER, defaultValue: enums_4.VARIANT_DEFAULTS.INVENTORY_LEAD_TIME }, max_quantity: { type: Sequelize.INTEGER, defaultValue: enums_4.VARIANT_DEFAULTS.MAX_QUANTITY }, tax_code: { type: Sequelize.STRING, defaultValue: enums_4.VARIANT_DEFAULTS.TAX_CODE }, weight: { type: Sequelize.INTEGER, defaultValue: 0 }, weight_unit: { type: Sequelize.ENUM, values: lodash_1.values(enums_1.UNITS), defaultValue: enums_4.VARIANT_DEFAULTS.WEIGHT_UNIT }, google: { type: Sequelize.JSONB, defaultValue: {} }, amazon: { type: Sequelize.JSONB, defaultValue: {} }, live_mode: { type: Sequelize.BOOLEAN, defaultValue: app.config.get('cart.live_mode') } }; } static associate(models) { models.ProductVariant.belongsTo(models.Product, { foreignKey: 'product_id' }); models.ProductVariant.belongsToMany(models.Shop, { as: 'shops', through: { model: models.ShopProduct, unique: false, }, foreignKey: 'variant_id', }); models.ProductVariant.belongsToMany(models.ProductVariant, { as: 'associations', through: { model: models.ProductAssociation, unique: false }, foreignKey: 'variant_id', otherKey: 'associated_variant_id' }); models.ProductVariant.belongsToMany(models.ProductVariant, { as: 'relations', through: { model: models.ProductAssociation, unique: false }, foreignKey: 'associated_variant_id', otherKey: 'variant_id' }); models.ProductVariant.hasMany(models.ProductImage, { as: 'images', foreignKey: 'product_variant_id', through: null, onDelete: 'CASCADE' }); models.ProductVariant.hasOne(models.Metadata, { as: 'metadata', foreignKey: 'product_variant_id' }); models.ProductVariant.belongsToMany(models.Discount, { as: 'discounts', through: { model: models.ItemDiscount, unique: false, scope: { model: 'productvariant' } }, foreignKey: 'model_id', constraints: false }); models.ProductVariant.hasMany(models.OrderItem, { as: 'order_items', foreignKey: 'variant_id' }); models.ProductVariant.belongsToMany(models.Event, { as: 'event_items', through: { model: models.EventItem, unique: false, scope: { object: 'productvariant' } }, foreignKey: 'object_id', constraints: false }); models.ProductVariant.belongsToMany(models.Vendor, { as: 'vendors', through: { model: models.VendorProduct, unique: false, }, foreignKey: 'variant_id', }); } } exports.ProductVariant = ProductVariant; ProductVariant.prototype.checkRestrictions = function (customer, shippingAddress) { return Promise.resolve(false); }; ProductVariant.prototype.checkAvailability = function (qty, options = {}) { let allowed = true; if (qty > this.inventory_quantity && this.inventory_policy === enums_3.INVENTORY_POLICY.DENY) { allowed = false; qty = Math.max(0, qty + (this.inventory_quantity - qty)); } if (this.inventory_policy === enums_3.INVENTORY_POLICY.RESTRICT) { qty = Math.max(0, qty + (this.inventory_quantity - qty)); } const res = { title: this.title, allowed: allowed, quantity: qty }; if (options.shop) { res.shop = options.shop; } return this.resolveShops({ transaction: options.transaction || null }) .then(() => { if (!res.shop && this.shops.length > 0) { res.shop = this.shops[0]; } return res; }) .catch(err => { return res; }); }; ProductVariant.prototype.resolveShops = function (options = {}) { if (this.shops && this.shops.length > 0 && this.shops.every(d => d instanceof this.app.models['Shop'].instance) && options.reload !== true) { return Promise.resolve(this); } else { return this.getShops({ transaction: options.transaction || null }) .then(_shops => { _shops = _shops || []; this.shops = _shops; this.setDataValue('shops', _shops); this.set('shops', _shops); return this; }); } }; ProductVariant.prototype.resolveImages = function (options = {}) { return this; }; ProductVariant.prototype.resolveDiscounts = function (options = {}) { if (this.discounts && this.discounts.length > 0 && this.discounts.every(d => d instanceof this.app.models['Discount'].instance) && options.reload !== true) { return Promise.resolve(this); } else { return this.getDiscounts({ transaction: options.transaction || null }) .then(_discounts => { _discounts = _discounts || []; this.discounts = _discounts; this.setDataValue('discounts', _discounts); this.set('discounts', _discounts); return this; }); } }; ProductVariant.prototype.resolveMetadata = function (options = {}) { if (this.metadata && this.metadata instanceof this.app.models['Metadata'].instance && options.reload !== true) { return Promise.resolve(this); } else { return this.getMetadata({ transaction: options.transaction || null }) .then(_metadata => { _metadata = _metadata || { product_variant_id: this.id }; this.metadata = _metadata; this.setDataValue('metadata', _metadata); this.set('metadata', _metadata); return this; }); } };