Issues (1588)

myems-api/reports/equipmentbatch.py (1 issue)

1
from datetime import datetime, timedelta, timezone
2
from decimal import Decimal
3
import falcon
4
import mysql.connector
5
import simplejson as json
6
from anytree import AnyNode, LevelOrderIter
7
import config
8
import excelexporters.equipmentbatch
9
from core.useractivity import access_control, api_key_control
10
11
12 View Code Duplication
class Reporting:
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
13
    def __init__(self):
14
        """"Initializes Reporting"""
15
        pass
16
17
    @staticmethod
18
    def on_options(req, resp):
19
        _ = req
20
        resp.status = falcon.HTTP_200
21
22
    ####################################################################################################################
23
    # PROCEDURES
24
    # Step 1: valid parameters
25
    # Step 2: build a space tree
26
    # Step 3: query all equipments in the space tree
27
    # Step 4: query energy categories
28
    # Step 5: query reporting period energy input
29
    # Step 6: construct the report
30
    ####################################################################################################################
31
    @staticmethod
32
    def on_get(req, resp):
33
        if 'API-KEY' not in req.headers or \
34
                not isinstance(req.headers['API-KEY'], str) or \
35
                len(str.strip(req.headers['API-KEY'])) == 0:
36
            access_control(req)
37
        else:
38
            api_key_control(req)
39
        print(req.params)
40
        space_id = req.params.get('spaceid')
41
        reporting_period_start_datetime_local = req.params.get('reportingperiodstartdatetime')
42
        reporting_period_end_datetime_local = req.params.get('reportingperiodenddatetime')
43
        language = req.params.get('language')
44
        quick_mode = req.params.get('quickmode')
45
46
        ################################################################################################################
47
        # Step 1: valid parameters
48
        ################################################################################################################
49
        if space_id is None:
50
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST', description='API.INVALID_SPACE_ID')
51
        else:
52
            space_id = str.strip(space_id)
53
            if not space_id.isdigit() or int(space_id) <= 0:
54
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
55
                                       description='API.INVALID_SPACE_ID')
56
            else:
57
                space_id = int(space_id)
58
59
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
60
        if config.utc_offset[0] == '-':
61
            timezone_offset = -timezone_offset
62
63
        if reporting_period_start_datetime_local is None:
64
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
65
                                   description="API.INVALID_REPORTING_PERIOD_START_DATETIME")
66
        else:
67
            reporting_period_start_datetime_local = str.strip(reporting_period_start_datetime_local)
68
            try:
69
                reporting_start_datetime_utc = datetime.strptime(reporting_period_start_datetime_local,
70
                                                                 '%Y-%m-%dT%H:%M:%S')
71
            except ValueError:
72
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
73
                                       description="API.INVALID_REPORTING_PERIOD_START_DATETIME")
74
            reporting_start_datetime_utc = \
75
                reporting_start_datetime_utc.replace(tzinfo=timezone.utc) - timedelta(minutes=timezone_offset)
76
            # nomalize the start datetime
77
            if config.minutes_to_count == 30 and reporting_start_datetime_utc.minute >= 30:
78
                reporting_start_datetime_utc = reporting_start_datetime_utc.replace(minute=30, second=0, microsecond=0)
79
            else:
80
                reporting_start_datetime_utc = reporting_start_datetime_utc.replace(minute=0, second=0, microsecond=0)
81
82
        if reporting_period_end_datetime_local is None:
83
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
84
                                   description="API.INVALID_REPORTING_PERIOD_END_DATETIME")
85
        else:
86
            reporting_period_end_datetime_local = str.strip(reporting_period_end_datetime_local)
87
            try:
88
                reporting_end_datetime_utc = datetime.strptime(reporting_period_end_datetime_local,
89
                                                               '%Y-%m-%dT%H:%M:%S')
90
            except ValueError:
91
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
92
                                       description="API.INVALID_REPORTING_PERIOD_END_DATETIME")
