mirror of
https://github.com/OCA/account-financial-tools.git
synced 2025-02-02 12:47:26 +02:00
[FIX] account_asset_disposal: Restore full functionality
This commit is contained in:
committed by
Jairo Llopis
parent
26432ccd53
commit
27b4e2f67f
@@ -1,22 +1,43 @@
|
||||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
|
||||
:target: http://www.gnu.org/licenses/agpl
|
||||
:alt: License: AGPL-3
|
||||
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png
|
||||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
:alt: License: AGPL-3
|
||||
|
||||
======================
|
||||
Account asset disposal
|
||||
======================
|
||||
|
||||
This module extends the functionality of account_asset adding a disposal
|
||||
date, allowing reversion of disposal operation and adding the state
|
||||
"Disposed" to the asset.
|
||||
It adds an expense account at asset category level to post expenses when
|
||||
asset is disposed.
|
||||
This module enables a real asset disposal with the proper accounting entries.
|
||||
|
||||
When an asset gets broken or is totally depreciated, you can close it and Odoo
|
||||
will generate automatically the asset close move (and compute the loss if a
|
||||
residual value is pending).
|
||||
|
||||
You can also cancel this disposal for returning to the previous state.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
#. Go to *Accounting > Configuration > Management > Asset Types*.
|
||||
#. There's a new field called "Loss Account" for setting the default loss
|
||||
account when disposing assets.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
In a disposed asset you will find an 'Undo disposal' button to revert
|
||||
operation.
|
||||
#. Go to *Accounting > Adviser > Assets*.
|
||||
#. There you will find a 'Dispose' button (instead of standard 'Set to Close').
|
||||
#. After clicking it, a wizard pops-up for asking disposal date and loss
|
||||
account to use if any residual value is pending.
|
||||
#. Click on "Dispose asset".
|
||||
#. A new screen will appear with the disposal account entry.
|
||||
#. On the asset, all remaining depreciation lines are removed, and a new one
|
||||
appears for the disposal move.
|
||||
|
||||
You can cancel afterwards the disposal:
|
||||
|
||||
#. Click on "Undo disposal" on the asset.
|
||||
#. The disposal entry is removed.
|
||||
#. The depreciation board is restored with all the remaining depreciations.
|
||||
|
||||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
|
||||
:alt: Try me on Runbot
|
||||
@@ -31,6 +52,11 @@ Bugs are tracked on `GitHub Issues
|
||||
check there if your issue has already been reported. If you spotted it first,
|
||||
help us smashing it by providing a detailed and welcomed feedback.
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
* Include a specific message type for notifying the disposal.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
@@ -42,9 +68,10 @@ Images
|
||||
Contributors
|
||||
------------
|
||||
|
||||
* Pedro M. Baeza <pedro.baeza@tecnativa.com>
|
||||
* Antonio Espinosa <antonio.espinosa@tecnativa.com>
|
||||
* Luis M. Ontalba <luis.martinez@tecnativa.com>
|
||||
* Tecnativa (https://www.tecnativa.com):
|
||||
* Pedro M. Baeza <pedro.baeza@tecnativa.com>
|
||||
* Antonio Espinosa <antonio.espinosa@tecnativa.com>
|
||||
* Luis M. Ontalba <luis.martinez@tecnativa.com>
|
||||
|
||||
Maintainer
|
||||
----------
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import models
|
||||
from . import wizards
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
|
||||
# Copyright 2017 Luis M. Ontalba - <luis.martinez@tecnativa.com>
|
||||
# Copyright 2016 Tecnativa - Antonio Espinosa
|
||||
# Copyright 2017 Tecnativa - Luis M. Ontalba
|
||||
# Copyright 2017 Tecnativa - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
{
|
||||
"name": "Account asset disposal",
|
||||
"summary": "Makes asset close account move automatically",
|
||||
"version": "10.0.1.1.0",
|
||||
"version": "10.0.2.0.0",
|
||||
"category": "Accounting & Finance",
|
||||
"website": "https://www.tecnativa.com",
|
||||
"website": "http://github.com/OCA/account-financial-tools",
|
||||
"author": "Tecnativa, "
|
||||
"Odoo Community Association (OCA)",
|
||||
"license": "AGPL-3",
|
||||
"application": False,
|
||||
"installable": True,
|
||||
"depends": [
|
||||
"account_asset",
|
||||
"account_cancel",
|
||||
],
|
||||
"data": [
|
||||
"views/account_asset_view.xml",
|
||||
"views/account_asset_asset_views.xml",
|
||||
"views/account_asset_category_views.xml",
|
||||
"wizards/account_asset_disposal_wizard_view.xml",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-23 09:15+0000\n"
|
||||
"PO-Revision-Date: 2017-11-23 09:15+0000\n"
|
||||
"POT-Creation-Date: 2017-11-25 12:17+0000\n"
|
||||
"PO-Revision-Date: 2017-11-25 12:17+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: \n"
|
||||
@@ -22,35 +22,76 @@ msgid "Asset category"
|
||||
msgstr "Categoría de activo"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: code:addons/account_asset_disposal/models/account_asset.py:88
|
||||
#: code:addons/account_asset_disposal/models/account_asset_asset.py:35
|
||||
#, python-format
|
||||
msgid "Asset depreciation"
|
||||
msgstr "Depreciación de activo"
|
||||
msgstr "Amortización del activo"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.model,name:account_asset_disposal.model_account_asset_depreciation_line
|
||||
msgid "Asset depreciation line"
|
||||
msgstr "Línea de Depreciación de Activo"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: code:addons/account_asset_disposal/models/account_asset.py:77
|
||||
#: code:addons/account_asset_disposal/models/account_asset_asset.py:23
|
||||
#: model:ir.ui.view,arch_db:account_asset_disposal.account_asset_disposal_wizard_form
|
||||
#, python-format
|
||||
msgid "Asset disposal"
|
||||
msgstr "Baja de activo"
|
||||
msgstr "Baja del activo"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: code:addons/account_asset_disposal/models/account_asset.py:99
|
||||
#: code:addons/account_asset_disposal/models/account_asset_asset.py:158
|
||||
#, python-format
|
||||
msgid "Asset disposal cancelled."
|
||||
msgstr "Baja del activo cancelada."
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: code:addons/account_asset_disposal/models/account_asset_asset.py:123
|
||||
#, python-format
|
||||
msgid "Asset disposed."
|
||||
msgstr "Activo dado de baja."
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: code:addons/account_asset_disposal/models/account_asset_asset.py:46
|
||||
#, python-format
|
||||
msgid "Asset loss"
|
||||
msgstr "Pérdida valor de activo"
|
||||
msgstr "Pérdida del activo"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.model,name:account_asset_disposal.model_account_asset_asset
|
||||
msgid "Asset/Revenue Recognition"
|
||||
msgstr "Aceptación de pagos/Ingresos"
|
||||
msgstr "Activo/Reconocimiento de beneficio"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.ui.view,arch_db:account_asset_disposal.account_asset_disposal_wizard_form
|
||||
msgid "Close"
|
||||
msgstr "Cerrar"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.model.fields,field_description:account_asset_disposal.field_account_asset_disposal_wizard_create_uid
|
||||
msgid "Created by"
|
||||
msgstr "Creado por"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.model.fields,field_description:account_asset_disposal.field_account_asset_disposal_wizard_create_date
|
||||
msgid "Created on"
|
||||
msgstr "Creado el"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.model.fields,field_description:account_asset_disposal.field_account_asset_disposal_wizard_display_name
|
||||
msgid "Display Name"
|
||||
msgstr "Nombre a mostrar"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: code:addons/account_asset_disposal/models/account_asset_asset.py:130
|
||||
#, python-format
|
||||
msgid "Disposal Move"
|
||||
msgstr "Asiento de baja"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: code:addons/account_asset_disposal/models/account_asset_asset.py:133
|
||||
#, python-format
|
||||
msgid "Disposal Moves"
|
||||
msgstr "Asientos de baja"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.model.fields,field_description:account_asset_disposal.field_account_asset_asset_disposal_date
|
||||
#: model:ir.model.fields,field_description:account_asset_disposal.field_account_asset_disposal_wizard_disposal_date
|
||||
msgid "Disposal date"
|
||||
msgstr "Fecha de baja"
|
||||
|
||||
@@ -60,7 +101,49 @@ msgid "Disposal move"
|
||||
msgstr "Asiento de baja"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.model.fields,field_description:account_asset_disposal.field_account_asset_category_loss_account_id
|
||||
#: model:ir.ui.view,arch_db:account_asset_disposal.view_account_asset_asset_form
|
||||
msgid "Dispose"
|
||||
msgstr "Dar de baja"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: code:addons/account_asset_disposal/models/account_asset_asset.py:78
|
||||
#, python-format
|
||||
msgid "Dispose Asset"
|
||||
msgstr "Dar de baja activo"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.ui.view,arch_db:account_asset_disposal.account_asset_disposal_wizard_form
|
||||
msgid "Dispose asset"
|
||||
msgstr "Dar de baja activo"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.model.fields,field_description:account_asset_disposal.field_account_asset_disposal_wizard_id
|
||||
msgid "ID"
|
||||
msgstr "ID"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.model,name:account_asset_disposal.model_account_move_line
|
||||
msgid "Journal Item"
|
||||
msgstr "Apunte contable"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.model.fields,field_description:account_asset_disposal.field_account_asset_disposal_wizard___last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr "Última modificación en"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.model.fields,field_description:account_asset_disposal.field_account_asset_disposal_wizard_write_uid
|
||||
msgid "Last Updated by"
|
||||
msgstr "Última actualización por"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.model.fields,field_description:account_asset_disposal.field_account_asset_disposal_wizard_write_date
|
||||
msgid "Last Updated on"
|
||||
msgstr "Última actualización el"
|
||||
|
||||
#. module: account_asset_disposal
|
||||
#: model:ir.model.fields,field_description:account_asset_disposal.field_account_asset_category_account_loss_id
|
||||
#: model:ir.model.fields,field_description:account_asset_disposal.field_account_asset_disposal_wizard_loss_account_id
|
||||
msgid "Loss Account"
|
||||
msgstr "Cuenta de pérdidas"
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import account_asset
|
||||
from . import account_asset_category
|
||||
from . import account_asset_asset
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
|
||||
# Copyright 2017 Luis M. Ontalba - <luis.martinez@tecnativa.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
|
||||
class AccountAssetCategory(models.Model):
|
||||
_inherit = "account.asset.category"
|
||||
|
||||
def _default_loss_account_id(self):
|
||||
exp_type = self.env.ref('account.data_account_type_expenses')
|
||||
first_expense = self.env['account.account'].search([
|
||||
('internal_type', '=', 'other'),
|
||||
('user_type_id', '=', exp_type.id),
|
||||
], limit=1)
|
||||
return first_expense
|
||||
|
||||
loss_account_id = fields.Many2one(
|
||||
comodel_name="account.account", string="Loss Account", required=True,
|
||||
domain=[('internal_type', '=', 'other')],
|
||||
default=lambda self: self._default_loss_account_id())
|
||||
|
||||
|
||||
class AccountAssetAsset(models.Model):
|
||||
_inherit = "account.asset.asset"
|
||||
|
||||
state = fields.Selection(
|
||||
selection_add=[('disposed', 'Disposed')],
|
||||
)
|
||||
disposal_date = fields.Date(string="Disposal date")
|
||||
disposal_move_id = fields.Many2one(
|
||||
comodel_name='account.move', string="Disposal move")
|
||||
|
||||
def get_disposal_date(self):
|
||||
return fields.Date.context_today(self)
|
||||
|
||||
@api.multi
|
||||
def set_to_close(self):
|
||||
value_residual_prev = self.value_residual
|
||||
res = super(AccountAssetAsset, self).set_to_close()
|
||||
if res:
|
||||
date = self.get_disposal_date()
|
||||
loss_account = self.category_id.loss_account_id
|
||||
self.value_residual = value_residual_prev
|
||||
move = self.disposal_move_create(date, loss_account)
|
||||
res['res_id'] = move.id
|
||||
self.disposal_move_id = res['res_id']
|
||||
self.disposal_move_id.post()
|
||||
self.write({
|
||||
'state': 'disposed',
|
||||
'disposal_date': self.get_disposal_date(),
|
||||
})
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def action_disposal_undo(self):
|
||||
for asset in self.with_context(asset_disposal_undo=True):
|
||||
if asset.disposal_move_id:
|
||||
asset.disposal_move_id.button_cancel()
|
||||
asset.disposal_move_id.unlink()
|
||||
last_line = self.depreciation_line_ids[-1]
|
||||
last_line.move_id = False
|
||||
last_line.unlink()
|
||||
asset.state = 'open'
|
||||
asset.method_end = asset.category_id.method_end
|
||||
asset.method_number = asset.category_id.method_number
|
||||
asset.compute_depreciation_board()
|
||||
return self.write({
|
||||
'disposal_date': False,
|
||||
'disposal_move_id': False,
|
||||
})
|
||||
|
||||
def _disposal_line_asset_prepare(self, date, journal):
|
||||
return {
|
||||
'name': _('Asset disposal'),
|
||||
'journal_id': journal.id,
|
||||
'account_id': self.category_id.account_asset_id.id,
|
||||
'date': date,
|
||||
'debit': 0.0,
|
||||
'credit': self.value,
|
||||
}
|
||||
|
||||
def _disposal_line_depreciation_prepare(self, date, journal,
|
||||
depreciation_value):
|
||||
return {
|
||||
'name': _('Asset depreciation'),
|
||||
'journal_id': journal.id,
|
||||
'account_id': self.category_id.account_depreciation_id.id,
|
||||
'date': date,
|
||||
'debit': depreciation_value,
|
||||
'credit': 0.0,
|
||||
}
|
||||
|
||||
def _disposal_line_loss_prepare(self, date, journal, loss_account,
|
||||
loss_value):
|
||||
return {
|
||||
'name': _('Asset loss'),
|
||||
'journal_id': journal.id,
|
||||
'account_id': loss_account.id,
|
||||
'analytic_account_id': self.category_id.account_analytic_id.id,
|
||||
'date': date,
|
||||
'debit': loss_value,
|
||||
'credit': 0.0,
|
||||
}
|
||||
|
||||
def _disposal_move_prepare(self, date, loss_account):
|
||||
journal = self.category_id.journal_id
|
||||
loss_value = self.salvage_value + self.value_residual
|
||||
depreciation_value = self.value - loss_value
|
||||
line_asset = self._disposal_line_asset_prepare(date, journal)
|
||||
line_depreciation = self._disposal_line_depreciation_prepare(
|
||||
date, journal, depreciation_value)
|
||||
lines = [
|
||||
(0, False, line_asset),
|
||||
(0, False, line_depreciation),
|
||||
]
|
||||
if loss_value:
|
||||
line_loss = self._disposal_line_loss_prepare(
|
||||
date, journal, loss_account, loss_value)
|
||||
lines.append((0, False, line_loss))
|
||||
return {
|
||||
'journal_id': journal.id,
|
||||
'ref': self.name,
|
||||
'date': date,
|
||||
'line_ids': lines,
|
||||
}
|
||||
|
||||
def disposal_move_create(self, date, loss_account):
|
||||
vals = self._disposal_move_prepare(date, loss_account)
|
||||
move = self.env['account.move'].create(vals)
|
||||
return move
|
||||
|
||||
|
||||
class AccountAssetDepreciationLine(models.Model):
|
||||
_inherit = 'account.asset.depreciation.line'
|
||||
|
||||
@api.multi
|
||||
def post_lines_and_close_asset(self):
|
||||
disposed_lines = self.filtered(lambda r: r.asset_id.state ==
|
||||
'disposed')
|
||||
super(AccountAssetDepreciationLine, self).post_lines_and_close_asset()
|
||||
disposed_lines.mapped('asset_id').write({'state': 'disposed'})
|
||||
166
account_asset_disposal/models/account_asset_asset.py
Normal file
166
account_asset_disposal/models/account_asset_asset.py
Normal file
@@ -0,0 +1,166 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Tecnativa - Antonio Espinosa
|
||||
# Copyright 2017 Tecnativa - Luis M. Ontalba
|
||||
# Copyright 2017 Tecnativa - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
|
||||
|
||||
class AccountAssetAsset(models.Model):
|
||||
_inherit = "account.asset.asset"
|
||||
|
||||
state = fields.Selection(
|
||||
selection_add=[('disposed', 'Disposed')],
|
||||
)
|
||||
disposal_date = fields.Date(string="Disposal date")
|
||||
disposal_move_id = fields.Many2one(
|
||||
comodel_name='account.move', string="Disposal move",
|
||||
)
|
||||
|
||||
def _disposal_line_asset_prepare(self, date):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'name': _('Asset disposal'),
|
||||
'journal_id': self.category_id.journal_id.id,
|
||||
'account_id': self.category_id.account_asset_id.id,
|
||||
'date': date,
|
||||
'debit': 0.0,
|
||||
'credit': self.value,
|
||||
}
|
||||
|
||||
def _disposal_line_depreciation_prepare(self, date):
|
||||
self.ensure_one()
|
||||
loss_value = self.salvage_value + self.value_residual
|
||||
depreciation_value = self.value - loss_value
|
||||
return {
|
||||
'name': _('Asset depreciation'),
|
||||
'journal_id': self.category_id.journal_id.id,
|
||||
'account_id': self.category_id.account_depreciation_id.id,
|
||||
'date': date,
|
||||
'debit': depreciation_value,
|
||||
'credit': 0.0,
|
||||
}
|
||||
|
||||
def _disposal_line_loss_prepare(self, date, loss_account):
|
||||
self.ensure_one()
|
||||
loss_value = self.salvage_value + self.value_residual
|
||||
return {
|
||||
'name': _('Asset loss'),
|
||||
'journal_id': self.category_id.journal_id.id,
|
||||
'account_id': loss_account.id,
|
||||
'analytic_account_id': self.category_id.account_analytic_id.id,
|
||||
'date': date,
|
||||
'debit': loss_value,
|
||||
'credit': 0.0,
|
||||
}
|
||||
|
||||
def _disposal_move_prepare(self, date, loss_account):
|
||||
self.ensure_one()
|
||||
journal = self.category_id.journal_id
|
||||
lines = [
|
||||
(0, False, self._disposal_line_asset_prepare(date)),
|
||||
(0, False, self._disposal_line_depreciation_prepare(date)),
|
||||
]
|
||||
loss_value = self.salvage_value + self.value_residual
|
||||
if loss_value:
|
||||
lines.append((
|
||||
0, False, self._disposal_line_loss_prepare(date, loss_account)
|
||||
))
|
||||
return {
|
||||
'journal_id': journal.id,
|
||||
'ref': self.name,
|
||||
'date': date,
|
||||
'line_ids': lines,
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def action_disposal(self):
|
||||
wizard_view_id = self.env.ref(
|
||||
'account_asset_disposal.account_asset_disposal_wizard_form')
|
||||
return {
|
||||
'name': _('Dispose Asset'),
|
||||
'res_model': 'account.asset.disposal.wizard',
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_type': 'tree,form',
|
||||
'view_mode': 'form',
|
||||
'view_id': wizard_view_id.id,
|
||||
'target': 'new',
|
||||
'context': self.env.context,
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def dispose(self, date, loss_account):
|
||||
moves = self.env['account.move']
|
||||
for asset in self:
|
||||
move = self.env['account.move'].create(
|
||||
asset._disposal_move_prepare(date, loss_account)
|
||||
)
|
||||
asset.disposal_move_id = move.id
|
||||
move.post()
|
||||
unposted_lines = asset.depreciation_line_ids.filtered(
|
||||
lambda x: not x.move_check
|
||||
)
|
||||
if unposted_lines:
|
||||
# Remove all unposted depreciation lines
|
||||
asset.write({
|
||||
'depreciation_line_ids': [
|
||||
(2, line_id.id) for line_id in unposted_lines
|
||||
],
|
||||
})
|
||||
# Create a new depr. line with the residual amount and post it
|
||||
sequence = (
|
||||
len(asset.depreciation_line_ids) - len(unposted_lines) + 1
|
||||
)
|
||||
vals = {
|
||||
'amount': asset.value_residual,
|
||||
'asset_id': asset.id,
|
||||
'sequence': sequence,
|
||||
'name': (asset.code or '') + '/' + str(sequence),
|
||||
'remaining_value': 0,
|
||||
# the asset is completely depreciated
|
||||
'depreciated_value': asset.value - asset.salvage_value,
|
||||
'depreciation_date': date,
|
||||
'move_id': move.id,
|
||||
}
|
||||
asset.depreciation_line_ids.create(vals)
|
||||
asset.message_post(body=_('Asset disposed.'))
|
||||
moves += move
|
||||
self.write({
|
||||
'disposal_date': date,
|
||||
'state': 'disposed',
|
||||
})
|
||||
if moves:
|
||||
name = _('Disposal Move')
|
||||
view_mode = 'form'
|
||||
if len(moves) > 1:
|
||||
name = _('Disposal Moves')
|
||||
view_mode = 'tree,form'
|
||||
return {
|
||||
'name': name,
|
||||
'domain': [('id', 'in', moves.ids)],
|
||||
'view_type': 'form',
|
||||
'view_mode': view_mode,
|
||||
'res_model': 'account.move',
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'current',
|
||||
'res_id': moves[:1].id,
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def action_disposal_undo(self):
|
||||
for asset in self.with_context(asset_disposal_undo=True):
|
||||
if asset.disposal_move_id:
|
||||
asset.disposal_move_id.button_cancel()
|
||||
asset.disposal_move_id.unlink()
|
||||
asset.depreciation_line_ids[-1].unlink()
|
||||
if asset.currency_id.is_zero(asset.value_residual):
|
||||
asset.state = 'close'
|
||||
else:
|
||||
asset.state = 'open'
|
||||
asset.compute_depreciation_board()
|
||||
asset.message_post(body=_('Asset disposal cancelled.'))
|
||||
return self.write({
|
||||
'disposal_date': False,
|
||||
'disposal_move_id': False,
|
||||
})
|
||||
15
account_asset_disposal/models/account_asset_category.py
Normal file
15
account_asset_disposal/models/account_asset_category.py
Normal file
@@ -0,0 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Tecnativa - Antonio Espinosa
|
||||
# Copyright 2017 Tecnativa - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class AccountAssetCategory(models.Model):
|
||||
_inherit = "account.asset.category"
|
||||
|
||||
account_loss_id = fields.Many2one(
|
||||
comodel_name="account.account", string="Loss Account",
|
||||
oldname='loss_account_id',
|
||||
)
|
||||
@@ -1,72 +1,91 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Tecnativa - Luis M. Ontalba - <luis.martinez@tecnativa.com>
|
||||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0
|
||||
# Copyright 2016 Tecnativa - Antonio Espinosa
|
||||
# Copyright 2017 Tecnativa - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo.tests import common
|
||||
from odoo import fields
|
||||
from datetime import datetime
|
||||
from odoo.tests import common
|
||||
|
||||
|
||||
class TestAccountAssetDisposal(common.SavepointCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestAccountAssetDisposal, cls).setUpClass()
|
||||
cls.journal = cls.env['account.journal'].create({
|
||||
'name': 'Test Journal',
|
||||
class TestAccountAsset(common.TransactionCase):
|
||||
def setUp(self):
|
||||
super(TestAccountAsset, self).setUp()
|
||||
# Create a journal for assets
|
||||
self.journal_asset = self.env['account.journal'].create({
|
||||
'name': 'Asset journal',
|
||||
'code': 'JRNL',
|
||||
'type': 'general',
|
||||
'code': 'TJ',
|
||||
'update_posted': True,
|
||||
})
|
||||
cls.account_type = cls.env['account.account.type'].create({
|
||||
'name': 'Test Account Type',
|
||||
# Create an account for assets
|
||||
self.account_asset = self.env['account.account'].create({
|
||||
'name': 'Asset',
|
||||
'code': '216x',
|
||||
'user_type_id': (
|
||||
self.env.ref('account.data_account_type_fixed_assets').id
|
||||
),
|
||||
})
|
||||
cls.asset_account = cls.env['account.account'].create({
|
||||
'code': 'TAA',
|
||||
'name': 'Test Asset Account',
|
||||
'internal_type': 'other',
|
||||
'user_type_id': cls.account_type.id,
|
||||
# Create an account for assets depreciation
|
||||
self.account_asset_depreciation = self.env['account.account'].create({
|
||||
'name': 'Asset depreciation',
|
||||
'code': '2816x',
|
||||
'user_type_id': (
|
||||
self.env.ref('account.data_account_type_fixed_assets').id
|
||||
),
|
||||
})
|
||||
cls.asset_category_number = cls.env['account.asset.category'].create({
|
||||
'name': 'Test Category Number',
|
||||
'journal_id': cls.journal.id,
|
||||
'account_asset_id': cls.asset_account.id,
|
||||
'account_depreciation_id': cls.asset_account.id,
|
||||
'account_depreciation_expense_id': cls.asset_account.id,
|
||||
'method_time': 'number',
|
||||
# Create an account for assets expense
|
||||
self.account_asset_expense = self.env['account.account'].create({
|
||||
'name': 'Asset expense',
|
||||
'code': '681x',
|
||||
'user_type_id': (
|
||||
self.env.ref('account.data_account_type_expenses').id
|
||||
),
|
||||
})
|
||||
# Create an account for assets loss
|
||||
self.account_asset_loss = self.env['account.account'].create({
|
||||
'name': 'Asset loss',
|
||||
'code': '671x',
|
||||
'user_type_id': (
|
||||
self.env.ref('account.data_account_type_expenses').id
|
||||
),
|
||||
})
|
||||
# Create an asset category
|
||||
self.asset_category = self.env['account.asset.category'].create({
|
||||
'name': 'Asset category for testing',
|
||||
'journal_id': self.journal_asset.id,
|
||||
'account_asset_id': self.account_asset.id,
|
||||
'account_depreciation_id': self.account_asset_depreciation.id,
|
||||
'account_depreciation_expense_id': self.account_asset_expense.id,
|
||||
'account_loss_id': self.account_asset_loss.id,
|
||||
})
|
||||
# Create an invoice
|
||||
self.asset = self.env['account.asset.asset'].create({
|
||||
'name': 'Test Asset',
|
||||
'value': 100.00,
|
||||
'category_id': self.asset_category.id,
|
||||
'method_number': 10,
|
||||
'method_period': 12,
|
||||
'method': 'linear',
|
||||
})
|
||||
cls.asset = cls.env['account.asset.asset'].create({
|
||||
'name': 'Test Asset Number',
|
||||
'category_id': cls.asset_category_number.id,
|
||||
'value': 16000.0,
|
||||
'salvage_value': 1000.0,
|
||||
'method_number': 15,
|
||||
self.asset.validate()
|
||||
|
||||
def test_asset_disposal(self):
|
||||
self.assertEqual(len(self.asset.depreciation_line_ids), 10)
|
||||
# Depreciate the first line
|
||||
self.asset.depreciation_line_ids[0].create_move()
|
||||
# Dispose asset
|
||||
disposal_date = fields.Date.today()
|
||||
wizard = self.env['account.asset.disposal.wizard'].with_context(
|
||||
active_ids=self.asset.ids, active_id=self.asset.id,
|
||||
).create({
|
||||
'disposal_date': disposal_date,
|
||||
})
|
||||
cls.asset.validate()
|
||||
cls.date_time = fields.Date.to_string(datetime.now())
|
||||
|
||||
def test_asset_depreciation_board(self):
|
||||
self.assertEqual(len(self.asset.depreciation_line_ids), 15)
|
||||
self.first_line = self.asset.depreciation_line_ids[0]
|
||||
self.assertEqual(self.first_line.depreciated_value, 1000.0)
|
||||
self.assertEqual(self.first_line.remaining_value, 14000.0)
|
||||
|
||||
def test_asset_unamortized(self):
|
||||
self.asset.set_to_close()
|
||||
self.assertTrue(self.asset.disposal_move_id)
|
||||
self.assertEqual(self.asset.disposal_date, self.date_time)
|
||||
self.assertEqual(wizard.loss_account_id, self.account_asset_loss)
|
||||
wizard.action_dispose()
|
||||
self.assertEqual(self.asset.disposal_date, disposal_date)
|
||||
self.assertEqual(self.asset.state, 'disposed')
|
||||
self.assertEqual(len(self.asset.depreciation_line_ids), 2)
|
||||
self.assertTrue(self.asset.disposal_move_id)
|
||||
self.assertEqual('posted', self.asset.disposal_move_id.state)
|
||||
self.assertEqual(self.asset.value, self.asset.disposal_move_id.amount)
|
||||
self.asset.action_disposal_undo()
|
||||
self.assertEqual(self.asset.state, 'open')
|
||||
self.assertEqual(self.asset.method_end,
|
||||
self.asset.category_id.method_end)
|
||||
self.assertEqual(self.asset.method_number,
|
||||
self.asset.category_id.method_number)
|
||||
|
||||
def test_asset_amortized(self):
|
||||
self.asset.depreciation_line_ids.create_move()
|
||||
for line in self.asset.depreciation_line_ids:
|
||||
line.move_id.post()
|
||||
self.assertEqual(self.asset.state, 'close')
|
||||
self.assertEqual(len(self.asset.depreciation_line_ids), 10)
|
||||
|
||||
@@ -1,33 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- Copyright 2016 Tecnativa - Antonio Espinosa
|
||||
Copyright 2017 Tecnativa - Pedro M. Baeza
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
|
||||
<odoo>
|
||||
|
||||
<record model="ir.ui.view" id="view_account_asset_category_form">
|
||||
<field name="name">Add loss account</field>
|
||||
<field name="model">account.asset.category</field>
|
||||
<field name="inherit_id" ref="account_asset.view_account_asset_category_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="account_depreciation_expense_id"
|
||||
position="after">
|
||||
<div>
|
||||
<label for="loss_account_id"/>
|
||||
</div>
|
||||
<field name="loss_account_id" nolabel="1"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_account_asset_asset_form">
|
||||
<field name="name">Add disposal fields</field>
|
||||
<field name="model">account.asset.asset</field>
|
||||
<field name="inherit_id"
|
||||
ref="account_asset.view_account_asset_asset_form"/>
|
||||
<field name="inherit_id" ref="account_asset.view_account_asset_asset_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<button name="compute_depreciation_board" position="attributes">
|
||||
<attribute name="attrs">{
|
||||
'invisible':[('state', '!=', 'draft')]}</attribute>
|
||||
<button name="set_to_close" position="attributes">
|
||||
<attribute name='invisible'>1</attribute>
|
||||
</button>
|
||||
<button name="set_to_close" position="after">
|
||||
<button name="action_disposal"
|
||||
states="open,close"
|
||||
string="Dispose"
|
||||
type="object"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
<button name="action_disposal_undo"
|
||||
states="disposed"
|
||||
string="Undo disposal"
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2017 Tecnativa - Pedro M. Baeza
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
|
||||
<odoo>
|
||||
|
||||
<record model="ir.ui.view" id="view_account_asset_category_form">
|
||||
<field name="name">Add loss account</field>
|
||||
<field name="model">account.asset.category</field>
|
||||
<field name="inherit_id" ref="account_asset.view_account_asset_category_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="account_depreciation_expense_id" position="after">
|
||||
<field name="account_loss_id"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
4
account_asset_disposal/wizards/__init__.py
Normal file
4
account_asset_disposal/wizards/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import account_asset_disposal_wizard
|
||||
@@ -0,0 +1,36 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Tecnativa - Antonio Espinosa
|
||||
# Copyright 2017 Tecnativa - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class AccountAssetDisposalWizard(models.TransientModel):
|
||||
_name = 'account.asset.disposal.wizard'
|
||||
|
||||
def _default_disposal_date(self):
|
||||
return fields.Date.context_today(self)
|
||||
|
||||
def _default_loss_account_id(self):
|
||||
asset = self.env['account.asset.asset'].browse(
|
||||
self.env.context.get('active_id', False)
|
||||
)
|
||||
return asset.category_id.account_loss_id.id
|
||||
|
||||
disposal_date = fields.Date(
|
||||
string="Disposal date", required=True,
|
||||
default=lambda self: self._default_disposal_date(),
|
||||
)
|
||||
loss_account_id = fields.Many2one(
|
||||
comodel_name='account.account', string="Loss Account", required=True,
|
||||
default=lambda self: self._default_loss_account_id(),
|
||||
)
|
||||
|
||||
@api.multi
|
||||
def action_dispose(self):
|
||||
self.ensure_one()
|
||||
assets = self.env['account.asset.asset'].browse(
|
||||
self.env.context.get('active_ids', False)
|
||||
)
|
||||
return assets.dispose(self.disposal_date, self.loss_account_id)
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record model="ir.ui.view" id="account_asset_disposal_wizard_form">
|
||||
<field name="name">account.asset.disposal.wizard.form</field>
|
||||
<field name="model">account.asset.disposal.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Asset disposal">
|
||||
<group>
|
||||
<field name="disposal_date"/>
|
||||
<field name="loss_account_id"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="action_dispose"
|
||||
string="Dispose asset"
|
||||
type="object" class="oe_highlight" />
|
||||
<button special="cancel" string="Close" class="oe_link" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
Reference in New Issue
Block a user