Passed
Push — master ( d6dd87...c1af40 )
by Guangyu
10:17 queued 14s
created

reports.offlinemetersaving.Reporting.on_options()   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 3
Ratio 100 %

Importance

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