mirror of
https://gitlab.com/flectra-community/mis-builder.git
synced 2024-11-16 19:22:04 +00:00
apply from old repository
apply from old repository
This commit is contained in:
parent
2125405b42
commit
dadcbbc470
@ -6,6 +6,7 @@ from collections import OrderedDict, defaultdict
|
|||||||
|
|
||||||
from flectra import _
|
from flectra import _
|
||||||
from flectra.exceptions import UserError
|
from flectra.exceptions import UserError
|
||||||
|
from flectra.tools import float_is_zero
|
||||||
|
|
||||||
from .accounting_none import AccountingNone
|
from .accounting_none import AccountingNone
|
||||||
from .mis_kpi_data import ACC_SUM
|
from .mis_kpi_data import ACC_SUM
|
||||||
@ -71,7 +72,8 @@ class KpiMatrixRow(object):
|
|||||||
|
|
||||||
def is_empty(self):
|
def is_empty(self):
|
||||||
for cell in self.iter_cells():
|
for cell in self.iter_cells():
|
||||||
if cell and cell.val not in (AccountingNone, None):
|
dp = cell and cell.row.kpi.env.user.company_id.currency_id.decimal_places or 6
|
||||||
|
if cell and not float_is_zero(cell.val, dp) and cell.val not in (AccountingNone, None):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -390,10 +390,15 @@ class MisReportQuery(models.Model):
|
|||||||
)
|
)
|
||||||
date_field = fields.Many2one(
|
date_field = fields.Many2one(
|
||||||
comodel_name="ir.model.fields",
|
comodel_name="ir.model.fields",
|
||||||
required=True,
|
required=False,
|
||||||
domain=[("ttype", "in", ("date", "datetime"))],
|
domain=[("ttype", "in", ("date", "datetime"))],
|
||||||
ondelete="restrict",
|
ondelete="restrict",
|
||||||
)
|
)
|
||||||
|
query_context = fields.Text(
|
||||||
|
string='Context',
|
||||||
|
translate=False,
|
||||||
|
default='{}',
|
||||||
|
)
|
||||||
domain = fields.Char(string="Domain")
|
domain = fields.Char(string="Domain")
|
||||||
report_id = fields.Many2one(
|
report_id = fields.Many2one(
|
||||||
comodel_name="mis.report", string="Report", required=True, ondelete="cascade"
|
comodel_name="mis.report", string="Report", required=True, ondelete="cascade"
|
||||||
@ -580,7 +585,21 @@ class MisReport(models.Model):
|
|||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
res = {}
|
res = {}
|
||||||
for query in self.query_ids:
|
for query in self.query_ids:
|
||||||
model = self.env[query.model_id.model]
|
eval_context = {
|
||||||
|
"env": self.env,
|
||||||
|
"fields": fields,
|
||||||
|
"time": time,
|
||||||
|
"datetime": datetime,
|
||||||
|
"dateutil": dateutil,
|
||||||
|
# deprecated
|
||||||
|
"uid": self.env.uid,
|
||||||
|
"context": self.env.context,
|
||||||
|
"date_from": date_from,
|
||||||
|
"date_to": date_to,
|
||||||
|
|
||||||
|
}
|
||||||
|
ctx = query.query_context and safe_eval(query.query_context, eval_context) or {}
|
||||||
|
model = self.env[query.model_id.model].with_context(ctx)
|
||||||
eval_context = {
|
eval_context = {
|
||||||
"env": self.env,
|
"env": self.env,
|
||||||
"time": time,
|
"time": time,
|
||||||
|
@ -534,6 +534,7 @@ class MisReportInstance(models.Model):
|
|||||||
)
|
)
|
||||||
landscape_pdf = fields.Boolean(string="Landscape PDF")
|
landscape_pdf = fields.Boolean(string="Landscape PDF")
|
||||||
no_auto_expand_accounts = fields.Boolean(string="Disable account details expansion")
|
no_auto_expand_accounts = fields.Boolean(string="Disable account details expansion")
|
||||||
|
use_external_layout = fields.Boolean(string='Use External Layout')
|
||||||
display_columns_description = fields.Boolean(
|
display_columns_description = fields.Boolean(
|
||||||
help="Display the date range details in the column headers."
|
help="Display the date range details in the column headers."
|
||||||
)
|
)
|
||||||
|
@ -20,7 +20,21 @@
|
|||||||
<template id="report_mis_report_instance">
|
<template id="report_mis_report_instance">
|
||||||
<t t-call="web.html_container">
|
<t t-call="web.html_container">
|
||||||
<t t-foreach="docs" t-as="o">
|
<t t-foreach="docs" t-as="o">
|
||||||
|
<t t-if="o.use_external_layout">
|
||||||
|
<t t-call="web.external_layout">
|
||||||
|
<t t-call="mis_builder.report_mis_report_instance_content"/>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
<t t-call="web.internal_layout">
|
<t t-call="web.internal_layout">
|
||||||
|
<t t-call="mis_builder.report_mis_report_instance_content"/>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template id="report_mis_report_instance_content">
|
||||||
<t t-set="matrix" t-value="o._compute_matrix()" />
|
<t t-set="matrix" t-value="o._compute_matrix()" />
|
||||||
<t t-set="style_obj" t-value="o.env['mis.report.style']" />
|
<t t-set="style_obj" t-value="o.env['mis.report.style']" />
|
||||||
<div class="page">
|
<div class="page">
|
||||||
@ -44,47 +58,42 @@
|
|||||||
</t>
|
</t>
|
||||||
</div>
|
</div>
|
||||||
</p>
|
</p>
|
||||||
<div class="mis_table">
|
<table class="table-condensed mis_table">
|
||||||
<div class="mis_thead">
|
<thead>
|
||||||
<div class="mis_row">
|
<tr>
|
||||||
<div class="mis_cell mis_collabel" />
|
<th/>
|
||||||
<t t-foreach="matrix.iter_cols()" t-as="col">
|
<t t-foreach="matrix.iter_cols()" t-as="col">
|
||||||
<div class="mis_cell mis_collabel">
|
<th class="mis_cell mis_collabel_group" t-att-colspan="len(list(col.iter_subcols()))">
|
||||||
<t t-esc="col.label" />
|
<t t-esc="col.label" />
|
||||||
<t t-if="col.description">
|
<t t-if="col.description">
|
||||||
<br />
|
<br />
|
||||||
<t t-esc="col.description" />
|
<t t-esc="col.description" />
|
||||||
</t>
|
</t>
|
||||||
</div>
|
</th>
|
||||||
<!-- add empty cells because we have no colspan with css tables -->
|
|
||||||
<t
|
|
||||||
t-foreach="list(col.iter_subcols())[1:]"
|
|
||||||
t-as="subcol"
|
|
||||||
>
|
|
||||||
<div class="mis_cell mis_collabel" />
|
|
||||||
</t>
|
</t>
|
||||||
</t>
|
</tr>
|
||||||
</div>
|
<tr>
|
||||||
<div class="mis_row">
|
<th/>
|
||||||
<div class="mis_cell mis_collabel" />
|
<t t-foreach="matrix.iter_cols()" t-as="col">
|
||||||
<t t-foreach="matrix.iter_subcols()" t-as="subcol">
|
<t t-foreach="col.iter_subcols()" t-as="subcol">
|
||||||
<div class="mis_cell mis_collabel">
|
<td t-attf-class="mis_cell mis_collabel {{subcol_first and 'mis_first' or ''}}">
|
||||||
<t t-esc="subcol.label" />
|
<t t-esc="subcol.label" />
|
||||||
<t t-if="subcol.description">
|
<t t-if="subcol.description">
|
||||||
<br />
|
<br />
|
||||||
<t t-esc="subcol.description" />
|
<t t-esc="subcol.description" />
|
||||||
</t>
|
</t>
|
||||||
</div>
|
</td>
|
||||||
</t>
|
</t>
|
||||||
</div>
|
</t>
|
||||||
</div>
|
</tr>
|
||||||
<div class="mis_tbody">
|
</thead>
|
||||||
|
<tbody>
|
||||||
<t t-foreach="matrix.iter_rows()" t-as="row">
|
<t t-foreach="matrix.iter_rows()" t-as="row">
|
||||||
<div
|
<tr
|
||||||
t-if="not ((row.style_props.hide_empty and row.is_empty()) or row.style_props.hide_always)"
|
t-if="not ((row.style_props.hide_empty and row.is_empty()) or row.style_props.hide_always)"
|
||||||
class="mis_row"
|
class="mis_row"
|
||||||
>
|
>
|
||||||
<div
|
<td
|
||||||
t-att-style="style_obj.to_css_style(row.style_props)"
|
t-att-style="style_obj.to_css_style(row.style_props)"
|
||||||
class="mis_cell mis_rowlabel"
|
class="mis_cell mis_rowlabel"
|
||||||
>
|
>
|
||||||
@ -93,24 +102,21 @@
|
|||||||
<br />
|
<br />
|
||||||
<t t-esc="row.description" />
|
<t t-esc="row.description" />
|
||||||
</t>
|
</t>
|
||||||
</div>
|
</td>
|
||||||
<t t-foreach="row.iter_cells()" t-as="cell">
|
<t t-foreach="row.iter_cells()" t-as="cell">
|
||||||
<div
|
<td
|
||||||
t-att-style="cell and style_obj.to_css_style(cell.style_props) or ''"
|
t-att-style="cell and style_obj.to_css_style(cell.style_props) or ''"
|
||||||
class="mis_cell mis_amount"
|
class="mis_cell mis_amount"
|
||||||
>
|
>
|
||||||
<t
|
<t
|
||||||
t-esc="cell and cell.val_rendered or ''"
|
t-esc="cell and cell.val_rendered or ''"
|
||||||
/>
|
/>
|
||||||
</div>
|
</td>
|
||||||
</t>
|
</t>
|
||||||
</div>
|
</tr>
|
||||||
</t>
|
</t>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</t>
|
|
||||||
</t>
|
|
||||||
</t>
|
|
||||||
</template>
|
</template>
|
||||||
</flectra>
|
</flectra>
|
||||||
|
@ -1,46 +1,39 @@
|
|||||||
.mis_table {
|
.mis_table {
|
||||||
display: table;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
table-layout: fixed;
|
|
||||||
}
|
}
|
||||||
.mis_row {
|
.mis_row {
|
||||||
display: table-row;
|
|
||||||
page-break-inside: avoid;
|
page-break-inside: avoid;
|
||||||
}
|
}
|
||||||
.mis_cell {
|
.mis_cell {
|
||||||
display: table-cell;
|
|
||||||
page-break-inside: avoid;
|
page-break-inside: avoid;
|
||||||
}
|
}
|
||||||
.mis_thead {
|
|
||||||
display: table-header-group;
|
|
||||||
}
|
|
||||||
.mis_tbody {
|
|
||||||
display: table-row-group;
|
|
||||||
}
|
|
||||||
.mis_table,
|
|
||||||
.mis_table .mis_row {
|
|
||||||
border-left: 0px;
|
|
||||||
border-right: 0px;
|
|
||||||
text-align: left;
|
|
||||||
padding-right: 3px;
|
|
||||||
padding-left: 3px;
|
|
||||||
padding-top: 2px;
|
|
||||||
padding-bottom: 2px;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
.mis_table .mis_row {
|
.mis_table .mis_row {
|
||||||
border-color: grey;
|
border-color: grey;
|
||||||
border-bottom: 1px solid lightGrey;
|
border-bottom: 1px solid lightGrey;
|
||||||
}
|
}
|
||||||
.mis_table .mis_cell.mis_collabel {
|
|
||||||
|
.mis_table .mis_cell.mis_collabel_group {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
background-color: #f0f0f0;
|
background-color: #f0f0f0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mis_table .mis_cell.mis_collabel_group, .mis_table .mis_cell.mis_collabel.mis_first {
|
||||||
|
border-left: 2px solid #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mis_table .mis_cell.mis_collabel {
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
text-align: right;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
.mis_table .mis_cell.mis_rowlabel {
|
.mis_table .mis_cell.mis_rowlabel {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
/*white-space: nowrap;*/
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.mis_table .mis_cell.mis_amount {
|
.mis_table .mis_cell.mis_amount {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
padding-right: 5px;
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,7 @@
|
|||||||
name="date_field"
|
name="date_field"
|
||||||
domain="[('model_id', '=', model_id), ('ttype', 'in', ('date', 'datetime'))]"
|
domain="[('model_id', '=', model_id), ('ttype', 'in', ('date', 'datetime'))]"
|
||||||
/>
|
/>
|
||||||
|
<field name="query_context"/>
|
||||||
<field name="domain" />
|
<field name="domain" />
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
|
@ -189,6 +189,7 @@
|
|||||||
<page string="Layout">
|
<page string="Layout">
|
||||||
<group name="layout">
|
<group name="layout">
|
||||||
<field name="landscape_pdf" />
|
<field name="landscape_pdf" />
|
||||||
|
<field name="use_external_layout" />
|
||||||
<field name="no_auto_expand_accounts" />
|
<field name="no_auto_expand_accounts" />
|
||||||
<field name="display_columns_description" />
|
<field name="display_columns_description" />
|
||||||
<field name="hide_analytic_filters" />
|
<field name="hide_analytic_filters" />
|
||||||
|
@ -17,7 +17,7 @@ class AddMisReportInstanceDashboard(models.TransientModel):
|
|||||||
"ir.actions.act_window",
|
"ir.actions.act_window",
|
||||||
string="Dashboard",
|
string="Dashboard",
|
||||||
required=True,
|
required=True,
|
||||||
domain="[('res_model', '=', " "'board.board')]",
|
domain="[('res_model', '=', 'board.board')]",
|
||||||
)
|
)
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
|
@ -37,6 +37,12 @@ class MisBudgetByAccountItem(models.Model):
|
|||||||
required=True,
|
required=True,
|
||||||
# TODO domain (company_id)
|
# TODO domain (company_id)
|
||||||
)
|
)
|
||||||
|
user_type_id = fields.Many2one(
|
||||||
|
comodel_name='account.account.type',
|
||||||
|
related='account_id.user_type_id',
|
||||||
|
store=True,
|
||||||
|
readonly=True,
|
||||||
|
)
|
||||||
|
|
||||||
_sql_constraints = [
|
_sql_constraints = [
|
||||||
(
|
(
|
||||||
|
1
mis_builder_expimp/__init__.py
Normal file
1
mis_builder_expimp/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from . import wizards
|
16
mis_builder_expimp/__manifest__.py
Normal file
16
mis_builder_expimp/__manifest__.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "MIS Builder Import / Export",
|
||||||
|
"summary": """Import / Export Reports with all dependencies""",
|
||||||
|
"version": "1.0.1.0.0",
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"author": "Jamotion GmbH",
|
||||||
|
"website": "https://gitlab.com/flectra-community/mis-builder",
|
||||||
|
"depends": ["mis_builder"],
|
||||||
|
"data": [
|
||||||
|
"wizards/mis_builder_export_views.xml",
|
||||||
|
"wizards/mis_builder_import_views.xml",
|
||||||
|
],
|
||||||
|
"installable": True,
|
||||||
|
}
|
BIN
mis_builder_expimp/static/description/icon.png
Normal file
BIN
mis_builder_expimp/static/description/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
69
mis_builder_expimp/static/description/index.html
Normal file
69
mis_builder_expimp/static/description/index.html
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<div class="mt32" style="max-width: 1024px; margin: 0 auto;">
|
||||||
|
<section class="container bg-gray-lighter oe_screenshot">
|
||||||
|
<div class="row oe_spaced">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<!-- The module's display name can differ from its technical name -->
|
||||||
|
<h2 class="oe_slogan" style="color: #FF7E00;">MIS Builder - Import / Export</h2>
|
||||||
|
<h3 class="oe_slogan">Function to import / export MIS Report Templates</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="container">
|
||||||
|
<div class="row oe_spaced">
|
||||||
|
<h2 class="oe_slogan" style="color: #FF7E00;">Full export and import of report template</h2>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<img class="oe_picture oe_screenshot" src="screenshot.png">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 text-justify">
|
||||||
|
<p class="oe_mt32">
|
||||||
|
When exporting a report, all related data are exported too:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>KPIs</li>
|
||||||
|
<li>SubKPIs</li>
|
||||||
|
<li>Expressions</li>
|
||||||
|
<li>Queries</li>
|
||||||
|
<li>Sub Reports</li>
|
||||||
|
<li>Styles</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="container">
|
||||||
|
<div class="row oe_spaced">
|
||||||
|
<h2 class='oe_slogan' style="color: #FF7E00;">Quick Start</h2>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<h3 class='oe_slogan'>Installation</h3>
|
||||||
|
<div>
|
||||||
|
<p class="oe_mt32">
|
||||||
|
There are no dependencies other than flectra base modules, so you can simply install the module.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<h3 class='oe_slogan'>Configuration</h3>
|
||||||
|
<div>
|
||||||
|
<p class="oe_mt32">
|
||||||
|
No configuration options available.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<h3 class='oe_slogan'>Usage</h3>
|
||||||
|
<div>
|
||||||
|
<p class="oe_mt32">
|
||||||
|
You will find two new menu items at Finance -> Configuration -> MIS Reporting:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Export MIS Report -> shows a PopUp to select the report to export</li>
|
||||||
|
<li>Import MIS Report -> shows a PopUp to select the file of exported report to import</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</div>
|
BIN
mis_builder_expimp/static/description/screenshot.png
Normal file
BIN
mis_builder_expimp/static/description/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 72 KiB |
2
mis_builder_expimp/wizards/__init__.py
Normal file
2
mis_builder_expimp/wizards/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from . import mis_builder_export_wizard
|
||||||
|
from . import mis_builder_import_wizard
|
45
mis_builder_expimp/wizards/mis_builder_export_views.xml
Normal file
45
mis_builder_expimp/wizards/mis_builder_export_views.xml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<flectra>
|
||||||
|
<data>
|
||||||
|
<record id="mis_builder_export_wizard_view" model="ir.ui.view">
|
||||||
|
<field name="name">mis.builder.export.wizard.view</field>
|
||||||
|
<field name="model">mis.builder.export.wizard</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Export MIS Report">
|
||||||
|
<field name="state" invisible="1"/>
|
||||||
|
<field name="name" invisible="1"/>
|
||||||
|
<div states="draft">
|
||||||
|
<p>This wizard will export a MIS Report including all dependencies.
|
||||||
|
<br/>After export you can import this file in another system to have the same MIS Report.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<group states="draft">
|
||||||
|
<field name="report_id"/>
|
||||||
|
</group>
|
||||||
|
<group states="download">
|
||||||
|
<group>
|
||||||
|
<field name="file_save" filename="name"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
<footer>
|
||||||
|
<button name="export" string="Generate File" type="object" class="oe_highlight"/>
|
||||||
|
or
|
||||||
|
<button string="Cancel" class="oe_link" special="cancel"/>
|
||||||
|
</footer>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
<record id="action_mis_builder_export_wizard" model="ir.actions.act_window">
|
||||||
|
<field name="name">Export MIS Report</field>
|
||||||
|
<field name="type">ir.actions.act_window</field>
|
||||||
|
<field name="res_model">mis.builder.export.wizard</field>
|
||||||
|
<field name="view_mode">form</field>
|
||||||
|
<field name="target">new</field>
|
||||||
|
</record>
|
||||||
|
<menuitem id="menu_mis_builder_export_action"
|
||||||
|
name="Export MIS Report"
|
||||||
|
parent="mis_builder.mis_report_conf_menu"
|
||||||
|
action="action_mis_builder_export_wizard"
|
||||||
|
sequence="500"/>
|
||||||
|
</data>
|
||||||
|
</flectra>
|
162
mis_builder_expimp/wizards/mis_builder_export_wizard.py
Normal file
162
mis_builder_expimp/wizards/mis_builder_export_wizard.py
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
# Copyright 2014 ACSONE SA/NV (<http://acsone.eu>)
|
||||||
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
|
||||||
|
from lxml import etree
|
||||||
|
|
||||||
|
from flectra import api, fields, models, _
|
||||||
|
|
||||||
|
QUERY_FIELDS = ['name', 'model_id', 'field_ids', 'aggregate', 'date_field', 'query_context', 'domain']
|
||||||
|
|
||||||
|
REPORT_FIELDS = ['name', 'description', 'account_model', 'subreport_ids']
|
||||||
|
|
||||||
|
KPI_FIELDS = [
|
||||||
|
'name', 'description', 'multi', 'auto_expand_accounts', 'style_expression',
|
||||||
|
'type', 'compare_method', 'accumulation_method', 'sequence', 'budgetable',
|
||||||
|
'expression'
|
||||||
|
]
|
||||||
|
|
||||||
|
STYLE_FIELDS = [
|
||||||
|
'name',
|
||||||
|
'color_inherit', 'color',
|
||||||
|
'background_color_inherit', 'background_color',
|
||||||
|
'font_style_inherit', 'font_style',
|
||||||
|
'font_weight_inherit', 'font_weight',
|
||||||
|
'font_size_inherit', 'font_size',
|
||||||
|
'indent_level_inherit', 'indent_level',
|
||||||
|
'prefix_inherit', 'prefix',
|
||||||
|
'suffix_inherit', 'suffix',
|
||||||
|
'dp_inherit', 'dp',
|
||||||
|
'divider_inherit', 'divider',
|
||||||
|
'hide_empty_inherit', 'hide_empty',
|
||||||
|
'hide_always_inherit', 'hide_alway',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class MisBuilderExportWizard(models.TransientModel):
|
||||||
|
_name = "mis.builder.export.wizard"
|
||||||
|
_description = "Export MIS Builder Report"
|
||||||
|
|
||||||
|
report_id = fields.Many2one(
|
||||||
|
comodel_name='mis.report',
|
||||||
|
string='Report',
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
name = fields.Char(
|
||||||
|
string='File Name',
|
||||||
|
default='mis_report.json',
|
||||||
|
)
|
||||||
|
|
||||||
|
file_save = fields.Binary(
|
||||||
|
string='Settings File',
|
||||||
|
readonly=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
state = fields.Selection([
|
||||||
|
('draft', 'Draft'),
|
||||||
|
('download', 'Download')
|
||||||
|
], default='draft')
|
||||||
|
|
||||||
|
def export(self):
|
||||||
|
self.ensure_one()
|
||||||
|
|
||||||
|
report_data = self._read_subreport_data(self.report_id.subreport_ids)
|
||||||
|
report_data.append(self._read_report_data(self.report_id))
|
||||||
|
|
||||||
|
json_data = json.dumps(report_data, indent=2)
|
||||||
|
# change state of the wizard
|
||||||
|
self.write({
|
||||||
|
'name': '%s.json' % self.report_id.name,
|
||||||
|
'file_save': base64.b64encode(json_data.encode()),
|
||||||
|
'state': 'download'
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
'name': _('Save'),
|
||||||
|
'view_type': 'form',
|
||||||
|
'view_mode': 'form',
|
||||||
|
'res_model': self._name,
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
'target': 'new',
|
||||||
|
'res_id': self.id,
|
||||||
|
}
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _read_subreport_data(self, subreport_ids):
|
||||||
|
report_data = []
|
||||||
|
for subreport_id in subreport_ids:
|
||||||
|
report_data.extend(self._read_subreport_data(subreport_id.subreport_id.subreport_ids))
|
||||||
|
report_data.append(self._read_report_data(subreport_id.subreport_id))
|
||||||
|
|
||||||
|
return report_data
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _read_report_data(self, report_id):
|
||||||
|
report_data = report_id.read(REPORT_FIELDS)[0]
|
||||||
|
del report_data['id']
|
||||||
|
report_data['extid'] = '__export__.mis_report_%s' % report_id.id
|
||||||
|
report_data['move_lines_source'] = report_id.move_lines_source.model
|
||||||
|
if report_id.style_id:
|
||||||
|
report_data['style_id'] = report_id.style_id.read(STYLE_FIELDS)[0]
|
||||||
|
del report_data['style_id']['id']
|
||||||
|
report_data['style_id']['extid'] = '__export__.mis_report_style_%s' % report_id.style_id.id
|
||||||
|
if report_id.query_ids:
|
||||||
|
report_data['query_ids'] = []
|
||||||
|
for query_id in report_id.query_ids:
|
||||||
|
query_data = query_id.read(QUERY_FIELDS)[0]
|
||||||
|
del query_data['id']
|
||||||
|
query_data['model_id'] = query_id.model_id.model
|
||||||
|
query_data['field_ids'] = query_id.field_ids.mapped('name')
|
||||||
|
query_data['extid'] = '__export__.mis_report_query_%s' % query_id.id
|
||||||
|
report_data['query_ids'].append(query_data)
|
||||||
|
if report_id.kpi_ids:
|
||||||
|
report_data['kpi_ids'] = []
|
||||||
|
last_kpi_sequence = -1
|
||||||
|
for kpi_id in report_id.kpi_ids.sorted(key=lambda s: s.sequence):
|
||||||
|
kpi_data = kpi_id.read(KPI_FIELDS)[0]
|
||||||
|
# Fix of sequences to be unique - otherwise there are problems on importing reports with subkpis
|
||||||
|
if kpi_id.sequence <= last_kpi_sequence:
|
||||||
|
kpi_data['sequence'] = last_kpi_sequence + 1
|
||||||
|
last_kpi_sequence = kpi_data['sequence']
|
||||||
|
del kpi_data['id']
|
||||||
|
if kpi_id.style_id:
|
||||||
|
kpi_data['style_id'] = kpi_id.style_id.read(STYLE_FIELDS)[0]
|
||||||
|
del kpi_data['style_id']['id']
|
||||||
|
kpi_data['style_id']['extid'] = '__export__.mis_report_style_%s' % kpi_id.style_id.id
|
||||||
|
if kpi_id.auto_expand_accounts_style_id:
|
||||||
|
kpi_data['auto_expand_accounts_style_id'] = kpi_id.auto_expand_accounts_style_id.read(STYLE_FIELDS)[0]
|
||||||
|
del kpi_data['auto_expand_accounts_style_id']['id']
|
||||||
|
kpi_data['auto_expand_accounts_style_id'][
|
||||||
|
'extid'] = '__export__.mis_report_style_%s' % kpi_id.auto_expand_accounts_style_id.id
|
||||||
|
kpi_data['extid'] = '__export__.mis_report_kpi_%s' % kpi_id.id
|
||||||
|
kpi_data['expression_ids'] = []
|
||||||
|
for expression_id in kpi_id.expression_ids:
|
||||||
|
expression_data = expression_id.read(['sequence', 'name'])[0]
|
||||||
|
del expression_data['id']
|
||||||
|
expression_data['extid'] = '__export__.mis_report_kpi_expression_%s' % expression_id.id
|
||||||
|
kpi_data['expression_ids'].append(expression_data)
|
||||||
|
report_data['kpi_ids'].append(kpi_data)
|
||||||
|
if report_id.subkpi_ids:
|
||||||
|
report_data['subkpi_ids'] = []
|
||||||
|
for subkpi_id in report_id.subkpi_ids:
|
||||||
|
subkpi_data = subkpi_id.read(['sequence', 'name', 'description'])[0]
|
||||||
|
del subkpi_data['id']
|
||||||
|
subkpi_data['extid'] = '__export__.mis_report_subkpi_%s' % subkpi_id.id
|
||||||
|
subkpi_data['expression_ids'] = []
|
||||||
|
for expression_id in subkpi_id.expression_ids:
|
||||||
|
expression_data = expression_id.read(['sequence', 'name'])[0]
|
||||||
|
del expression_data['id']
|
||||||
|
expression_data['kpi_id'] = '__export__.mis_report_kpi_%s' % expression_id.kpi_id.id
|
||||||
|
expression_data['extid'] = '__export__.mis_report_kpi_expression_%s' % expression_id.id
|
||||||
|
subkpi_data['expression_ids'].append(expression_data)
|
||||||
|
report_data['subkpi_ids'].append(subkpi_data)
|
||||||
|
if report_id.subreport_ids:
|
||||||
|
report_data['subreport_ids'] = []
|
||||||
|
for subreport_id in report_id.subreport_ids:
|
||||||
|
subreport_data = subreport_id.read(['name'])[0]
|
||||||
|
del subreport_data['id']
|
||||||
|
subreport_data['subreport_id'] = '__export__.mis_report_%s' % subreport_id.subreport_id.id
|
||||||
|
report_data['subreport_ids'].append(subreport_data)
|
||||||
|
return report_data
|
34
mis_builder_expimp/wizards/mis_builder_import_views.xml
Normal file
34
mis_builder_expimp/wizards/mis_builder_import_views.xml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<flectra>
|
||||||
|
<data>
|
||||||
|
<record id="mis_builder_import_wizard_view" model="ir.ui.view">
|
||||||
|
<field name="name">mis.builder.import.wizard.view</field>
|
||||||
|
<field name="model">mis.builder.import.wizard</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Import Settings">
|
||||||
|
<div>
|
||||||
|
<p>This wizard will import a MIS report from json File.</p>
|
||||||
|
</div>
|
||||||
|
<field name="file"/>
|
||||||
|
<footer>
|
||||||
|
<button name="import_report" string="Import" type="object" class="oe_highlight"/>
|
||||||
|
or
|
||||||
|
<button string="Cancel" class="oe_link" special="cancel"/>
|
||||||
|
</footer>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
<record id="action_mis_builder_import_wizard" model="ir.actions.act_window">
|
||||||
|
<field name="name">Import MIS Report</field>
|
||||||
|
<field name="type">ir.actions.act_window</field>
|
||||||
|
<field name="res_model">mis.builder.import.wizard</field>
|
||||||
|
<field name="view_mode">form</field>
|
||||||
|
<field name="target">new</field>
|
||||||
|
</record>
|
||||||
|
<menuitem id="menu_mis_builder_import_action"
|
||||||
|
name="Import MIS Report"
|
||||||
|
parent="mis_builder.mis_report_conf_menu"
|
||||||
|
action="action_mis_builder_import_wizard"
|
||||||
|
sequence="500"/>
|
||||||
|
</data>
|
||||||
|
</flectra>
|
153
mis_builder_expimp/wizards/mis_builder_import_wizard.py
Normal file
153
mis_builder_expimp/wizards/mis_builder_import_wizard.py
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
import copy
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from io import StringIO
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from flectra import models, fields, api, _
|
||||||
|
from flectra.tools import config, etree, base64, convert_xml_import, tempfile
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from flectra.exceptions import ValidationError
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class MisBuilderImportWizard(models.TransientModel):
|
||||||
|
# Private attributes
|
||||||
|
_name = "mis.builder.import.wizard"
|
||||||
|
_description = "Import MIS Builder Report"
|
||||||
|
|
||||||
|
file = fields.Binary(
|
||||||
|
string='Settings File',
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __int__(self):
|
||||||
|
super(MisBuilderImportWizard, self).__int__()
|
||||||
|
|
||||||
|
def import_report(self):
|
||||||
|
self.ensure_one()
|
||||||
|
|
||||||
|
json_data = base64.b64decode(self.file)
|
||||||
|
report_data = json.loads(json_data)
|
||||||
|
|
||||||
|
for report_entry in report_data:
|
||||||
|
report_values = self.__prepare_report_values(report_entry)
|
||||||
|
|
||||||
|
self.__prepare_style_values(report_entry, report_values)
|
||||||
|
|
||||||
|
self.__prepare_subreport_values(report_entry, report_values)
|
||||||
|
|
||||||
|
self.__prepare_query_values(report_values)
|
||||||
|
|
||||||
|
self.__prepare_kpi_values(report_values)
|
||||||
|
|
||||||
|
subkpi_values = []
|
||||||
|
if report_values.get('subkpi_ids'):
|
||||||
|
for subkpi_value in report_values['subkpi_ids']:
|
||||||
|
subkpi_values.append(subkpi_value)
|
||||||
|
del report_values['subkpi_ids']
|
||||||
|
|
||||||
|
new_report = self.env['mis.report'].create(report_values)
|
||||||
|
self._create_external_reference(new_report, report_entry['extid'])
|
||||||
|
|
||||||
|
self.__update_subkpi_values(new_report, report_entry, subkpi_values)
|
||||||
|
|
||||||
|
def __prepare_style_values(self, report_entry, report_values):
|
||||||
|
if report_entry.get('style_id'):
|
||||||
|
report_values['style_id'] = self._create_style(report_values['style_id']).id
|
||||||
|
|
||||||
|
def __prepare_report_values(self, report_entry):
|
||||||
|
result = self.env['ir.model.data'].xmlid_to_res_id(report_entry['extid'])
|
||||||
|
if result:
|
||||||
|
raise ValidationError('Report already exists! Please delete it first before importing')
|
||||||
|
report_values = copy.deepcopy(report_entry)
|
||||||
|
report_values['move_lines_source'] = self.env['ir.model'].search([('model', '=', report_values['move_lines_source'])]).id
|
||||||
|
return report_values
|
||||||
|
|
||||||
|
def __update_subkpi_values(self, new_report, report_entry, subkpi_values):
|
||||||
|
temporary_extids = self.env['ir.model.data']
|
||||||
|
subkpi_updates = []
|
||||||
|
if subkpi_values:
|
||||||
|
for kpi_id in new_report.kpi_ids:
|
||||||
|
for kpi_data in report_entry['kpi_ids']:
|
||||||
|
if kpi_id.sequence == kpi_data['sequence']:
|
||||||
|
temporary_extids |= self._create_external_reference(kpi_id, kpi_data['extid'])
|
||||||
|
for subkpi_value in subkpi_values:
|
||||||
|
expression_updates = []
|
||||||
|
for expression_value in subkpi_value['expression_ids']:
|
||||||
|
expression_value['kpi_id'] = self.env.ref(expression_value['kpi_id']).id
|
||||||
|
expression_updates.append((0, False, expression_value))
|
||||||
|
subkpi_value['expression_ids'] = expression_updates
|
||||||
|
subkpi_updates.append((0, False, subkpi_value))
|
||||||
|
if subkpi_updates:
|
||||||
|
new_report.write({'subkpi_ids': subkpi_updates})
|
||||||
|
if temporary_extids:
|
||||||
|
temporary_extids.unlink()
|
||||||
|
|
||||||
|
def __prepare_kpi_values(self, report_values):
|
||||||
|
if report_values.get('kpi_ids'):
|
||||||
|
kpi_values = []
|
||||||
|
for kpi_value in report_values['kpi_ids']:
|
||||||
|
self.__prepare_style_values(kpi_value, kpi_value)
|
||||||
|
if kpi_value.get('auto_expand_accounts_style_id'):
|
||||||
|
kpi_value['auto_expand_accounts_style_id'] = self._create_style(kpi_value['auto_expand_accounts_style_id']).id
|
||||||
|
if report_values.get('subkpi_ids'):
|
||||||
|
del kpi_value['expression']
|
||||||
|
del kpi_value['expression_ids']
|
||||||
|
else:
|
||||||
|
if kpi_value.get('expression_ids'):
|
||||||
|
expression_values = [(0, False, v) for v in kpi_value['expression_ids']]
|
||||||
|
kpi_value['expression_ids'] = expression_values
|
||||||
|
kpi_values.append((0, False, kpi_value))
|
||||||
|
report_values['kpi_ids'] = kpi_values
|
||||||
|
|
||||||
|
def __prepare_query_values(self, report_values):
|
||||||
|
if report_values.get('query_ids'):
|
||||||
|
query_values = []
|
||||||
|
for query_value in report_values['query_ids']:
|
||||||
|
query_model = self.env['ir.model'].search([('model', '=', query_value['model_id'])])
|
||||||
|
query_value['model_id'] = query_model.id
|
||||||
|
query_value['field_ids'] = [(6, 0, [f.id for f in query_model.field_id if f.name in query_value['field_ids']])]
|
||||||
|
query_values.append((0, False, query_value))
|
||||||
|
report_values['query_ids'] = query_values
|
||||||
|
|
||||||
|
def __prepare_subreport_values(self, report_entry, report_values):
|
||||||
|
if report_entry.get('subreport_ids'):
|
||||||
|
subreport_values = []
|
||||||
|
for subreport_value in report_entry['subreport_ids']:
|
||||||
|
subreport_value['subreport_id'] = self.env.ref(subreport_value['subreport_id']).id
|
||||||
|
subreport_values.append((0, False, subreport_value))
|
||||||
|
report_values['subreport_ids'] = subreport_values
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _create_style(self, style_data):
|
||||||
|
result = self.env['ir.model.data'].xmlid_to_object(style_data['extid'])
|
||||||
|
if result:
|
||||||
|
return result
|
||||||
|
|
||||||
|
new_style = self.env['mis.report.style'].create(style_data)
|
||||||
|
self._create_external_reference(new_style, style_data['extid'])
|
||||||
|
return new_style
|
||||||
|
|
||||||
|
def _create_external_reference(self, obj, extid, temporary=False):
|
||||||
|
module, name = extid.split('.', 1)
|
||||||
|
existing = self.env['ir.model.data'].search([
|
||||||
|
('module', '=', module),
|
||||||
|
('model', '=', obj._name),
|
||||||
|
('name', '=', name),
|
||||||
|
], limit=1)
|
||||||
|
if existing:
|
||||||
|
existing.res_id = obj.id
|
||||||
|
return existing
|
||||||
|
|
||||||
|
return self.env['ir.model.data'].create({
|
||||||
|
'module': module,
|
||||||
|
'model': obj._name,
|
||||||
|
'name': name,
|
||||||
|
'res_id': obj.id,
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user