feat(fusion_accounting_assets): depreciation run wizard
Made-with: Cursor
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
'name': 'Fusion Accounting Assets',
|
||||
'version': '19.0.1.0.29',
|
||||
'version': '19.0.1.0.30',
|
||||
'category': 'Accounting/Accounting',
|
||||
'summary': 'AI-augmented asset management with depreciation schedules.',
|
||||
'description': """
|
||||
@@ -37,6 +37,7 @@ menu hides; the engine + AI tools remain available for the chat.
|
||||
'wizards/create_asset_wizard_views.xml',
|
||||
'wizards/disposal_wizard_views.xml',
|
||||
'wizards/partial_sale_wizard_views.xml',
|
||||
'wizards/depreciation_run_wizard_views.xml',
|
||||
],
|
||||
'assets': {
|
||||
'web.assets_backend': [
|
||||
|
||||
@@ -12,3 +12,4 @@ access_fusion_asset_anomaly_admin,fusion.asset.anomaly.admin,model_fusion_asset_
|
||||
access_fusion_create_asset_wizard_user,fusion.create.asset.wizard.user,model_fusion_create_asset_wizard,base.group_user,1,1,1,0
|
||||
access_fusion_disposal_wizard_user,fusion.disposal.wizard.user,model_fusion_disposal_wizard,base.group_user,1,1,1,0
|
||||
access_fusion_partial_sale_wizard_user,fusion.partial.sale.wizard.user,model_fusion_partial_sale_wizard,base.group_user,1,1,1,0
|
||||
access_fusion_depreciation_run_wizard_user,fusion.depreciation.run.wizard.user,model_fusion_depreciation_run_wizard,base.group_user,1,1,1,0
|
||||
|
||||
|
@@ -22,3 +22,4 @@ from . import test_performance_benchmarks
|
||||
from . import test_create_asset_wizard
|
||||
from . import test_disposal_wizard
|
||||
from . import test_partial_sale_wizard
|
||||
from . import test_depreciation_run_wizard
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
from datetime import date
|
||||
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestDepreciationRunWizard(TransactionCase):
|
||||
|
||||
def test_run_all_running_posts_due_periods(self):
|
||||
for amt in [3000, 5000]:
|
||||
asset = self.env['fusion.asset'].create({
|
||||
'name': f'Run Test {amt}', 'cost': amt,
|
||||
'acquisition_date': date(2026, 1, 1),
|
||||
'in_service_date': date(2026, 1, 1),
|
||||
'method': 'straight_line', 'useful_life_years': 3,
|
||||
})
|
||||
self.env['fusion.asset.engine'].compute_depreciation_schedule(asset)
|
||||
asset.action_set_running()
|
||||
wizard = self.env['fusion.depreciation.run.wizard'].create({
|
||||
'period_date': date(2030, 12, 31),
|
||||
'state_filter': 'all_running',
|
||||
})
|
||||
wizard.action_run()
|
||||
self.assertEqual(wizard.state, 'done')
|
||||
self.assertGreater(wizard.posted_count, 0)
|
||||
|
||||
def test_run_selected_posts_only_selected(self):
|
||||
asset = self.env['fusion.asset'].create({
|
||||
'name': 'Selected Test', 'cost': 1000,
|
||||
'acquisition_date': date(2026, 1, 1),
|
||||
'in_service_date': date(2026, 1, 1),
|
||||
'method': 'straight_line', 'useful_life_years': 3,
|
||||
})
|
||||
self.env['fusion.asset.engine'].compute_depreciation_schedule(asset)
|
||||
asset.action_set_running()
|
||||
wizard = self.env['fusion.depreciation.run.wizard'].create({
|
||||
'period_date': date(2030, 12, 31),
|
||||
'state_filter': 'selected',
|
||||
'asset_ids': [(6, 0, [asset.id])],
|
||||
})
|
||||
wizard.action_run()
|
||||
self.assertEqual(wizard.state, 'done')
|
||||
@@ -1,3 +1,4 @@
|
||||
from . import create_asset_wizard
|
||||
from . import disposal_wizard
|
||||
from . import partial_sale_wizard
|
||||
from . import depreciation_run_wizard
|
||||
|
||||
72
fusion_accounting_assets/wizards/depreciation_run_wizard.py
Normal file
72
fusion_accounting_assets/wizards/depreciation_run_wizard.py
Normal file
@@ -0,0 +1,72 @@
|
||||
"""Manual depreciation run wizard.
|
||||
|
||||
Operator picks a period_date and the wizard posts all running assets'
|
||||
unposted lines whose scheduled_date <= period_date."""
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class FusionDepreciationRunWizard(models.TransientModel):
|
||||
_name = "fusion.depreciation.run.wizard"
|
||||
_description = "Manual Depreciation Run Wizard"
|
||||
|
||||
period_date = fields.Date(
|
||||
required=True, default=fields.Date.today,
|
||||
help="Post all unposted lines whose scheduled_date is on or before this date.",
|
||||
)
|
||||
state_filter = fields.Selection([
|
||||
('all_running', 'All Running Assets'),
|
||||
('selected', 'Selected Asset(s) Only'),
|
||||
], default='all_running', required=True)
|
||||
asset_ids = fields.Many2many(
|
||||
'fusion.asset', domain=[('state', '=', 'running')],
|
||||
)
|
||||
|
||||
state = fields.Selection(
|
||||
[('draft', 'Draft'), ('done', 'Done')], default='draft',
|
||||
)
|
||||
posted_count = fields.Integer(readonly=True)
|
||||
skipped_count = fields.Integer(readonly=True)
|
||||
error_count = fields.Integer(readonly=True)
|
||||
summary = fields.Text(readonly=True)
|
||||
|
||||
def action_run(self):
|
||||
self.ensure_one()
|
||||
if self.state_filter == 'all_running':
|
||||
assets = self.env['fusion.asset'].search([
|
||||
('state', '=', 'running'),
|
||||
('company_id', '=', self.env.company.id),
|
||||
])
|
||||
else:
|
||||
assets = self.asset_ids
|
||||
|
||||
engine = self.env['fusion.asset.engine']
|
||||
posted = 0
|
||||
skipped = 0
|
||||
errors = []
|
||||
for asset in assets:
|
||||
try:
|
||||
with self.env.cr.savepoint():
|
||||
result = engine.post_depreciation_entry(
|
||||
asset, period_date=self.period_date,
|
||||
)
|
||||
posted += result.get('posted_count', 0)
|
||||
if result.get('posted_count', 0) == 0:
|
||||
skipped += 1
|
||||
except Exception as e: # noqa: BLE001
|
||||
errors.append(f"{asset.name}: {e}")
|
||||
|
||||
self.write({
|
||||
'state': 'done',
|
||||
'posted_count': posted,
|
||||
'skipped_count': skipped,
|
||||
'error_count': len(errors),
|
||||
'summary': '\n'.join(errors[:20]) if errors else False,
|
||||
})
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': self._name,
|
||||
'res_id': self.id,
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_fusion_depreciation_run_wizard_form" model="ir.ui.view">
|
||||
<field name="name">fusion.depreciation.run.wizard.form</field>
|
||||
<field name="model">fusion.depreciation.run.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Run Depreciation">
|
||||
<group invisible="state == 'done'">
|
||||
<field name="period_date"/>
|
||||
<field name="state_filter" widget="radio"/>
|
||||
<field name="asset_ids" widget="many2many_tags"
|
||||
invisible="state_filter != 'selected'"/>
|
||||
</group>
|
||||
<group invisible="state != 'done'" string="Results">
|
||||
<field name="posted_count"/>
|
||||
<field name="skipped_count"/>
|
||||
<field name="error_count"/>
|
||||
<field name="summary"/>
|
||||
</group>
|
||||
<field name="state" invisible="1"/>
|
||||
<footer>
|
||||
<button name="action_run" type="object" string="Run"
|
||||
class="btn-primary" invisible="state == 'done'"/>
|
||||
<button special="cancel" string="Close"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_fusion_depreciation_run_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Run Depreciation</field>
|
||||
<field name="res_model">fusion.depreciation.run.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user