Odoo Help


Access not yet persisted timesheet entries in @api.onchange handler to propose a better 'date_from' and to do overlap checking

Renzo Meister
on 10/1/15, 9:08 AM 1,073 views

We are porting some code to v8. For this we are rewriting our old on_change_xxx handlers with the new @api.onchange methods.

In the HR module we'd like to:

1. Set the 'date_from' value of a new entry to the latest time of all entries of the current day.

2. Check for overlapping time-entries dynamically (not when finally writing them).

For this to achieve we need to be able to access both, entries in the DB and entries in the 'cache' e.g. entries not yet persisted to the DB, within the @api.onchange decorated method. Accessing the DB is no problem. But how can we access all edited/added lines which have not yet been persited (no write done)?

PS: With v7, the on change handlers have been registered in the views and where passed the correct model/cache. E.g. on_change="on_change_hours(hour_from, hour_to, parent.timesheet_ids, date)"...

To make the problem clear here is a screenshot and some code:


During ONE edit session, the user adds these three entries. We want to be able to check for overlapping entries during editing and NOT when saving. So we like to report an error to the user, that there are overlapping lines (line 1 and line2).

We tried the following code:

 @api.onchange('date', 'hour_from', 'hour_to')
    def on_change_hour_values(self):
        # self._origin contains the analytic_timesheet which is being changed right now
        # find the current timesheet and get all entries for this timesheet
        analytic_timesheets = self._origin.sheet_id.timesheet_ids

      timesheets_to_check = []

        for entry in analytic_timesheets:
     timesheet_data = {}

            if entry == self._origin:
                # this is the currently changeing line. Don't take the DB values but the changed ones.
                timesheet_data['hour_from'] = self.hour_from
                timesheet_data['hour_to'] = self.hour_to
                timesheet_data['date'] = self.date
                timesheet_data['unit_amount'] = self.unit_amount
                timesheet_data['hour_from'] = entry.hour_from
                timesheet_data['hour_to'] = entry.hour_to
                timesheet_data['date'] = entry.date
                timesheet_data['unit_amount'] = entry.unit_amount


but it does not behave as expected.

If a user adds multiple new lines during one edit sessions, these entries can not be accessed.

So the question is: In the screenshot below, how can we access the values from the three entries during editing, just when the onchange handler fires?




| 6 5 7
Tbilisi, Georgia
On 10/1/15, 9:54 AM

Normally you have NOT to carry about cached/written versions. The recordset you get inside the onchange function is somewhat different from normal recordset and all the fields are already updated with latest state from cached/written versions. here is example from documentation (I added comments in bold):

@api.onchange('field1', 'field2') # if these fields are changed, call method
def check_change(self):
if self.field1 < self.field2: # Here you read latest values of field1 and field2, as it's in UIs self.field3 = True # Here you set field3 to True, but it will not be written to database # immediately, but it'll be applied to UI and will be saved later, if user
# will save the edited document.

So, your assumption

Accessing the DB is no problem. But how can we access all edited/added lines which have not yet been persited (no write done)?

is intuitively correct if we think that "self" in the above code is a normal recordset, but as I mentioned there is exception for @api.onchange function and recodset here (the "self" above) is NOT a normal recordset, fields are updated in this recordset according latest versions from UI, and as per my comments in code, if you change fields in the "self" reocordset, they are not immediately persisted to the db, but only if user will actually save changes, as per NOTE from documentation:

onchange methods work on virtual records assignment on these records is not written to the database, just used to know which value to send back to the client

I have updated the question to make the problem clearer.

Jamotion GmbH, Renzo Meister
on 10/1/15, 5:23 PM

I see. fields listed in your @api.onchange are fields in the lines from table yes? and virtual record you get is the one of the single line yes? What if you'll add onchange function not for a line records, but for the main record? I do not know if it'll react to internal changes in lines, but you can try to add @api.onchange('one_to_many_field_name_that_holds_lines_in_the_table') to the parent mode of these lines, this table is a one field from point of view of parent model that holds actually this form view... so what I suggest is to add onchange function for that one2many field instead and check what it gives us...

on 10/2/15, 6:00 AM

Good point! I'm still working on it but it looks promisingly so far.

Jamotion GmbH, Renzo Meister
on 10/2/15, 7:12 PM

I have been able to access all inserted account-lines by adding the onchange listener to the hr_timesheet_sheet as you suggested. To set a hour_to field on the analytic line depending on all the other lines, it is still necessary to have the onchange listener on the line itself. Therefore I needed to make the cache available to the hr_analytic_timesheet's onchange('..') listener. I did this with a separate class responsible for this cache information. Thanks for the hint!

Jamotion GmbH, Renzo Meister
on 10/6/15, 8:48 AM

About This Community

This platform is for beginners and experts willing to share their Odoo knowledge. It's not a forum to discuss ideas, but a knowledge base of questions and their answers.


Odoo Training Center

Access to our E-learning platform and experience all Odoo Apps through learning videos, exercises and Quizz.

Test it now

Question tools

1 follower(s)


Asked: 10/1/15, 9:08 AM
Seen: 1073 times
Last updated: 10/1/15, 5:32 PM