seshbot-packing 0.3.0 → 0.8.1

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: 5c3c46a22371cf5d5dcaaad8a7579cd346c32439f7ea0dfefb59f58972da7e0e
4
- data.tar.gz: a3884d158b30816d2c712d2e3511143ac337b264c7e75cba6f479a978699b47f
3
+ metadata.gz: 3134dc89051dbe2bb688dc5608eee3ecc73847d141561f9a78376a414130039d
4
+ data.tar.gz: eb87d9d7d2f0a5ea8e3b972201101dd6eaeed1f207637e38a4c68a9e607c7f43
5
5
  SHA512:
6
- metadata.gz: 67a9c55e750216d5f607414bee1717e8c793ba3fae818ac9d1f707deacbc3292e42e9cd99b5a22c8dc51031646ea116da77fa5341e226f04d3c27606f050c82f
7
- data.tar.gz: c249a389f7cfce920c5d13e70be9585dcd9a1e3eaf0cc641d415554010df0cd51e621057b0c9307736a814d9924397d82fdc7c332587b6138731ef8f38da29e8
6
+ metadata.gz: 75385b37a1a5b0304483316012a6b626120861523701087ca5ea19ebbf0adf7a236d66783e7385206009989b4578f836bf44ddd2226914fafc5bd5a2da250a8a
7
+ data.tar.gz: 48d84bdb45a986d0cb166f2d073965f38c8aba4ebacf9456e8ed980a4e33b06ee60c33722c60c551c6863f316c4ac73663f0512e678769d166a2059ccd018970
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  .byebug_history
2
+ .ruby-version
2
3
  /.bundle/
3
4
  /.yardoc
4
5
  /_yardoc/
@@ -7,3 +8,4 @@
7
8
  /pkg/
8
9
  /spec/reports/
9
10
  /tmp/
11
+ *.gem
@@ -0,0 +1,3 @@
1
+ ## Version 0.8.0
2
+
3
+ * -C324 are calculated and separated from bundling
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- seshbot-packing (0.3.0)
4
+ seshbot-packing (0.8.0)
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
@@ -16,45 +33,79 @@ module Seshbot
16
33
 
17
34
  def packaged_size(sku)
18
35
  # 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})/]
36
+ result = sku[/[LUP]\d{2}|[BCM]\d{3}/]
20
37
  if result == "B502"
21
38
  result = "B306"
22
39
  end
23
40
  if result == "B504"
24
41
  result = "B312"
25
42
  end
26
- result.gsub!(/^C/, 'B')
43
+ raise "Cannot determine packaged size for SKU: #{sku}" if result.nil?
44
+
27
45
  result
28
46
  end
29
47
 
30
48
  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
49
+ logger.debug "***** BUNDLING"
50
+ logger.debug "Bundling Items: #{items}. Fulfilled at: #{fulfilled_at || '(no fulfillment date)'}"
51
+ if !fulfilled_at.nil? && fulfilled_at < DateTime.new(2020, 1, 14, 8, 0, 0, Time.new.zone)
52
+ return items.map { |item| { 'sku' => item.sku, 'quantity' => item.quantity, 'price' => item.price } }
35
53
  end
36
54
 
37
- items.each do |item|
38
- size = packaged_size(item["sku"])
55
+ # get the cans first, and separate them out
56
+ cans = filter_by_sku(items, '-C')
57
+ unless cans.empty?
58
+ product_type_counts = count_product_types(cans)
59
+ product_type_counts = unpack(product_type_counts)
60
+ product_type_counts = pack(product_type_counts)
61
+ new_can_items = product_type_counts.map { |k, v| { 'sku' => "BUND-#{k}", 'quantity' => v, 'price' => 0 } }
62
+ # separate out all the C324s
63
+ separated_c324s = filter_by_sku(new_can_items, '-C324')
64
+ logger.debug "Cans: #{cans}"
65
+ logger.debug " - Removed C324s: #{separated_c324s}"
66
+
67
+ remaining_cans = filter_by_sku(new_can_items, '-C324', inverse: true)
68
+ logger.debug " - Remaining skus: #{remaining_cans}"
39
69
  end
40
70
 
41
- # get a hash of {pack_6: 5, pack_12: 1}
42
- product_type_counts = count_product_types(items)
71
+ # merge the remaining with the original leftover
72
+ non_cans = filter_by_sku(items, '-C', inverse: true)
73
+ remaining_cans ||= []
74
+ remaining_items = non_cans + remaining_cans
75
+ logger.debug "Substituting:"
76
+ logger.debug " - remaining items: #{remaining_items}"
77
+
78
+ # substitute C's for B's
79
+ substitute_sku(remaining_items, '-C', '-B')
80
+ logger.debug " - skus updated to: #{remaining_items}"
43
81
 
