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.
		
		
		
		
		
			
		
			
				
					
					
						
							539 lines
						
					
					
						
							27 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							539 lines
						
					
					
						
							27 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/>.
							 | 
						|
								#
							 | 
						|
								#############################################################################
							 | 
						|
								import calendar
							 | 
						|
								from datetime import date, datetime
							 | 
						|
								from dateutil.relativedelta import relativedelta
							 | 
						|
								from odoo import api, fields, models, _
							 | 
						|
								from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF, float_is_zero
							 | 
						|
								from odoo.exceptions import UserError, ValidationError
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								class AccountAssetAsset(models.Model):
							 | 
						|
								    """
							 | 
						|
								        Model for managing assets with depreciation functionality
							 | 
						|
								    """
							 | 
						|
								    _name = 'account.asset.asset'
							 | 
						|
								    _description = 'Asset/Revenue Recognition'
							 | 
						|
								    _inherit = ['mail.thread']
							 | 
						|
								
							 | 
						|
								    entry_count = fields.Integer(compute='_entry_count',
							 | 
						|
								                                 string='# Asset Entries')
							 | 
						|
								    name = fields.Char(string='Asset Name', required=True, readonly=True)
							 | 
						|
								    code = fields.Char(string='Reference', size=32, readonly=True)
							 | 
						|
								    value = fields.Float(string='Gross Value', required=True, readonly=True,
							 | 
						|
								                         digits=0)
							 | 
						|
								    currency_id = fields.Many2one('res.currency', string='Currency',
							 | 
						|
								                                  required=True, readonly=True,
							 | 
						|
								                                  default=lambda self: self.env.company.currency_id.id)
							 | 
						|
								    company_id = fields.Many2one('res.company', string='Company',
							 | 
						|
								                                 required=True, readonly=True,
							 | 
						|
								                                 default=lambda self: self.env.company)
							 | 
						|
								    note = fields.Text()
							 | 
						|
								    category_id = fields.Many2one('account.asset.category', string='Category',
							 | 
						|
								                                  required=True, change_default=True,
							 | 
						|
								                                  readonly=True)
							 | 
						|
								    date = fields.Date(string='Date', required=True, readonly=True,
							 | 
						|
								                       default=fields.Date.context_today)
							 | 
						|
								    state = fields.Selection(
							 | 
						|
								        [('draft', 'Draft'), ('open', 'Running'), ('close', 'Close')],
							 | 
						|
								        'Status', required=True, copy=False, default='draft',
							 | 
						|
								        help="When an asset is created, the status is 'Draft'.\n"
							 | 
						|
								             "If the asset is confirmed, the status goes in 'Running' and the depreciation lines can be posted in the accounting.\n"
							 | 
						|
								             "You can manually close an asset when the depreciation is over. If the last line of depreciation is posted, the asset automatically goes in that status.")
							 | 
						|
								    active = fields.Boolean(default=True)
							 | 
						|
								    partner_id = fields.Many2one('res.partner', string='Partner',
							 | 
						|
								                                 readonly=True)
							 | 
						|
								    method = fields.Selection(
							 | 
						|
								        [('linear', 'Linear'), ('degressive', 'Degressive')],
							 | 
						|
								        string='Computation Method', required=True, readonly=True, default='linear',
							 | 
						|
								        help="Choose the method to use to compute the amount of depreciation lines.\n  * Linear: Calculated on basis of: Gross Value / Number of Depreciations\n"
							 | 
						|
								             "  * Degressive: Calculated on basis of: Residual Value * Degressive Factor")
							 | 
						|
								    method_number = fields.Integer(string='Number of Depreciations',
							 | 
						|
								                                   readonly=True,
							 | 
						|
								                                   default=5,
							 | 
						|
								                                   help="The number of depreciation's needed to depreciate your asset")
							 | 
						|
								    method_period = fields.Integer(string='Number of Months in a Period',
							 | 
						|
								                                   required=True, readonly=True, default=12,
							 | 
						|
								                                   help="The amount of time between two depreciation's, in months")
							 | 
						|
								    method_end = fields.Date(string='Ending Date', readonly=True,)
							 | 
						|
								    method_progress_factor = fields.Float(string='Degressive Factor',
							 | 
						|
								                                          readonly=True, default=0.3,)
							 | 
						|
								    value_residual = fields.Float(compute='_amount_residual',
							 | 
						|
								                                  digits=0, string='Residual Value')
							 | 
						|
								    method_time = fields.Selection(
							 | 
						|
								        [('number', 'Number of Entries'), ('end', 'Ending Date')],
							 | 
						|
								        string='Time Method', required=True, readonly=True, default='number',
							 | 
						|
								        help="Choose the method to use to compute the dates and number of entries.\n"
							 | 
						|
								             "  * Number of Entries: Fix the number of entries and the time between 2 depreciations.\n"
							 | 
						|
								             "  * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond.")
							 | 
						|
								    prorata = fields.Boolean(string='Prorata Temporis', readonly=True,
							 | 
						|
								                             help='Indicates that the first depreciation entry for this asset have to be done from the purchase date instead of the first January / Start date of fiscal year')
							 | 
						|
								    depreciation_line_ids = fields.One2many('account.asset.depreciation.line',
							 | 
						|
								                                            'asset_id',
							 | 
						|
								                                            string='Depreciation Lines',
							 | 
						|
								                                            readonly=True,)
							 | 
						|
								    salvage_value = fields.Float(string='Salvage Value', digits=0,
							 | 
						|
								                                 readonly=True,
							 | 
						|
								                                 help="It is the amount you plan to have that you cannot depreciate.")
							 | 
						|
								    invoice_id = fields.Many2one('account.move', string='Invoice',
							 | 
						|
								                                 copy=False)
							 | 
						|
								    type = fields.Selection(related="category_id.type", string='Type',
							 | 
						|
								                            required=True)
							 | 
						|
								
							 | 
						|
								    def unlink(self):
							 | 
						|
								        """ Prevents deletion of assets in 'open' or 'close' state or with posted depreciation entries."""
							 | 
						|
								        for asset in self:
							 | 
						|
								            if asset.state in ['open', 'close']:
							 | 
						|
								                raise UserError(
							 | 
						|
								                    _('You cannot delete a document is in %s state.') % (
							 | 
						|
								                        asset.state,))
							 | 
						|
								            for depreciation_line in asset.depreciation_line_ids:
							 | 
						|
								                if depreciation_line.move_id:
							 | 
						|
								                    raise UserError(_(
							 | 
						|
								                        'You cannot delete a document that contains posted entries.'))
							 | 
						|
								        return super(AccountAssetAsset, self).unlink()
							 | 
						|
								
							 | 
						|
								    def _get_last_depreciation_date(self):
							 | 
						|
								        """
							 | 
						|
								        @param id: ids of a account.asset.asset objects
							 | 
						|
								        @return: Returns a dictionary of the effective dates of the last depreciation entry made for given asset ids. If there isn't any, return the purchase date of this asset
							 | 
						|
								        """
							 | 
						|
								        self.env.cr.execute("""
							 | 
						|
								            SELECT a.id as id, COALESCE(MAX(m.date),a.date) AS date
							 | 
						|
								            FROM account_asset_asset a
							 | 
						|
								            LEFT JOIN account_asset_depreciation_line rel ON (rel.asset_id = a.id)
							 | 
						|
								            LEFT JOIN account_move m ON (rel.move_id = m.id)
							 | 
						|
								            WHERE a.id IN %s
							 | 
						|
								            GROUP BY a.id, m.date """, (tuple(self.ids),))
							 | 
						|
								        result = dict(self.env.cr.fetchall())
							 | 
						|
								        return result
							 | 
						|
								
							 | 
						|
								    # @api.model
							 | 
						|
								    # def _cron_generate_entries(self):
							 | 
						|
								    #     self.compute_generated_entries(datetime.today())
							 | 
						|
								    @api.onchange('category_id')
							 | 
						|
								    def gross_value(self):
							 | 
						|
								        """Update the 'value' field based on the 'price' of the selected 'category_id'."""
							 | 
						|
								        self.value = self.category_id.price
							 | 
						|
								
							 | 
						|
								    @api.model
							 | 
						|
								    def compute_generated_entries(self, date, asset_type=None):
							 | 
						|
								        """Compute generated entries for assets based on the provided date and asset type."""
							 | 
						|
								        # Entries generated : one by grouped category and one by asset from ungrouped category
							 | 
						|
								        created_move_ids = []
							 | 
						|
								        type_domain = []
							 | 
						|
								        if asset_type:
							 | 
						|
								            type_domain = [('type', '=', asset_type)]
							 | 
						|
								
							 | 
						|
								        ungrouped_assets = self.env['account.asset.asset'].search(
							 | 
						|
								            type_domain + [('state', '=', 'open'),
							 | 
						|
								                           ('category_id.group_entries', '=', False)])
							 | 
						|
								        created_move_ids += ungrouped_assets._compute_entries(date,
							 | 
						|
								                                                              group_entries=False)
							 | 
						|
								
							 | 
						|
								        for grouped_category in self.env['account.asset.category'].search(
							 | 
						|
								                type_domain + [('group_entries', '=', True)]):
							 | 
						|
								            assets = self.env['account.asset.asset'].search(
							 | 
						|
								                [('state', '=', 'open'),
							 | 
						|
								                 ('category_id', '=', grouped_category.id)])
							 | 
						|
								            created_move_ids += assets._compute_entries(date,
							 | 
						|
								                                                        group_entries=True)
							 | 
						|
								        return created_move_ids
							 | 
						|
								
							 | 
						|
								    def _compute_board_amount(self, sequence, residual_amount, amount_to_depr,
							 | 
						|
								                              undone_dotation_number,
							 | 
						|
								                              posted_depreciation_line_ids, total_days,
							 | 
						|
								                              depreciation_date):
							 | 
						|
								        """Compute the depreciation amount for a specific sequence in the asset's depreciation schedule."""
							 | 
						|
								        amount = 0
							 | 
						|
								        if sequence == undone_dotation_number:
							 | 
						|
								            amount = residual_amount
							 | 
						|
								        else:
							 | 
						|
								            if self.method == 'linear':
							 | 
						|
								                amount = amount_to_depr / (undone_dotation_number - len(
							 | 
						|
								                    posted_depreciation_line_ids))
							 | 
						|
								                if self.prorata:
							 | 
						|
								                    amount = amount_to_depr / self.method_number
							 | 
						|
								                    if sequence == 1:
							 | 
						|
								                        if self.method_period % 12 != 0:
							 | 
						|
								                            date = datetime.strptime(str(self.date),
							 | 
						|
								                                                     '%Y-%m-%d')
							 | 
						|
								                            month_days = \
							 | 
						|
								                                calendar.monthrange(date.year, date.month)[1]
							 | 
						|
								                            days = month_days - date.day + 1
							 | 
						|
								                            amount = (
							 | 
						|
								                                             amount_to_depr / self.method_number) / month_days * days
							 | 
						|
								                        else:
							 | 
						|
								                            days = (self.company_id.compute_fiscalyear_dates(
							 | 
						|
								                                depreciation_date)[
							 | 
						|
								                                        'date_to'] - depreciation_date).days + 1
							 | 
						|
								                            amount = (
							 | 
						|
								                                             amount_to_depr / self.method_number) / total_days * days
							 | 
						|
								            elif self.method == 'degressive':
							 | 
						|
								                amount = residual_amount * self.method_progress_factor
							 | 
						|
								                if self.prorata:
							 | 
						|
								                    if sequence == 1:
							 | 
						|
								                        if self.method_period % 12 != 0:
							 | 
						|
								                            date = datetime.strptime(str(self.date),
							 | 
						|
								                                                     '%Y-%m-%d')
							 | 
						|
								                            month_days = \
							 | 
						|
								                                calendar.monthrange(date.year, date.month)[1]
							 | 
						|
								                            days = month_days - date.day + 1
							 | 
						|
								                            amount = (
							 | 
						|
								                                             residual_amount * self.method_progress_factor) / month_days * days
							 | 
						|
								                        else:
							 | 
						|
								                            days = (self.company_id.compute_fiscalyear_dates(
							 | 
						|
								                                depreciation_date)[
							 | 
						|
								                                        'date_to'] - depreciation_date).days + 1
							 | 
						|
								                            amount = (
							 | 
						|
								                                             residual_amount * self.method_progress_factor) / total_days * days
							 | 
						|
								        return amount
							 | 
						|
								
							 | 
						|
								    def _compute_board_undone_dotation_nb(self, depreciation_date, total_days):
							 | 
						|
								        """Compute the number of remaining depreciations for an asset based on the depreciation date and total days."""
							 | 
						|
								        undone_dotation_number = self.method_number
							 | 
						|
								        if self.method_time == 'end':
							 | 
						|
								            end_date = datetime.strptime(str(self.method_end), DF).date()
							 | 
						|
								            undone_dotation_number = 0
							 | 
						|
								            while depreciation_date <= end_date:
							 | 
						|
								                depreciation_date = date(depreciation_date.year,
							 | 
						|
								                                         depreciation_date.month,
							 | 
						|
								                                         depreciation_date.day) + relativedelta(
							 | 
						|
								                    months=+self.method_period)
							 | 
						|
								                undone_dotation_number += 1
							 | 
						|
								        if self.prorata:
							 | 
						|
								            undone_dotation_number += 1
							 | 
						|
								        return undone_dotation_number
							 | 
						|
								
							 | 
						|
								    def compute_depreciation_board(self):
							 | 
						|
								        """
							 | 
						|
								            Compute the depreciation schedule for the asset based on its current state and parameters.
							 | 
						|
								            This method calculates the depreciation amount for each period and generates depreciation entries accordingly.
							 | 
						|
								        """
							 | 
						|
								        self.ensure_one()
							 | 
						|
								        posted_depreciation_line_ids = self.depreciation_line_ids.filtered(
							 | 
						|
								            lambda x: x.move_check).sorted(key=lambda l: l.depreciation_date)
							 | 
						|
								        unposted_depreciation_line_ids = self.depreciation_line_ids.filtered(
							 | 
						|
								            lambda x: not x.move_check)
							 | 
						|
								
							 | 
						|
								        # Remove old unposted depreciation lines. We cannot use unlink() with One2many field
							 | 
						|
								        commands = [(2, line_id.id, False) for line_id in
							 | 
						|
								                    unposted_depreciation_line_ids]
							 | 
						|
								
							 | 
						|
								        if self.value_residual != 0.0:
							 | 
						|
								            amount_to_depr = residual_amount = self.value_residual
							 | 
						|
								            if self.prorata:
							 | 
						|
								                # if we already have some previous validated entries, starting date is last entry + method perio
							 | 
						|
								                if posted_depreciation_line_ids and \
							 | 
						|
								                        posted_depreciation_line_ids[-1].depreciation_date:
							 | 
						|
								                    last_depreciation_date = datetime.strptime(
							 | 
						|
								                        posted_depreciation_line_ids[-1].depreciation_date,
							 | 
						|
								                        DF).date()
							 | 
						|
								                    depreciation_date = last_depreciation_date + relativedelta(
							 | 
						|
								                        months=+self.method_period)
							 | 
						|
								                else:
							 | 
						|
								                    depreciation_date = datetime.strptime(
							 | 
						|
								                        str(self._get_last_depreciation_date()[self.id]),
							 | 
						|
								                        DF).date()
							 | 
						|
								            else:
							 | 
						|
								                # depreciation_date = 1st of January of purchase year if annual valuation, 1st of
							 | 
						|
								                # purchase month in other cases
							 | 
						|
								                if self.method_period >= 12:
							 | 
						|
								                    if self.company_id.fiscalyear_last_month:
							 | 
						|
								                        asset_date = date(year=int(self.date.year),
							 | 
						|
								                                          month=int(
							 | 
						|
								                                              self.company_id.fiscalyear_last_month),
							 | 
						|
								                                          day=int(
							 | 
						|
								                                              self.company_id.fiscalyear_last_day)) + relativedelta(
							 | 
						|
								                            days=1) + \
							 | 
						|
								                                     relativedelta(year=int(
							 | 
						|
								                                         self.date.year))  # e.g. 2018-12-31 +1 -> 2019
							 | 
						|
								                    else:
							 | 
						|
								                        asset_date = datetime.strptime(
							 | 
						|
								                            str(self.date)[:4] + '-01-01', DF).date()
							 | 
						|
								                else:
							 | 
						|
								                    asset_date = datetime.strptime(str(self.date)[:7] + '-01',
							 | 
						|
								                                                   DF).date()
							 | 
						|
								                # if we already have some previous validated entries, starting date isn't 1st January but last entry + method period
							 | 
						|
								                if posted_depreciation_line_ids and \
							 | 
						|
								                        posted_depreciation_line_ids[-1].depreciation_date:
							 | 
						|
								                    last_depreciation_date = datetime.strptime(str(
							 | 
						|
								                        posted_depreciation_line_ids[-1].depreciation_date),
							 | 
						|
								                        DF).date()
							 | 
						|
								                    depreciation_date = last_depreciation_date + relativedelta(
							 | 
						|
								                        months=+self.method_period)
							 | 
						|
								                else:
							 | 
						|
								                    depreciation_date = asset_date
							 | 
						|
								            day = depreciation_date.day
							 | 
						|
								            month = depreciation_date.month
							 | 
						|
								            year = depreciation_date.year
							 | 
						|
								            total_days = (year % 4) and 365 or 366
							 | 
						|
								
							 | 
						|
								            undone_dotation_number = self._compute_board_undone_dotation_nb(
							 | 
						|
								                depreciation_date, total_days)
							 | 
						|
								
							 | 
						|
								            for x in range(len(posted_depreciation_line_ids),
							 | 
						|
								                           undone_dotation_number):
							 | 
						|
								                sequence = x + 1
							 | 
						|
								                amount = self._compute_board_amount(sequence, residual_amount,
							 | 
						|
								                                                    amount_to_depr,
							 | 
						|
								                                                    undone_dotation_number,
							 | 
						|
								                                                    posted_depreciation_line_ids,
							 | 
						|
								                                                    total_days,
							 | 
						|
								                                                    depreciation_date)
							 | 
						|
								
							 | 
						|
								                amount = self.currency_id.round(amount)
							 | 
						|
								                if float_is_zero(amount,
							 | 
						|
								                                 precision_rounding=self.currency_id.rounding):
							 | 
						|
								                    continue
							 | 
						|
								                residual_amount -= amount
							 | 
						|
								                vals = {
							 | 
						|
								                    'amount': amount,
							 | 
						|
								                    'asset_id': self.id,
							 | 
						|
								                    'sequence': sequence,
							 | 
						|
								                    'name': (self.code or '') + '/' + str(sequence),
							 | 
						|
								                    'remaining_value': residual_amount if residual_amount >= 0 else 0.0,
							 | 
						|
								                    'depreciated_value': self.value - (
							 | 
						|
								                            self.salvage_value + residual_amount),
							 | 
						|
								                    'depreciation_date': depreciation_date.strftime(DF),
							 | 
						|
								                }
							 | 
						|
								                commands.append((0, False, vals))
							 | 
						|
								                # Considering Depr. Period as months
							 | 
						|
								                depreciation_date = date(year, month, day) + relativedelta(
							 | 
						|
								                    months=+self.method_period)
							 | 
						|
								                day = depreciation_date.day
							 | 
						|
								                month = depreciation_date.month
							 | 
						|
								                year = depreciation_date.year
							 | 
						|
								
							 | 
						|
								        self.write({'depreciation_line_ids': commands})
							 | 
						|
								
							 | 
						|
								        return True
							 | 
						|
								
							 | 
						|
								    def validate(self):
							 | 
						|
								        """Update the state to 'open' and track specific fields based on the asset's method."""
							 | 
						|
								        self.write({'state': 'open'})
							 | 
						|
								        fields = [
							 | 
						|
								            'method',
							 | 
						|
								            'method_number',
							 | 
						|
								            'method_period',
							 | 
						|
								            'method_end',
							 | 
						|
								            'method_progress_factor',
							 | 
						|
								            'method_time',
							 | 
						|
								            'salvage_value',
							 | 
						|
								            'invoice_id',
							 | 
						|
								        ]
							 | 
						|
								        ref_tracked_fields = self.env['account.asset.asset'].fields_get(fields)
							 | 
						|
								        for asset in self:
							 | 
						|
								            tracked_fields = ref_tracked_fields.copy()
							 | 
						|
								            if asset.method == 'linear':
							 | 
						|
								                del (tracked_fields['method_progress_factor'])
							 | 
						|
								            if asset.method_time != 'end':
							 | 
						|
								                del (tracked_fields['method_end'])
							 | 
						|
								            else:
							 | 
						|
								                del (tracked_fields['method_number'])
							 | 
						|
								            dummy, tracking_value_ids = asset._mail_track(tracked_fields,
							 | 
						|
								                                                          dict.fromkeys(
							 | 
						|
								                                                              fields))
							 | 
						|
								            asset.message_post(subject=_('Asset created'),
							 | 
						|
								                               tracking_value_ids=tracking_value_ids)
							 | 
						|
								
							 | 
						|
								    def _get_disposal_moves(self):
							 | 
						|
								        """Get the disposal moves for the asset."""
							 | 
						|
								        move_ids = []
							 | 
						|
								        for asset in self:
							 | 
						|
								            unposted_depreciation_line_ids = asset.depreciation_line_ids.filtered(
							 | 
						|
								                lambda x: not x.move_check)
							 | 
						|
								            if unposted_depreciation_line_ids:
							 | 
						|
								                old_values = {
							 | 
						|
								                    'method_end': asset.method_end,
							 | 
						|
								                    'method_number': asset.method_number,
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                # Remove all unposted depr. lines
							 | 
						|
								                commands = [(2, line_id.id, False) for line_id in
							 | 
						|
								                            unposted_depreciation_line_ids]
							 | 
						|
								
							 | 
						|
								                # Create a new depr. line with the residual amount and post it
							 | 
						|
								                sequence = len(asset.depreciation_line_ids) - len(
							 | 
						|
								                    unposted_depreciation_line_ids) + 1
							 | 
						|
								                today = datetime.today().strftime(DF)
							 | 
						|
								                vals = {
							 | 
						|
								                    'amount': asset.value_residual,
							 | 
						|
								                    'asset_id': asset.id,
							 | 
						|
								                    'sequence': sequence,
							 | 
						|
								                    'name': (asset.code or '') + '/' + str(sequence),
							 | 
						|
								                    'remaining_value': 0,
							 | 
						|
								                    'depreciated_value': asset.value - asset.salvage_value,
							 | 
						|
								                    # the asset is completely depreciated
							 | 
						|
								                    'depreciation_date': today,
							 | 
						|
								                }
							 | 
						|
								                commands.append((0, False, vals))
							 | 
						|
								                asset.write(
							 | 
						|
								                    {'depreciation_line_ids': commands, 'method_end': today,
							 | 
						|
								                     'method_number': sequence})
							 | 
						|
								                tracked_fields = self.env['account.asset.asset'].fields_get(
							 | 
						|
								                    ['method_number', 'method_end'])
							 | 
						|
								                changes, tracking_value_ids = asset._mail_track(
							 | 
						|
								                    tracked_fields, old_values)
							 | 
						|
								
							 | 
						|
								                if changes:
							 | 
						|
								                    asset.message_post(subject=_(
							 | 
						|
								                        'Asset sold or disposed. Accounting entry awaiting for validation.'),
							 | 
						|
								                        tracking_value_ids=tracking_value_ids)
							 | 
						|
								                move_ids += asset.depreciation_line_ids[-1].create_move(
							 | 
						|
								                    post_move=False)
							 | 
						|
								
							 | 
						|
								        return move_ids
							 | 
						|
								
							 | 
						|
								    def set_to_close(self):
							 | 
						|
								        """Set the asset to close state by creating disposal moves and returning an action window to view the move(s)."""
							 | 
						|
								        move_ids = self._get_disposal_moves()
							 | 
						|
								        if move_ids:
							 | 
						|
								            name = _('Disposal Move')
							 | 
						|
								            view_mode = 'form'
							 | 
						|
								            if len(move_ids) > 1:
							 | 
						|
								                name = _('Disposal Moves')
							 | 
						|
								                view_mode = 'list,form'
							 | 
						|
								            return {
							 | 
						|
								                'name': name,
							 | 
						|
								                'view_mode': view_mode,
							 | 
						|
								                'res_model': 'account.move',
							 | 
						|
								                'type': 'ir.actions.act_window',
							 | 
						|
								                'target': 'current',
							 | 
						|
								                'res_id': move_ids[0],
							 | 
						|
								            }
							 | 
						|
								        # Fallback, as if we just clicked on the smartbutton
							 | 
						|
								        return self.open_entries()
							 | 
						|
								
							 | 
						|
								    def set_to_draft(self):
							 | 
						|
								        """Set the asset's state to 'draft'."""
							 | 
						|
								        self.write({'state': 'draft'})
							 | 
						|
								
							 | 
						|
								    @api.depends('value', 'salvage_value', 'depreciation_line_ids.move_check',
							 | 
						|
								                 'depreciation_line_ids.amount')
							 | 
						|
								    def _amount_residual(self):
							 | 
						|
								        """Compute the residual value of the asset based on the total depreciation amount."""
							 | 
						|
								        for record in self:
							 | 
						|
								            total_amount = 0.0
							 | 
						|
								            for line in record.depreciation_line_ids:
							 | 
						|
								                if line.move_check:
							 | 
						|
								                    total_amount += line.amount
							 | 
						|
								            record.value_residual = record.value - total_amount - record.salvage_value
							 | 
						|
								
							 | 
						|
								    @api.onchange('company_id')
							 | 
						|
								    def onchange_company_id(self):
							 | 
						|
								        """Update the 'currency_id' field based on the selected 'company_id'."""
							 | 
						|
								        self.currency_id = self.company_id.currency_id.id
							 | 
						|
								
							 | 
						|
								    @api.depends('depreciation_line_ids.move_id')
							 | 
						|
								    def _entry_count(self):
							 | 
						|
								        """Compute the number of entries related to the asset based on the depreciation lines."""
							 | 
						|
								        for asset in self:
							 | 
						|
								            res = self.env['account.asset.depreciation.line'].search_count(
							 | 
						|
								                [('asset_id', '=', asset.id), ('move_id', '!=', False)])
							 | 
						|
								            asset.entry_count = res or 0
							 | 
						|
								
							 | 
						|
								    @api.constrains('prorata', 'method_time')
							 | 
						|
								    def _check_prorata(self):
							 | 
						|
								        """Check if prorata temporis can be applied for the given asset based on the 'prorata' and 'method_time' fields."""
							 | 
						|
								        if self.prorata and self.method_time != 'number':
							 | 
						|
								            raise ValidationError(_(
							 | 
						|
								                'Prorata temporis can be applied only for time method "number of depreciations".'))
							 | 
						|
								
							 | 
						|
								    @api.onchange('category_id')
							 | 
						|
								    def onchange_category_id(self):
							 | 
						|
								        """Update the fields of the asset based on the selected 'category_id'."""
							 | 
						|
								        vals = self.onchange_category_id_values(self.category_id.id)
							 | 
						|
								        # We cannot use 'write' on an object that doesn't exist yet
							 | 
						|
								        if vals:
							 | 
						|
								            for k, v in vals['value'].items():
							 | 
						|
								                setattr(self, k, v)
							 | 
						|
								
							 | 
						|
								    def onchange_category_id_values(self, category_id):
							 | 
						|
								        """Update the fields of the asset based on the selected 'category_id'."""
							 | 
						|
								        if category_id:
							 | 
						|
								            category = self.env['account.asset.category'].browse(category_id)
							 | 
						|
								            return {
							 | 
						|
								                'value': {
							 | 
						|
								                    'method': category.method,
							 | 
						|
								                    'method_number': category.method_number,
							 | 
						|
								                    'method_time': category.method_time,
							 | 
						|
								                    'method_period': category.method_period,
							 | 
						|
								                    'method_progress_factor': category.method_progress_factor,
							 | 
						|
								                    'method_end': category.method_end,
							 | 
						|
								                    'prorata': category.prorata,
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								    @api.onchange('method_time')
							 | 
						|
								    def onchange_method_time(self):
							 | 
						|
								        """Update the 'prorata' field based on the selected 'method_time' value."""
							 | 
						|
								        if self.method_time != 'number':
							 | 
						|
								            self.prorata = False
							 | 
						|
								
							 | 
						|
								    def copy_data(self, default=None):
							 | 
						|
								        """Copies the data of the current record with the option to override default values."""
							 | 
						|
								        if default is None:
							 | 
						|
								            default = {}
							 | 
						|
								        default['name'] = self.name + _(' (copy)')
							 | 
						|
								        return super(AccountAssetAsset, self).copy_data(default)
							 | 
						|
								
							 | 
						|
								    def _compute_entries(self, date, group_entries=False):
							 | 
						|
								        """Compute depreciation entries for the given date."""
							 | 
						|
								        depreciation_ids = self.env['account.asset.depreciation.line'].search([
							 | 
						|
								            ('asset_id', 'in', self.ids), ('depreciation_date', '<=', date),
							 | 
						|
								            ('move_check', '=', False)])
							 | 
						|
								        if group_entries:
							 | 
						|
								            return depreciation_ids.create_grouped_move()
							 | 
						|
								        return depreciation_ids.create_move()
							 | 
						|
								
							 | 
						|
								    @api.model
							 | 
						|
								    def create(self, vals):
							 | 
						|
								        """Create a new asset record using the provided values and compute its depreciation schedule."""
							 | 
						|
								        asset = super(AccountAssetAsset,
							 | 
						|
								                      self.with_context(mail_create_nolog=True)).create(vals)
							 | 
						|
								        asset.sudo().compute_depreciation_board()
							 | 
						|
								        return asset
							 | 
						|
								
							 | 
						|
								    def write(self, vals):
							 | 
						|
								        """Updates the records with the provided values and computes the depreciation board if necessary."""
							 | 
						|
								        res = super(AccountAssetAsset, self).write(vals)
							 | 
						|
								        if 'depreciation_line_ids' not in vals and 'state' not in vals:
							 | 
						|
								            for rec in self:
							 | 
						|
								                rec.compute_depreciation_board()
							 | 
						|
								        return res
							 | 
						|
								
							 | 
						|
								    def open_entries(self):
							 | 
						|
								        """Return a dictionary to open journal entries related to the asset."""
							 | 
						|
								        move_ids = []
							 | 
						|
								        for asset in self:
							 | 
						|
								            for depreciation_line in asset.depreciation_line_ids:
							 | 
						|
								                if depreciation_line.move_id:
							 | 
						|
								                    move_ids.append(depreciation_line.move_id.id)
							 | 
						|
								        return {
							 | 
						|
								            'name': _('Journal Entries'),
							 | 
						|
								            'view_mode': 'list,form',
							 | 
						|
								            'res_model': 'account.move',
							 | 
						|
								            'view_id': False,
							 | 
						|
								            'type': 'ir.actions.act_window',
							 | 
						|
								            'domain': [('id', 'in', move_ids)],
							 | 
						|
								        }
							 | 
						|
								
							 |