Both sql and python constraints are not working in odoo 9 - methods

I have been battling with this for a while. none of the two options are working neither were they giving errors. i commented the pythonic constrain method for you to see.
code snippet:
class house_development(models.Model):
_name = 'house.development'
_description = 'Development'
_inherit = ["mail.thread"]
name = fields.Char(string="Name", required=True, track_visibility='onchange')
description = fields.Text(string="Description", track_visibility='onchange')
# #api.one
# #api.constrains('name')
# def _identify_same_name(self):
# for record in self:
# if record.name in self:
# raise exceptions.ValidationError("There is another development/project with the same name: %s" % record.name)
_sql_constraints = [
('name_unique',
'UNIQUE(name)',
"There is another development/project with the same name"),
]

It should be like that,
#api.multi
#api.constrains('name')
def _identify_same_name(self):
for record in self:
obj = self.search([('name','=ilike',record.name),('id','!=',record.id)])
if obj:
raise exceptions.ValidationError("There is another development/project with the same name: %s" % record.name)
You need to search for the same name but not with the same id.
And for database unique constrains you may add like that.
_sql_constraints = [
('name_unique', 'unique(name)', 'There is another development/project with the same name!!!'),
]
Database constrains will not be added if there are duplicate name in
table. Sql constrains will apply only if the rule is not violated by
the existing data. I think in your case that's the point with Sql
constrains. And make sure for that you need to upgrade module. first
check duplicate records in database by firing that query.
Select name, count(*) from table_name
group by name
having count(*) > 1;
Available operators in domain in odoo Click to see more.

Related

IronPython Spotfire: Creating Hierarchy Column and moving associated Filter to TableGroup.Subgroup

I am working on an IronPython script for TIBCO Spotfire to create a new hierarchy column and then move the filter associated with the hierarchy to a TableGroup.Subgroup.
In my script I am doing the following:
1. Retrieving the table group "Result Table Group"
2. Retrieving the data table "Result Table"
3. creating a new subgroup "Result hierarchy subgroup"
4. Looping through all filters in the table group and
- hiding the filter
- creating a hierarchy column for the filter-associated column
- try to move the filter to the subgroup
Here is the relevant part from the code:
filterPanel = Document.ActivePageReference.FilterPanel
# get the correct tableGroup
for tableGroup in filterPanel.TableGroups:
if tableGroup.Name == "Result Table Group":
resultTableGroup = tableGroup
# get the correct dataTable
for table in Document.Data.Tables:
if table.Name == "Result Table":
resultDataTable = table
# create new subgroup
hierarchyfilterGroup = resultTableGroup.AddNewSubGroup("Result hierarchy subgroup")
filterPanel.InteractiveSearchPattern = ""
for filterHandle in filterPanel.FiltersMatchingSearchPattern:
tableGroupFilterHandle = resultTableGroup.GetFilter(filterHandle.FilterReference.Name)
if tableGroupFilterHandle != None:
tableGroupFilterHandle.Visible = False # hide filter in table group
# create a new hiearchy column
hierarchyColName = tableGroupFitlerHandle.FilterReference.Name + " - process hierarchy"
hierarchyExpressions = List[str]()
hierarchyExpressions.Add("[" + tableGroupFitlerHandle.FilterReference.Name + "]")
hierarchyExpressions.Add("[Process]")
hierarchy = HierarchyDefinition(HierarchyNestingMode.Nested, hierarchyExpressions)
resultDataTable.Columns.AddHierarchyColumn(hierarchyColName, hierarchy)
# try to get the hierarchy associated filter
hieararchyFilterHandle = tableGroup.GetFilter(hierarchyColName)
if hiearchyFilterHandle != None:
hierarchyfilterGroup.Add(hierarchyFilter.FilterReference)
However, tableGroup.GetFilter(hierarchyColName) always returns None for the hiearchy columns. As a result of running the script, I get the hierarchy filters correctly and I also see the subgroup correctly, but the hierarchy filters are not sorted into the subgroup.
Here are some other things I have tried:
Searching the whole FilterPanel for the hiearachy filter
FilterPanel.InteractiveSearchPattern = hierarchyColName
for filterHandle in filterPanel.FiltersMatchingSearchPattern:
...
--> does not find any MatchingFilters
Refreshing the dataTable before trying to find the filter
resultDataTable.Refresh()
...
​​​​​​​--> has no effect on the result
Using a separate second loop after the first loop for moving the filters
Could you please help me moving the hierarchy filter to the newly created subgroup?
Thank you in advance!
Finally figured it out and leaving the answer in case someone else ever gets stuck in the same place.
filterPanel = Document.ActivePageReference.FilterPanel
# get the correct tableGroup
for tableGroup in filterPanel.TableGroups:
if tableGroup.Name == "Result Table Group":
resultTableGroup = tableGroup
# get the correct dataTable
for table in Document.Data.Tables:
if table.Name == "Result Table":
resultDataTable = table
# create new subgroup
hierarchyfilterGroup = resultTableGroup.AddNewSubGroup("Result hierarchy subgroup")
filterPanel.InteractiveSearchPattern = ""
for filterHandle in filterPanel.FiltersMatchingSearchPattern:
tableGroupFilterHandle = resultTableGroup.GetFilter(filterHandle.FilterReference.Name)
if tableGroupFilterHandle != None:
tableGroupFilterHandle.Visible = False # hide filter in table group
# create a new hiearchy column
hierarchyColName = tableGroupFitlerHandle.FilterReference.Name + " - process hierarchy"
hierarchyExpressions = List[str]()
hierarchyExpressions.Add("[" + tableGroupFitlerHandle.FilterReference.Name + "]")
hierarchyExpressions.Add("[Process]")
hierarchy = HierarchyDefinition(HierarchyNestingMode.Nested, hierarchyExpressions)
resultDataTable.Columns.AddHierarchyColumn(hierarchyColName, hierarchy)
colExists, hierarchyCol = resultDataTable.Columns.TryGetValue(hierarchyColName)
resultTableGroup.FilterCollectionReference.AddNewFilter(hierarchyCol)
# move the filter to the subgroup
hierarchyFilterHandle = resultTableGroup.GetFilter(hierarchyColName)
hierarchyFilterHandle.Visible = True
dynamicSubGroup.Add(hierarchyFilterHandle.FilterReference)

How to write this domain to be sure at 100 % that we will get the right stock pack operation for each invoice line?

This post should be a little more complex than usual.
We have created a new field for an account.invoice.line : pack_operation. With this field, we can print serial/lot number for each line on the PDF invoice (this part works well).
Many hours passed trying to write the domain to select the EXACT and ONLY stock pack operation for each invoice line.
In the code below, we used the domain [('id','=', 31)] to make our tests printing the PDF.
Ho to write this domain to be sure at 100 % that we will get the right stock pack operation for each invoice line?
I really need your help here... Too complex for my brain.
Our code :
class AccountInvoiceLine(models.Model):
_inherit = "account.invoice.line"
pack_operation = fields.Many2one(comodel_name='stock.pack.operation', compute='compute_stock_pack_operation_id')
def compute_stock_pack_operation_id(self):
stock_operation_obj = self.env['stock.pack.operation']
stock_operation = stock_operation_obj.search( [('id','=', 31)] )
self.pack_operation = stock_operation[0]
EDIT#1
I know that you won't like my code. But, this one seems to work. I take any comments and improvements with pleasure.
class AccountInvoiceLine(models.Model):
_inherit = "account.invoice.line"
pack_operation = fields.Many2one(comodel_name='stock.pack.operation', compute='compute_stock_pack_operation_id')#api.one
def compute_stock_pack_operation_id(self):
procurement_order_obj = self.env['procurement.order']
stock_operation_obj = self.env['stock.pack.operation']
all_picking_ids_for_this_invoice_line = []
for saleorderline in self.sale_line_ids:
for procurement in saleorderline.procurement_ids:
for stockmove in procurement.move_ids:
if stockmove.picking_id.id not in all_picking_ids_for_this_invoice_line
all_picking_ids_for_this_invoice_line.append(stockmove.picking_id.id)
all_picking_ids_for_this_invoice_line))
stock_operation = stock_operation_obj.search(
[ '&',
('picking_id','in',all_picking_ids_for_this_invoice_line),
('product_id','=',self.product_id.id)
]
)
self.pack_operation = stock_operation[0]
The pack_operation field is a computed field, that be default means that the field will not be saved on the database unless you set store=True when you define your field.
So, what you can do here is change:
pack_operation = fields.Many2one(comodel_name='stock.pack.operation', compute='compute_stock_pack_operation_id')
to:
pack_operation = fields.Many2one(comodel_name='stock.pack.operation', compute='compute_stock_pack_operation_id', store=True)
And try running your query again.

How can I create a complete_name field in a custom module for a custom hierarchy like used on product categories in Odoo?

I'm trying to create a field “complete_name” that displays a hierarchy name similar to whats done on the product categories grid but I can't seem to get it to work. It just puts Odoo in an endless loading screen when I access the relevant view using the new field "complete_name".
I have tried to copy the code used in addons/product/product.py and migrate to work with Odoo 9 API by using compute instead of .function type but it did not work.
Can someone help me understand whats wrong? Below is my model class which works fine without the complete_name field in my view.
class cb_public_catalog_category( models.Model ):
_name = "cb.public.catalog.category"
_parent_store = True
parent_left = newFields.Integer( index = True )
parent_right = newFields.Integer( index = True )
name = newFields.Char( string = 'Category Name' )
child_id = newFields.One2many( 'catalog.category', 'parent_id', string = 'Child Categories' )
complete_name = newFields.Char( compute = '_name_get_fnc', string = 'Name' )
def _name_get_fnc( self ):
res = self.name_get( self )
return dict( res )
Your compute function is supposed to define the value of an attribute of your class, not return a value. Ensure the value you are assigning complete_name is a string.
Also name_get() returns a tuple. I am not sure if you really want a string representation of this tuple or just the actual name value.
Try this
def _name_get_fnc( self ):
self.complete_name = self.name_get()[1]
If you really want what is returned by name_get() then try this.
def _name_get_fnc( self ):
self.complete_name = str(self.name_get())
If you are still having issues I would incorporate some logging to get a better idea of what you are setting the value of complete_name to.
import logging
_logger = logging.getLogger(__name__)
def _name_get_fnc( self ):
_logger.info("COMPUTING COMPLETE NAME")
_logger.info("COMPLETE NAME: " + str(self.name_get()))
self.complete_name = self.name_get()
If this does not make it apparent what the issue is you could always try statically assigning it a value in the off chance that there is a problem with your view.
def _name_get_fnc( self ):
self.complete_name = "TEST COMPLETE NAME"
After further review I think I have the answer to my own question. It turns out as with a lot of things its very simple.
Simply use "_inherit" and inherit the product.category
model. This gives access to all the functions and fields
of product.category including the complete_name field
and computes the name from my custom model data. I was
able to remove my _name_get_func and just use the inherited
function.
The final model definition is below. Once this
update was complete I was able to add a "complete_name" field
to my view and the results were as desired!
class cb_public_catalog_category( models.Model ):
_name = "cb.public.catalog.category"
_inherit = 'product.category'
_parent_store = True
parent_left = newFields.Integer( index = True )
parent_right = newFields.Integer( index = True )
name = newFields.Char( string = 'Category Name' )
child_id = newFields.One2many( 'catalog.category', 'parent_id', string = 'Child Categories' )

appending to rails field value

I need to find and update a number of records in a Rails 3.2, Ruby 2 application. The following code successfully finds the records I want. What I need to do though is add " x" (including the space) to the email address of every user and I can't figure out how to do it.
This finds the records
User.joins(:account)
.where("users.account_id NOT IN (?)", [1955, 3083, 3869])
.where("accounts.partner_id IN (?)", [23,50])
.where("users.staff = '0'")
.where("users.admin = '0'")
.where("users.api_user = '0'")
.where("users.partner_id is null")
.update_all(email: :email.to_s << " X")
but it's the last line I'm having problems with. Is this possible, or do I need to find the records another way?
The update_all method updates a collection of records, but unless you write your own SQL expression, it can only set one value. For example, if you wanted to overwrite all the email addresses with "X", you could do it easily:
User.joins(:account)
.where("users.account_id NOT IN (?)", [1955, 3083, 3869])
# ...other scopes...
.update_all(email: "X")
In your case, what you really need to do is make individual updates to all these records. One way to do it is to find the records, then loop over them and update them one at a time:
users_to_update = User.joins(:account)
.where("users.account_id NOT IN (?)", [1955, 3083, 3869])
.where("accounts.partner_id IN (?)", [23,50])
.where("users.staff = '0'")
.where("users.admin = '0'")
.where("users.api_user = '0'")
.where("users.partner_id is null")
users_to_update.each do |user|
user.update_attribute(:email, "#{user.email} X")
end
Another solution would be to use a SQL expression with update_all, as in Zoran's answer.
Try writing the last line like so:
.update_all("email = email || ' X'")
This uses SQL's string concatenation operator to append the X to the end of the emails.
Hope that helps!

Counting associations in ActiveRecord

I have two models, User and Group, where groups contain many users. If I want to count the number of users in each group using a single query, I can use the following SQL:
select id, (select count(1) from users where group_id = groups.id) from groups
Is it possible to do this efficiently with ActiveRecord?
To be clear, this query will list all group ids, along with the number of users in each group.
You can use either to get count
using associations
group = Group.find(1) #find group with id = 1
group.users.count # count users whose group_id = 1 calls db everytime
or
group.users.size # get size from cache if group.users loaded
or directly
User.where(:group_id=>1).count
count helper fires a count(*) query on the database with specified conditions
check more options at
http://apidock.com/rails/ActiveRecord/Calculations/count
also I recommend you to go through rails guides
I found an efficient solution using a join:
Group.all(
:select => "groups.id, count(u.group_id) as users_count",
:joins => "LEFT OUTER JOIN users u ON u.group_id = groups.id",
:group => "groups.id"
)
First solution is simply translate your query to ActiveRecord and use the subquery:
subquery = User.where("users.group_id = groups.id").select('count(1)')
groups_with_count = Group.select(:id, "(#{subquery.to_sql}) as users_count")
Or use a sql grouping for the same result
groups_with_count = Group.joins(:users).select(:id, 'count(users.id) as users_count').group(:id)
in both case you can now have the result in ONE query with MINIMAL raw sql:
groups_with_count.each { |group| puts "#{group.id} => #{group.users_count}" }
Additional note
You can write the first subquery as subquery = User.via(:group).select('count(1)') which is more simple and maintainable imo, by using the following helper.
I've used this code on several projects in order to write nicer subquery:
class ApplicationRecord < ActiveRecord::Base
# transform Raw sql that references an association such as: Shift.where('shifts.id = checkins.shift_id')
# into a simpler version Shift.via(:checkin) if shift have the checkin relationship
# No support for polymorphic association
# Basic support for "through" reflection (using join)
def via(name)
association = reflect_on_association(name)
raise ArgumentError, "#{name} is not a valid association of #{self.class.name}" unless association
raise NotImplementedError if association.polymorphic?
join_keys = association.join_keys
table_column = arel_table[join_keys.foreign_key]
association_column = Arel::Table.new(association.table_name)[join_keys.key]
if association.through_reflection?
through_association = association.through_reflection
table_column = Arel::Table.new(through_association.table_name)[join_keys.foreign_key]
joins(through_association.name).where(table_column.eq(association_column))
else
where(table_column.eq(association_column))
end
end
end

Resources