Passed
Push — master ( 8ba0c1...7a1547 )
by Guangyu
09:24 queued 12s
created

reports.virtualmetersaving.Reporting.on_get()   F

Complexity

Conditions 73

Size

Total Lines 506
Code Lines 404

Duplication

Lines 0
Ratio 0 %

Importance

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