@fabrix/spool-cart
Version:
Spool - eCommerce Spool for Fabrix
751 lines (750 loc) • 30.1 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 _ = require("lodash");
const fs = require("fs");
class CollectionService 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();
}
add(collection, options = {}) {
const Collection = this.app.models.Collection;
return Collection.resolve(collection, {
transaction: options.transaction || null,
reject: false
})
.then(resCollection => {
if (!resCollection) {
return this.create(collection, { transaction: options.transaction || null });
}
else {
resCollection = _.merge(resCollection, collection);
return this.update(resCollection, { transaction: options.transaction || null });
}
});
}
create(collection, options) {
options = options || {};
const Collection = this.app.models['Collection'];
const Image = this.app.models['Image'];
const Discount = this.app.models['Discount'];
const Tag = this.app.models['Tag'];
let discounts = [];
let resCollection;
let create = _.omit(collection, [
'collections',
'images',
'discounts',
'discount_name',
'discount_status',
'discount_code',
'discount_scope',
'discount_type',
'discount_product_exclude',
'discount_product_include',
'discount_rate',
'discount_percentage',
'tags'
]);
create = _.omitBy(create, _.isNil);
if (collection.discount_type && collection.discount_type) {
discounts.push({
name: collection.discount_name || collection.title,
code: collection.discount_code || collection.title,
status: collection.discount_status,
discount_scope: collection.discount_scope,
discount_type: collection.discount_type,
discount_product_exclude: collection.discount_product_exclude,
discount_product_include: collection.discount_product_include,
discount_rate: collection.discount_rate,
discount_percentage: collection.discount_percentage
});
}
if (collection.discounts && collection.discounts.length > 0) {
discounts = [...discounts, ...collection.discounts];
}
return Collection.create(create, { transaction: options.transaction || null })
.then(createdCollection => {
if (!createdCollection) {
throw new Error('Collection was not created');
}
resCollection = createdCollection;
if (collection.collections && collection.collections.length > 0) {
collection.collections = _.sortedUniq(collection.collections.filter(n => n));
return Collection.transformCollections(collection.collections, { transaction: options.transaction || null });
}
return [];
})
.then(collections => {
if (collections && collections.length > 0) {
return resCollection.setCollections(collections.map(c => c.id), { transaction: options.transaction || null });
}
return;
})
.then(collections => {
if (collection.images && collection.images.length > 0) {
collection.images = _.sortedUniq(collection.images.filter(n => n));
return Image.transformImages(collection.images, { transaction: options.transaction || null });
}
return [];
})
.then(images => {
if (images && images.length > 0) {
return Collection.sequelize.Promise.mapSeries(images, (image, index) => {
return resCollection.addImage(image.id, { through: { position: index + 1 }, transaction: options.transaction || null });
});
}
return;
})
.then(() => {
if (discounts.length > 0) {
return Discount.transformDiscounts(discounts, { transaction: options.transaction || null });
}
return;
})
.then(_discounts => {
if (_discounts && _discounts.length > 0) {
return resCollection.setDiscounts(_discounts.map(d => d.id), { transaction: options.transaction || null });
}
return;
})
.then(_discounts => {
if (collection.tags && collection.tags.length > 0) {
collection.tags = _.sortedUniq(collection.tags.filter(n => n));
return Tag.transformTags(collection.tags, { transaction: options.transaction || null });
}
return;
})
.then(tags => {
if (tags && tags.length > 0) {
return resCollection.setTags(tags.map(tag => tag.id), { transaction: options.transaction || null });
}
return;
})
.then(tags => {
return Collection.findByIdDefault(resCollection.id, { transaction: options.transaction || null });
});
}
update(collection, options) {
options = options || {};
const Collection = this.app.models['Collection'];
const Image = this.app.models['Image'];
const Tag = this.app.models['Tag'];
if (!collection.id) {
const err = new errors_1.ModelError('E_NOT_FOUND', 'Collection is missing id');
return Promise.reject(err);
}
const update = _.omit(collection, ['id', 'created_at', 'updated_at', 'collections', 'images', 'tags']);
let resCollection;
return Collection.resolve(collection, {
transaction: options.transaction || null,
reject: true
})
.then(_collection => {
if (!_collection) {
throw new Error('Collection could not be resolved');
}
resCollection = _collection;
return resCollection.update(update, { transaction: options.transaction || null });
})
.then(updatedCollection => {
resCollection = updatedCollection;
if (collection.collections && collection.collections.length > 0) {
collection.collections = _.sortedUniq(collection.collections.filter(n => n));
return Collection.transformCollections(collection.collections, { transaction: options.transaction || null });
}
return;
})
.then(collections => {
if (collections && collections.length > 0) {
return resCollection.setCollections(collections.map(c => c.id), { transaction: options.transaction || null });
}
return [];
})
.then(collections => {
if (collection.images && collection.images.length > 0) {
collection.images = _.sortedUniq(collection.images.filter(n => n));
return Image.transformImages(collection.images, { transaction: options.transaction || null });
}
else {
return [];
}
})
.then(images => {
if (images && images.length > 0) {
return Collection.sequelize.Promise.mapSeries(images, (image, index) => {
return resCollection.addImage(image.id, {
through: { position: index + 1 },
transaction: options.transaction || null
});
});
}
return;
})
.then(images => {
if (collection.tags && collection.tags.length > 0) {
collection.tags = _.sortedUniq(collection.tags.filter(n => n));
return Tag.transformTags(collection.tags, { transaction: options.transaction || null });
}
return;
})
.then(tags => {
if (tags && tags.length > 0) {
return resCollection.setTags(tags.map(tag => tag.id), { transaction: options.transaction || null });
}
return;
})
.then(() => {
return Collection.findByIdDefault(resCollection.id, { transaction: options.transaction || null });
});
}
addCollections(collection, collections, options) {
options = options || {};
if (!Array.isArray(collections)) {
collections = [collections];
}
const Sequelize = this.app.models['Collection'].sequelize;
return Sequelize.transaction(t => {
return Sequelize.Promise.mapSeries(collections, subCollection => {
return this.addCollection(collection, subCollection, {
transaction: t
});
});
});
}
addCollection(collection, subCollection, options = {}) {
const Collection = this.app.models['Collection'];
let resCollection, resSubCollection;
return Collection.resolveOrCreate(collection, {
transaction: options.transaction || null
})
.then(([_collection, _created]) => {
if (!_collection) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Collection not found');
}
resCollection = _collection;
return Collection.resolve(subCollection, {
transaction: options.transaction || null,
reject: true
});
})
.then(_subCollection => {
if (!_subCollection) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Sub Collection not found');
}
resSubCollection = _subCollection;
const through = subCollection.collection_position ? { position: subCollection.collection_position } : {};
return resCollection.addCollection(resSubCollection.id, {
through: through,
hooks: false,
individualHooks: false,
returning: false,
transaction: options.transaction || null
});
})
.then(() => {
return resSubCollection;
});
}
removeCollections(collection, collections, options = {}) {
if (!Array.isArray(collections)) {
collections = [collections];
}
const Sequelize = this.app.models['Collection'].sequelize;
return Sequelize.transaction(t => {
return Sequelize.Promise.mapSeries(collections, subCollection => {
return this.removeCollection(collection, subCollection, {
transaction: t
});
});
});
}
removeCollection(collection, subCollection, options) {
options = options || {};
const Collection = this.app.models['Collection'];
let resCollection, resSubCollection;
return Collection.resolve(collection, {
transaction: options.transaction || null,
reject: true
})
.then(_collection => {
if (!_collection) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Collection not found');
}
resCollection = _collection;
return Collection.resolve(subCollection, {
transaction: options.transaction || null,
reject: true
});
})
.then(_subCollection => {
if (!_subCollection) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Sub Collection not found');
}
resSubCollection = _subCollection;
return resCollection.hasCollection(resSubCollection.id, { transaction: options.transaction || null });
})
.then(hasCollection => {
if (hasCollection) {
return resCollection.removeCollection(resSubCollection.id, { transaction: options.transaction || null });
}
return resCollection;
})
.then(_collection => {
return resSubCollection;
});
}
addProducts(collection, products, options) {
options = options || {};
if (!Array.isArray(products)) {
products = [products];
}
const Sequelize = this.app.models['Collection'].sequelize;
return Sequelize.transaction(t => {
return Sequelize.Promise.mapSeries(products, product => {
return this.addProduct(collection, product, {
transaction: t
});
});
});
}
addProduct(collection, product, options) {
options = options || {};
const Collection = this.app.models['Collection'];
const Product = this.app.models['Product'];
let resCollection, resProduct;
return Collection.resolve(collection, {
transaction: options.transaction || null,
reject: true
})
.then(_collection => {
if (!_collection) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Collection not found');
}
resCollection = _collection;
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 resCollection.hasProduct(resProduct.id, { transaction: options.transaction || null });
})
.then(hasCollection => {
const through = product.product_position ? { position: product.product_position } : {};
return resCollection.addProduct(resProduct.id, {
through: through,
transaction: options.transaction || null
});
})
.then(_collection => {
return resProduct;
});
}
removeProduct(collection, product, options) {
options = options || {};
const Collection = this.app.models['Collection'];
const Product = this.app.models['Product'];
let resCollection, resProduct;
return Collection.resolve(collection, {
transaction: options.transaction || null,
reject: true
})
.then(_collection => {
if (!_collection) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Collection not found');
}
resCollection = _collection;
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 resCollection.hasProduct(resProduct.id, { transaction: options.transaction || null });
})
.then(hasCollection => {
if (hasCollection) {
return resCollection.removeProduct(resProduct.id, { transaction: options.transaction || null });
}
return resCollection;
})
.then(_collection => {
return resProduct;
});
}
removeImages(collection, images) {
if (!Array.isArray(images)) {
images = [images];
}
const Collection = this.app.models['Collection'];
return Collection.sequelize.Promise.mapSeries(images, image => {
const collectionId = typeof collection.id !== 'undefined' ? collection.id : collection;
const id = typeof image.id !== 'undefined' ? image.id : image;
return this.removeImage(collectionId, id);
});
}
removeImage(collectionId, id, options = {}) {
const Image = this.app.models['ItemImage'];
const Collection = this.app.models['Collection'];
let resDestroy;
return Image.findOne({ where: { image_id: id } }, {
transaction: options.transaction || null
})
.then(_image => {
if (!_image) {
throw new Error(`Image ${id} not found`);
}
resDestroy = _image;
return Image.findAll({
where: {
model_id: resDestroy.model_id,
model: 'collection'
},
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;
});
}
addImages(collection, images) {
if (!Array.isArray(images)) {
images = [images];
}
const Collection = this.app.models['Collection'];
return Collection.sequelize.Promise.mapSeries(images, image => {
const id = typeof image.id !== 'undefined' ? image.id : image;
return this.addImage(collection, id);
});
}
addImage(collection, image, options = {}) {
const Image = this.app.models['ItemImage'];
const Collection = this.app.models['Collection'];
let resCollection, resImage;
return Collection.resolve(collection, { transaction: options.transaction || null })
.then(foundCollection => {
if (!foundCollection) {
throw new Error('Collection could not be resolved');
}
resCollection = foundCollection;
return resCollection.createImage({
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: {
model_id: resCollection.id,
model: 'collection'
},
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();
});
}
createImage(collection, filePath, options = {}) {
const image = fs.readFileSync(filePath);
const Image = this.app.models['ItemImage'];
const Collection = this.app.models['Collection'];
let resCollection, resImage;
return Collection.resolve(collection, { transaction: options.transaction || null })
.then(_collection => {
if (!_collection) {
throw new Error('Collection could not be resolved');
}
resCollection = _collection;
return this.app.services.ProxyCartService.uploadImage(image, filePath);
})
.then(uploadedImage => {
return resCollection.createImage({
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: {
model_id: resCollection.id,
model: 'collection'
},
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(collection, tag, options) {
options = options || {};
const Collection = this.app.models['Collection'];
const Tag = this.app.models['Tag'];
let resCollection, resTag;
return Collection.resolve(collection, {
transaction: options.transaction || null,
reject: true
})
.then(_collection => {
if (!_collection) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Collection not found');
}
resCollection = _collection;
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 resCollection.hasTag(resTag.id, { transaction: options.transaction || null });
})
.then(hasCollection => {
if (!hasCollection) {
return resCollection.addTag(resTag.id, { transaction: options.transaction || null });
}
return resCollection;
})
.then(_collection => {
return Collection.findByIdDefault(resCollection.id, { transaction: options.transaction || null });
});
}
removeTag(collection, tag, options) {
options = options || {};
const Collection = this.app.models['Collection'];
const Tag = this.app.models['Tag'];
let resCollection, resTag;
return Collection.resolve(collection, {
transaction: options.transaction || null,
reject: true
})
.then(_collection => {
if (!_collection) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Collection not found');
}
resCollection = _collection;
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 resCollection.hasTag(resTag.id, { transaction: options.transaction || null });
})
.then(hasCollection => {
if (hasCollection) {
return resCollection.removeTag(resTag.id, { transaction: options.transaction || null });
}
return resCollection;
})
.then(_collection => {
return Collection.findByIdDefault(resCollection.id, { transaction: options.transaction || null });
});
}
addCustomers(collection, customers, options) {
options = options || {};
if (!Array.isArray(customers)) {
customers = [customers];
}
const Sequelize = this.app.models['Collection'].sequelize;
return Sequelize.transaction(t => {
return Sequelize.Promise.mapSeries(customers, customer => {
return this.addCustomer(collection, customer, {
transaction: t
});
});
});
}
addCustomer(collection, customer, options) {
options = options || {};
const Collection = this.app.models['Collection'];
const Customer = this.app.models['Customer'];
let resCollection, resCustomer;
return Collection.resolve(collection, {
transaction: options.transaction || null,
reject: true
})
.then(_collection => {
if (!_collection) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Collection not found');
}
resCollection = _collection;
return Customer.resolve(customer, { transaction: options.transaction || null, create: false });
})
.then(_customer => {
if (!_customer) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Customer not found');
}
resCustomer = _customer;
return resCollection.hasCustomer(resCustomer.id, { transaction: options.transaction || null });
})
.then(hasCollection => {
if (!hasCollection) {
return resCollection.addCustomer(resCustomer.id, { transaction: options.transaction || null });
}
return resCollection;
})
.then(_collection => {
return resCustomer;
});
}
removeCustomer(collection, customer, options = {}) {
const Collection = this.app.models['Collection'];
const Customer = this.app.models['Customer'];
let resCollection, resCustomer;
return Collection.resolve(collection, {
transaction: options.transaction || null,
reject: true
})
.then(_collection => {
if (!_collection) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Collection not found');
}
resCollection = _collection;
return Customer.resolve(customer, { create: false });
})
.then(_customer => {
if (!_customer) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Customer not found');
}
resCustomer = _customer;
return resCollection.hasCustomer(resCustomer.id);
})
.then(hasCollection => {
if (hasCollection) {
return resCollection.removeCustomer(resCustomer.id);
}
return resCollection;
})
.then(_collection => {
return resCustomer;
});
}
analytics(collection, options = {}) {
const Collection = this.app.models['Collection'];
const OrderItem = this.app.models['OrderItem'];
let resCollection;
return Collection.resolve(collection, {
transaction: options.transaction || null,
reject: true
})
.then(_collection => {
if (!_collection) {
throw new errors_1.ModelError('E_NOT_FOUND', 'Collection not found');
}
resCollection = _collection;
return resCollection.resolveProducts({ attributes: ['id'] });
})
.then((_collection) => {
const ids = resCollection.products.map(p => p.id);
console.log(ids);
return OrderItem.findAll({
where: {
product_id: ids
},
attributes: [
[OrderItem.sequelize.literal('SUM(calculated_price)'), 'total'],
[OrderItem.sequelize.literal('SUM(price)'), 'value'],
[OrderItem.sequelize.literal('COUNT(id)'), 'count'],
],
})
.then(count => {
let data = count.map(c => {
const cTotal = c instanceof OrderItem.instance
? c.get('total') || 0
: c.total || 0;
const cValue = c instanceof OrderItem.instance
? c.get('value') || 0
: c.value || 0;
const cCount = c instanceof OrderItem.instance
? c.get('count') || 0
: c.count || 0;
return {
count: parseInt(cCount, 10),
total: parseInt(cTotal, 10),
value: parseInt(cValue, 10)
};
});
if (data.length === 0) {
data = [{
count: 0,
total: 0,
value: 0
}];
}
return data;
});
});
}
}
exports.CollectionService = CollectionService;