【问题标题】:How to onchange parent value field of One2many to update column in child tree view?如何更改 One2many 的父值字段以更新子树视图中的列?
【发布时间】:2025-11-27 20:25:02
【问题描述】:

我有一个包含以下类的自定义模块:

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', 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)
        }

我有一个 onchange 方法用所选合作伙伴 ID 的发票填充 one2many 字段:

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))
        invoice_lines.reverse()                
        res['value']['line_ids'] = invoice_lines
    return res

这个 onchange 方法工作正常。

问题是我无法更改此方法,因此如果父模型中的“total_amount”字段!=0,则将该值拆分为 val_trx 列中的子行。

值的拆分要考虑sold_open的值。例如:total_amount=1000 欧元,我们有 2 张发票,其中 sold_open1= 500 和 sold_open2= 700,而不是 val_trx1=500 和 val_trx2=500。剩余的 200 欧元将在父模型的 amount_adv 字段中更新。

你能帮忙吗?

非常感谢

【问题讨论】:

    标签: openerp


    【解决方案1】:

    检查帐户凭证模块,您将清楚地知道如何做。

    如果您选择合作伙伴,它将自动填充所有待处理的合作伙伴

    查看account_voucher.py中的函数

    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
                else:
                    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
        else:
            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)
        else:
            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
        ids.reverse()
        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():
                continue
    
            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
                    move_lines_found.append(line.id)
            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
                    move_lines_found.append(line.id)
                    break
                #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:
                    move_lines_found.append(line.id)
                    break
                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():
                continue
    
            if line.currency_id and currency_id == line.currency_id.id:
                amount_original = abs(line.amount_currency)
                amount_unreconciled = abs(line.amount_residual_currency)
            else:
                #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 = {
                'name':line.move_id.name,
                'type': line.credit and 'dr' or 'cr',
                'move_line_id':line.id,
                'account_id':line.account_id.id,
                'amount_original': amount_original,
                'amount': (line.id in move_lines_found) and min(abs(remaining_amount), amount_unreconciled) or 0.0,
                'date_original':line.date,
                'date_due':line.date_maturity,
                '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
                    else:
                        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':
                default['value']['line_cr_ids'].append(rs)
            else:
                default['value']['line_dr_ids'].append(rs)
    
            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
    

    【讨论】:

    • 感谢重播。我做了,但仍然有问题。例如,我设法更改,但如果所选的 partner_id 有 3 行,它只返回 1 或只更改了一个。我很清楚我做错了什么,因为我不知道该怎么做。可能是我难以完全理解的 line.id 和 move_line_found 。如果你有时间请写几行。再次感谢。
    最近更新 更多