93
            reporting_end_datetime_utc = reporting_end_datetime_utc.replace(tzinfo=timezone.utc) - \
94
                timedelta(minutes=timezone_offset)
95
96
        if reporting_start_datetime_utc >= reporting_end_datetime_utc:
97
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
98
                                   description='API.INVALID_REPORTING_PERIOD_END_DATETIME')
99
100
        # if turn quick mode on, do not return parameters data and excel file
101
        is_quick_mode = False
102
        if quick_mode is not None and \
103
                len(str.strip(quick_mode)) > 0 and \
104
                str.lower(str.strip(quick_mode)) in ('true', 't', 'on', 'yes', 'y'):
105
            is_quick_mode = True
106
107
        cnx_system_db = mysql.connector.connect(**config.myems_system_db)
108
        cursor_system_db = cnx_system_db.cursor()
109
110
        cursor_system_db.execute(" SELECT name "
111
                                 " FROM tbl_spaces "
112
                                 " WHERE id = %s ", (space_id,))
113
        row = cursor_system_db.fetchone()
114
115
        if row is None:
116
            if cursor_system_db:
117
                cursor_system_db.close()
118
            if cnx_system_db:
119
                cnx_system_db.close()
120
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
121
                                   description='API.SPACE_NOT_FOUND')
122
        else:
123
            space_name = row[0]
124
125
        ################################################################################################################
126
        # Step 2: build a space tree
127
        ################################################################################################################
128
129
        query = (" SELECT id, name, parent_space_id "
130
                 " FROM tbl_spaces "
131
                 " ORDER BY id ")
132
        cursor_system_db.execute(query)
133
        rows_spaces = cursor_system_db.fetchall()
134
        node_dict = dict()
135
        if rows_spaces is not None and len(rows_spaces) > 0:
136
            for row in rows_spaces:
137
                parent_node = node_dict[row[2]] if row[2] is not None else None
138
                node_dict[row[0]] = AnyNode(id=row[0], parent=parent_node, name=row[1])
139
140
        ################################################################################################################
141
        # Step 3: query all equipments in the space tree
142
        ################################################################################################################
143
        equipment_dict = dict()
144
        space_dict = dict()
145
146
        for node in LevelOrderIter(node_dict[space_id]):
147
            space_dict[node.id] = node.name
148
149
        cursor_system_db.execute(" SELECT e.id, e.name AS equipment_name, "
150
                                 "        e.uuid AS equipment_uuid, s.name AS space_name, "
151
                                 "        cc.name AS cost_center_name, e.description "
152
                                 " FROM tbl_spaces s, tbl_spaces_equipments se, "
153
                                 "      tbl_equipments e, tbl_cost_centers cc "
154
                                 " WHERE s.id IN ( " + ', '.join(map(str, space_dict.keys())) + ") "
155
                                 "       AND se.space_id = s.id AND se.equipment_id = e.id "
156
                                 "       AND e.cost_center_id = cc.id  ", )
157
        rows_equipments = cursor_system_db.fetchall()
158
        if rows_equipments is not None and len(rows_equipments) > 0:
159
            for row in rows_equipments:
160
                equipment_dict[row[0]] = {"equipment_name": row[1],
161
                                          "equipment_uuid": row[2],
162
                                          "space_name": row[3],
163
                                          "cost_center_name": row[4],
164
                                          "description": row[5],
165
                                          "values": list()}
166
167
        ################################################################################################################
168
        # Step 4: query energy categories
169
        ################################################################################################################
170
        cnx_energy_db = mysql.connector.connect(**config.myems_energy_db)
171
        cursor_energy_db = cnx_energy_db.cursor()
172
173
        # query energy categories in reporting period
174
        energy_category_set = set()
175
        cursor_energy_db.execute(" SELECT DISTINCT(energy_category_id) "
176
                                 " FROM tbl_equipment_input_category_hourly "
177
                                 " WHERE start_datetime_utc >= %s AND start_datetime_utc < %s ",
178
                                 (reporting_start_datetime_utc, reporting_end_datetime_utc))
