Skip to content

Commit

Permalink
Merge pull request #86 from sphereio/60-remove-zero-stock-inventories
Browse files Browse the repository at this point in the history
feat(stockImport): add a possibility to remove zero inventories
  • Loading branch information
junajan committed Feb 19, 2019
2 parents b506c89 + 3db330b commit aeed76c
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 52 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 15 additions & 1 deletion src/coffee/run.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ argv = require('optimist')
.describe('sphereAuthProtocol', 'SPHERE.IO OAuth protocol to connect to')
.describe('file', 'XML or CSV file containing inventory information to import')
.describe('csvDelimiter', 'the delimiter type used in the csv')
.describe('removeZeroInventories', 'Remove inventory entries where the quantityOnStock equals to zero')
.describe('sftpCredentials', 'the path to a JSON file where to read the credentials from')
.describe('sftpHost', 'the SFTP host (overwrite value in sftpCredentials JSON, if given)')
.describe('sftpUsername', 'the SFTP username (overwrite value in sftpCredentials JSON, if given)')
Expand All @@ -35,6 +36,7 @@ argv = require('optimist')
.describe('logSilent', 'use console to print messages')
.describe('timeout', 'Set timeout for requests')
.default('csvDelimiter', ',')
.default('removeZeroInventories', false)
.default('logLevel', 'info')
.default('logDir', '.')
.default('logSilent', false)
Expand Down Expand Up @@ -62,6 +64,12 @@ if argv.logSilent
process.on 'SIGUSR2', -> logger.reopenFileStreams()
process.on 'exit', => process.exit(@exitCode)

removeZeroInventories = (importer, logger) ->
logger.info("Deleting inventories with zero quantity on stock")
importer.removeZeroInventories()
.then (removedInventoriesCount) ->
logger.info "Removed #{removedInventoriesCount} inventories with zero quantity on stock"

importFn = (importer, fileName) ->
throw new Error 'You must provide a file to be processed' unless fileName
logger.debug "About to process file #{fileName}"
Expand Down Expand Up @@ -98,6 +106,7 @@ ensureCredentials = (argv) ->
ensureCredentials(argv)
.then (credentials) =>
options = _.extend credentials,
removeZeroInventories: argv.removeZeroInventories
timeout: argv.timeout
user_agent: "#{package_json.name} - #{package_json.version}"
csvDelimiter: argv.csvDelimiter
Expand All @@ -115,6 +124,9 @@ ensureCredentials(argv)

if file
importFn(stockimport, file)
.then =>
if argv.removeZeroInventories
removeZeroInventories(stockimport, logger)
.then => @exitCode = 0
.catch (error) =>
logger.error error, 'Oops, something went wrong when processing file (no SFTP)!'
Expand Down Expand Up @@ -168,7 +180,6 @@ ensureCredentials(argv)
else file
else
filename = file

logger.debug "Finishing processing file #{file}"
sftpHelper.finish(file, filename)
.then ->
Expand All @@ -182,6 +193,9 @@ ensureCredentials(argv)
else
Promise.reject err
, {concurrency: 1}
.then =>
if argv.removeZeroInventories
removeZeroInventories(stockimport, logger)
.then =>
totFiles = _.size(filesToProcess)
if totFiles > 0
Expand Down
45 changes: 42 additions & 3 deletions src/coffee/stockimport.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class StockImport
@sync = new InventorySync
@client = new SphereClient options
@csvHeaders = options.csvHeaders
@shouldRemoveZeroInventories = options.removeZeroInventories
@csvDelimiter = options.csvDelimiter
@customFieldMappings = new CustomFieldMappings()
@max409Retries = options.max409Retries
Expand All @@ -27,6 +28,9 @@ class StockImport
created: 0
updated: 0

if @shouldRemoveZeroInventories
@_summary.removed = 0

getMode: (fileName) ->
switch
when fileName.match /\.csv$/i then 'CSV'
Expand Down Expand Up @@ -104,11 +108,15 @@ class StockImport
Promise.reject "#{CONS.LOG_PREFIX}Unknown import mode '#{mode}'!"

summaryReport: (filename) ->
if @_summary.created is 0 and @_summary.updated is 0
if @_summary.created is 0 and @_summary.updated is 0 and (not @shouldRemoveZeroInventories or @_summary.removed is 0)
message = 'Summary: nothing to do, everything is fine'
else
deletedStocksMessage = ""
if @shouldRemoveZeroInventories
deletedStocksMessage = " and #{@_summary.removed} were deletions"

message = "Summary: there were #{@_summary.created + @_summary.updated} imported stocks " +
"(#{@_summary.created} were new and #{@_summary.updated} were updates)"
"(#{@_summary.created} were new, #{@_summary.updated} were updates#{deletedStocksMessage})"

if @_summary.emptySKU > 0
message += "\nFound #{@_summary.emptySKU} empty SKUs from file input"
Expand Down Expand Up @@ -148,6 +156,19 @@ class StockImport
performStream: (chunk, cb) ->
@_processBatches(chunk).then -> cb()

