seshbot-packing 0.6.0 → 0.8.4

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: 7b80363f49d8261808f18ebcebe8528d731c6c0d403160c272cecb444406c26d
4
- data.tar.gz: a3678393e846e90f01a224b48169c428ce36317891db90122de0abee77fc0dee
3
+ metadata.gz: 728e83e27d39aeceeb0bf6ecbb9bbf411406a058bc8a411bf2318384c2f41e52
4
+ data.tar.gz: 940ae010ff99df20da529c315887af533c4884e7f3722da9cf69244839c869df
5
5
  SHA512:
6
- metadata.gz: a6a0f4c34b59d8a38100c6aa41b76a69b825811a8880f68b83262f78b028e6cd67076e4c20d8ad251fc80b12b179d9335785ce8d7710cbc8f07b9b4562fc5427
7
- data.tar.gz: dfba97a9dddd01c985acfb3d14d67e0c32bfa37a04c1bd132d938d894237a1096d31a7c051cde80e8ebb1bba2abe439a091f369cd63c1300f11d3cfc7498de1f
6
+ metadata.gz: 14a29e1baacaaa6d4b64975da651999e3e4401c60298a5eb403d0a21ec5dabc58839c592afb934a7efbfe9fbe96e7958d2628b8eee903c0d30009860e94b1a43
7
+ data.tar.gz: 57e13a72efdbeb1987071b070e3974a02769c2bd905aabdd60fd9ebbc19e7da1ecc211c7b8fd6be6d4b948b4589753870a77a8a1c582fcd3e8172563797de295
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  .byebug_history
2
+ .ruby-version
2
3
  /.bundle/
3
4
  /.yardoc
