How to configure flexible access rules - odoo

BASIC PROBLEM TO SOLVE
I am trying to configure flexible rules using user groups and ir.rules in Odoo 10. Basically I want to give users access only to certain records, based on specific values in columns. There are some records that I want to restrict - regardless if it was allowed in another group based on different criteria.
Here are some simplified examples of what I want to accomplish:
1.
(country = 'USA'
or
office= London)
and
vip = false
2.
(country = 'uk'
or
country = 'netherlands'
or
office = London)
etc
To make the access rules flexible, I want to create the following groups:
group_country_usa
group_country_germany
group_country_uk
group_country_netherlands
etc
group_office_london
group_office_new_york
group_office_paris
group_office_tokyo
group_office_st_petersburg
etc
group_no_vips
I have corresponding ir.rules records for each group above:
[('country','=', 'usa')]
etc
[('office','=', 'amsterdam')]
etc
[('vip','=', False)]
Per my testing I do not believe I can do the the above with only using separate ir.rules records.
Is there a way I can accomplish my objective?
I hope the above makes sense and that someone can hint me in the right direction.

Assuming there's a global rule allowing access to all records, I see no problem with using your described ir.rule and res.groups configuration. However, group rules are additive, meaning it is not possible to join ir.rule domains with and like in your example #1. See official docs for more information.

Related

How to Implement Contains logic in Oracle SQL for Multiple values

Scenario
Each Online User has a set of skills assigned to him, Based on their skills they need to be mapped to a specific team, For which I need to check all the skills and if a certain set of skills are present assign him a team.
My Implementation till now
I used a CASE statement to check skills and if they match exactly give the name to that entry.
Problem I am facing
If the user is assigned more skills to help other teams then these conditions fails and it goes to ELSE condition.
So I was thinking if it is possible to include contains logic that will check if certain skills are present for the user then assign him a team according to that, And it is also possible a User is part of two teams, So if two skill set matches then two teams should be assigned to him, In CASE statement it is
not possible to achieve this.
I have gone through REGEXP, but I guess that also will not help.
Let me know if more clarity is needed.

Tableau count values after a GROUP BY in SQL

I'm using Tableau to show some schools data.
My data structure gives a table that has all de school classes in the country. The thing is I need to count, for example, how many schools has Primary and Preschool (both).
A simplified version of my table should look like this:
In that table, if I want to know the number needed in the example, the result should be 1, because in only one school exists both Primary and Preschool.
I want to have a multiple filter in Tableau that gives me that information.
I was thinking in the SQL query that should be made and it needs a GROUP BY statement. An example of the consult is here in a fiddle: Database example query
In the SQL query I group by id all the schools that meet either one of the conditions inside de IN(...) and then count how many of them meet both (c=2).
Is there a way to do something like this in Tableau? Either using groups or sets, using advanced filters or programming a RAW SQL calculated fiel?
Thanks!
Dubafek
PS: I add a link to my question in Tableu's forum because you can download my testing workbook there: Tableu's forum question
I've solved the issue using LODs (specifically INCLUDE and EXCLUDE statements).
I created two calculated fields having the aggregation I needed:
Then I made a calculated field that leaves only the School IDs that matches the number of types they have (according with the filtering) with the number of types selected in the multiple filter (both of the fields shown above):
Finally, I used COUNTD([Condition]) to display the amounts of schools matching with at least the School types selected.
Hope this helps someone with similar issue.
PS: If someone wants the Workbook with the solution I've uploaded it in an answer in the Tableau Forum

SQL complicated query with joins

