You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
12 KiB
251 lines
12 KiB
# -*- coding: utf-8 -*-
|
|
##############################################################################
|
|
#
|
|
# Cybrosys Technologies Pvt. Ltd.
|
|
# Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
|
|
# Author: Treesa Maria Jude(<https://www.cybrosys.com>)
|
|
# you can modify it under the terms of the GNU LESSER
|
|
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
|
|
#
|
|
# It is forbidden to publish, distribute, sublicense, or sell copies
|
|
# of the Software or modified copies of the Software.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
|
|
#
|
|
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
|
|
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program.
|
|
# If not, see <https://www.gnu.org/licenses/>.
|
|
#
|
|
##############################################################################
|
|
|
|
|
|
from odoo.tools import float_is_zero
|
|
from odoo.exceptions import UserError
|
|
from odoo import fields, models, api, _
|
|
|
|
|
|
class RoundOffSetting(models.TransientModel):
|
|
_inherit = 'account.config.settings'
|
|
|
|
round_off = fields.Boolean(string='Allow rounding of invoice amount', help="Allow rounding of invoice amount")
|
|
round_off_account = fields.Many2one('account.account', string='Round Off Account')
|
|
|
|
@api.multi
|
|
def set_round_off(self):
|
|
ir_values_obj = self.env['ir.values']
|
|
ir_values_obj.sudo().set_default('account.config.settings', "round_off", self.round_off)
|
|
ir_values_obj.sudo().set_default('account.config.settings', "round_off_account", self.round_off_account.id)
|
|
|
|
|
|
class AccountRoundOff(models.Model):
|
|
_inherit = 'account.invoice'
|
|
|
|
round_off_value = fields.Float(compute='_compute_amount', string='Round off amount')
|
|
rounded_total = fields.Float(compute='_compute_amount', string='Rounded Total')
|
|
round_active = fields.Boolean(compute='get_round_active')
|
|
|
|
def get_round_active(self):
|
|
ir_values = self.env['ir.values']
|
|
for i in self:
|
|
i.round_active = ir_values.get_default('account.config.settings', 'round_off')
|
|
|
|
@api.one
|
|
@api.depends('invoice_line_ids.price_subtotal', 'tax_line_ids.amount', 'currency_id', 'company_id',
|
|
'date_invoice', 'type')
|
|
def _compute_amount(self):
|
|
self.amount_untaxed = sum(line.price_subtotal for line in self.invoice_line_ids)
|
|
self.amount_tax = sum(line.amount for line in self.tax_line_ids)
|
|
self.rounded_total = round(self.amount_untaxed + self.amount_tax)
|
|
self.amount_total = self.amount_untaxed + self.amount_tax
|
|
self.round_off_value = self.rounded_total - (self.amount_untaxed + self.amount_tax)
|
|
amount_total_company_signed = self.amount_total
|
|
amount_untaxed_signed = self.amount_untaxed
|
|
if self.currency_id and self.company_id and self.currency_id != self.company_id.currency_id:
|
|
currency_id = self.currency_id.with_context(date=self.date_invoice)
|
|
amount_total_company_signed = currency_id.compute(self.amount_total, self.company_id.currency_id)
|
|
amount_untaxed_signed = currency_id.compute(self.amount_untaxed, self.company_id.currency_id)
|
|
sign = self.type in ['in_refund', 'out_refund'] and -1 or 1
|
|
self.amount_total_company_signed = amount_total_company_signed * sign
|
|
self.amount_total_signed = self.amount_total * sign
|
|
self.amount_untaxed_signed = amount_untaxed_signed * sign
|
|
|
|
@api.one
|
|
@api.depends(
|
|
'state', 'currency_id', 'invoice_line_ids.price_subtotal',
|
|
'move_id.line_ids.amount_residual',
|
|
'move_id.line_ids.currency_id')
|
|
def _compute_residual(self):
|
|
residual = 0.0
|
|
residual_company_signed = 0.0
|
|
sign = self.type in ['in_refund', 'out_refund'] and -1 or 1
|
|
for line in self.sudo().move_id.line_ids:
|
|
if line.account_id.internal_type in ('receivable', 'payable'):
|
|
residual_company_signed += line.amount_residual
|
|
if line.currency_id == self.currency_id:
|
|
residual += line.amount_residual_currency if line.currency_id else line.amount_residual
|
|
else:
|
|
from_currency = (line.currency_id and line.currency_id.with_context(
|
|
date=line.date)) or line.company_id.currency_id.with_context(date=line.date)
|
|
residual += from_currency.compute(line.amount_residual, self.currency_id)
|
|
self.residual_company_signed = abs(residual_company_signed) * sign
|
|
self.residual_signed = abs(residual) * sign
|
|
if self.round_active is True and self.type == 'out_invoice':
|
|
self.residual = round(abs(residual))
|
|
else:
|
|
self.residual = abs(residual)
|
|
digits_rounding_precision = self.currency_id.rounding
|
|
if float_is_zero(self.residual, precision_rounding=digits_rounding_precision):
|
|
self.reconciled = True
|
|
else:
|
|
self.reconciled = False
|
|
|
|
@api.multi
|
|
def action_move_create(self):
|
|
""" Creates invoice related analytics and financial move lines """
|
|
account_move = self.env['account.move']
|
|
|
|
for inv in self:
|
|
|
|
if not inv.journal_id.sequence_id:
|
|
raise UserError(_('Please define sequence on the journal related to this invoice.'))
|
|
if not inv.invoice_line_ids:
|
|
raise UserError(_('Please create some invoice lines.'))
|
|
if inv.move_id:
|
|
continue
|
|
|
|
ctx = dict(self._context, lang=inv.partner_id.lang)
|
|
|
|
if not inv.date_invoice:
|
|
inv.with_context(ctx).write({'date_invoice': fields.Date.context_today(self)})
|
|
date_invoice = inv.date_invoice
|
|
company_currency = inv.company_id.currency_id
|
|
|
|
# create move lines (one per invoice line + eventual taxes and analytic lines)
|
|
iml = inv.invoice_line_move_line_get()
|
|
iml += inv.tax_line_move_line_get()
|
|
|
|
diff_currency = inv.currency_id != company_currency
|
|
# create one move line for the total and possibly adjust the other lines amount
|
|
total, total_currency, iml = inv.with_context(ctx).compute_invoice_totals(company_currency, iml)
|
|
|
|
name = inv.name or '/'
|
|
if inv.payment_term_id:
|
|
totlines = inv.with_context(ctx).payment_term_id.with_context(currency_id=company_currency.id).compute(
|
|
total, date_invoice)[0]
|
|
res_amount_currency = total_currency
|
|
ctx['date'] = date_invoice
|
|
for i, t in enumerate(totlines):
|
|
if inv.currency_id != company_currency:
|
|
amount_currency = company_currency.with_context(ctx).compute(t[1], inv.currency_id)
|
|
else:
|
|
amount_currency = False
|
|
|
|
# last line: add the diff
|
|
res_amount_currency -= amount_currency or 0
|
|
if i + 1 == len(totlines):
|
|
amount_currency += res_amount_currency
|
|
if self.round_active is True and self.type == 'out_invoice':
|
|
iml.append({
|
|
'type': 'dest',
|
|
'name': name,
|
|
'price': t[1]+self.round_off_value,
|
|
'account_id': inv.account_id.id,
|
|
'date_maturity': t[0],
|
|
'amount_currency': diff_currency and amount_currency,
|
|
'currency_id': diff_currency and inv.currency_id.id,
|
|
'invoice_id': inv.id
|
|
})
|
|
ir_values = self.env['ir.values']
|
|
acc_id = ir_values.get_default('account.config.settings', 'round_off_account')
|
|
iml.append({
|
|
'type': 'dest',
|
|
'name': "Round off",
|
|
'price': -self.round_off_value,
|
|
'account_id': acc_id,
|
|
'date_maturity': t[0],
|
|
'amount_currency': diff_currency and amount_currency,
|
|
'currency_id': diff_currency and inv.currency_id.id,
|
|
'invoice_id': inv.id
|
|
})
|
|
else:
|
|
|
|
iml.append({
|
|
'type': 'dest',
|
|
'name': name,
|
|
'price': t[1],
|
|
'account_id': inv.account_id.id,
|
|
'date_maturity': t[0],
|
|
'amount_currency': diff_currency and amount_currency,
|
|
'currency_id': diff_currency and inv.currency_id.id,
|
|
'invoice_id': inv.id
|
|
})
|
|
|
|
else:
|
|
if self.round_active is True and self.type == 'out_invoice':
|
|
iml.append({
|
|
'type': 'dest',
|
|
'name': name,
|
|
'price': total + self.round_off_value,
|
|
'account_id': inv.account_id.id,
|
|
'date_maturity': inv.date_due,
|
|
'amount_currency': diff_currency and total_currency,
|
|
'currency_id': diff_currency and inv.currency_id.id,
|
|
'invoice_id': inv.id
|
|
})
|
|
ir_values = self.env['ir.values']
|
|
acc_id = ir_values.get_default('account.config.settings', 'round_off_account')
|
|
iml.append({
|
|
'type': 'dest',
|
|
'name': "Round off",
|
|
'price': -self.round_off_value,
|
|
'account_id': acc_id,
|
|
'date_maturity': inv.date_due,
|
|
'amount_currency': diff_currency and total_currency,
|
|
'currency_id': diff_currency and inv.currency_id.id,
|
|
'invoice_id': inv.id
|
|
})
|
|
else:
|
|
iml.append({
|
|
'type': 'dest',
|
|
'name': name,
|
|
'price': total,
|
|
'account_id': inv.account_id.id,
|
|
'date_maturity': inv.date_due,
|
|
'amount_currency': diff_currency and total_currency,
|
|
'currency_id': diff_currency and inv.currency_id.id,
|
|
'invoice_id': inv.id
|
|
})
|
|
part = self.env['res.partner']._find_accounting_partner(inv.partner_id)
|
|
line = [(0, 0, self.line_get_convert(l, part.id)) for l in iml]
|
|
line = inv.group_lines(iml, line)
|
|
|
|
journal = inv.journal_id.with_context(ctx)
|
|
line = inv.finalize_invoice_move_lines(line)
|
|
|
|
date = inv.date or date_invoice
|
|
move_vals = {
|
|
'ref': inv.reference,
|
|
'line_ids': line,
|
|
'journal_id': journal.id,
|
|
'date': date,
|
|
'narration': inv.comment,
|
|
}
|
|
ctx['company_id'] = inv.company_id.id
|
|
ctx['invoice'] = inv
|
|
ctx_nolang = ctx.copy()
|
|
ctx_nolang.pop('lang', None)
|
|
move = account_move.with_context(ctx_nolang).create(move_vals)
|
|
# Pass invoice in context in method post: used if you want to get the same
|
|
# account move reference when creating the same invoice after a cancelled one:
|
|
move.post()
|
|
# make the invoice point to that move
|
|
vals = {
|
|
'move_id': move.id,
|
|
'date': date,
|
|
'move_name': move.name,
|
|
}
|
|
inv.with_context(ctx).write(vals)
|
|
return True
|
|
|