Merge branch '2.0-vivek-account-discount-changes' into 'master'

[MODIFIED] account discount module discount proportionate

See merge request flectra-hq/flectra!494
This commit is contained in:
Parthiv Patel committed 2021-11-15 09:12:31 +00:00
commit 74d2cc8fbe
3 files changed
+113 -184

No files matched your search

+1 -1
View File
@@ -15,7 +15,7 @@
'account',
],
'data': [
'views/res_config_settings_views.xml',
# 'views/res_config_settings_views.xml',
'views/account_move_views.xml',
'reports/invoice_report_views.xml',
],
+108 -176
View File
@@ -3,6 +3,7 @@ from functools import partial
from flectra import models, fields, api, _
from flectra.tools import float_is_zero, float_round, float_compare
from flectra.tools.misc import formatLang
from flectra.exceptions import UserError
_logger = logging.getLogger(__name__)
@@ -11,221 +12,152 @@ class AccountMove(models.Model):
_inherit = 'account.move'
discount_type = fields.Selection(
selection=[
('fixed', 'Fixed'),
('percent', 'Percent')
],
string="Discount Type",
default="percent",
selection=[
('fixed', 'Fixed'),
('percent', 'Percent')
],
string="Discount Type",
default="percent",
)
discount_value = fields.Float(
string='Discount',
tracking=True,
string='Discount',
tracking=True,
)
discount_value_percent = fields.Float(
string='Discount (%)',
digits='Discount',
compute='_compute_document_discount',
compute_sudo=True,
string='Discount (%)',
digits='Discount',
compute='_compute_document_discount',
compute_sudo=True,
)
amount_gross = fields.Monetary(
string='Gross Amount',
store=True,
readonly=True,
compute='_compute_amount',
string='Gross Amount',
store=True,
readonly=True,
compute='_compute_amount',
)
document_discount = fields.Monetary(
string='Document Discount',
store=True,
readonly=True,
compute='_compute_document_discount',
string='Document Discount',
store=True,
readonly=True,
compute='_compute_document_discount',
)
document_discount_tax_amount = fields.Monetary(
string='Document Discount Tax',
store=True,
readonly=True,
compute='_compute_document_discount',
string='Document Discount Tax',
store=True,
readonly=True,
compute='_compute_document_discount',
)
has_document_discount = fields.Boolean(
string='Has Document Discount',
store=True,
readonly=True,
compute='_compute_document_discount',
string='Has Document Discount',
store=True,
readonly=True,
compute='_compute_document_discount',
)
@api.depends(
'line_ids.amount_currency',
'line_ids.price_subtotal',
'line_ids.price_total',
'discount_type',
'discount_value',
'line_ids.amount_currency',
'line_ids.price_subtotal',
'line_ids.price_total',
'line_ids.product_id',
'discount_type',
'discount_value',
)
def _compute_document_discount(self):
for move in self:
document_discount = 0
discount_used = move.discount_type and not float_is_zero(move.discount_value, precision_digits=move.currency_id.decimal_places)
discount_used = move.discount_type and not float_is_zero(move.discount_value,
precision_digits=move.currency_id.decimal_places)
if discount_used:
amount_gross = 0
for line in move.invoice_line_ids:
amount_gross += line.quantity * line.price_unit
untaxed_amount = amount_gross
taxed_amt = 0
for line in move.line_ids:
if line.tax_ids:
for tax in line.tax_ids:
taxed_amt += line.price_unit * tax.amount / 100
total_amt = untaxed_amount + taxed_amt
if move.discount_type == 'fixed':
document_discount = move.discount_value * -1
document_discount = move.discount_value
if document_discount >= total_amt:
raise UserError(_("Discount Cannot be more than or equal to Total Amount"))
for line in move.invoice_line_ids:
if line.product_id:
tax = 0
if line.tax_ids:
for taxes_line in line.tax_ids:
tax += line.price_unit * taxes_line.amount / 100
line_price = line.price_unit + tax
discount_value = line_price * document_discount / total_amt
discount_ratio = discount_value / line_price * 100
if discount_ratio:
line.update({
'discount': discount_ratio
})
move._move_autocomplete_invoice_lines_values()
else:
document_discount = (move.amount_gross * (move.discount_value / 100)) * -1
document_discount = (total_amt * (move.discount_value / 100))
document_discount = float_round(document_discount, precision_digits=move.currency_id.decimal_places)
discount_lines = move.line_ids.filtered(lambda f: f.is_document_discount_line)
if discount_lines:
document_discount_tax_amount = float_round(
sum(line.price_total - line.price_subtotal for line in discount_lines),
precision_digits=move.currency_id.decimal_places
)
if document_discount >= total_amt:
raise UserError(_("Discount Cannat be more than or equal to Total Amount"))
for line in move.invoice_line_ids:
if line.product_id:
tax = 0
if line.tax_ids:
for taxes_line in line.tax_ids:
tax += line.price_unit * taxes_line.amount / 100
line_price = line.price_unit + tax
discount_value = line_price * document_discount / total_amt
discount_ratio = discount_value / line_price * 100
if discount_ratio:
line.update({
'discount': discount_ratio
})
move._move_autocomplete_invoice_lines_values()
else:
document_discount_tax_amount = 0
move.update({
'document_discount': document_discount,
'document_discount_tax_amount': document_discount_tax_amount,
'has_document_discount': discount_used,
'discount_value_percent': move.discount_value,
})
for line in move.invoice_line_ids:
line.update({
'discount': 0.0
})
move._move_autocomplete_invoice_lines_values()
@api.depends(
'line_ids.matched_debit_ids.debit_move_id.move_id.line_ids.amount_residual',
'line_ids.matched_debit_ids.debit_move_id.move_id.line_ids.amount_residual_currency',
'line_ids.matched_credit_ids.credit_move_id.move_id.line_ids.amount_residual',
'line_ids.matched_credit_ids.credit_move_id.move_id.line_ids.amount_residual_currency',
'line_ids.debit',
'line_ids.credit',
'line_ids.currency_id',
'line_ids.amount_currency',
'line_ids.amount_residual',
'line_ids.amount_residual_currency',
'line_ids.payment_id.state',
'line_ids.full_reconcile_id',
'line_ids.price_total',
'document_discount',
'line_ids.matched_debit_ids.debit_move_id.move_id.line_ids.amount_residual',
'line_ids.matched_debit_ids.debit_move_id.move_id.line_ids.amount_residual_currency',
'line_ids.matched_credit_ids.credit_move_id.move_id.line_ids.amount_residual',
'line_ids.matched_credit_ids.credit_move_id.move_id.line_ids.amount_residual_currency',
'line_ids.debit',
'line_ids.credit',
'line_ids.currency_id',
'line_ids.amount_currency',
'line_ids.amount_residual',
'line_ids.amount_residual_currency',
'line_ids.payment_id.state',
'line_ids.full_reconcile_id',
'line_ids.price_total',
'document_discount',
)
def _compute_amount(self):
super(AccountMove, self)._compute_amount()
for move in self:
if move.line_ids:
amount_gross = sum(move.line_ids.filtered(lambda f: not f.exclude_from_invoice_tab).mapped('price_subtotal'))
amount_gross = sum(
move.line_ids.filtered(lambda f: not f.exclude_from_invoice_tab).mapped('price_subtotal'))
move.update({
'amount_gross': amount_gross,
'amount_untaxed': move.amount_gross + move.document_discount,
'amount_untaxed': amount_gross
})
move._generate_document_discount_move_line()
# move._generate_document_discount_move_line()
move.update({
'amount_total': move.amount_untaxed + move.amount_tax,
})
def _generate_document_discount_move_line(self):
aml = self.env['account.move.line'].with_context(check_move_validity=False)
update_needed = False
for move in self:
update_needed = False
in_draft_mode = move != move._origin
if float_is_zero(move.document_discount, precision_digits=move.currency_id.decimal_places):
to_del = move.line_ids.filtered(lambda f: f.is_document_discount_line)
if in_draft_mode:
move.update({'line_ids': [(2, line.id) for line in to_del]})
update_needed = True
continue
currency = move.currency_id or move.company_id.currency_id
if move.discount_type == 'fixed':
account_id = move.company_id.document_discount_fixed_account_id
else:
account_id = move.company_id.document_discount_percent_account_id
create_method = in_draft_mode and aml.new or aml.create
distributions = move._get_document_tax_distribution()
for distribution in distributions.values():
existing_line = move.line_ids.filtered(lambda f: f.is_document_discount_line and f.tax_ids.ids == distribution['tax'].ids)
balance = currency._convert(
move.document_discount * distribution['factor'],
move.journal_id.company_id.currency_id,
move.journal_id.company_id,
move.date or fields.Date.context_today(move),
)
price_unit = move.document_discount * distribution['factor']
amount_currency = price_unit * -1
if existing_line:
line_values = {
'amount_currency': amount_currency,
'price_unit': price_unit,
'debit': balance < 0.0 and -balance or 0.0,
'credit': balance > 0.0 and balance or 0.0,
}
if existing_line.credit == line_values['credit'] and existing_line.debit == line_values['debit']:
continue
update_needed = True
if in_draft_mode:
existing_line.update(line_values)
else:
existing_line.write(line_values)
else:
line_values = {
'account_id': account_id.id,
'amount_currency': amount_currency,
'price_unit': price_unit,
'currency_id': currency.id,
'debit': balance < 0.0 and -balance or 0.0,
'credit': balance > 0.0 and balance or 0.0,
'name': _('Document Discount'),
'move_id': move.id,
'partner_id': move.partner_id.id,
'company_id': move.company_id.id,
'company_currency_id': currency.id,
'exclude_from_invoice_tab': True,
'is_document_discount_line': True,
'tax_ids': distribution['tax'].ids,
}
create_method(line_values)
update_needed = True
if update_needed:
self.with_context(check_move_validity=False)._recompute_dynamic_lines(recompute_all_taxes=True)
def _get_document_tax_distribution(self):
"""
This function calculates distribution factor for right split
of negative tax amount of document discount amount.
@param amount_gross: the base amount (total untaxed amount) used as 100%
@return: dict with tax.id as key and tax data includin the distribution factor
"""
self.ensure_one()
res = {}
tax_lines = self.line_ids.filtered(lambda f: f.tax_line_id)
if not tax_lines:
return res
total_amount = sum(tax_lines.mapped('tax_base_amount'))
for line in tax_lines:
key = line.tax_line_id.id
res.setdefault(key, {'tax': line.tax_line_id, 'factor': 0.0})
res[key]['factor'] = line.tax_base_amount / total_amount
return res
@api.model_create_multi
def create(self, vals_list):
rslt = super(AccountMove, self).create(vals_list)
rslt._compute_document_discount()
rslt._compute_amount()
rslt._generate_document_discount_move_line()
return rslt
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
is_document_discount_line = fields.Boolean(help="Technical field used to identify document discount lines.")
@@ -7,23 +7,20 @@
<field name="arch" type="xml">
<field name="amount_untaxed" position="before">
<field name="has_document_discount" invisible="1"/>
<field name="amount_gross" attrs="{'invisible': [('has_document_discount', '=', False)]}"/>
<field name="document_discount" attrs="{'invisible': [('has_document_discount', '=', False)]}"/>
<field name="amount_gross"/>
</field>
<field name="narration" position="after">
<group>
<group>
<label for="discount_type" string="Document Discount"/>
<div class="o_row">
<field name="discount_type"/>
<field name="discount_value" attrs="{'invisible': [('discount_type', '=', False)]}"/>
<field name="discount_type" attrs="{'readonly': [('state','=','posted')]}"/>
<field name="discount_value"
attrs="{'invisible': [('discount_type', '=', False)], 'readonly': [('state','=','posted')]}"/>
</div>
</group>
</group>
</field>
<xpath expr="//page[@id='aml_tab']//tree/field[@name='account_id']" position="after">
<field name="is_document_discount_line" invisible="True"/>
</xpath>
</field>
</record>
</flectra>