@fabrix/spool-cart
Version:
Spool - eCommerce Spool for Fabrix
1,217 lines • 72.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const common_1 = require("@fabrix/fabrix/dist/common");
const errors_1 = require("@fabrix/spool-sequelize/dist/errors");
const fs = require("fs");
const _ = require("lodash");
const enums_1 = require("../../enums");
class ProductService extends common_1.FabrixService {
publish(type, event, options = {}) {
if (this.app.services.EventsService) {
options.include = options.include || [{
model: this.app.models.EventItem.instance,
as: 'objects'
}];
return this.app.services.EventsService.publish(type, event, options);
}
this.app.log.debug('spool-events is not installed, please install it to use publish');
return Promise.resolve();
}
resolveItem(item, options = {}) {
const Product = this.app.models.Product;
const ProductVariant = this.app.models.ProductVariant;
const Image = this.app.models.ProductImage;
if (item.id || item.variant_id || item.product_variant_id) {
const id = item.id || item.variant_id || item.product_variant_id;
return ProductVariant.findById(id, {
transaction: options.transaction || null,
include: [
{
model: Product.instance,
include: [
{
model: Image.instance,
as: 'images',
attributes: ['src', 'full', 'thumbnail', 'small', 'medium', 'large', 'alt', 'position']
}
]
},
{
model: Image.instance,
as: 'images',
attributes: ['src', 'full', 'thumbnail', 'small', 'medium', 'large', 'alt', 'position']
}
]
});
}
else if (item.product_id) {
return ProductVariant.findOne({
where: {
product_id: item.product_id,
position: 1
},
transaction: options.transaction || null,
include: [
{
model: Product.instance,
include: [
{
model: Image.instance,
as: 'images',
attributes: ['src', 'full', 'thumbnail', 'small', 'medium', 'large', 'alt', 'position']
}
]
},
{
model: Image.instance,
as: 'images',
attributes: ['src', 'full', 'thumbnail', 'small', 'medium', 'large', 'alt', 'position']
}
]
});
}
else {
const err = new errors_1.ModelError('E_NOT_FOUND', `${item} not found`);
return Promise.reject(err);
}
}
resolveItems(items, options = {}) {
if (!Array.isArray(items)) {
items = [items];
}
const Sequelize = this.app.models['Product'].sequelize;
return Sequelize.transaction(t => {
return Sequelize.Promise.mapSeries(items, item => {
return this.resolveItem(item, {
transaction: t
});
});
});
}
addProducts(products, options = {}) {
if (!Array.isArray(products)) {
products = [products];
}
const Sequelize = this.app.models['Product'].sequelize;
return Sequelize.transaction(t => {
return Sequelize.Promise.mapSeries(products, product => {
return this.addProduct(product, {
transaction: t
});
});
});
}
addProduct(product, options = {}) {
const Product = this.app.models.Product;
return Product.findOne({
where: {
host: product.host ? product.host : 'localhost',
handle: product.handle
},
attributes: ['id'],
transaction: options.transaction || null
})
.then(resProduct => {
if (resProduct instanceof Product.instance) {
product.id = resProduct.id;
return this.updateProduct(product, options);
}
else {
return this.createProduct(product, options);
}
});
}
createProduct(product, options = {}) {
const Product = this.app.models.Product;
const Tag = this.app.models.Tag;
const Variant = this.app.models.ProductVariant;
const Metadata = this.app.models.Metadata;
const Collection = this.app.models.Collection;
const Vendor = this.app.models.Vendor;
const Shop = this.app.models.Shop;
if (!product) {
const err = new Error('A product is required');
return Promise.reject(err);
}
product = this.productDefaults(product);
const create = {
host: product.host,
handle: product.handle,
title: product.title,
seo_title: product.seo_title,
seo_description: product.seo_description,
body: product.body,
type: product.type,
price: product.price,
compare_at_price: product.compare_at_price,
calculated_price: product.calculated_price,
tax_code: product.tax_code,
published: product.published,
available: product.available,
published_scope: product.published_scope,
weight: product.weight,
weight_unit: product.weight_unit,
average_shipping: product.average_shipping,
property_pricing: product.property_pricing,
exclude_payment_types: product.exclude_payment_types,
metadata: Metadata.transform(product.metadata || {}),
google: product.google,
amazon: product.amazon,
options: product.options
};
if (product.published === true) {
create.published_at = new Date();
}
if (product.published === false) {
create.unpublished_at = new Date();
}
if (product.published_scope) {
create.published_scope = product.published_scope;
}
if (product.seo_title) {
create.seo_title = product.seo_title;
}
if (!product.seo_title && product.title) {
create.seo_title = product.title;
}
if (product.seo_description) {
create.seo_description = this.app.services.ProxyCartService.description(product.seo_description);
}
if (!product.seo_description && product.body) {
create.seo_description = this.app.services.ProxyCartService.description(product.body);
}
let images = [];
if (product.images.length > 0) {
product.images = product.images.map(image => {
image.variant = 0;
return image;
});
images = images.concat(product.images);
delete product.images;
}
let variants = [{
title: product.title,
sku: product.sku,
vendors: product.vendors,
google: product.google,
amazon: product.amazon
}];
if (product.published === true) {
variants[0].published_at = create.published_at;
}
if (product.published === false) {
variants[0].unpublished_at = create.unpublished_at;
}
if (!variants[0].sku) {
variants.splice(0, 1);
}
if (product.variants.length > 0) {
variants = variants.concat(product.variants);
}
variants = variants.map((variant, index) => {
variant = this.variantDefaults(variant, product);
variant.position = index + 1;
if (product.published && variant.published !== false) {
variant.published = true;
}
if (variant.published) {
variant.published_at = create.published_at;
}
if (variant.images.length > 0) {
variant.images = variant.images.map(image => {
image.variant = index;
return image;
});
images = images.concat(variant.images);
delete variant.images;
}
if (variant.option) {
const keys = Object.keys(variant.option);
create.options = _.union(create.options, keys);
}
return variant;
});
variants = variants.filter(variant => variant);
create.total_variants = variants.length;
create.variants = variants;
images = images.map((image, index) => {
image.position = index + 1;
return image;
});
let resProduct;
return Product.create(create, {
include: [
{
model: Variant.instance,
as: 'variants',
include: [
{
model: Metadata.instance,
as: 'metadata'
}
]
},
{
model: Metadata.instance,
as: 'metadata',
}
],
transaction: options.transaction || null
})
.then(createdProduct => {
if (!createdProduct) {
throw new Error('Product was not created');
}
resProduct = createdProduct;
if (product.tags && product.tags.length > 0) {
product.tags = _.sortedUniq(product.tags.filter(n => n));
return Tag.transformTags(product.tags, { transaction: options.transaction || null });
}
return;
})
.then(tags => {
if (tags && tags.length > 0) {
return resProduct.setTags(tags.map(tag => tag.id), { transaction: options.transaction || null });
}
return;
})
.then(productTags => {
if (product.shops && product.shops.length > 0) {
product.shops = _.sortedUniq(product.shops.filter(n => n));
return Shop.transformShops(product.shops, { transaction: options.transaction || null });
}
return;
})
.then(shops => {
if (shops && shops.length > 0) {
return Product.sequelize.Promise.mapSeries(resProduct.variants, variant => {
return variant.setShops(shops, { through: { product_id: resProduct.id }, transaction: options.transaction || null });
});
}
return;
})
.then(shops => {
if (product.collections && product.collections.length > 0) {
product.collections = _.sortedUniq(product.collections.filter(n => n));
return Collection.transformCollections(product.collections, { transaction: options.transaction || null });
}
return;
})
.then(collections => {
if (collections && collections.length > 0) {
return Product.sequelize.Promise.mapSeries(collections, collection => {
const through = collection.product_position ? { position: collection.product_position } : {};
return resProduct.addCollection(collection.id, {
through: through,
transaction: options.transaction || null
});
});
}
return;
})
.then(productCollections => {
if (product.vendors && product.vendors.length > 0) {
return Vendor.transformVendors(product.vendors, { transaction: options.transaction || null });
}
return;
})
.then(vendors => {
if (vendors && vendors.length > 0) {
return resProduct.setVendors(vendors.map(v => v.id), {
through: { vendor_price: resProduct.price },
transaction: options.transaction || null
});
}
return;
})
.then(vendors => {
return Product.sequelize.Promise.mapSeries(images, image => {
if (typeof image.variant !== 'undefined') {
if (resProduct.variants && resProduct.variants[image.variant] && resProduct.variants[image.variant].id) {
image.product_variant_id = resProduct.variants[image.variant].id;
}
delete image.variant;
}
return resProduct.createImage(image, { transaction: options.transaction || null });
});
})
.then(createdImages => {
return Product.findByIdDefault(resProduct.id, { transaction: options.transaction || null });
});
}
updateProducts(products) {
if (!Array.isArray(products)) {
products = [products];
}
const Product = this.app.models.Product;
return Product.datastore.transaction(t => {
return Product.sequelize.Promise.mapSeries(products, product => {
return this.updateProduct(product, {
transaction: t
});
});
});
}
updateProduct(product, options) {
options = options || {};
const Product = this.app.models['Product'];
const Variant = this.app.models['ProductVariant'];
const Image = this.app.models['ProductImage'];
const Tag = this.app.models['Tag'];
const Collection = this.app.models['Collection'];
const Vendor = this.app.models['Vendor'];
const productOptions = [];
let resProduct, update = {};
return Product.resolve(product, {
transaction: options.transaction || null
})
.then(_product => {
if (!_product) {
throw new Error('Product not found');
}
resProduct = _product;
return resProduct.resolveVariants({ transaction: options.transaction || null });
})
.then(() => {
if (product.collections) {
return resProduct.resolveCollections({ transaction: options.transaction || null });
}
return;
})
.then(() => {
return resProduct.resolveImages({ transaction: options.transaction || null });
})
.then(() => {
if (product.metadata) {
return resProduct.resolveMetadata({ transaction: options.transaction || null });
}
return;
})
.then(() => {
if (product.associations) {
return resProduct.resolveAssociations({ transaction: options.transaction || null });
}
return;
})
.then(() => {
if (product.vendors) {
return resProduct.resolveVendors({ transaction: options.transaction || null });
}
return;
})
.then(() => {
update = {
host: product.host || resProduct.host,
handle: product.handle || resProduct.handle,
seo_title: product.seo_title || resProduct.seo_title,
seo_description: product.seo_description || resProduct.seo_description,
body: product.body || resProduct.body,
type: product.type || resProduct.type,
published_scope: product.published_scope || resProduct.published_scope,
available: product.available,
average_shipping: product.average_shipping,
property_pricing: product.property_pricing,
exclude_payment_types: product.exclude_payment_types,
weight: product.weight || resProduct.weight,
weight_unit: product.weight_unit || resProduct.weight_unit,
requires_shipping: product.requires_shipping || resProduct.requires_shipping,
tax_code: product.tax_code || resProduct.tax_code,
options: productOptions
};
product.variants = product.variants || [];
product.images = product.images || [];
product.tags = product.tags || [];
product.collections = product.collections || [];
product.associations = product.associations || [];
if (product.published === true && resProduct.published === false) {
update.published = resProduct.variants[0].published = product.published;
update.published_at = resProduct.variants[0].published_at = new Date();
}
if (product.published === false && resProduct.published === true) {
update.published = resProduct.variants[0].published = product.published;
update.unpublished_at = resProduct.variants[0].unpublished_at = new Date();
}
if (product.sku) {
resProduct.variants[0].sku = product.sku;
}
if (product.title) {
update.title = resProduct.variants[0].title = product.title;
}
if (product.price) {
update.price = resProduct.variants[0].price = product.price;
}
if (product.compare_at_price) {
update.compare_at_price = resProduct.variants[0].compare_at_price = product.compare_at_price;
}
if (product.seo_title) {
update.seo_title = product.seo_title;
}
if (product.title && !product.seo_title) {
update.seo_title = product.title;
}
if (product.seo_description) {
update.seo_description = this.app.services.ProxyCartService.description(product.seo_description);
}
if (!product.seo_description && product.body) {
update.seo_description = this.app.services.ProxyCartService.description(product.body);
}
resProduct.variants = resProduct.variants.map(variant => {
const variantToUpdate = product.variants.find(v => variant.id === v.id || variant.sku === v.sku) || {};
if (variantToUpdate && variantToUpdate.images) {
let newImages = variantToUpdate.images.filter(image => !image.id);
newImages = newImages.map(image => {
image.product_id = resProduct.id;
image.product_variant_id = variant.id;
return Image.build(image);
});
resProduct.images = _.concat(resProduct.images, newImages);
}
for (const k in variantToUpdate) {
if (variantToUpdate.hasOwnProperty(k) && variantToUpdate.hasOwnProperty(k)) {
if (!_.isNil(variantToUpdate[k])) {
variant[k] = variantToUpdate[k];
}
}
}
return variant;
});
product.variants = product.variants.filter(variant => !variant.id && !resProduct.variants.find(v => {
return v.id === variant.id || v.sku === variant.sku;
}));
product.variants = product.variants.map((variant) => {
variant.product_id = resProduct.id;
variant = this.variantDefaults(variant, resProduct.get({ plain: true }));
if (variant.images.length > 0) {
resProduct.images = resProduct.images.map(image => {
return _.extend(image, variant.images.find(i => i.id === image.id || i.src === image.src));
});
variant.images = variant.images.filter(image => !image.id);
variant.images = variant.images.map(image => {
image.product_id = resProduct.id;
return Image.build(image);
});
resProduct.images = _.concat(resProduct.images, variant.images);
}
return Variant.build(variant);
});
resProduct.variants = _.sortBy(_.concat(resProduct.variants, product.variants), 'position');
resProduct.variants = resProduct.variants.map((variant, index) => {
variant.position = index + 1;
return variant;
});
resProduct.total_variants = resProduct.variants.length;
resProduct.variants.forEach(variant => {
if (variant.option) {
const keys = Object.keys(variant.option);
update.options = _.union(update.options, keys);
}
});
resProduct.images = resProduct.images.map(image => {
const imageToUpdate = product.images.find(i => i.id === image.id || i.src === image.src) || {};
for (const k in imageToUpdate) {
if (imageToUpdate.hasOwnProperty(k) && imageToUpdate.hasOwnProperty(k)) {
if (!_.isNil(imageToUpdate[k])) {
image[k] = imageToUpdate[k];
}
}
}
return image;
});
product.images = product.images.filter(image => !image.id && !resProduct.images.find(i => {
return i.id === image.id || i.src === image.src;
}));
product.images = product.images.map(image => {
image.product_id = resProduct.id;
return Image.build(image);
});
resProduct.images = _.sortBy(_.concat(resProduct.images, product.images), 'position');
resProduct.images = resProduct.images.map((image, index) => {
image.position = index + 1;
return image;
});
return resProduct.updateAttributes(update, { transaction: options.transaction || null });
})
.then(updateProduct => {
if (product.tags && product.tags.length > 0) {
product.tags = _.sortedUniq(product.tags.filter(n => n));
return Tag.transformTags(product.tags, { transaction: options.transaction || null });
}
return;
})
.then(tags => {
if (tags && tags.length > 0) {
return resProduct.setTags(tags.map(t => t.id), { transaction: options.transaction || null });
}
return;
})
.then(productTags => {
if (product.collections && product.collections.length > 0) {
product.collections = _.sortedUniq(product.collections.filter(n => n));
return Collection.transformCollections(product.collections, { transaction: options.transaction || null });
}
return;
})
.then(collections => {
if (collections && collections.length > 0) {
return Product.sequelize.Promise.mapSeries(collections, collection => {
const through = collection.product_position ? { position: collection.product_position } : {};
return resProduct.addCollection(collection.id, {
through: through,
hooks: false,
individualHooks: false,
returning: false,
transaction: options.transaction || null
});
});
}
return;
})
.then(() => {
if (product.metadata && _.isObject(product.metadata)) {
resProduct.metadata.data = product.metadata || {};
return resProduct.metadata.save({ transaction: options.transaction || null });
}
return;
})
.then(metadata => {
if (product.vendors && product.vendors.length > 0) {
return Vendor.transformVendors(product.vendors, { transaction: options.transaction || null });
}
return;
})
.then(vendors => {
if (vendors && vendors.length > 0) {
return resProduct.setVendors(vendors.map(v => v.id), { transaction: options.transaction || null });
}
return;
})
.then(vendors => {
return Product.sequelize.Promise.mapSeries(resProduct.variants, variant => {
if (variant instanceof Variant.instance) {
return variant.save({
transaction: options.transaction || null
})
.catch(err => {
this.app.log.error(err);
return variant;
});
}
else {
return resProduct.createVariant(variant, {
transaction: options.transaction || null
});
}
});
})
.then(variants => {
return Product.sequelize.Promise.mapSeries(resProduct.images, image => {
if (typeof image.variant !== 'undefined') {
image.product_variant_id = resProduct.variants[image.variant].id;
delete image.variant;
}
if (image instanceof Image.instance) {
return image.save({ transaction: options.transaction || null });
}
else {
return resProduct.createImage(image, {
transaction: options.transaction || null
});
}
});
})
.then(images => {
return Product.findByIdDefault(resProduct.id, {
transaction: options.transaction || null
});
});
}
removeProducts(products) {
if (!Array.isArray(products)) {
products = [products];
}
const Product = this.app.models['Product'];
return Product.sequelize.Promise.mapSeries(products, product => {
return this.removeProduct(product);
});
}
removeProduct(product, options = {}) {
if (!product.id) {
const err = new errors_1.ModelError('E_NOT_FOUND', 'Product is missing id');
return Promise.reject(err);
}
const Product = this.app.models.Product;
return Product.destroy({
where: {
id: product.id
},
transaction: options.transaction || null
});
}
removeVariants(variants) {
if (!Array.isArray(variants)) {
variants = [variants];
}
const Product = this.app.models['Product'];
return Product.sequelize.Promise.mapSeries(variants, variant => {
return this.removeVariant(variant);
});
}
createVariant(product, variant, options = {}) {
const Product = this.app.models['Product'];
const Variant = this.app.models['ProductVariant'];
let resProduct, resVariant, productOptions = [];
return Product.resolve(product, { transaction: options.transaction || null })
.then(_product => {
if (!_product) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Could not find Product');
}
resProduct = _product;
variant.product_id = resProduct.id;
variant = this.variantDefaults(variant, resProduct);
return resProduct.createVariant(variant, { transaction: options.transaction || null });
})
.then(_variant => {
resVariant = _variant;
return Variant.findAll({
where: {
product_id: resProduct.id
},
transaction: options.transaction || null
});
})
.then(variants => {
const updates = _.sortBy(variants, 'position');
_.map(updates, (_variant, index) => {
_variant.position = index + 1;
});
_.map(updates, _variant => {
const keys = Object.keys(_variant.option);
productOptions = _.union(productOptions, keys);
});
return Product.sequelize.Promise.mapSeries(updates, _variant => {
return _variant.save({
transaction: options.transaction || null
});
});
})
.then(updatedVariants => {
resProduct.options = productOptions;
resProduct.total_variants = updatedVariants.length;
return resProduct.save({ transaction: options.transaction || null });
})
.then(updatedProduct => {
return Variant.findByIdDefault(resVariant.id, { transaction: options.transaction || null });
});
}
createVariants(product, variants, options) {
const Product = this.app.models['Product'];
return Product.sequelize.Promise.mapSeries(variants, variant => {
return this.createVariant(product, variant, options);
});
}
updateVariant(product, variant, options) {
options = options || {};
const Product = this.app.models['Product'];
const Variant = this.app.models['ProductVariant'];
const Image = this.app.models['ProductImage'];
let resProduct, resVariant, productOptions = [];
return Product.resolve(product, { transaction: options.transaction || null })
.then(_product => {
if (!_product) {
throw new Error('Product did not resolve');
}
resProduct = _product;
return Variant.resolve(variant, options);
})
.then(foundVariant => {
resVariant = foundVariant;
resVariant = _.extend(resVariant, _.omit(variant, ['id', 'sku']));
resVariant = this.variantDefaults(resVariant, resProduct);
return resVariant.resolveImages({ transaction: options.transaction || null });
}).then(() => {
return resVariant.save({ transaction: options.transaction || null });
})
.then(_variant => {
return Variant.findAll({
where: {
product_id: resProduct.id
},
transaction: options.transaction || null
});
})
.then(variants => {
const updates = _.sortBy(variants, 'position');
_.map(updates, (_variant, index) => {
_variant.position = index + 1;
});
_.map(updates, _variant => {
const keys = Object.keys(_variant.option);
productOptions = _.union(productOptions, keys);
});
return Product.sequelize.Promise.mapSeries(updates, _variant => {
return _variant.save({ transaction: options.transaction || null });
});
})
.then(updatedVariants => {
resProduct.options = product.options;
return resProduct.save({ transaction: options.transaction || null });
})
.then(updatedProduct => {
return Variant.findByIdDefault(resVariant.id, { transaction: options.transaction || null });
});
}
updateVariants(product, variants, options) {
const Product = this.app.models['Product'];
return Product.sequelize.Promise.mapSeries(variants, variant => {
return this.updateVariant(product, variant, options);
});
}
removeVariant(id, options = {}) {
const Product = this.app.models['Product'];
const Variant = this.app.models.ProductVariant;
let resVariant, resProduct;
let updates;
let productOptions = [];
return Variant.resolve(id, { transaction: options.transaction || null })
.then(foundVariant => {
resVariant = foundVariant;
return Product.resolve(resVariant.product_id, { transaction: options.transaction || null });
})
.then(product => {
resProduct = product;
return Variant.findAll({
where: {
product_id: resVariant.product_id
},
transaction: options.transaction || null
});
})
.then(foundVariants => {
updates = _.sortBy(_.filter(foundVariants, variant => {
if (variant.id !== resVariant.id) {
return variant;
}
}), 'position');
_.map(updates, (variant, index) => {
variant.position = index + 1;
});
_.map(updates, variant => {
const keys = Object.keys(variant.option);
productOptions = _.union(productOptions, keys);
});
return Variant.sequelize.Promise.mapSeries(updates, variant => {
return variant.save({ transaction: options.transaction || null });
});
})
.then(updatedVariants => {
resProduct.options = productOptions;
resProduct.total_variants = updatedVariants.length;
return resProduct.save({ transaction: options.transaction || null });
})
.then(updatedProduct => {
return resVariant.destroy({ transaction: options.transaction || null });
})
.then(destroyed => {
return resVariant;
});
}
removeImages(images) {
if (!Array.isArray(images)) {
images = [images];
}
const Product = this.app.models['Product'];
return Product.sequelize.Promise.mapSeries(images, image => {
const id = typeof image.id !== 'undefined' ? image.id : image;
return this.removeImage(id);
});
}
removeImage(id, options = {}) {
const Image = this.app.models['ProductImage'];
const Product = this.app.models['Product'];
const Variant = this.app.models['ProductVariant'];
let resDestroy;
return Image.findById(id, {
transaction: options.transaction || null
})
.then(_image => {
if (!_image) {
throw new Error('Image not found');
}
resDestroy = _image;
return Image.findAll({
where: {
product_id: resDestroy.product_id
},
order: [['position', 'ASC']],
transaction: options.transaction || null
});
})
.then(foundImages => {
foundImages = foundImages.filter(image => image.id !== id);
foundImages = foundImages.map((image, index) => {
image.position = index + 1;
return image;
});
return Image.sequelize.Promise.mapSeries(foundImages, image => {
return image.save({
transaction: options.transaction || null
});
});
})
.then(updatedImages => {
return resDestroy.destroy({
transaction: options.transaction || null
});
})
.then(() => {
return resDestroy;
});
}
addImage(product, variant, image, options = {}) {
const Image = this.app.models['ProductImage'];
const Product = this.app.models['Product'];
const Variant = this.app.models['ProductVariant'];
let resProduct, resImage, resVariant;
return Product.resolve(product, { transaction: options.transaction || null })
.then(foundProduct => {
if (!foundProduct) {
throw new Error('Product could not be resolved');
}
resProduct = foundProduct;
if (variant) {
return Variant.resolve(variant, { transaction: options.transaction || null });
}
else {
return null;
}
})
.then(_variant => {
resVariant = _variant ? _variant.id : null;
return resProduct.createImage({
product_variant_id: resVariant,
src: image,
position: options.position || null,
alt: options.alt || null
}, {
transaction: options.transaction
});
})
.then(createdImage => {
if (!createdImage) {
throw new Error('Image Could not be created');
}
resImage = createdImage;
return Image.findAll({
where: {
product_id: resProduct.id
},
order: [['position', 'ASC']],
transaction: options.transaction || null
});
})
.then(_images => {
_images = _images.map((_image, index) => {
_image.position = index + 1;
return _image;
});
return Image.sequelize.Promise.mapSeries(_images, _image => {
return _image.save({
transaction: options.transaction || null
});
});
})
.then(updatedImages => {
return resImage.reload();
});
}
updateImages(images, options = {}) {
if (!Array.isArray(images)) {
images = [images];
}
const Product = this.app.models['Product'];
return Product.sequelize.Promise.mapSeries(images, image => {
return this.updateImage(image, image, options);
});
}
updateImage(image, body, options = {}) {
const Image = this.app.models['ProductImage'];
const Product = this.app.models['Product'];
const Variant = this.app.models['ProductVariant'];
let resUpdate;
return Image.resolve(image, {
transaction: options.transaction || null
})
.then(_image => {
if (!_image) {
throw new Error('Image not found');
}
resUpdate = _image;
return Image.findAll({
where: {
product_id: resUpdate.product_id
},
order: [['position', 'ASC']],
transaction: options.transaction || null
});
})
.then(updatedImages => {
return resUpdate.update(body, {
transaction: options.transaction || null
});
})
.then(() => {
return resUpdate;
});
}
createImage(product, variant, filePath, options = {}) {
const image = fs.readFileSync(filePath);
const Image = this.app.models['ProductImage'];
const Product = this.app.models['Product'];
const Variant = this.app.models['ProductVariant'];
let resProduct, resImage, resVariant;
return Product.resolve(product, { transaction: options.transaction || null })
.then(_product => {
if (!_product) {
throw new Error('Product could not be resolved');
}
resProduct = _product;
if (variant) {
return Variant.resolve(variant, { transaction: options.transaction || null });
}
else {
return null;
}
})
.then(_variant => {
resVariant = _variant ? _variant.id : null;
return this.app.services.ProxyCartService.uploadImage(image, filePath);
})
.then(uploadedImage => {
return resProduct.createImage({
product_variant_id: resVariant,
src: uploadedImage.url,
position: options.position || null,
alt: options.alt || null
}, {
transaction: options.transaction
});
})
.then(createdImage => {
if (!createdImage) {
throw new Error('Image Could not be created');
}
resImage = createdImage;
return Image.findAll({
where: {
product_id: resProduct.id
},
order: [['position', 'ASC']],
transaction: options.transaction || null
});
})
.then(foundImages => {
foundImages = foundImages.map((_image, index) => {
_image.position = index + 1;
return _image;
});
return Image.sequelize.Promise.mapSeries(foundImages, _image => {
return _image.save({
transaction: options.transaction || null
});
});
})
.then(updatedImages => {
return resImage.reload();
});
}
addTag(product, tag, options) {
options = options || {};
const Product = this.app.models['Product'];
const Tag = this.app.models['Tag'];
let resProduct, resTag;
return Product.resolve(product, { transaction: options.transaction || null })
.then(_product => {
if (!_product) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Product not found');
}
resProduct = _product;
return Tag.resolve(tag, { transaction: options.transaction || null });
})
.then(_tag => {
if (!_tag) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Tag not found');
}
resTag = _tag;
return resProduct.hasTag(resTag.id, { transaction: options.transaction || null });
})
.then(hasTag => {
if (!hasTag) {
return resProduct.addTag(resTag.id, { transaction: options.transaction || null });
}
return resProduct;
})
.then(_tag => {
return Product.findByIdDefault(resProduct.id, { transaction: options.transaction || null });
});
}
removeTag(product, tag, options) {
options = options || {};
const Product = this.app.models['Product'];
const Tag = this.app.models['Tag'];
let resProduct, resTag;
return Product.resolve(product, { transaction: options.transaction || null })
.then(_product => {
if (!_product) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Product not found');
}
resProduct = _product;
return Tag.resolve(tag, { transaction: options.transaction || null });
})
.then(_tag => {
if (!_tag) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Tag not found');
}
resTag = _tag;
return resProduct.hasTag(resTag.id, { transaction: options.transaction || null });
})
.then(hasTag => {
if (hasTag) {
return resProduct.removeTag(resTag.id, { transaction: options.transaction || null });
}
return false;
})
.then(newTag => {
return Product.findByIdDefault(resProduct.id, { transaction: options.transaction || null });
});
}
addAssociations(product, associations = [], options = {}) {
const Product = this.app.models['Product'];
let resProduct;
return Product.resolve(product, options)
.then(_product => {
resProduct = _product;
return Product.sequelize.Promise.mapSeries(associations, a => {
return this.addAssociation(resProduct, a, options);
});
});
}
addVariantAssociations(product, variant, associations = [], options = {}) {
const ProductVariant = this.app.models['ProductVariant'];
let resVariant;
return ProductVariant.resolve(variant, options)
.then(_variant => {
resVariant = _variant;
return ProductVariant.sequelize.Promise.mapSeries(associations, a => {
return this.addVariantAssociation(resVariant, a, options);
});
});
}
addAssociation(product, association, options = {}) {
const Product = this.app.models['Product'];
const ProductVariant = this.app.models['ProductVariant'];
let resProduct, resVariant, resAssociationProduct, resAssociationVariant, through;
if (!product || !association) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Product or Association was not provided');
}
return Product.resolve(product, { transaction: options.transaction || null })
.then(_product => {
if (!_product) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Product not found');
}
resProduct = _product;
if (product.sku) {
return ProductVariant.resolve(product, { transaction: options.transaction || null });
}
else {
return resProduct.getDefaultVariant({ transaction: options.transaction || null });
}
})
.then(_variant => {
if (_variant) {
resVariant = _variant;
}
return Product.resolve(association, { transaction: options.transaction || null });
})
.then(_association => {
if (!_association) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Product not found');
}
resAssociationProduct = _association;
if (association.sku) {
return ProductVariant.resolve(association);
}
else {
return resAssociationProduct.getDefaultVariant({ transaction: options.transaction || null });
}
})
.then(_variantAssociation => {
if (_variantAssociation) {
resAssociationVariant = _variantAssociation;
}
through = resVariant && resAssociationVariant ? {
variant_id: resVariant.id,
associated_variant_id: resAssociationVariant.id,
} : {};
if (association.position !== 'undefined') {
through.position = association.position;
}
return resProduct.hasAssociation(resAssociationProduct.id, {
transaction: options.transaction || null,
through: through
});
})
.then(hasAssociation => {
if (!hasAssociation) {
return resProduct.addAssociation(resAssociationProduct.id, {
transaction: options.transaction || null,
through: through
})
.then(() => {
return resProduct.save({ transaction: options.transaction || null });
});
}
return false;
})
.then(_newAssociation => {
return resAssociationProduct;
});
}
removeAssociation(product, association, options = {}) {
const Product = this.app.models['Product'];
const ProductVariant = this.app.models['ProductVariant'];
let resProduct, resVariant, resAssociationProduct, resAssociationVariant, through;
if (!product || !association) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Product or Association was not provided');
}
return Product.resolve(product, { transaction: options.transaction || null })
.then(_product => {
if (!_product) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Product not found');
}
resProduct = _product;
if (product.sku) {
return ProductVariant.resolve(product);
}
return;
})
.then(_variant => {
if (_variant) {
resVariant = _variant;
}
return Product.resolve(association, { transaction: options.transaction || null });
})
.then(_association => {
if (!_association) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Product not found');
}
resAssociationProduct = _association;
if (association.sku) {
return ProductVariant.resolve(association);
}
return;
})
.then(_variantAssociation => {
if (_variantAssociation) {
resAssociationVariant = _variantAssociation;
}
through =