order_optimizer 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5868b03e4f28cfec6001c9e53e61ffba0907c6d626d4ee950596bf4b1f154075
4
- data.tar.gz: 739453efda8bcfe9e015f91a47b0cf8945d0c9270fe8f18dc6241a71c5d35e63
3
+ metadata.gz: 21b6b1f9358d26572d0f3fe4d2a237c2da2a217bbb5f2d241d7a98683a9a43e1
4
+ data.tar.gz: 29987d3e12a263c8f18acdcf6c1972dcfa91204ece002e1a778ccc72a38a2843
5
5
  SHA512:
6
- metadata.gz: eebd782f5bc6971227292700da42edb7c30a3bca2d19573f65f901311b708aa91fd422ad1ca51a17798d28351e89a020eb1857b7ff7671892874f9e67fbe1429
7
- data.tar.gz: d4f80534e745ed6723468c7bf7b49ce5fd5d45fb6db915b756601aa7b00894d10550baeb16bba5da96f4bc24c01e5638ab7ab79ac07ca6eb0bb6576aa4648663
6
+ metadata.gz: 32b08adac0ba68f5133e60506b72a2f969d2e5617fd02ab16e922a05088e0afb81294041d6cbf6762dc70e8877a522733dc6160bb5583a30f744d67668efbee7
7
+ data.tar.gz: e8808b19221863663091640750d3765fccbf9dea0a4191f8cb9b1d13c46f49a3fa47f7ba8f906efaaa7bf5f3a6f7f13873ccdf19a59fcd32e81025b409676300
data/CHANGELOG.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # OrderOptimizer Gem Changelog
2
2
 
3
+ ## 0.5.0 (2021-04-15)
4
+ - Add `maximum_quantity` for SKUs
5
+
3
6
  ## 0.4.1 (2021-02-15)
4
7
 
5
8
  - Fix issue with floating point conversion [#3]
data/README.md CHANGED
@@ -72,7 +72,7 @@ cheapest_exact_order_for_58_units.total # => 322
72
72
  cheapest_exact_order_for_58_units.skus # => { '10-pack' => 5, '1-pack' => 8 }
73
73
  ```
74
74
 
75
- It is possible to define dicount prices a minimum quantity:
75
+ It is possible to define discount prices with a minimum quantity:
76
76
 
77
77
  ```ruby
78
78
  order_optimizer = OrderOptimizer.new(
@@ -100,6 +100,17 @@ order_optimizer.cheapest_order(required_qty: 29).skus
100
100
  #=> { '20-pack' => 1, '10-discount' => 10 }
101
101
  ```
102
102
 
103
+ It is also possible to define discount prices with a maximum quantity:
104
+ ```ruby
105
+ order_optimizer = OrderOptimizer.new(
106
+ '1-pack' => { quantity: 1, price_per_unit: 9 },
107
+ '10-pack' => { quantity: 10, price_per_unit: 8, max_quantity: 20 },
108
+ )
109
+
110
+ order_optimizer.cheapest_order(required_qty: 30).skus
111
+ #=> { '10-pack' => 2, '1-pack' => 10 }
112
+ ```
113
+
103
114
  If you're just interested in all possible order combinations:
104
115
 
105
116
  ```ruby
@@ -32,19 +32,19 @@ class OrderOptimizer
32
32
 
33
33
  skus.each do |sku|
34
34
  orders.reject(&:complete?).each do |order|
35
- count, remainder = count_and_remainder_for_sku(order.missing_qty, sku)
35
+ count, remainder, skip_increase = count_and_remainder_for_sku(order.missing_qty, sku)
36
36
 
37
37
  orders << order.dup.add(sku, count: count) unless count.zero?
38
- orders << order.dup.add(sku, count: count + 1) unless remainder.zero?
38
+ orders << order.dup.add(sku, count: count + 1) unless remainder.zero? || skip_increase
39
39
  end
40
40
 
41
- count, remainder = count_and_remainder_for_sku(required_qty, sku)
41
+ count, remainder, skip_increase = count_and_remainder_for_sku(required_qty, sku)
42
42
 
43
43
  unless count.zero?
44
44
  orders << OrderOptimizer::Order.new(required_qty: required_qty).add(sku, count: count)
45
45
  end
46
46
 
47
- unless remainder.zero?
47
+ unless remainder.zero? || skip_increase
48
48
  orders << OrderOptimizer::Order.new(required_qty: required_qty).add(sku, count: count + 1)
49
49
  end
50
50
  end
@@ -55,12 +55,18 @@ class OrderOptimizer
55
55
  def count_and_remainder_for_sku(quantity, sku)
56
56
  count, remainder = quantity.divmod(sku.quantity)
57
57
 
58
- if sku.min_quantity && count * sku.quantity < sku.min_quantity
58
+ if sku.max_quantity && count * sku.quantity > sku.max_quantity
59
+ new_count = (sku.max_quantity / sku.quantity).ceil
60
+ remainder = (count - new_count) * sku.quantity
61
+
62
+ [new_count, [remainder, 0].max, true]
63
+ elsif sku.min_quantity && count * sku.quantity < sku.min_quantity
59
64
  new_count = (sku.min_quantity / sku.quantity).ceil
60
65
  remainder -= (new_count - count) * sku.quantity
61
- [new_count, [remainder, 0].max]
66
+
67
+ [new_count, [remainder, 0].max, false]
62
68
  else
63
- [count, remainder]
69
+ [count, remainder, false]
64
70
  end
65
71
  end
66
72
  end
@@ -1,16 +1,19 @@
1
1
  class OrderOptimizer
2
2
  class Sku
3
- attr_reader :id, :quantity, :price_per_unit, :price_per_sku, :min_quantity
3
+ attr_reader :id, :quantity, :price_per_unit, :price_per_sku, :min_quantity, :max_quantity
4
4
 
5
- def initialize(id, quantity:, price_per_sku: nil, price_per_unit: nil, min_quantity: nil)
5
+ def initialize(id, quantity:, price_per_sku: nil, price_per_unit: nil, min_quantity: nil, max_quantity: nil)
6
6
  @id = id
7
7
  @quantity = BigDecimal(quantity, 2)
8
8
  @min_quantity = BigDecimal(min_quantity, 2) if min_quantity
9
+ @max_quantity = BigDecimal(max_quantity, 2) if max_quantity
9
10
 
10
- unless price_per_unit || price_per_sku
11
- raise ':price_per_sku or :price_per_unit must be set'
11
+ if min_quantity && max_quantity && (min_quantity > max_quantity)
12
+ raise ArgumentError, "min_quantity can't be larger than max_quantity"
12
13
  end
13
14
 
15
+ raise ArgumentError, ':price_per_sku or :price_per_unit must be set' unless price_per_unit || price_per_sku
16
+
14
17
  @price_per_unit = BigDecimal(price_per_unit, 2) if price_per_unit
15
18
  @price_per_unit ||= BigDecimal(price_per_sku, 2) / quantity
16
19
 
@@ -1,3 +1,3 @@
1
1
  class OrderOptimizer
2
- VERSION = "0.4.1".freeze
2
+ VERSION = "0.5.0".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: order_optimizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - crispymtn
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-02-15 00:00:00.000000000 Z
13
+ date: 2021-04-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -101,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
101
  - !ruby/object:Gem::Version
102
102
  version: '0'
103
103
  requirements: []
104
- rubygems_version: 3.2.3
104
+ rubygems_version: 3.2.15
105
105
  signing_key:
106
106
  specification_version: 4
107
107
  summary: Helps to optimize orders if the goods are offered in different pack sizes