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.
247 lines
12 KiB
247 lines
12 KiB
# -*- coding: utf-8 -*-
|
|
#############################################################################
|
|
#
|
|
# Cybrosys Technologies Pvt. Ltd.
|
|
#
|
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
|
|
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
|
|
#
|
|
# You can modify it under the terms of the GNU LESSER
|
|
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
|
|
#
|
|
# 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
|
|
# (LGPL v3) along with this program.
|
|
# If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
#############################################################################
|
|
from odoo import api, fields, models, _
|
|
from odoo.exceptions import UserError
|
|
from odoo.tools import float_compare
|
|
|
|
|
|
class AccountAssetDepreciationLine(models.Model):
|
|
"""Model for managing asset depreciation lines in the accounting system."""
|
|
_name = 'account.asset.depreciation.line'
|
|
_description = 'Asset depreciation line'
|
|
|
|
name = fields.Char(string='Depreciation Name', required=True, index=True)
|
|
sequence = fields.Integer(required=True)
|
|
asset_id = fields.Many2one('account.asset.asset', string='Asset',
|
|
required=True, ondelete='cascade')
|
|
parent_state = fields.Selection(related='asset_id.state',
|
|
string='State of Asset')
|
|
amount = fields.Float(string='Current Depreciation',
|
|
required=True)
|
|
remaining_value = fields.Float(string='Next Period Depreciation',
|
|
required=True)
|
|
depreciated_value = fields.Float(string='Cumulative Depreciation',
|
|
required=True)
|
|
depreciation_date = fields.Date('Depreciation Date', index=True)
|
|
move_id = fields.Many2one('account.move', string='Depreciation Entry')
|
|
move_check = fields.Boolean(compute='_get_move_check', string='Linked',
|
|
store=True)
|
|
move_posted_check = fields.Boolean(compute='_get_move_posted_check',
|
|
string='Posted', store=True)
|
|
|
|
@api.depends('move_id')
|
|
def _get_move_check(self):
|
|
"""Compute the 'move_check' field based on the presence of 'move_id'
|
|
for each record in the 'AccountAssetDepreciationLine' class."""
|
|
for line in self:
|
|
line.move_check = bool(line.move_id)
|
|
|
|
@api.depends('move_id.state')
|
|
def _get_move_posted_check(self):
|
|
"""Compute the 'move_posted_check' field based on the state of 'move_id'
|
|
for each record in the 'AccountAssetDepreciationLine' class."""
|
|
for line in self:
|
|
line.move_posted_check = True if line.move_id and line.move_id.state == 'posted' else False
|
|
|
|
def create_move(self, post_move=True):
|
|
"""Create accounting moves for asset depreciation lines."""
|
|
created_moves = self.env['account.move']
|
|
prec = self.env['decimal.precision'].precision_get('Account')
|
|
if self.mapped('move_id'):
|
|
raise UserError(_(
|
|
'This depreciation is already linked to a journal entry! Please post or delete it.'))
|
|
for line in self:
|
|
category_id = line.asset_id.category_id
|
|
depreciation_date = self.env.context.get(
|
|
'depreciation_date') or line.depreciation_date or fields.Date.context_today(
|
|
self)
|
|
company_currency = line.asset_id.company_id.currency_id
|
|
current_currency = line.asset_id.currency_id
|
|
amount = current_currency._convert(line.amount, company_currency,
|
|
line.asset_id.company_id,
|
|
depreciation_date)
|
|
asset_name = line.asset_id.name + ' (%s/%s)' % (line.sequence, len(line.asset_id.depreciation_line_ids))
|
|
partner = self.env['res.partner']._find_accounting_partner(line.asset_id.partner_id)
|
|
move_line_1 = {
|
|
'name': asset_name,
|
|
'account_id': category_id.account_depreciation_id.id,
|
|
'debit': 0.0 if float_compare(amount, 0.0,
|
|
precision_digits=prec) > 0 else -amount,
|
|
'credit': amount if float_compare(amount, 0.0,
|
|
precision_digits=prec) > 0 else 0.0,
|
|
'journal_id': category_id.journal_id.id,
|
|
'partner_id': partner.id,
|
|
'currency_id': company_currency != current_currency and current_currency.id or company_currency.id,
|
|
'amount_currency': company_currency != current_currency and - 1.0 * line.amount or 0.0,
|
|
}
|
|
move_line_2 = {
|
|
'name': asset_name,
|
|
'account_id': category_id.account_depreciation_expense_id.id,
|
|
'credit': 0.0 if float_compare(amount, 0.0,
|
|
precision_digits=prec) > 0 else -amount,
|
|
'debit': amount if float_compare(amount, 0.0,
|
|
precision_digits=prec) > 0 else 0.0,
|
|
'journal_id': category_id.journal_id.id,
|
|
'partner_id': partner.id,
|
|
'currency_id': company_currency != current_currency and current_currency.id or company_currency.id,
|
|
'amount_currency': company_currency != current_currency and line.amount or 0.0,
|
|
}
|
|
line_ids = [(0, 0, {
|
|
'account_id': category_id.account_depreciation_id.id,
|
|
'partner_id': partner.id,
|
|
'credit': amount if float_compare(amount, 0.0,
|
|
precision_digits=prec) > 0 else 0.0,
|
|
}), (0, 0, {
|
|
'account_id': category_id.account_depreciation_expense_id.id,
|
|
'partner_id': partner.id,
|
|
'debit': amount if float_compare(amount, 0.0,
|
|
precision_digits=prec) > 0 else 0.0,
|
|
})]
|
|
move = self.env['account.move'].create({
|
|
'ref': line.asset_id.code,
|
|
'date': depreciation_date or False,
|
|
'journal_id': category_id.journal_id.id,
|
|
'line_ids': line_ids,
|
|
})
|
|
for move_line in move.line_ids:
|
|
if move_line.account_id.id == move_line_1['account_id']:
|
|
move_line.write({'credit': move_line_1['credit'],
|
|
'debit': move_line_1['debit']})
|
|
elif move_line.account_id.id == move_line_2['account_id']:
|
|
move_line.write({'debit': move_line_2['debit'],
|
|
'credit': move_line_2['credit']})
|
|
if move.line_ids.filtered(
|
|
lambda x: x.name == 'Automatic Balancing Line'):
|
|
move.line_ids.filtered(
|
|
lambda x: x.name == 'Automatic Balancing Line').unlink()
|
|
line.write({'move_id': move.id, 'move_check': True})
|
|
created_moves |= move
|
|
|
|
if post_move and created_moves:
|
|
created_moves.filtered(lambda m: any(
|
|
m.asset_depreciation_ids.mapped(
|
|
'asset_id.category_id.open_asset'))).post()
|
|
return [x.id for x in created_moves]
|
|
|
|
def create_grouped_move(self, post_move=True):
|
|
"""Create a grouped accounting move for asset depreciation lines."""
|
|
if not self.exists():
|
|
return []
|
|
created_moves = self.env['account.move']
|
|
category_id = self[
|
|
0].asset_id.category_id # we can suppose that all lines have the same category
|
|
depreciation_date = self.env.context.get(
|
|
'depreciation_date') or fields.Date.context_today(self)
|
|
amount = 0.0
|
|
for line in self:
|
|
# Sum amount of all depreciation lines
|
|
company_currency = line.asset_id.company_id.currency_id
|
|
current_currency = line.asset_id.currency_id
|
|
amount += current_currency.compute(line.amount, company_currency)
|
|
|
|
name = category_id.name + _(' (grouped)')
|
|
move_line_1 = {
|
|
'name': name,
|
|
'account_id': category_id.account_depreciation_id.id,
|
|
'debit': 0.0,
|
|
'credit': amount,
|
|
'journal_id': category_id.journal_id.id,
|
|
'analytic_account_id': category_id.account_analytic_id.id if category_id.type == 'sale' else False,
|
|
}
|
|
move_line_2 = {
|
|
'name': name,
|
|
'account_id': category_id.account_depreciation_expense_id.id,
|
|
'credit': 0.0,
|
|
'debit': amount,
|
|
'journal_id': category_id.journal_id.id,
|
|
'analytic_account_id': category_id.account_analytic_id.id if category_id.type == 'purchase' else False,
|
|
}
|
|
move_vals = {
|
|
'ref': category_id.name,
|
|
'date': depreciation_date or False,
|
|
'journal_id': category_id.journal_id.id,
|
|
'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
|
|
}
|
|
move = self.env['account.move'].create(move_vals)
|
|
self.write({'move_id': move.id, 'move_check': True})
|
|
created_moves |= move
|
|
|
|
if post_move and created_moves:
|
|
self.post_lines_and_close_asset()
|
|
created_moves.post()
|
|
return [x.id for x in created_moves]
|
|
|
|
def post_lines_and_close_asset(self):
|
|
# we re-evaluate the assets to determine whether we can close them
|
|
# `message_post` invalidates the (whole) cache
|
|
# preprocess the assets and lines in which a message should be posted,
|
|
# and then post in batch will prevent the re-fetch of the same data over and over.
|
|
assets_to_close = self.env['account.asset.asset']
|
|
for line in self:
|
|
asset = line.asset_id
|
|
if asset.currency_id.is_zero(asset.value_residual):
|
|
assets_to_close |= asset
|
|
self.log_message_when_posted()
|
|
assets_to_close.write({'state': 'close'})
|
|
for asset in assets_to_close:
|
|
asset.message_post(body=_("Document closed."))
|
|
|
|
def log_message_when_posted(self):
|
|
"""Format and post messages for asset depreciation lines that are posted."""
|
|
def _format_message(message_description, tracked_values):
|
|
message = ''
|
|
if message_description:
|
|
message = '<span>%s</span>' % message_description
|
|
for name, values in tracked_values.items():
|
|
message += '<div> • <b>%s</b>: ' % name
|
|
message += '%s</div>' % values
|
|
return message
|
|
|
|
# `message_post` invalidates the (whole) cache
|
|
# preprocess the assets in which messages should be posted,
|
|
# and then post in batch will prevent the re-fetch of the same data over and over.
|
|
assets_to_post = {}
|
|
for line in self:
|
|
if line.move_id and line.move_id.state == 'draft':
|
|
partner_name = line.asset_id.partner_id.name
|
|
currency_name = line.asset_id.currency_id.name
|
|
msg_values = {_('Currency'): currency_name,
|
|
_('Amount'): line.amount}
|
|
if partner_name:
|
|
msg_values[_('Partner')] = partner_name
|
|
msg = _format_message(_('Depreciation line posted.'),
|
|
msg_values)
|
|
assets_to_post.setdefault(line.asset_id, []).append(msg)
|
|
for asset, messages in assets_to_post.items():
|
|
for msg in messages:
|
|
asset.message_post(body=msg)
|
|
|
|
def unlink(self):
|
|
"""Check if the depreciation line is linked to a posted move before deletion."""
|
|
for record in self:
|
|
if record.move_check:
|
|
if record.asset_id.category_id.type == 'purchase':
|
|
msg = _("You cannot delete posted depreciation lines.")
|
|
else:
|
|
msg = _("You cannot delete posted installment lines.")
|
|
raise UserError(msg)
|
|
return super(AccountAssetDepreciationLine, self).unlink()
|
|
|