protection not working with api.constrains - odoo-8

I want to forbid making product if there is no "qty_available". But this code is not working.
It works only if i change #api.constrains to #api.onchange('move_lines') but if i do it with onchange there is still possibility to save record.
as api.constrains ingores doted names, how can i make this work
class mrp_production(osv.osv):
_inherit = 'mrp.production'
#api.constrains('qty_available', 'move_lines.qty_available')
def move_lines_check(self):
for line in self.move_lines:
if line.qty_available < 1:
raise ValidationError(_('There is not enough raw material, check Quantity on hand'))
UPDATE goal
So again goal is to make Warning appear if there is no raw materials to make product from (we can't manufacture from nothing) and it should be impossible to make product if there is not enough materials.

Please add below constraint to mrp.production model to restrict saving Manufacturing order, if raw material product is not enough for production.
from openerp import api
from openerp.exceptions import Warning
#api.one
#api.constrains('move_lines','bom_id')
def _check_product_stock_availability(self):
if self.move_lines:
for move in self.move_lines:
qty_available = move.product_id.with_context(location=move.location_id.id).qty_available
if qty_available < move.product_uom_qty:
raise Warning(_('There is not enough raw material, check Quantity on hand.'))
elif self.bom_id:
factor = self.product_uom._compute_qty(self.product_uom.id,self.product_qty, self.bom_id.product_uom.id)
result, result2 = self.bom_id._bom_explode(self.bom_id,self.product_id, factor / self.bom_id.product_qty, None, routing_id=self.routing_id.id)
product_obj = self.env['product.product']
for line in result:
qty_available = product_obj.browse(line.get('product_id')).with_context(location=self.location_src_id.id).qty_available
#qty_available = line.product_id.with_context(location=self.location_src_id.id).qty_available
if qty_available < line.get('product_qty'):
raise Warning(_('There is not enough raw material, check Quantity on hand for products in BOM.'))

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")

Google Sheets - Dependent drop-down lists

I am recreating and expanding on a doc I had previously made. I have already brought in the script I had used originally, and tweaked it where I believed appropriate to get it working in this sheet, but I must have missed something. Editable samples of the 3 spreadsheet files involved can be found here. These files are a sample "Price List", "Catalog"(which aggregates manufacturer names from all price lists, and also has a "Catalog" tab for misc items not sold by one of my primary vendors), and "Addendum B" which is the file I require assistance with.
This document is an addendum to my contracts which lists all equipment being sold as part of that contract. It has 2 sheets in it ("Addendum B" and "XREF"), and "Addendum B" has several dependent columns: Vendor, Manufacturer, Model, Description, and Price. Their dependencies are as follows:
Currently Working
Vendor: Basic data validation pulling from XREF!A2:A.
Not working, script in file
Manufacturer: Based on the Vendor selected, should be a drop-down
list generated from the column headed with that vendor's name on
"XREF".
Now here's were it gets tricky beyond what I had previously done.
Model: I want this column to be a drop-down listing all model numbers
associated with that manufacturer, from a completely separate price
list provided to me by my vendor. (I have shared a sample price list which reflects column positions as they appear in all such files.
Description: Displays the corresponding description for the Model selected, from the price list selected in the Vendor column.
Price: Displays the corresponding markup price for the Model selected, from the price list selected in the Vendor column.
And that about summarizes my goals and what I'm struggling with.
So I looked into your script file in sheet Addendum B.
I have made few edits and it should be working now, the modified code:
function onEdit()
{
var ss = SpreadsheetApp.getActiveSpreadsheet(),
sheet = ss.getActiveSheet(),
name = sheet.getName();
if (name != 'Addendum B') return;
var range = sheet.getActiveRange(),
col = range.getColumn();
if (col != 6) return; //You col was set to 5 changed it to 6!
var val = range.getValue(),
dv = ss.getSheetByName('XREF'),
data = dv.getDataRange().getValues(),
catCol = data[0].indexOf(val),
list = [];
Logger.log(catCol)
for (var i = 1, len = 100; i < len; i++) // Problem is here, you have too many items in list! Cannot have more 500 items for validation
list.push(data[i][catCol]);
var listRange = dv.getRange(2,catCol +1,dv.getLastRow() - 1, 1)
Logger.log(list)
var cell = sheet.getRange(range.getRow(), col-1)
var rule = SpreadsheetApp.newDataValidation()
.requireValueInRange(listRange) // Use requireValueIn Range instead to fix the problem
.build();
cell.setDataValidation(rule);
Logger.log(cell.getRow())
}
The reason your validation was not working was you had more than 500 items in your data validation list. I just modified it to take the same values from range instead. Hope you find that helpful!
Now for the remaining 3 questions, here are my comments and thoughts on it:
1) I didn't find any code related to the problem you mentioned in your question. So, I am gonna assume you are asking for general ideas on how to achieve this?
2) You basically approach the problem the same as you did with the above code! Once a manufacturer is selected, the script looks for that manufacturer in the sheet and update the Data validation in the corresponding model column.
You will modify the code like so
var ss = SpreadsheetApp.openById("1nbCJOkpIQxnn71sJPj6X4KaahROP5cMg1SI9xIeJdvY")
//The above code with select the catalog sheet.
dv = ss.getSheetByName('Misc_Catalog')
//The above code will open the Misc_Catalog tab.
3) A better approach would be to use Sidebar/Dialog Box to validate your input then add it to the sheet at the end. (Looks Cleaner and also prevents unnecessary on edit trigger in the sheet, which can take a while to update.)
You find more details here: https://developers.google.com/apps-script/guides/dialogs

