diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 6585b3ac91b..d61c6fddd40 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -2948,9 +2948,14 @@ class AccountMove(models.Model): def grouping_key_generator(base_line, tax_values): return self.env['account.tax']._get_generation_dict_from_base_line(base_line, tax_values) + def inverse_tax_rep(tax_rep): + tax = tax_rep.tax_id + index = list(tax.invoice_repartition_line_ids).index(tax_rep) + return tax.refund_repartition_line_ids[index] + # Get the current tax amounts in the current invoice. tax_amounts = { - line.tax_repartition_line_id.id: { + inverse_tax_rep(line.tax_repartition_line_id).id: { 'amount_currency': line.amount_currency, 'balance': line.balance, } @@ -2958,7 +2963,13 @@ class AccountMove(models.Model): } product_lines = self.line_ids.filtered(lambda x: x.display_type == 'product') - base_lines = [x._convert_to_tax_base_line_dict() for x in product_lines] + base_lines = [ + { + **x._convert_to_tax_base_line_dict(), + 'is_refund': True, + } + for x in product_lines + ] for base_line in base_lines: base_line['taxes'] = base_line['taxes'].filtered(lambda t: t.amount_type != 'fixed') @@ -2982,8 +2993,9 @@ class AccountMove(models.Model): term_amount_currency = payment_term_line.amount_currency - payment_term_line.discount_amount_currency term_balance = payment_term_line.balance - payment_term_line.discount_balance if early_pay_discount_computation == 'included' and product_lines.tax_ids: - # Compute the base amounts. + # Compute the base amounts. resulting_delta_base_details = {} + resulting_delta_tax_details = {} to_process = [] for base_line in base_lines: invoice_line = base_line['record'] @@ -3023,7 +3035,6 @@ class AccountMove(models.Model): grouping_key_generator=grouping_key_generator, ) - resulting_delta_tax_details = {} for tax_detail in tax_details_with_epd['tax_details'].values(): tax_amount_without_epd = tax_amounts.get(tax_detail['tax_repartition_line_id']) if not tax_amount_without_epd: @@ -3045,25 +3056,28 @@ class AccountMove(models.Model): # Multiply the amount by the percentage percentage_paid = abs(payment_term_line.amount_residual_currency / self.amount_total) - tax_rep = self.env['account.tax.repartition.line'].browse(tax_detail['tax_repartition_line_id']) - tax = tax_rep.tax_id + for tax_detail in resulting_delta_tax_details.values(): + tax_rep = self.env['account.tax.repartition.line'].browse(tax_detail['tax_repartition_line_id']) + tax = tax_rep.tax_id - grouping_dict = { - 'account_id': tax_detail['account_id'], - 'partner_id': tax_detail['partner_id'], - 'currency_id': tax_detail['currency_id'], - 'analytic_distribution': tax_detail['analytic_distribution'], - 'tax_repartition_line_id': tax_rep.id, - 'tax_ids': tax_detail['tax_ids'], - 'tax_tag_ids': tax_detail['tax_tag_ids'], - 'group_tax_id': tax_detail['tax_id'] if tax_detail['tax_id'] != tax.id else None, - } + grouping_dict = { + 'account_id': tax_detail['account_id'], + 'partner_id': tax_detail['partner_id'], + 'currency_id': tax_detail['currency_id'], + 'analytic_distribution': tax_detail['analytic_distribution'], + 'tax_repartition_line_id': tax_rep.id, + 'tax_ids': tax_detail['tax_ids'], + 'tax_tag_ids': tax_detail['tax_tag_ids'], + 'group_tax_id': tax_detail['tax_id'] if tax_detail['tax_id'] != tax.id else None, + } + + res['tax_lines'][payment_term_line][frozendict(grouping_dict)] = { + 'name': _("Early Payment Discount (%s)", tax.name), + 'amount_currency': payment_term_line.currency_id.round(tax_detail['amount_currency'] * percentage_paid), + 'balance': payment_term_line.company_currency_id.round(tax_detail['balance'] * percentage_paid), + 'tax_tag_invert': True, + } - res['tax_lines'][payment_term_line][frozendict(grouping_dict)] = { - 'name': _("Early Payment Discount (%s)", tax.name), - 'amount_currency': payment_term_line.currency_id.round(tax_detail['tax_amount_currency'] * percentage_paid), - 'balance': payment_term_line.company_currency_id.round(tax_detail['tax_amount'] * percentage_paid), - } for grouping_dict, base_detail in bases_details.items(): res['base_lines'][payment_term_line][grouping_dict] = { 'name': _("Early Payment Discount"), diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py index c91d49dbfd7..a2b208ab0c0 100644 --- a/addons/account/models/account_payment.py +++ b/addons/account/models/account_payment.py @@ -873,12 +873,14 @@ class AccountPayment(models.Model): # Update the existing journal items. # If dealing with multiple write-off lines, they are dropped and a new one is generated. - pay.move_id.write({ - 'partner_id': pay.partner_id.id, - 'currency_id': pay.currency_id.id, - 'partner_bank_id': pay.partner_bank_id.id, - 'line_ids': line_ids_commands, - }) + pay.move_id\ + .with_context(skip_invoice_sync=True)\ + .write({ + 'partner_id': pay.partner_id.id, + 'currency_id': pay.currency_id.id, + 'partner_bank_id': pay.partner_bank_id.id, + 'line_ids': line_ids_commands, + }) def _create_paired_internal_transfer_payment(self): ''' When an internal transfer is posted, a paired payment is created diff --git a/addons/account/tests/test_early_payment_discount.py b/addons/account/tests/test_early_payment_discount.py index 7a475c85a56..f83ea1d83bc 100644 --- a/addons/account/tests/test_early_payment_discount.py +++ b/addons/account/tests/test_early_payment_discount.py @@ -375,3 +375,75 @@ class TestAccountEarlyPaymentDiscount(AccountTestInvoicingCommon): } ], }) + + def test_intracomm_bill_with_early_payment_included(self): + tax_tags = self.env['account.account.tag'].create({ + 'name': f'tax_tag_{i}', + 'applicability': 'taxes', + 'country_id': self.env.company.account_fiscal_country_id.id, + } for i in range(6)) + + intracomm_tax = self.env['account.tax'].create({ + 'name': 'tax20', + 'amount_type': 'percent', + 'amount': 20, + 'type_tax_use': 'purchase', + 'invoice_repartition_line_ids': [ + # pylint: disable=bad-whitespace + Command.create({'repartition_type': 'base', 'factor_percent': 100.0, 'tag_ids': [Command.set(tax_tags[0].ids)]}), + Command.create({'repartition_type': 'tax', 'factor_percent': 100.0, 'tag_ids': [Command.set(tax_tags[1].ids)]}), + Command.create({'repartition_type': 'tax', 'factor_percent': -100.0, 'tag_ids': [Command.set(tax_tags[2].ids)]}), + ], + 'refund_repartition_line_ids': [ + # pylint: disable=bad-whitespace + Command.create({'repartition_type': 'base', 'factor_percent': 100.0, 'tag_ids': [Command.set(tax_tags[3].ids)]}), + Command.create({'repartition_type': 'tax', 'factor_percent': 100.0, 'tag_ids': [Command.set(tax_tags[4].ids)]}), + Command.create({'repartition_type': 'tax', 'factor_percent': -100.0, 'tag_ids': [Command.set(tax_tags[5].ids)]}), + ], + }) + + early_payment_term = self.env['account.payment.term'].create({ + 'name': "early_payment_term", + 'company_id': self.company_data['company'].id, + 'early_pay_discount_computation': 'included', + 'early_discount': True, + 'discount_percentage': 2, + 'discount_days': 7, + 'line_ids': [ + Command.create({ + 'value': 'percent', + 'value_amount': 100.0, + 'nb_days': 30, + }), + ], + }) + + bill = self.env['account.move'].create({ + 'move_type': 'in_invoice', + 'partner_id': self.partner_a.id, + 'invoice_payment_term_id': early_payment_term.id, + 'invoice_date': '2019-01-01', + 'date': '2019-01-01', + 'invoice_line_ids': [ + Command.create({ + 'name': 'line', + 'price_unit': 1000.0, + 'tax_ids': [Command.set(intracomm_tax.ids)], + }), + ], + }) + bill.action_post() + + payment = self.env['account.payment.register']\ + .with_context(active_model='account.move', active_ids=bill.ids)\ + .create({'payment_date': '2019-01-01'})\ + ._create_payments() + + self.assertRecordValues(payment.line_ids.sorted('balance'), [ + # pylint: disable=bad-whitespace + {'amount_currency': -980.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_tag_invert': False}, + {'amount_currency': -20.0, 'tax_ids': intracomm_tax.ids, 'tax_tag_ids': tax_tags[3].ids, 'tax_tag_invert': True}, + {'amount_currency': -4.0, 'tax_ids': [], 'tax_tag_ids': tax_tags[4].ids, 'tax_tag_invert': True}, + {'amount_currency': 4.0, 'tax_ids': [], 'tax_tag_ids': tax_tags[5].ids, 'tax_tag_invert': True}, + {'amount_currency': 1000.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_tag_invert': False}, + ]) diff --git a/addons/account/wizard/account_payment_register.py b/addons/account/wizard/account_payment_register.py index 31180b08d0b..33661d55657 100644 --- a/addons/account/wizard/account_payment_register.py +++ b/addons/account/wizard/account_payment_register.py @@ -774,7 +774,9 @@ class AccountPaymentRegister(models.TransientModel): :param edit_mode: Is the wizard in edition mode. """ - payments = self.env['account.payment'].create([x['create_vals'] for x in to_process]) + payments = self.env['account.payment']\ + .with_context(skip_invoice_sync=True)\ + .create([x['create_vals'] for x in to_process]) for payment, vals in zip(payments, to_process): vals['payment'] = payment