reports.energyflowdiagram.Reporting.on_get()   F
last analyzed

Complexity

Conditions 49

Size

Total Lines 237
Code Lines 170

Duplication

Lines 20
Ratio 8.44 %

Importance

Changes 0
Metric Value
cc 49
eloc 170
nop 2
dl 20
loc 237
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like reports.energyflowdiagram.Reporting.on_get() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import falcon
2
import simplejson as json
3
import mysql.connector
4
from datetime import datetime, timedelta, timezone
5
from core import utilities
6
from decimal import Decimal
7
import config
8
9
10
class Reporting:
11
    @staticmethod
12
    def __init__():
13
        pass
14
15
    @staticmethod
16
    def on_options(req, resp):
17
        resp.status = falcon.HTTP_200
18
19
    ####################################################################################################################
20
    # PROCEDURES
21
    # Step 1: valid parameters
22
    # Step 2: query the energy flor diagram
23
    # Step 3: query nodes
24
    # Step 4: query links
25
    # Step 5: query reporting period meter energy input
26
    # Step 6: query reporting period offline meter energy input
27
    # Step 7: query reporting period virtual energy input
28
    # Step 8: construct the report
29
    ####################################################################################################################
30
    @staticmethod
31
    def on_get(req, resp):
32
        print(req.params)
33
        energy_flow_diagram_id = req.params.get('energyflowdiagramid')
34
        reporting_start_datetime_local = req.params.get('reportingperiodstartdatetime')
35
        reporting_end_datetime_local = req.params.get('reportingperiodenddatetime')
36
37
        ################################################################################################################
38
        # Step 1: valid parameters
39
        ################################################################################################################
40
        if energy_flow_diagram_id is None:
41
            raise falcon.HTTPError(falcon.HTTP_400,
42
                                   title='API.BAD_REQUEST',
43
                                   description='API.INVALID_ENERGY_FLOW_DIAGRAM_ID')
44
        else:
45
            energy_flow_diagram_id = str.strip(energy_flow_diagram_id)
46
            if not energy_flow_diagram_id.isdigit() or int(energy_flow_diagram_id) <= 0:
47
                raise falcon.HTTPError(falcon.HTTP_400,
48
                                       title='API.BAD_REQUEST',
49
                                       description='API.INVALID_ENERGY_FLOW_DIAGRAM_ID')
50
51
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
52
        if config.utc_offset[0] == '-':
53
            timezone_offset = -timezone_offset
54
55
        if reporting_start_datetime_local is None:
56
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
57
                                   description="API.INVALID_REPORTING_PERIOD_START_DATETIME")
58
        else:
59
            reporting_start_datetime_local = str.strip(reporting_start_datetime_local)
60
            try:
61
                reporting_start_datetime_utc = datetime.strptime(reporting_start_datetime_local,
62
                                                                 '%Y-%m-%dT%H:%M:%S').replace(tzinfo=timezone.utc) - \
63
                    timedelta(minutes=timezone_offset)
64
            except ValueError:
65
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
66
                                       description="API.INVALID_REPORTING_PERIOD_START_DATETIME")
67
68
        if reporting_end_datetime_local is None:
69
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
70
                                   description="API.INVALID_REPORTING_PERIOD_END_DATETIME")
71
        else:
72
            reporting_end_datetime_local = str.strip(reporting_end_datetime_local)
73
            try:
74
                reporting_end_datetime_utc = datetime.strptime(reporting_end_datetime_local,
75
                                                               '%Y-%m-%dT%H:%M:%S').replace(tzinfo=timezone.utc) - \
76
                    timedelta(minutes=timezone_offset)
77
            except ValueError:
78
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
79
                                       description="API.INVALID_REPORTING_PERIOD_END_DATETIME")
80
81
        if reporting_start_datetime_utc >= reporting_end_datetime_utc:
82
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
83
                                   description='API.INVALID_REPORTING_PERIOD_END_DATETIME')
84
        ################################################################################################################
85
        # Step 2: query the energy flow diagram
86
        ################################################################################################################
87
88
        cnx_system = mysql.connector.connect(**config.myems_system_db)
89
        cursor_system = cnx_system.cursor(dictionary=True)
90
91
        query = (" SELECT name, uuid "
92
                 " FROM tbl_energy_flow_diagrams "
93
                 " WHERE id = %s ")
94
        cursor_system.execute(query, (energy_flow_diagram_id,))
95
        row = cursor_system.fetchone()
96
97
        if row is None:
98
            if cursor_system:
99
                cursor_system.close()
100
            if cnx_system:
101
                cnx_system.disconnect()
102
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
103
                                   description='API.ENERGY_FLOW_DIAGRAM_NOT_FOUND')
104
        else:
105
            energy_flow_diagram_name = row['name']
106
            energy_flow_diagram_uuid = row['uuid']
107
108
        ################################################################################################################
109
        # Step 3: query nodes
110
        ################################################################################################################
111
112
        query = (" SELECT id, energy_flow_diagram_id, name "
113
                 " FROM tbl_energy_flow_diagrams_nodes")
114
        cursor_system.execute(query)
115
        rows_nodes = cursor_system.fetchall()
116
117
        node_dict = dict()
118
        node_list_dict = dict()
119
        if rows_nodes is not None and len(rows_nodes) > 0:
120
            for row in rows_nodes:
121
                node_dict[row['id']] = row['name']
122
                if node_list_dict.get(row['energy_flow_diagram_id']) is None:
123
                    node_list_dict[row['energy_flow_diagram_id']] = list()
124
                node_list_dict[row['energy_flow_diagram_id']].append({"id": row['id'], "name": row['name']})
125
126
        ################################################################################################################
127
        # Step 4: query links
128
        ################################################################################################################
129
        query = (" SELECT id, name, uuid "
130
                 " FROM tbl_meters ")
131
        cursor_system.execute(query)
132
        rows_meters = cursor_system.fetchall()
133
134
        meter_dict = dict()
135
        if rows_meters is not None and len(rows_meters) > 0:
136
            for row in rows_meters:
137
                meter_dict[row['uuid']] = {"type": 'meter',
138
                                           "id": row['id'],
139
                                           "name": row['name'],
140
                                           "uuid": row['uuid']}
141
142
        query = (" SELECT id, name, uuid "
143
                 " FROM tbl_offline_meters ")
144
        cursor_system.execute(query)
145
        rows_offline_meters = cursor_system.fetchall()
146
147
        offline_meter_dict = dict()
148
        if rows_offline_meters is not None and len(rows_offline_meters) > 0:
149
            for row in rows_offline_meters:
150
                offline_meter_dict[row['uuid']] = {"type": 'offline_meter',
151
                                                   "id": row['id'],
152
                                                   "name": row['name'],
153
                                                   "uuid": row['uuid']}
154
155
        query = (" SELECT id, name, uuid "
156
                 " FROM tbl_virtual_meters ")
157
        cursor_system.execute(query)
158
        rows_virtual_meters = cursor_system.fetchall()
159
160
        virtual_meter_dict = dict()
161
        if rows_virtual_meters is not None and len(rows_virtual_meters) > 0:
162
            for row in rows_virtual_meters:
163
                virtual_meter_dict[row['uuid']] = {"type": 'virtual_meter',
164
                                                   "id": row['id'],
165
                                                   "name": row['name'],
166
                                                   "uuid": row['uuid']}
167
168
        query = (" SELECT id, energy_flow_diagram_id, source_node_id, target_node_id, meter_uuid "
169
                 " FROM tbl_energy_flow_diagrams_links")
170
        cursor_system.execute(query)
171
        rows_links = cursor_system.fetchall()
172
173
        link_list_dict = dict()
174 View Code Duplication
        if rows_links is not None and len(rows_links) > 0:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
175
            for row in rows_links:
176
                # find meter by uuid
177
                meter = meter_dict.get(row['meter_uuid'], None)
178
                if meter is None:
179
                    meter = virtual_meter_dict.get(row['meter_uuid'], None)
180
                if meter is None:
181
                    meter = offline_meter_dict.get(row['meter_uuid'], None)
182
183
                if link_list_dict.get(row['energy_flow_diagram_id']) is None:
184
                    link_list_dict[row['energy_flow_diagram_id']] = list()
185
                link_list_dict[row['energy_flow_diagram_id']].append({"id": row['id'],
186
                                                                      "source_node": {
187
                                                                          "id": row['source_node_id'],
188
                                                                          "name": node_dict.get(row['source_node_id'])},
189
                                                                      "target_node": {
190
                                                                          "id": row['target_node_id'],
191
                                                                          "name": node_dict.get(row['target_node_id'])},
192
                                                                      "meter": meter,
193
                                                                      "value": None})
194
195
        meta_result = {"id": energy_flow_diagram_id,
196
                       "name": energy_flow_diagram_name,
197
                       "uuid": energy_flow_diagram_uuid,
198
                       "nodes": node_list_dict.get(int(energy_flow_diagram_id), None),
199
                       "links": link_list_dict.get(int(energy_flow_diagram_id), None),
200
                       }
201
        print(meta_result)
202
        if cursor_system:
203
            cursor_system.close()
204
        if cnx_system:
205
            cnx_system.disconnect()
206
207
        ################################################################################################################
208
        # Step 5: query reporting period meter energy input
209
        ################################################################################################################
210
        cnx_energy = mysql.connector.connect(**config.myems_energy_db)
211
        cursor_energy = cnx_energy.cursor()
212
        for x in range(len(meta_result['links'])):
213
            if meta_result['links'][x] is None or meta_result['links'][x]['meter'] is None:
214
                continue
215
            if meta_result['links'][x]['meter']['type'] == 'meter':
216
                query = (" SELECT SUM(actual_value) "
217
                         " FROM tbl_meter_hourly "
218
                         " WHERE meter_id = %s "
219
                         " AND start_datetime_utc >= %s "
220
                         " AND start_datetime_utc < %s ")
221
                cursor_energy.execute(query, (meta_result['links'][x]['meter']['id'],
222
                                              reporting_start_datetime_utc,
223
                                              reporting_end_datetime_utc))
224
                row = cursor_energy.fetchone()
225
                if row is not None:
226
                    meta_result['links'][x]['value'] = row[0]
227
            elif meta_result['links'][x]['meter']['type'] == 'offline_meter':
228
                query = (" SELECT SUM(actual_value) "
229
                         " FROM tbl_offline_meter_hourly "
230
                         " WHERE meter_id = %s "
231
                         " AND start_datetime_utc >= %s "
232
                         " AND start_datetime_utc < %s ")
233
                cursor_energy.execute(query, (meta_result['links'][x]['meter']['id'],
234
                                              reporting_start_datetime_utc,
235
                                              reporting_end_datetime_utc))
236
                row = cursor_energy.fetchone()
237
                if row is not None:
238
                    meta_result['links'][x]['value'] = row[0]
239
            elif meta_result['links'][x]['meter']['type'] == 'virtual_meter':
240
                query = (" SELECT SUM(actual_value) "
241
                         " FROM tbl_virtual_meter_hourly "
242
                         " WHERE meter_id = %s "
243
                         " AND start_datetime_utc >= %s "
244
                         " AND start_datetime_utc < %s ")
245
                cursor_energy.execute(query, (meta_result['links'][x]['meter']['id'],
246
                                              reporting_start_datetime_utc,
247
                                              reporting_end_datetime_utc))
248
                row = cursor_energy.fetchone()
249
                if row is not None:
250
                    meta_result['links'][x]['value'] = row[0]
251
252
        ################################################################################################################
253
        # Step 8: construct the report
254
        ################################################################################################################
255
256
        result = {'nodes': list(),
257
                  'links': list()}
258
        if meta_result['nodes'] is not None and len(meta_result['nodes']) > 0:
259
            for node in meta_result['nodes']:
260
                result['nodes'].append({'name': node['name']})
261
        if meta_result['links'] is not None and len(meta_result['links']) > 0:
262
            for link in meta_result['links']:
263
                result['links'].append({'source': link['source_node']['name'],
264
                                        'target': link['target_node']['name'],
265
                                        'value': link['value']})
266
        resp.body = json.dumps(result)
267