feat(fusion_accounting_assets): asset_detail_panel component

Made-with: Cursor
This commit is contained in:
gsinghpal
2026-04-19 17:38:28 -04:00
parent bf8689716c
commit 7ba15c65aa
3 changed files with 85 additions and 1 deletions

View File

@@ -1,6 +1,6 @@
{
'name': 'Fusion Accounting Assets',
'version': '19.0.1.0.22',
'version': '19.0.1.0.23',
'category': 'Accounting/Accounting',
'summary': 'AI-augmented asset management with depreciation schedules.',
'description': """
@@ -46,6 +46,8 @@ menu hides; the engine + AI tools remain available for the chat.
'fusion_accounting_assets/static/src/views/asset_dashboard/asset_dashboard_view.js',
'fusion_accounting_assets/static/src/components/asset_card/asset_card.js',
'fusion_accounting_assets/static/src/components/asset_card/asset_card.xml',
'fusion_accounting_assets/static/src/components/asset_detail_panel/asset_detail_panel.js',
'fusion_accounting_assets/static/src/components/asset_detail_panel/asset_detail_panel.xml',
],
},
'installable': True,

View File

@@ -0,0 +1,36 @@
/** @odoo-module **/
import { Component } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
import { DepreciationBoard } from "../depreciation_board/depreciation_board";
export class AssetDetailPanel extends Component {
static template = "fusion_accounting_assets.AssetDetailPanel";
static props = {
detail: { type: Object },
formatCurrency: { type: Function },
};
static components = { DepreciationBoard };
setup() {
this.assets = useService("fusion_assets");
}
async onComputeSchedule() {
await this.assets.computeSchedule(this.props.detail.asset.id, false);
}
async onRecomputeSchedule() {
await this.assets.computeSchedule(this.props.detail.asset.id, true);
}
async onPostDepreciation() {
await this.assets.postDepreciation(this.props.detail.asset.id);
}
async onDispose() {
const saleAmount = parseFloat(prompt("Sale amount (0 for scrap)?", "0"));
if (isNaN(saleAmount)) return;
await this.assets.disposeAsset(this.props.detail.asset.id, { saleAmount });
}
}

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="fusion_accounting_assets.AssetDetailPanel">
<div style="background: white; padding: 1rem; border-radius: 0.5rem; border: 1px solid #e5e7eb;">
<h3><t t-esc="props.detail.asset.name"/></h3>
<div class="text-muted" t-if="props.detail.asset.code">
[<t t-esc="props.detail.asset.code"/>]
</div>
<div class="mt-3">
<div><strong>State:</strong> <t t-esc="props.detail.asset.state"/></div>
<div><strong>Cost:</strong> $<t t-esc="props.formatCurrency(props.detail.asset.cost)"/></div>
<div><strong>Salvage:</strong> $<t t-esc="props.formatCurrency(props.detail.asset.salvage_value)"/></div>
<div><strong>Book Value:</strong> $<t t-esc="props.formatCurrency(props.detail.asset.book_value)"/></div>
<div><strong>Total Depreciated:</strong> $<t t-esc="props.formatCurrency(props.detail.asset.total_depreciated)"/></div>
<div><strong>Method:</strong> <t t-esc="props.detail.asset.method"/></div>
<div><strong>Useful Life:</strong> <t t-esc="props.detail.asset.useful_life_years"/> years</div>
</div>
<div class="d-flex mt-3" style="gap: 0.5rem; flex-wrap: wrap;">
<button class="btn_asset" t-on-click="onComputeSchedule">Compute Schedule</button>
<button class="btn_asset" t-on-click="onRecomputeSchedule">Recompute</button>
<button class="btn_asset primary"
t-if="props.detail.asset.state === 'running'"
t-on-click="onPostDepreciation">Post Next</button>
<button class="btn_asset danger"
t-if="props.detail.asset.state !== 'disposed'"
t-on-click="onDispose">Dispose</button>
</div>
<h4 class="mt-4">Depreciation Schedule</h4>
<DepreciationBoard t-if="props.detail.depreciation_lines"
lines="props.detail.depreciation_lines"
formatCurrency="props.formatCurrency"/>
<div t-if="props.detail.anomalies and props.detail.anomalies.length" class="mt-3">
<h4>Active Anomalies</h4>
<div t-foreach="props.detail.anomalies" t-as="a" t-key="a.id"
class="o_fusion_anomaly_strip" t-att-data-severity="a.severity">
<strong><t t-esc="a.anomaly_type"/></strong>: <t t-esc="a.detail"/>
</div>
</div>
</div>
</t>
</templates>