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

Complexity

Conditions 121

Size

Total Lines 530
Code Lines 394

Duplication

Lines 38
Ratio 7.17 %

Importance

Changes 0
Metric Value
eloc 394
dl 38
loc 530
rs 0
c 0
b 0
f 0
cc 121
nop 2

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.equipmentoutput.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
"""
2
Equipment Output Report API
3
4
This module provides REST API endpoints for generating equipment output reports.
5
It analyzes equipment output performance and production metrics to provide
6
insights into output optimization and production efficiency opportunities.
7
8
Key Features:
9
- Equipment output analysis
10
- Base period vs reporting period comparison
11
- Output performance metrics
12
- Production efficiency analysis
13
- Excel export functionality
14
- Output optimization insights
15
16
Report Components:
17
- Equipment output summary
18
- Base period comparison data
19
- Output performance metrics
20
- Production efficiency indicators
21
- Output optimization recommendations
22
- Production trends and patterns
23
24
The module uses Falcon framework for REST API and includes:
25
- Database queries for output data
26
- Output calculation algorithms
27
- Production analysis tools
28
- Excel export via excelexporters
29
- Multi-language support
30
- User authentication and authorization
31
"""
32
33
import re
34
from datetime import datetime, timedelta, timezone
35
from decimal import Decimal
36
import falcon
37
import mysql.connector
38
import simplejson as json
39
import config
40
import excelexporters.equipmentoutput
41
from core import utilities
42
from core.useractivity import access_control, api_key_control
43
44
45
class Reporting:
46
    def __init__(self):
47
        """"Initializes Reporting"""
48
        pass
49
50
    @staticmethod
51
    def on_options(req, resp):
52
        _ = req
53
        resp.status = falcon.HTTP_200
54
55
    ####################################################################################################################
56
    # PROCEDURES
57
    # Step 1: valid parameters
58
    # Step 2: query the equipment
59
    # Step 3: query energy categories
60
    # Step 4: query associated points
61
    # Step 5: query base period energy output
62
    # Step 6: query reporting period energy output
63
    # Step 7: query tariff data
64
    # Step 8: query associated points data
65
    # Step 9: construct the report
66
    ####################################################################################################################
67
    @staticmethod
68
    def on_get(req, resp):
69
        if 'API-KEY' not in req.headers or \
70
                not isinstance(req.headers['API-KEY'], str) or \
71
                len(str.strip(req.headers['API-KEY'])) == 0:
72
            access_control(req)
73
        else:
74
            api_key_control(req)
75
        print(req.params)
76
        equipment_id = req.params.get('equipmentid')
77
        equipment_uuid = req.params.get('equipmentuuid')
78
        period_type = req.params.get('periodtype')
79
        base_period_start_datetime_local = req.params.get('baseperiodstartdatetime')
80
        base_period_end_datetime_local = req.params.get('baseperiodenddatetime')
81
        reporting_period_start_datetime_local = req.params.get('reportingperiodstartdatetime')
82
        reporting_period_end_datetime_local = req.params.get('reportingperiodenddatetime')
83
        language = req.params.get('language')
84
        quick_mode = req.params.get('quickmode')
85
86
        ################################################################################################################
87
        # Step 1: valid parameters
88
        ################################################################################################################
89
        if equipment_id is None and equipment_uuid is None:
90
            raise falcon.HTTPError(status=falcon.HTTP_400,
91
                                   title='API.BAD_REQUEST',
92
                                   description='API.INVALID_EQUIPMENT_ID')
93
94
        if equipment_id is not None:
95
            equipment_id = str.strip(equipment_id)
96
            if not equipment_id.isdigit() or int(equipment_id) <= 0:
97
                raise falcon.HTTPError(status=falcon.HTTP_400,
98
                                       title='API.BAD_REQUEST',
99
                                       description='API.INVALID_EQUIPMENT_ID')
100
101
        if equipment_uuid is not None:
102
            regex = re.compile(r'^[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}\Z', re.I)
103
            match = regex.match(str.strip(equipment_uuid))
104
            if not bool(match):
105
                raise falcon.HTTPError(status=falcon.HTTP_400,
106
                                       title='API.BAD_REQUEST',
107
                                       description='API.INVALID_EQUIPMENT_UUID')
108
109
        if period_type is None:
110
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
111
                                   description='API.INVALID_PERIOD_TYPE')
112
        else:
113
            period_type = str.strip(period_type)
114
            if period_type not in ['hourly', 'daily', 'weekly', 'monthly', 'yearly']:
115
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
116
                                       description='API.INVALID_PERIOD_TYPE')
117
118
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
119
        if config.utc_offset[0] == '-':
120
            timezone_offset = -timezone_offset
121
122
        base_start_datetime_utc = None
123
        if base_period_start_datetime_local is not None and len(str.strip(base_period_start_datetime_local)) > 0:
124
            base_period_start_datetime_local = str.strip(base_period_start_datetime_local)
125
            try:
126
                base_start_datetime_utc = datetime.strptime(base_period_start_datetime_local, '%Y-%m-%dT%H:%M:%S')
127
            except ValueError:
128
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
129
                                       description="API.INVALID_BASE_PERIOD_START_DATETIME")
130
            base_start_datetime_utc = \
131
                base_start_datetime_utc.replace(tzinfo=timezone.utc) - timedelta(minutes=timezone_offset)
132
            # nomalize the start datetime
133
            if config.minutes_to_count == 30 and base_start_datetime_utc.minute >= 30:
134
                base_start_datetime_utc = base_start_datetime_utc.replace(minute=30, second=0, microsecond=0)
135
            else:
136
                base_start_datetime_utc = base_start_datetime_utc.replace(minute=0, second=0, microsecond=0)
137
138
        base_end_datetime_utc = None
139
        if base_period_end_datetime_local is not None and len(str.strip(base_period_end_datetime_local)) > 0:
140
            base_period_end_datetime_local = str.strip(base_period_end_datetime_local)
141
            try:
142
                base_end_datetime_utc = datetime.strptime(base_period_end_datetime_local, '%Y-%m-%dT%H:%M:%S')
143
            except ValueError:
144
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
145
                                       description="API.INVALID_BASE_PERIOD_END_DATETIME")
146
            base_end_datetime_utc = \
147
                base_end_datetime_utc.replace(tzinfo=timezone.utc) - timedelta(minutes=timezone_offset)
148
149
        if base_start_datetime_utc is not None and base_end_datetime_utc is not None and \
150
                base_start_datetime_utc >= base_end_datetime_utc:
151
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
152
                                   description='API.INVALID_BASE_PERIOD_END_DATETIME')
153
154
        if reporting_period_start_datetime_local is None:
155
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
156
                                   description="API.INVALID_REPORTING_PERIOD_START_DATETIME")
157
        else:
158
            reporting_period_start_datetime_local = str.strip(reporting_period_start_datetime_local)
159
            try:
160
                reporting_start_datetime_utc = datetime.strptime(reporting_period_start_datetime_local,
161
                                                                 '%Y-%m-%dT%H:%M:%S')
162
            except ValueError:
163
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
164
                                       description="API.INVALID_REPORTING_PERIOD_START_DATETIME")
165
            reporting_start_datetime_utc = \
166
                reporting_start_datetime_utc.replace(tzinfo=timezone.utc) - timedelta(minutes=timezone_offset)
167
            # nomalize the start datetime
168
            if config.minutes_to_count == 30 and reporting_start_datetime_utc.minute >= 30:
169
                reporting_start_datetime_utc = reporting_start_datetime_utc.replace(minute=30, second=0, microsecond=0)
170
            else:
171
                reporting_start_datetime_utc = reporting_start_datetime_utc.replace(minute=0, second=0, microsecond=0)
172
173
        if reporting_period_end_datetime_local is None:
174
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
175
                                   description="API.INVALID_REPORTING_PERIOD_END_DATETIME")
176
        else:
177
            reporting_period_end_datetime_local = str.strip(reporting_period_end_datetime_local)
178
            try:
179
                reporting_end_datetime_utc = datetime.strptime(reporting_period_end_datetime_local,
180
                                                               '%Y-%m-%dT%H:%M:%S').replace(tzinfo=timezone.utc) - \
181
                                             timedelta(minutes=timezone_offset)
182
            except ValueError:
183
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
184
                                       description="API.INVALID_REPORTING_PERIOD_END_DATETIME")
185
186
        if reporting_start_datetime_utc >= reporting_end_datetime_utc:
187
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
188
                                   description='API.INVALID_REPORTING_PERIOD_END_DATETIME')
189
190
        # if turn quick mode on, do not return parameters data and excel file
191
        is_quick_mode = False
192
        if quick_mode is not None and \
193
                len(str.strip(quick_mode)) > 0 and \
194
                str.lower(str.strip(quick_mode)) in ('true', 't', 'on', 'yes', 'y'):
195
            is_quick_mode = True
196
197
        trans = utilities.get_translation(language)
198
        trans.install()
199
        _ = trans.gettext
200
201
        ################################################################################################################
202
        # Step 2: query the equipment
203
        ################################################################################################################
204
        cnx_system = mysql.connector.connect(**config.myems_system_db)
205
        cursor_system = cnx_system.cursor()
206
207
        cnx_energy = mysql.connector.connect(**config.myems_energy_db)
208
        cursor_energy = cnx_energy.cursor()
209
210
        cnx_historical = mysql.connector.connect(**config.myems_historical_db)
211
        cursor_historical = cnx_historical.cursor()
212
213
        if equipment_id is not None:
214
            cursor_system.execute(" SELECT id, name, cost_center_id "
215
                                  " FROM tbl_equipments "
216
                                  " WHERE id = %s ", (equipment_id,))
217
            row_equipment = cursor_system.fetchone()
218
        elif equipment_uuid is not None:
219
            cursor_system.execute(" SELECT id, name, cost_center_id "
220
                                  " FROM tbl_equipments "
221
                                  " WHERE uuid = %s ", (equipment_uuid,))
222
            row_equipment = cursor_system.fetchone()
223
224 View Code Duplication
        if row_equipment is None:
0 ignored issues
show
introduced by
The variable row_equipment does not seem to be defined for all execution paths.
Loading history...
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
225
            if cursor_system:
226
                cursor_system.close()
227
            if cnx_system:
228
                cnx_system.close()
229
230
            if cursor_energy:
231
                cursor_energy.close()
232
            if cnx_energy:
233
                cnx_energy.close()
234
235
            if cursor_historical:
236
                cursor_historical.close()
237
            if cnx_historical:
238
                cnx_historical.close()
239
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND', description='API.EQUIPMENT_NOT_FOUND')
240
241
        equipment = dict()
242
        equipment['id'] = row_equipment[0]
243
        equipment['name'] = row_equipment[1]
244
        equipment['cost_center_id'] = row_equipment[2]
245
246
        ################################################################################################################
247
        # Step 3: query energy categories
248
        ################################################################################################################
249
        energy_category_set = set()
250
        # query energy categories in base period
251
        cursor_energy.execute(" SELECT DISTINCT(energy_category_id) "
252
                              " FROM tbl_equipment_output_category_hourly "
253
                              " WHERE equipment_id = %s "
254
                              "     AND start_datetime_utc >= %s "
255
                              "     AND start_datetime_utc < %s ",
256
                              (equipment['id'], base_start_datetime_utc, base_end_datetime_utc))
257
        rows_energy_categories = cursor_energy.fetchall()
258
        if rows_energy_categories is not None and len(rows_energy_categories) > 0:
259
            for row_energy_category in rows_energy_categories:
260
                energy_category_set.add(row_energy_category[0])
261
262
        # query energy categories in reporting period
263
        cursor_energy.execute(" SELECT DISTINCT(energy_category_id) "
264
                              " FROM tbl_equipment_output_category_hourly "
265
                              " WHERE equipment_id = %s "
266
                              "     AND start_datetime_utc >= %s "
267
                              "     AND start_datetime_utc < %s ",
268
                              (equipment['id'], reporting_start_datetime_utc, reporting_end_datetime_utc))
269
        rows_energy_categories = cursor_energy.fetchall()
270
        if rows_energy_categories is not None and len(rows_energy_categories) > 0:
271
            for row_energy_category in rows_energy_categories:
272
                energy_category_set.add(row_energy_category[0])
273
274
        # query all energy categories in base period and reporting period
275
        cursor_system.execute(" SELECT id, name, unit_of_measure, kgce, kgco2e "
276
                              " FROM tbl_energy_categories "
277
                              " ORDER BY id ", )
278
        rows_energy_categories = cursor_system.fetchall()
279
        if rows_energy_categories is None or len(rows_energy_categories) == 0:
280
            if cursor_system:
281
                cursor_system.close()
282
            if cnx_system:
283
                cnx_system.close()
284
285
            if cursor_energy:
286
                cursor_energy.close()
287
            if cnx_energy:
288
                cnx_energy.close()
289
290
            if cursor_historical:
291
                cursor_historical.close()
292
            if cnx_historical:
293
                cnx_historical.close()
294
            raise falcon.HTTPError(status=falcon.HTTP_404,
295
                                   title='API.NOT_FOUND',
296
                                   description='API.ENERGY_CATEGORY_NOT_FOUND')
297
        energy_category_dict = dict()
298
        for row_energy_category in rows_energy_categories:
299
            if row_energy_category[0] in energy_category_set:
300
                energy_category_dict[row_energy_category[0]] = {"name": row_energy_category[1],
301
                                                                "unit_of_measure": row_energy_category[2],
302
                                                                "kgce": row_energy_category[3],
303
                                                                "kgco2e": row_energy_category[4]}
304
305
        ################################################################################################################
306
        # Step 4: query associated points
307
        ################################################################################################################
308
        point_list = list()
309
        cursor_system.execute(" SELECT p.id, ep.name, p.units, p.object_type  "
310
                              " FROM tbl_equipments e, tbl_equipments_parameters ep, tbl_points p "
311
                              " WHERE e.id = %s AND e.id = ep.equipment_id AND ep.parameter_type = 'point' "
312
                              "       AND ep.point_id = p.id "
313
                              " ORDER BY p.id ", (equipment['id'],))
314
        rows_points = cursor_system.fetchall()
315
        if rows_points is not None and len(rows_points) > 0:
316
            for row in rows_points:
317
                point_list.append({"id": row[0], "name": row[1], "units": row[2], "object_type": row[3]})
318
319
        ################################################################################################################
320
        # Step 5: query base period energy output
321
        ################################################################################################################
322
        base = dict()
323
        if energy_category_set is not None and len(energy_category_set) > 0:
324
            for energy_category_id in energy_category_set:
325
                base[energy_category_id] = dict()
326
                base[energy_category_id]['timestamps'] = list()
327
                base[energy_category_id]['values'] = list()
328
                base[energy_category_id]['subtotal'] = Decimal(0.0)
329
330
                cursor_energy.execute(" SELECT start_datetime_utc, actual_value "
331
                                      " FROM tbl_equipment_output_category_hourly "
332
                                      " WHERE equipment_id = %s "
333
                                      "     AND energy_category_id = %s "
334
                                      "     AND start_datetime_utc >= %s "
335
                                      "     AND start_datetime_utc < %s "
336
                                      " ORDER BY start_datetime_utc ",
337
                                      (equipment['id'],
338
                                       energy_category_id,
339
                                       base_start_datetime_utc,
340
                                       base_end_datetime_utc))
341
                rows_equipment_hourly = cursor_energy.fetchall()
342
343
                rows_equipment_periodically = utilities.aggregate_hourly_data_by_period(rows_equipment_hourly,
344
                                                                                        base_start_datetime_utc,
345
                                                                                        base_end_datetime_utc,
346
                                                                                        period_type)
347
                for row_equipment_periodically in rows_equipment_periodically:
348
                    current_datetime_local = row_equipment_periodically[0].replace(tzinfo=timezone.utc) + \
349
                                             timedelta(minutes=timezone_offset)
350
                    if period_type == 'hourly':
351
                        current_datetime = current_datetime_local.isoformat()[0:19]
352
                    elif period_type == 'daily':
353
                        current_datetime = current_datetime_local.isoformat()[0:10]
354
                    elif period_type == 'weekly':
355
                        current_datetime = current_datetime_local.isoformat()[0:10]
356
                    elif period_type == 'monthly':
357
                        current_datetime = current_datetime_local.isoformat()[0:7]
358
                    elif period_type == 'yearly':
359
                        current_datetime = current_datetime_local.isoformat()[0:4]
360
361
                    actual_value = Decimal(0.0) if row_equipment_periodically[1] is None \
362
                        else row_equipment_periodically[1]
363
                    base[energy_category_id]['timestamps'].append(current_datetime)
0 ignored issues
show
introduced by
The variable current_datetime does not seem to be defined for all execution paths.
Loading history...
364
                    base[energy_category_id]['values'].append(actual_value)
365
                    base[energy_category_id]['subtotal'] += actual_value
366
367
        ################################################################################################################
368
        # Step 8: query reporting period energy output
369
        ################################################################################################################
370
        reporting = dict()
371
        if energy_category_set is not None and len(energy_category_set) > 0:
372
            for energy_category_id in energy_category_set:
373
                reporting[energy_category_id] = dict()
374
                reporting[energy_category_id]['timestamps'] = list()
375
                reporting[energy_category_id]['values'] = list()
376
                reporting[energy_category_id]['subtotal'] = Decimal(0.0)
377
378
                cursor_energy.execute(" SELECT start_datetime_utc, actual_value "
379
                                      " FROM tbl_equipment_output_category_hourly "
380
                                      " WHERE equipment_id = %s "
381
                                      "     AND energy_category_id = %s "
382
                                      "     AND start_datetime_utc >= %s "
383
                                      "     AND start_datetime_utc < %s "
384
                                      " ORDER BY start_datetime_utc ",
385
                                      (equipment['id'],
386
                                       energy_category_id,
387
                                       reporting_start_datetime_utc,
388
                                       reporting_end_datetime_utc))
389
                rows_equipment_hourly = cursor_energy.fetchall()
390
391
                rows_equipment_periodically = utilities.aggregate_hourly_data_by_period(rows_equipment_hourly,
392
                                                                                        reporting_start_datetime_utc,
393
                                                                                        reporting_end_datetime_utc,
394
                                                                                        period_type)
395
                for row_equipment_periodically in rows_equipment_periodically:
396
                    current_datetime_local = row_equipment_periodically[0].replace(tzinfo=timezone.utc) + \
397
                                             timedelta(minutes=timezone_offset)
398
                    if period_type == 'hourly':
399
                        current_datetime = current_datetime_local.isoformat()[0:19]
400
                    elif period_type == 'daily':
401
                        current_datetime = current_datetime_local.isoformat()[0:10]
402
                    elif period_type == 'weekly':
403
                        current_datetime = current_datetime_local.isoformat()[0:10]
404
                    elif period_type == 'monthly':
405
                        current_datetime = current_datetime_local.isoformat()[0:7]
406
                    elif period_type == 'yearly':
407
                        current_datetime = current_datetime_local.isoformat()[0:4]
408
409
                    actual_value = Decimal(0.0) if row_equipment_periodically[1] is None \
410
                        else row_equipment_periodically[1]
411
                    reporting[energy_category_id]['timestamps'].append(current_datetime)
412
                    reporting[energy_category_id]['values'].append(actual_value)
413
                    reporting[energy_category_id]['subtotal'] += actual_value
414
415
        ################################################################################################################
416
        # Step 9: query tariff data
417
        ################################################################################################################
418
        parameters_data = dict()
419
        parameters_data['names'] = list()
420
        parameters_data['timestamps'] = list()
421
        parameters_data['values'] = list()
422
        if not is_quick_mode:
423
            if config.is_tariff_appended and energy_category_set is not None and len(energy_category_set) > 0:
424
                for energy_category_id in energy_category_set:
425
                    energy_category_tariff_dict = utilities.get_energy_category_tariffs(equipment['cost_center_id'],
426
                                                                                        energy_category_id,
427
                                                                                        reporting_start_datetime_utc,
428
                                                                                        reporting_end_datetime_utc)
429
                    tariff_timestamp_list = list()
430
                    tariff_value_list = list()
431
                    for k, v in energy_category_tariff_dict.items():
432
                        # convert k from utc to local
433
                        k = k + timedelta(minutes=timezone_offset)
434
                        tariff_timestamp_list.append(k.isoformat()[0:19])
435
                        tariff_value_list.append(v)
436
437
                    parameters_data['names'].append(_('Tariff') + '-'
438
                                                    + energy_category_dict[energy_category_id]['name'])
439
                    parameters_data['timestamps'].append(tariff_timestamp_list)
440
                    parameters_data['values'].append(tariff_value_list)
441
442
        ################################################################################################################
443
        # Step 10: query associated points data
444
        ################################################################################################################
445
        if not is_quick_mode:
446
            for point in point_list:
447
                point_values = []
448
                point_timestamps = []
449
                if point['object_type'] == 'ENERGY_VALUE':
450
                    query = (" SELECT utc_date_time, actual_value "
451
                             " FROM tbl_energy_value "
452
                             " WHERE point_id = %s "
453
                             "       AND utc_date_time BETWEEN %s AND %s "
454
                             " ORDER BY utc_date_time ")
455
                    cursor_historical.execute(query, (point['id'],
456
                                                      reporting_start_datetime_utc,
457
                                                      reporting_end_datetime_utc))
458
                    rows = cursor_historical.fetchall()
459
460
                    if rows is not None and len(rows) > 0:
461
                        for row in rows:
462
                            current_datetime_local = row[0].replace(tzinfo=timezone.utc) + \
463
                                                     timedelta(minutes=timezone_offset)
464
                            current_datetime = current_datetime_local.isoformat()[0:19]
465
                            point_timestamps.append(current_datetime)
466
                            point_values.append(row[1])
467
                elif point['object_type'] == 'ANALOG_VALUE':
468
                    query = (" SELECT utc_date_time, actual_value "
469
                             " FROM tbl_analog_value "
470
                             " WHERE point_id = %s "
471
                             "       AND utc_date_time BETWEEN %s AND %s "
472
                             " ORDER BY utc_date_time ")
473
                    cursor_historical.execute(query, (point['id'],
474
                                                      reporting_start_datetime_utc,
475
                                                      reporting_end_datetime_utc))
476
                    rows = cursor_historical.fetchall()
477
478
                    if rows is not None and len(rows) > 0:
479
                        for row in rows:
480
                            current_datetime_local = row[0].replace(tzinfo=timezone.utc) + \
481
                                                     timedelta(minutes=timezone_offset)
482
                            current_datetime = current_datetime_local.isoformat()[0:19]
483
                            point_timestamps.append(current_datetime)
484
                            point_values.append(row[1])
485
                elif point['object_type'] == 'DIGITAL_VALUE':
486
                    query = (" SELECT utc_date_time, actual_value "
487
                             " FROM tbl_digital_value "
488
                             " WHERE point_id = %s "
489
                             "       AND utc_date_time BETWEEN %s AND %s "
490
                             " ORDER BY utc_date_time ")
491
                    cursor_historical.execute(query, (point['id'],
492
                                                      reporting_start_datetime_utc,
493
                                                      reporting_end_datetime_utc))
494
                    rows = cursor_historical.fetchall()
495
496
                    if rows is not None and len(rows) > 0:
497
                        for row in rows:
498
                            current_datetime_local = row[0].replace(tzinfo=timezone.utc) + \
499
                                                     timedelta(minutes=timezone_offset)
500
                            current_datetime = current_datetime_local.isoformat()[0:19]
501
                            point_timestamps.append(current_datetime)
502
                            point_values.append(row[1])
503
504
                parameters_data['names'].append(point['name'] + ' (' + point['units'] + ')')
505
                parameters_data['timestamps'].append(point_timestamps)
506
                parameters_data['values'].append(point_values)
507
508
        ################################################################################################################
509
        # Step 12: construct the report
510
        ################################################################################################################
511
        if cursor_system:
512
            cursor_system.close()
513
        if cnx_system:
514
            cnx_system.close()
515
516
        if cursor_energy:
517
            cursor_energy.close()
518
        if cnx_energy:
519
            cnx_energy.close()
520
521
        if cursor_historical:
522
            cursor_historical.close()
523
        if cnx_historical:
524
            cnx_historical.close()
525
526
        result = dict()
527
528
        result['equipment'] = dict()
529
        result['equipment']['name'] = equipment['name']
530
531
        result['base_period'] = dict()
532
        result['base_period']['names'] = list()
533
        result['base_period']['units'] = list()
534
        result['base_period']['timestamps'] = list()
535
        result['base_period']['values'] = list()
536
        result['base_period']['subtotals'] = list()
537
        if energy_category_set is not None and len(energy_category_set) > 0:
538
            for energy_category_id in energy_category_set:
539
                result['base_period']['names'].append(energy_category_dict[energy_category_id]['name'])
540
                result['base_period']['units'].append(energy_category_dict[energy_category_id]['unit_of_measure'])
541
                result['base_period']['timestamps'].append(base[energy_category_id]['timestamps'])
542
                result['base_period']['values'].append(base[energy_category_id]['values'])
543
                result['base_period']['subtotals'].append(base[energy_category_id]['subtotal'])
544
545
        result['reporting_period'] = dict()
546
        result['reporting_period']['names'] = list()
547
        result['reporting_period']['energy_category_ids'] = list()
548
        result['reporting_period']['units'] = list()
549
        result['reporting_period']['timestamps'] = list()
550
        result['reporting_period']['values'] = list()
551
        result['reporting_period']['rates'] = list()
552
        result['reporting_period']['subtotals'] = list()
553
        result['reporting_period']['increment_rates'] = list()
554
555 View Code Duplication
        if energy_category_set is not None and len(energy_category_set) > 0:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
556
            for energy_category_id in energy_category_set:
557
                result['reporting_period']['names'].append(energy_category_dict[energy_category_id]['name'])
558
                result['reporting_period']['energy_category_ids'].append(energy_category_id)
559
                result['reporting_period']['units'].append(energy_category_dict[energy_category_id]['unit_of_measure'])
560
                result['reporting_period']['timestamps'].append(reporting[energy_category_id]['timestamps'])
561
                result['reporting_period']['values'].append(reporting[energy_category_id]['values'])
562
                result['reporting_period']['subtotals'].append(reporting[energy_category_id]['subtotal'])
563
                result['reporting_period']['increment_rates'].append(
564
                    (reporting[energy_category_id]['subtotal'] - base[energy_category_id]['subtotal']) /
565
                    base[energy_category_id]['subtotal']
566
                    if base[energy_category_id]['subtotal'] > 0.0 else None)
567
568
                rate = list()
569
                for index, value in enumerate(reporting[energy_category_id]['values']):
570
                    if index < len(base[energy_category_id]['values']) \
571
                            and base[energy_category_id]['values'][index] != 0 and value != 0:
572
                        rate.append((value - base[energy_category_id]['values'][index])
573
                                    / base[energy_category_id]['values'][index])
574
                    else:
575
                        rate.append(None)
576
                result['reporting_period']['rates'].append(rate)
577
578
        result['parameters'] = {
579
            "names": parameters_data['names'],
580
            "timestamps": parameters_data['timestamps'],
581
            "values": parameters_data['values']
582
        }
583
584
        # export result to Excel file and then encode the file to base64 string
585
        result['excel_bytes_base64'] = None
586
        if not is_quick_mode:
587
            result['excel_bytes_base64'] = excelexporters.equipmentoutput.export(result,
588
                                                                                 equipment['name'],
589
                                                                                 base_period_start_datetime_local,
590
                                                                                 base_period_end_datetime_local,
591
                                                                                 reporting_period_start_datetime_local,
592
                                                                                 reporting_period_end_datetime_local,
593
                                                                                 period_type,
594
                                                                                 language)
595
596
        resp.text = json.dumps(result)
597