Fedex gem, multiples packages - ruby-on-rails

I'm trying to calculate the shipping cost depending of the total quantity of the product purchased with the Fedex gemhttps://github.com/jazminschroeder/fedex. I'm getting the rates but I have different packages options, 3 actually.
the first one when the quantity is 1 (small), the second one when the quantity is 2 (medium) and the third one when the quantity is 3 or 4 (larger).
def packages_types
packages = []
if #order.quantity >= 4
packages << { :weight => {:units => "LB", :value => #order.case_weight},
:dimensions => {:length => 8, :width => 1, :height => 7, :units => "IN" } }
elsif #order.quantity == 2
packages << { :weight => {:units => "LB", :value => 21},
:dimensions => {:length => 1, :width => 2, :height => 7, :units => "IN" } }
elsif #order.quantity == 1
packages << { :weight => {:units => "LB", :value => 10},
:dimensions => {:length => 1, :width => 2, :height => 2, :units => "IN" } }
end
end
So if the client orders 5 on quantity. It's going to be the package of 4(large) and 1 of the small package. I was thinking using the mod...

def packages_types
packages = []
extra_items_count = #order.quantity % 4
large_packages_needed = (#order.quantity - extra_items_count) / 4
# point A
large_packages_needed.times do
packages << { :weight => { :units => "LB", :value => #order.case_weight },
:dimensions => { :length => 8, :width => 1, :height => 7, :units => "IN" } }
end
# point B
case extra_items_count
when 1
packages << { :weight => { :units => "LB", :value => 10 },
:dimensions => { :length => 1, :width => 2, :height => 2, :units => "IN" } }
when 2
packages << { :weight => { :units => "LB", :value => 21 },
:dimensions => { :length => 1, :width => 2, :height => 7, :units => "IN" } }
when 3, 4
packages << { :weight => { :units => "LB", :value => #order.case_weight },
:dimensions => { :length => 8, :width => 1, :height => 7, :units => "IN" } }
end
return packages
end
Point A: For each group of 4 items, a large package is needed (and added to the packages array).
Point B: For the remaining items (example: you ordered 5 items -> 1 large package of 4 items + 1 small for 1 remaining item), we add the corresponding conditions in the package array.

Related

Rails Axlsx render conditional row background color

I am using axlsx gem to generate Excel sheets in Ruby on Rails.
wb = xlsx_package.workbook
wb.styles do |s|
title = s.add_style :b => true, :sz => 10,
:border => { :style => :thin, :color => "00" },
:alignment => {
:horizontal => :center,
:vertical => :center
}
row = s.add_style :b => false,
:sz => 10,
:border => { :style => :thin, :color => "00" },
:alignment => {
:horizontal => :left,
:vertical => :center
}
wb.add_worksheet(name: "Customer") do |sheet|
sheet.add_row ['Customer Name', 'Status'] :style => title
#customers.each do |customer|
sheet.add_row [customer.name, customer.status] :style => row
end
end
how can I conditionally change the row background color if the customer status let say = "Late Payment"
I haven't tested it but this should do the job.
wb = xlsx_package.workbook
wb.styles do |s|
title = s.add_style :b => true, :sz => 10,
:border => { :style => :thin, :color => "00" },
:alignment => {
:horizontal => :center,
:vertical => :center
}
row = s.add_style :b => false,
:sz => 10,
:border => { :style => :thin, :color => "00" },
:alignment => {
:horizontal => :left,
:vertical => :center
}
red_cell_row = s.add_style :b => false,
:sz => 10,
:border => { :style => :thin, :color => "00" },
:alignment => {
:horizontal => :left,
:vertical => :center
},
:bg_color => "FF0000",
:fg_color => "000000"
wb.add_worksheet(name: "Customer") do |sheet|
sheet.add_row ['Customer Name', 'Status'] :style => title
#customers.each do |customer|
if customer.status == "Late Payment"
sheet.add_row [customer.name, customer.status] :style => red_cell_row
else
sheet.add_row [customer.name, customer.status] :style => row
end
end
end

Load a hash on grouped_collection_select rails form

currently, I have a hash like this:
#lg = {
"Latin East Group" => [
{:id => 2, :name => "HONGKONG"},
{:id => 3, :name => "NINGBO, ZHEJIANG"},
{:id => 4, :name => "SINGAPORE"},
{:id => 5, :name => "LARCHMONT, NY"},
{:id => 6, :name => "CHICAGO, IL"},
{:id => 7, :name => "HAIPHONG"},
{:id => 8, :name => "DANANG"},
{:id => 9, :name => "HANOI"},
{:id => 10, :name => "MARSEILLE"},
{:id => 11, :name => "LONDON"},
{:id => 12, :name => "EDINBURGH"},
{:id => 13, :name => "AMSTERDAM"},
{:id => 14, :name => "HOCHIMINH"},
{:id => 15, :name => "SHANGHAI"}
],
"Latin West Group" => [],
"Others" => [
{:id => 16, :name => "Brazil" },
{:id => 17, :name => "Mexico" },
{:id => 18, :name => "Columbia"}
]
}
Now, I am using select2 with my form, and I wanna create a dropdown menu from that hash instance variable. I want the keys of the hash will be the optgroups, and the option values are gonna be the name sin the hash like Singapore, Brazil... Therefore, I am wondering what is the correct syntax for it. Currently, this is my code:
_form_body.haml:
%div.col-md-8
= f.grouped_collection_select :origin_locations, #lg, #lg.keys, #lg.values, {:selected => f.options[:origin_locations]}, {class: 'form-control select2-multiple origin_locations', :multiple => true}
pricing_histories_controller.rb:
def load_location_groups
#lg = {}
location_groups = LocationGroup.all.includes(:locations).each { |group|
#lg[group.name]= group.locations.map{|l| {id: l.id,name: l.name}}
}
# location_groups.each_with_index do |location_group, index|
arr = Location.where("id NOT IN (SELECT DISTINCT(location_id) FROM location_group_assignments)").pluck(:id,:name)
#location_groups = {}
#lg["Others"] = arr.map{ |e| {id: e.first, name: e.last}}
end
I will get the error:
ActionView::Template::Error (["Latin East Group", "Latin West Group",
"Others"] is not a symbol nor a string)
So, I am wondering what I am doing wrong here. Any suggestions would be appreciated. Thanks and have a nice day.

Include counts in as_json method

I have a Customers table and an Orders table. Each customer has multiple orders. When I do a Customers.all.as_json(:include => :orders), I get all the orders but I just want to get the count
I tried Customers.all.as_json(:include => {:orders => {:only => [], :methods => [:custom_method_to_get_order_count}}) though it gets the correct count I have array of object that are equal to count.
Wrong output! :(
[
{
:customer_id => 1,
:customer_name => "ABC",
:orders => [
{:custom_method_to_get_order_count => 2},
{:custom_method_to_get_order_count => 2}
]
},
{
:customer_id => 2,
:customer_name => "DEF",
:orders => [
{:custom_method_to_get_order_count => 3},
{:custom_method_to_get_order_count => 3},
{:custom_method_to_get_order_count => 3}
]
},
{
:customer_id => 3,
:customer_name => "XYZ",
:orders => [
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10}
]
}
]
Correct output I am looking for
[
{
:customer_id => 1,
:customer_name => "ABC",
:orders => {
:custom_method_to_get_order_count => 2
}
},
{
:customer_id => 2,
:customer_name => "DEF",
:orders => {
:custom_method_to_get_order_count => 3
}
},
{
:customer_id => 3,
:customer_name => "XYZ",
:orders => {
:custom_method_to_get_order_count => 10
}
}
]
You can also use like this:
class Customers
def get_orders_count
self.orders.count
end
end
and now you can get all orders count in customer object:
Customers.all.as_json(method: :get_orders_count)
Output will be something like:
[
{
:customer_id => 1,
:customer_name => "ABC",
:get_orders_count => 12
},
{
:customer_id => 2,
:customer_name => "DEF",
:get_orders_count => 20
},
{
:customer_id => 3,
:customer_name => "XYZ",
:get_orders_count => 50
}
]
Never mind! I got the answer.
class Customers
def custom_method_to_get_order_count
Orders.where(:customer_id => id).count
end
end
What's happening to me, whenever I post the question on SO, I get the answer!

Remove duplicate from an array in ruby

I want to output an array of hashes with the name being unique to all hashes. How would I go about doing this using ruby?
This is my input:
input = [{:name => "Kutty", :score => 2, :some_key => 'value', ...},
{:name => "Kutty", :score => 4, :some_key => 'value', ...},
{:name => "Baba", :score => 5, :some_key => 'value', ...}]
I want the output to look like this:
output = [{:name => "Kutty", :score => 4, :some_key => 'value', ...},
{:name => "Baba", :score => 5, :some_key => 'value', ...}]
To just remove duplicates based on :name, simply try;
output = input.uniq { |x| x[:name] }
Demo here.
Edit: Since you added a sorting requirement in the comments, here's how to select the entry with the highest score for every name if you're using Rails, I see you already got an answer for "standard" Ruby above;
output = input.group_by { |x| x[:name] }
.map {|x,y|y.max_by {|x|x[:score]}}
A little explanation may be in order; the first line groups the entries by name so that each name gets its own array of entries. The second line goes through the groups, name by name, and maps each name group to the entry with the highest score.
Demo here.
input = [{:name => "Kutty", :score => 2, :some_key => 'value'},{:name => "Kutty", :score => 4, :some_key => 'value'},{:name => "Baba", :score => 5, :some_key => 'value'}]
p input.uniq { |e| e[:name] }
The above solution works for ruby > 1.9, for older versions of ruby you could use something along these lines:
input = [{:name => "Kutty", :score => 2, :some_key => 'value'},{:name => "Kutty", :score => 4, :some_key => 'value'},{:name => "Baba", :score => 5, :some_key => 'value'}]
unames = []
new_input = input.delete_if { |e|
if unames.include?(e[:name])
true
else
unames << e[:name]
false
end
}
p new_input
Try this solution..
input = [{:name => "Kutty", :score => 2, :some_key => 'value'},
{:name => "Kutty", :score => 4, :some_key => 'value'},
{:name => "Baba", :score => 5, :some_key => 'value'}]
a = []
output = []
input.collect do |i|
input.delete(i) if !a.include?(i[:name])
output << i if !a.include?(i[:name])
a << i[:name] if !a.include?(i[:name])
end
output = [{:some_key=>"value", :name=>"Kutty", :score=>2},
{:some_key=>"value", :name=>"Baba", :score=>5}]
UPDATED
output = {}
input.each do |e|
ref = output[e[:name]]
if ref && ref[:score] > e[:score]
#nothing
else
output[e[:name]] = e
end
end
check output:
puts output.values
input.uniq{|hash| hash[:name]}

Array to hash of key value pairs in ruby

From a model that returns all the values from a table, how would I convert that to a hash of name value pairs
{column_value => column_value}
e.g.
[{:id => 1, :name => 'first'}, {:id => 2, :name => 'second'}, {:id => 3, :name => 'third'}]
to (specifying :id and :name)
{'first' => 1, 'second' => 2, 'third' => 3}
You can do it in one line with inject:
a = [{:id => 1, :name => 'first'}, {:id => 2, :name => 'second'}, {:id => 3, :name => 'third'}]
a.inject({}) { |sum, h| sum.merge({ h[:name] => h[:id]}) }
# => {"third" => 3, "second" => 2, "first" => 1}
The following approach is reasonably compact, yet still readable:
def join_rows(rows, key_column, value_column)
result = {}
rows.each { |row| result[row[key_column]] = row[value_column] }
result
end
Usage:
>> rows = [{:id => 1, :name => 'first'}, {:id => 2, :name => 'second'}, {:id => 3, :name => 'third'}]
>> join_rows(rows, :name, :id)
=> {"third"=>3, "second"=>2, "first"=>1}
Or, if you want a one-liner:
>> rows.inject({}) { |result, row| result.update(row[:name] => row[:id]) }
=> {"third"=>3, "second"=>2, "first"=>1}
o = Hash.new
a = [{:id => 1, :name => 'first'}, {:id => 2, :name => 'second'}, {:id => 3, :name => 'third'}]
a.each {|h| o[h[:name]] = h[:id] }
puts o #{'third' => 3, 'second' => 2, 'first' => 1}

Resources