seshbot-packing 0.8.5 → 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1df1737c878348a458089c20c950a5a2c0a8fdd501736904f8a4c89cc83e92ad
4
- data.tar.gz: bb96a3429acfbda5e066652600df576f6cf3a0a4e303ee3c6a68a1841eb984e8
3
+ metadata.gz: c1693c794a4be401fe157bd5a6385e1375e37c738e8919a168cc881ec262f9ec
4
+ data.tar.gz: 44c25e149bc8dba14cc2cc49f309b5e3ba5901bf4a636f89787ec5e946e28502
5
5
  SHA512:
6
- metadata.gz: 8557f78b9e1092f5ea8d776399d2ebc9b1163cd184a45e28482abf2635788b57e27f7dc6fd7d32e7b6b013eb62f86dddb71f3ff64c77f74e71c36278a24e6403
7
- data.tar.gz: 52d32265eedae66704b42a43a6183a47bf4268007b463a6cc2529cc291b09c10ef5353b15b725add93931d7f273053fbfc46700a70e43091218b8106017f9e4d
6
+ metadata.gz: 59f4cb5bad8c401ef6dde61443937c3bbce68f37f659aef074175a067fd6ea91b346531bc1c809d7b2788a30969eb14c92d8f716fc382d56ac26560cec6c93fd
7
+ data.tar.gz: c9536fe10e717e4841e8521f5986e467cc0e2b029c3a7512cee255f61941f0d0a5041c6ff0a9a047c218691d9b47ef69b14da6df7227f304cc4eb015f0ba1afa
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- seshbot-packing (0.8.5)
4
+ seshbot-packing (0.8.6)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -1,3 +1,4 @@
1
1
  require "seshbot/packing/version"
2
2
  require "seshbot/packing/package"
3
3
  require "seshbot/packing/recipe"
4
+ require "seshbot/packing/line_item"
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Seshbot
4
+ module Packing
5
+ # :nodocs:
6
+ class LineItem
7
+ attr_accessor :sku, :quantity, :price
8
+
9
+ def initialize(sku, quantity, price=0)
10
+ raise 'SKU must be a string' if sku.class != String
11
+ raise 'Quantity must be an integer' if quantity.class != Integer
12
+
13
+ @sku = sku
14
+ @quantity = quantity
15
+ @price = price
16
+ end
17
+ end
18
+ end
19
+ end
@@ -5,32 +5,34 @@ module Seshbot
5
5
  module Packing
6
6
  class Error < StandardError; end
7
7
  class << self
8
+ @@logger = nil
8
9
  def logger
9
- logger = Logger.new(STDERR)
10
- logger.level = 1
11
- logger
10
+ if @@logger.nil?
11
+ @@logger = Logger.new(STDERR)
12
+ @@logger.level = 1
13
+ end
14
+ @@logger
12
15
  end
13
16
 
14
17
  def filter_by_sku(items, sku_fragment, inverse: false)
15
18
  items.select do |i|
16
- matches = i['sku'].include?(sku_fragment)
19
+ matches = i.sku.include?(sku_fragment)
17
20
  inverse ? !matches : matches
18
21
  end
19
22
  end
20
23
 
21
24
  def substitute_sku(items, from, to)
22
- items.each { |i| i['sku'].gsub!(from, to) }
23
- items
25
+ items.map { |i| Seshbot::Packing::LineItem.new(i.sku.gsub(from, to), i.quantity) }
24
26
  end
25
27
 
26
28
  def count_product_types(items)
27
29
  result = Hash.new(0)
28
30
  # create a hash were the keys are sku_fragment, and the values are the summed quantities
29
31
  items.each do |item|
30
- size = packaged_size(item["sku"])
31
- result[size] += item["quantity"]
32
+ size = packaged_size(item.sku)
33
+ result[size] += item.quantity
32
34
  end
33
- result
35
+ result.map { |k,v| Seshbot::Packing::LineItem.new("BUND-#{k}", v) }
34
36
  end
35
37
 
36
38
  def packaged_size(sku)
@@ -58,16 +60,15 @@ module Seshbot
58
60
  logger.debug "***** BUNDLING"
59
61
  logger.debug "Bundling Items: #{items}. Fulfilled at: #{fulfilled_at || '(no fulfillment date)'}"
60
62
  if !fulfilled_at.nil? && fulfilled_at < DateTime.new(2020, 1, 14, 8, 0, 0, Time.new.zone)
61
- return items.map { |item| { 'sku' => item.sku, 'quantity' => item.quantity, 'price' => item.price } }
63
+ return items
62
64
  end
63
65
 
64
66
  # get the cans first, and separate them out
65
67
  cans = filter_by_sku(items, '-C')
66
68
  unless cans.empty?
67
- product_type_counts = count_product_types(cans)
68
- product_type_counts = unpack(recipes, product_type_counts)
69
- product_type_counts = pack(recipes, product_type_counts)
70
- new_can_items = product_type_counts.map { |k, v| { 'sku' => "BUND-#{k}", 'quantity' => v, 'price' => 0 } }
69
+ bundle_items_by_type = count_product_types(cans)
70
+ bundle_items_by_type = unpack(recipes, bundle_items_by_type)
71
+ new_can_items = pack(recipes, bundle_items_by_type)
71
72
  # separate out all the C324s
