seshbot-packing 0.5.0 → 0.8.3

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: fcd108047bea2fe4b890f489dfae607149553eda6580377307ba0da508b09106
4
- data.tar.gz: fa66fc1bf3d90177921fd3abb9916140bffe80d83a3ebcd991e4ea7c6090bf26
3
+ metadata.gz: b5c704b0aaa991e8fe3cc828791fa04b78b5cb742da74985e7d8fb4a151d6bb7
4
+ data.tar.gz: 704326012b06c7cb027004351e54f9123aceede796cf11da63bccaf793df68b6
5
5
  SHA512:
6
- metadata.gz: 489a49b0e178294f885d70301b339292a85de575044a6c4a1473a25793cf851f288b95a50530c26fb6fadfc5b94639f4eaec35c218aa659be37a064942597b16
7
- data.tar.gz: 6e2bd8737ef03133ae76ae6811f6ddc96efe5e72ff8db287471a0be89f8c631587335f8032a69196498bf4d449548b628d98d24adecde619845a7b2dc58c4266
6
+ metadata.gz: 0a9c6f27dceded9253e7e0ba1297ff4bb331d5b2b695e5261bb3255609c003ea438313d691e8fade12cb4752d021b1c1256214a7aa5ec39c81f3400c4afd2518
7
+ data.tar.gz: c18687b3b45ac45f5894e0b1ddc394d2931e698c68cc6c3c860cfeb4b8b4611ad7dc812b190ddf033f9828723207b29055f6229da8df974eb8170f933821f22a
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.2)
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,36 +32,74 @@ 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
23
47
  if result == "B504"
24
48
  result = "B312"
25
49
  end
26
- result.gsub!(/^C/, 'B')
50
+ raise "Cannot determine packaged size for SKU: #{sku}" if result.nil?
51
+
27
52
  result
28
53
  end
29
54
 
30
55
  def bundle_items(items, fulfilled_at: nil)
31
- if fulfilled_at
32
- bundling_start_date = DateTime.new(2020, 1, 14, 8, 0, 0, Time.new.zone)
33
- result = items.map { |item| { "sku" => item.sku, "quantity" => item.quantity, "price" => item.price } }
34
- 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 } }
35
60
  end
36
61
 
37
- # get a hash of {pack_6: 5, pack_12: 1}
38
- 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
39
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)
40
91
  # dismantle packages into individual units (e.g., {pack_6: 7})
41
92
  product_type_counts = unpack(product_type_counts)
42
-
43
93
  # repackage into the 'best' packaging we can figure out (e.g., {pack_12: 2})
44
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} }
45
96
 
46
- new_line_items = product_type_counts.map { |k,v| { "sku" => "BUND-#{k}", "quantity" => v, "price" => 0} }
47
- 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
48
103
  end
49
104
 
50
105
 
@@ -54,6 +109,7 @@ module Seshbot
54
109
  while true
55
110
  new_result = pack_single_step(final_result, unpacking: true)
56
111
  break if new_result == final_result
112
+
57
113
  final_result = new_result
58
114
  end
59
115
  final_result
@@ -1,5 +1,5 @@
1
1
  module Seshbot
2
2
  module Packing
3
- VERSION = "0.5.0"
3
+ VERSION = '0.8.3'
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.5.0
4
+ version: 0.8.3
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-16 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: