Files
Odoo-Modules/fusion_accounting_assets/controllers/assets_controller.py
2026-04-19 17:14:22 -04:00

176 lines
8.1 KiB
Python

"""HTTP controller: 8 JSON-RPC endpoints for the OWL asset dashboard.
All endpoints route through fusion.asset.engine. V19 type='jsonrpc'.
"""
import logging
from datetime import date, datetime
from odoo import _, http
from odoo.exceptions import ValidationError
from odoo.http import request
_logger = logging.getLogger(__name__)
def _parse_date(value):
if isinstance(value, date):
return value
if not value:
return None
return datetime.strptime(value, '%Y-%m-%d').date()
class FusionAssetsController(http.Controller):
@http.route('/fusion/assets/list', type='jsonrpc', auth='user')
def list_assets(self, state=None, category_id=None, limit=50, offset=0,
company_id=None):
company_id = int(company_id) if company_id else request.env.company.id
Asset = request.env['fusion.asset'].sudo()
domain = [('company_id', '=', company_id)]
if state:
domain.append(('state', '=', state))
if category_id:
domain.append(('category_id', '=', int(category_id)))
total = Asset.search_count(domain)
assets = Asset.search(domain, limit=int(limit), offset=int(offset),
order='acquisition_date desc')
return {
'count': len(assets),
'total': total,
'assets': [{
'id': a.id, 'name': a.name, 'code': a.code or '',
'state': a.state, 'cost': a.cost, 'salvage_value': a.salvage_value,
'book_value': a.book_value, 'total_depreciated': a.total_depreciated,
'method': a.method, 'useful_life_years': a.useful_life_years,
'acquisition_date': str(a.acquisition_date),
'in_service_date': str(a.in_service_date) if a.in_service_date else None,
'category_id': a.category_id.id if a.category_id else None,
'category_name': a.category_id.name if a.category_id else None,
'currency_code': a.currency_id.name,
} for a in assets],
}
@http.route('/fusion/assets/get_detail', type='jsonrpc', auth='user')
def get_detail(self, asset_id):
asset = request.env['fusion.asset'].browse(int(asset_id))
if not asset.exists():
raise ValidationError(_("Asset %s not found") % asset_id)
return {
'asset': {
'id': asset.id, 'name': asset.name, 'code': asset.code or '',
'state': asset.state, 'cost': asset.cost,
'salvage_value': asset.salvage_value,
'book_value': asset.book_value,
'total_depreciated': asset.total_depreciated,
'method': asset.method,
'useful_life_years': asset.useful_life_years,
'declining_rate_pct': asset.declining_rate_pct,
'total_units_expected': asset.total_units_expected,
'units_used_to_date': asset.units_used_to_date,
'prorate_convention': asset.prorate_convention,
'acquisition_date': str(asset.acquisition_date),
'in_service_date': str(asset.in_service_date) if asset.in_service_date else None,
'disposed_date': str(asset.disposed_date) if asset.disposed_date else None,
'category_id': asset.category_id.id if asset.category_id else None,
'category_name': asset.category_id.name if asset.category_id else None,
'currency_id': asset.currency_id.id,
'currency_code': asset.currency_id.name,
},
'depreciation_lines': [{
'id': l.id, 'period_index': l.period_index,
'scheduled_date': str(l.scheduled_date),
'amount': l.amount, 'accumulated': l.accumulated,
'book_value_at_end': l.book_value_at_end,
'is_posted': l.is_posted,
'posted_date': str(l.posted_date) if l.posted_date else None,
} for l in asset.depreciation_line_ids.sorted('period_index')],
'anomalies': [{
'id': a.id, 'anomaly_type': a.anomaly_type,
'severity': a.severity, 'detail': a.detail or '',
'state': a.state,
} for a in request.env['fusion.asset.anomaly'].search([
('asset_id', '=', asset.id), ('state', 'in', ('new', 'acknowledged'))
])],
}
@http.route('/fusion/assets/compute_schedule', type='jsonrpc', auth='user')
def compute_schedule(self, asset_id, recompute=False):
asset = request.env['fusion.asset'].sudo().browse(int(asset_id))
engine = request.env['fusion.asset.engine'].sudo()
return engine.compute_depreciation_schedule(asset, recompute=bool(recompute))
@http.route('/fusion/assets/post_depreciation', type='jsonrpc', auth='user')
def post_depreciation(self, asset_id, period_date=None):
asset = request.env['fusion.asset'].sudo().browse(int(asset_id))
engine = request.env['fusion.asset.engine'].sudo()
return engine.post_depreciation_entry(asset, period_date=_parse_date(period_date))
@http.route('/fusion/assets/dispose', type='jsonrpc', auth='user')
def dispose(self, asset_id, sale_amount=0, sale_date=None,
sale_partner_id=None, disposal_type='sale'):
asset = request.env['fusion.asset'].sudo().browse(int(asset_id))
engine = request.env['fusion.asset.engine'].sudo()
partner = None
if sale_partner_id:
partner = request.env['res.partner'].sudo().browse(int(sale_partner_id))
return engine.dispose_asset(
asset, sale_amount=float(sale_amount),
sale_date=_parse_date(sale_date),
sale_partner=partner, disposal_type=disposal_type,
)
@http.route('/fusion/assets/get_anomalies', type='jsonrpc', auth='user')
def get_anomalies(self, asset_id=None, severity=None, state='new', limit=50,
company_id=None):
company_id = int(company_id) if company_id else request.env.company.id
Anomaly = request.env['fusion.asset.anomaly'].sudo()
domain = [('company_id', '=', company_id)]
if asset_id:
domain.append(('asset_id', '=', int(asset_id)))
if severity:
domain.append(('severity', '=', severity))
if state:
domain.append(('state', '=', state))
anomalies = Anomaly.search(domain, limit=int(limit), order='detected_at desc')
return {
'count': len(anomalies),
'anomalies': [{
'id': a.id, 'asset_id': a.asset_id.id, 'asset_name': a.asset_id.name,
'anomaly_type': a.anomaly_type, 'severity': a.severity,
'expected': a.expected, 'actual': a.actual,
'variance_pct': a.variance_pct, 'detail': a.detail or '',
'state': a.state,
'detected_at': str(a.detected_at),
} for a in anomalies],
}
@http.route('/fusion/assets/suggest_useful_life', type='jsonrpc', auth='user')
def suggest_useful_life(self, description, amount=None, partner_name=None):
from odoo.addons.fusion_accounting_assets.services.useful_life_predictor import (
predict_useful_life,
)
return predict_useful_life(
request.env, description=description,
amount=float(amount) if amount is not None else None,
partner_name=partner_name,
)
@http.route('/fusion/assets/get_partner_history', type='jsonrpc', auth='user')
def get_partner_history(self, partner_id, limit=20):
Asset = request.env['fusion.asset'].sudo()
assets = Asset.search([
('source_invoice_line_id.partner_id', '=', int(partner_id)),
], limit=int(limit), order='acquisition_date desc')
return {
'partner_id': int(partner_id),
'count': len(assets),
'assets': [{
'id': a.id, 'name': a.name,
'cost': a.cost, 'book_value': a.book_value,
'state': a.state,
'acquisition_date': str(a.acquisition_date),
} for a in assets],
}