feat(fusion_accounting_reports): reports_service.js reactive frontend service
Made-with: Cursor
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
'name': 'Fusion Accounting Reports',
|
'name': 'Fusion Accounting Reports',
|
||||||
'version': '19.0.1.0.22',
|
'version': '19.0.1.0.23',
|
||||||
'category': 'Accounting/Accounting',
|
'category': 'Accounting/Accounting',
|
||||||
'summary': 'AI-augmented financial reports (P&L, balance sheet, trial balance, GL).',
|
'summary': 'AI-augmented financial reports (P&L, balance sheet, trial balance, GL).',
|
||||||
'description': """
|
'description': """
|
||||||
@@ -42,6 +42,7 @@ menu hides; the engine and AI tools remain available for the chat.
|
|||||||
'fusion_accounting_reports/static/src/scss/_variables.scss',
|
'fusion_accounting_reports/static/src/scss/_variables.scss',
|
||||||
'fusion_accounting_reports/static/src/scss/reports.scss',
|
'fusion_accounting_reports/static/src/scss/reports.scss',
|
||||||
'fusion_accounting_reports/static/src/scss/dark_mode.scss',
|
'fusion_accounting_reports/static/src/scss/dark_mode.scss',
|
||||||
|
'fusion_accounting_reports/static/src/services/reports_service.js',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'installable': True,
|
'installable': True,
|
||||||
|
|||||||
147
fusion_accounting_reports/static/src/services/reports_service.js
Normal file
147
fusion_accounting_reports/static/src/services/reports_service.js
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/** @odoo-module **/
|
||||||
|
|
||||||
|
import { registry } from "@web/core/registry";
|
||||||
|
import { reactive } from "@odoo/owl";
|
||||||
|
|
||||||
|
const ENDPOINT_BASE = "/fusion/reports";
|
||||||
|
|
||||||
|
export class ReportsService {
|
||||||
|
constructor(env, services) {
|
||||||
|
this.env = env;
|
||||||
|
this.rpc = services.rpc;
|
||||||
|
this.notification = services.notification;
|
||||||
|
|
||||||
|
this.state = reactive({
|
||||||
|
availableReports: [],
|
||||||
|
currentReportType: null,
|
||||||
|
currentResult: null,
|
||||||
|
currentAnomalies: [],
|
||||||
|
currentCommentary: null,
|
||||||
|
isLoading: false,
|
||||||
|
isGeneratingCommentary: false,
|
||||||
|
dateFrom: null,
|
||||||
|
dateTo: null,
|
||||||
|
comparison: 'none',
|
||||||
|
companyId: null,
|
||||||
|
drillDown: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadAvailableReports(companyId = null) {
|
||||||
|
this.state.companyId = companyId;
|
||||||
|
this.state.isLoading = true;
|
||||||
|
try {
|
||||||
|
const result = await this.rpc(`${ENDPOINT_BASE}/list_available`,
|
||||||
|
{ company_id: companyId });
|
||||||
|
this.state.availableReports = result.reports;
|
||||||
|
} finally {
|
||||||
|
this.state.isLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async runReport(reportType, dateFrom, dateTo, comparison = 'none') {
|
||||||
|
this.state.isLoading = true;
|
||||||
|
this.state.currentReportType = reportType;
|
||||||
|
this.state.dateFrom = dateFrom;
|
||||||
|
this.state.dateTo = dateTo;
|
||||||
|
this.state.comparison = comparison;
|
||||||
|
try {
|
||||||
|
this.state.currentResult = await this.rpc(`${ENDPOINT_BASE}/run`, {
|
||||||
|
report_type: reportType,
|
||||||
|
date_from: dateFrom,
|
||||||
|
date_to: dateTo,
|
||||||
|
comparison: comparison,
|
||||||
|
company_id: this.state.companyId,
|
||||||
|
});
|
||||||
|
if (comparison && comparison !== 'none') {
|
||||||
|
this.fetchAnomalies();
|
||||||
|
} else {
|
||||||
|
this.state.currentAnomalies = [];
|
||||||
|
}
|
||||||
|
this.state.currentCommentary = null;
|
||||||
|
return this.state.currentResult;
|
||||||
|
} catch (err) {
|
||||||
|
this.notification.add(`Run failed: ${err.message || err}`, { type: 'danger' });
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
this.state.isLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchAnomalies() {
|
||||||
|
if (!this.state.currentReportType) return;
|
||||||
|
try {
|
||||||
|
const result = await this.rpc(`${ENDPOINT_BASE}/get_anomalies`, {
|
||||||
|
report_type: this.state.currentReportType,
|
||||||
|
date_from: this.state.dateFrom,
|
||||||
|
date_to: this.state.dateTo,
|
||||||
|
comparison: this.state.comparison,
|
||||||
|
company_id: this.state.companyId,
|
||||||
|
});
|
||||||
|
this.state.currentAnomalies = result.anomalies || [];
|
||||||
|
} catch (err) {
|
||||||
|
this.state.currentAnomalies = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async generateCommentary({ forceRegenerate = false } = {}) {
|
||||||
|
if (!this.state.currentReportType) return;
|
||||||
|
this.state.isGeneratingCommentary = true;
|
||||||
|
try {
|
||||||
|
this.state.currentCommentary = await this.rpc(`${ENDPOINT_BASE}/get_commentary`, {
|
||||||
|
report_type: this.state.currentReportType,
|
||||||
|
date_from: this.state.dateFrom,
|
||||||
|
date_to: this.state.dateTo,
|
||||||
|
comparison: this.state.comparison,
|
||||||
|
company_id: this.state.companyId,
|
||||||
|
force_regenerate: forceRegenerate,
|
||||||
|
});
|
||||||
|
return this.state.currentCommentary;
|
||||||
|
} catch (err) {
|
||||||
|
this.notification.add(`Commentary failed: ${err.message || err}`, { type: 'danger' });
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
this.state.isGeneratingCommentary = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async drillDown(accountId, label = null) {
|
||||||
|
try {
|
||||||
|
const result = await this.rpc(`${ENDPOINT_BASE}/drill_down`, {
|
||||||
|
account_id: accountId,
|
||||||
|
date_from: this.state.dateFrom,
|
||||||
|
date_to: this.state.dateTo,
|
||||||
|
company_id: this.state.companyId,
|
||||||
|
});
|
||||||
|
this.state.drillDown = {
|
||||||
|
accountId, label, rows: result.rows || [],
|
||||||
|
count: result.count, isOpen: true,
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
} catch (err) {
|
||||||
|
this.notification.add(`Drill failed: ${err.message || err}`, { type: 'danger' });
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closeDrillDown() {
|
||||||
|
if (this.state.drillDown) {
|
||||||
|
this.state.drillDown.isOpen = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setComparison(mode) {
|
||||||
|
this.state.comparison = mode;
|
||||||
|
if (this.state.currentReportType) {
|
||||||
|
return this.runReport(this.state.currentReportType,
|
||||||
|
this.state.dateFrom, this.state.dateTo, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const reportsService = {
|
||||||
|
dependencies: ["rpc", "notification"],
|
||||||
|
start(env, services) { return new ReportsService(env, services); },
|
||||||
|
};
|
||||||
|
|
||||||
|
registry.category("services").add("fusion_reports", reportsService);
|
||||||
Reference in New Issue
Block a user