4
5
  /_yardoc/
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ## Version 0.8.0
2
+
3
+ * -C324 are calculated and separated from bundling
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- seshbot-packing (0.5.0)
4
+ seshbot-packing (0.8.3)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,9 +1,5 @@
1
1
  # Seshbot::Packing
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/seshbot/packing`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
6
-
7
3
  ## Installation
8
4
 
9
5
  Add this line to your application's Gemfile:
@@ -20,9 +16,43 @@ Or install it yourself as:
20
16
 
21
17
  $ gem install seshbot-packing
22
18
 
23
- ## Usage
19
+ ## Methods
20
+
21
+ ```ruby
22
+ # Bundle Items
23
+ ## this is the main method, it calls most other methods to get its result
24
+ items = [{ 'sku' => 'B-B306', 'quantity' => 2, 'price' => 1 }]
25
+ Seshbot::Packing.bundle_items(items)
26
+ #=> [{ 'sku' => 'BUND-B312', 'quantity' => 1, 'price' => 0 }]
27
+
28
+ # Count Product Types
29
+ ## groups together everythign after the `-` and counts them
30
+ items = [{"sku" => "A-B306", "quantity" => 2}, {"sku" => "B-B306", "quantity" => 1}]
31
+ Seshbot::Packing.count_product_types(items)
32
+ #=> {"B306"=>3}
33
+
34
+ # Separate SKU
35
+ ## returns the hashes where the sku value matches the given string
36
+ items = [{ 'sku' => 'A-C306', 'quantity' => 4, 'price' => 1 },
37
+ { 'sku' => 'A-B306', 'quantity' => 4, 'price' => 1 }]
38
+ Seshbot::Packing.filter_by_sku(items, '-C')
39
+ #=> [{ 'sku' => 'A-C306', 'quantity' => 4, 'price' => 1 }]
40
+ ## also takes a named argument
41
+ Seshbot::Packing.filter_by_sku(items, '-C', inverse: true)
42
+ #=> [{ 'sku' => 'A-B306', 'quantity' => 4, 'price' => 1 }]
43
+
44
+ # Substitute SKU
45
+ ## replaces an sku in a hash
46
+ Seshbot::Packing.substitute_sku(items, '-B', '-C')
47
+ #=> items = [{"sku" => "A-C306", "quantity" => 2}, {"sku" => "B-C306", "quantity" => 1}]
48
+ ```
49
+
24
50
 
25
- TODO: Write usage instructions here
51
+ ## C324s
52
+ As of v0.8.0, C324s will be treated differently. If there are any C324s that can exist, they will stay as C324s, and not converted to bottles.
53
+ eg.
54
+ In: 1x C312, 1x C312, 1x C306, 1x B306
55
+ Out: 1x C324, 1x B312
26
56
 
27
57
  ## Development
28
58
 
@@ -1,13 +1,30 @@
1
- require "date"
1
+ require 'logger'
2
+ require 'date'
3
+
2
4
  module Seshbot
3
5
  module Packing
4
6
  class Error < StandardError; end
5
-
6
7
  class << self
8
+ def logger
9
+ Logger.new(STDERR)
10
+ end
11
+
12
+ def filter_by_sku(items, sku_fragment, inverse: false)
13
+ items.select do |i|
14
+ matches = i['sku'].include?(sku_fragment)
15
+ inverse ? !matches : matches
16
+ end
17
+ end
18
+
19
+ def substitute_sku(items, from, to)
20
+ items.each { |i| i['sku'].gsub!(from, to) }
21
+ items
22
+ end
23
+
7
24
  def count_product_types(items)
8
25
  result = Hash.new(0)
9
26
  # create a hash were the keys are sku_fragment, and the values are the summed quantities
10
- items.each do |item|
27
+ items.each do |item|
11
28
  size = packaged_size(item["sku"])
12
29
  result[size] += item["quantity"]
13
30
  end
@@ -15,8 +32,15 @@ module Seshbot
15
32
  end
16
33
 
17
34
  def packaged_size(sku)
18
- # Takes an sku and returns the size
19
- result = sku[/(L\d{2}|U\d{2}|B\d{3}|C\d{3}|M\d{3}|P\d{2})/]
35
+ size_regex = /-(K?[LUP]\d{2}|[BCM]\d{3})/
36
+ match = sku.match(size_regex)
37
+ raise "Cannot determine packaged size for SKU: #{sku}" if match.nil? || match.captures.empty?
38
+
39
+ # this is everything inside the (..) in the regex (everything except the leading '-')
40
+ result = match.captures[0]
41
+ # HACK! for legacy reasons, we don't consider K to be part of the size.
42
+ result.gsub!(/^K/, '')
43
+
20
44
  if result == "B502"
21
45
  result = "B306"
22
46
  end
@@ -24,28 +48,58 @@ module Seshbot
24
48
  result = "B312"
25
49
  end
26
50
  raise "Cannot determine packaged size for SKU: #{sku}" if result.nil?
27
- result.gsub!(/^C/, 'B')
51
+
28
52
  result
29
53
  end
30
54
 
31
55
  def bundle_items(items, fulfilled_at: nil)
32
- if fulfilled_at
33
- bundling_start_date = DateTime.new(2020, 1, 14, 8, 0, 0, Time.new.zone)
34
- result = items.map { |item| { "sku" => item.sku, "quantity" => item.quantity, "price" => item.price } }
35
- return result if fulfilled_at < bundling_start_date # TODO remove bundling start date method
56
+ logger.debug "***** BUNDLING"
57
+ logger.debug "Bundling Items: #{items}. Fulfilled at: #{fulfilled_at || '(no fulfillment date)'}"
58
+ if !fulfilled_at.nil? && fulfilled_at < DateTime.new(2020, 1, 14, 8, 0, 0, Time.new.zone)
59
+ return items.map { |item| { 'sku' => item.sku, 'quantity' => item.quantity, 'price' => item.price } }
36
60
  end
37
61
 
38
- # get a hash of {pack_6: 5, pack_12: 1}
39
- product_type_counts = count_product_types(items)
62
+ # get the cans first, and separate them out
63
+ cans = filter_by_sku(items, '-C')
64
+ unless cans.empty?
65
+ product_type_counts = count_product_types(cans)
66
+ product_type_counts = unpack(product_type_counts)
67
+ product_type_counts = pack(product_type_counts)
68
+ new_can_items = product_type_counts.map { |k, v| { 'sku' => "BUND-#{k}", 'quantity' => v, 'price' => 0 } }
69
+ # separate out all the C324s
70
+ separated_c324s = filter_by_sku(new_can_items, '-C324')
71
+ logger.debug "Cans: #{cans}"
72
+ logger.debug " - Removed C324s: #{separated_c324s}"
73
+
74
+ remaining_cans = filter_by_sku(new_can_items, '-C324', inverse: true)
75
+ logger.debug " - Remaining skus: #{remaining_cans}"
76
+ end
40
77
 
78
+ # merge the remaining with the original leftover
79
+ non_cans = filter_by_sku(items, '-C', inverse: true)
80
+ remaining_cans ||= []
81
+ remaining_items = non_cans + remaining_cans
82
+ logger.debug "Substituting:"
83
+ logger.debug " - remaining items: #{remaining_items}"
84
+
85
+ # substitute C's for B's
86
+ substitute_sku(remaining_items, '-C', '-B')
87
+ logger.debug " - skus updated to: #{remaining_items}"
88
+
89
+ # get a hash of {pack_6: 5, pack_12: 1}
90
+ product_type_counts = count_product_types(remaining_items)
41
91
  # dismantle packages into individual units (e.g., {pack_6: 7})
42
92
  product_type_counts = unpack(product_type_counts)
43
-
44
93
  # repackage into the 'best' packaging we can figure out (e.g., {pack_12: 2})
45
94
  product_type_counts = pack(product_type_counts)
95
+ new_remaining_items = product_type_counts.map { |k,v| { "sku" => "BUND-#{k}", "quantity" => v, "price" => 0} }
46
96
 
47
- new_line_items = product_type_counts.map { |k,v| { "sku" => "BUND-#{k}", "quantity" => v, "price" => 0} }
48
- new_line_items
97
+ separated_c324s ||= []
98
+ merged_items = new_remaining_items + separated_c324s
99
+ logger.debug "Bundled result:"
100
+ logger.debug " - IN: #{items}"
101
+ logger.debug " - OUT: #{merged_items}"
102
+ merged_items
49
103
  end
50
104
 
51
105
 
@@ -55,6 +109,7 @@ module Seshbot
55
109
  while true
56
110
  new_result = pack_single_step(final_result, unpacking: true)
57
111
  break if new_result == final_result
112
+
58
113
  final_result = new_result
59
114
  end
60
115
  final_result
@@ -4,6 +4,12 @@ module Seshbot
4
4
  class << self
5
5
  def get_recipes
6
6
  {
7
+ "bottles_forty_eight_pack_8"=>{
8
+ "input_fragment"=>"B306",
9
+ "input_quantity"=>8,
10
+ "output_fragment"=>"B348",
11
+ "output_quantity"=>1
12
+ },
7
13
  "bottles_twenty_four_pack_4"=>{
8
14
  "input_fragment"=>"B306",
9
15
  "input_quantity"=>4,
@@ -28,6 +34,12 @@ module Seshbot
28
34
  "output_fragment"=>"B306",
29
35
  "output_quantity"=>1
30
36
  },
37
+ "cans_forty_eight_pack_8"=>{
38
+ "input_fragment"=>"C306",
39
+ "input_quantity"=>8,
40
+ "output_fragment"=>"C348",
41
+ "output_quantity"=>1
42
+ },
31
43
  "cans_twenty_four_pack_4"=>{
32
44
  "input_fragment"=>"C306",
33
45
  "input_quantity"=>4,
@@ -1,5 +1,5 @@
1
1
  module Seshbot
2
2
  module Packing
3
- VERSION = "0.6.0"
3
+ VERSION = '0.8.4'
4
4
  end
5
5
  end
@@ -1,20 +1,20 @@
1
1
  require_relative 'lib/seshbot/packing/version'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
- spec.name = "seshbot-packing"
4
+ spec.name = 'seshbot-packing'
5
5
  spec.version = Seshbot::Packing::VERSION
6
- spec.authors = ["Shaun"]
7
- spec.email = ["shaun@brewkeeper.com.au"]
8
-
6
+ spec.authors = ['Shaun']
7
+ spec.email = ['shaun@brewkeeper.com.au']
8
+ spec.license = 'MIT'
9
9
  spec.summary = %q{Receives, calculates, returns skus with new quantities}
10
- spec.homepage = "https://gitlab.com/brewkeeper/seshbot-packing"
10
+ spec.homepage = 'https://gitlab.com/brewkeeper/seshbot-packing'
11
11
  spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
12
12
 
13
13
  # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
14
14
 
15
15
  spec.metadata["homepage_uri"] = spec.homepage
16
16
  spec.metadata["source_code_uri"] = "https://gitlab.com/brewkeeper/seshbot-packing"
17
- spec.metadata["changelog_uri"] = "https://gitlab.com/brewkeeper/seshbot-packing/~blob/master/CHANGELOG.md"
17
+ spec.metadata["changelog_uri"] = "https://gitlab.com/brewkeeper/seshbot-packing/-/blob/master/CHANGELOG.md"
18
18
 
19
19
  # Specify which files should be added to the gem when it is released.
20
20
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
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.6.0
4
+ version: 0.8.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shaun
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-11-19 00:00:00.000000000 Z
11
+ date: 2021-03-16 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -19,6 +19,7 @@ extra_rdoc_files: []
19
19
  files:
20
20
  - ".gitignore"
21
21
  - ".travis.yml"
22
+ - CHANGELOG.md
22
23
  - CODE_OF_CONDUCT.md
23
24
  - Gemfile
24
25
  - Gemfile.lock
@@ -32,11 +33,12 @@ files:
32
33
  - lib/seshbot/packing/version.rb
33
34
  - seshbot-packing.gemspec
34
35
  homepage: https://gitlab.com/brewkeeper/seshbot-packing
35
- licenses: []
36
+ licenses:
37
+ - MIT
36
38
  metadata:
37
39
  homepage_uri: https://gitlab.com/brewkeeper/seshbot-packing
38
40
  source_code_uri: https://gitlab.com/brewkeeper/seshbot-packing
39
- changelog_uri: https://gitlab.com/brewkeeper/seshbot-packing/~blob/master/CHANGELOG.md
41
+ changelog_uri: https://gitlab.com/brewkeeper/seshbot-packing/-/blob/master/CHANGELOG.md
40
42
  post_install_message:
41
43
  rdoc_options: []
42
44
  require_paths: