ssb-dash-framework 0.2.1__tar.gz → 0.2.2__tar.gz

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.
Files changed (62) hide show
  1. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/PKG-INFO +5 -4
  2. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/pyproject.toml +14 -2
  3. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/__init__.py +26 -6
  4. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/assets/dashAgGridFunctions.js +37 -10
  5. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/assets/stylesheet.css +31 -4
  6. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/control/control_framework_base.py +63 -35
  7. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/__init__.py +24 -6
  8. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/aarsregnskap.py +17 -8
  9. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/agg_dist_plotter.py +3 -3
  10. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/altinn_control_view.py +84 -32
  11. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/altinn_data_capture.py +5 -5
  12. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/altinn_editor/__init__.py +2 -0
  13. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_comment.py +2 -2
  14. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_contact.py +3 -4
  15. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_control.py +3 -4
  16. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_history.py +29 -7
  17. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_main_view.py +21 -19
  18. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_primary_table.py +101 -19
  19. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_submitted_forms.py +8 -4
  20. ssb_dash_framework-0.2.2/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_supporting_table.py +244 -0
  21. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_unit_details.py +4 -5
  22. ssb_dash_framework-0.2.2/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_utility.py +17 -0
  23. ssb_dash_framework-0.2.2/src/ssb_dash_framework/modules/bedriftstabell.py +310 -0
  24. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/bofregistry.py +38 -18
  25. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/building_blocks/canvas.py +6 -6
  26. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/building_blocks/figuredisplay.py +6 -6
  27. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/building_blocks/map_display.py +27 -27
  28. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/building_blocks/multimodule.py +6 -6
  29. ssb_dash_framework-0.2.2/src/ssb_dash_framework/modules/building_blocks/tables.py +411 -0
  30. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/freesearch.py +13 -14
  31. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/hb_method.py +13 -13
  32. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/macro_module.py +287 -81
  33. ssb_dash_framework-0.2.2/src/ssb_dash_framework/modules/nspek.py +412 -0
  34. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/parquet_editor.py +215 -47
  35. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/pi_memorizer.py +7 -13
  36. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/skjemapdfviewer.py +10 -15
  37. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/visualizationbuilder.py +12 -16
  38. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/setup/app_setup.py +9 -9
  39. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/setup/main_layout.py +5 -10
  40. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/setup/variableselector.py +13 -14
  41. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/utils/alert_handler.py +22 -22
  42. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/utils/app_logger.py +5 -5
  43. ssb_dash_framework-0.2.2/src/ssb_dash_framework/utils/core_query_functions.py +170 -0
  44. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/utils/datahelper.py +6 -5
  45. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/utils/debugger_modal.py +3 -3
  46. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/utils/eimerdb_helpers.py +4 -4
  47. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/utils/functions.py +10 -4
  48. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/utils/implementations.py +22 -28
  49. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/utils/module_validation.py +1 -1
  50. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/utils/r_helpers.py +24 -14
  51. ssb_dash_framework-0.2.1/src/ssb_dash_framework/modules/altinn_editor/altinn_editor_supporting_table.py +0 -320
  52. ssb_dash_framework-0.2.1/src/ssb_dash_framework/modules/building_blocks/tables.py +0 -678
  53. ssb_dash_framework-0.2.1/src/ssb_dash_framework/modules/control.py +0 -206
  54. ssb_dash_framework-0.2.1/src/ssb_dash_framework/utils/core_query_functions.py +0 -75
  55. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/LICENSE +0 -0
  56. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/README.md +0 -0
  57. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/__main__.py +0 -0
  58. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/control/__init__.py +0 -0
  59. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/modules/building_blocks/__init__.py +0 -0
  60. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/py.typed +0 -0
  61. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/setup/__init__.py +0 -0
  62. {ssb_dash_framework-0.2.1 → ssb_dash_framework-0.2.2}/src/ssb_dash_framework/utils/__init__.py +0 -0
@@ -1,18 +1,19 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: ssb-dash-framework
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: SSB Dash Framework
5
- License: GPL-3.0
5
+ License-Expression: GPL-3.0
6
+ License-File: LICENSE
6
7
  Author: Magnus Theodor Engh
7
8
  Author-email: dor@ssb.no
8
9
  Requires-Python: >=3.10,<4.0
