Permalink
Browse files

Orders are made up of optimal pack combinations

  • Loading branch information...
SelenaSmall committed Sep 3, 2017
1 parent 4b96f15 commit ace50ed589c4e0a3bb1038e716633324d54e3b63
Showing with 96 additions and 61 deletions.
  1. +94 −35 lib/order_line.rb
  2. +2 −26 spec/order_line_spec.rb
@@ -11,65 +11,124 @@ def initialize(order_qty, order_item)
end
def optimal(product)
puts "Quantity: #{order_qty}"
pack_qtys = []
@order_item.packs(product).each { |p| pack_qtys << [p.qty, p.price] }
puts "Packs: #{pack_qtys}"
whole_packs = whole_packs(pack_qtys, [], order_qty)
# Get Exact matches
exact_matches = []
pack_qtys.sort { |a, b| b <=> a }.each do |p, v|
next unless (order_qty / p) * p == order_qty
exact_matches << [order_qty / p, p, v]
end
# puts exact_matches
return whole_packs[0] if whole_packs[1].zero?
# Check for the optimim price
price_check = []
exact_matches.each do |x, y, z|
val = (x * z)
total_packs = left_over_items(pack_qtys, whole_packs[0], whole_packs[1])
price_check << [x, y, z, val]
end
# puts price_check
total_packs[0]
end
numbers = price_check.select { |x| x[3] }.map
def present_line(packs)
sub_total = []
sub_item = []
packs.each do |k, v, i|
sub_total << k * i
sub_item << "#{k}x #{v} packs @ #{i}"
# Get Part matches
partial_matches = []
pack_qtys.sort { |a, b| b <=> a }.each do |p, v|
partial_matches << [order_qty / p, p, v]
end
puts "partial: #{partial_matches}"
# Top up part matches
exact_partial = []
partial_matches.each do |x, y, z|
val = order_qty - (x * y)
puts "VAL: #{val}"
pack_qtys.detect do |a|
# To be optimised: a.include?(val) does not cooperate with Money
if a[0] == val || a[0] * 3 == val
exact_partial << [x, y, z]
exact_partial << [val / a[0], a[0], a[1]]
end
end
end
puts "exact partial: #{exact_partial}"
@line_total = sub_total.inject(0) { |sum, x| sum + x }
# Check for the optimim partial price
partial_price_check = []
exact_partial.each do |x, y, z|
val = (x * z)
sub_item.each { |s| s }
end
partial_price_check << [x, y, z, val]
end
# puts partial_price_check
def presenter_line_total
@line_total
end
partial_numbers = partial_price_check.select { |x| x[3] }.map
private
partial_price_array = []
partial_numbers.each do |f|
partial_price_array << f
end
# puts partial_price_array
def whole_packs(pack_qtys, packs, left_over_qty)
pack_qtys.sort { |a, b| b <=> a }.each do |p, v|
volume = left_over_qty.to_f / p
puts "Exact Match: #{exact_matches}"
# Array for best price line: 1x 9pk @16 = $16
puts "Best Exact Price: #{numbers.min}"
puts "Partial Match: #{exact_partial}"
puts "Best Partial Price: #{partial_price_array}"
next unless volume >= 1
return calculate_best(numbers, partial_price_array) unless price_check.empty?
left_over_qty -= volume.to_int * p
calculate_best(numbers.min, partial_price_array)
end
packs << [volume.to_int, p, v]
def calculate_best(exact, partial)
if exact.nil?
puts "\nThis is it #{partial}"
return partial
end
[packs, left_over_qty]
end
if partial.empty?
puts "\nThis is it #{exact}"
return exact
end
def left_over_items(pack_qtys, packs, left_over_qty)
pack_qtys.sort { |a, b| a <=> b }.each do |p, v|
break if left_over_qty.zero?
sub_total = []
partial.each do |_x, _y, _z, val|
sub_total << val
end
next unless left_over_qty <= p
# Find total cost of sub_items
line_total = sub_total.inject(:+)
packs.map { |a| a[0] += 1 if a[1].to_i == p }
left_over_qty = 0
# Return array of the cheapest line
if [exact.min[3], line_total].min == line_total
puts "\nThis is it #{partial}"
return partial
end
next if packs.detect { |a| a[1] == p }
puts "\nThis is it #{exact}" if [exact.min[3], line_total].min == exact
exact
end
packs << [1, p, v]
def present_line(packs)
puts "pACKS: #{packs}"
sub_total = []
sub_item = []
packs.each do |k, v, i|
sub_total << k * i
sub_item << "#{k}x #{v} packs @ #{i}"
end
[packs, left_over_qty]
@line_total = sub_total.inject(:+)
sub_item.each { |s| s }
end
def presenter_line_total
@line_total
end
end
@@ -25,16 +25,10 @@
end
describe '#optimal' do
it 'should return total_packs[0] which is an Array' do
it 'should return optimum combination of packs which is an Enumerator' do
instance = OrderLine.new(12, Item.new('watermelons'))
expect(instance.optimal(instance.order_item.name)).to be_a Array
end
it 'should return whole_packs[0] which is an Array' do
instance = OrderLine.new(10, Item.new('watermelons'))
expect(instance.optimal(instance.order_item.name)).to be_a Array
expect(instance.optimal(instance.order_item.name)).to be_a Enumerator
end
end
@@ -54,22 +48,4 @@
expect(instance.presenter_line_total).to be_a Money
end
end
describe '#whole_packs' do
it 'should return an Array' do
instance = OrderLine.new(12, Item.new('watermelons'))
pack_qtys = [[3, 6.99], [5, 8.99]]
expect(instance.send(:whole_packs, pack_qtys, [], @order_qty)).to be_a Array
end
end
describe '#left_over_items' do
it 'should return an Array' do
instance = OrderLine.new(12, Item.new('watermelons'))
pack_qtys = [[3, 6.99], [5, 8.99]]
expect(instance.send(:left_over_items, pack_qtys, [], 1)).to be_a Array
end
end
end

0 comments on commit ace50ed

Please sign in to comment.