82
+ # get a hash of {pack_6: 5, pack_12: 1}
83
+ product_type_counts = count_product_types(remaining_items)
44
84
  # dismantle packages into individual units (e.g., {pack_6: 7})
45
85
  product_type_counts = unpack(product_type_counts)
46
-
47
86
  # repackage into the 'best' packaging we can figure out (e.g., {pack_12: 2})
48
87
  product_type_counts = pack(product_type_counts)
88
+ new_remaining_items = product_type_counts.map { |k,v| { "sku" => "BUND-#{k}", "quantity" => v, "price" => 0} }
49
89
 
50
- new_line_items = product_type_counts.map { |k,v| { "sku" => "BUND-#{k}", "quantity" => v, "price" => 0} }
51
- new_line_items
90
+ separated_c324s ||= []
91
+ merged_items = new_remaining_items + separated_c324s
92
+ logger.debug "Bundled result:"
93
+ logger.debug " - IN: #{items}"
94
+ logger.debug " - OUT: #{merged_items}"
95
+ merged_items
52
96
  end
53
97
 
54
98
 
55
99
  def unpack(product_type_counts)
56
- result = pack_single_step(product_type_counts, unpacking: true)
57
- result
100
+ final_result = product_type_counts
101
+
102
+ while true
103
+ new_result = pack_single_step(final_result, unpacking: true)
104
+ break if new_result == final_result
105
+
106
+ final_result = new_result
107
+ end
108
+ final_result
58
109
  end
59
110
 
60
111
  def pack_single_step(product_type_counts, unpacking:)
@@ -4,41 +4,53 @@ module Seshbot
4
4
  class << self
5
5
  def get_recipes
6
6
  {
7
- "twenty_four_pack_4"=>{
7
+ "bottles_twenty_four_pack_4"=>{
8
8
  "input_fragment"=>"B306",
9
9
  "input_quantity"=>4,
10
10
  "output_fragment"=>"B324",
11
11
  "output_quantity"=>1
12
12
  },
13
- "twenty_four_pack_3"=>{
13
+ "bottles_twenty_four_pack_3"=>{
14
14
  "input_fragment"=>"B306",
15
15
  "input_quantity"=>3,
16
16
  "output_fragment"=>"B318",
17
17
  "output_quantity"=>1
18
18
  },
19
- "twelve_pack"=>{
19
+ "bottles_twelve_pack"=>{
20
20
  "input_fragment"=>"B306",
21
21
  "input_quantity"=>2,
22
22
  "output_fragment"=>"B312",
23
23
  "output_quantity"=>1
24
24
  },
25
+ "bottles_six_pack"=>{
26
+ "input_fragment"=>"B301",
27
+ "input_quantity"=>6,
28
+ "output_fragment"=>"B306",
29
+ "output_quantity"=>1
30
+ },
25
31
  "cans_twenty_four_pack_4"=>{
26
- "input_fragment"=>"C306",
27
- "input_quantity"=>4,
28
- "output_fragment"=>"C324",
29
- "output_quantity"=>1
32
+ "input_fragment"=>"C306",
33
+ "input_quantity"=>4,
34
+ "output_fragment"=>"C324",
35
+ "output_quantity"=>1
30
36
  },
31
37
  "cans_twenty_four_pack_3"=>{
32
- "input_fragment"=>"C306",
33
- "input_quantity"=>3,
34
- "output_fragment"=>"C318",
35
- "output_quantity"=>1
38
+ "input_fragment"=>"C306",
39
+ "input_quantity"=>3,
40
+ "output_fragment"=>"C318",
41
+ "output_quantity"=>1
36
42
  },
37
43
  "cans_twelve_pack"=>{
38
- "input_fragment"=>"C306",
39
- "input_quantity"=>2,
40
- "output_fragment"=>"C312",
41
- "output_quantity"=>1
44
+ "input_fragment"=>"C306",
45
+ "input_quantity"=>2,
46
+ "output_fragment"=>"C312",
47
+ "output_quantity"=>1
48
+ },
49
+ "cans_six_pack"=>{
50
+ "input_fragment"=>"C301",
51
+ "input_quantity"=>6,
52
+ "output_fragment"=>"C306",
53
+ "output_quantity"=>1
42
54
  }
43
55
  }
44
56
  end
@@ -1,5 +1,5 @@
1
1
  module Seshbot
2
2
  module Packing
3
- VERSION = "0.3.0"
3
+ VERSION = '0.8.1'
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.3.0
4
+ version: 0.8.1
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-15 00:00:00.000000000 Z
11
+ date: 2021-01-13 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: