Calculating an Average from booleans with Ruby on Rails - ruby

I have a setup in which there are 10 attributes that accept a float in a rails form. Each attribute also is associated with a value in my model. If a number is entered on the form for more than one attribute, I need to create a weighted average.
An example would be if I have 10 products, each having a price in my model. In the form, a user can enter in the amount (number of products) for each product. I'd like to calculate a weighted price for those products that have an amount entered.
So how can I create a weighted average that checks which products have amounts entered?

columns_names = ['a','b','c','d'] # array of name of the columns
obj = Model.find(:id) # find the object with id
# loop and get column values that are set
values = columns_names.inject([]) do |arr,column_name|
arr << obj.column_name if params[column_name].eql?"true" # collect the values if the column set
arr
end
#get average
if values.blank?
# no column selected
else
avg = values.reduce(:+)/values.size
end
check this for help on weighted average
http://www.dzone.com/snippets/weighted-mean

This code retrieves all attributes that are true on your model:
#model = Model.find(params[:id)
#model.attributes.select{|k,v| (v.is_a?(TrueClass) || v.is_a?(FalseClass)) && v}
If you want the false ones just do a:
#model.attributes.select{|k,v| (v.is_a?(TrueClass) || v.is_a?(FalseClass)) && !v}
Don't know if this is what you are looking for, but maybe it can clear your head a little bit.

Related

'LpVariable' object does not support indexing

I ran into the error of 'LpVariable' object does not support indexing. Is this due to how my data are being setup for my PuLP optimization?
Basically, I am trying to get the optimized sales by multiplying the replenishment quantity with the selling price for each SKU (UPC). The replenishment quantity will be based on the quantity sold (available in the dataset) and will be the constraint for the optimization problem. I should not replenish way too much than what I sold.
Could someone with PuLP experience please help me with my error? Is the way I setup my For-Loop logical?
Here is the key portion of my Python codes:
After sorting my data based on LocationNumber, the first and last few rows of my data are as follows:
enter image description here
df.drop(['LowlawWeekYear'], axis=1, inplace=True) # Drop the WeekYear column
store_list = {108} # This is LocationNumber. Will only run one store for now
for store_number in sorted(store_list):
specific_store = df[df['LocationNumber'] == store_number]
Qty_Price_df = specific_store.groupby('UPC', as_index = False)['AvgSellingPricewoTax', 'Units'].mean()
# get the mean of the AvgSellingPricewoTax and Units. Ultimately, I only need one row for each UPC with the average values of AvgSellingPricewoTax and Units.
SKU_list = sorted(list(set(Qty_Price_df.UPC))) # List of SKU numbers
Variable_list = dict(zip(Qty_Price_df.UPC, Qty_Price_df.UPC)) # Variables which I am looking to optimize
Price_list = dict(zip(Qty_Price_df.UPC, Qty_Price_df.AvgSellingPricewoTax))
Qty_list = dict(zip(Qty_Price_df.UPC, Qty_Price_df.Units)) # Quantity sold per UPC. This will be used in the constraint.
from pulp import *
optimization = LpProblem("Perfect_Store", LpMaximize)
Variable_list = LpVariable("SKU", lowBound=0) # Continuous by default
# Define objective function
optimization += lpSum([Price_list[type]*Variable_list[type] for type in SKU_list]), "Total Sales by multiplying Price with Variable Qty"
***# Here is where I ran into the error message: 'LpVariable' object does not support indexing***
# Set constraint for each SKU
for c in SKU_list:
optimization += (Qty_list[c] <= Qty_list[c]*1.05), "Constraints for each SKU is the replenishment quantity which should not be more than 5% of the quantity sold"
print("Status:", LpStatus[optimization.status])

Ruby / Redmine: compile a hash from issue subjects and appropriate custom fields

I’m using Redmine and Computed Custom Field plugin.
The plugin provides a possibility to make custom fields computed and it accepts ruby code for calculations.
In Redmine I have a project (Project_id = 11) where in I calculate the cost of products in a separate custom field for each issue. It looks like this:
Each Issue has a custom field (cf_id = 31) for selecting the product: Pears, Pineapples, Tomatoes, Coconuts.
Each Issue has a custom field (cf_id = 32) for entering the quantity (pieces) of goods.
Each Issue has a custom field (cf_id = 33) for entering the weight (pounds) of goods.
Each Issue has a computed custom field (cf_id = 34) in which the formula calculates the cost of the product.
The formula in the computed custom field (cf_id = 34) includes two hashes with prices of products (depending on the product type):
products_by_weight = {
"Pears" => [110],
"Tomatoes" => [120]
}
products_by_pieces = {
"Pineapples" => [130,300],
"Coconuts" => [140,200]
}
Then my formula checks the product selected in cf_id = 31 for belonging to the first or the second hashes and performs the corresponding calculations:
Multiplies the price by weight (cf_id = 32) in case of using the goods from the first list
Or multiplies the price by the quantity (cf_id = 33) in case of using the goods from the second list. The second value in the value array of "products_by_pieces" hash is the weight limit per piece. If the weight divided by the limit is a larger amount than entered in cf_id = 32, then the formula in scenario 2 will use this quantity instead of the one indicated in cf_id = 32.
Now I`m trying to move these variables outside the formula. I made a project (Project_id = 22) in which I want to save these variables as issues.
I imagine it like this:
The name of the issue is the name of the product
Each issue has two custom fields:
cf_id = 41 is price of product
cf_id = 42 is weight limit per piece
For each issue a category is assigned: "products_by_weight" or "products_by_pieces".
I want to compile the same hashes that are now included in my formula in the cf_id = 34 of the issues of the project 11, but automatically from the issues of the project 22, taking into account the category.
So far, all I have achieved is to find the price of a known product from such issues of the project 22.
price = Project.find(22).issues.where(subject: "Pineapples").first.try(:custom_field_value,41)
But this does not help in any way and requires changes to the code when adding each new product.
I'm new to programming and Ruby, so I’m trying to experiment with Redmine classes, and tried to compile a hash with such code:
Issue.by_category(Project.find(22))
But as a result, so far I have received only this:
[{"status_id"=>"27", "closed"=>true, "category_id"=>"1", "total"=>"10"}]
Which is completely different from the result I expect.
Any help would be helpful!
UPD.
Right now, my variables (product prices and weight limits) are in a hash, which is directly a part of the code for computed field 34. But I do not want these variables (prices and weight limits) to be part of the code. I want to manage them as Issues with corresponding custom fields (41 and 42) in a separate project (22) - in such a way that regular user can change or add these values in Issues without having to change the code of the calculated custom field (34). So I want to compile that hash based on the Issues from Project 22 instead of writing it directly. I assume this is so, that the Subjects of the Issues of the Project 22 should become the keys and array of custom fields [41,41] - the values. In doing so, I need two separate hashes determined by the assigned category ("goods_by_weight" and "goods_by_pieces") because they are calculated differently and in Project 22 I have other variables written as values of custom fields in Issues with a different category.
I solved this problem in the following way.
As planned, now I store the price list for my products as issues in a separate Project (ID 22). To get the prices hash of all products of the selected category (A) in the computed custom field's formula if Issue of Project (ID 11), I do the following:
PRICELIST_PROJECT_ID = 22
CATEGORY_A_ID = 1
PRICE_VALUE_CFID = 41
WLIMIT_VALUE_CFID = 42
delimiter = ','
pricelist_issues_cat_a = Project.find(PRICELIST_PROJECT_ID).issues.select { |rate| rate.category_id == CATEGORY_A_ID }
cata_products_names = []
cata_products_pvalues = []
for i in (0..pricelist_issues_cat_a.size-1) do
cata_products_names[i] = pricelist_issues_cat_a[i].try(:subject)
cata_products_pvalues[i] = pricelist_issues_cat_a[i].try(:custom_field_value,PRICE_VALUE_CFID).split(Regexp.union(delimiter)).map(&:to_f)
end
cata_price_hash = Hash[cata_products_names.zip(cata_products_pvalues)]
And the same way for product category B.
Not sure if this is the most efficient way, but it works for me.

Qty available by location (again)

I know this was discussed before but it's not really working for me. How can i get qty available for location or warehouse my product is now.
(Most of the answers are in old API and this one not really working for me)
class ProductProduct(models.Model):
_inherit = 'product.template'
available_qty = fields.Integer(
string='Qty By Loc',
compute='product_qty_location_check',
)
def product_qty_location_check(self):
if self:
self.available_qty = self.with_context({'location' : self.source_location.id}).qty_‌​available
AttributeError: 'product.template' object has no attribute 'source_location'
To get the quantity by location you need to search the location with the product_id in stock.quant
Use the below sample in your compute function:
quant_sr = self.env["stock.quant"].search([('location_id','=',self.source_location.id),('product_id','=',self.product_id.id)])
qty = 0.0
for quant in quant_sr:
qty += quant.qty
print qty
First you have to find out your location and/or warehouse. There are enough possibilities to do so:
use a wizard which has a field
search by reference e.g. self.env.ref('my_module.my_location')
use other sources
Now you can use them on product.product's _product_available(). Just call that method on one or more products (recordssets) and evaluate the result of this method. To filter for locations and/or warehouses use the context. For example:
# get a recordset of all products
products = self.env['product.product'].search([])
# get a special location (my_location)
location = self.env.ref('my_module.my_location')
quantities = products.with_context(location=location.id)._product_available()
# print the quantities
for product_id, quantity_dict in quantities.iteritems():
print product_id
print quantity_dict
The same is possible with with_context(warehouse=warehouse.id) or even with list of IDs or names: with_context(location=[1,2,3]), with_context(location="My Location")

How do I use the on_change method to calculate total current value

How do I make a value change in real time after I input a specific field value in a form? e.g from the screenshot below , if I enter Quantity recieved as 10000 the Actual stock should compute to 80500.
so far this is the code for the on_change method I came up with :
I would like to know whether this is the correct approach
#api.one
#api.onchange('qnty_recieved', 'init_stock')
def _compute_current_stock(self):
qnty_recieved = self.qnty_recieved
init_stock = self.init_stock
current_quantity = self.current_quantity
self.current_quantity = self.qnty_recieved + self.init_stock
Below is a screenshot of what I am trying to achieve.
If i'm not wrong you want to change your actual stock in real time based on quantity received field.
This can be best achieved by using depends method.
#api.one
#api.depends('qnty_recieved')
def _compute_current_stock(self):
# Assuming current_quantity as the field name of actual stock
self.current_quantity += self.qnty_recieved
You should also add
compute=_compute_current_stock, store=True keyword arguments to your actual stock field.

How to merge ActiveRecord::Relation objects and add only the value, not the key

I have a simple question about programming in Ruby. I'm a newbie to Ruby, so if somebody can help me, I will really appreciate it.
Assume a system lets users have buyer and seller feedback ratings. I want to add/merge the buy and sell feedback ratings for a user into one consolidated rating, so only the rating needs to be added from the two Relation objects. The user id is only used as the key, but is not added.
buy_rating = user_object.group(buy_feedback_rating).select('buy_feedback_rating, COUNT(id) as count')
sell_rating = user_object.group(sell_feedback_rating).select('sell_feedback_rating, COUNT(id) as count')
buy_rating and sell_rating are histograms of the user's buy/sell rating, with 1=Terrible, 2=Poor, 3=Average, 4=Good, 5=Very Good.
The following is a sample array with (key,value) pairs where key=rating from 1 to 5, and value=number of ratings
buy rating = [(1,2),(2,5),(3,1),(4,7),(5,6)]
sell rating = [(1,3),(2,2),(3,7),(4,4),(5,7)]
Desired output = [(1,5),(2,7),(3,8),(4,11),(5,13)]
(obtained by adding only the second values from each array, not the first values).
The buy_rating and sell_rating arrays will only have the the key->value pair if the value>0. Meaning, if a buyer has no buyer rating=1, then the pair (1,0) will not be present in the buy_rating array. This means the arrays could be as follows:
buy_rating = [[2,5],[3,1],[4,7]]
sell_rating = [[1,3],[2,2],[5,7]]
Question is, how do I achieve the desired result? I want to add only the second column, not the first, from each array. Object returned should be of the same data type as buy_rating and sell_rating, i.e. buy_rating and sell_rating are both ActiveRecord::Relation objects, and the result should also be an ActiveRecord::Relation object.
You can make a map of values, sum based on the first, index, and then convert back to an array
buy_rating = [[1,2],[2,5],[3,1],[4,7],[5,6]]
sell_rating = [[1,3],[2,2],[3,7],[4,4],[5,7]]
merged_ratings = buy_rating + sell_rating
composite_ratings = Hash.new(0)
merged_ratings.each do |rating|
composite_ratings[rating[0]]+=rating[1]
end
composite_ratings.to_a
Check this fiddle: http://rubyfiddle.com/riddles/2d0f9/2

Resources