179
        rows_energy_categories = cursor_energy_db.fetchall()
180
        if rows_energy_categories is not None and len(rows_energy_categories) > 0:
181
            for row_energy_category in rows_energy_categories:
182
                energy_category_set.add(row_energy_category[0])
183
184
        # query all energy categories
185
        cursor_system_db.execute(" SELECT id, name, unit_of_measure "
186
                                 " FROM tbl_energy_categories "
187
                                 " ORDER BY id ", )
188
        rows_energy_categories = cursor_system_db.fetchall()
189
        if rows_energy_categories is None or len(rows_energy_categories) == 0:
190
            if cursor_system_db:
191
                cursor_system_db.close()
192
            if cnx_system_db:
193
                cnx_system_db.close()
194
195
            if cursor_energy_db:
196
                cursor_energy_db.close()
197
            if cnx_energy_db:
198
                cnx_energy_db.close()
199
200
            raise falcon.HTTPError(status=falcon.HTTP_404,
201
                                   title='API.NOT_FOUND',
202
                                   description='API.ENERGY_CATEGORY_NOT_FOUND')
203
        energy_category_list = list()
204
        for row_energy_category in rows_energy_categories:
205
            if row_energy_category[0] in energy_category_set:
206
                energy_category_list.append({"id": row_energy_category[0],
207
                                             "name": row_energy_category[1],
208
                                             "unit_of_measure": row_energy_category[2]})
209
210
        ################################################################################################################
211
        # Step 5: query reporting period energy input
212
        ################################################################################################################
213
        for equipment_id in equipment_dict:
214
215
            cursor_energy_db.execute(" SELECT energy_category_id, SUM(actual_value) "
216
                                     " FROM tbl_equipment_input_category_hourly "
217
                                     " WHERE equipment_id = %s "
218
                                     "     AND start_datetime_utc >= %s "
219
                                     "     AND start_datetime_utc < %s "
220
                                     " GROUP BY energy_category_id ",
221
                                     (equipment_id,
222
                                      reporting_start_datetime_utc,
223
                                      reporting_end_datetime_utc))
224
            rows_equipment_energy = cursor_energy_db.fetchall()
225
            for energy_category in energy_category_list:
226
                subtotal = Decimal(0.0)
227
                for row_equipment_energy in rows_equipment_energy:
228
                    if energy_category['id'] == row_equipment_energy[0]:
229
                        subtotal = row_equipment_energy[1]
230
                        break
231
                equipment_dict[equipment_id]['values'].append(subtotal)
232
233
        if cursor_system_db:
234
            cursor_system_db.close()
235
        if cnx_system_db:
236
            cnx_system_db.close()
237
238
        if cursor_energy_db:
239
            cursor_energy_db.close()
240
        if cnx_energy_db:
241
            cnx_energy_db.close()
242
243
        ################################################################################################################
244
        # Step 6: construct the report
245
        ################################################################################################################
246
        equipment_list = list()
247
        for equipment_id, equipment in equipment_dict.items():
248
            equipment_list.append({
249
                "id": equipment_id,
250
                "equipment_name": equipment['equipment_name'],
251
                "equipment_uuid": equipment['equipment_uuid'],
252
                "space_name": equipment['space_name'],
253
                "cost_center_name": equipment['cost_center_name'],
254
                "description": equipment['description'],
255
                "values": equipment['values'],
256
            })
257
258
        result = {'equipments': equipment_list, 'energycategories': energy_category_list, 'excel_bytes_base64': None}
259
260
        # export result to Excel file and then encode the file to base64 string
261
        if not is_quick_mode:
262
            result['excel_bytes_base64'] = \
263
                excelexporters.equipmentbatch.export(result,
264
                                                     space_name,
265
                                                     reporting_period_start_datetime_local,
266
                                                     reporting_period_end_datetime_local,
267
                                                     language)
268
        resp.text = json.dumps(result)
269