removeZeroInventories: () ->
removedCount = 0
@client.inventoryEntries
.perPage 500
.where 'quantityOnStock = 0'
.process (res) =>
Promise.map res.body.results, @_removeInventory
.then (removedResponses) ->
removedCount += removedResponses.length
, { accumulate: false }
.then ->
removedCount

_mapStockFromXML: (xmljs, channelId) ->
stocks = []
if xmljs.row?
Expand Down Expand Up @@ -206,7 +227,6 @@ class StockImport
resolve(data)
)


_mapCellData: (data, headerName) ->
data = data?.trim()
switch on
Expand Down Expand Up @@ -325,6 +345,7 @@ class StockImport
switch r.statusCode
when 201 then @_summary.created++
when 200 then @_summary.updated++
when 204 then @_summary.removed++
Promise.resolve()
, {concurrency: 1} # run 1 batch at a time

Expand Down Expand Up @@ -358,14 +379,32 @@ class StockImport
existingEntry = @_match(entry, existingEntries)
if existingEntry?
@_updateInventory(entry, existingEntry)
else if @shouldRemoveZeroInventories and entry.quantityOnStock == 0
Promise.resolve statusCode: 304
else
@client.inventoryEntries.create(entry)

debug 'About to send %s requests', _.size(posts)
Promise.all(posts)

_removeInventory: (existingEntry) =>
@client.inventoryEntries
.byId(existingEntry.id)
.delete(existingEntry.version)
.then ->
Promise.resolve statusCode: 204
.catch (err) ->
if err.statusCode is 404
Promise.resolve statusCode: 204
else
Promise.reject err

_updateInventory: (entry, existingEntry, tryCount = 1) =>
synced = @sync.buildActions(entry, existingEntry)

if @shouldRemoveZeroInventories and entry.quantityOnStock == 0
return @_removeInventory(existingEntry)

if synced.shouldUpdate()
@client.inventoryEntries.byId(synced.getUpdateId()).update(synced.getUpdatePayload())
.catch (err) =>
Expand Down
12 changes: 6 additions & 6 deletions src/spec/elasticio.spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,11 @@ describe 'elasticio integration', ->

elasticio.process msg, cfg, (error, message) ->
expect(error).toBe null
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new and 0 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new, 0 were updates)'
msg.body.QUANTITY = '3'
elasticio.process msg, cfg, (error, message) ->
expect(error).toBe null
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new and 1 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new, 1 were updates)'
elasticio.process msg, cfg, (error, message) ->
expect(error).toBe null
expect(message).toBe 'Summary: nothing to do, everything is fine'
Expand All @@ -179,11 +179,11 @@ describe 'elasticio integration', ->

elasticio.process msg, cfg, (error, message) ->
expect(error).toBe null
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new and 0 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new, 0 were updates)'
msg.body.QUANTITY = '3'
elasticio.process msg, cfg, (error, message) ->
expect(error).toBe null
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new and 1 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new, 1 were updates)'
done()
, 10000 # 10sec

Expand All @@ -204,10 +204,10 @@ describe 'elasticio integration', ->

elasticio.process msg, cfg, (error, message) ->
expect(error).toBe null
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new and 0 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new, 0 were updates)'
msg.body.QUANTITY = '3'
elasticio.process msg, cfg, (error, message) ->
expect(error).toBe null
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new and 1 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new, 1 were updates)'
done()
, 10000 # 10sec
56 changes: 16 additions & 40 deletions src/spec/integration.spec.coffee
Original file line number Diff line number Diff line change
@@ -1,34 +1,10 @@
_ = require 'underscore'
Promise = require 'bluebird'
{ExtendedLogger} = require 'sphere-node-utils'
package_json = require '../package.json'
Config = require '../config'
StockImport = require '../lib/stockimport'
{customTypePayload1, customTypePayload2, customTypePayload3} = require './helper-customTypePayload.spec'

cleanup = (logger, client) ->
logger.debug 'Deleting old inventory entries...'
client.inventoryEntries.all().fetch()
.then (result) ->
Promise.all _.map result.body.results, (e) ->
client.inventoryEntries.byId(e.id).delete(e.version)
.then (results) ->
logger.debug "Inventory #{_.size results} deleted."
logger.debug 'Deleting old types entries...'
client.types.all().fetch()
.then (result) ->
Promise.all _.map result.body.results, (e) ->
client.types.byId(e.id).delete(e.version)
.then (results) ->
logger.debug "Types #{_.size results} deleted."
logger.debug 'Deleting old channels entries...'
client.channels.all().fetch()
.then (result) ->
Promise.all _.map result.body.results, (e) ->
client.channels.byId(e.id).delete(e.version)
.then (results) ->
logger.debug "Channels #{_.size results} deleted."
Promise.resolve()
{ cleanup } = require './utils.spec'

describe 'integration test', ->

