(self)
Handle the cash rounding feature on invoices.

        In some countries, the smallest coins do not exist. For example, in Switzerland, there is no coin for 0.01 CHF.
        For this reason, if invoices are paid in cash, you have to round their total amount to the smallest coin that
        exists in the currency. For the CHF, the smallest coin is 0.05 CHF.

        There are two strategies for the rounding:

        1) Add a line on the invoice for the rounding: The cash rounding line is added as a new invoice line.
        2) Add the rounding in the biggest tax amount: The cash rounding line is added as a new tax line on the tax
        having the biggest balance.
Handle the cash rounding feature on invoices.
Handle the cash rounding feature on invoices .
def _recompute_cash_rounding_lines(self):
        ''' Handle the cash rounding feature on invoices.

        In some countries, the smallest coins do not exist. For example, in Switzerland, there is no coin for 0.01 CHF.
        For this reason, if invoices are paid in cash, you have to round their total amount to the smallest coin that
        exists in the currency. For the CHF, the smallest coin is 0.05 CHF.

        There are two strategies for the rounding:

        1) Add a line on the invoice for the rounding: The cash rounding line is added as a new invoice line.
        2) Add the rounding in the biggest tax amount: The cash rounding line is added as a new tax line on the tax
        having the biggest balance.
        '''
        self.ensure_one()
        in_draft_mode = self != self._origin

        def _compute_cash_rounding(self, total_amount_currency):
            ''' Compute the amount differences due to the cash rounding.
            :param self:                    The current account.move record.
            :param total_amount_currency:   The invoice's total in invoice's currency.
            :return:                        The amount differences both in company's currency & invoice's currency.
            '''
            difference = self.invoice_cash_rounding_id.compute_difference(self.currency_id, total_amount_currency)
            if self.currency_id == self.company_id.currency_id:
                diff_amount_currency = diff_balance = difference
            else:
                diff_amount_currency = difference
                diff_balance = self.currency_id._convert(diff_amount_currency, self.company_id.currency_id, self.company_id, self.date)
            return diff_balance, diff_amount_currency

        def _apply_cash_rounding(self, diff_balance, diff_amount_currency, cash_rounding_line):
            ''' Apply the cash rounding.
            :param self:                    The current account.move record.
            :param diff_balance:            The computed balance to set on the new rounding line.
            :param diff_amount_currency:    The computed amount in invoice's currency to set on the new rounding line.
            :param cash_rounding_line:      The existing cash rounding line.
            :return:                        The newly created rounding line.
            '''
            rounding_line_vals = {
                'debit': diff_balance > 0.0 and diff_balance or 0.0,
                'credit': diff_balance < 0.0 and -diff_balance or 0.0,
                'quantity': 1.0,
                'amount_currency': diff_amount_currency,
                'partner_id': self.partner_id.id,
                'move_id': self.id,
                'currency_id': self.currency_id.id,
                'company_id': self.company_id.id,
                'company_currency_id': self.company_id.currency_id.id,
                'is_rounding_line': True,
                'sequence': 9999,
            }

            if self.invoice_cash_rounding_id.strategy == 'biggest_tax':
                biggest_tax_line = None
                for tax_line in self.line_ids.filtered('tax_repartition_line_id'):
                    if not biggest_tax_line or tax_line.price_subtotal > biggest_tax_line.price_subtotal:
                        biggest_tax_line = tax_line

                # No tax found.
                if not biggest_tax_line:
                    return

                rounding_line_vals.update({
                    'name': _('%s (rounding)', biggest_tax_line.name),
                    'account_id': biggest_tax_line.account_id.id,
                    'tax_repartition_line_id': biggest_tax_line.tax_repartition_line_id.id,
                    'tax_tag_ids': [(6, 0, biggest_tax_line.tax_tag_ids.ids)],
                    'exclude_from_invoice_tab': True,
                })

            elif self.invoice_cash_rounding_id.strategy == 'add_invoice_line':
                if diff_balance > 0.0 and self.invoice_cash_rounding_id.loss_account_id:
                    account_id = self.invoice_cash_rounding_id.loss_account_id.id
                else:
                    account_id = self.invoice_cash_rounding_id.profit_account_id.id
                rounding_line_vals.update({
                    'name': self.invoice_cash_rounding_id.name,
                    'account_id': account_id,
                })

            # Create or update the cash rounding line.
            if cash_rounding_line:
                cash_rounding_line.update({
                    'amount_currency': rounding_line_vals['amount_currency'],
                    'debit': rounding_line_vals['debit'],
                    'credit': rounding_line_vals['credit'],
                    'account_id': rounding_line_vals['account_id'],
                })
            else:
                create_method = in_draft_mode and self.env['account.move.line'].new or self.env['account.move.line'].create
                cash_rounding_line = create_method(rounding_line_vals)

            if in_draft_mode:
                cash_rounding_line.update(cash_rounding_line._get_fields_onchange_balance(force_computation=True))

        existing_cash_rounding_line = self.line_ids.filtered(lambda line: line.is_rounding_line)

        # The cash rounding has been removed.
        if not self.invoice_cash_rounding_id:
            self.line_ids -= existing_cash_rounding_line
            return

        # The cash rounding strategy has changed.
        if self.invoice_cash_rounding_id and existing_cash_rounding_line:
            strategy = self.invoice_cash_rounding_id.strategy
            old_strategy = 'biggest_tax' if existing_cash_rounding_line.tax_line_id else 'add_invoice_line'
            if strategy != old_strategy:
                self.line_ids -= existing_cash_rounding_line
                existing_cash_rounding_line = self.env['account.move.line']

        others_lines = self.line_ids.filtered(lambda line: line.account_id.user_type_id.type not in ('receivable', 'payable'))
        others_lines -= existing_cash_rounding_line
        total_amount_currency = sum(others_lines.mapped('amount_currency'))

        diff_balance, diff_amount_currency = _compute_cash_rounding(self, total_amount_currency)

        # The invoice is already rounded.
        if self.currency_id.is_zero(diff_balance) and self.currency_id.is_zero(diff_amount_currency):
            self.line_ids -= existing_cash_rounding_line
            return

        _apply_cash_rounding(self, diff_balance, diff_amount_currency, existing_cash_rounding_line)
