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.
		
		
		
		
		
			
		
			
				
					
					
						
							537 lines
						
					
					
						
							26 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							537 lines
						
					
					
						
							26 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) | |
|     code = fields.Char(string='Reference', size=32) | |
|     value = fields.Float(string='Gross Value', required=True, | |
|                          digits=0) | |
|     currency_id = fields.Many2one('res.currency', string='Currency', | |
|                                   required=True, | |
|                                   default=lambda self: self.env.company.currency_id.id) | |
|     company_id = fields.Many2one('res.company', string='Company', | |
|                                  required=True, | |
|                                  default=lambda self: self.env.company) | |
|     note = fields.Text() | |
|     category_id = fields.Many2one('account.asset.category', string='Category', | |
|                                   required=True, change_default=True | |
|                                   ) | |
|     date = fields.Date(string='Date', required=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') | |
|     method = fields.Selection( | |
|         [('linear', 'Linear'), ('degressive', 'Degressive')], | |
|         string='Computation Method', required=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', | |
|                                    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, default=12, | |
|                                    help="The amount of time between two depreciation's, in months") | |
|     method_end = fields.Date(string='Ending Date') | |
|     method_progress_factor = fields.Float(string='Degressive Factor', | |
|                                           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,  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', | |
|                              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', | |
|                                             ) | |
|     salvage_value = fields.Float(string='Salvage Value', digits=0, | |
| 
 | |
|                                  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)], | |
|         }
 | |
| 
 |