UNPKG

trailpack-proxy-cart

Version:

eCommerce - Trailpack for Proxy Engine

496 lines (476 loc) 16.2 kB
/* eslint no-console: [0] */ 'use strict' const Service = require('trails/service') // const _ = require('lodash') const Errors = require('proxy-engine-errors') const FULFILLMENT_SERVICE = require('../../lib').Enums.FULFILLMENT_SERVICE const FULFILLMENT_STATUS = require('../../lib').Enums.FULFILLMENT_STATUS // const ORDER_FINANCIAL = require('../../lib').Enums.ORDER_FINANCIAL /** * @module FulfillmentService * @description Fulfillment Service */ module.exports = class FulfillmentService extends Service { /** * * @param order * @param fulfillment * @param options * @returns {Promise.<T>} */ sendFulfillment(order, fulfillment, options) { options = options || {} const Order = this.app.orm['Order'] const Fulfillment = this.app.orm['Fulfillment'] let resOrder, resFulfillment return Order.resolve(order, {transaction: options.transaction || null}) .then(_order => { if (!_order) { throw new Error('Order not found') } resOrder = _order return Fulfillment.resolve(fulfillment, {transaction: options.transaction || null}) }) .then(_fulfillment => { if (!_fulfillment) { throw new Error('Fulfillment not found') } resFulfillment = _fulfillment return resFulfillment.resolveOrderItems({transaction: options.transaction || null}) }) .then(() => { if (!resFulfillment.order_items) { throw new Error('Fulfillment missing order_items') } // If a manually supplied and a non-shippable item, mark as fully fulfilled if ( resFulfillment.service === FULFILLMENT_SERVICE.MANUAL && !resFulfillment.order_items.some(i => i.requires_shipping === true) ){ resFulfillment.fulfilled() return Fulfillment.sequelize.Promise.mapSeries(resFulfillment.order_items, item => { item.fulfillment_status = resFulfillment.status return item.save({ hooks: false, transaction: options.transaction || null }) }) } // If a manually supplied and a shippable item, mark as sent to manual else if ( resFulfillment.service === FULFILLMENT_SERVICE.MANUAL && resFulfillment.order_items.some(i => i.requires_shipping === true) ){ resFulfillment.sent() return Fulfillment.sequelize.Promise.mapSeries(resFulfillment.order_items, item => { item.fulfillment_status = resFulfillment.status return item.save({ hooks: false, transaction: options.transaction || null }) }) } else { return this.app.services.FulfillmentGenericService.createOrder(resFulfillment, resFulfillment.service) .then(result => { resFulfillment[result.status]() return Fulfillment.sequelize.Promise.mapSeries(resFulfillment.order_items, item => { item.fulfillment_status = resFulfillment.status return item.save({ hooks: false, transaction: options.transaction || null }) }) }) } }) .then(() => { return resFulfillment.saveFulfillmentStatus({transaction: options.transaction || null}) }) .then(() => { // TODO, put this in life cycle const event = { object_id: resFulfillment.order_id, object: 'order', objects: [{ order: resOrder.id },{ customer: resOrder.customer_id },{ fulfillment: resFulfillment.id }], type: `order.fulfillment.${resFulfillment.status}`, message: `Order ${resOrder.name} fulfillment ID ${resFulfillment.id} ${resFulfillment.status}`, data: resFulfillment } return this.app.services.ProxyEngineService.publish(event.type, event, { save: true, transaction: options.transaction || null }) }) .then(event => { return resFulfillment }) } /** * * @param fulfillment * @param options * @returns {Promise.<T>} */ updateFulfillment(fulfillment, options) { options = options || {} const Fulfillment = this.app.orm['Fulfillment'] let resFulfillment return Fulfillment.resolve(fulfillment, {transaction: options.transaction || null}) .then(_fulfillment => { if (!_fulfillment) { throw new Error('Fulfillment not found') } if ([FULFILLMENT_STATUS.FULFILLED, FULFILLMENT_STATUS.CANCELLED].indexOf(_fulfillment.status) > -1) { throw new Error(`Fulfillment status must be ${ FULFILLMENT_STATUS.PENDING }, ${ FULFILLMENT_STATUS.NONE }, ${FULFILLMENT_STATUS.PARTIAL}, ${FULFILLMENT_STATUS.SENT} to update`) } resFulfillment = _fulfillment if ([FULFILLMENT_STATUS.NONE, FULFILLMENT_STATUS.PENDING].indexOf(resFulfillment.status) > -1) { return } else if ([FULFILLMENT_STATUS.SENT, FULFILLMENT_STATUS.PARTIAL].indexOf(resFulfillment.status) > -1) { return this.app.services.FulfillmentGenericService.updateOrder(resFulfillment, resFulfillment.service) } else { // Unhandled return } }) .then(() => { return resFulfillment.saveFulfillmentStatus({transaction: options.transaction || null}) }) } /** * * @param fulfillment * @param options * @returns {Promise.<TResult>} */ cancelFulfillment(fulfillment, options) { options = options || {} const Fulfillment = this.app.orm['Fulfillment'] let resFulfillment return Fulfillment.resolve(fulfillment, { transaction: options.transaction || null }) .then(_fulfillment => { if (!_fulfillment) { throw new Error('Fulfillment not found') } if ([FULFILLMENT_STATUS.FULFILLED, FULFILLMENT_STATUS.CANCELLED].indexOf(_fulfillment.status) > -1) { throw new Error(`Fulfillment status must be ${ FULFILLMENT_STATUS.PENDING }, ${ FULFILLMENT_STATUS.NONE }, ${FULFILLMENT_STATUS.PARTIAL}, ${FULFILLMENT_STATUS.SENT} to be cancelled`) } resFulfillment = _fulfillment return resFulfillment.resolveOrderItems({transaction: options.transaction || null,}) }) .then(() => { if ([FULFILLMENT_STATUS.NONE, FULFILLMENT_STATUS.PENDING].indexOf(resFulfillment.status) > -1) { return } else if (resFulfillment.service === FULFILLMENT_SERVICE.MANUAL) { return } else { return this.app.services.FulfillmentGenericService.destroyOrder(resFulfillment, resFulfillment.service) } }) .then(() => { resFulfillment.cancelled() return resFulfillment.fulfillUpdate( {status: FULFILLMENT_STATUS.CANCELLED }, {transaction: options.transaction || null} ) }) .then(() => { return resFulfillment.save({transaction: options.transaction || null}) }) } /** * * @param item * @param options * @returns {Promise.<T>} */ addOrCreateFulfillmentItem(item, options) { options = options || {} const OrderItem = this.app.orm['OrderItem'] const Fulfillment = this.app.orm['Fulfillment'] let resOrderItem, resFulfillment return OrderItem.resolve(item, {transaction: options.transaction || null}) .then(_item => { if (!_item) { throw new Errors.FoundError('Order Item not Found') } resOrderItem = _item return Fulfillment.find({ where: { order_id: resOrderItem.order_id, service: resOrderItem.fulfillment_service }, include: [ { model: OrderItem, as: 'order_items' } ], transaction: options.transaction || null }) }) .then(_fulfillment => { if (_fulfillment) { resFulfillment = _fulfillment return resFulfillment.addOrder_item(resOrderItem, { hooks: false, individualHooks: false, returning: false, transaction: options.transaction || null }) .then(() => { return resFulfillment.reload({transaction: options.transaction || null}) .then(() => { return resFulfillment.saveFulfillmentStatus({transaction: options.transaction || null}) }) }) .then(() => { return this.updateFulfillment(resFulfillment, {transaction: options.transaction || null}) }) } else { resFulfillment = Fulfillment.build({ order_id: resOrderItem.order_id, service: resOrderItem.fulfillment_service, // order_items: [ // resOrderItem // ] }, { include: [ { model: OrderItem, as: 'order_items' } ]}) // console.log('addOrCreateFulfillment Creating...', resOrderItem, resFulfillment) return resFulfillment.save({transaction: options.transaction || null}) .then(() => { return resFulfillment.addOrder_item(resOrderItem, { hooks: false, individualHooks: false, returning: false, transaction: options.transaction || null }) .then(() => { return resFulfillment.reload({transaction: options.transaction || null}) .then(() => { return resFulfillment.saveFulfillmentStatus({transaction: options.transaction || null}) }) }) .then(() => { return this.updateFulfillment(resFulfillment, {transaction: options.transaction || null}) }) }) // .then(() => { // return resFulfillment.reload({transaction: options.transaction || null}) // }) // .then(() => { // return resFulfillment.saveFulfillmentStatus({transaction: options.transaction || null}) // }) } }) .then(() => { return resOrderItem.reload({transaction: options.transaction || null}) }) } /** * * @param item * @param options * @returns {Promise.<TResult>} */ updateFulfillmentItem(item, options) { options = options || {} const OrderItem = this.app.orm['OrderItem'] const Fulfillment = this.app.orm['Fulfillment'] let resOrderItem, resFulfillment return OrderItem.resolve(item, {transaction: options.transaction || null}) .then(_item => { if (!_item) { throw new Errors.FoundError('Order Item not Found') } resOrderItem = _item return Fulfillment.find({ where: { order_id: resOrderItem.order_id, service: resOrderItem.fulfillment_service }, include: [ { model: OrderItem, as: 'order_items' } ], transaction: options.transaction || null }) }) .then(fulfillment => { if (!fulfillment) { throw new Errors.FoundError('Fulfillment not found') } resFulfillment = fulfillment return resFulfillment.hasOrder_item(resOrderItem.id, {transaction: options.transaction || null}) }) .then(hasOrderItem => { if (!hasOrderItem) { return resFulfillment.addOrder_item(resOrderItem, { hooks: false, individualHooks: false, returning: false, transaction: options.transaction || null }) } else { return } }) .then(() => { return resFulfillment.reload({transaction: options.transaction || null}) }) .then(() => { return resFulfillment.saveFulfillmentStatus({transaction: options.transaction || null}) }) .then(() => { return this.updateFulfillment(resFulfillment, {transaction: options.transaction || null}) }) .then(() => { return resOrderItem.reload({transaction: options.transaction || null}) }) } /** * * @param item * @param options * @returns {*|Promise.<TResult>} */ removeFulfillmentItem(item, options) { options = options || {} const OrderItem = this.app.orm['OrderItem'] const Fulfillment = this.app.orm['Fulfillment'] let resOrderItem, resFulfillment return OrderItem.resolve(item, options) .then(_item => { if (!_item) { throw new Error('Order Item not Found') } resOrderItem = _item return Fulfillment.find({ where: { order_id: resOrderItem.order_id, service: resOrderItem.fulfillment_service }, include: [ { model: OrderItem, as: 'order_items' } ], transaction: options.transaction || null }) }) .then(fulfillment => { if (!fulfillment) { throw new Errors.FoundError('Fulfillment not found') } resFulfillment = fulfillment return resFulfillment.hasOrder_item(resOrderItem, {transaction: options.transaction || null}) }) .then(hasOrderItem => { if (hasOrderItem && resOrderItem.quantity === 0) { return resFulfillment.removeOrder_item(resOrderItem, { hooks: false, individualHooks: false, returning: false, transaction: options.transaction || null }) } else { return } }) .then(() => { return resFulfillment.reload({transaction: options.transaction || null}) }) .then(() => { return resFulfillment.saveFulfillmentStatus({transaction: options.transaction || null}) }) .then(() => { return this.updateFulfillment(resFulfillment, {transaction: options.transaction || null}) }) .then(() => { return resOrderItem }) } /** * * @param fulfillment * @param options * @returns {Promise.<T>} */ manualUpdateFulfillment(fulfillment, options) { options = options || {} const Fulfillment = this.app.orm['Fulfillment'] let resFulfillment return Fulfillment.resolve(fulfillment, {transaction: options.transaction || null}) .then(_fulfillment => { if (!_fulfillment) { throw new Error('Fulfillment not found') } resFulfillment = _fulfillment return resFulfillment.fulfillUpdate( fulfillment, {transaction: options.transaction || null} ) }) .then((_update) => { return resFulfillment.save({transaction: options.transaction || null}) }) } beforeCreate(fulfillment, options){ return Promise.resolve(fulfillment) } beforeUpdate(fulfillment, options){ return Promise.resolve(fulfillment) } /** * * @param fulfillment * @param options * @returns {Promise.<TResult>} */ afterCreate(fulfillment, options) { return fulfillment.reconcileFulfillmentStatus({transaction: options.transaction || null}) } /** * * @param fulfillment * @param options * @returns {Promise.<TResult>} */ afterUpdate(fulfillment, options) { return fulfillment.reconcileFulfillmentStatus({transaction: options.transaction || null}) } beforeEventCreate(fulfillment, options){ return Promise.resolve(fulfillment) } beforeEventUpdate(fulfillment, options){ return Promise.resolve(fulfillment) } afterEventCreate(fulfillment, options){ return Promise.resolve(fulfillment) } afterEventUpdate(fulfillment, options){ return Promise.resolve(fulfillment) } }