@ -22,10 +22,12 @@
import calendar
from datetime import date , datetime
from dateutil . relativedelta import relativedelta
from odoo import api , fields , models , _
from odoo . exceptions import UserError , ValidationError
from odoo . tools import DEFAULT_SERVER_DATE_FORMAT as DF
from odoo . tools import float_compare , float_is_zero
@ -35,36 +37,57 @@ class AccountAssetCategory(models.Model):
active = fields . Boolean ( default = True )
name = fields . Char ( required = True , index = True , string = " Asset Type " )
account_analytic_id = fields . Many2one ( ' account.analytic.account ' , string = ' Analytic Account ' )
analytic_tag_ids = fields . Many2many ( ' account.analytic.tag ' , string = ' Analytic Tag ' )
account_asset_id = fields . Many2one ( ' account.account ' , string = ' Asset Account ' , required = True , domain = [ ( ' internal_type ' , ' = ' , ' other ' ) , ( ' deprecated ' , ' = ' , False ) ] , help = " Account used to record the purchase of the asset at its original price. " )
account_depreciation_id = fields . Many2one ( ' account.account ' , string = ' Depreciation Entries: Asset Account ' , required = True , domain = [ ( ' internal_type ' , ' = ' , ' other ' ) , ( ' deprecated ' , ' = ' , False ) ] , help = " Account used in the depreciation entries, to decrease the asset value. " )
account_depreciation_expense_id = fields . Many2one ( ' account.account ' , string = ' Depreciation Entries: Expense Account ' , required = True , domain = [ ( ' internal_type ' , ' = ' , ' other ' ) , ( ' deprecated ' , ' = ' , False ) ] , oldname = ' account_income_recognition_id ' , help = " Account used in the periodical entries, to record a part of the asset as expense. " )
journal_id = fields . Many2one ( ' account.journal ' , string = ' Journal ' , required = True )
company_id = fields . Many2one ( ' res.company ' , string = ' Company ' , required = True , default = lambda self : self . env [ ' res.company ' ] . _company_default_get ( ' account.asset.category ' ) )
method = fields . Selection ( [ ( ' linear ' , ' Linear ' ) , ( ' degressive ' , ' Degressive ' ) ] , string = ' Computation Method ' , required = True , default = ' linear ' ,
account_analytic_id = fields . Many2one ( ' account.analytic.account ' ,
string = ' Analytic Account ' )
account_asset_id = fields . Many2one ( ' account.account ' ,
string = ' Asset Account ' , required = True ,
domain = [ ( ' internal_type ' , ' = ' , ' other ' ) ,
( ' deprecated ' , ' = ' , False ) ] ,
help = " Account used to record the purchase of the asset at its original price. " )
account_depreciation_id = fields . Many2one ( ' account.account ' ,
string = ' Depreciation Entries: Asset Account ' ,
required = True , domain = [
( ' internal_type ' , ' = ' , ' other ' ) , ( ' deprecated ' , ' = ' , False ) ] ,
help = " Account used in the depreciation entries, to decrease the asset value. " )
account_depreciation_expense_id = fields . Many2one ( ' account.account ' ,
string = ' Depreciation Entries: Expense Account ' ,
required = True , domain = [
( ' internal_type ' , ' = ' , ' other ' ) , ( ' deprecated ' , ' = ' , False ) ] ,
oldname = ' account_income_recognition_id ' ,
help = " Account used in the periodical entries, to record a part of the asset as expense. " )
journal_id = fields . Many2one ( ' account.journal ' , string = ' Journal ' ,
required = True )
company_id = fields . Many2one ( ' res.company ' , string = ' Company ' ,
required = True , default = lambda self : self . env [
' res.company ' ] . _company_default_get ( ' account.asset.category ' ) )
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 depreciations needed to depreciate your asset " )
method_period = fields . Integer ( string = ' Period Length ' , default = 1 , help = " State here the time between 2 depreciations, in months " , required = True )
" * 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 depreciations needed to depreciate your asset " )
method_period = fields . Integer ( string = ' Period Length ' , default = 1 ,
help = " State here the time between 2 depreciations, in months " ,
required = True )
method_progress_factor = fields . Float ( ' Degressive Factor ' , default = 0.3 )
method_time = fields . Selection ( [ ( ' number ' , ' Number of Entries ' ) , ( ' end ' , ' Ending Date ' ) ] , string = ' Time Method ' , required = True , default = ' number ' ,
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. " )
" * 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. " )
method_end = fields . Date ( ' Ending date ' )
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 of January ' )
open_asset = fields . Boolean ( string = ' Auto-Confirm Assets ' , help = " Check this if you want to automatically confirm the assets of this category when created by invoices. " )
group_entries = fields . Boolean ( string = ' Group Journal Entries ' , help = " Check this if you want to group the generated entries by categories. " )
type = fields . Selection ( [ ( ' sale ' , ' Sale: Revenue Recognition ' ) , ( ' purchase ' , ' Purchase: Asset ' ) ] , required = True , index = True , default = ' purchase ' )
date_first_depreciation = fields . Selection ( [
( ' last_day_period ' , ' Based on Last Day of Purchase Period ' ) ,
( ' manual ' , ' Manual (Defaulted on Purchase Date) ' ) ] ,
string = ' Depreciation Dates ' , default = ' manual ' , required = True ,
help = ' The way to compute the date of the first depreciation. \n '
' * Based on last day of purchase period: The depreciation dates will be based on the last day of the purchase month or the purchase year (depending on the periodicity of the depreciations). \n '
' * Based on purchase date: The depreciation dates will be based on the purchase date. ' )
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 of January ' )
open_asset = fields . Boolean ( string = ' Auto-confirm Assets ' ,
help = " Check this if you want to automatically confirm the assets of this category when created by invoices. " )
group_entries = fields . Boolean ( string = ' Group Journal Entries ' ,
help = " Check this if you want to group the generated entries by categories. " )
type = fields . Selection ( [ ( ' sale ' , ' Sale: Revenue Recognition ' ) ,
( ' purchase ' , ' Purchase: Asset ' ) ] , required = True ,
index = True , default = ' purchase ' )
@api . onchange ( ' account_asset_id ' )
def onchange_account_asset ( self ) :
@ -92,68 +115,119 @@ class AccountAssetAsset(models.Model):
_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 , states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
code = fields . Char ( string = ' Reference ' , size = 32 , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
value = fields . Float ( string = ' Gross Value ' , required = True , readonly = True , digits = 0 , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , oldname = ' purchase_value ' )
currency_id = fields . Many2one ( ' res.currency ' , string = ' Currency ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
default = lambda self : self . env . user . company_id . currency_id . id )
company_id = fields . Many2one ( ' res.company ' , string = ' Company ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
default = lambda self : self . env [ ' res.company ' ] . _company_default_get ( ' account.asset.asset ' ) )
entry_count = fields . Integer ( compute = ' _entry_count ' ,
string = ' # Asset Entries ' )
name = fields . Char ( string = ' Asset Name ' , required = True , readonly = True ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
code = fields . Char ( string = ' Reference ' , size = 32 , readonly = True ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
value = fields . Float ( string = ' Gross Value ' , required = True , readonly = True ,
digits = 0 , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
oldname = ' purchase_value ' )
currency_id = fields . Many2one ( ' res.currency ' , string = ' Currency ' ,
required = True , readonly = True ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
default = lambda
self : self . env . user . company_id . currency_id . id )
company_id = fields . Many2one ( ' res.company ' , string = ' Company ' ,
required = True , readonly = True ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
default = lambda self : self . env [
' res.company ' ] . _company_default_get (
' account.asset.asset ' ) )
note = fields . Text ( )
category_id = fields . Many2one ( ' account.asset.category ' , string = ' Category ' , required = True , change_default = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
date = fields . Date ( string = ' Date ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , default = fields . Date . context_today , oldname = " purchase_date " )
state = fields . Selection ( [ ( ' draft ' , ' Draft ' ) , ( ' open ' , ' Running ' ) , ( ' close ' , ' Close ' ) ] , ' Status ' , required = True , copy = False , default = ' draft ' ,
category_id = fields . Many2one ( ' account.asset.category ' , string = ' Category ' ,
required = True , change_default = True ,
readonly = True ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
date = fields . Date ( string = ' Date ' , required = True , readonly = True ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
default = fields . Date . context_today ,
oldname = " purchase_date " )
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. " )
" 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 , states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
method = fields . Selection ( [ ( ' linear ' , ' Linear ' ) , ( ' degressive ' , ' Degressive ' ) ] , string = ' Computation Method ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , default = ' linear ' ,
partner_id = fields . Many2one ( ' res.partner ' , string = ' Partner ' ,
readonly = True ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
method = fields . Selection (
[ ( ' linear ' , ' Linear ' ) , ( ' degressive ' , ' Degressive ' ) ] ,
string = ' Computation Method ' , required = True , readonly = True ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } , 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 , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , default = 5 , help = " The number of depreciations needed to depreciate your asset " )
method_period = fields . Integer ( string = ' Number of Months in a Period ' , required = True , readonly = True , default = 12 , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
help = " The amount of time between two depreciations, in months " )
method_end = fields . Date ( string = ' Ending Date ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
method_progress_factor = fields . Float ( string = ' Degressive Factor ' , readonly = True , default = 0.3 , states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
value_residual = fields . Float ( compute = ' _amount_residual ' , method = True , 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 ' , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
" * Degressive: Calculated on basis of: Residual Value * Degressive Factor " )
method_number = fields . Integer ( string = ' Number of Depreciations ' ,
readonly = True ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
default = 5 ,
help = " The number of depreciations needed to depreciate your asset " )
method_period = fields . Integer ( string = ' Number of Months in a Period ' ,
required = True , readonly = True , default = 12 ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
help = " The amount of time between two depreciations, in months " )
method_end = fields . Date ( string = ' Ending Date ' , readonly = True ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
method_progress_factor = fields . Float ( string = ' Degressive Factor ' ,
readonly = True , default = 0.3 , states = {
' draft ' : [ ( ' readonly ' , False ) ] } )
value_residual = fields . Float ( compute = ' _amount_residual ' , method = True ,
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 ' ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
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 , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
help = ' Indicates that the first depreciation entry for this asset have to be done from the asset date (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 , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' open ' : [ ( ' readonly ' , False ) ] } )
salvage_value = fields . Float ( string = ' Salvage Value ' , digits = 0 , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
help = " It is the amount you plan to have that you cannot depreciate. " )
invoice_id = fields . Many2one ( ' account.move ' , string = ' Invoice ' , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , copy = False )
type = fields . Selection ( related = " category_id.type " , string = ' Type ' , required = True )
account_analytic_id = fields . Many2one ( ' account.analytic.account ' , string = ' Analytic Account ' )
analytic_tag_ids = fields . Many2many ( ' account.analytic.tag ' , string = ' Analytic Tag ' )
date_first_depreciation = fields . Selection ( [
( ' last_day_period ' , ' Based on Last Day of Purchase Period ' ) ,
( ' manual ' , ' Manual ' ) ] ,
string = ' Depreciation Dates ' , default = ' manual ' ,
readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , required = True ,
help = ' The way to compute the date of the first depreciation. \n '
' * Based on last day of purchase period: The depreciation dates will be based on the last day of the purchase month or the purchase year (depending on the periodicity of the depreciations). \n '
' * Based on purchase date: The depreciation dates will be based on the purchase date. \n ' )
first_depreciation_manual_date = fields . Date (
string = ' First Depreciation Date ' ,
readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
help = ' Note that this date does not alter the computation of the first journal entry in case of prorata temporis assets. It simply changes its accounting date '
)
prorata = fields . Boolean ( string = ' Prorata Temporis ' , readonly = True ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
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 , states = {
' draft ' : [ ( ' readonly ' , False ) ] , ' open ' : [ ( ' readonly ' , False ) ] } )
salvage_value = fields . Float ( string = ' Salvage Value ' , digits = 0 ,
readonly = True ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
help = " It is the amount you plan to have that you cannot depreciate. " )
invoice_id = fields . Many2one ( ' account.move ' , string = ' Invoice ' ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
copy = False )
type = fields . Selection ( related = " category_id.type " , string = ' Type ' ,
required = True )
def unlink ( self ) :
for asset in self :
if asset . state in [ ' open ' , ' close ' ] :
raise UserError ( _ ( ' You cannot delete a document that is in %s state. ' ) % ( asset . state , ) )
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. ' ) )
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 ( ) )
@ -166,128 +240,184 @@ class AccountAssetAsset(models.Model):
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 )
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 ) :
for record in self :
amount = 0
if sequence == undone_dotation_number :
amount = residual_amount
else :
if record . method == ' linear ' :
amount = amount_to_depr / ( undone_dotation_number - len ( posted_depreciation_line_ids ) )
if record . prorata :
amount = amount_to_depr / record . method_number
if sequence == 1 :
date = record . date
if record . method_period % 12 != 0 :
month_days = calendar . monthrange ( date . year , date . month ) [ 1 ]
days = month_days - date . day + 1
amount = ( amount_to_depr / record . method_number ) / month_days * days
else :
days = ( record . company_id . compute_fiscalyear_dates ( date ) [ ' date_to ' ] - date ) . days + 1
amount = ( amount_to_depr / record . method_number ) / total_days * days
elif record . method == ' degressive ' :
amount = residual_amount * record . method_progress_factor
if record . prorata :
if sequence == 1 :
date = record . date
if record . method_period % 12 != 0 :
month_days = calendar . monthrange ( date . year , date . month ) [ 1 ]
days = month_days - date . day + 1
amount = ( residual_amount * record . method_progress_factor ) / month_days * days
else :
days = ( record . company_id . compute_fiscalyear_dates ( date ) [ ' date_to ' ] - date ) . days + 1
amount = ( residual_amount * record . method_progress_factor ) / total_days * days
return amount
def _compute_board_amount ( self , sequence , residual_amount , amount_to_depr ,
undone_dotation_number ,
posted_depreciation_line_ids , total_days ,
depreciation_date ) :
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 ( 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 ( 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 ) :
for record in self :
undone_dotation_number = record . method_number
if record . method_time == ' end ' :
end_date = record . method_end
undone_dotation_number = 0
while depreciation_date < = end_date :
depreciation_date = date ( depreciation_date . year , depreciation_date . month , depreciation_date . day ) + relativedelta ( months = + record . method_period )
undone_dotation_number + = 1
if record . prorata :
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
return undone_dotation_number
if self . prorata :
undone_dotation_number + = 1
return undone_dotation_number
def compute_depreciation_board ( self ) :
self . ensure_one ( )
for record in self :
posted_depreciation_line_ids = record . depreciation_line_ids . filtered ( lambda x : x . move_check ) . sorted ( key = lambda l : l . depreciation_date )
unposted_depreciation_line_ids = record . 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 ]
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 :
print ( self . company_id . fiscalyear_last_month )
print ( self . company_id . fiscalyear_last_day )
print ( self . date )
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 (
self . date [ : 4 ] + ' -01-01 ' , DF ) . date ( )
else :
asset_date = datetime . strptime ( 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 (
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 ,
' 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
if record . value_residual != 0.0 :
amount_to_depr = residual_amount = record . value_residual
self . write ( { ' depreciation_line_ids ' : commands } )
# if we already have some previous validated entries, starting date is last entry + method period
if posted_depreciation_line_ids and posted_depreciation_line_ids [ - 1 ] . depreciation_date :
last_depreciation_date = fields . Date . from_string ( posted_depreciation_line_ids [ - 1 ] . depreciation_date )
depreciation_date = last_depreciation_date + relativedelta ( months = + record . method_period )
else :
# depreciation_date computed from the purchase date
depreciation_date = record . date
if record . date_first_depreciation == ' last_day_period ' :
# depreciation_date = the last day of the month
depreciation_date = depreciation_date + relativedelta ( day = 31 )
# ... or fiscalyear depending the number of period
if record . method_period == 12 :
depreciation_date = depreciation_date + relativedelta ( month = record . company_id . fiscalyear_last_month )
depreciation_date = depreciation_date + relativedelta ( day = record . company_id . fiscalyear_last_day )
if depreciation_date < record . date :
depreciation_date = depreciation_date + relativedelta ( years = 1 )
elif record . first_depreciation_manual_date and record . first_depreciation_manual_date != record . date :
# depreciation_date set manually from the 'first_depreciation_manual_date' field
depreciation_date = record . first_depreciation_manual_date
total_days = ( depreciation_date . year % 4 ) and 365 or 366
month_day = depreciation_date . day
undone_dotation_number = record . _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 = record . _compute_board_amount ( sequence , residual_amount , amount_to_depr , undone_dotation_number , posted_depreciation_line_ids , total_days , depreciation_date )
amount = record . currency_id . round ( amount )
if float_is_zero ( amount , precision_rounding = record . currency_id . rounding ) :
continue
residual_amount - = amount
vals = {
' amount ' : amount ,
' asset_id ' : record . id ,
' sequence ' : sequence ,
' name ' : ( record . code or ' ' ) + ' / ' + str ( sequence ) ,
' remaining_value ' : residual_amount ,
' depreciated_value ' : record . value - ( record . salvage_value + residual_amount ) ,
' depreciation_date ' : depreciation_date ,
}
commands . append ( ( 0 , False , vals ) )
depreciation_date = depreciation_date + relativedelta ( months = + record . method_period )
if month_day > 28 and record . date_first_depreciation == ' manual ' :
max_day_in_month = calendar . monthrange ( depreciation_date . year , depreciation_date . month ) [ 1 ]
depreciation_date = depreciation_date . replace ( day = min ( max_day_in_month , month_day ) )
# datetime doesn't take into account that the number of days is not the same for each month
if not record . prorata and record . method_period % 12 != 0 and record . date_first_depreciation == ' last_day_period ' :
max_day_in_month = calendar . monthrange ( depreciation_date . year , depreciation_date . month ) [ 1 ]
depreciation_date = depreciation_date . replace ( day = max_day_in_month )
record . write ( { ' depreciation_line_ids ' : commands } )
return True
return True
def validate ( self ) :
self . write ( { ' state ' : ' open ' } )
@ -305,34 +435,22 @@ class AccountAssetAsset(models.Model):
for asset in self :
tracked_fields = ref_tracked_fields . copy ( )
if asset . method == ' linear ' :
del ( tracked_fields [ ' method_progress_factor ' ] )
del ( tracked_fields [ ' method_progress_factor ' ] )
if asset . method_time != ' end ' :
del ( tracked_fields [ ' method_end ' ] )
del ( tracked_fields [ ' method_end ' ] )
else :
del ( tracked_fields [ ' method_number ' ] )
dummy , tracking_value_ids = asset . _message_track ( tracked_fields , dict . fromkeys ( fields ) )
asset . message_post ( subject = _ ( ' Asset created ' ) , tracking_value_ids = tracking_value_ids )
def _return_disposal_view ( self , move_ids ) :
name = _ ( ' Disposal Move ' )
view_mode = ' form '
if len ( move_ids ) > 1 :
name = _ ( ' Disposal Moves ' )
view_mode = ' tree,form '
return {
' name ' : name ,
' view_type ' : ' form ' ,
' view_mode ' : view_mode ,
' res_model ' : ' account.move ' ,
' type ' : ' ir.actions.act_window ' ,
' target ' : ' current ' ,
' res_id ' : move_ids [ 0 ] ,
}
del ( tracked_fields [ ' method_number ' ] )
dummy , tracking_value_ids = asset . _message_track ( tracked_fields ,
dict . fromkeys (
fields ) )
asset . message_post ( subject = _ ( ' Asset created ' ) ,
tracking_value_ids = tracking_value_ids )
def _get_disposal_moves ( self ) :
move_ids = [ ]
for asset in self :
unposted_depreciation_line_ids = asset . depreciation_line_ids . filtered ( lambda x : not x . move_check )
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 ,
@ -340,41 +458,65 @@ class AccountAssetAsset(models.Model):
}
# Remove all unposted depr. lines
commands = [ ( 2 , line_id . id , False ) for line_id in unposted_depreciation_line_ids ]
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 = fields . Datetime . today ( )
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
' 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 . _message_track ( tracked_fields , old_values )
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 . _message_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 )
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 ) :
move_ids = self . _get_disposal_moves ( )
if move_ids :
return self . _return_disposal_view ( move_ids )
name = _ ( ' Disposal Move ' )
view_mode = ' form '
if len ( move_ids ) > 1 :
name = _ ( ' Disposal Moves ' )
view_mode = ' tree,form '
return {
' name ' : name ,
' view_type ' : ' form ' ,
' 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 ) :
self . write ( { ' state ' : ' draft ' } )
@api . depends ( ' value ' , ' salvage_value ' , ' depreciation_line_ids.move_check ' , ' depreciation_line_ids.amount ' )
@api . depends ( ' value ' , ' salvage_value ' , ' depreciation_line_ids.move_check ' ,
' depreciation_line_ids.amount ' )
def _amount_residual ( self ) :
for record in self :
total_amount = 0.0
@ -387,21 +529,18 @@ class AccountAssetAsset(models.Model):
def onchange_company_id ( self ) :
self . currency_id = self . company_id . currency_id . id
@api . onchange ( ' date_first_depreciation ' )
def onchange_date_first_depreciation ( self ) :
if self . date_first_depreciation == ' manual ' :
self . first_depreciation_manual_date = self . date
@api . depends ( ' depreciation_line_ids.move_id ' )
def _entry_count ( self ) :
for asset in self :
res = self . env [ ' account.asset.depreciation.line ' ] . search_count ( [ ( ' asset_id ' , ' = ' , asset . id ) , ( ' move_id ' , ' != ' , False ) ] )
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 ) :
if self . prorata and self . method_time != ' number ' :
raise ValidationError ( _ ( ' Prorata temporis can be applied only for the " number of depreciations " time method. ' ) )
raise ValidationError ( _ (
' Prorata temporis can be applied only for time method " number of depreciations " . ' ) )
@api . onchange ( ' category_id ' )
def onchange_category_id ( self ) :
@ -423,9 +562,6 @@ class AccountAssetAsset(models.Model):
' method_progress_factor ' : category . method_progress_factor ,
' method_end ' : category . method_end ,
' prorata ' : category . prorata ,
' date_first_depreciation ' : category . date_first_depreciation ,
' account_analytic_id ' : category . account_analytic_id . id ,
' analytic_tag_ids ' : [ ( 6 , 0 , category . analytic_tag_ids . ids ) ] ,
}
}
@ -450,17 +586,17 @@ class AccountAssetAsset(models.Model):
@api . model
def create ( self , vals ) :
asset = super ( AccountAssetAsset , self . with_context ( mail_create_nolog = True ) ) . create ( vals )
asset = super ( AccountAssetAsset ,
self . with_context ( mail_create_nolog = True ) ) . create ( vals )
asset . sudo ( ) . compute_depreciation_board ( )
return asset
def write ( self , vals ) :
for record in self :
res = super ( AccountAssetAsset , record ) . write ( vals )
if ' depreciation_line_ids ' not in vals and ' state ' not in vals :
for rec in record :
rec . compute_depreciation_board ( )
return res
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 ) :
move_ids = [ ]
@ -485,15 +621,23 @@ class AccountAssetDepreciationLine(models.Model):
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 ' , digits = 0 , required = True )
remaining_value = fields . Float ( string = ' Next Period Depreciation ' , digits = 0 , required = True )
depreciated_value = fields . Float ( string = ' Cumulative Depreciation ' , 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 ' , digits = 0 ,
required = True )
remaining_value = fields . Float ( string = ' Next Period Depreciation ' , digits = 0 ,
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 ' , track_visibility = ' always ' , store = True )
move_posted_check = fields . Boolean ( compute = ' _get_move_posted_check ' , string = ' Posted ' , track_visibility = ' always ' , store = True )
move_check = fields . Boolean ( compute = ' _get_move_check ' , string = ' Linked ' ,
track_visibility = ' always ' , store = True )
move_posted_check = fields . Boolean ( compute = ' _get_move_posted_check ' ,
string = ' Posted ' ,
track_visibility = ' always ' , store = True )
@api . depends ( ' move_id ' )
def _get_move_check ( self ) :
@ -507,72 +651,80 @@ class AccountAssetDepreciationLine(models.Model):
def create_move ( self , post_move = True ) :
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 :
if line . move_id :
raise UserError ( _ ( ' This depreciation is already linked to a journal entry. Please post or delete it. ' ) )
move_vals = self . _prepare_move ( line )
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 . with_context (
date = depreciation_date ) . compute ( line . amount , company_currency )
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 ,
' analytic_account_id ' : category_id . account_analytic_id . id if category_id . type == ' sale ' else False ,
' currency_id ' : company_currency != current_currency and current_currency . id or False ,
' 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 ,
' analytic_account_id ' : category_id . account_analytic_id . id if category_id . type == ' purchase ' else False ,
' currency_id ' : company_currency != current_currency and current_currency . id or False ,
' amount_currency ' : company_currency != current_currency and line . amount or 0.0 ,
}
move_vals = {
' ref ' : line . asset_id . code ,
' 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 )
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 ( )
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 _prepare_move ( self , line ) :
category_id = line . asset_id . category_id
account_analytic_id = line . asset_id . account_analytic_id
analytic_tag_ids = line . asset_id . analytic_tag_ids
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
prec = company_currency . decimal_places
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 ) )
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 ,
' partner_id ' : line . asset_id . partner_id . id ,
' analytic_account_id ' : account_analytic_id . id if category_id . type == ' sale ' else False ,
' analytic_tag_ids ' : [ ( 6 , 0 , analytic_tag_ids . ids ) ] if category_id . type == ' sale ' else False ,
' currency_id ' : company_currency != current_currency and current_currency . id or False ,
' 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 ,
' partner_id ' : line . asset_id . partner_id . id ,
' analytic_account_id ' : account_analytic_id . id if category_id . type == ' purchase ' else False ,
' analytic_tag_ids ' : [ ( 6 , 0 , analytic_tag_ids . ids ) ] if category_id . type == ' purchase ' else False ,
' currency_id ' : company_currency != current_currency and current_currency . id or False ,
' amount_currency ' : company_currency != current_currency and line . amount or 0.0 ,
}
move_vals = {
' ref ' : line . asset_id . code ,
' date ' : depreciation_date or False ,
' journal_id ' : category_id . journal_id . id ,
' line_ids ' : [ ( 0 , 0 , move_line_1 ) , ( 0 , 0 , move_line_2 ) ] ,
}
return move_vals
def _prepare_move_grouped ( self ) :
asset_id = self [ 0 ] . asset_id
category_id = asset_id . category_id # we can suppose that all lines have the same category
account_analytic_id = asset_id . account_analytic_id
analytic_tag_ids = asset_id . analytic_tag_ids
depreciation_date = self . env . context . get ( ' depreciation_date ' ) or fields . Date . context_today ( self )
def create_grouped_move ( self , post_move = True ) :
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
company = line . asset_id . company_id
amount + = current_currency . _convert ( line . amount , company_currency , company , fields . Date . today ( ) )
amount + = current_currency . compute ( line . amount , company_currency )
name = category_id . name + _ ( ' (grouped) ' )
move_line_1 = {
@ -581,8 +733,7 @@ class AccountAssetDepreciationLine(models.Model):
' debit ' : 0.0 ,
' credit ' : amount ,
' journal_id ' : category_id . journal_id . id ,
' analytic_account_id ' : account_analytic_id . id if category_id . type == ' sale ' else False ,
' analytic_tag_ids ' : [ ( 6 , 0 , analytic_tag_ids . ids ) ] if category_id . type == ' sale ' else False ,
' analytic_account_id ' : category_id . account_analytic_id . id if category_id . type == ' sale ' else False ,
}
move_line_2 = {
' name ' : name ,
@ -590,8 +741,7 @@ class AccountAssetDepreciationLine(models.Model):
' credit ' : 0.0 ,
' debit ' : amount ,
' journal_id ' : category_id . journal_id . id ,
' analytic_account_id ' : account_analytic_id . id if category_id . type == ' purchase ' else False ,
' analytic_tag_ids ' : [ ( 6 , 0 , analytic_tag_ids . ids ) ] if category_id . type == ' purchase ' else False ,
' analytic_account_id ' : category_id . account_analytic_id . id if category_id . type == ' purchase ' else False ,
}
move_vals = {
' ref ' : category_id . name ,
@ -599,15 +749,7 @@ class AccountAssetDepreciationLine(models.Model):
' journal_id ' : category_id . journal_id . id ,
' line_ids ' : [ ( 0 , 0 , move_line_1 ) , ( 0 , 0 , move_line_2 ) ] ,
}
return move_vals
def create_grouped_move ( self , post_move = True ) :
if not self . exists ( ) :
return [ ]
created_moves = self . env [ ' account.move ' ]
move = self . env [ ' account.move ' ] . create ( self . _prepare_move_grouped ( ) )
move = self . env [ ' account.move ' ] . create ( move_vals )
self . write ( { ' move_id ' : move . id , ' move_check ' : True } )
created_moves | = move
@ -618,12 +760,18 @@ class AccountAssetDepreciationLine(models.Model):
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 :
line . log_message_when_posted ( )
asset = line . asset_id
if asset . currency_id . is_zero ( asset . value_residual ) :
asset . message_post ( body = _ ( " Document closed. " ) )
asset . write ( { ' state ' : ' close ' } )
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 ) :
def _format_message ( message_description , tracked_values ) :
@ -635,15 +783,24 @@ class AccountAssetDepreciationLine(models.Model):
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 }
msg_values = { _ ( ' Currency ' ) : currency_name ,
_ ( ' Amount ' ) : line . amount }
if partner_name :
msg_values [ _ ( ' Partner ' ) ] = partner_name
msg = _format_message ( _ ( ' Depreciation line posted. ' ) , msg_values )
line . asset_id . message_post ( body = msg )
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 ) :
for record in self :