Passed
Push — master ( db6f57...6c9994 )
by
unknown
09:19 queued 17s
created

reports.virtualmeterplan.Reporting.on_get()   F

Complexity

Conditions 87

Size

Total Lines 489
Code Lines 374

Duplication

Lines 489
Ratio 100 %

Importance

Changes 0
Metric Value
eloc 374
dl 489
loc 489
rs 0
c 0
b 0
f 0
cc 87
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.virtualmeterplan.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 re
2
from datetime import datetime, timedelta, timezone
3
from decimal import Decimal
4
import falcon
5
import mysql.connector
6
import simplejson as json
7
import config
8
import excelexporters.virtualmetersaving
9
from core import utilities
10
from core.useractivity import access_control, api_key_control
11
12
13 View Code Duplication
class Reporting:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
14
    @staticmethod
15
    def __init__():
16
        """"Initializes Reporting"""
17
        pass
18
19
    @staticmethod
20
    def on_options(req, resp):
21
        resp.status = falcon.HTTP_200
22
23
    ####################################################################################################################
24
    # PROCEDURES
25
    # Step 1: valid parameters
26
    # Step 2: query the virtual meter and energy category
27
    # Step 3: query base period energy saving
28
    # Step 4: query reporting period energy saving
29
    # Step 5: query tariff data
30
    # Step 6: construct the report
31
    ####################################################################################################################
32
    @staticmethod
33
    def on_get(req, resp):
34
        if 'API-KEY' not in req.headers or \
35
                not isinstance(req.headers['API-KEY'], str) or \
36
                len(str.strip(req.headers['API-KEY'])) == 0:
37
            access_control(req)
38
        else:
39
            api_key_control(req)
40
        print(req.params)
41
        virtual_meter_id = req.params.get('virtualmeterid')
42
        virtual_meter_uuid = req.params.get('virtualmeteruuid')
43
        period_type = req.params.get('periodtype')
44
        base_period_start_datetime_local = req.params.get('baseperiodstartdatetime')
45
        base_period_end_datetime_local = req.params.get('baseperiodenddatetime')
46
        reporting_period_start_datetime_local = req.params.get('reportingperiodstartdatetime')
47
        reporting_period_end_datetime_local = req.params.get('reportingperiodenddatetime')
48
        language = req.params.get('language')
49
        quick_mode = req.params.get('quickmode')
50
51
        ################################################################################################################
52
        # Step 1: valid parameters
53
        ################################################################################################################
54
        if virtual_meter_id is None and virtual_meter_uuid is None:
55
            raise falcon.HTTPError(status=falcon.HTTP_400,
56
                                   title='API.BAD_REQUEST',
57
                                   description='API.INVALID_VIRTUAL_METER_ID')
58
59
        if virtual_meter_id is not None:
60
            virtual_meter_id = str.strip(virtual_meter_id)
61
            if not virtual_meter_id.isdigit() or int(virtual_meter_id) <= 0:
62
                raise falcon.HTTPError(status=falcon.HTTP_400,
63
                                       title='API.BAD_REQUEST',
64
                                       description='API.INVALID_VIRTUAL_METER_ID')
65
66
        if virtual_meter_uuid is not None:
67
            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)
68
            match = regex.match(str.strip(virtual_meter_uuid))
69
            if not bool(match):
70
                raise falcon.HTTPError(status=falcon.HTTP_400,
71
                                       title='API.BAD_REQUEST',
72
                                       description='API.INVALID_VIRTUAL_METER_UUID')
73
74
        if period_type is None:
75
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
76
                                   description='API.INVALID_PERIOD_TYPE')
77
        else:
78
            period_type = str.strip(period_type)
79
            if period_type not in ['hourly', 'daily', 'weekly', 'monthly', 'yearly']:
80
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
81
                                       description='API.INVALID_PERIOD_TYPE')
82
83
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
84
        if config.utc_offset[0] == '-':
85
            timezone_offset = -timezone_offset
86
87
        base_start_datetime_utc = None
88
        if base_period_start_datetime_local is not None and len(str.strip(base_period_start_datetime_local)) > 0:
89
            base_period_start_datetime_local = str.strip(base_period_start_datetime_local)
90
            try:
91
                base_start_datetime_utc = datetime.strptime(base_period_start_datetime_local, '%Y-%m-%dT%H:%M:%S')
92
            except ValueError:
93
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
94
                                       description="API.INVALID_BASE_PERIOD_START_DATETIME")
95
            base_start_datetime_utc = \
96
                base_start_datetime_utc.replace(tzinfo=timezone.utc) - timedelta(minutes=timezone_offset)
97
            # nomalize the start datetime
98
            if config.minutes_to_count == 30 and base_start_datetime_utc.minute >= 30:
99
                base_start_datetime_utc = base_start_datetime_utc.replace(minute=30, second=0, microsecond=0)
100
            else:
101
                base_start_datetime_utc = base_start_datetime_utc.replace(minute=0, second=0, microsecond=0)
102
103
        base_end_datetime_utc = None
104
        if base_period_end_datetime_local is not None and len(str.strip(base_period_end_datetime_local)) > 0:
105
            base_period_end_datetime_local = str.strip(base_period_end_datetime_local)
106
            try:
107
                base_end_datetime_utc = datetime.strptime(base_period_end_datetime_local, '%Y-%m-%dT%H:%M:%S')
108
            except ValueError:
109
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
110
                                       description="API.INVALID_BASE_PERIOD_END_DATETIME")
111
            base_end_datetime_utc = \
112
                base_end_datetime_utc.replace(tzinfo=timezone.utc) - timedelta(minutes=timezone_offset)
113
114
        if base_start_datetime_utc is not None and base_end_datetime_utc is not None and \
115
                base_start_datetime_utc >= base_end_datetime_utc:
116
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
117
                                   description='API.INVALID_BASE_PERIOD_END_DATETIME')
118
119
        if reporting_period_start_datetime_local is None:
120
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
121
                                   description="API.INVALID_REPORTING_PERIOD_START_DATETIME")
122
        else:
123
            reporting_period_start_datetime_local = str.strip(reporting_period_start_datetime_local)
124
            try:
125
                reporting_start_datetime_utc = datetime.strptime(reporting_period_start_datetime_local,
126
                                                                 '%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_REPORTING_PERIOD_START_DATETIME")
130
            reporting_start_datetime_utc = \
131
                reporting_start_datetime_utc.replace(tzinfo=timezone.utc) - timedelta(minutes=timezone_offset)
132
            # nomalize the start datetime
133
            if config.minutes_to_count == 30 and reporting_start_datetime_utc.minute >= 30:
134
                reporting_start_datetime_utc = reporting_start_datetime_utc.replace(minute=30, second=0, microsecond=0)
135
            else:
136
                reporting_start_datetime_utc = reporting_start_datetime_utc.replace(minute=0, second=0, microsecond=0)
137
138
        if reporting_period_end_datetime_local is None:
139
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
140
                                   description="API.INVALID_REPORTING_PERIOD_END_DATETIME")
141
        else:
142
            reporting_period_end_datetime_local = str.strip(reporting_period_end_datetime_local)
143
            try:
144
                reporting_end_datetime_utc = datetime.strptime(reporting_period_end_datetime_local,
145
                                                               '%Y-%m-%dT%H:%M:%S')
146
            except ValueError:
147
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
148
                                       description="API.INVALID_REPORTING_PERIOD_END_DATETIME")
149
            reporting_end_datetime_utc = reporting_end_datetime_utc.replace(tzinfo=timezone.utc) - \
150
                timedelta(minutes=timezone_offset)
151
152
        if reporting_start_datetime_utc >= reporting_end_datetime_utc:
153
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
154
                                   description='API.INVALID_REPORTING_PERIOD_END_DATETIME')
155
156
        # if turn quick mode on, do not return parameters data and excel file
157
        is_quick_mode = False
158
        if quick_mode is not None and \
159
                len(str.strip(quick_mode)) > 0 and \
160
                str.lower(str.strip(quick_mode)) in ('true', 't', 'on', 'yes', 'y'):
161
            is_quick_mode = True
162
163
        trans = utilities.get_translation(language)
164
        trans.install()
165
        _ = trans.gettext
166
167
        ################################################################################################################
168
        # Step 2: query the virtual meter and energy category
169
        ################################################################################################################
170
        cnx_system = mysql.connector.connect(**config.myems_system_db)
171
        cursor_system = cnx_system.cursor()
172
173
        cnx_energy = mysql.connector.connect(**config.myems_energy_db)
174
        cursor_energy = cnx_energy.cursor()
175
176
        cnx_energy_plan = mysql.connector.connect(**config.myems_energy_plan_db)
177
        cursor_energy_plan = cnx_energy_plan.cursor()
178
179
        cursor_system.execute(" SELECT m.id, m.name, m.cost_center_id, m.energy_category_id, "
180
                              "        ec.name, ec.unit_of_measure, ec.kgce, ec.kgco2e "
181
                              " FROM tbl_virtual_meters m, tbl_energy_categories ec "
182
                              " WHERE m.id = %s AND m.energy_category_id = ec.id ", (virtual_meter_id,))
183
        row_virtual_meter = cursor_system.fetchone()
184
        if row_virtual_meter is None:
185
            if cursor_system:
186
                cursor_system.close()
187
            if cnx_system:
188
                cnx_system.close()
189
190
            if cursor_energy:
191
                cursor_energy.close()
192
            if cnx_energy:
193
                cnx_energy.close()
194
195
            if cursor_energy_plan:
196
                cursor_energy_plan.close()
197
            if cnx_energy_plan:
198
                cnx_energy_plan.close()
199
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
200
                                   description='API.VIRTUAL_METER_NOT_FOUND')
201
202
        virtual_meter = dict()
203
        virtual_meter['id'] = row_virtual_meter[0]
204
        virtual_meter['name'] = row_virtual_meter[1]
205
        virtual_meter['cost_center_id'] = row_virtual_meter[2]
206
        virtual_meter['energy_category_id'] = row_virtual_meter[3]
207
        virtual_meter['energy_category_name'] = row_virtual_meter[4]
208
        virtual_meter['unit_of_measure'] = row_virtual_meter[5]
209
        virtual_meter['kgce'] = row_virtual_meter[6]
210
        virtual_meter['kgco2e'] = row_virtual_meter[7]
211
212
        ################################################################################################################
213
        # Step 3: query base period energy saving
214
        ################################################################################################################
215
        base = dict()
216
        base['timestamps'] = list()
217
        base['values_plan'] = list()
218
        base['values_actual'] = list()
219
        base['values_saving'] = list()
220
        base['total_in_category_plan'] = Decimal(0.0)
221
        base['total_in_category_actual'] = Decimal(0.0)
222
        base['total_in_category_saving'] = Decimal(0.0)
223
        base['total_in_kgce_plan'] = Decimal(0.0)
224
        base['total_in_kgce_actual'] = Decimal(0.0)
225
        base['total_in_kgce_saving'] = Decimal(0.0)
226
        base['total_in_kgco2e_plan'] = Decimal(0.0)
227
        base['total_in_kgco2e_actual'] = Decimal(0.0)
228
        base['total_in_kgco2e_saving'] = Decimal(0.0)
229
230
        # query base period plan
231
        cursor_energy_plan.execute(" SELECT start_datetime_utc, actual_value "
232
                                   " FROM tbl_virtual_meter_hourly "
233
                                   " WHERE virtual_meter_id = %s "
234
                                   " AND start_datetime_utc >= %s "
235
                                   " AND start_datetime_utc < %s "
236
                                   " ORDER BY start_datetime_utc ",
237
                                   (virtual_meter['id'],
238
                                    base_start_datetime_utc,
239
                                    base_end_datetime_utc))
240
        rows_virtual_meter_hourly = cursor_energy_plan.fetchall()
241
242
        rows_virtual_meter_periodically = \
243
            utilities.aggregate_hourly_data_by_period(rows_virtual_meter_hourly,
244
                                                      base_start_datetime_utc,
245
                                                      base_end_datetime_utc,
246
                                                      period_type)
247
248
        for row_virtual_meter_periodically in rows_virtual_meter_periodically:
249
            current_datetime_local = row_virtual_meter_periodically[0].replace(tzinfo=timezone.utc) + \
250
                                     timedelta(minutes=timezone_offset)
251
            if period_type == 'hourly':
252
                current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
253
            elif period_type == 'daily':
254
                current_datetime = current_datetime_local.strftime('%Y-%m-%d')
255
            elif period_type == 'weekly':
256
                current_datetime = current_datetime_local.strftime('%Y-%m-%d')
257
            elif period_type == 'monthly':
258
                current_datetime = current_datetime_local.strftime('%Y-%m')
259
            elif period_type == 'yearly':
260
                current_datetime = current_datetime_local.strftime('%Y')
261
262
            actual_value = Decimal(0.0) if row_virtual_meter_periodically[1] is None \