72
73
  separated_c324s = filter_by_sku(new_can_items, '-C324')
73
74
  logger.debug "Cans: #{cans}"
@@ -85,16 +86,15 @@ module Seshbot
85
86
  logger.debug " - remaining items: #{remaining_items}"
86
87
 
87
88
  # substitute C's for B's
88
- substitute_sku(remaining_items, '-C', '-B')
89
+ remaining_items = substitute_sku(remaining_items, '-C', '-B')
89
90
  logger.debug " - skus updated to: #{remaining_items}"
90
91
 
91
92
  # get a hash of {pack_6: 5, pack_12: 1}
92
- product_type_counts = count_product_types(remaining_items)
93
+ bundle_items_by_type = count_product_types(remaining_items)
93
94
  # dismantle packages into individual units (e.g., {pack_6: 7})
94
- product_type_counts = unpack(recipes, product_type_counts)
95
+ bundle_items_by_type = unpack(recipes, bundle_items_by_type)
95
96
  # repackage into the 'best' packaging we can figure out (e.g., {pack_12: 2})
96
- product_type_counts = pack(recipes, product_type_counts)
97
- new_remaining_items = product_type_counts.map { |k,v| { "sku" => "BUND-#{k}", "quantity" => v, "price" => 0} }
97
+ new_remaining_items = pack(recipes, bundle_items_by_type)
98
98
 
99
99
  separated_c324s ||= []
100
100
  merged_items = new_remaining_items + separated_c324s
@@ -104,45 +104,47 @@ module Seshbot
104
104
  merged_items
105
105
  end
106
106
 
107
+ def unpack(recipes, items)
107
108
 
108
- def unpack(recipes, product_type_counts)
109
- final_result = product_type_counts
109
+ final_result = items
110
110
 
111
- while true
111
+ loop do
112
112
  new_result = pack_single_step(recipes, final_result, unpacking: true)
113
- break if new_result == final_result
113
+ break if new_result.map { |li| [li.sku, li.quantity] }.sort == final_result.map { |li| [li.sku, li.quantity] }.sort
114
114
 
115
115
  final_result = new_result
116
116
  end
117
117
  final_result
118
118
  end
119
119
 
120
- def pack_single_step(recipes, product_type_counts, unpacking:)
120
+ def pack_single_step(recipes, items, unpacking:)
121
121
  result = Hash.new(0)
122
- product_type_counts.each do |sku_fragment, qty|
123
- recipe = Recipe::find_best_recipe(recipes, sku_fragment, qty, unpacking: unpacking)
122
+ items.each do |item|
123
+ sku_size = packaged_size(item.sku)
124
+ recipe = Recipe::find_best_recipe(recipes, sku_size, item.quantity, unpacking: unpacking)
124
125
  if recipe.nil?
125
- result[sku_fragment] += qty
126
+ result[sku_size] += item.quantity
126
127
  next
127
128
  end
128
129
 
129
- recipe_quantities = Recipe::apply_recipe(recipe, qty)
130
+ recipe_quantities = Recipe::apply_recipe(recipe, item.quantity)
130
131
  result[recipe["input_fragment"]] += recipe_quantities[:input_quantity]
131
132
  result[recipe["output_fragment"]] += recipe_quantities[:output_quantity]
132
133
  end
133
134
  result.delete_if { |k,v| v == 0}
134
- result
135
+ result.map { |k,v| Seshbot::Packing::LineItem.new("BUND-#{k}", v) }
135
136
  end
136
137
 
137
138
 
138
- def pack(recipes, product_type_counts)
139
- final_result = product_type_counts
139
+ def pack(recipes, items)
140
+ final_result = items
140
141
 
141
142
  # keep trying to 'pack' until it stabilises (e.g., 6x6pack => 1x24pack+2x6pack => 1x24pack+1x12pack)
142
- while true
143
+ loop do
143
144
  new_result = pack_single_step(recipes, final_result, unpacking: false)
144
145
  # no changes, break out
145
- break if new_result == final_result
146
+ break if new_result.map { |li| [li.sku, li.quantity] }.sort == final_result.map { |li| [li.sku, li.quantity] }.sort
147
+
146
148
  final_result = new_result
147
149
  end
148
150
  final_result
@@ -1,5 +1,5 @@
1
1
  module Seshbot
2
2
  module Packing
3
- VERSION = '0.8.5'
3
+ VERSION = '0.8.6'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: seshbot-packing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.5
4
+ version: 0.8.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shaun
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-29 00:00:00.000000000 Z
11
+ date: 2021-03-31 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -28,6 +28,7 @@ files:
28
28
  - bin/console
29
29
  - bin/setup
30
30
  - lib/seshbot/packing.rb
31
+ - lib/seshbot/packing/line_item.rb
31
32
  - lib/seshbot/packing/package.rb
32
33
  - lib/seshbot/packing/recipe.rb
33
34
  - lib/seshbot/packing/version.rb