Expand Down Expand Up @@ -86,7 +62,7 @@ describe 'integration test', ->
@stockimport.run(rawXml, 'XML')
.then => @stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new and 0 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new, 0 were updates)'
@client.inventoryEntries.fetch()
.then (result) =>
stocks = result.body.results
Expand Down Expand Up @@ -121,7 +97,7 @@ describe 'integration test', ->
@stockimport.run(rawXml, 'XML')
.then => @stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new and 0 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new, 0 were updates)'
@client.inventoryEntries.fetch()
.then (result) =>
stocks = result.body.results
Expand All @@ -131,7 +107,7 @@ describe 'integration test', ->
@stockimport.run(rawXmlChanged, 'XML')
.then => @stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new and 1 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new, 1 were updates)'
@client.inventoryEntries.fetch()
.then (result) ->
stocks = result.body.results
Expand All @@ -156,7 +132,7 @@ describe 'integration test', ->
@stockimport.run(rawXml, 'XML')
.then => @stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new and 0 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new, 0 were updates)'
@client.inventoryEntries.fetch()
.then (result) =>
stocks = result.body.results
Expand All @@ -166,7 +142,7 @@ describe 'integration test', ->
@stockimport.run(rawXmlChanged, 'XML')
.then => @stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new and 1 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new, 1 were updates)'
@client.inventoryEntries.fetch()
.then (result) ->
stocks = result.body.results
Expand Down Expand Up @@ -196,7 +172,7 @@ describe 'integration test', ->
@stockimport.run(rawXml, 'XML')
.then => @stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 2 imported stocks (2 were new and 0 were updates)'
expect(message).toBe 'Summary: there were 2 imported stocks (2 were new, 0 were updates)'
@client.inventoryEntries.sort('id').fetch()
.then (result) =>
stocks = result.body.results
Expand All @@ -218,7 +194,7 @@ describe 'integration test', ->
@stockimport.run(rawXmlChangedAppointedQuantity, 'XML')
.then => @stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new and 1 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new, 1 were updates)'
@client.inventoryEntries.sort('id').fetch()
.then (result) =>
stocks = result.body.results
Expand All @@ -239,7 +215,7 @@ describe 'integration test', ->
@stockimport.run(rawXmlChangedCommittedDeliveryDate, 'XML')
.then => @stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new and 1 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new, 1 were updates)'
@client.inventoryEntries.sort('id').fetch()
.then (result) =>
stocks = result.body.results
Expand Down Expand Up @@ -281,7 +257,7 @@ describe 'integration test', ->
@stockimport.run(rawXmlEmptyValues, 'XML')
.then => @stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new and 1 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new, 1 were updates)'
@client.inventoryEntries.sort('id').fetch()
.then (result) ->
stocks = result.body.results
Expand Down Expand Up @@ -315,7 +291,7 @@ describe 'integration test', ->
.then =>
@stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new and 0 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new, 0 were updates)'
@client.inventoryEntries.fetch()
.then (result) =>
stocks = result.body.results
Expand Down Expand Up @@ -413,7 +389,7 @@ describe 'integration test', ->
.then =>
@stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new and 0 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new, 0 were updates)'
@client.inventoryEntries.fetch()
.then (result) =>
stocks = result.body.results
Expand Down Expand Up @@ -447,7 +423,7 @@ describe 'integration test', ->
.then =>
@stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 2 imported stocks (2 were new and 0 were updates)'
expect(message).toBe 'Summary: there were 2 imported stocks (2 were new, 0 were updates)'
@client.inventoryEntries.fetch()
.then (result) =>
stocks = result.body.results
Expand Down Expand Up @@ -492,7 +468,7 @@ describe 'integration test', ->
.then =>
@stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new and 0 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new, 0 were updates)'
@client.inventoryEntries.fetch()
.then (result) =>
stocks = result.body.results
Expand All @@ -502,7 +478,7 @@ describe 'integration test', ->
@stockimport.run(raw2, 'CSV')
.then => @stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new and 1 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (0 were new, 1 were updates)'
@client.inventoryEntries.fetch()
.then (result) ->
stocks = result.body.results
Expand All @@ -526,7 +502,7 @@ describe 'integration test', ->
.then =>
@stockimport.summaryReport()
.then (message) =>
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new and 0 were updates)'
expect(message).toBe 'Summary: there were 1 imported stocks (1 were new, 0 were updates)'
@client.inventoryEntries.fetch()
.then (result) =>
stocks = result.body.results
Expand Down
2 changes: 1 addition & 1 deletion src/spec/stockimport.spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe 'StockImport', ->
emptySKU: 2
created: 5
updated: 10
message = 'Summary: there were 15 imported stocks (5 were new and 10 were updates)' +
message = 'Summary: there were 15 imported stocks (5 were new, 10 were updates)' +
'\nFound 2 empty SKUs from file input \'./foo.json\''
expect(@import.summaryReport('./foo.json')).toEqual message

Expand Down
Loading

0 comments on commit aeed76c

Please sign in to comment.