263
                else row_virtual_meter_periodically[1]
264
            base['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...
265
            base['values_plan'].append(actual_value)
266
            base['total_in_category_plan'] += actual_value
267
            base['total_in_kgce_plan'] += actual_value * virtual_meter['kgce']
268
            base['total_in_kgco2e_plan'] += actual_value * virtual_meter['kgco2e']
269
270
        # query base period actual
271
        cursor_energy.execute(" SELECT start_datetime_utc, actual_value "
272
                              " FROM tbl_virtual_meter_hourly "
273
                              " WHERE virtual_meter_id = %s "
274
                              " AND start_datetime_utc >= %s "
275
                              " AND start_datetime_utc < %s "
276
                              " ORDER BY start_datetime_utc ",
277
                              (virtual_meter['id'],
278
                               base_start_datetime_utc,
279
                               base_end_datetime_utc))
280
        rows_virtual_meter_hourly = cursor_energy.fetchall()
281
282
        rows_virtual_meter_periodically = \
283
            utilities.aggregate_hourly_data_by_period(rows_virtual_meter_hourly,
284
                                                      base_start_datetime_utc,
285
                                                      base_end_datetime_utc,
286
                                                      period_type)
287
288
        for row_virtual_meter_periodically in rows_virtual_meter_periodically:
289
            current_datetime_local = row_virtual_meter_periodically[0].replace(tzinfo=timezone.utc) + \
290
                                     timedelta(minutes=timezone_offset)
291
            if period_type == 'hourly':
292
                current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
293
            elif period_type == 'daily':
294
                current_datetime = current_datetime_local.strftime('%Y-%m-%d')
295
            elif period_type == 'weekly':
296
                current_datetime = current_datetime_local.strftime('%Y-%m-%d')
297
            elif period_type == 'monthly':
298
                current_datetime = current_datetime_local.strftime('%Y-%m')
299
            elif period_type == 'yearly':
300
                current_datetime = current_datetime_local.strftime('%Y')
301
302
            actual_value = Decimal(0.0) if row_virtual_meter_periodically[1] is None \
303
                else row_virtual_meter_periodically[1]
304
            base['values_actual'].append(actual_value)
305
            base['total_in_category_actual'] += actual_value
306
            base['total_in_kgce_actual'] += actual_value * virtual_meter['kgce']
307
            base['total_in_kgco2e_actual'] += actual_value * virtual_meter['kgco2e']
308
309
        # calculate base period saving
310
        for i in range(len(base['values_plan'])):
311
            base['values_saving'].append(base['values_plan'][i] - base['values_actual'][i])
312
313
        base['total_in_category_saving'] = base['total_in_category_plan'] - base['total_in_category_actual']
314
        base['total_in_kgce_saving'] = base['total_in_kgce_plan'] - base['total_in_kgce_actual']
315
        base['total_in_kgco2e_saving'] = base['total_in_kgco2e_plan'] - base['total_in_kgco2e_actual']
316
317
        ################################################################################################################
318
        # Step 3: query reporting period energy saving
319
        ################################################################################################################
320
        reporting = dict()
321
        reporting['timestamps'] = list()
322
        reporting['values_plan'] = list()
323
        reporting['values_actual'] = list()
324
        reporting['values_saving'] = list()
325
        reporting['values_rates'] = list()
326
        reporting['total_in_category_plan'] = Decimal(0.0)
327
        reporting['total_in_category_actual'] = Decimal(0.0)
328
        reporting['total_in_category_saving'] = Decimal(0.0)
329
        reporting['total_in_kgce_plan'] = Decimal(0.0)
330
        reporting['total_in_kgce_actual'] = Decimal(0.0)
331
        reporting['total_in_kgce_saving'] = Decimal(0.0)
332
        reporting['total_in_kgco2e_plan'] = Decimal(0.0)
333
        reporting['total_in_kgco2e_actual'] = Decimal(0.0)
334
        reporting['total_in_kgco2e_saving'] = Decimal(0.0)
335
        # query reporting period plan
336
        cursor_energy_plan.execute(" SELECT start_datetime_utc, actual_value "
337
                                   " FROM tbl_virtual_meter_hourly "
338
                                   " WHERE virtual_meter_id = %s "
339
                                   " AND start_datetime_utc >= %s "
340
                                   " AND start_datetime_utc < %s "
341
                                   " ORDER BY start_datetime_utc ",
342
                                   (virtual_meter['id'],
343
                                    reporting_start_datetime_utc,
344
                                    reporting_end_datetime_utc))
345
        rows_virtual_meter_hourly = cursor_energy_plan.fetchall()
346
347
        rows_virtual_meter_periodically = utilities.aggregate_hourly_data_by_period(rows_virtual_meter_hourly,
348
                                                                                    reporting_start_datetime_utc,
349
                                                                                    reporting_end_datetime_utc,
350
                                                                                    period_type)
351
352
        for row_virtual_meter_periodically in rows_virtual_meter_periodically:
353
            current_datetime_local = row_virtual_meter_periodically[0].replace(tzinfo=timezone.utc) + \
354
                                     timedelta(minutes=timezone_offset)
355
            if period_type == 'hourly':
356
                current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
357
            elif period_type == 'daily':
358
                current_datetime = current_datetime_local.strftime('%Y-%m-%d')
359
            elif period_type == 'weekly':
360
                current_datetime = current_datetime_local.strftime('%Y-%m-%d')
361
            elif period_type == 'monthly':
362
                current_datetime = current_datetime_local.strftime('%Y-%m')
363
            elif period_type == 'yearly':
364
                current_datetime = current_datetime_local.strftime('%Y')
365
366
            actual_value = Decimal(0.0) if row_virtual_meter_periodically[1] is None \
367
                else row_virtual_meter_periodically[1]
368
369
            reporting['timestamps'].append(current_datetime)
370
            reporting['values_plan'].append(actual_value)
371
            reporting['total_in_category_plan'] += actual_value
372
            reporting['total_in_kgce_plan'] += actual_value * virtual_meter['kgce']
373
            reporting['total_in_kgco2e_plan'] += actual_value * virtual_meter['kgco2e']
374
375
        # query reporting period actual
376
        cursor_energy.execute(" SELECT start_datetime_utc, actual_value "
377
                              " FROM tbl_virtual_meter_hourly "
378
                              " WHERE virtual_meter_id = %s "
379
                              " AND start_datetime_utc >= %s "
380
                              " AND start_datetime_utc < %s "
381
                              " ORDER BY start_datetime_utc ",
382
                              (virtual_meter['id'],
383
                               reporting_start_datetime_utc,
384
                               reporting_end_datetime_utc))
385
        rows_virtual_meter_hourly = cursor_energy.fetchall()
386
387
        rows_virtual_meter_periodically = utilities.aggregate_hourly_data_by_period(rows_virtual_meter_hourly,
388
                                                                                    reporting_start_datetime_utc,
389
                                                                                    reporting_end_datetime_utc,
390
                                                                                    period_type)
391
392
        for row_virtual_meter_periodically in rows_virtual_meter_periodically:
393
            current_datetime_local = row_virtual_meter_periodically[0].replace(tzinfo=timezone.utc) + \
394
                                     timedelta(minutes=timezone_offset)
395
            if period_type == 'hourly':
396
                current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
397
            elif period_type == 'daily':
398
                current_datetime = current_datetime_local.strftime('%Y-%m-%d')
399
            elif period_type == 'weekly':
400
                current_datetime = current_datetime_local.strftime('%Y-%m-%d')
401
            elif period_type == 'monthly':
402
                current_datetime = current_datetime_local.strftime('%Y-%m')
403
            elif period_type == 'yearly':
404
                current_datetime = current_datetime_local.strftime('%Y')
405
406
            actual_value = Decimal(0.0) if row_virtual_meter_periodically[1] is None \
407
                else row_virtual_meter_periodically[1]
408
409
            reporting['values_actual'].append(actual_value)
410
            reporting['total_in_category_actual'] += actual_value
411
            reporting['total_in_kgce_actual'] += actual_value * virtual_meter['kgce']
412
            reporting['total_in_kgco2e_actual'] += actual_value * virtual_meter['kgco2e']
413
414
        # calculate base period saving
415
        for i in range(len(reporting['values_plan'])):
416
            reporting['values_saving'].append(reporting['values_plan'][i] - reporting['values_actual'][i])
417
418
        reporting['total_in_category_saving'] = \
419
            reporting['total_in_category_plan'] - reporting['total_in_category_actual']
420
        reporting['total_in_kgce_saving'] = \
421
            reporting['total_in_kgce_plan'] - reporting['total_in_kgce_actual']
422
        reporting['total_in_kgco2e_saving'] = \
423
            reporting['total_in_kgco2e_plan'] - reporting['total_in_kgco2e_actual']
424
425
        for index, value in enumerate(reporting['values_saving']):
426
            if index < len(base['values_saving']) and base['values_saving'][index] != 0 and value != 0:
427
                reporting['values_rates'].append((value - base['values_saving'][index]) / base['values_saving'][index])
428
            else:
429
                reporting['values_rates'].append(None)
430
431
        ################################################################################################################
432
        # Step 5: query tariff data
433
        ################################################################################################################
434
        parameters_data = dict()
435
        parameters_data['names'] = list()
436
        parameters_data['timestamps'] = list()
437
        parameters_data['values'] = list()
438
        if config.is_tariff_appended and not is_quick_mode:
439
            tariff_dict = utilities.get_energy_category_tariffs(virtual_meter['cost_center_id'],
440
                                                                virtual_meter['energy_category_id'],
441
                                                                reporting_start_datetime_utc,
442
                                                                reporting_end_datetime_utc)
443
            tariff_timestamp_list = list()
444
            tariff_value_list = list()
445
            for k, v in tariff_dict.items():
446
                # convert k from utc to local
447
                k = k + timedelta(minutes=timezone_offset)
448
                tariff_timestamp_list.append(k.isoformat()[0:19])
449
                tariff_value_list.append(v)
450
451
            parameters_data['names'].append(_('Tariff') + '-' + virtual_meter['energy_category_name'])
452
            parameters_data['timestamps'].append(tariff_timestamp_list)
453
            parameters_data['values'].append(tariff_value_list)
454
455
        ################################################################################################################
456
        # Step 6: construct the report
457
        ################################################################################################################
458
        if cursor_system:
459
            cursor_system.close()
460
        if cnx_system:
461
            cnx_system.close()
462
463
        if cursor_energy:
464
            cursor_energy.close()
465
        if cnx_energy:
466
            cnx_energy.close()
467
468
        if cursor_energy_plan:
469
            cursor_energy_plan.close()
470
        if cnx_energy_plan:
471
            cnx_energy_plan.close()
472
473
        result = {
474
            "virtual_meter": {
475
                "cost_center_id": virtual_meter['cost_center_id'],
476
                "energy_category_id": virtual_meter['energy_category_id'],
477
                "energy_category_name": virtual_meter['energy_category_name'],
478
                "unit_of_measure": virtual_meter['unit_of_measure'],
479
                "kgce": virtual_meter['kgce'],
480
                "kgco2e": virtual_meter['kgco2e'],
481
            },
482
            "base_period": {
483
                "total_in_category_saving": base['total_in_category_saving'],
484
                "total_in_kgce_saving": base['total_in_kgce_saving'],
485
                "total_in_kgco2e_saving": base['total_in_kgco2e_saving'],
486
                "timestamps": base['timestamps'],
487
                "values_saving": base['values_saving'],
488
            },
489
            "reporting_period": {
490
                "increment_rate_saving":
491
                    (reporting['total_in_category_saving'] - base['total_in_category_saving']) /
492
                    base['total_in_category_saving']
493
                    if base['total_in_category_saving'] != Decimal(0.0) else None,
494
                "total_in_category_saving": reporting['total_in_category_saving'],
495
                "total_in_kgce_saving": reporting['total_in_kgce_saving'],
496
                "total_in_kgco2e_saving": reporting['total_in_kgco2e_saving'],
497
                "timestamps": reporting['timestamps'],
498
                "values_saving": reporting['values_saving'],
499
                "values_rates": reporting['values_rates'],
500
            },
501
            "parameters": {
502
                "names": parameters_data['names'],
503
                "timestamps": parameters_data['timestamps'],
504
                "values": parameters_data['values']
505
            },
506
        }
507
508
        # export result to Excel file and then encode the file to base64 string
509
        if not is_quick_mode:
510
            result['excel_bytes_base64'] = \
511
                excelexporters.virtualmetersaving.export(result,
512
                                                         virtual_meter['name'],
513
                                                         base_period_start_datetime_local,
514
                                                         base_period_end_datetime_local,
515
                                                         reporting_period_start_datetime_local,
516
                                                         reporting_period_end_datetime_local,
517
                                                         period_type,
518
                                                         language)
519
520
        resp.text = json.dumps(result)
521