def _recompute_cash_rounding_lines ( self ) : self . ensure_one ( ) in_draft_mode = self != self . _origin def _compute_cash_rounding ( self , total_amount_currency ) : ''' Compute the amount differences due to the cash rounding.
            :param self:                    The current account.move record.
            :param total_amount_currency:   The invoice's total in invoice's currency.
            :return:                        The amount differences both in company's currency & invoice's currency.
            ''' difference = self . invoice_cash_rounding_id . compute_difference ( self . currency_id , total_amount_currency ) if self . currency_id == self . company_id . currency_id : diff_amount_currency = diff_balance = difference else : diff_amount_currency = difference diff_balance = self . currency_id . _convert ( diff_amount_currency , self . company_id . currency_id , self . company_id , self . date ) return diff_balance , diff_amount_currency def _apply_cash_rounding ( self , diff_balance , diff_amount_currency , cash_rounding_line ) : ''' Apply the cash rounding.
            :param self:                    The current account.move record.
            :param diff_balance:            The computed balance to set on the new rounding line.
            :param diff_amount_currency:    The computed amount in invoice's currency to set on the new rounding line.
            :param cash_rounding_line:      The existing cash rounding line.
            :return:                        The newly created rounding line.
            ''' rounding_line_vals = { 'debit' : diff_balance > 0.0 and diff_balance or 0.0 , 'credit' : diff_balance < 0.0 and - diff_balance or 0.0 , 'quantity' : 1.0 , 'amount_currency' : diff_amount_currency , 'partner_id' : self . partner_id . id , 'move_id' : self . id , 'currency_id' : self . currency_id . id , 'company_id' : self . company_id . id , 'company_currency_id' : self . company_id . currency_id . id , 'is_rounding_line' : True , 'sequence' : 9999 , } if self . invoice_cash_rounding_id . strategy == 'biggest_tax' : biggest_tax_line = None for tax_line in self . line_ids . filtered ( 'tax_repartition_line_id' ) : if not biggest_tax_line or tax_line . price_subtotal > biggest_tax_line . price_subtotal : biggest_tax_line = tax_line # No tax found. if not biggest_tax_line : return rounding_line_vals . update ( { 'name' : _ ( '%s (rounding)' , biggest_tax_line . name ) , 'account_id' : biggest_tax_line . account_id . id , 'tax_repartition_line_id' : biggest_tax_line . tax_repartition_line_id . id , 'tax_tag_ids' : [ ( 6 , 0 , biggest_tax_line . tax_tag_ids . ids ) ] , 'exclude_from_invoice_tab' : True , } ) elif self . invoice_cash_rounding_id . strategy == 'add_invoice_line' : if diff_balance > 0.0 and self . invoice_cash_rounding_id . loss_account_id : account_id = self . invoice_cash_rounding_id . loss_account_id . id else : account_id = self . invoice_cash_rounding_id . profit_account_id . id rounding_line_vals . update ( { 'name' : self . invoice_cash_rounding_id . name , 'account_id' : account_id , } ) # Create or update the cash rounding line. if cash_rounding_line : cash_rounding_line . update ( { 'amount_currency' : rounding_line_vals [ 'amount_currency' ] , 'debit' : rounding_line_vals [ 'debit' ] , 'credit' : rounding_line_vals [ 'credit' ] , 'account_id' : rounding_line_vals [ 'account_id' ] , } ) else : create_method = in_draft_mode and self . env [ 'account.move.line' ] . new or self . env [ 'account.move.line' ] . create cash_rounding_line = create_method ( rounding_line_vals ) if in_draft_mode : cash_rounding_line . update ( cash_rounding_line . _get_fields_onchange_balance ( force_computation = True ) ) existing_cash_rounding_line = self . line_ids . filtered ( lambda line : line . is_rounding_line ) # The cash rounding has been removed. if not self . invoice_cash_rounding_id : self . line_ids -= existing_cash_rounding_line return # The cash rounding strategy has changed. if self . invoice_cash_rounding_id and existing_cash_rounding_line : strategy = self . invoice_cash_rounding_id . strategy old_strategy = 'biggest_tax' if existing_cash_rounding_line . tax_line_id else 'add_invoice_line' if strategy != old_strategy : self . line_ids -= existing_cash_rounding_line existing_cash_rounding_line = self . env [ 'account.move.line' ] others_lines = self . line_ids . filtered ( lambda line : line . account_id . user_type_id . type not in ( 'receivable' , 'payable' ) ) others_lines -= existing_cash_rounding_line total_amount_currency = sum ( others_lines . mapped ( 'amount_currency' ) ) diff_balance , diff_amount_currency = _compute_cash_rounding ( self , total_amount_currency ) # The invoice is already rounded. if self . currency_id . is_zero ( diff_balance ) and self . currency_id . is_zero ( diff_amount_currency ) : self . line_ids -= existing_cash_rounding_line return _apply_cash_rounding ( self , diff_balance , diff_amount_currency , existing_cash_rounding_line )