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()
							 | 
						|
								
							 |