651 lines
25 KiB
Python
651 lines
25 KiB
Python
# Fusion Accounting - Asset Modification Wizard
|
|
# Enables users to modify, dispose, sell, pause, or resume
|
|
# fixed assets with full depreciation board recalculation.
|
|
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
from odoo import api, fields, models, _, Command
|
|
from odoo.exceptions import UserError
|
|
from odoo.tools import float_is_zero
|
|
from odoo.tools.misc import format_date
|
|
|
|
|
|
class AssetModify(models.TransientModel):
|
|
"""Wizard for modifying running assets, including value changes,
|
|
depreciation parameter adjustments, disposal, and sales."""
|
|
|
|
_name = 'asset.modify'
|
|
_description = 'Modify Asset'
|
|
|
|
# --- Core Fields ---
|
|
name = fields.Text(string='Note')
|
|
asset_id = fields.Many2one(
|
|
string="Asset",
|
|
comodel_name='account.asset',
|
|
required=True,
|
|
help="The target asset to modify.",
|
|
ondelete="cascade",
|
|
)
|
|
currency_id = fields.Many2one(
|
|
related='asset_id.currency_id',
|
|
)
|
|
company_id = fields.Many2one(
|
|
comodel_name='res.company',
|
|
related='asset_id.company_id',
|
|
)
|
|
date = fields.Date(
|
|
default=lambda self: fields.Date.today(),
|
|
string='Date',
|
|
)
|
|
|
|
# --- Depreciation Parameters ---
|
|
method_number = fields.Integer(
|
|
string='Duration',
|
|
required=True,
|
|
)
|
|
method_period = fields.Selection(
|
|
selection=[('1', 'Months'), ('12', 'Years')],
|
|
string='Number of Months in a Period',
|
|
help="Interval between successive depreciation entries.",
|
|
)
|
|
value_residual = fields.Monetary(
|
|
string="Depreciable Amount",
|
|
help="Updated depreciable amount for the asset.",
|
|
compute="_compute_value_residual",
|
|
store=True,
|
|
readonly=False,
|
|
)
|
|
salvage_value = fields.Monetary(
|
|
string="Not Depreciable Amount",
|
|
help="Updated non-depreciable (salvage) amount.",
|
|
)
|
|
|
|
# --- Action Selection ---
|
|
modify_action = fields.Selection(
|
|
selection="_get_selection_modify_options",
|
|
string="Action",
|
|
)
|
|
|
|
# --- Gross Increase Accounts ---
|
|
account_asset_id = fields.Many2one(
|
|
comodel_name='account.account',
|
|
string="Gross Increase Account",
|
|
check_company=True,
|
|
domain="[]",
|
|
)
|
|
account_asset_counterpart_id = fields.Many2one(
|
|
comodel_name='account.account',
|
|
check_company=True,
|
|
domain="[]",
|
|
string="Asset Counterpart Account",
|
|
)
|
|
account_depreciation_id = fields.Many2one(
|
|
comodel_name='account.account',
|
|
check_company=True,
|
|
domain="[]",
|
|
string="Depreciation Account",
|
|
)
|
|
account_depreciation_expense_id = fields.Many2one(
|
|
comodel_name='account.account',
|
|
check_company=True,
|
|
domain="[]",
|
|
string="Expense Account",
|
|
)
|
|
|
|
# --- Sale / Disposal Fields ---
|
|
invoice_ids = fields.Many2many(
|
|
comodel_name='account.move',
|
|
string="Customer Invoice",
|
|
check_company=True,
|
|
domain="[('move_type', '=', 'out_invoice'), ('state', '=', 'posted')]",
|
|
help="Invoice(s) linked to this disposal or sale.",
|
|
)
|
|
invoice_line_ids = fields.Many2many(
|
|
comodel_name='account.move.line',
|
|
check_company=True,
|
|
domain="[('move_id', '=', invoice_id), ('display_type', '=', 'product')]",
|
|
help="Specific invoice line(s) related to this asset.",
|
|
)
|
|
select_invoice_line_id = fields.Boolean(
|
|
compute="_compute_select_invoice_line_id",
|
|
)
|
|
gain_value = fields.Boolean(
|
|
compute="_compute_gain_value",
|
|
)
|
|
|
|
# --- Gain/Loss Accounts ---
|
|
gain_account_id = fields.Many2one(
|
|
comodel_name='account.account',
|
|
check_company=True,
|
|
domain="[]",
|
|
compute="_compute_accounts",
|
|
inverse="_inverse_gain_account",
|
|
readonly=False,
|
|
compute_sudo=True,
|
|
help="Account for recording gains on asset disposal.",
|
|
)
|
|
loss_account_id = fields.Many2one(
|
|
comodel_name='account.account',
|
|
check_company=True,
|
|
domain="[]",
|
|
compute="_compute_accounts",
|
|
inverse="_inverse_loss_account",
|
|
readonly=False,
|
|
compute_sudo=True,
|
|
help="Account for recording losses on asset disposal.",
|
|
)
|
|
|
|
# --- Informational ---
|
|
informational_text = fields.Html(
|
|
compute='_compute_informational_text',
|
|
)
|
|
gain_or_loss = fields.Selection(
|
|
selection=[('gain', 'Gain'), ('loss', 'Loss'), ('no', 'No')],
|
|
compute='_compute_gain_or_loss',
|
|
)
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Selection Helpers
|
|
# -------------------------------------------------------------------------
|
|
|
|
def _compute_modify_action(self):
|
|
"""Determine the default action based on context."""
|
|
if self.env.context.get('resume_after_pause'):
|
|
return 'resume'
|
|
return 'dispose'
|
|
|
|
@api.depends('asset_id')
|
|
def _get_selection_modify_options(self):
|
|
"""Return available modification actions."""
|
|
if self.env.context.get('resume_after_pause'):
|
|
return [('resume', _('Resume'))]
|
|
return [
|
|
('dispose', _("Dispose")),
|
|
('sell', _("Sell")),
|
|
('modify', _("Re-evaluate")),
|
|
('pause', _("Pause")),
|
|
]
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Compute Methods
|
|
# -------------------------------------------------------------------------
|
|
|
|
@api.depends('company_id')
|
|
def _compute_accounts(self):
|
|
for rec in self:
|
|
rec.gain_account_id = rec.company_id.gain_account_id
|
|
rec.loss_account_id = rec.company_id.loss_account_id
|
|
|
|
@api.depends('date')
|
|
def _compute_value_residual(self):
|
|
for rec in self:
|
|
rec.value_residual = rec.asset_id._get_residual_value_at_date(rec.date)
|
|
|
|
def _inverse_gain_account(self):
|
|
for rec in self:
|
|
rec.company_id.sudo().gain_account_id = rec.gain_account_id
|
|
|
|
def _inverse_loss_account(self):
|
|
for rec in self:
|
|
rec.company_id.sudo().loss_account_id = rec.loss_account_id
|
|
|
|
@api.depends('asset_id', 'invoice_ids', 'invoice_line_ids', 'modify_action', 'date')
|
|
def _compute_gain_or_loss(self):
|
|
"""Determine whether disposing/selling results in a gain or loss."""
|
|
for rec in self:
|
|
invoice_total = abs(sum(
|
|
ln.balance for ln in rec.invoice_line_ids
|
|
))
|
|
book_val = rec.asset_id._get_own_book_value(rec.date)
|
|
cmp_result = rec.company_id.currency_id.compare_amounts(
|
|
book_val, invoice_total,
|
|
)
|
|
if rec.modify_action in ('sell', 'dispose') and cmp_result < 0:
|
|
rec.gain_or_loss = 'gain'
|
|
elif rec.modify_action in ('sell', 'dispose') and cmp_result > 0:
|
|
rec.gain_or_loss = 'loss'
|
|
else:
|
|
rec.gain_or_loss = 'no'
|
|
|
|
@api.depends('asset_id', 'value_residual', 'salvage_value')
|
|
def _compute_gain_value(self):
|
|
"""Check whether the modification increases the asset's book value."""
|
|
for rec in self:
|
|
rec.gain_value = rec.currency_id.compare_amounts(
|
|
rec._get_own_book_value(),
|
|
rec.asset_id._get_own_book_value(rec.date),
|
|
) > 0
|
|
|
|
@api.depends('loss_account_id', 'gain_account_id', 'gain_or_loss',
|
|
'modify_action', 'date', 'value_residual', 'salvage_value')
|
|
def _compute_informational_text(self):
|
|
"""Generate user-facing description of what will happen."""
|
|
for wiz in self:
|
|
formatted_date = format_date(self.env, wiz.date)
|
|
|
|
if wiz.modify_action == 'dispose':
|
|
acct_name, result_label = '', _('gain/loss')
|
|
if wiz.gain_or_loss == 'gain':
|
|
acct_name = wiz.gain_account_id.display_name or ''
|
|
result_label = _('gain')
|
|
elif wiz.gain_or_loss == 'loss':
|
|
acct_name = wiz.loss_account_id.display_name or ''
|
|
result_label = _('loss')
|
|
wiz.informational_text = _(
|
|
"Depreciation will be posted through %(date)s."
|
|
"<br/> A disposal entry will go to the %(account_type)s "
|
|
"account <b>%(account)s</b>.",
|
|
date=formatted_date,
|
|
account_type=result_label,
|
|
account=acct_name,
|
|
)
|
|
|
|
elif wiz.modify_action == 'sell':
|
|
acct_name = ''
|
|
if wiz.gain_or_loss == 'gain':
|
|
acct_name = wiz.gain_account_id.display_name or ''
|
|
elif wiz.gain_or_loss == 'loss':
|
|
acct_name = wiz.loss_account_id.display_name or ''
|
|
wiz.informational_text = _(
|
|
"Depreciation will be posted through %(date)s."
|
|
"<br/> A secondary entry will neutralize the original "
|
|
"revenue and post the sale outcome to account "
|
|
"<b>%(account)s</b>.",
|
|
date=formatted_date,
|
|
account=acct_name,
|
|
)
|
|
|
|
elif wiz.modify_action == 'pause':
|
|
wiz.informational_text = _(
|
|
"Depreciation will be posted through %s.",
|
|
formatted_date,
|
|
)
|
|
|
|
elif wiz.modify_action == 'modify':
|
|
increase_note = (
|
|
_("A child asset will be created for the value increase. <br/>")
|
|
if wiz.gain_value else ""
|
|
)
|
|
wiz.informational_text = _(
|
|
"Depreciation will be posted through %(date)s. <br/> "
|
|
"%(extra_text)s Future entries will be recalculated to "
|
|
"reflect the updated parameters.",
|
|
date=formatted_date,
|
|
extra_text=increase_note,
|
|
)
|
|
|
|
else:
|
|
# Resume or other
|
|
increase_note = (
|
|
_("A child asset will be created for the value increase. <br/>")
|
|
if wiz.gain_value else ""
|
|
)
|
|
wiz.informational_text = _(
|
|
"%s Future entries will be recalculated to reflect "
|
|
"the updated parameters.",
|
|
increase_note,
|
|
)
|
|
|
|
@api.depends('invoice_ids', 'modify_action')
|
|
def _compute_select_invoice_line_id(self):
|
|
for rec in self:
|
|
rec.select_invoice_line_id = (
|
|
rec.modify_action == 'sell'
|
|
and len(rec.invoice_ids.invoice_line_ids) > 1
|
|
)
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Onchange
|
|
# -------------------------------------------------------------------------
|
|
|
|
@api.onchange('modify_action')
|
|
def _onchange_action(self):
|
|
if (
|
|
self.modify_action == 'sell'
|
|
and self.asset_id.children_ids.filtered(
|
|
lambda child: child.state in ('draft', 'open')
|
|
or child.value_residual > 0
|
|
)
|
|
):
|
|
raise UserError(_(
|
|
"Cannot automate the sale journal entry for an asset "
|
|
"with active gross increases. Please dispose of the "
|
|
"increase(s) first."
|
|
))
|
|
if self.modify_action not in ('modify', 'resume'):
|
|
self.write({
|
|
'value_residual': self.asset_id._get_residual_value_at_date(self.date),
|
|
'salvage_value': self.asset_id.salvage_value,
|
|
})
|
|
|
|
@api.onchange('invoice_ids')
|
|
def _onchange_invoice_ids(self):
|
|
"""Keep invoice_line_ids in sync when invoices change."""
|
|
valid_line_ids = self.invoice_ids.invoice_line_ids.filtered(
|
|
lambda ln: ln._origin.id in self.invoice_line_ids.ids,
|
|
)
|
|
self.invoice_line_ids = valid_line_ids
|
|
# Auto-select lines for single-line invoices
|
|
for inv in self.invoice_ids.filtered(lambda i: len(i.invoice_line_ids) == 1):
|
|
self.invoice_line_ids += inv.invoice_line_ids
|
|
|
|
# -------------------------------------------------------------------------
|
|
# CRUD Override
|
|
# -------------------------------------------------------------------------
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
"""Populate defaults from the linked asset when not provided."""
|
|
AssetModel = self.env['account.asset']
|
|
for vals in vals_list:
|
|
if 'asset_id' not in vals:
|
|
continue
|
|
asset = AssetModel.browse(vals['asset_id'])
|
|
# Block if future posted depreciation exists
|
|
future_posted = asset.depreciation_move_ids.filtered(
|
|
lambda mv: (
|
|
mv.state == 'posted'
|
|
and not mv.reversal_move_ids
|
|
and mv.date > fields.Date.today()
|
|
)
|
|
)
|
|
if future_posted:
|
|
raise UserError(_(
|
|
'Please reverse any future-dated depreciation entries '
|
|
'before modifying this asset.'
|
|
))
|
|
# Fill in missing defaults from the asset
|
|
field_defaults = {
|
|
'method_number': asset.method_number,
|
|
'method_period': asset.method_period,
|
|
'salvage_value': asset.salvage_value,
|
|
'account_asset_id': asset.account_asset_id.id,
|
|
'account_depreciation_id': asset.account_depreciation_id.id,
|
|
'account_depreciation_expense_id': asset.account_depreciation_expense_id.id,
|
|
}
|
|
for fld, default_val in field_defaults.items():
|
|
if fld not in vals:
|
|
vals[fld] = default_val
|
|
return super().create(vals_list)
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Main Business Actions
|
|
# -------------------------------------------------------------------------
|
|
|
|
def modify(self):
|
|
"""Re-evaluate the asset: update depreciation parameters,
|
|
handle value increases/decreases, and recompute the schedule."""
|
|
lock_threshold = self.asset_id.company_id._get_user_fiscal_lock_date(
|
|
self.asset_id.journal_id,
|
|
)
|
|
if self.date <= lock_threshold:
|
|
raise UserError(_(
|
|
"The selected date is on or before the fiscal lock date. "
|
|
"Re-evaluation is not permitted."
|
|
))
|
|
|
|
# Snapshot current values for change tracking
|
|
prior_vals = {
|
|
'method_number': self.asset_id.method_number,
|
|
'method_period': self.asset_id.method_period,
|
|
'value_residual': self.asset_id.value_residual,
|
|
'salvage_value': self.asset_id.salvage_value,
|
|
}
|
|
|
|
updated_vals = {
|
|
'method_number': self.method_number,
|
|
'method_period': self.method_period,
|
|
'salvage_value': self.salvage_value,
|
|
'account_asset_id': self.account_asset_id,
|
|
'account_depreciation_id': self.account_depreciation_id,
|
|
'account_depreciation_expense_id': self.account_depreciation_expense_id,
|
|
}
|
|
|
|
# Handle resume-after-pause scenario
|
|
is_resuming = self.env.context.get('resume_after_pause')
|
|
if is_resuming:
|
|
latest_depr = self.asset_id.depreciation_move_ids
|
|
last_depr_date = (
|
|
max(latest_depr, key=lambda m: m.date).date
|
|
if latest_depr else self.asset_id.acquisition_date
|
|
)
|
|
gap_days = self.asset_id._get_delta_days(last_depr_date, self.date) - 1
|
|
if self.currency_id.compare_amounts(gap_days, 0) < 0:
|
|
raise UserError(_(
|
|
"Resume date must be after the pause date."
|
|
))
|
|
updated_vals['asset_paused_days'] = (
|
|
self.asset_id.asset_paused_days + gap_days
|
|
)
|
|
updated_vals['state'] = 'open'
|
|
self.asset_id.message_post(
|
|
body=_("Asset resumed. %s", self.name),
|
|
)
|
|
|
|
# Compute value changes
|
|
current_book = self.asset_id._get_own_book_value(self.date)
|
|
target_book = self._get_own_book_value()
|
|
book_increase = target_book - current_book
|
|
|
|
new_residual, new_salvage = self._get_new_asset_values(current_book)
|
|
residual_diff = max(0, self.value_residual - new_residual)
|
|
salvage_diff = max(0, self.salvage_value - new_salvage)
|
|
|
|
# Create depreciation up to modification date (unless resuming)
|
|
if not is_resuming:
|
|
draft_before = self.env['account.move'].search_count([
|
|
('asset_id', '=', self.asset_id.id),
|
|
('state', '=', 'draft'),
|
|
('date', '<=', self.date),
|
|
], limit=1)
|
|
if draft_before:
|
|
raise UserError(_(
|
|
'Unposted depreciation entries exist before the '
|
|
'selected date. Please process them first.'
|
|
))
|
|
self.asset_id._create_move_before_date(self.date)
|
|
|
|
updated_vals['salvage_value'] = new_salvage
|
|
|
|
# Detect if child assets need recomputation
|
|
schedule_changed = (
|
|
updated_vals['method_number'] != self.asset_id.method_number
|
|
or updated_vals['method_period'] != self.asset_id.method_period
|
|
or (
|
|
updated_vals.get('asset_paused_days')
|
|
and not float_is_zero(
|
|
updated_vals['asset_paused_days']
|
|
- self.asset_id.asset_paused_days, 8,
|
|
)
|
|
)
|
|
)
|
|
self.asset_id.write(updated_vals)
|
|
|
|
# Create gross increase asset if value went up
|
|
total_increase = residual_diff + salvage_diff
|
|
if self.currency_id.compare_amounts(total_increase, 0) > 0:
|
|
increase_date = self.date + relativedelta(days=1)
|
|
increase_entry = self.env['account.move'].create({
|
|
'journal_id': self.asset_id.journal_id.id,
|
|
'date': increase_date,
|
|
'move_type': 'entry',
|
|
'asset_move_type': 'positive_revaluation',
|
|
'line_ids': [
|
|
Command.create({
|
|
'account_id': self.account_asset_id.id,
|
|
'debit': total_increase,
|
|
'credit': 0,
|
|
'name': _(
|
|
'Value increase for: %(asset)s',
|
|
asset=self.asset_id.name,
|
|
),
|
|
}),
|
|
Command.create({
|
|
'account_id': self.account_asset_counterpart_id.id,
|
|
'debit': 0,
|
|
'credit': total_increase,
|
|
'name': _(
|
|
'Value increase for: %(asset)s',
|
|
asset=self.asset_id.name,
|
|
),
|
|
}),
|
|
],
|
|
})
|
|
increase_entry._post()
|
|
|
|
child_asset = self.env['account.asset'].create({
|
|
'name': (
|
|
self.asset_id.name + ': ' + self.name
|
|
if self.name else ""
|
|
),
|
|
'currency_id': self.asset_id.currency_id.id,
|
|
'company_id': self.asset_id.company_id.id,
|
|
'method': self.asset_id.method,
|
|
'method_number': self.method_number,
|
|
'method_period': self.method_period,
|
|
'method_progress_factor': self.asset_id.method_progress_factor,
|
|
'acquisition_date': increase_date,
|
|
'value_residual': residual_diff,
|
|
'salvage_value': salvage_diff,
|
|
'prorata_date': increase_date,
|
|
'prorata_computation_type': (
|
|
'daily_computation'
|
|
if self.asset_id.prorata_computation_type == 'daily_computation'
|
|
else 'constant_periods'
|
|
),
|
|
'original_value': self._get_increase_original_value(
|
|
residual_diff, salvage_diff,
|
|
),
|
|
'account_asset_id': self.account_asset_id.id,
|
|
'account_depreciation_id': self.account_depreciation_id.id,
|
|
'account_depreciation_expense_id': self.account_depreciation_expense_id.id,
|
|
'journal_id': self.asset_id.journal_id.id,
|
|
'parent_id': self.asset_id.id,
|
|
'original_move_line_ids': [
|
|
(6, 0, increase_entry.line_ids.filtered(
|
|
lambda ln: ln.account_id == self.account_asset_id,
|
|
).ids),
|
|
],
|
|
})
|
|
child_asset.validate()
|
|
|
|
link_html = child_asset._get_html_link()
|
|
self.asset_id.message_post(
|
|
body=_('Gross increase created: %(link)s', link=link_html),
|
|
)
|
|
|
|
# Create negative revaluation entry if value went down
|
|
if self.currency_id.compare_amounts(book_increase, 0) < 0:
|
|
depr_vals = self.env['account.move']._prepare_move_for_asset_depreciation({
|
|
'amount': -book_increase,
|
|
'asset_id': self.asset_id,
|
|
'move_ref': _(
|
|
'Value decrease for: %(asset)s', asset=self.asset_id.name,
|
|
),
|
|
'depreciation_beginning_date': self.date,
|
|
'depreciation_end_date': self.date,
|
|
'date': self.date,
|
|
'asset_number_days': 0,
|
|
'asset_value_change': True,
|
|
'asset_move_type': 'negative_revaluation',
|
|
})
|
|
self.env['account.move'].create(depr_vals)._post()
|
|
|
|
# Recompute depreciation schedule
|
|
board_start = self.date if is_resuming else self.date + relativedelta(days=1)
|
|
if self.asset_id.depreciation_move_ids:
|
|
self.asset_id.compute_depreciation_board(board_start)
|
|
else:
|
|
self.asset_id.compute_depreciation_board()
|
|
|
|
# Propagate changes to child assets if schedule params changed
|
|
if schedule_changed:
|
|
child_assets = self.asset_id.children_ids
|
|
child_assets.write({
|
|
'method_number': updated_vals['method_number'],
|
|
'method_period': updated_vals['method_period'],
|
|
'asset_paused_days': self.asset_id.asset_paused_days,
|
|
})
|
|
for child in child_assets:
|
|
if not is_resuming:
|
|
child._create_move_before_date(self.date)
|
|
if child.depreciation_move_ids:
|
|
child.compute_depreciation_board(board_start)
|
|
else:
|
|
child.compute_depreciation_board()
|
|
child._check_depreciations()
|
|
child.depreciation_move_ids.filtered(
|
|
lambda mv: mv.state != 'posted',
|
|
)._post()
|
|
|
|
# Log tracked changes in the chatter
|
|
tracked_fields = self.env['account.asset'].fields_get(prior_vals.keys())
|
|
changes, tracking_vals = self.asset_id._mail_track(
|
|
tracked_fields, prior_vals,
|
|
)
|
|
if changes:
|
|
self.asset_id.message_post(
|
|
body=_('Depreciation board modified %s', self.name),
|
|
tracking_value_ids=tracking_vals,
|
|
)
|
|
|
|
self.asset_id._check_depreciations()
|
|
self.asset_id.depreciation_move_ids.filtered(
|
|
lambda mv: mv.state != 'posted',
|
|
)._post()
|
|
|
|
return {'type': 'ir.actions.act_window_close'}
|
|
|
|
def pause(self):
|
|
"""Pause depreciation for the asset."""
|
|
for rec in self:
|
|
rec.asset_id.pause(pause_date=rec.date, message=self.name)
|
|
|
|
def sell_dispose(self):
|
|
"""Dispose of or sell the asset, generating closing entries."""
|
|
self.ensure_one()
|
|
if (
|
|
self.gain_account_id == self.asset_id.account_depreciation_id
|
|
or self.loss_account_id == self.asset_id.account_depreciation_id
|
|
):
|
|
raise UserError(_(
|
|
"The gain/loss account cannot be the same as the "
|
|
"Depreciation Account."
|
|
))
|
|
disposal_lines = (
|
|
self.env['account.move.line']
|
|
if self.modify_action == 'dispose'
|
|
else self.invoice_line_ids
|
|
)
|
|
return self.asset_id.set_to_close(
|
|
invoice_line_ids=disposal_lines,
|
|
date=self.date,
|
|
message=self.name,
|
|
)
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Utility Methods
|
|
# -------------------------------------------------------------------------
|
|
|
|
def _get_own_book_value(self):
|
|
"""Return the wizard's configured book value (residual + salvage)."""
|
|
return self.value_residual + self.salvage_value
|
|
|
|
def _get_increase_original_value(self, residual_increase, salvage_increase):
|
|
"""Compute the original value for a gross increase child asset."""
|
|
return residual_increase + salvage_increase
|
|
|
|
def _get_new_asset_values(self, current_asset_book):
|
|
"""Calculate capped residual and salvage values to ensure
|
|
they don't exceed the current book value."""
|
|
self.ensure_one()
|
|
capped_residual = min(
|
|
current_asset_book - min(self.salvage_value, self.asset_id.salvage_value),
|
|
self.value_residual,
|
|
)
|
|
capped_salvage = min(
|
|
current_asset_book - capped_residual,
|
|
self.salvage_value,
|
|
)
|
|
return capped_residual, capped_salvage
|