I have problem with one query.
Let me explain what I want:
For the sake of bravity let's say that I have three tables:
-Offers
-Ratings
-Users
Now what I want to do is to create SQL query:
I want Offers to be listed with all its fields and additional temporary column that IS NOT storred anywhere called AverageUserScore.
This AverageUserScore is product of grabbing all offers, belonging to particular user and then grabbing all ratings belonging to these offers and then evaluating those ratings average - this average score is AverageUserScore.
To explain it even further, I need this query for Ruby on Rails application. In the browser inside application you can see all offers of other users , with AverageUserScore at the very end, as the last column.
Associations:
Offer has many ratings
Offer belongs to user
Rating belongs to offer
User has many offers
Assumptions made:
You actually have a numeric column (of any type that SQL's AVG is fine with) in your Rating model. I'm using a column ratings.rating in my examples.
AverageUserScore is unconventional, so average_user_score is better.
You don't mind not getting users that have no offers: average rating is not clearly defined for them anyway.
You don't deviate from Rails' conventions far enough to have a primary key other than id.
Displaying offers for each user is a straightforward task: in a loop of #users.each do |user|, you can do user.offers.each do |offer| and be set. The only problem here is that it will execute a separate query for every user. Not good.
The "fetching offers" part is a standard N+1 counter seen even in the guides.
#users = User.includes(:offers).all
The interesting part here is only getting the averages.
For that I'm going to use Arel. It's already part of Rails, ActiveRecord is built on top of it, so you don't need to install anything extra.
You should be able to do a join like this:
User.joins(offers: :ratings)
And this won't get you anything interesting (apart from filtering users that have no offers). Inside though, you'll get a huge set of every rating joined with its corresponding offer and that offer's user. Since we're taking averages per-user we need to group by users.id, effectively making one entry per one users.id value. That is, one per user. A list of users, yes!
Let's stop for a second and make some assignments to make Arel-related code prettier. In fact, we only need two:
users = User.arel_table
ratings = Rating.arel_table
Okay. So. We need to get a list of users (all fields), and for each user fetch an average value seen on his offers' ratings' rating field. So let's compose these SQL expressions:
# users.*
user_fields = users[Arel.star] # Arel.star is a portable SQL "wildcard"
# AVG(ratings.rating) AS average_user_score
average_user_score = ratings[:rating].average.as('average_user_score')
All set. Ready for the final query:
User.includes(:offers) # N+1 counteraction
.joins(offers: :ratings) # dat join
.select(user_fields, average_user_score) # fields we need
.group(users[:id]) # grouping to only get one row per user

Filtering user access based on tabled responses

I am building a "Survey" type application. The user answers a set of questions with pre-vetted answers.
Question: Where do you live?
Answers: England, Finland, Spain, France, Monrovia
The answers in this case would be in a DropDownList.
Once the user has completed the basic responses (location, age, sex etc) I would like to be able to prevent them accessing the rest of the survey based on their answers.
So for example, if they live anywhere but England I want to direct them to a page which says "Thanks, but Monrovian's can't complete this survey". I need my filtering to be user configurable (Table based) and I need to be able to have ANDs and ORs.
So one filter being the user MUST earn 100k+ a year.
Another being they must either live in Spain, or be female AND like model trains - "100k+ && (Spain || (Female && Trains))"
I would usually use Enums and bitmasking for this, but as my country list is 200+ items long, I can't think of a sensible way to store the filtering.
Hopefully I have made some sense and someone has a decent solution :)
I don't know if I can answer your question completely, but I'll try...
So, we have a bunch of Views that are only visible to the user if she previously chose some answers, like, she will see view#3 if she is older that 30, and view#4 if she is younger than 30 AND from China, and view#5 if she is older than 40 AND from Spain OR Italy, and so on...I want also to introduce the notion of **step**, and for each step we could have 1, 2, or more corresponding views. Each view should have a set of rules (like the ones above) that define if it is displayed or not.
How to create these rules? These rules could be simple instances of a Filter class/interface that, when asked, should return true/false. Like this:
interface Filter {
boolean apply();
}
Then you can create Filters like 'older than 30', 'from Spain', whatever. Remember that each view is configured with a set of rules (Filters) so it can answer yes/no if asked if it can display itself.
Next, how to apply these filters?
We could have a controller object that only knows about **steps** (each step can have one or more corresponding views, as I said), and, after the user pressed **next** at the current step, it should collect the answers and apply them against the rules attached to each view. Like, take the answers from step one, and apply them to all views from step two, and see which one matches (returns true). For example, at step two, you can have two separate views, one for young people, other for old people, and you apply the rules from each view to decide if you show the old or young view.
I could give you one code example, and you could also do research on your own, since I know nothing about your technical environment. I have used Google Guava's predicates on a similar problem and here it is: suppose we are dealing with Witch objects, and each of them has name(string), age(int) and spells(collection) attributes. If I have a list of witches and I need to sort them based on specific criteria, I can do:
// first I want to sort witches by age(natural ordering) then by spells,
// and then by name lexicographically
Ordering.natural()
.compound(new BySpellsWitchOrdering())
.compound(new ByNameWitchOrdering())
.sortedCopy(witchList);
The above line of code is going to take the witch list and return a list of sorted witches according to the criteria. Your situation is pretty similar.
Next, how to create the answers? For each view(page), you have possible answers, like, for view#1, you can have : age, sex, race, country. You can construct some answers, in the form of strings, ints, enums, and pass them to the controller, which in turn is going to apply them to each view corresponding to the next step.
As for how to store the rules in the database, as an example, you could have a column defining rule name (like, OLDER THAN) and one column for value, say, 30. Again, I do not know that much about your environment, and it is a really general issue, so I will stop here...

How to make a record belong to all options of a field

I have a database of records called "services", each service has about 30 attributes and each service has an associated country as an attribute. The problem is some services are offered to ALL countries. On the front end of this database I have a drop-down menu that selects all the records based on a country filter. How would I be able to include the service offered to ALL countries without needing to duplicate the record for the service and replacing the country name.
P.S. For those interested in the actual implementation, I am using Drupal nodes to represent each service and a view with exposed filters to select the country. But if I have to do some SQL work then I can do that too.
Your WHERE clause would follow this pattern
WHERE (CounrtyID = PassedVariable OR PassedVariable = 'all')