[IMP] account_asset: improved depreciation dates management
related to task id 29411
add selection field 'date_first_depreciation' on 'account.asset.asset' to manage the depreciation dates:
-manual: set manually with the manual_date_first_depreciation field (defaulted on purchase date)
-last_day_period: last day of purchase month/year
add a selection field on 'account.asset.category' to set the default value as well.
This commit is contained in:
@@ -36,9 +36,16 @@ class AccountAssetCategory(models.Model):
|
||||
" * 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.")
|
||||
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.')
|
||||
|
||||
@api.onchange('account_asset_id')
|
||||
def onchange_account_asset(self):
|
||||
@@ -97,12 +104,25 @@ class AccountAssetAsset(models.Model):
|
||||
" * 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 purchase date instead of the first January / Start date of fiscal year')
|
||||
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.invoice', string='Invoice', states={'draft': [('readonly', False)]}, copy=False)
|
||||
type = fields.Selection(related="category_id.type", string='Type', required=True)
|
||||
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'
|
||||
)
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
@@ -114,22 +134,6 @@ class AccountAssetAsset(models.Model):
|
||||
raise UserError(_('You cannot delete a document that contains posted entries.'))
|
||||
return super(AccountAssetAsset, self).unlink()
|
||||
|
||||
@api.multi
|
||||
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())
|
||||
@@ -160,25 +164,25 @@ class AccountAssetAsset(models.Model):
|
||||
if self.prorata:
|
||||
amount = amount_to_depr / self.method_number
|
||||
if sequence == 1:
|
||||
date = datetime.strptime(self.date, DF)
|
||||
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
|
||||
days = (self.company_id.compute_fiscalyear_dates(date)['date_to'] - 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:
|
||||
date = datetime.strptime(self.date, DF)
|
||||
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
|
||||
days = (self.company_id.compute_fiscalyear_dates(date)['date_to'] - date).days + 1
|
||||
amount = (residual_amount * self.method_progress_factor) / total_days * days
|
||||
return amount
|
||||
|
||||
@@ -206,31 +210,32 @@ class AccountAssetAsset(models.Model):
|
||||
|
||||
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(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:
|
||||
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
|
||||
|
||||
# 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 = datetime.strptime(posted_depreciation_line_ids[-1].depreciation_date, DF).date()
|
||||
depreciation_date = last_depreciation_date + relativedelta(months=+self.method_period)
|
||||
else:
|
||||
# depreciation_date computed from the purchase date
|
||||
depreciation_date = self.date
|
||||
depreciation_date = datetime.strptime(depreciation_date, DF)
|
||||
if self.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 self.method_period == 12:
|
||||
depreciation_date = depreciation_date + relativedelta(month=self.company_id.fiscalyear_last_month)
|
||||
depreciation_date = depreciation_date + relativedelta(day=self.company_id.fiscalyear_last_day)
|
||||
if datetime.strftime(depreciation_date, DF) < self.date:
|
||||
depreciation_date = depreciation_date + relativedelta(years=1)
|
||||
elif self.first_depreciation_manual_date and self.first_depreciation_manual_date != self.date:
|
||||
# depreciation_date set manually from the 'first_depreciation_manual_date' field
|
||||
depreciation_date = self.first_depreciation_manual_date
|
||||
depreciation_date = datetime.strptime(depreciation_date, DF)
|
||||
|
||||
depreciation_date = depreciation_date.date()
|
||||
total_days = (depreciation_date.year % 4) and 365 or 366
|
||||
month_day = depreciation_date.day
|
||||
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):
|
||||
@@ -250,11 +255,17 @@ class AccountAssetAsset(models.Model):
|
||||
'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
|
||||
|
||||
depreciation_date = depreciation_date + relativedelta(months=+self.method_period)
|
||||
|
||||
if month_day > 28 and self.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 self.prorata and self.method_period % 12 != 0 and self.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)
|
||||
|
||||
self.write({'depreciation_line_ids': commands})
|
||||
|
||||
@@ -359,6 +370,13 @@ class AccountAssetAsset(models.Model):
|
||||
def onchange_company_id(self):
|
||||
self.currency_id = self.company_id.currency_id.id
|
||||
|
||||
@api.multi
|
||||
@api.onchange('date_first_depreciation')
|
||||
def onchange_date_first_depreciation(self):
|
||||
for record in self:
|
||||
if record.date_first_depreciation == 'manual':
|
||||
record.first_depreciation_manual_date = record.date
|
||||
|
||||
@api.multi
|
||||
@api.depends('depreciation_line_ids.move_id')
|
||||
def _entry_count(self):
|
||||
@@ -392,6 +410,7 @@ 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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,57 +10,72 @@
|
||||
<field name="model">account.asset.category</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Asset category">
|
||||
<group>
|
||||
<div class="oe_title">
|
||||
<label for="name" string="Asset Type" class="oe_edit_only" attrs="{'invisible': [('type','!=','purchase')]}"/>
|
||||
<label for="name" string="Deferred Revenue Type" class="oe_edit_only" attrs="{'invisible': [('type','==','purchase')]}"/>
|
||||
<h1>
|
||||
<field name="name" placeholder="e.g. Computers"/>
|
||||
</h1>
|
||||
</div>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="type" invisible="1"/>
|
||||
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group string="Journal Entries">
|
||||
<field name="journal_id"/>
|
||||
<div>
|
||||
<label for="account_asset_id" attrs="{'invisible': [('type','!=','purchase')]}"/>
|
||||
<label for="account_asset_id" string="Deferred Revenue Account" attrs="{'invisible': [('type','!=','sale')]}"/>
|
||||
<div class="oe_title">
|
||||
<label for="name" string="Asset Type" class="oe_edit_only" attrs="{'invisible': [('type','!=','purchase')]}"/>
|
||||
<label for="name" string="Deferred Revenue Type" class="oe_edit_only" attrs="{'invisible': [('type','==','purchase')]}"/>
|
||||
<h1>
|
||||
<field name="name" placeholder="e.g. Computers"/>
|
||||
</h1>
|
||||
</div>
|
||||
<field name="account_asset_id" nolabel="1" attrs="{'invisible': [('type','=', False)]}"/>
|
||||
<div>
|
||||
<label for="account_depreciation_id" attrs="{'invisible': [('type','!=','purchase')]}"/>
|
||||
<label for="account_depreciation_id" string="Recognition Income Account" attrs="{'invisible': [('type','!=','sale')]}"/>
|
||||
</div>
|
||||
<field name="account_depreciation_id" nolabel="1"/>
|
||||
<div>
|
||||
<label for="account_depreciation_expense_id" attrs="{'invisible': [('type','!=','purchase')]}"/>
|
||||
<label for="account_depreciation_expense_id" string="Recognition Account" attrs="{'invisible': [('type','!=','sale')]}"/>
|
||||
</div>
|
||||
<field name="account_depreciation_expense_id" nolabel="1"/>
|
||||
<field name="account_analytic_id" groups="analytic.group_analytic_accounting"/>
|
||||
<group>
|
||||
<field name="type" attrs="{'invisible': 1}"/>
|
||||
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group string="Journal Entries">
|
||||
<field name="journal_id"/>
|
||||
<div>
|
||||
<label for="account_asset_id"
|
||||
attrs="{'invisible': [('type','!=','purchase')]}"
|
||||
style="font-weight: bold" class="o_light_label"/>
|
||||
<label for="account_asset_id" string="Deferred Revenue Account"
|
||||
attrs="{'invisible': [('type','!=','sale')]}"
|
||||
style="font-weight: bold" class="o_light_label"/>
|
||||
</div>
|
||||
<field name="account_asset_id" nolabel="1" attrs="{'invisible': [('type','=', False)]}"/>
|
||||
<div>
|
||||
<label for="account_depreciation_id"
|
||||
attrs="{'invisible': [('type','!=','purchase')]}"
|
||||
style="font-weight: bold" class="o_light_label"/>
|
||||
<label for="account_depreciation_id" string="Recognition Income Account"
|
||||
attrs="{'invisible': [('type','!=','sale')]}"
|
||||
style="font-weight: bold" class="o_light_label"/>
|
||||
</div>
|
||||
<field name="account_depreciation_id" nolabel="1"/>
|
||||
<div>
|
||||
<label for="account_depreciation_expense_id"
|
||||
attrs="{'invisible': [('type','!=','purchase')]}"
|
||||
style="font-weight: bold" class="o_light_label"/>
|
||||
<label for="account_depreciation_expense_id" string="Recognition Account"
|
||||
attrs="{'invisible': [('type','!=','sale')]}"
|
||||
style="font-weight: bold" class="o_light_label"/>
|
||||
</div>
|
||||
<field name="account_depreciation_expense_id" nolabel="1"/>
|
||||
<field name="account_analytic_id" groups="analytic.group_analytic_accounting"/>
|
||||
</group>
|
||||
<group string="Periodicity">
|
||||
<field name="method_time" string="Time Method Based On" widget="radio" attrs="{'invisible': [('type','!=','purchase')]}"/>
|
||||
<field name="method_number" string="Number of Entries" attrs="{'invisible':['|',('method_time','!=','number'),'&',('type','=', False)], 'required':[('method_time','=','number')]}"/>
|
||||
<label for="method_period" string="One Entry Every"/>
|
||||
<div>
|
||||
<field name="method_period" nolabel="1" attrs="{'invisible': [('type','=', False)]}" class="oe_inline"/>
|
||||
months
|
||||
</div>
|
||||
<field name="method_end" attrs="{'required': [('method_time','=','end')], 'invisible':[('method_time','!=','end')]}"/>
|
||||
</group>
|
||||
<group string="Additional Options">
|
||||
<field name="open_asset"/>
|
||||
<field name="group_entries"/>
|
||||
<field name="date_first_depreciation"/>
|
||||
</group>
|
||||
<group attrs="{'invisible': [('type','=','sale')]}" string="Depreciation Method">
|
||||
<field name="method" widget="radio"/>
|
||||
<field name="method_progress_factor" attrs="{'invisible':[('method','=','linear')], 'required':[('method','=','degressive')]}"/>
|
||||
<field name="prorata" attrs="{'invisible': [('method_time','=','end')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Periodicity">
|
||||
<field name="method_time" string="Time Method Based On" widget="radio" attrs="{'invisible': [('type','!=','purchase')]}"/>
|
||||
<field name="method_number" string="Number of Entries" attrs="{'invisible':['|',('method_time','!=','number'),'&',('type','=', False)], 'required':[('method_time','=','number')]}"/>
|
||||
<label for="method_period" string="One Entry Every"/>
|
||||
<div>
|
||||
<field name="method_period" nolabel="1" attrs="{'invisible': [('type','=', False)]}" class="oe_inline"/>
|
||||
months
|
||||
</div>
|
||||
<field name="method_end" attrs="{'required': [('method_time','=','end')], 'invisible':[('method_time','!=','end')]}"/>
|
||||
</group>
|
||||
<group string="Additional Options">
|
||||
<field name="open_asset"/>
|
||||
<field name="group_entries"/>
|
||||
</group>
|
||||
<group attrs="{'invisible': [('type','=','sale')]}" string="Depreciation Method">
|
||||
<field name="method" widget="radio"/>
|
||||
<field name="method_progress_factor" attrs="{'invisible':[('method','=','linear')], 'required':[('method','=','degressive')]}"/>
|
||||
<field name="prorata" attrs="{'invisible': [('method_time','=','end')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
@@ -151,6 +166,9 @@
|
||||
<field name="category_id" string="Asset Category" domain="[('type', '=', 'purchase')]" context="{'default_type': 'purchase'}" help="Category of asset"/>
|
||||
<field name="code"/>
|
||||
<field name="date" help="Date of asset"/>
|
||||
<field name="date_first_depreciation"/>
|
||||
<field name="first_depreciation_manual_date"
|
||||
attrs="{'invisible': [('date_first_depreciation', '!=', 'manual')], 'required': [('date_first_depreciation', '=', 'manual')]}"/>
|
||||
<field name="type" invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
@@ -168,8 +186,8 @@
|
||||
<field name="depreciation_line_ids" mode="tree" options="{'reload_whole_on_button': true}">
|
||||
<tree string="Depreciation Lines" decoration-info="(move_check == False)" create="false">
|
||||
<field name="depreciation_date"/>
|
||||
<field name="depreciated_value" readonly="1"/>
|
||||
<field name="amount" widget="monetary" string="Depreciation"/>
|
||||
<field name="depreciated_value" readonly="1"/>
|
||||
<field name="remaining_value" readonly="1" widget="monetary" string="Residual"/>
|
||||
<field name="move_check" widget="deprec_lines_toggler" attrs="{'invisible': [('parent_state', '!=', 'open')]}"/>
|
||||
<field name="move_posted_check" invisible="1"/>
|
||||
|
||||
Reference in New Issue
Block a user