1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/sale_external_tax/models/sale_order.py
2024-12-10 09:04:09 +07:00

152 lines
7.3 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, _
from odoo.tools import formatLang
class SaleOrder(models.Model):
_name = 'sale.order'
_inherit = ['account.external.tax.mixin', 'sale.order']
def _compute_tax_totals(self):
"""This overrides the standard values which come from
account.tax. The percentage (amount field) on account.tax
won't be correct in case of (partial) exemptions. As always we
should rely purely on the values the external tax integration
returns, not the values Odoo computes. This will create a
single tax group using the amount_* fields on the order which
come from the external tax integration.
"""
res = super()._compute_tax_totals()
group_name = _('Untaxed Amount')
for order in self.filtered('is_tax_computed_externally'):
currency = order.currency_id
tax_totals = order.tax_totals
tax_totals['groups_by_subtotal'] = {
group_name: [{
'tax_group_name': _('Taxes'),
'tax_group_amount': order.amount_tax,
'tax_group_base_amount': order.amount_untaxed,
'formatted_tax_group_amount': formatLang(self.env, order.amount_tax, currency_obj=currency),
'formatted_tax_group_base_amount': formatLang(self.env, order.amount_untaxed, currency_obj=currency),
'tax_group_id': 1,
'group_key': 1,
'hide_base_amount': False,
}]
}
tax_totals['subtotals'] = [{
'name': group_name,
'amount': order.amount_untaxed,
'formatted_amount': formatLang(self.env, order.amount_untaxed, currency_obj=currency),
}]
tax_totals['amount_total'] = order.amount_total
tax_totals['amount_untaxed'] = order.amount_untaxed
tax_totals['formatted_amount_total'] = formatLang(self.env, order.amount_total, currency_obj=currency)
tax_totals['subtotals_order'] = [group_name]
order.tax_totals = tax_totals
return res
def _compute_amounts(self):
""" This overrides the standard values for orders using external tax calculation. The round_globally option
doesn't work when calculating taxes externally hence the tax (amount_tax field) on sale.order won't be
correct in case of (partial) exemptions. As always we should rely purely on the values the external tax
service returns, not the values Odoo computes.
"""
external_tax_orders = self.filtered('is_tax_computed_externally')
for order in external_tax_orders:
order_lines = order.order_line.filtered(lambda x: not x.display_type)
order.amount_untaxed = sum(order_lines.mapped('price_subtotal'))
order.amount_tax = sum(order_lines.mapped('price_tax'))
order.amount_total = order.amount_untaxed + order.amount_tax
super(SaleOrder, self - external_tax_orders)._compute_amounts()
def _create_account_invoices(self, invoice_vals_list, final):
""" Override. Always calculate taxes on final invoices that have down payment lines. We clear tax_ids on
invoice lines in _prepare_invoice_line() to avoid confusing users when the tax amount Odoo calculates is
different from what Avatax calculated for their SO. But because down payments are based on the total,
not subtotal, this can lead to a negative total on the invoice. To avoid the invoice being turned into a
credit note, automatically calculate taxes on invoices with a down payment line."""
moves = super()._create_account_invoices(invoice_vals_list, final)
if final: # Don't needlessly do this for non-final invoices.
moves.filtered(lambda move: any(move.line_ids.sale_line_ids.mapped('is_downpayment')))._get_and_set_external_taxes_on_eligible_records()
return moves
def action_confirm(self):
""" Ensure confirmed orders have the right taxes. """
self._get_and_set_external_taxes_on_eligible_records()
return super().action_confirm()
def action_quotation_send(self):
""" Calculate taxes before presenting order to the customer. """
self._get_and_set_external_taxes_on_eligible_records()
return super().action_quotation_send()
def _get_and_set_external_taxes_on_eligible_records(self):
""" account.external.tax.mixin override. """
eligible_orders = self.filtered(lambda order: order.is_tax_computed_externally and order.state in ('draft', 'sent', 'sale') and not order.locked)
eligible_orders._set_external_taxes(*eligible_orders._get_external_taxes())
return super()._get_and_set_external_taxes_on_eligible_records()
def _get_lines_eligible_for_external_taxes(self):
""" account.external.tax.mixin override. """
return self.order_line.filtered(lambda l: not l.display_type and not l.is_downpayment)
def _get_line_data_for_external_taxes(self):
""" account.external.tax.mixin override. """
res = []
for line in self._get_lines_eligible_for_external_taxes():
# Clear all taxes (e.g. default customer tax). Not every line will be sent to the external tax
# calculation service, those lines would keep their default taxes otherwise.
line.tax_id = False
res.append({
"id": line.id,
"model_name": line._name,
"product_id": line.product_id,
"qty": line.product_uom_qty,
"price_subtotal": line.price_subtotal,
"price_unit": line.price_unit,
"discount": line.discount,
"is_refund": False,
})
return res
def _set_external_taxes(self, mapped_taxes, summary):
""" account.external.tax.mixin override. """
to_flush = self.env['sale.order.line']
for line, detail in mapped_taxes.items():
line.tax_id = detail['tax_ids']
to_flush += line
# Trigger field computation due to changing the tax id. Do
# this here because we will manually change the taxes.
to_flush.flush_recordset(['price_tax', 'price_subtotal', 'price_total'])
for line, detail in mapped_taxes.items():
line.price_tax = detail['tax_amount']
line.price_subtotal = detail['total']
line.price_total = detail['tax_amount'] + detail['total']
def _get_date_for_external_taxes(self):
""" account.external.tax.mixin override. """
return self.date_order
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
def _prepare_invoice_line(self, **optional_values):
""" Override to clear tax_ids on lines. Brazilian taxes are variable and don't have the right amount set in Odoo (always 1%),
so taxes are always wrong unless recomputed with button_external_tax_calculation. Although this automatically happens when needed, clearing the
taxes here avoids potential confusion.
"""
res = super()._prepare_invoice_line(**optional_values)
if self.order_id.is_tax_computed_externally:
res['tax_ids'] = False
return res