9
10
  Classifier: Development Status :: 4 - Beta
10
- Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
15
  Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
16
17
  Requires-Dist: click (>=8.0.1)
17
18
  Requires-Dist: dapla-toolbelt (>=2.0.8,<5.0.0)
18
19
  Requires-Dist: dash (>=3.3.0,<4.0.0)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ssb-dash-framework"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  description = "SSB Dash Framework"
5
5
  authors = [{ name = "Magnus Theodor Engh", email = "dor@ssb.no" }]
6
6
  license = "GPL-3.0"
@@ -46,7 +46,6 @@ requires-poetry = ">=2.0"
46
46
  pygments = ">=2.10.0"
47
47
  black = { extras = ["jupyter"], version = ">=23.1.0" }
48
48
  coverage = { extras = ["toml"], version = ">=6.2" }
49
- darglint = ">=1.8.1"
50
49
  furo = ">=2021.11.12"
51
50
  mypy = ">=0.930"
52
51
  pre-commit = ">=2.16.0"
@@ -61,6 +60,8 @@ typeguard = ">=2.13.3"
61
60
  xdoctest = { extras = ["colors"], version = ">=0.15.10" }
62
61
  myst-parser = { version = ">=0.16.1" }
63
62
  deptry = ">=0.23.0"
63
+ pydoclint = ">=0.8.3"
64
+ pandas-stubs = ">=2.3.1"
64
65
 
65
66
  [tool.poetry.requires-plugins]
66
67
  poetry-plugin-export = ">=1.9"
@@ -92,6 +93,16 @@ show_column_numbers = true
92
93
  show_error_context = true
93
94
  ignore_missing_imports = true
94
95
 
96
+ [tool.pydoclint]
97
+ style = "google"
98
+ exclude = '\.git|\.nox'
99
+ arg-type-hints-in-docstring = false
100
+ check-return-types = false
101
+ check-yield-types = false
102
+ allow-init-docstring = true
103
+ # native-mode-noqa-location = "definition"
104
+ quiet = true
105
+
95
106
  [tool.ruff]
96
107
  force-exclude = true # Apply excludes to pre-commit
97
108
  show-fixes = true
@@ -130,6 +141,7 @@ ignore = [
130
141
  "E501", # Supress line-too-long warnings: trust black's judgement on this one.
131
142
  "PLR2004", # Allow to compare with unnamed numerical constants.
132
143
  ]
144
+ external = ["DOC"] ## Avoiding removing any codes starting with `DOC` from any `# noqa` directives.
133
145
 
134
146
  [tool.ruff.lint.isort]
135
147
  force-single-line = true
@@ -8,20 +8,25 @@ from .modules import AarsregnskapWindow
8
8
  from .modules import AggDistPlotter
9
9
  from .modules import AggDistPlotterTab
10
10
  from .modules import AggDistPlotterWindow
11
- from .modules import AltinnControlView
11
+ from .modules import AltinnControlViewTab
12
12
  from .modules import AltinnControlViewWindow
13
13
  from .modules import AltinnDataCapture
14
14
  from .modules import AltinnDataCaptureTab
15
15
  from .modules import AltinnDataCaptureWindow
16
16
  from .modules import AltinnSkjemadataEditor
17
+ from .modules import AltinnSupportTable
18
+ from .modules import Bedriftstabell
19
+ from .modules import BedriftstabellTab
20
+ from .modules import BedriftstabellWindow
17
21
  from .modules import BofInformation
18
22
  from .modules import BofInformationTab
19
23
  from .modules import BofInformationWindow
20
24
  from .modules import Canvas
21
25
  from .modules import CanvasTab
22
26
  from .modules import CanvasWindow
23
- from .modules import Control
24
- from .modules import ControlWindow
27
+ from .modules import ControlView
28
+ from .modules import ControlViewTab
29
+ from .modules import ControlViewWindow
25
30
  from .modules import EditingTable
26
31
  from .modules import EditingTableTab
27
32
  from .modules import EditingTableWindow
@@ -42,6 +47,9 @@ from .modules import MapDisplayWindow
42
47
  from .modules import MultiModule
43
48
  from .modules import MultiModuleTab
44
49
  from .modules import MultiModuleWindow
50
+ from .modules import Naeringsspesifikasjon
51
+ from .modules import NaeringsspesifikasjonTab
52
+ from .modules import NaeringsspesifikasjonWindow
45
53
  from .modules import ParquetEditor
46
54
  from .modules import ParquetEditorChangelog
47
55
  from .modules import PimemorizerTab
@@ -52,6 +60,7 @@ from .modules import VisualizationBuilder
52
60
  from .modules import VisualizationBuilderWindow
53
61
  from .modules import apply_edits
54
62
  from .modules import export_from_parqueteditor
63
+ from .modules import get_export_log_path
55
64
  from .modules import get_log_path
56
65
  from .setup import VariableSelector
57
66
  from .setup import VariableSelectorOption
@@ -72,6 +81,7 @@ from .utils import create_database
72
81
  from .utils import create_database_engine
73
82
  from .utils import enable_app_logging
74
83
  from .utils import hb_method
84
+ from .utils import ibis_filter_with_dict
75
85
  from .utils import module_validator
76
86
  from .utils import sidebar_button
77
87
 
@@ -85,21 +95,26 @@ __all__ = [
85
95
  "AggDistPlotterTab",
86
96
  "AggDistPlotterWindow",
87
97
  "AlertHandler",
88
- "AltinnControlView",
98
+ "AltinnControlViewTab",
89
99
  "AltinnControlViewWindow",
90
100
  "AltinnDataCapture",
91
101
  "AltinnDataCaptureTab",
92
102
  "AltinnDataCaptureWindow",
93
103
  "AltinnSkjemadataEditor",
104
+ "AltinnSupportTable",
105
+ "Bedriftstabell",
106
+ "BedriftstabellTab",
107
+ "BedriftstabellWindow",
94
108
  "BofInformation",
95
109
  "BofInformationTab",
96
110
  "BofInformationWindow",
97
111
  "Canvas",
98
112
  "CanvasTab",
99
113
  "CanvasWindow",
100
- "Control",
101
114
  "ControlFrameworkBase",
102
- "ControlWindow",
115
+ "ControlView",
116
+ "ControlViewTab",
117
+ "ControlViewWindow",
103
118
  "DatabaseBuilderAltinnEimerdb",
104
119
  "DebugInspector",
105
120
  "DemoDataCreator",
@@ -127,6 +142,9 @@ __all__ = [
127
142
  "MultiModuleWindow",
128
143
  "MultiModuleWindow",
129
144
  "MultiModuleWindow",
145
+ "Naeringsspesifikasjon",
146
+ "NaeringsspesifikasjonTab",
147
+ "NaeringsspesifikasjonWindow",
130
148
  "ParquetEditor",
131
149
  "ParquetEditorChangelog",
132
150
  "PimemorizerTab",
@@ -148,7 +166,9 @@ __all__ = [
148
166
  "create_database_engine",
149
167
  "enable_app_logging",
150
168
  "export_from_parqueteditor",
169
+ "get_export_log_path",
151
170
  "get_log_path",
171
+ "ibis_filter_with_dict",
152
172
  "main_layout",
153
173
  "module_validator",
154
174
  "register_control",
@@ -155,11 +155,12 @@ window.dashAgGridFunctions.MacroModule = {
155
155
 
156
156
  // === Function displayDiffHighlight (Compare current cell's value to previous year, highlight if different) ===
157
157
  displayDiffHighlight(props) {
158
- const field = props.colDef.field;
159
- const value = props.value;
160
158
 
161
159
  if (!props.data) return {};
162
160
 
161
+ const field = props.colDef.field;
162
+ const value = props.value;
163
+
163
164
  const normalize = (v) =>
164
165
  v !== null && v !== undefined ? String(v).trim() : "";
165
166
 
@@ -190,14 +191,6 @@ window.dashAgGridFunctions.MacroModule = {
190
191
  return {}; // no change
191
192
  }
192
193
 
193
- // all other columns
194
- if (field.endsWith("_x")) {
195
- return {
196
- backgroundColor: '#e8e9eb',
197
- color: 'black'
198
- };
199
- }
200
-
201
194
  const prevField = field + "_x";
202
195
  const prevValue = normalize(props.data[prevField]);
203
196
  const currentValue = normalize(value);
@@ -228,6 +221,40 @@ window.dashAgGridFunctions.MacroModule = {
228
221
  const prefixF = String(naringF).substring(0, 2);
229
222
 
230
223
  return prefixB !== prefixF;
224
+ },
225
+
226
+ // === Function displayDiffColumnHighlight (Mark tilgang & avgang on the diff-column) ===
227
+ displayDiffColumnHighlight(props) {
228
+ if (!props.data) return {};
229
+
230
+ const field = props.colDef.field;
231
+
232
+ const isDiffColumn = field.endsWith("_diff");
233
+ const isExitHighlightField =
234
+ (field === "orgnr_b" || field === "navn") &&
235
+ props.data.is_avgang &&
236
+ props.data.is_exiter;
237
+
238
+ // Guard: only apply to allowed columns
239
+ if (!isDiffColumn && !isExitHighlightField) return {};
240
+
241
+ // tilgang (still only for diff columns)
242
+ if (isDiffColumn && props.data.is_tilgang) {
243
+ return {
244
+ backgroundColor: "#c7f5c7",
245
+ color: "black",
246
+ };
247
+ }
248
+
249
+ // avgang (diff columns OR exiter name/orgnr)
250
+ if (props.data.is_avgang) {
251
+ return {
252
+ backgroundColor: "#ffc7c7",
253
+ color: "black",
254
+ };
255
+ }
256
+
257
+ return {};
231
258
  }
232
259
 
233
260
  };
@@ -131,12 +131,13 @@ Aarsregnskap
131
131
  }
132
132
 
133
133
  .aarsregnskap-pdf-col {
134
+ padding: 15px;
134
135
  flex: 1;
135
136
  min-height: 0;
136
137
  }
137
138
 
138
139
  .aarsregnskap-pdf-iframe {
139
- width: 100%;
140
+ width: 120vh;
140
141
  height: 100%;
141
142
  border: none;
142
143
  }
@@ -155,7 +156,7 @@ AggDistPlotter
155
156
  }
156
157
 
157
158
  /*
158
- AltinnControlView
159
+ ControlView
159
160
  */
160
161
 
161
162
 
@@ -200,7 +201,7 @@ Bofregistry
200
201
 
201
202
  .bofregistry-table-bedrift-aggrid {
202
203
  width: 100%;
203
- height: 45vh;
204
+ height: 55vh !important;
204
205
  }
205
206
 
206
207
  .bofregistry-modal {
@@ -213,7 +214,33 @@ Bofregistry
213
214
 
214
215
  .bofregistry-modal-aggrid {
215
216
  height: 100% !important;
216
- width: 100% !important;
217
+ width: 60vh !important;
218
+ }
219
+
220
+ /*
221
+ Altinn Editor History
222
+ */
223
+ .history-modal .modal-dialog {
224
+ max-width: 70vw !important;
225
+ width: 80vw !important;
226
+ }
227
+
228
+ .history-modal .modal-content {
229
+ height: 60vh !important;
230
+ }
231
+
232
+
233
+ /*
234
+ Altinn Editor Support Tables
235
+ */
236
+ .hjelpetabeller-modal .modal-dialog {
237
+ max-width: 90vw !important;
238
+ width: 90vw !important;
239
+ }
240
+
241
+ .hjelpetabeller-modal .modal-content {
242
+ height: 70vh !important;
243
+ overflow: hidden;
217
244
  }
218
245
 
219
246
  /*
@@ -29,22 +29,22 @@ def register_control(
29
29
  It is recommended to have the name of your control method / function start with the prefix 'control_'.
30
30
 
31
31
  Args:
32
- kontrollid (str): The id of the control, preferably a code or shortened name. Must be unique. Note that in the control module controls are sorted alphabetically based on kontrollid, meaning you can add numbers as prefix to control the sorting order in the app.
33
- kontrolltype (str): The type of control. Must be 'H' (Hard control), 'S' (Soft control) or 'I' (Informative)
34
- beskrivelse (str): A description of the control.
35
- kontrollerte_variabler (list[str]): A list of variables that are covered / relevant to the control.
36
- sorteringsvariabel (str | None): Variable to sort the values on.
37
- sortering (str | None): Controls if the sorting is ascending (ASC) or descending (DESC). Defaults to DESC
38
- kwargs (Any): These will be added to the _control_meta dict attached to the method as additional key and value pairs.
32
+ kontrollid: The id of the control, preferably a code or shortened name. Must be unique. Note that in the control module controls are sorted alphabetically based on kontrollid, meaning you can add numbers as prefix to control the sorting order in the app.
33
+ kontrolltype: The type of control. Must be 'H' (Hard control), 'S' (Soft control) or 'I' (Informative)
34
+ beskrivelse: A description of the control.
35
+ kontrollerte_variabler: A list of variables that are covered / relevant to the control.
36
+ sorteringsvariabel: Variable to sort the values on.
37
+ sortering: Controls if the sorting is ascending (ASC) or descending (DESC). Defaults to DESC
38
+ **kwargs: These will be added to the `_control_meta` dict attached to the method as additional key and value pairs.
39
39
 
40
40
  Raises:
41
41
  TypeError: If `kontrollerte_variabler` is not a list of strings.
42
- ValueError: If `kontrolltype` is not one of 'H', 'S', or 'I'.
43
- ValueError: If `sortering` is not one of 'ASC' or 'DESC'.
44
- ValueError: If required keys are missing from the metadata dictionary.
42
+ ValueError: If `kontrolltype` is not one of 'H', 'S', or 'I'. Or
43
+ if `sortering` is not one of 'ASC' or 'DESC'. Or
44
+ if required keys are missing from the metadata dictionary.
45
45
 
46
46
  Returns:
47
- Callable[..., Any]: The decorated function with added attribute '_control_meta' containing a dictionary with metadata.
47
+ The decorated function with added attribute '_control_meta' containing a dictionary with metadata.
48
48
 
49
49
  Example:
50
50
  @register_control(
@@ -227,8 +227,7 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
227
227
  self.conn.insert("kontroller", rows_to_register)
228
228
  elif conn_is_ibis(self.conn):
229
229
  conn = self.conn
230
- k = conn.table("kontroller") # type: ignore[attr-defined]
231
- k.insert(rows_to_register)
230
+ conn.insert("kontroller", rows_to_register)
232
231
  else:
233
232
  raise NotImplementedError(
234
233
  f"Connection type '{type(self.conn)}' is currently not implemented."
@@ -313,18 +312,17 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
313
312
 
314
313
  Raises:
315
314
  TypeError: If the control method does not return a `pd.DataFrame`.
316
- ValueError: If a required column from `_required_kontrollutslag_columns` is missing.
317
- ValueError: If the result contains extra columns that are not allowed.
318
- ValueError: If the control is not registered in `self.controls`.
319
- ValueError: If any key in `applies_to_subset` has too many unique values.
320
- ValueError: If any value in `applies_to_subset` does not match the expected period.
321
- ValueError: If the results contain more than one unique `kontrollid`.
322
- ValueError: If the `kontrollid` in the results does not match the registered `_control_meta`.
323
- ValueError: If there are duplicated rows in the results based on `time_units`, `ident`, and `refnr`.
315
+ ValueError: If a required column from `_required_kontrollutslag_columns` is missing. Or
316
+ if the result contains extra columns that are not allowed. Or
317
+ if the control is not registered in `self.controls`. Or
318
+ if any key in `applies_to_subset` has too many unique values. Or
319
+ if any value in `applies_to_subset` does not match the expected period. Or
320
+ if the results contain more than one unique `kontrollid`. Or
321
+ if the `kontrollid` in the results does not match the registered `_control_meta`. Or
322
+ if there are duplicated rows in the results based on `time_units`, `ident`, and `refnr`.
324
323
  """
325
324
  logger.info(f"Running control: {control}")
326
325
  results = getattr(self, control)()
327
-
328
326
  logger.debug("Starting validation of results.")
329
327
  if not isinstance(results, pd.DataFrame):
330
328
  raise TypeError(
@@ -348,10 +346,14 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
348
346
  raise ValueError(
349
347
  f"Error when running {control}. Could not find {results['kontrollid'].unique()} among registered controls. Valid options retrieved from the 'kontrollutslag' table: {self.controls}"
350
348
  )
349
+
350
+ # IMPORTANT! This code must not fix the error for the user.
351
+ # This check exists because it is expected that users mistakenly forget to filter on periods / form type
352
+ # and that forgetting that filtering WILL cause false positives/negatives. Do not change this validation check.
351
353
  for key, value in self.applies_to_subset.items():
352
354
  if len(results[key].unique()) != 1:
353
355
  raise ValueError(
354
- f"Results from control {control} has too many unique values for '{key}'. Expected '{value[0]}'. Received: '{results[key].unique()}'"
356
+ f"Results from control '{control}' has too many unique values for '{key}'. Expected '{value[0]}'. Received: '{results[key].unique()}'\nYou "
355
357
  )
356
358
  if not value[0] == results[key].unique()[0]:
357
359
  raise ValueError(
@@ -392,6 +394,7 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
392
394
 
393
395
  Raises:
394
396
  NotImplementedError: If connection is not EimerDBInstance or Ibis connection.
397
+ ValueError: If the query fails for reasons other than an empty 'kontrollutslag' table.
395
398
  """
396
399
  logger.info("Getting current kontrollutslag.")
397
400
  if isinstance(self.conn, EimerDBInstance):
@@ -437,7 +440,10 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
437
440
  else:
438
441
  specific_control = None
439
442
  existing_kontrollutslag = self.get_current_kontrollutslag(specific_control)
440
- if existing_kontrollutslag is not None:
443
+ if existing_kontrollutslag is not None and not existing_kontrollutslag.empty:
444
+ logger.debug(
445
+ f"Merging new results with existing results.\nNew:{control_results.shape}\n{control_results.head(10)}\n\nExisting:{existing_kontrollutslag.shape}\n{existing_kontrollutslag.head(10)}"
446
+ )
441
447
  control_results = control_results.merge(
442
448
  existing_kontrollutslag,
443
449
  on=[*self.applies_to_subset.keys(), "kontrollid", "ident", "refnr"],
@@ -451,7 +457,7 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
451
457
  "kontrollid",
452
458
  "ident",
453
459
  "refnr",
454
- "verdi_x",
460
+ "verdi_x" if "verdi_x" in control_results.columns else "verdi",
455
461
  "utslag_x",
456
462
  ]
457
463
  ]
@@ -469,8 +475,7 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
469
475
  self.conn.insert("kontrollutslag", control_results)
470
476
  elif conn_is_ibis(self.conn):
471
477
  conn = self.conn
472
- k = conn.table("kontrollutslag") # type: ignore[attr-defined]
473
- k.insert(control_results)
478
+ conn.insert("kontrollutslag", control_results)
474
479
  else:
475
480
  raise NotImplementedError(
476
481
  f"Connection type '{type(self.conn)}' is currently not implemented."
@@ -493,25 +498,48 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
493
498
  logger.info("No existing rows found, ending here.")
494
499
  return None
495
500
  else:
501
+ logger.debug(
502
+ f"Merging new results with existing results.\nNew:{control_results.shape}\n{control_results.head(10)}\n\nExisting:{existing_kontrollutslag.shape}\n{existing_kontrollutslag.head(10)}"
503
+ )
496
504
  control_results = control_results.merge(
497
505
  existing_kontrollutslag,
498
- on=["kontrollid", "ident", "refnr"],
506
+ on=[*self.applies_to_subset.keys(), "kontrollid", "ident", "refnr"],
499
507
  how="outer",
500
508
  indicator=True,
501
- ).dropna()
509
+ )
510
+ logger.debug(f"{control_results}")
511
+ control_results = control_results.dropna(
512
+ subset=[col for col in control_results if col != "verdi"]
513
+ ) # TODO: Check if this causes unexpected behavior.
502
514
  if control_results.empty:
515
+ logger.debug(f"Empty control_results:\n{control_results}")
503
516
  raise ValueError(
504
- "Combined results from 'control_results' and 'existing_kontrollutslag' is empty."
517
+ "Combined results from 'control_results' and 'existing_kontrollutslag' is empty when it shouldn't be."
505
518
  )
506
519
  logger.debug(control_results)
507
520
  logger.debug(
508
521
  f"Utslag left:\n{control_results['utslag_x'].value_counts()}\nUtslag right:\n{control_results['utslag_y'].value_counts()}"
509
522
  )
510
- changed = control_results[
523
+ changed = control_results[ # This might have issues.
511
524
  control_results["utslag_x"] != control_results["utslag_y"]
512
- ][["kontrollid", "ident", "refnr", "verdi_x", "utslag_x"]].rename(
513
- columns={"utslag_x": "utslag", "verdi_x": "verdi"}
525
+ ][
526
+ [
527
+ *self.time_units,
528
+ "kontrollid",
529
+ "ident",
530
+ "refnr",
531
+ "verdi_x" if "verdi_x" in control_results.columns else "verdi",
532
+ "utslag_x",
533
+ ]
534
+ ].rename(
535
+ columns={"utslag_x": "utslag"}
514
536
  )
537
+ if "verdi_x" in changed.columns:
538
+ changed = changed.rename(columns={"verdi_x": "verdi"})
539
+
540
+ missing = set(self._required_kontrollutslag_columns) - set(changed.columns)
541
+ if missing:
542
+ raise ValueError(f"Missing required columns: {missing}")
515
543
  if changed.empty:
516
544
  logger.info("No changed rows, ending here.")
517
545
  return None
@@ -533,10 +561,10 @@ class ControlFrameworkBase: # TODO: Add some common control methods here for ea
533
561
  """Generates a SQL UPDATE query for updating rows in 'kontrollutslag'.
534
562
 
535
563
  Args:
536
- df_updates (pd.DataFrame): DataFrame with updates to apply.
564
+ df_updates: DataFrame with updates to apply.
537
565
 
538
566
  Returns:
539
- str: SQL query string.
567
+ SQL query string.
540
568
  """
541
569
  update_query = "UPDATE kontrollutslag SET utslag = CASE"
542
570
 
@@ -6,12 +6,19 @@ from .aarsregnskap import AarsregnskapWindow
6
6
  from .agg_dist_plotter import AggDistPlotter
7
7
  from .agg_dist_plotter import AggDistPlotterTab
8
8
  from .agg_dist_plotter import AggDistPlotterWindow
9
- from .altinn_control_view import AltinnControlView
9
+ from .altinn_control_view import AltinnControlViewTab
10
10
  from .altinn_control_view import AltinnControlViewWindow
11
+ from .altinn_control_view import ControlView
12
+ from .altinn_control_view import ControlViewTab
13
+ from .altinn_control_view import ControlViewWindow
11
14
  from .altinn_data_capture import AltinnDataCapture
12
15
  from .altinn_data_capture import AltinnDataCaptureTab
13
16
  from .altinn_data_capture import AltinnDataCaptureWindow
14
17
  from .altinn_editor import AltinnSkjemadataEditor
18
+ from .altinn_editor import AltinnSupportTable
19
+ from .bedriftstabell import Bedriftstabell
20
+ from .bedriftstabell import BedriftstabellTab
21
+ from .bedriftstabell import BedriftstabellWindow
15
22
  from .bofregistry import BofInformation
16
23
  from .bofregistry import BofInformationTab
17
24
  from .bofregistry import BofInformationWindow
@@ -30,8 +37,6 @@ from .building_blocks import MapDisplayWindow
30
37
  from .building_blocks import MultiModule
31
38
  from .building_blocks import MultiModuleTab
32
39
  from .building_blocks import MultiModuleWindow
33
- from .control import Control
34
- from .control import ControlWindow
35
40
  from .freesearch import FreeSearch
36
41
  from .freesearch import FreeSearchTab
37
42
  from .freesearch import FreeSearchWindow
@@ -40,10 +45,14 @@ from .hb_method import HBMethodWindow
40
45
  from .macro_module import MacroModule
41
46
  from .macro_module import MacroModuleTab
42
47
  from .macro_module import MacroModuleWindow
48
+ from .nspek import Naeringsspesifikasjon
49
+ from .nspek import NaeringsspesifikasjonTab
50
+ from .nspek import NaeringsspesifikasjonWindow
43
51
  from .parquet_editor import ParquetEditor
44
52
  from .parquet_editor import ParquetEditorChangelog
45
53
  from .parquet_editor import apply_edits
46
54
  from .parquet_editor import export_from_parqueteditor
55
+ from .parquet_editor import get_export_log_path
47
56
  from .parquet_editor import get_log_path
48
57
  from .pi_memorizer import PimemorizerTab
49
58
  from .skjemapdfviewer import SkjemapdfViewer
@@ -59,20 +68,25 @@ __all__ = [
59
68
  "AggDistPlotter",
60
69
  "AggDistPlotterTab",
61
70
  "AggDistPlotterWindow",
62
- "AltinnControlView",
71
+ "AltinnControlViewTab",
63
72
  "AltinnControlViewWindow",
64
73
  "AltinnDataCapture",
65
74
  "AltinnDataCaptureTab",
66
75
  "AltinnDataCaptureWindow",
67
76
  "AltinnSkjemadataEditor",
77
+ "AltinnSupportTable",
78
+ "Bedriftstabell",
79
+ "BedriftstabellTab",
80
+ "BedriftstabellWindow",
68
81
  "BofInformation",
69
82
  "BofInformationTab",
70
83
  "BofInformationWindow",
71
84
  "Canvas",
72
85
  "CanvasTab",
73
86
  "CanvasWindow",
74
- "Control",
75
- "ControlWindow",
87
+ "ControlView",
88
+ "ControlViewTab",
89
+ "ControlViewWindow",
76
90
  "EditingTable",
77
91
  "EditingTableTab",
78
92
  "EditingTableWindow",
@@ -93,6 +107,9 @@ __all__ = [
93
107
  "MultiModule",
94
108
  "MultiModuleTab",
95
109
  "MultiModuleWindow",
110
+ "Naeringsspesifikasjon",
111
+ "NaeringsspesifikasjonTab",
112
+ "NaeringsspesifikasjonWindow",
96
113
  "ParquetEditor",
97
114
  "ParquetEditorChangelog",
98
115
  "PimemorizerTab",
@@ -103,5 +120,6 @@ __all__ = [
103
120
  "VisualizationBuilderWindow",
104
121
  "apply_edits",
105
122
  "export_from_parqueteditor",
123
+ "get_export_log_path",
106
124
  "get_log_path",
107
125
  ]
@@ -24,10 +24,19 @@ class Aarsregnskap(ABC):
24
24
  """Module for displaying annual financial statements (Årsregnskap).
25
25
 
26
26
  Attributes:
27
- label (str): Label for the module when initialized, displayed as "Årsregnskap".
27
+ module_number: Sequential ID of the module instance.
28
+ module_name: Name of the module class.
29
+ label: User-visible label of the module, shown as "Årsregnskap".
30
+ icon: Emoji icon representing the module.
31
+ module_layout: The UI layout object returned by ``_create_layout()``.
28
32
  """
29
33
 
30
34
  _id_number: ClassVar[int] = 0
35
+ module_number: int
36
+ module_name: str
37
+ label: str
38
+ icon: str
39
+ module_layout: html.Div
31
40
 
32
41
  def __init__(
33
42
  self,
@@ -147,10 +156,10 @@ class Aarsregnskap(ABC):
147
156
  """Update the year input field based on the selected year.
148
157
 
149
158
  Args:
150
- aar (int): The selected year.
159
+ aar: The selected year.
151
160
 
152
161
  Returns:
153
- int: The updated year value.
162
+ The updated year value.
154
163
  """
155
164
  logger.debug(f"Args:\naar: {aar}\n")
156
165
  return aar
@@ -163,10 +172,10 @@ class Aarsregnskap(ABC):
163
172
  """Update the organization number input field.
164
173
 
165
174
  Args:
166
- orgnr (str): The selected organization number.
175
+ orgnr: The selected organization number.
167
176
 
168
177
  Returns:
169
- str: The updated organization number value.
178
+ The updated organization number value.
170
179
  """
171
180
  logger.debug(f"Args:\norgnr: {orgnr}\n")
172
181
  return orgnr
@@ -180,11 +189,11 @@ class Aarsregnskap(ABC):
180
189
  """Fetch and encode the PDF source based on the year and organization number.
181
190
 
182
191
  Args:
183
- aar (int): The year input value.
184
- orgnr (str): The organization number input value.
192
+ aar: The year input value.
193
+ orgnr: The organization number input value.
185
194
 
186
195
  Returns:
187
- str: A data URI for the PDF file, encoded in base64.
196
+ A data URI for the PDF file, encoded in base64.
188
197
 
189
198
  Raises:
190
199
  PreventUpdate: If the year or organization number is not provided.