Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IMP] Ricarica del valore di un cespite per restituzione #4263

Open
wants to merge 1 commit into
base: 16.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions l10n_it_asset_management/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ Depreciations can be generated by using the related wizard found in
Assets -> Assets Management -> Generate Depreciations, or by triggering
the same wizard from a single asset form view.

When an asset is returned, it is possible to recharge its purchase and
fund amounts choosing "Partial Recharge" in the "Link to Asset" wizard
of the credit note. The wizard will allow to link to the credit note
only the assets of the refunded invoice.

**Italiano**

È possibile creare e gestire cespiti dalla sezione contabilità di Odoo.
Expand All @@ -63,6 +68,11 @@ contabili. Gli ammortamenti possono essere generati utilizzando
l'apposito wizard in Cespiti -> Gestione Cestpiti -> Genera
Ammortamenti, o aprendo quello stesso wizard dalla scheda del cespite.

Quando un cespite viene restituito, è possibile ricaricare gli importi
di acquisto e di fondo scegliendo "Ricarica parziale" nella procedura
"Collega a cespite" della nota di credito. La procedura consentirà di
collegare alla nota di credito solo i cespiti della fattura rimborsata.

Bug Tracker
===========

Expand Down Expand Up @@ -99,8 +109,7 @@ Contributors
- Nextev Srl <[email protected]>

