I need to understand the eval attribute in the following code in the product_demo.xml in product module in Odoo:
"record id="product_product_4_product_template" model="product.template">
field name="attribute_line_ids" eval="[(6,0,[ref('product.product_attribute_line_1'), ref('product.product_attribute_line_2'), ref('product.product_attribute_line_3')])]"/>
</record>"
I understand that the attribute_line_ids value is being set here. I also understand that the values inside the 'ref' refers to XML ids which would, in short, return the model-'product.attribute.line associate with the XML id.
I really don't understand what each of the values in the eval attribute mean and what changes would it do on view level and db level. I have referred to many odoo documentation but none could provide clarity.
This adds a bunch of values to a Many2many field called attribute_line_ids. Odoo has a special syntax for setting values on Many2many fields. This syntax is described here and is used in the code you asked about.
Basically, to modify a many2many relation you use a three-element tuple. The first element of the tuple is a numeric command, and two other elements are values - their exact function depend on the command.
There are six numeric commands:
0 - creates a new object and adds it to the Many2many relation
1 - updates an object that already exists on the relation
2 - deletes an object that already exists on the relation
3 - removes an existing object from the relation, without deleting it
4 - adds an existing object to the relation
5 - removes all objects from the relation, without deleting them
6 - replaces pervious objects existing on the relation with a new set of objects
The relevant part of your code look like this:
(6,0,[ref('product.product_attribute_line_1'), ref('product.product_attribute_line_2'), ref('product.product_attribute_line_3')])
It's a three-element tuple (which is expected, since the code sets values on a Many2many relation):
The first element is the command. "6" means elements previously existing in the relation (if any) will be replaced with elements which ids are passed as the third element of the tuple.
The second argument is irrelevant. It has a role with other commands, but when used with "6" it can be anything (personally I would use None to better reflect this).
The third element is a list of ids. Since the first element is "6", this signifies the objects that will be put into the relation, replacing whatever was previously there.
Related
Link to example that only changes first occurance: https://www.db-fiddle.com/f/wd6jJmDxGp3W1x6ptrEjB4/0
Example Data:
id (int)
application_questions (JSONB)
1
[{"id":1,"type":"single-select"},{"id":2,"type":"multi-select-check"}, {"id":3,"type":"single-select"},{"id":4,"type":"multi-select-check"}, {"id":5,"type":"single-select"},{"id":6,"type":"multi-select-check"}]
2
[{"id":1,"type":"single-select"},{"id":2,"type":"multi-select-check"}, {"id":3,"type":"single-select"},{"id":4,"type":"multi-select-check"}]
3
[{"id":1,"type":"single-select"},{"id":2,"type":"multi-select-check"}, {"id":3,"type":"single-select"},{"id":4,"type":"multi-select-check"}]
I have a JSONB column where each record is an array of objects. Each object has the key type.
What I want to do is update each type if it matches a condition. For example if type is multi-select-check then change it to multi-select-combo, but leave the types that are not multi-select-check unchanged.
What I have found is that it is possible to change the first occurrence of type C but the others in that same list are ignored (see my db-fiddle example).
Please enlighten me.
The following code gets a list of entities in bulk by their key names:
key_names = [a, b, c, d, e]
result = models.SomeModel.get_by_key_name(key_names)
The question is:
Can we safely assume that the order of the entities in the returned list is always the same as the order of keys in the input list (key_names)?
From Class Methods (emphasis mine):
Model.get_by_key_name (key_names, parent=None)
...
If key_names consists of a single key name, this method returns the
model instance associated with the name if the name exists in the
Datastore, otherwise None. If key_names is a list, the return
value is a corresponding list of model instances, with None
values where no entity exists for a given key name.
I considered that a confirmation and I did make that assumption in my code At least so far I didn't encounter any error or other hint/indication that the assumption would somehow be incorrect.
I have two view objects in Oracle ADF.
LineVO represents order lines -- with one line per product.
Products are differentiated by several attributes... say "model" and "color". So, VO #1 contains a row for each model/color combination.
ModelVO represents a model-level summary of the lines.
Both VOs have a "quantity" field (an Integer).
There is a ViewLink between them and each has a row accessor to the other.
I want to achieve two-way coordination between these two view objects, such that:
When a user queries data, ModelVO.Quantity equals the sum of LineVO.Quantity, for the associated rows
When a user updates any LineVO.Quantity, the ModelVO.Quantity is immediately updated to reflect the new total
When a user updates a ModelVO.Quantity, the quantity is spread among the associated LineVO rows (according to complex business logic which I hope is not relevant here).
I have tried many different ways to do this and cannot get it perfect.
Right now, I am working on variations where ModelVO.Quantity is set to a Groovy expression "LineVO.sum('Quantity')". Unfortunately, everything I try either has the summing from LineVO->ModelVO working or the spreading from ModelVO->LineVO working, but never both at the same time.
Can someone suggest a way to do this? I want to do it in the model layer (either a EO or VO or combination).
Nevermind.. it turns out to be simple:
ModelVO.Quantity must be set to a Groovy "LineVO.sum('Quantity')" and it must have a recalcExpression set to a method where I can control things so it only recalculates when I am changing a LineVO.Quantity value.
The reason my approach didn't work initially was because, when the user updated a LineVO.Quantity value and I wanted to recalculate, I was getting the ModelVO row by lineVORow.getModelVO()... i.e., via a view accessor.
Apparently, that returns some sort of internal copy of the row and not the actual row.
When I got the parent row via the applicationModule.getModelVO().getCurrentRow(), the whole thing works perfectly.
I've posted another question about why accessing the row via the view accessor did not work. That part is still a mystery to me.
What I want to do is trigger an action when one of the fields on my field collection is changed to a certain value. For example, my 'campaign' node has a field collection with a field called 'status' This status is a list containing 3 options; 'onboard', 'live', or 'dead'. When the field on a campaign node field collection is set to 'live' I want to trigger an action.
So I start by saying:
Events: After node is updated
Conditions: This is the bit I am struggling to work out as I cannot do a data comparison with this particular field.
Action: send email
How can I achieve this?
You may get it to work by using an approach similar to what is mentioned in comment # 4 of issue # 1315566, i.e.:
Create an "entity has field" condition on your Rule.
For the "Data Selector," select the entity that contains the field (in my case, a node). For the "Field" value, select the machine name of the field collection in question.
Go to your action. Using the "Data Selector" mode, you should be able to drill down through the entity in question to all the values contained within the field collection. In my case, the end result is "node:field-enrollee:field-school-district:0:tid"
In your case you try to do what is mentioned in step 3 above as a Rules Condition (instead of a Rules Action). So add a Rules Condition "Entity has field" (prior to being able to use it anywhere later on in your rule), which refers to your field collection field.
For way more details about this, refer to "How to iterate over all field collection items in the Rules module?" (which also includes a rule in export format you may want to experiment with, if you only adapt some machine names of the used fields).
Quick Question. In the below code, you can see that the for loop (which takes all of the records in newTimecards and puts them as a variable called timecard) and adds the Resource_c to the resourceIds set. I'm confused about how this object is considered an ID data type. When an object is made in Salesforce does it automatically have an ID made, so that it knows Resource_c ID can be added to a set? Note that within the Resource_c Object there is also a field called Resource_ID_c. Resource_c within Timecard_c is a Master-Detail data type. Resource_c is the parent of Timecard_c.
Now that I think about it, resourceIds.add(timecard.Resource_c), does that reference the relationship between the two objects and then searches through Resource_c and adds the ID field Resource_ID_c automactically since it's a unique field?
Thanks for your help.
public class TimecardManager {
public class TimecardException extends Exception {}
public static void handleTimecardChange(List<Timecard__c> oldTimecards,
List<Timecard__c> newTimecards) {
Set<ID> resourceIds = new Set<ID>();
for (Timecard__c timecard : newTimecards) {
resourceIds.add(timecard.Resource__c);
}
Every object instance (and that means EVERY, including factory ones) has a unique organization level ID, whose field name is always Id, is covered by Apex type ID and is a case-sensitive string of 15 characters that also has an 18 character case-insensitive representation. The first three characters are object prefix code (e.g. 500 for a Case) so all instances of the same object share the same prefix. You see these values all across SF (for example in https://na1.salesforce.com/02s7000000BW59L the 02s7000000BW59L in the URL is the ID). When an instance of the object is created using INSERT DML operation, the salesforce automatically assigns unique value based on the prefix and the next available transactional sub ID, it all happens transparently to you.
This is not to be confused with object Name field which is a field you define when you create an object and which can be auto-incremented and so on (e.g. MYOBJ-{00000}) and which can have more meaning to a user than a cryptic ID
When you create a lookup or master-detail relationship it is ID that is being used to link the two instances, not the Name. In the above example Resource__c seems to be that lookup field and it contains Id value of row's master.
What the code does is it enumerates all resources used in timelines and builds a set of their IDs, the purpose of which is most probably to be used via WHERE Id IN :resourceIds clause to load resource details from master table.
mmix's answer is a great overview to what an ID is and where it comes from. To answer what I think is your specific question:
Any time there is a reference from one object to another (like here, between Timecard_c and Resource_c), the field representing the reference will be an ID. So, the for loop that calls resourceIds.add(timecard.Resource__c) is just building up your set of ID's (those 15-character strings). The timecard.Resource__c doesn't look through the Resource__c table to find the ID, timecard.Resource__c is the ID.