odoo-addon-mis-builder 16.0.5.2.3.1__py3-none-any.whl → 16.0.5.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- odoo/addons/mis_builder/README.rst +1 -1
- odoo/addons/mis_builder/__manifest__.py +2 -1
- odoo/addons/mis_builder/i18n/ca.po +91 -0
- odoo/addons/mis_builder/i18n/de.po +91 -0
- odoo/addons/mis_builder/i18n/el.po +91 -0
- odoo/addons/mis_builder/i18n/el_GR.po +91 -0
- odoo/addons/mis_builder/i18n/es.po +91 -0
- odoo/addons/mis_builder/i18n/fr.po +91 -0
- odoo/addons/mis_builder/i18n/hr.po +91 -0
- odoo/addons/mis_builder/i18n/it.po +91 -0
- odoo/addons/mis_builder/i18n/mis_builder.pot +97 -0
- odoo/addons/mis_builder/i18n/nl.po +91 -0
- odoo/addons/mis_builder/i18n/nl_NL.po +91 -0
- odoo/addons/mis_builder/i18n/pt.po +91 -0
- odoo/addons/mis_builder/i18n/pt_BR.po +91 -0
- odoo/addons/mis_builder/i18n/sv.po +91 -0
- odoo/addons/mis_builder/i18n/tr.po +91 -0
- odoo/addons/mis_builder/models/__init__.py +1 -0
- odoo/addons/mis_builder/models/kpimatrix.py +39 -4
- odoo/addons/mis_builder/models/mis_report_instance.py +71 -1
- odoo/addons/mis_builder/models/mis_report_instance_annotation.py +113 -0
- odoo/addons/mis_builder/report/mis_report_instance_qweb.xml +23 -0
- odoo/addons/mis_builder/report/mis_report_instance_xlsx.py +11 -1
- odoo/addons/mis_builder/security/ir.model.access.csv +2 -0
- odoo/addons/mis_builder/security/res_groups.xml +17 -0
- odoo/addons/mis_builder/static/description/index.html +1 -1
- odoo/addons/mis_builder/static/src/components/mis_report_widget.css +41 -0
- odoo/addons/mis_builder/static/src/components/mis_report_widget.esm.js +109 -4
- odoo/addons/mis_builder/static/src/components/mis_report_widget.xml +104 -13
- odoo/addons/mis_builder/static/src/css/report.css +22 -0
- odoo/addons/mis_builder/tests/__init__.py +1 -0
- odoo/addons/mis_builder/tests/test_mis_report_instance_annotation.py +154 -0
- odoo/addons/mis_builder/views/mis_report_instance.xml +1 -0
- {odoo_addon_mis_builder-16.0.5.2.3.1.dist-info → odoo_addon_mis_builder-16.0.5.4.0.dist-info}/METADATA +2 -2
- {odoo_addon_mis_builder-16.0.5.2.3.1.dist-info → odoo_addon_mis_builder-16.0.5.4.0.dist-info}/RECORD +37 -34
- {odoo_addon_mis_builder-16.0.5.2.3.1.dist-info → odoo_addon_mis_builder-16.0.5.4.0.dist-info}/WHEEL +0 -0
- {odoo_addon_mis_builder-16.0.5.2.3.1.dist-info → odoo_addon_mis_builder-16.0.5.4.0.dist-info}/top_level.txt +0 -0
@@ -16,6 +16,14 @@ msgstr ""
|
|
16
16
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
17
17
|
"X-Generator: Weblate 4.17\n"
|
18
18
|
|
19
|
+
#. module: mis_builder
|
20
|
+
#: model:ir.model.fields,help:mis_builder.field_mis_report_instance_annotation__annotation_context
|
21
|
+
msgid ""
|
22
|
+
"\n"
|
23
|
+
" Context used when adding annotation\n"
|
24
|
+
" "
|
25
|
+
msgstr ""
|
26
|
+
|
19
27
|
#. module: mis_builder
|
20
28
|
#. odoo-python
|
21
29
|
#: code:addons/mis_builder/models/mis_report.py:0
|
@@ -309,6 +317,18 @@ msgstr ""
|
|
309
317
|
msgid "Analytic Domain"
|
310
318
|
msgstr "Analitik Etki Alanı(sorgu)"
|
311
319
|
|
320
|
+
#. module: mis_builder
|
321
|
+
#. odoo-javascript
|
322
|
+
#: code:addons/mis_builder/static/src/components/mis_report_widget.xml:0
|
323
|
+
#, python-format
|
324
|
+
msgid "Annotate"
|
325
|
+
msgstr ""
|
326
|
+
|
327
|
+
#. module: mis_builder
|
328
|
+
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_annotation__annotation_context
|
329
|
+
msgid "Annotation Context"
|
330
|
+
msgstr ""
|
331
|
+
|
312
332
|
#. module: mis_builder
|
313
333
|
#: model_terms:ir.ui.view,arch_db:mis_builder.mis_report_view_kpi_form
|
314
334
|
msgid "Auto expand"
|
@@ -349,8 +369,11 @@ msgid "Bold"
|
|
349
369
|
msgstr "Kalın"
|
350
370
|
|
351
371
|
#. module: mis_builder
|
372
|
+
#. odoo-javascript
|
373
|
+
#: code:addons/mis_builder/static/src/components/mis_report_widget.esm.js:0
|
352
374
|
#: model_terms:ir.ui.view,arch_db:mis_builder.mis_report_instance_add_to_dashboard_form_view
|
353
375
|
#: model_terms:ir.ui.view,arch_db:mis_builder.wizard_mis_report_instance_view_form
|
376
|
+
#, python-format
|
354
377
|
msgid "Cancel"
|
355
378
|
msgstr "iptal"
|
356
379
|
|
@@ -441,6 +464,7 @@ msgstr "Karşılaştırma Modu"
|
|
441
464
|
#: model:ir.model.fields,field_description:mis_builder.field_add_mis_report_instance_dashboard_wizard__create_uid
|
442
465
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report__create_uid
|
443
466
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance__create_uid
|
467
|
+
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_annotation__create_uid
|
444
468
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period__create_uid
|
445
469
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period_sum__create_uid
|
446
470
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_kpi__create_uid
|
@@ -456,6 +480,7 @@ msgstr "Oluşturan"
|
|
456
480
|
#: model:ir.model.fields,field_description:mis_builder.field_add_mis_report_instance_dashboard_wizard__create_date
|
457
481
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report__create_date
|
458
482
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance__create_date
|
483
|
+
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_annotation__create_date
|
459
484
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period__create_date
|
460
485
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period_sum__create_date
|
461
486
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_kpi__create_date
|
@@ -566,6 +591,7 @@ msgstr "Sütun Açıklamalarını Görüntüle"
|
|
566
591
|
#: model:ir.model.fields,field_description:mis_builder.field_add_mis_report_instance_dashboard_wizard__display_name
|
567
592
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report__display_name
|
568
593
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance__display_name
|
594
|
+
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_annotation__display_name
|
569
595
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period__display_name
|
570
596
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period_sum__display_name
|
571
597
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_kpi__display_name
|
@@ -808,6 +834,7 @@ msgstr "Boş Devralmayı Gizle"
|
|
808
834
|
#: model:ir.model.fields,field_description:mis_builder.field_add_mis_report_instance_dashboard_wizard__id
|
809
835
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report__id
|
810
836
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance__id
|
837
|
+
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_annotation__id
|
811
838
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period__id
|
812
839
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period_sum__id
|
813
840
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_kpi__id
|
@@ -849,6 +876,13 @@ msgstr "Girinti Düzeyi Devralma"
|
|
849
876
|
msgid "Indent level must be greater than or equal to 0"
|
850
877
|
msgstr ""
|
851
878
|
|
879
|
+
#. module: mis_builder
|
880
|
+
#. odoo-javascript
|
881
|
+
#: code:addons/mis_builder/static/src/components/mis_report_widget.xml:0
|
882
|
+
#, python-format
|
883
|
+
msgid "Insert note here"
|
884
|
+
msgstr ""
|
885
|
+
|
852
886
|
#. module: mis_builder
|
853
887
|
#: model:ir.model.fields.selection,name:mis_builder.selection__mis_report_style__font_style__italic
|
854
888
|
msgid "Italic"
|
@@ -906,6 +940,7 @@ msgid "KPIs of this report and subreports."
|
|
906
940
|
msgstr ""
|
907
941
|
|
908
942
|
#. module: mis_builder
|
943
|
+
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_annotation__kpi_id
|
909
944
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_kpi_expression__kpi_id
|
910
945
|
msgid "Kpi"
|
911
946
|
msgstr ""
|
@@ -924,6 +959,7 @@ msgstr "Yatay PDF"
|
|
924
959
|
#: model:ir.model.fields,field_description:mis_builder.field_add_mis_report_instance_dashboard_wizard____last_update
|
925
960
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report____last_update
|
926
961
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance____last_update
|
962
|
+
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_annotation____last_update
|
927
963
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period____last_update
|
928
964
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period_sum____last_update
|
929
965
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_kpi____last_update
|
@@ -945,6 +981,7 @@ msgstr "Son Oluşturulan Raporlar"
|
|
945
981
|
#: model:ir.model.fields,field_description:mis_builder.field_add_mis_report_instance_dashboard_wizard__write_uid
|
946
982
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report__write_uid
|
947
983
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance__write_uid
|
984
|
+
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_annotation__write_uid
|
948
985
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period__write_uid
|
949
986
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period_sum__write_uid
|
950
987
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_kpi__write_uid
|
@@ -960,6 +997,7 @@ msgstr ""
|
|
960
997
|
#: model:ir.model.fields,field_description:mis_builder.field_add_mis_report_instance_dashboard_wizard__write_date
|
961
998
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report__write_date
|
962
999
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance__write_date
|
1000
|
+
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_annotation__write_date
|
963
1001
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period__write_date
|
964
1002
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period_sum__write_date
|
965
1003
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_kpi__write_date
|
@@ -1066,6 +1104,16 @@ msgstr "Mali Rapor Şablonu"
|
|
1066
1104
|
msgid "MIS Report Templates"
|
1067
1105
|
msgstr "Mali Rapor Şablonları"
|
1068
1106
|
|
1107
|
+
#. module: mis_builder
|
1108
|
+
#: model:res.groups,name:mis_builder.group_edit_annotation
|
1109
|
+
msgid "MIS Report: add annotations"
|
1110
|
+
msgstr ""
|
1111
|
+
|
1112
|
+
#. module: mis_builder
|
1113
|
+
#: model:res.groups,name:mis_builder.group_read_annotation
|
1114
|
+
msgid "MIS Report: view annotations"
|
1115
|
+
msgstr ""
|
1116
|
+
|
1069
1117
|
#. module: mis_builder
|
1070
1118
|
#: model:ir.ui.menu,name:mis_builder.mis_report_conf_menu
|
1071
1119
|
#: model:ir.ui.menu,name:mis_builder.mis_report_finance_menu
|
@@ -1104,6 +1152,11 @@ msgstr ""
|
|
1104
1152
|
msgid "Min"
|
1105
1153
|
msgstr ""
|
1106
1154
|
|
1155
|
+
#. module: mis_builder
|
1156
|
+
#: model:ir.model,name:mis_builder.model_mis_report_instance_annotation
|
1157
|
+
msgid "Mis Report Instance Annotation"
|
1158
|
+
msgstr ""
|
1159
|
+
|
1107
1160
|
#. module: mis_builder
|
1108
1161
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period__mode
|
1109
1162
|
msgid "Mode"
|
@@ -1190,6 +1243,11 @@ msgstr ""
|
|
1190
1243
|
msgid "Normal"
|
1191
1244
|
msgstr ""
|
1192
1245
|
|
1246
|
+
#. module: mis_builder
|
1247
|
+
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_annotation__note
|
1248
|
+
msgid "Note"
|
1249
|
+
msgstr ""
|
1250
|
+
|
1193
1251
|
#. module: mis_builder
|
1194
1252
|
#: model_terms:ir.ui.view,arch_db:mis_builder.mis_report_style_view_form
|
1195
1253
|
msgid "Number"
|
@@ -1232,6 +1290,11 @@ msgstr ""
|
|
1232
1290
|
msgid "Percentage"
|
1233
1291
|
msgstr ""
|
1234
1292
|
|
1293
|
+
#. module: mis_builder
|
1294
|
+
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_annotation__period_id
|
1295
|
+
msgid "Period"
|
1296
|
+
msgstr ""
|
1297
|
+
|
1235
1298
|
#. module: mis_builder
|
1236
1299
|
#: model:ir.model.constraint,message:mis_builder.constraint_mis_report_instance_period_name_unique
|
1237
1300
|
msgid "Period name should be unique by report"
|
@@ -1319,6 +1382,13 @@ msgstr ""
|
|
1319
1382
|
msgid "Relative to report base date"
|
1320
1383
|
msgstr ""
|
1321
1384
|
|
1385
|
+
#. module: mis_builder
|
1386
|
+
#. odoo-javascript
|
1387
|
+
#: code:addons/mis_builder/static/src/components/mis_report_widget.esm.js:0
|
1388
|
+
#, python-format
|
1389
|
+
msgid "Remove"
|
1390
|
+
msgstr ""
|
1391
|
+
|
1322
1392
|
#. module: mis_builder
|
1323
1393
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance__report_id
|
1324
1394
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_period__report_id
|
@@ -1355,8 +1425,11 @@ msgid "Rounding inherit"
|
|
1355
1425
|
msgstr "Yuvarlama Devralma"
|
1356
1426
|
|
1357
1427
|
#. module: mis_builder
|
1428
|
+
#. odoo-javascript
|
1429
|
+
#: code:addons/mis_builder/static/src/components/mis_report_widget.esm.js:0
|
1358
1430
|
#: model_terms:ir.ui.view,arch_db:mis_builder.mis_report_instance_view_form
|
1359
1431
|
#: model_terms:ir.ui.view,arch_db:mis_builder.wizard_mis_report_instance_view_form
|
1432
|
+
#, python-format
|
1360
1433
|
msgid "Save"
|
1361
1434
|
msgstr ""
|
1362
1435
|
|
@@ -1518,6 +1591,7 @@ msgid "Sub-KPI name ({}) must be a valid python identifier"
|
|
1518
1591
|
msgstr ""
|
1519
1592
|
|
1520
1593
|
#. module: mis_builder
|
1594
|
+
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance_annotation__subkpi_id
|
1521
1595
|
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_kpi_expression__subkpi_id
|
1522
1596
|
msgid "Subkpi"
|
1523
1597
|
msgstr ""
|
@@ -1669,6 +1743,16 @@ msgstr ""
|
|
1669
1743
|
msgid "Unsupported operator %s for searching on date"
|
1670
1744
|
msgstr ""
|
1671
1745
|
|
1746
|
+
#. module: mis_builder
|
1747
|
+
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance__user_can_edit_annotation
|
1748
|
+
msgid "User Can Edit Annotation"
|
1749
|
+
msgstr ""
|
1750
|
+
|
1751
|
+
#. module: mis_builder
|
1752
|
+
#: model:ir.model.fields,field_description:mis_builder.field_mis_report_instance__user_can_read_annotation
|
1753
|
+
msgid "User Can Read Annotation"
|
1754
|
+
msgstr ""
|
1755
|
+
|
1672
1756
|
#. module: mis_builder
|
1673
1757
|
#: model:ir.actions.server,name:mis_builder.ir_cron_vacuum_temp_reports_ir_actions_server
|
1674
1758
|
#: model:ir.cron,cron_name:mis_builder.ir_cron_vacuum_temp_reports
|
@@ -1733,6 +1817,13 @@ msgstr ""
|
|
1733
1817
|
msgid "You cannot sum period %s with itself."
|
1734
1818
|
msgstr ""
|
1735
1819
|
|
1820
|
+
#. module: mis_builder
|
1821
|
+
#. odoo-python
|
1822
|
+
#: code:addons/mis_builder/models/mis_report_instance_annotation.py:0
|
1823
|
+
#, python-format
|
1824
|
+
msgid "You do not have the rights to edit annotations"
|
1825
|
+
msgstr ""
|
1826
|
+
|
1736
1827
|
#. module: mis_builder
|
1737
1828
|
#. odoo-python
|
1738
1829
|
#: code:addons/mis_builder/models/aep.py:0
|
@@ -45,10 +45,7 @@ class KpiMatrixRow:
|
|
45
45
|
|
46
46
|
@property
|
47
47
|
def row_id(self):
|
48
|
-
|
49
|
-
return self.kpi.name
|
50
|
-
else:
|
51
|
-
return f"{self.kpi.name}:{self.account_id}"
|
48
|
+
self._matrix._make_row_id(self.kpi.id, self.account_id)
|
52
49
|
|
53
50
|
def iter_cell_tuples(self, cols=None):
|
54
51
|
if cols is None:
|
@@ -143,6 +140,7 @@ class KpiMatrixCell: # noqa: B903 (immutable data class)
|
|
143
140
|
self.style_props = style_props
|
144
141
|
self.drilldown_arg = drilldown_arg
|
145
142
|
self.val_type = val_type
|
143
|
+
self.cell_id = KpiMatrix._pack_cell_id(self)
|
146
144
|
|
147
145
|
|
148
146
|
class KpiMatrix:
|
@@ -524,12 +522,15 @@ class KpiMatrix:
|
|
524
522
|
else:
|
525
523
|
val = cell.val
|
526
524
|
col_data = {
|
525
|
+
"cell_id": cell.cell_id,
|
527
526
|
"val": val,
|
528
527
|
"val_r": cell.val_rendered,
|
529
528
|
"val_c": cell.val_comment,
|
530
529
|
"style": self._style_model.to_css_style(
|
531
530
|
cell.style_props, no_indent=True
|
532
531
|
),
|
532
|
+
# notes can not be added on 'details by account' lines
|
533
|
+
"can_be_annotated": not cell.row.account_id,
|
533
534
|
}
|
534
535
|
if cell.drilldown_arg:
|
535
536
|
col_data["drilldown_arg"] = cell.drilldown_arg
|
@@ -537,3 +538,37 @@ class KpiMatrix:
|
|
537
538
|
body.append(row_data)
|
538
539
|
|
539
540
|
return {"header": header, "body": body}
|
541
|
+
|
542
|
+
# Logic to convert semantic coordinates (period, kpi, subkpi)
|
543
|
+
# to visual coordinates (cell id) and back. The rendering logic musn't know
|
544
|
+
# about semantic concepts such as periods and kpis. Having these well identified
|
545
|
+
# methods allow us to easily spot where the conversion between the rendering and
|
546
|
+
# semantic domain occur.
|
547
|
+
|
548
|
+
@classmethod
|
549
|
+
def _make_row_id(cls, kpi_id: int, account_id: int | None) -> str:
|
550
|
+
return f"{kpi_id}:{account_id or ''}"
|
551
|
+
|
552
|
+
@classmethod
|
553
|
+
def _make_cell_id(
|
554
|
+
cls, kpi_id: int, account_id: int | None, period_id: int, subkpi_id: int | None
|
555
|
+
) -> str:
|
556
|
+
return f"{kpi_id}#{account_id or ''}#{period_id}#{subkpi_id or ''}"
|
557
|
+
|
558
|
+
@classmethod
|
559
|
+
def _pack_cell_id(cls, cell: KpiMatrixCell) -> str:
|
560
|
+
return cls._make_cell_id(
|
561
|
+
cell.row.kpi.id,
|
562
|
+
cell.row.account_id,
|
563
|
+
cell.subcol.col.key,
|
564
|
+
cell.subcol.subkpi and cell.subcol.subkpi.id,
|
565
|
+
)
|
566
|
+
|
567
|
+
@classmethod
|
568
|
+
def _unpack_cell_id(cls, cell_id: str) -> tuple[int, int | None, int, int | None]:
|
569
|
+
kpi_id, account_id, col_key, subkpi_id = cell_id.split("#")
|
570
|
+
kpi_id = int(kpi_id)
|
571
|
+
account_id = int(account_id) if account_id else None
|
572
|
+
period_id = int(col_key)
|
573
|
+
subkpi_id = int(subkpi_id) if subkpi_id else None
|
574
|
+
return kpi_id, account_id, period_id, subkpi_id
|
@@ -13,6 +13,7 @@ from odoo.exceptions import UserError, ValidationError
|
|
13
13
|
|
14
14
|
from .aep import AccountingExpressionProcessor as AEP
|
15
15
|
from .expression_evaluator import ExpressionEvaluator
|
16
|
+
from .kpimatrix import KpiMatrix
|
16
17
|
|
17
18
|
_logger = logging.getLogger(__name__)
|
18
19
|
|
@@ -580,6 +581,16 @@ class MisReportInstance(models.Model):
|
|
580
581
|
string="Filter box search view",
|
581
582
|
help="Search view to customize the filter box in the report widget.",
|
582
583
|
)
|
584
|
+
user_can_read_annotation = fields.Boolean(
|
585
|
+
compute="_compute_user_can_read_annotation",
|
586
|
+
)
|
587
|
+
user_can_edit_annotation = fields.Boolean(
|
588
|
+
compute="_compute_user_can_edit_annotation",
|
589
|
+
)
|
590
|
+
|
591
|
+
wide_display_by_default = fields.Boolean(
|
592
|
+
string="Open report in wide mode by default",
|
593
|
+
)
|
583
594
|
|
584
595
|
@api.depends("report_id.move_lines_source")
|
585
596
|
def _compute_widget_search_view_id(self):
|
@@ -877,7 +888,44 @@ class MisReportInstance(models.Model):
|
|
877
888
|
def compute(self):
|
878
889
|
self.ensure_one()
|
879
890
|
kpi_matrix = self._compute_matrix()
|
880
|
-
|
891
|
+
ret = kpi_matrix.as_dict()
|
892
|
+
|
893
|
+
ret["notes"] = self.get_notes_by_cell_id()
|
894
|
+
return ret
|
895
|
+
|
896
|
+
def get_notes_by_cell_id(self) -> dict:
|
897
|
+
self.ensure_one()
|
898
|
+
if not self.user_can_read_annotation:
|
899
|
+
return {}
|
900
|
+
|
901
|
+
annotations = self.env["mis.report.instance.annotation"].search(
|
902
|
+
[
|
903
|
+
("period_id", "in", self.period_ids.ids),
|
904
|
+
]
|
905
|
+
)
|
906
|
+
annotation_context = self._get_annotation_context()
|
907
|
+
annotations = annotations.filtered(
|
908
|
+
lambda rec: rec.annotation_context == annotation_context
|
909
|
+
)
|
910
|
+
|
911
|
+
annotations_sorted = sorted(
|
912
|
+
annotations,
|
913
|
+
key=lambda r: (
|
914
|
+
r.kpi_id.sequence,
|
915
|
+
r.period_id.sequence,
|
916
|
+
r.subkpi_id.sequence,
|
917
|
+
),
|
918
|
+
)
|
919
|
+
|
920
|
+
return {
|
921
|
+
KpiMatrix._make_cell_id(
|
922
|
+
annotation.kpi_id.id,
|
923
|
+
False,
|
924
|
+
annotation.period_id.id,
|
925
|
+
annotation.subkpi_id and annotation.subkpi_id.id,
|
926
|
+
): {"text": annotation.note, "sequence": sequence}
|
927
|
+
for sequence, annotation in enumerate(annotations_sorted, 1)
|
928
|
+
}
|
881
929
|
|
882
930
|
@api.model
|
883
931
|
def _get_drilldown_views_and_orders(self):
|
@@ -940,3 +988,25 @@ class MisReportInstance(models.Model):
|
|
940
988
|
return f"{kpi.description} - {account.display_name} - {period.display_name}"
|
941
989
|
else:
|
942
990
|
return f"{kpi.description} - {period.display_name}"
|
991
|
+
|
992
|
+
def _get_annotation_context(self):
|
993
|
+
"""Return the context used to filter annotation linked to this instance."""
|
994
|
+
self.ensure_one()
|
995
|
+
annotation_context = {}
|
996
|
+
if query_company_ids := self.query_company_ids.ids:
|
997
|
+
# sort ids to make the comparaison easier
|
998
|
+
annotation_context["query_company_ids"] = sorted(query_company_ids)
|
999
|
+
|
1000
|
+
return annotation_context
|
1001
|
+
|
1002
|
+
@api.depends_context("uid")
|
1003
|
+
def _compute_user_can_read_annotation(self):
|
1004
|
+
self.user_can_read_annotation = self.env.user.has_group(
|
1005
|
+
"mis_builder.group_read_annotation"
|
1006
|
+
)
|
1007
|
+
|
1008
|
+
@api.depends_context("uid")
|
1009
|
+
def _compute_user_can_edit_annotation(self):
|
1010
|
+
self.user_can_edit_annotation = self.env.user.has_group(
|
1011
|
+
"mis_builder.group_edit_annotation"
|
1012
|
+
)
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# Copyright 2025 ACSONE SA/NV
|
2
|
+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
3
|
+
|
4
|
+
|
5
|
+
from odoo import _, api, fields, models
|
6
|
+
from odoo.exceptions import AccessError
|
7
|
+
|
8
|
+
from .kpimatrix import KpiMatrix
|
9
|
+
|
10
|
+
|
11
|
+
class MisReportInstanceAnnotation(models.Model):
|
12
|
+
_name = "mis.report.instance.annotation"
|
13
|
+
_description = "Mis Report Instance Annotation"
|
14
|
+
|
15
|
+
period_id = fields.Many2one(
|
16
|
+
comodel_name="mis.report.instance.period",
|
17
|
+
ondelete="cascade",
|
18
|
+
required=True,
|
19
|
+
)
|
20
|
+
kpi_id = fields.Many2one(
|
21
|
+
comodel_name="mis.report.kpi",
|
22
|
+
ondelete="cascade",
|
23
|
+
required=True,
|
24
|
+
)
|
25
|
+
subkpi_id = fields.Many2one(
|
26
|
+
comodel_name="mis.report.subkpi",
|
27
|
+
ondelete="cascade",
|
28
|
+
)
|
29
|
+
note = fields.Char()
|
30
|
+
annotation_context = fields.Json(
|
31
|
+
help="""
|
32
|
+
Context used when adding annotation
|
33
|
+
"""
|
34
|
+
)
|
35
|
+
|
36
|
+
def init(self):
|
37
|
+
self.env.cr.execute(
|
38
|
+
"""
|
39
|
+
CREATE INDEX IF NOT EXISTS
|
40
|
+
mis_report_instance_annotation_period_id_kpi_id_subkpi_id_idx
|
41
|
+
ON mis_report_instance_annotation(period_id,kpi_id,subkpi_id);
|
42
|
+
"""
|
43
|
+
)
|
44
|
+
|
45
|
+
@api.model
|
46
|
+
def _get_first_matching_annotation(self, cell_id, instance_id):
|
47
|
+
"""
|
48
|
+
Return first annoation
|
49
|
+
matching exactly the period,kpi,subkpi and annotation context
|
50
|
+
"""
|
51
|
+
|
52
|
+
kpi_id, _, period_id, subkpi_id = KpiMatrix._unpack_cell_id(cell_id)
|
53
|
+
|
54
|
+
annotations = self.env["mis.report.instance.annotation"].search(
|
55
|
+
[
|
56
|
+
("period_id", "=", period_id),
|
57
|
+
("kpi_id", "=", kpi_id),
|
58
|
+
("subkpi_id", "=", subkpi_id),
|
59
|
+
],
|
60
|
+
)
|
61
|
+
annotation_context = (
|
62
|
+
self.env["mis.report.instance"]
|
63
|
+
.browse(instance_id)
|
64
|
+
._get_annotation_context()
|
65
|
+
)
|
66
|
+
annotation = fields.first(
|
67
|
+
annotations.filtered(
|
68
|
+
lambda rec: rec.annotation_context == annotation_context
|
69
|
+
)
|
70
|
+
)
|
71
|
+
return annotation
|
72
|
+
|
73
|
+
@api.model
|
74
|
+
def set_annotation(self, cell_id, instance_id, note):
|
75
|
+
if (
|
76
|
+
not self.env["mis.report.instance"]
|
77
|
+
.browse(instance_id)
|
78
|
+
.user_can_edit_annotation
|
79
|
+
):
|
80
|
+
raise AccessError(_("You do not have the rights to edit annotations"))
|
81
|
+
|
82
|
+
annotation = self._get_first_matching_annotation(cell_id, instance_id)
|
83
|
+
|
84
|
+
if annotation:
|
85
|
+
annotation.note = note
|
86
|
+
else:
|
87
|
+
kpi_id, _account_id, period_id, subkpi_id = KpiMatrix._unpack_cell_id(
|
88
|
+
cell_id
|
89
|
+
)
|
90
|
+
self.env["mis.report.instance.annotation"].create(
|
91
|
+
{
|
92
|
+
"period_id": period_id,
|
93
|
+
"kpi_id": kpi_id,
|
94
|
+
"subkpi_id": subkpi_id,
|
95
|
+
"note": note,
|
96
|
+
"annotation_context": self.env["mis.report.instance"]
|
97
|
+
.browse(instance_id)
|
98
|
+
._get_annotation_context(),
|
99
|
+
}
|
100
|
+
)
|
101
|
+
|
102
|
+
@api.model
|
103
|
+
def remove_annotation(self, cell_id, instance_id):
|
104
|
+
if (
|
105
|
+
not self.env["mis.report.instance"]
|
106
|
+
.browse(instance_id)
|
107
|
+
.user_can_edit_annotation
|
108
|
+
):
|
109
|
+
raise AccessError(_("You do not have the rights to edit annotations"))
|
110
|
+
|
111
|
+
annotation = self._get_first_matching_annotation(cell_id, instance_id)
|
112
|
+
if annotation:
|
113
|
+
annotation.unlink()
|
@@ -17,6 +17,7 @@
|
|
17
17
|
<t t-foreach="docs" t-as="o">
|
18
18
|
<t t-call="web.internal_layout">
|
19
19
|
<t t-set="matrix" t-value="o._compute_matrix()" />
|
20
|
+
<t t-set="notes" t-value="o.get_notes_by_cell_id()" />
|
20
21
|
<t t-set="style_obj" t-value="o.env['mis.report.style']" />
|
21
22
|
<div class="page">
|
22
23
|
<h3>
|
@@ -97,12 +98,34 @@
|
|
97
98
|
<t
|
98
99
|
t-out="cell and cell.val_rendered or ''"
|
99
100
|
/>
|
101
|
+
<span
|
102
|
+
class="oe_mis_builder_footnote"
|
103
|
+
t-if="cell"
|
104
|
+
>
|
105
|
+
<t
|
106
|
+
t-out="notes.get(cell.cell_id,{}).get('sequence','')"
|
107
|
+
/>
|
108
|
+
</span>
|
100
109
|
</div>
|
101
110
|
</t>
|
102
111
|
</div>
|
103
112
|
</t>
|
104
113
|
</div>
|
105
114
|
</div>
|
115
|
+
<!-- Foot notes -->
|
116
|
+
<div class="oe_mis_builder_footnote_div">
|
117
|
+
<table class="oe_mis_builder_footnote_table">
|
118
|
+
<t
|
119
|
+
t-foreach="sorted(notes.values(),key=lambda r:r['sequence'])"
|
120
|
+
t-as="note"
|
121
|
+
>
|
122
|
+
<tr>
|
123
|
+
<td><t t-out="note['sequence']" />. </td>
|
124
|
+
<td><t t-out="note['text']" /></td>
|
125
|
+
</tr>
|
126
|
+
</t>
|
127
|
+
</table>
|
128
|
+
</div>
|
106
129
|
</div>
|
107
130
|
</t>
|
108
131
|
</t>
|
@@ -6,7 +6,7 @@ import numbers
|
|
6
6
|
from collections import defaultdict
|
7
7
|
from datetime import datetime
|
8
8
|
|
9
|
-
from odoo import _, fields, models
|
9
|
+
from odoo import _, api, fields, models
|
10
10
|
|
11
11
|
from ..models.accounting_none import AccountingNone
|
12
12
|
from ..models.data_error import DataError
|
@@ -26,9 +26,18 @@ class MisBuilderXlsx(models.AbstractModel):
|
|
26
26
|
_description = "MIS Builder XLSX report"
|
27
27
|
_inherit = "report.report_xlsx.abstract"
|
28
28
|
|
29
|
+
@api.model
|
30
|
+
def _mis_builder_add_annotation(self, sheet, cell, row_pos, col_pos, notes):
|
31
|
+
"""
|
32
|
+
Add anotation as a comment on cell in .xls
|
33
|
+
"""
|
34
|
+
if cell and (annotation := notes.get(cell.cell_id, {}).get("text")):
|
35
|
+
sheet.write_comment(row_pos, col_pos, annotation)
|
36
|
+
|
29
37
|
def generate_xlsx_report(self, workbook, data, objects):
|
30
38
|
# get the computed result of the report
|
31
39
|
matrix = objects._compute_matrix()
|
40
|
+
notes = objects.get_notes_by_cell_id()
|
32
41
|
style_obj = self.env["mis.report.style"]
|
33
42
|
|
34
43
|
# create worksheet
|
@@ -120,6 +129,7 @@ class MisBuilderXlsx(models.AbstractModel):
|
|
120
129
|
)
|
121
130
|
for cell in row.iter_cells():
|
122
131
|
col_pos += 1
|
132
|
+
self._mis_builder_add_annotation(sheet, cell, row_pos, col_pos, notes)
|
123
133
|
if not cell or cell.val is AccountingNone:
|
124
134
|
# TODO col/subcol format
|
125
135
|
sheet.write(row_pos, col_pos, "", row_format)
|
@@ -20,3 +20,5 @@ access_mis_report_subreport,access_mis_report_subreport,model_mis_report_subrepo
|
|
20
20
|
manage_mis_report_style,access_mis_report_style,model_mis_report_style,account.group_account_manager,1,1,1,1
|
21
21
|
access_mis_report_style,access_mis_report_style,model_mis_report_style,base.group_user,1,0,0,0
|
22
22
|
access_add_to_dashboard_wizard,access_add_to_dashboard_wizard,model_add_mis_report_instance_dashboard_wizard,base.group_user,1,1,1,0
|
23
|
+
access_read_mis_report_annotation, access_read_mis_report_annotation,model_mis_report_instance_annotation,mis_builder.group_read_annotation,1,0,0,0
|
24
|
+
access_edit_mis_report_annotation, access_edit_mis_report_annotation,model_mis_report_instance_annotation,mis_builder.group_edit_annotation,1,1,1,1
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8" ?>
|
2
|
+
<odoo>
|
3
|
+
<record model="res.groups" id="group_read_annotation">
|
4
|
+
<field name="name">MIS Report: view annotations</field>
|
5
|
+
</record>
|
6
|
+
<record model="res.groups" id="group_edit_annotation">
|
7
|
+
<field name="name">MIS Report: add annotations</field>
|
8
|
+
<field
|
9
|
+
name="implied_ids"
|
10
|
+
eval="[Command.link(ref('mis_builder.group_read_annotation'))]"
|
11
|
+
/>
|
12
|
+
<field
|
13
|
+
name="users"
|
14
|
+
eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"
|
15
|
+
/>
|
16
|
+
</record>
|
17
|
+
</odoo>
|
@@ -367,7 +367,7 @@ ul.auto-toc {
|
|
367
367
|
!! This file is generated by oca-gen-addon-readme !!
|
368
368
|
!! changes will be overwritten. !!
|
369
369
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
370
|
-
!! source digest: sha256:
|
370
|
+
!! source digest: sha256:eaf310c997ae9746cf01edf102baa7c519355121536c5a695b45470f6ab27dee
|
371
371
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
372
372
|
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Production/Stable" src="https://img.shields.io/badge/maturity-Production%2FStable-green.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/mis-builder/tree/16.0/mis_builder"><img alt="OCA/mis-builder" src="https://img.shields.io/badge/github-OCA%2Fmis--builder-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/mis-builder-16-0/mis-builder-16-0-mis_builder"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/mis-builder&target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
|
373
373
|
<p>This module allows you to build Management Information Systems dashboards.
|