How do I break up high-cpu requests on Google App Engine?

To give an example of the kind of request that I can't figure out what else to do for:
The application is a bowling score/stat tracker. When someone enters their scores in advanced mode, a number of stats are calculated, as well as their score. The data is modeled as:
Game - members like name, user, reference to the bowling alley, score
Frame - pinfalls for each ball, boolean lists for which pins were knocked down on each ball, information about the path of the ball (stance, target, where it actually went), the score as of that frame, etc
GameStats - stores calculated statistics for the entire game, to be merged with other game stats as needed for statistics display across groups of games.
An example of this information in practice can be found here.
When a game is complete, and a frame is updated, I have to update the game, the frame, every frame after it and possibly some before it (to make sure their scores are correct), and the stats. This operation always flags the CPU monitor. Even if the game isn't complete, and statistics don't need to be calculated, the scores and such need to be updated to show the real-time progress to the user, and so these also get flagged. The average CPU time for this handler is over 7000 mcycles, and it doesn't even display a view. Most people bowl 3 to 4 games per series - if they are entering their scores realtime, at the lanes, that's about 1 request every 2 to 4 minutes, but if they write it all down and enter it later, there are 30-40 of these requests being made in a row.
As requested, the data model for the important classes:
class Stats(db.Model):
version = db.IntegerProperty(default=1)
first_balls=db.IntegerProperty(default=0)
pocket_tracked=db.IntegerProperty(default=0)
pocket=db.IntegerProperty(default=0)
strike=db.IntegerProperty(default=0)
carry=db.IntegerProperty(default=0)
double=db.IntegerProperty(default=0)
double_tries=db.IntegerProperty(default=0)
target_hit=db.IntegerProperty(default=0)
target_missed_left=db.IntegerProperty(default=0)
target_missed_right=db.IntegerProperty(default=0)
target_missed=db.FloatProperty(default=0.0)
first_count=db.IntegerProperty(default=0)
first_count_miss=db.IntegerProperty(default=0)
second_balls=db.IntegerProperty(default=0)
spare=db.IntegerProperty(default=0)
single=db.IntegerProperty(default=0)
single_made=db.IntegerProperty(default=0)
multi=db.IntegerProperty(default=0)
multi_made=db.IntegerProperty(default=0)
split=db.IntegerProperty(default=0)
split_made=db.IntegerProperty(default=0)
class Game(db.Model):
version = db.IntegerProperty(default=3)
user = db.UserProperty(required=True)
series = db.ReferenceProperty(Series)
score = db.IntegerProperty()
game_number = db.IntegerProperty()
pair = db.StringProperty()
notes = db.TextProperty()
simple_entry_mode = db.BooleanProperty(default=False)
stats = db.ReferenceProperty(Stats)
complete = db.BooleanProperty(default=False)
class Frame(db.Model):
version = db.IntegerProperty(default=1)
user = db.UserProperty()
game = db.ReferenceProperty(Game, required=True)
frame_number = db.IntegerProperty(required=True)
first_count = db.IntegerProperty(required=True)
second_count = db.IntegerProperty()
total_count = db.IntegerProperty()
score = db.IntegerProperty()
ball = db.ReferenceProperty(Ball)
stance = db.FloatProperty()
target = db.FloatProperty()
actual = db.FloatProperty()
slide = db.FloatProperty()
breakpoint = db.FloatProperty()
pocket = db.BooleanProperty()
pocket_type = db.StringProperty()
notes = db.TextProperty()
first_pinfall = db.ListProperty(bool)
second_pinfall = db.ListProperty(bool)
split = db.BooleanProperty(default=False)
A few suggestions:
You could store the stats for frames as part of the same entity as the game, rather than having a separate entity for each, by storing it as a list of bitfields (stored in integers) for the pins standing at the end of each half-frame, for example. Let me know if you want more details on how this would be implemented.
Failing that, you can calculate some of the more interrelated stats on fetch. For example, calculating the score-so-far ought to be simple if you have the whole game loaded at once, which means you can avoid having to update multiple frames on every request.
We can be of more help if you show us your data model. :)

Resources