Odoo Help


This community 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.


How to onchange parent value field of One2many to update column in child tree view?

Mihai Marius
on 5/27/14, 2:29 AM 2,928 views


I have a costum module with the following 2 models:

class parent_model(osv.osv):
    """parent model"""
    _name = "parent_model"
    _description = "parent model description"
    _columns = {

        'partner_id': fields.many2one('res.partner', 'Partener'),
        'total_amount': fields.float('Total amount cashed', digits=(12,2)),
        'line_ids': fields.one2many('child.model', 'operation_id', 'Reconcile'),
        'reconciliere': fields.selection([('1', 'Manual'),('2', 'Automata')], 'Modalitate reconciliere', help="Selectati modalitatea de reconciliere automat pentru alocarea sumelor in mod automat, respectiv manual pentru alocare manuala", required=True),
        'amount_adv': fields.float('Payment in advance', digits=(12,2))

class child_model(osv.osv):
    """child model"""
    _name = "child model"
    _description = "child model description"
    _columns = {

        'partner_id': fields.many2one('res.partner', 'Partener', required=True, readonly=True),
        'operation_id': fields.many2one('parent.model', 'Bank account operation', readonly=True),
        'invoice_id': fields.many2one('invoice.trx', 'Invoice', readonly=True),
        'sold_initial': fields.float('Initial sold of the invoice', digits=(12,2), readonly=True),
        'sold_open': fields.float('Open transaction sold', digits=(12,2), readonly=True),
        'val_trx': fields.float('Amount to be cashed paid', digits=(12,2)),
        'sold_final': fields.float('Final sold', digits=(12,2), readonly=True),
        'val_all': fields.boolean('Reconcile entire value')

class invoice_trx(osv.osv):
    """Invoice model"""
    _name = "invoice_trx"
    _description = "Invoices model description"
    _columns = {

        'partner_id': fields.many2one('res.partner', 'Partener'),
        'sold_initial': fields.float('Initial sold of the invoice', digits=(12,2), readonly=True),
        'sold_open': fields.float('Open transaction sold', digits=(12,2), readonly=True),
        'val_trx': fields.float('Amount to be cashed paid', digits=(12,2)),
        'sold_final': fields.float('Final sold', digits=(12,2), readonly=True)

I have an onchange method to populate the one2many fields with the invoices of the selected partner_id:

    def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
        res = {'value':{}}
        invoice_lines = []
        line_pool = self.pool.get('child.model')
        if not partner_id:
            return default       
        line_ids = ids and line_pool.search(cr, uid, [('operation_id', '=', ids[0])]) or False
        if line_ids:
            line_pool.unlink(cr, uid, line_ids)
        invoice_ids = self.pool.get('invoice.trx').search(cr, uid, [('partner_id','=', partner_id)])
        for p in self.pool.get('invoice.trx').browse(cr, uid, invoice_ids):
            rs = {
                'partner_id': p.partner_id.id,
                'sold_initial': p.sold_initial,
                'sold_open': p.sold_final,
                'val_all': False,
                'val_trx': 0.0,
                'sold_final': p.sold_final,

            invoice_lines.append((0, 0, rs))
            res['value']['line_ids'] = invoice_lines
        return res

This onchange method is working ok.

The problem is that I'm not able to change this method, so if the 'total_amount' field in parent model !=0 than split that value to child lines in column val_trx.

The split of the values have to consider the value of sold_open. Eg: total_amount=1000 EUR and we have 2 invoices with sold_open1= 500 and sold_open2= 700 than val_trx1=500 and val_trx2=500. The rest of 200 EUR will be updated in amount_adv field of the parent model.

Can you please help?

Many thanks


Mihai Marius
On 5/27/14, 11:05 AM

Looking into account_voucher to the following code will make things easy to understand.

Just place the code here in case others will face the same question.

Many thanks!


def recompute_voucher_lines(self, cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, date, context=None):
    Returns a dict that contains new values and context

    @param partner_id: latest value from user input for field partner_id
    @param args: other arguments
    @param context: context arguments, like lang, time zone

    @return: Returns a dict which contains new values, and context
    def _remove_noise_in_o2m():
        """if the line is partially reconciled, then we must pay attention to display it only once and
            in the good o2m.
            This function returns True if the line is considered as noise and should not be displayed
        if line.reconcile_partial_id:
            if currency_id == line.currency_id.id:
                if line.amount_residual_currency <= 0:
                    return True
                if line.amount_residual <= 0:
                    return True
        return False

    if context is None:
        context = {}
    context_multi_currency = context.copy()

    currency_pool = self.pool.get('res.currency')
    move_line_pool = self.pool.get('account.move.line')
    partner_pool = self.pool.get('res.partner')
    journal_pool = self.pool.get('account.journal')
    line_pool = self.pool.get('account.voucher.line')

    #set default values
    default = {
        'value': {'line_dr_ids': [] ,'line_cr_ids': [] ,'pre_line': False,},

    #drop existing lines
    line_ids = ids and line_pool.search(cr, uid, [('voucher_id', '=', ids[0])]) or False
    if line_ids:
        line_pool.unlink(cr, uid, line_ids)

    if not partner_id or not journal_id:
        return default

    journal = journal_pool.browse(cr, uid, journal_id, context=context)
    partner = partner_pool.browse(cr, uid, partner_id, context=context)
    currency_id = currency_id or journal.company_id.currency_id.id

    total_credit = 0.0
    total_debit = 0.0
    account_type = None
    if context.get('account_id'):
        account_type = self.pool['account.account'].browse(cr, uid, context['account_id'], context=context).type
    if ttype == 'payment':
        if not account_type:
            account_type = 'payable'
        total_debit = price or 0.0
        total_credit = price or 0.0
        if not account_type:
            account_type = 'receivable'

    if not context.get('move_line_ids', False):
        ids = move_line_pool.search(cr, uid, [('state','=','valid'), ('account_id.type', '=', account_type), ('reconcile_id', '=', False), ('partner_id', '=', partner_id)], context=context)
        ids = context['move_line_ids']
    invoice_id = context.get('invoice_id', False)
    company_currency = journal.company_id.currency_id.id
    move_lines_found = []

    #order the lines by most old first
    account_move_lines = move_line_pool.browse(cr, uid, ids, context=context)

    #compute the total debit/credit and look for a matching open amount or invoice
    for line in account_move_lines:
        if _remove_noise_in_o2m():

        if invoice_id:
            if line.invoice.id == invoice_id:
                #if the invoice linked to the voucher line is equal to the invoice_id in context
                #then we assign the amount on that line, whatever the other voucher lines
        elif currency_id == company_currency:
            #otherwise treatments is the same but with other field names
            if line.amount_residual == price:
                #if the amount residual is equal the amount voucher, we assign it to that voucher
                #line, whatever the other voucher lines
            #otherwise we will split the voucher amount on each line (by most old first)
            total_credit += line.credit or 0.0
            total_debit += line.debit or 0.0
        elif currency_id == line.currency_id.id:
            if line.amount_residual_currency == price:
            total_credit += line.credit and line.amount_currency or 0.0
            total_debit += line.debit and line.amount_currency or 0.0

    remaining_amount = price
    #voucher line creation
    for line in account_move_lines:

        if _remove_noise_in_o2m():

        if line.currency_id and currency_id == line.currency_id.id:
            amount_original = abs(line.amount_currency)
            amount_unreconciled = abs(line.amount_residual_currency)
            #always use the amount booked in the company currency as the basis of the conversion into the voucher currency
            amount_original = currency_pool.compute(cr, uid, company_currency, currency_id, line.credit or line.debit or 0.0, context=context_multi_currency)
            amount_unreconciled = currency_pool.compute(cr, uid, company_currency, currency_id, abs(line.amount_residual), context=context_multi_currency)
        line_currency_id = line.currency_id and line.currency_id.id or company_currency
        rs = {
            'type': line.credit and 'dr' or 'cr',
            'amount_original': amount_original,
            'amount': (line.id in move_lines_found) and min(abs(remaining_amount), amount_unreconciled) or 0.0,
            'amount_unreconciled': amount_unreconciled,
            'currency_id': line_currency_id,
        remaining_amount -= rs['amount']
        #in case a corresponding move_line hasn't been found, we now try to assign the voucher amount
        #on existing invoices: we split voucher amount by most old first, but only for lines in the same currency
        if not move_lines_found:
            if currency_id == line_currency_id:
                if line.credit:
                    amount = min(amount_unreconciled, abs(total_debit))
                    rs['amount'] = amount
                    total_debit -= amount
                    amount = min(amount_unreconciled, abs(total_credit))
                    rs['amount'] = amount
                    total_credit -= amount

        if rs['amount_unreconciled'] == rs['amount']:
            rs['reconcile'] = True

        if rs['type'] == 'cr':

        if len(default['value']['line_cr_ids']) > 0:
            default['value']['pre_line'] = 1
        elif len(default['value']['line_dr_ids']) > 0:
            default['value']['pre_line'] = 1
        default['value']['writeoff_amount'] = self._compute_writeoff_amount(cr, uid, default['value']['line_dr_ids'], default['value']['line_cr_ids'], price, ttype)
    return default

Fekete Mihai
On 7/22/14, 1:26 AM

You can watch the Romanian developments on :


Your Answer

Please try to give a substantial answer. If you wanted to comment on the question or answer, just use the commenting tool. Please remember that you can always revise your answers - no need to answer the same question twice. Also, please don't forget to vote - it really helps to select the best questions and answers!

About This Community

This community is for professionals and enthusiasts of our products and services. Read Guidelines

Question tools

1 follower(s)


Asked: 5/27/14, 2:29 AM
Seen: 2928 times
Last updated: 3/16/15, 8:10 AM