trailpack-proxy-cart
Version:
eCommerce - Trailpack for Proxy Engine
267 lines (247 loc) • 7.91 kB
JavaScript
/* eslint no-console: [0] */
'use strict'
const Service = require('trails/service')
const csvParser = require('papaparse')
const _ = require('lodash')
const shortid = require('shortid')
const fs = require('fs')
const SUBSCRIPTION_UPLOAD = require('../../lib').Enums.SUBSCRIPTION_UPLOAD
/**
* @module SubscriptionCsvService
* @description Subscription Csv Service
*/
module.exports = class SubscriptionCsvService extends Service {
/**
*
* @param file
* @returns {Promise}
*/
subscriptionCsv(file) {
console.time('csv')
const uploadID = shortid.generate()
const ProxyEngineService = this.app.services.ProxyEngineService
const errors = []
let errorsCount = 0, lineNumber = 1
return new Promise((resolve, reject)=>{
const options = {
header: true,
dynamicTyping: true,
encoding: 'utf-8',
step: (results, parser) => {
parser.pause()
lineNumber++
return this.csvSubscriptionRow(results.data[0], uploadID)
.then(row => {
parser.resume()
})
.catch(err => {
errorsCount++
errors.push(`Line ${lineNumber}: ${err.message}`)
this.app.log.error('ROW ERROR', err)
parser.resume()
})
},
complete: (results, file) => {
console.timeEnd('csv')
// console.log('Parsing complete:', results, file)
results.upload_id = uploadID
ProxyEngineService.count('SubscriptionUpload', { where: { upload_id: uploadID }})
.then(count => {
results.subscriptions = count
results.errors = errors
results.errors_count = errorsCount
// Publish the event
ProxyEngineService.publish('subscription_upload.complete', results)
return resolve(results)
})
.catch(err => {
errorsCount++
errors.push(err.message)
results.errors = errors
results.errors_count = errorsCount
return resolve(results)
})
},
error: (err, file) => {
return reject(err)
}
}
const fileString = fs.readFileSync(file, 'utf8')
// Parse the CSV/TSV
csvParser.parse(fileString, options)
})
}
/**
*
* @param row
* @param uploadID
*/
csvSubscriptionRow(row, uploadID) {
// Wrap this in a promise so we can gracefully handle an error
return Promise.resolve()
.then(() => {
const SubscriptionUpload = this.app.orm.SubscriptionUpload
const values = _.values(SUBSCRIPTION_UPLOAD)
const keys = _.keys(SUBSCRIPTION_UPLOAD)
const upload = {
upload_id: uploadID,
options: {}
}
_.each(row, (data, key) => {
if (typeof(data) === 'undefined' || data === '') {
row[key] = null
}
})
row = _.omitBy(row, _.isNil)
if (_.isEmpty(row)) {
return Promise.resolve({})
}
_.each(row, (data, key) => {
if (typeof(data) !== 'undefined' && data !== null && data !== '') {
const i = values.indexOf(key.replace(/^\s+|\s+$/g, ''))
const k = keys[i]
if (i > -1 && k) {
if (k === 'products') {
upload[k] = data.split(',').map(product => { return product.trim()})
}
else {
upload[k] = data
}
}
}
})
upload.products = _.map(upload.products, (handle, index) => {
return {
handle: handle
}
})
// customer is required, if not here, then reject whole row without error
if (!upload.customer) {
return Promise.resolve({})
}
const newSubscription = SubscriptionUpload.build(upload)
return newSubscription.save()
})
}
/**
*
* @param uploadId
* @returns {Promise}
*/
processSubscriptionUpload(uploadId) {
const SubscriptionUpload = this.app.orm.SubscriptionUpload
const errors = []
let subscriptionsTotal = 0, errorsCount = 0
return SubscriptionUpload.batch({
where: {
upload_id: uploadId
}
}, (subscriptions) => {
const Sequelize = this.app.orm.Subscription.sequelize
return Sequelize.Promise.mapSeries(subscriptions, subscription => {
const create = {
customer: {
email: subscription.customer
},
email: subscription.customer,
products: subscription.products,
interval: subscription.interval,
unit: subscription.unit,
active: subscription.active,
token: subscription.token
}
// console.log('UPLOAD SUBSCRIPTION', create)
return this.transformFromRow(create)
.then(() => {
subscriptionsTotal++
return
})
.catch(err => {
errorsCount++
errors.push(`${subscription.customer}: ${err.message}`)
return
})
})
})
.then(results => {
return SubscriptionUpload.destroy({where: {upload_id: uploadId }})
.catch(err => {
errorsCount++
errors.push(err.message)
return
})
})
.then(destroyed => {
const results = {
upload_id: uploadId,
subscriptions: subscriptionsTotal,
errors: errors,
errors_count: errorsCount
}
this.app.services.ProxyEngineService.publish('subscription_process.complete', results)
return results
})
}
/**
*
* @param obj
* @param options
* @returns {Promise.<TResult>}
*/
transformFromRow(obj, options) {
options = options || {}
let resCustomer, resProducts
const Customer = this.app.orm['Customer']
const Subscription = this.app.orm['Subscription']
const resSubscription = Subscription.build(obj)
return Customer.resolve(obj.customer, {transaction: options.transaction || null, create: true})
.then(customer => {
resCustomer = customer
return this.app.orm['Product'].findAll({
where: {
handle: obj.products.map(product => product.handle)
},
transaction: options.transaction || null
})
})
.then(products => {
resProducts = products
return Promise.all(resProducts.map(item => {
return this.app.services.ProductService.resolveItem(item, {transaction: options.transaction || null})
}))
})
.then(resolvedItems => {
return Subscription.sequelize.Promise.mapSeries(resolvedItems, (item) => {
// item = _.omit(item.get({plain: true}), [
// 'requires_subscription',
// 'subscription_unit',
// 'subscription_interval'
// ])
return resSubscription.addLine(item, 1, [])
})
})
.then(resolvedItems => {
resSubscription.customer_id = resCustomer.id
return resSubscription.save({transaction: options.transaction || null})
})
.then(subscription => {
const event = {
object_id: subscription.customer_id,
object: 'customer',
objects: [{
customer: subscription.customer_id
},{
subscription: subscription.id
}],
type: 'customer.subscription.started',
message: `Customer imported subscription ${subscription.token} started`,
data: subscription
}
this.app.services.ProxyEngineService.publish(event.type, event, {
save: true,
transaction: options.transaction || null
})
return subscription
})
}
}