Base icon made by `surang <https://www.flaticon.com/authors/surang>`__
from
[`www.flaticon.com](https://www.flaticon.com/) <http://www.flaticon.com](https://www.flaticon.com/)>`__.
from `www.flaticon.com <http://www.flaticon.com>`__.

Maintainers
-----------
Expand Down
1 change: 1 addition & 0 deletions l10n_it_asset_management/models/account_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ def open_wizard_manage_asset(self):
{
"default_company_id": self.company_id.id,
"default_dismiss_date": self.invoice_date or self.invoice_date_due,
"default_recharge_date": self.invoice_date or self.invoice_date_due,
"default_move_ids": [Command.set(self.ids)],
"default_move_line_ids": [Command.set(lines.ids)],
"default_purchase_date": self.invoice_date or self.invoice_date_due,
Expand Down
1 change: 1 addition & 0 deletions l10n_it_asset_management/models/asset_accounting_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class AssetAccountingInfo(models.Model):
relation_type = fields.Selection(
[
("create", "Asset Creation"),
("partial_recharge", "Partial Recharge"),
("update", "Asset Update"),
("partial_dismiss", "Asset Partial Dismissal"),
("dismiss", "Asset Dismissal"),
Expand Down
2 changes: 1 addition & 1 deletion l10n_it_asset_management/models/asset_depreciation.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ def _compute_last_depreciation_date(self):
for dep in self:
dep_lines = dep.line_ids.filtered(
lambda line: line.move_type == "depreciated"
and not line.partial_dismissal
and not (line.partial_dismissal or line.partial_recharge)
)
if dep_lines:
dep.last_depreciation_date = max(dep_lines.mapped("date"))
Expand Down
20 changes: 15 additions & 5 deletions l10n_it_asset_management/models/asset_depreciation_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class AssetDepreciationLine(models.Model):
)

partial_dismissal = fields.Boolean()
partial_recharge = fields.Boolean()

percentage = fields.Float(string="%")

Expand Down Expand Up @@ -265,9 +266,8 @@ def get_update_move_types(self):
def is_depreciation_nr_required(self):
"""Defines if a line requires to be numbered"""
self.ensure_one()
return (
self.move_type in self.get_numbered_move_types()
and not self.partial_dismissal
return self.move_type in self.get_numbered_move_types() and not (
self.partial_dismissal or self.partial_recharge
)

def make_name(self):
Expand Down Expand Up @@ -398,15 +398,22 @@ def get_depreciated_account_move_line_vals(self):
self.ensure_one()

# Asset depreciation
if not self.partial_dismissal:
if not (self.partial_dismissal or self.partial_recharge):
credit_account_id = self.asset_id.category_id.fund_account_id.id
debit_account_id = self.depreciation_id.depreciation_account_id.id

# Asset partial dismissal
else:
# Asset partial dismissal
debit_account_id = self.asset_id.category_id.fund_account_id.id
credit_account_id = self.asset_id.category_id.asset_account_id.id

# Asset partial recharge
if self.partial_recharge:
credit_account_id, debit_account_id = (
debit_account_id,
credit_account_id,
)

amt = abs(self.amount)
credit_line_vals = {
"account_id": credit_account_id,
Expand Down Expand Up @@ -499,3 +506,6 @@ def post_partial_dismiss_asset(self):
)
if to_create_move:
to_create_move.generate_account_move()

def post_partial_recharge_asset(self):
return self.post_partial_dismiss_asset()
6 changes: 6 additions & 0 deletions l10n_it_asset_management/readme/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Depreciations can be generated by using the related wizard found in
Assets -\> Assets Management -\> Generate Depreciations, or by
triggering the same wizard from a single asset form view.

When an asset is returned, it is possible to recharge its purchase and fund amounts choosing "Partial Recharge" in the "Link to Asset" wizard of the credit note.
The wizard will allow to link to the credit note only the assets of the refunded invoice.

**Italiano**

È possibile creare e gestire cespiti dalla sezione contabilità di Odoo.
Expand All @@ -22,3 +25,6 @@ I cespiti possono essere creati manualmente o da fatture e registrazioni
contabili. Gli ammortamenti possono essere generati utilizzando
l'apposito wizard in Cespiti -\> Gestione Cestpiti -\> Genera
Ammortamenti, o aprendo quello stesso wizard dalla scheda del cespite.

Quando un cespite viene restituito, è possibile ricaricare gli importi di acquisto e di fondo scegliendo "Ricarica parziale" nella procedura "Collega a cespite" della nota di credito.
La procedura consentirà di collegare alla nota di credito solo i cespiti della fattura rimborsata.
4 changes: 2 additions & 2 deletions l10n_it_asset_management/report/asset_journal.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ def get_report_dep_line_year_data(self):
line.amount
for line in self.dep_line_ids.filtered(
lambda line: line.move_type == "depreciated"
and not line.partial_dismissal
and not (line.partial_dismissal or line.partial_recharge)
)
]
)
Expand All @@ -737,7 +737,7 @@ def get_report_dep_line_year_data(self):
line.amount
for line in self.dep_line_ids.filtered(
lambda line: line.move_type == "depreciated"
and line.partial_dismissal
and (line.partial_dismissal or line.partial_recharge)
)
]
)
Expand Down
8 changes: 5 additions & 3 deletions l10n_it_asset_management/report/asset_previsional.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,9 @@ def generate_structure(self):
if fyear.date_to >= dep.date_start:
prev = not lines or not any(
line.move_type == "depreciated"
and not line.partial_dismissal
and not (
line.partial_dismissal or line.partial_recharge
)
for line in lines
)
sequence += 1
Expand Down Expand Up @@ -797,7 +799,7 @@ def get_report_dep_line_year_data(self):
line.amount
for line in self.dep_line_ids.filtered(
lambda line: line.move_type == "depreciated"
and not line.partial_dismissal
and not (line.partial_dismissal or line.partial_recharge)
)
]
)
Expand All @@ -806,7 +808,7 @@ def get_report_dep_line_year_data(self):
line.amount
for line in self.dep_line_ids.filtered(
lambda line: line.move_type == "depreciated"
and line.partial_dismissal
and (line.partial_dismissal or line.partial_recharge)
)
]
)
Expand Down
11 changes: 9 additions & 2 deletions l10n_it_asset_management/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,10 @@ <h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
Depreciations can be generated by using the related wizard found in
Assets -&gt; Assets Management -&gt; Generate Depreciations, or by triggering
the same wizard from a single asset form view.</p>
<p>When an asset is returned, it is possible to recharge its purchase and
fund amounts choosing “Partial Recharge” in the “Link to Asset” wizard
of the credit note. The wizard will allow to link to the credit note
only the assets of the refunded invoice.</p>
<p><strong>Italiano</strong></p>
<p>È possibile creare e gestire cespiti dalla sezione contabilità di Odoo.</p>
<p>La configurazione dei cespiti dev’essere fatta andando in Cespiti -&gt;
Expand All @@ -403,6 +407,10 @@ <h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
contabili. Gli ammortamenti possono essere generati utilizzando
l’apposito wizard in Cespiti -&gt; Gestione Cestpiti -&gt; Genera
Ammortamenti, o aprendo quello stesso wizard dalla scheda del cespite.</p>
<p>Quando un cespite viene restituito, è possibile ricaricare gli importi
di acquisto e di fondo scegliendo “Ricarica parziale” nella procedura
“Collega a cespite” della nota di credito. La procedura consentirà di
collegare alla nota di credito solo i cespiti della fattura rimborsata.</p>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
Expand Down Expand Up @@ -438,8 +446,7 @@ <h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<li>Nextev Srl &lt;<a class="reference external" href="mailto:odoo&#64;nextev.it">odoo&#64;nextev.it</a>&gt;</li>
</ul>
<p>Base icon made by <a class="reference external" href="https://www.flaticon.com/authors/surang">surang</a>
from
[<a class="reference external" href="http://www.flaticon.com](https://www.flaticon.com/)">www.flaticon.com](https://www.flaticon.com/)</a>.</p>
from <a class="reference external" href="http://www.flaticon.com">www.flaticon.com</a>.</p>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
Expand Down
21 changes: 21 additions & 0 deletions l10n_it_asset_management/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,27 @@ def _create_entry(self, account, amount, post=True):
self.assertEqual(entry.move_type, "entry")
return entry

def _refund_move(self, move, method="cancel", ref_date=None):
reverse_context = {
"active_model": move._name,
"active_ids": move.ids,
}
refund_wizard_form = Form(
self.env["account.move.reversal"].with_context(**reverse_context)
)
refund_wizard_form.reason = "test"
if ref_date:
refund_wizard_form.date_mode = "custom"
refund_wizard_form.date = ref_date
refund_wizard_form.refund_method = method
refund_wizard = refund_wizard_form.save()

refund_action = refund_wizard.reverse_moves()
refund_move = self.env[refund_action["res_model"]].browse(
refund_action["res_id"]
)
return refund_move

def _civil_depreciate_asset(self, asset):
# Keep only one civil depreciation
civil_depreciation_type = self.env.ref(
Expand Down
131 changes: 131 additions & 0 deletions l10n_it_asset_management/tests/test_assets_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Copyright 2022 Simone Rubino - TAKOBI
# Copyright 2023 Simone Rubino - Aion Tech
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

import datetime
from datetime import date

from odoo import fields
Expand Down Expand Up @@ -731,3 +733,132 @@ def test_same_asset_report_residual_partial_depreciation(self):
self.assertEqual(
asset_report_depreciation_line.amount_residual, expected_residual_amount
)

def test_purchase_sale_refund_recharge(self):
"""A sale refund can be used to restore asset value."""
# Create with purchase
purchase_amount = 2500
purchase_invoice = self._create_purchase_invoice(
datetime.date(2020, month=1, day=1), amount=purchase_amount
)
asset = self._link_asset_move(
purchase_invoice,
"create",
{
"category_id": self.asset_category_1,
"name": "Test recharge asset",
},
)
civ_depreciation = asset.depreciation_ids.filtered(
lambda x: x.type_id
== self.env.ref("l10n_it_asset_management.ad_type_civilistico")
)
self.assertEqual(civ_depreciation.amount_depreciable_updated, purchase_amount)

# Partial dismiss with sale
asset_account_amount = asset_fund_amount = 1000
sale_invoice = self._create_sale_invoice(
asset, amount=8000, invoice_date=datetime.date(2020, month=3, day=1)
)
self._link_asset_move(
sale_invoice,
"partial_dismiss",
wiz_values={
"asset_id": asset,
"depreciated_fund_amount": asset_account_amount,
"asset_purchase_amount": asset_fund_amount,
},
)
civ_depreciation_lines = civ_depreciation.line_ids
self.assertRecordValues(
civ_depreciation_lines.sorted("move_type"),
[
{
"move_type": "depreciated",
"amount": -1000.0,
},
{
"move_type": "gain",
"amount": 8000.0,
},
{
"move_type": "out",
"amount": 1000.0,
},
],
)
civ_depreciation_move_lines = civ_depreciation_lines.filtered(
lambda cdl: cdl.move_type == "depreciated"
).move_id.line_ids
self.assertRecordValues(
civ_depreciation_move_lines.sorted("balance"),
[
{
"account_id": asset.category_id.asset_account_id.id,
"balance": -1000,
},
{
"account_id": asset.category_id.fund_account_id.id,
"balance": 1000,
},
],
)
self.assertEqual(
civ_depreciation.amount_depreciable_updated,
purchase_amount - asset_account_amount,
)

# Refund and recharge
sale_refund = self._refund_move(
sale_invoice, ref_date=datetime.date(2020, month=7, day=1)
)
recharge_purchase_amount = recharge_fund_amount = 1000
wizard = self._get_move_asset_wizard(
sale_refund,
"partial_recharge",
wiz_values={
"recharge_purchase_amount": recharge_purchase_amount,
"recharge_fund_amount": recharge_fund_amount,
},
)
wizard.link_asset()
self.assertEqual(wizard.asset_id, asset)
self.assertEqual(wizard.allowed_asset_ids, asset)
civ_depreciation_lines = civ_depreciation.line_ids - civ_depreciation_lines
self.assertRecordValues(
civ_depreciation_lines.sorted("move_type"),
[
{
"move_type": "depreciated",
"amount": 1000.0,
},
{
"move_type": "in",
"amount": 1000.0,
},
{
"move_type": "loss",
"amount": 8000.0,
},
],
)
civ_depreciation_move_lines = civ_depreciation_lines.filtered(
lambda cdl: cdl.move_type == "depreciated"
).move_id.line_ids
self.assertRecordValues(
civ_depreciation_move_lines.sorted("balance"),
[
{
"account_id": asset.category_id.fund_account_id.id,
"balance": -1000,
},
{
"account_id": asset.category_id.asset_account_id.id,
"balance": 1000,
},
],
)
self.assertEqual(
civ_depreciation.amount_depreciable_updated,
purchase_amount,
)
12 changes: 11 additions & 1 deletion l10n_it_asset_management/views/account_move.xml
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,19 @@
/>
<field name="force_dep_nr" invisible="1" />
<field name="partial_dismissal" invisible="1" />
<field name="partial_recharge" invisible="1" />
<field
name="depreciation_nr"
attrs="{'invisible': [('force_dep_nr', '=', False), '|', ('partial_dismissal', '=', True), ('move_type', 'not in', ('depreciated', 'historical'))]}"
attrs="{
'invisible': [
('force_dep_nr', '=', False),
'|',
'|',
('partial_dismissal', '=', True),
('partial_recharge', '=', True),
('move_type', 'not in', ('depreciated', 'historical')),
],
}"
/>
<field name="amount" widget="monetary" />
<field name="requires_account_move" invisible="1" />
Expand Down
Loading
Loading