Passed
Push — master ( 7c39ee...97c280 )
by
unknown
11:02
created

core.tariff.TariffItem.on_put()   F

Complexity

Conditions 25

Size

Total Lines 133
Code Lines 101

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 101
dl 0
loc 133
rs 0
c 0
b 0
f 0
cc 25
nop 3

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 core.tariff.TariffItem.on_put() 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 uuid
2
from datetime import datetime, timedelta, timezone
3
import falcon
4
import mysql.connector
5
import simplejson as json
6
from core.useractivity import user_logger, admin_control, access_control, api_key_control
7
import config
8
9
10
class TariffCollection:
11
    """
12
    Tariff Collection Resource
13
14
    This class handles CRUD operations for tariff collection.
15
    It provides endpoints for listing all tariffs and creating new tariffs.
16
    Tariffs define pricing structures for energy consumption in the energy management system.
17
    """
18
    def __init__(self):
19
        """Initialize TariffCollection"""
20
        pass
21
22
23
    @staticmethod
24
    def on_options(req, resp):
25
        """Handle OPTIONS requests for CORS preflight"""
26
        _ = req
27
        resp.status = falcon.HTTP_200
28
29
    @staticmethod
30
    def on_get(req, resp):
31
        if 'API-KEY' not in req.headers or \
32
                not isinstance(req.headers['API-KEY'], str) or \
33
                len(str.strip(req.headers['API-KEY'])) == 0:
34
            access_control(req)
35
        else:
36
            api_key_control(req)
37
38
        search_query = req.get_param('q', default=None)
39
        if search_query is not None:
40
            search_query = search_query.strip()
41
        else:
42
            search_query = ''
43
        cnx = mysql.connector.connect(**config.myems_system_db)
44
        cursor = cnx.cursor()
45
46
        query = (" SELECT t.id, t.name, t.uuid, "
47
                 "        ec.id AS energy_category_id, ec.name AS energy_category_name, "
48
                 "        t.tariff_type, t.unit_of_price, "
49
                 "        t.valid_from_datetime_utc, t.valid_through_datetime_utc "
50
                 " FROM tbl_tariffs t, tbl_energy_categories ec "
51
                 " WHERE t.energy_category_id = ec.id ")
52
        params = []
53
        if search_query:
54
            query += " AND t.name LIKE %s "
55
            params = [f'%{search_query}%']
56
        query += " ORDER BY id "
57
        cursor.execute(query, params)
58
59
        rows = cursor.fetchall()
60
61
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
62
        if config.utc_offset[0] == '-':
63
            timezone_offset = -timezone_offset
64
65
        result = list()
66
        if rows is not None and len(rows) > 0:
67
            for row in rows:
68
                meta_result = {"id": row[0],
69
                               "name": row[1],
70
                               "uuid": row[2],
71
                               "energy_category": {"id": row[3],
72
                                                   "name": row[4]},
73
                               "tariff_type": row[5],
74
                               "unit_of_price": row[6],
75
                               "valid_from": (row[7].replace(tzinfo=timezone.utc)
76
                                              + timedelta(minutes=timezone_offset)).isoformat()[0:19],
77
                               "valid_through": (row[8].replace(tzinfo=timezone.utc)
78
                                                 + timedelta(minutes=timezone_offset)).isoformat()[0:19]}
79
80
                if meta_result['tariff_type'] == 'timeofuse':
81
                    meta_result['timeofuse'] = list()
82
                    query = (" SELECT start_time_of_day, end_time_of_day, peak_type, price "
83
                             " FROM tbl_tariffs_timeofuses "
84
                             " WHERE tariff_id = %s  "
85
                             " ORDER BY id")
86
                    cursor.execute(query, (meta_result['id'],))
87
                    rows_timeofuses = cursor.fetchall()
88
                    if rows_timeofuses is not None and len(rows_timeofuses) > 0:
89
                        for row_timeofuse in rows_timeofuses:
90
                            meta_data = {"start_time_of_day": str(row_timeofuse[0]),
91
                                         "end_time_of_day": str(row_timeofuse[1]),
92
                                         "peak_type": row_timeofuse[2],
93
                                         "price": row_timeofuse[3]}
94
                            meta_result['timeofuse'].append(meta_data)
95
                else:
96
                    cursor.close()
97
                    cnx.close()
98
                    raise falcon.HTTPError(status=falcon.HTTP_400,
99
                                           title='API.ERROR',
100
                                           description='API.INVALID_TARIFF_TYPE')
101
102
                result.append(meta_result)
103
104
        cursor.close()
105
        cnx.close()
106
107
        resp.text = json.dumps(result)
108
109
    @staticmethod
110
    @user_logger
111
    def on_post(req, resp):
112
        """Handles POST requests"""
113
        admin_control(req)
114
        try:
115
            raw_json = req.stream.read().decode('utf-8')
116
        except Exception as ex:
117
            print(str(ex))
118
            raise falcon.HTTPError(status=falcon.HTTP_400,
119
                                   title='API.BAD_REQUEST',
120
                                   description='API.FAILED_TO_READ_REQUEST_STREAM')
121
        new_values = json.loads(raw_json)
122
123
        if 'name' not in new_values['data'].keys() or \
124
                not isinstance(new_values['data']['name'], str) or \
125
                len(str.strip(new_values['data']['name'])) == 0:
126
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
127
                                   description='API.INVALID_TARIFF_NAME')
128
        name = str.strip(new_values['data']['name'])
129
130
        if 'energy_category' not in new_values['data'].keys() or \
131
                'id' not in new_values['data']['energy_category'].keys() or \
132
                not isinstance(new_values['data']['energy_category']['id'], int) or \
133
                new_values['data']['energy_category']['id'] <= 0:
134
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
135
                                   description='API.INVALID_ENERGY_CATEGORY_ID')
136
        energy_category_id = new_values['data']['energy_category']['id']
137
138
        if 'tariff_type' not in new_values['data'].keys() \
139
           or str.strip(new_values['data']['tariff_type']) not in ('timeofuse',):
140
            raise falcon.HTTPError(status=falcon.HTTP_400,
141
                                   title='API.BAD_REQUEST',
142
                                   description='API.INVALID_TARIFF_TYPE')
143
        tariff_type = str.strip(new_values['data']['tariff_type'])
144
145
        if new_values['data']['tariff_type'] == 'timeofuse':
146
            if new_values['data']['timeofuse'] is None:
147
                raise falcon.HTTPError(status=falcon.HTTP_400,
148
                                       title='API.BAD_REQUEST',
149
                                       description='API.INVALID_TARIFF_TIME_OF_USE_PRICING')
150
151
        if 'unit_of_price' not in new_values['data'].keys() or \
152
                not isinstance(new_values['data']['unit_of_price'], str) or \
153
                len(str.strip(new_values['data']['unit_of_price'])) == 0:
154
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
155
                                   description='API.INVALID_UNIT_OF_PRICE')
156
        unit_of_price = str.strip(new_values['data']['unit_of_price'])
157
158
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
159
        if config.utc_offset[0] == '-':
160
            timezone_offset = -timezone_offset
161
162
        cnx = mysql.connector.connect(**config.myems_system_db)
163
        cursor = cnx.cursor()
164
165
        cursor.execute(" SELECT name "
166
                       " FROM tbl_tariffs "
167
                       " WHERE name = %s ", (name,))
168
        if cursor.fetchone() is not None:
169
            cursor.close()
170
            cnx.close()
171
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
172
                                   description='API.TARIFF_NAME_IS_ALREADY_IN_USE')
173
174
        cursor.execute(" SELECT name "
175
                       " FROM tbl_energy_categories "
176
                       " WHERE id = %s ", (energy_category_id,))
177
        if cursor.fetchone() is None:
178
            cursor.close()
179
            cnx.close()
180
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
181
                                   description='API.ENERGY_CATEGORY_NOT_FOUND')
182
183
        # todo: validate datetime values
184
        valid_from = datetime.strptime(new_values['data']['valid_from'], '%Y-%m-%dT%H:%M:%S')
185
        valid_from = valid_from.replace(tzinfo=timezone.utc)
186
        valid_from -= timedelta(minutes=timezone_offset)
187
        valid_through = datetime.strptime(new_values['data']['valid_through'], '%Y-%m-%dT%H:%M:%S')
188
        valid_through = valid_through.replace(tzinfo=timezone.utc)
189
        valid_through -= timedelta(minutes=timezone_offset)
190
191
        add_row = (" INSERT INTO tbl_tariffs "
192
                   "             (name, uuid, energy_category_id, tariff_type, unit_of_price, "
193
                   "              valid_from_datetime_utc, valid_through_datetime_utc ) "
194
                   " VALUES (%s, %s, %s, %s, %s, %s, %s) ")
195
        cursor.execute(add_row, (name,
196
                                 str(uuid.uuid4()),
197
                                 energy_category_id,
198
                                 tariff_type,
199
                                 unit_of_price,
200
                                 valid_from,
201
                                 valid_through))
202
        new_id = cursor.lastrowid
203
        cnx.commit()
204
        # insert time of use prices
205 View Code Duplication
        if tariff_type == 'timeofuse':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
206
            for timeofuse in new_values['data']['timeofuse']:
207
                add_timeofuse = (" INSERT INTO tbl_tariffs_timeofuses "
208
                                 "             (tariff_id, start_time_of_day, end_time_of_day, peak_type, price) "
209
                                 " VALUES (%s, %s, %s, %s, %s) ")
210
                cursor.execute(add_timeofuse, (new_id,
211
                                               timeofuse['start_time_of_day'],
212
                                               timeofuse['end_time_of_day'],
213
                                               timeofuse['peak_type'],
214
                                               timeofuse['price']))
215
                cnx.commit()
216
217
        cursor.close()
218
        cnx.close()
219
220
        resp.status = falcon.HTTP_201
221
        resp.location = '/tariffs/' + str(new_id)
222
223
224
class TariffItem:
225
    def __init__(self):
226
        pass
227
228
    @staticmethod
229
    def on_options(req, resp, id_):
230
        _ = req
231
        resp.status = falcon.HTTP_200
232
        _ = id_
233
234 View Code Duplication
    @staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
235
    def on_get(req, resp, id_):
236
        """Handles GET requests"""
237
        if 'API-KEY' not in req.headers or \
238
                not isinstance(req.headers['API-KEY'], str) or \
239
                len(str.strip(req.headers['API-KEY'])) == 0:
240
            access_control(req)
241
        else:
242
            api_key_control(req)
243
        if not id_.isdigit() or int(id_) <= 0:
244
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
245
                                   description='API.INVALID_TARIFF_ID')
246
247
        cnx = mysql.connector.connect(**config.myems_system_db)
248
        cursor = cnx.cursor()
249
250
        query = (" SELECT t.id, t.name, t.uuid, "
251
                 "        ec.id AS energy_category_id, ec.name AS energy_category_name, "
252
                 "        t.tariff_type, "
253
                 "        t.unit_of_price, "
254
                 "        t.valid_from_datetime_utc, t.valid_through_datetime_utc "
255
                 " FROM tbl_tariffs t, tbl_energy_categories ec "
256
                 " WHERE t.energy_category_id = ec.id AND t.id = %s ")
257
        cursor.execute(query, (id_,))
258
        row = cursor.fetchone()
259
        if row is None:
260
            cursor.close()
261
            cnx.close()
262
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
263
                                   description='API.TARIFF_NOT_FOUND')
264
265
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
266
        if config.utc_offset[0] == '-':
267
            timezone_offset = -timezone_offset
268
269
        result = {"id": row[0],
270
                  "name": row[1],
271
                  "uuid": row[2],
272
                  "energy_category": {"id": row[3],
273
                                      "name": row[4]},
274
                  "tariff_type": row[5],
275
                  "unit_of_price": row[6],
276
                  "valid_from": (row[7].replace(tzinfo=timezone.utc)
277
                                 + timedelta(minutes=timezone_offset)).isoformat()[0:19],
278
                  "valid_through": (row[8].replace(tzinfo=timezone.utc)
279
                                    + timedelta(minutes=timezone_offset)).isoformat()[0:19]}
280
281
        if result['tariff_type'] == 'timeofuse':
282
            result['timeofuse'] = list()
283
            query = (" SELECT start_time_of_day, end_time_of_day, peak_type, price "
284
                     " FROM tbl_tariffs_timeofuses"
285
                     " WHERE tariff_id = %s ")
286
            cursor.execute(query, (result['id'],))
287
            rows_timeofuses = cursor.fetchall()
288
            if rows_timeofuses is not None and len(rows_timeofuses) > 0:
289
                for row_timeofuse in rows_timeofuses:
290
                    meta_data = {"start_time_of_day": str(row_timeofuse[0]),
291
                                 "end_time_of_day": str(row_timeofuse[1]),
292
                                 "peak_type": row_timeofuse[2],
293
                                 "price": row_timeofuse[3]}
294
                    result['timeofuse'].append(meta_data)
295
296
        cursor.close()
297
        cnx.close()
298
299
        resp.text = json.dumps(result)
300
301
    @staticmethod
302
    @user_logger
303
    def on_delete(req, resp, id_):
304
        """Handles DELETE requests"""
305
        admin_control(req)
306
        if not id_.isdigit() or int(id_) <= 0:
307
            raise falcon.HTTPError(status=falcon.HTTP_400,
308
                                   title='API.BAD_REQUEST',
309
                                   description='API.INVALID_TARIFF_ID')
310
311
        cnx = mysql.connector.connect(**config.myems_system_db)
312
        cursor = cnx.cursor()
313
314
        cursor.execute(" SELECT name "
315
                       " FROM tbl_tariffs "
316
                       " WHERE id = %s ", (id_,))
317
        if cursor.fetchone() is None:
318
            cursor.close()
319
            cnx.close()
320
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
321
                                   description='API.TARIFF_NOT_FOUND')
322
323
        cursor.execute(" SELECT id "
324
                       " FROM tbl_cost_centers_tariffs "
325
                       " WHERE tariff_id = %s ", (id_,))
326
        rows = cursor.fetchall()
327
        if rows is not None and len(rows) > 0:
328
            cursor.close()
329
            cnx.close()
330
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
331
                                   description='API.TARIFF_IN_USE')
332
333
        cursor.execute(" DELETE FROM tbl_tariffs_timeofuses WHERE tariff_id = %s ", (id_,))
334
        cnx.commit()
335
336
        cursor.execute(" DELETE FROM tbl_tariffs WHERE id = %s ", (id_,))
337
        cnx.commit()
338
339
        cursor.close()
340
        cnx.close()
341
342
        resp.status = falcon.HTTP_204
343
344
    @staticmethod
345
    @user_logger
346
    def on_put(req, resp, id_):
347
        """Handles PUT requests"""
348
        admin_control(req)
349
        try:
350
            raw_json = req.stream.read().decode('utf-8')
351
        except Exception as ex:
352
            print(str(ex))
353
            raise falcon.HTTPError(status=falcon.HTTP_400,
354
                                   title='API.BAD_REQUEST',
355
                                   description='API.FAILED_TO_READ_REQUEST_STREAM')
356
357
        if not id_.isdigit() or int(id_) <= 0:
358
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
359
                                   description='API.INVALID_TARIFF_ID')
360
361
        new_values = json.loads(raw_json)
362
363
        if 'name' not in new_values['data'].keys() or \
364
                not isinstance(new_values['data']['name'], str) or \
365
                len(str.strip(new_values['data']['name'])) == 0:
366
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
367
                                   description='API.INVALID_TARIFF_NAME')
368
        name = str.strip(new_values['data']['name'])
369
370
        if 'energy_category' not in new_values['data'].keys() or \
371
                'id' not in new_values['data']['energy_category'].keys() or \
372
                not isinstance(new_values['data']['energy_category']['id'], int) or \
373
                new_values['data']['energy_category']['id'] <= 0:
374
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
375
                                   description='API.INVALID_ENERGY_CATEGORY_ID')
376
        energy_category_id = new_values['data']['energy_category']['id']
377
378
        if 'tariff_type' not in new_values['data'].keys() \
379
           or str.strip(new_values['data']['tariff_type']) not in ('timeofuse',):
380
            raise falcon.HTTPError(status=falcon.HTTP_400,
381
                                   title='API.BAD_REQUEST',
382
                                   description='API.INVALID_TARIFF_TYPE')
383
        tariff_type = str.strip(new_values['data']['tariff_type'])
384
385
        if new_values['data']['tariff_type'] == 'timeofuse':
386
            if new_values['data']['timeofuse'] is None:
387
                raise falcon.HTTPError(status=falcon.HTTP_400,
388
                                       title='API.BAD_REQUEST',
389
                                       description='API.INVALID_TARIFF_TIME_OF_USE_PRICING')
390
391
        if 'unit_of_price' not in new_values['data'].keys() or \
392
                not isinstance(new_values['data']['unit_of_price'], str) or \
393
                len(str.strip(new_values['data']['unit_of_price'])) == 0:
394
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
395
                                   description='API.INVALID_UNIT_OF_PRICE')
396
        unit_of_price = str.strip(new_values['data']['unit_of_price'])
397
398
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
399
        if config.utc_offset[0] == '-':
400
            timezone_offset = -timezone_offset
401
402
        cnx = mysql.connector.connect(**config.myems_system_db)
403
        cursor = cnx.cursor()
404
405
        # check if the tariff exist
406
        query = (" SELECT name "
407
                 " FROM tbl_tariffs "
408
                 " WHERE id = %s ")
409
        cursor.execute(query, (id_,))
410
        cursor.fetchone()
411
412
        if cursor.rowcount != 1:
413
            cursor.close()
414
            cnx.close()
415
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
416
                                   description='API.TARIFF_NOT_FOUND')
417
418
        cursor.execute(" SELECT name "
419
                       " FROM tbl_tariffs "
420
                       " WHERE name = %s AND id != %s ", (name, id_))
421
        if cursor.fetchone() is not None:
422
            cursor.close()
423
            cnx.close()
424
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
425
                                   description='API.TARIFF_NAME_IS_ALREADY_IN_USE')
426
427
        valid_from = datetime.strptime(new_values['data']['valid_from'], '%Y-%m-%dT%H:%M:%S')
428
        valid_from = valid_from.replace(tzinfo=timezone.utc)
429
        valid_from -= timedelta(minutes=timezone_offset)
430
        valid_through = datetime.strptime(new_values['data']['valid_through'], '%Y-%m-%dT%H:%M:%S')
431
        valid_through = valid_through.replace(tzinfo=timezone.utc)
432
        valid_through -= timedelta(minutes=timezone_offset)
433
434
        # update tariff itself
435
        update_row = (" UPDATE tbl_tariffs "
436
                      " SET name = %s, energy_category_id = %s, tariff_type = %s, unit_of_price = %s, "
437
                      "     valid_from_datetime_utc = %s , valid_through_datetime_utc = %s "
438
                      " WHERE id = %s ")
439
        cursor.execute(update_row, (name,
440
                                    energy_category_id,
441
                                    tariff_type,
442
                                    unit_of_price,
443
                                    valid_from,
444
                                    valid_through,
445
                                    id_,))
446
        cnx.commit()
447
448
        # update prices of the tariff
449
        if tariff_type == 'timeofuse':
450
            if 'timeofuse' not in new_values['data'].keys() or new_values['data']['timeofuse'] is None:
451
                cursor.close()
452
                cnx.close()
453
                raise falcon.HTTPError(status=falcon.HTTP_400,
454
                                       title='API.BAD_REQUEST',
455
                                       description='API.INVALID_TARIFF_TIME_OF_USE_PRICING')
456
            else:
457
                # remove all (possible) exist prices
458
                cursor.execute(" DELETE FROM tbl_tariffs_timeofuses "
459
                               " WHERE tariff_id = %s ",
460
                               (id_,))
461
                cnx.commit()
462
463
                for timeofuse in new_values['data']['timeofuse']:
464
                    add_timeofuse = (" INSERT INTO tbl_tariffs_timeofuses "
465
                                     "             (tariff_id, start_time_of_day, end_time_of_day, peak_type, price) "
466
                                     " VALUES (%s, %s, %s, %s, %s) ")
467
                    cursor.execute(add_timeofuse, (id_,
468
                                                   timeofuse['start_time_of_day'],
469
                                                   timeofuse['end_time_of_day'],
470
                                                   timeofuse['peak_type'],
471
                                                   timeofuse['price']))
472
                    cnx.commit()
473
474
        cursor.close()
475
        cnx.close()
476
        resp.status = falcon.HTTP_200
477
478
479
class TariffExport:
480
    def __init__(self):
481
        pass
482
483
    @staticmethod
484
    def on_options(req, resp, id_):
485
        _ = req
486
        resp.status = falcon.HTTP_200
487
        _ = id_
488
489 View Code Duplication
    @staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
490
    def on_get(req, resp, id_):
491
        """Handles GET requests"""
492
        if 'API-KEY' not in req.headers or \
493
                not isinstance(req.headers['API-KEY'], str) or \
494
                len(str.strip(req.headers['API-KEY'])) == 0:
495
            access_control(req)
496
        else:
497
            api_key_control(req)
498
        if not id_.isdigit() or int(id_) <= 0:
499
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
500
                                   description='API.INVALID_TARIFF_ID')
501
502
        cnx = mysql.connector.connect(**config.myems_system_db)
503
        cursor = cnx.cursor()
504
505
        query = (" SELECT t.id, t.name, t.uuid, "
506
                 "        ec.id AS energy_category_id, ec.name AS energy_category_name, "
507
                 "        t.tariff_type, "
508
                 "        t.unit_of_price, "
509
                 "        t.valid_from_datetime_utc, t.valid_through_datetime_utc "
510
                 " FROM tbl_tariffs t, tbl_energy_categories ec "
511
                 " WHERE t.energy_category_id = ec.id AND t.id = %s ")
512
        cursor.execute(query, (id_,))
513
        row = cursor.fetchone()
514
        if row is None:
515
            cursor.close()
516
            cnx.close()
517
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
518
                                   description='API.TARIFF_NOT_FOUND')
519
520
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
521
        if config.utc_offset[0] == '-':
522
            timezone_offset = -timezone_offset
523
524
        result = {"id": row[0],
525
                  "name": row[1],
526
                  "uuid": row[2],
527
                  "energy_category": {"id": row[3],
528
                                      "name": row[4]},
529
                  "tariff_type": row[5],
530
                  "unit_of_price": row[6],
531
                  "valid_from": (row[7].replace(tzinfo=timezone.utc)
532
                                 + timedelta(minutes=timezone_offset)).isoformat()[0:19],
533
                  "valid_through": (row[8].replace(tzinfo=timezone.utc)
534
                                    + timedelta(minutes=timezone_offset)).isoformat()[0:19]}
535
536
        if result['tariff_type'] == 'timeofuse':
537
            result['timeofuse'] = list()
538
            query = (" SELECT start_time_of_day, end_time_of_day, peak_type, price "
539
                     " FROM tbl_tariffs_timeofuses"
540
                     " WHERE tariff_id = %s ")
541
            cursor.execute(query, (result['id'],))
542
            rows_timeofuses = cursor.fetchall()
543
            if rows_timeofuses is not None and len(rows_timeofuses) > 0:
544
                for row_timeofuse in rows_timeofuses:
545
                    meta_data = {"start_time_of_day": str(row_timeofuse[0]),
546
                                 "end_time_of_day": str(row_timeofuse[1]),
547
                                 "peak_type": row_timeofuse[2],
548
                                 "price": row_timeofuse[3]}
549
                    result['timeofuse'].append(meta_data)
550
551
        cursor.close()
552
        cnx.close()
553
554
        resp.text = json.dumps(result)
555
556
557
class TariffImport:
558
    def __init__(self):
559
        pass
560
561
    @staticmethod
562
    def on_options(req, resp):
563
        _ = req
564
        resp.status = falcon.HTTP_200
565
566
    @staticmethod
567
    @user_logger
568
    def on_post(req, resp):
569
        """Handles POST requests"""
570
        admin_control(req)
571
        try:
572
            raw_json = req.stream.read().decode('utf-8')
573
        except Exception as ex:
574
            print(str(ex))
575
            raise falcon.HTTPError(status=falcon.HTTP_400,
576
                                   title='API.BAD_REQUEST',
577
                                   description='API.FAILED_TO_READ_REQUEST_STREAM')
578
        new_values = json.loads(raw_json)
579
580
        if 'name' not in new_values.keys() or \
581
                not isinstance(new_values['name'], str) or \
582
                len(str.strip(new_values['name'])) == 0:
583
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
584
                                   description='API.INVALID_TARIFF_NAME')
585
        name = str.strip(new_values['name'])
586
587
        if 'energy_category' not in new_values.keys() or \
588
                'id' not in new_values['energy_category'].keys() or \
589
                not isinstance(new_values['energy_category']['id'], int) or \
590
                new_values['energy_category']['id'] <= 0:
591
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
592
                                   description='API.INVALID_ENERGY_CATEGORY_ID')
593
        energy_category_id = new_values['energy_category']['id']
594
595
        if 'tariff_type' not in new_values.keys() \
596
                or str.strip(new_values['tariff_type']) not in ('timeofuse',):
597
            raise falcon.HTTPError(status=falcon.HTTP_400,
598
                                   title='API.BAD_REQUEST',
599
                                   description='API.INVALID_TARIFF_TYPE')
600
        tariff_type = str.strip(new_values['tariff_type'])
601
602
        if new_values['tariff_type'] == 'timeofuse':
603
            if new_values['timeofuse'] is None:
604
                raise falcon.HTTPError(status=falcon.HTTP_400,
605
                                       title='API.BAD_REQUEST',
606
                                       description='API.INVALID_TARIFF_TIME_OF_USE_PRICING')
607
608
        if 'unit_of_price' not in new_values.keys() or \
609
                not isinstance(new_values['unit_of_price'], str) or \
610
                len(str.strip(new_values['unit_of_price'])) == 0:
611
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
612
                                   description='API.INVALID_UNIT_OF_PRICE')
613
        unit_of_price = str.strip(new_values['unit_of_price'])
614
615
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
616
        if config.utc_offset[0] == '-':
617
            timezone_offset = -timezone_offset
618
619
        cnx = mysql.connector.connect(**config.myems_system_db)
620
        cursor = cnx.cursor()
621
622
        cursor.execute(" SELECT name "
623
                       " FROM tbl_tariffs "
624
                       " WHERE name = %s ", (name,))
625
        if cursor.fetchone() is not None:
626
            cursor.close()
627
            cnx.close()
628
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
629
                                   description='API.TARIFF_NAME_IS_ALREADY_IN_USE')
630
631
        cursor.execute(" SELECT name "
632
                       " FROM tbl_energy_categories "
633
                       " WHERE id = %s ", (energy_category_id,))
634
        if cursor.fetchone() is None:
635
            cursor.close()
636
            cnx.close()
637
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
638
                                   description='API.ENERGY_CATEGORY_NOT_FOUND')
639
640
        # todo: validate datetime values
641
        valid_from = datetime.strptime(new_values['valid_from'], '%Y-%m-%dT%H:%M:%S')
642
        valid_from = valid_from.replace(tzinfo=timezone.utc)
643
        valid_from -= timedelta(minutes=timezone_offset)
644
        valid_through = datetime.strptime(new_values['valid_through'], '%Y-%m-%dT%H:%M:%S')
645
        valid_through = valid_through.replace(tzinfo=timezone.utc)
646
        valid_through -= timedelta(minutes=timezone_offset)
647
648
        add_row = (" INSERT INTO tbl_tariffs "
649
                   "             (name, uuid, energy_category_id, tariff_type, unit_of_price, "
650
                   "              valid_from_datetime_utc, valid_through_datetime_utc ) "
651
                   " VALUES (%s, %s, %s, %s, %s, %s, %s) ")
652
        cursor.execute(add_row, (name,
653
                                 str(uuid.uuid4()),
654
                                 energy_category_id,
655
                                 tariff_type,
656
                                 unit_of_price,
657
                                 valid_from,
658
                                 valid_through))
659
        new_id = cursor.lastrowid
660
        cnx.commit()
661
        # insert time of use prices
662 View Code Duplication
        if tariff_type == 'timeofuse':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
663
            for timeofuse in new_values['timeofuse']:
664
                add_timeofuse = (" INSERT INTO tbl_tariffs_timeofuses "
665
                                 "             (tariff_id, start_time_of_day, end_time_of_day, peak_type, price) "
666
                                 " VALUES (%s, %s, %s, %s, %s) ")
667
                cursor.execute(add_timeofuse, (new_id,
668
                                               timeofuse['start_time_of_day'],
669
                                               timeofuse['end_time_of_day'],
670
                                               timeofuse['peak_type'],
671
                                               timeofuse['price']))
672
                cnx.commit()
673
674
        cursor.close()
675
        cnx.close()
676
677
        resp.status = falcon.HTTP_201
678
        resp.location = '/tariffs/' + str(new_id)
679
680
681
class TariffClone:
682
    def __init__(self):
683
        pass
684
685
    @staticmethod
686
    def on_options(req, resp, id_):
687
        _ = req
688
        resp.status = falcon.HTTP_200
689
        _ = id_
690
691
    @staticmethod
692
    @user_logger
693
    def on_post(req, resp, id_):
694
        admin_control(req)
695
        if not id_.isdigit() or int(id_) <= 0:
696
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
697
                                   description='API.INVALID_TARIFF_ID')
698
699
        cnx = mysql.connector.connect(**config.myems_system_db)
700
        cursor = cnx.cursor()
701
702
        query = (" SELECT t.id, t.name, t.uuid, "
703
                 "        ec.id AS energy_category_id, ec.name AS energy_category_name, "
704
                 "        t.tariff_type, "
705
                 "        t.unit_of_price, "
706
                 "        t.valid_from_datetime_utc, t.valid_through_datetime_utc "
707
                 " FROM tbl_tariffs t, tbl_energy_categories ec "
708
                 " WHERE t.energy_category_id = ec.id AND t.id = %s ")
709
        cursor.execute(query, (id_,))
710
        row = cursor.fetchone()
711
        if row is None:
712
            cursor.close()
713
            cnx.close()
714
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
715
                                   description='API.TARIFF_NOT_FOUND')
716
717
        result = {"id": row[0],
718
                  "name": row[1],
719
                  "uuid": row[2],
720
                  "energy_category": {"id": row[3],
721
                                      "name": row[4]},
722
                  "tariff_type": row[5],
723
                  "unit_of_price": row[6],
724
                  "valid_from": row[7].isoformat()[0:19],
725
                  "valid_through": row[8].isoformat()[0:19]}
726
727
        if result['tariff_type'] == 'timeofuse':
728
            result['timeofuse'] = list()
729
            query = (" SELECT start_time_of_day, end_time_of_day, peak_type, price "
730
                     " FROM tbl_tariffs_timeofuses"
731
                     " WHERE tariff_id = %s ")
732
            cursor.execute(query, (result['id'],))
733
            rows_timeofuses = cursor.fetchall()
734
            if rows_timeofuses is not None and len(rows_timeofuses) > 0:
735
                for row_timeofuse in rows_timeofuses:
736
                    meta_data = {"start_time_of_day": str(row_timeofuse[0]),
737
                                 "end_time_of_day": str(row_timeofuse[1]),
738
                                 "peak_type": row_timeofuse[2],
739
                                 "price": row_timeofuse[3]}
740
                    result['timeofuse'].append(meta_data)
741
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
742
        if config.utc_offset[0] == '-':
743
            timezone_offset = -timezone_offset
744
        new_name = (str.strip(result['name']) +
745
                    (datetime.utcnow() + timedelta(minutes=timezone_offset)).isoformat(sep='-', timespec='seconds'))
746
        add_row = (" INSERT INTO tbl_tariffs "
747
                   "             (name, uuid, energy_category_id, tariff_type, unit_of_price, "
748
                   "              valid_from_datetime_utc, valid_through_datetime_utc ) "
749
                   " VALUES (%s, %s, %s, %s, %s, %s, %s) ")
750
        cursor.execute(add_row, (new_name,
751
                                 str(uuid.uuid4()),
752
                                 result['energy_category']['id'],
753
                                 result['tariff_type'],
754
                                 result['unit_of_price'],
755
                                 result['valid_from'],
756
                                 result['valid_through']))
757
        new_id = cursor.lastrowid
758
        cnx.commit()
759
        # insert time of use prices
760
        if result['tariff_type'] == 'timeofuse':
761
            for timeofuse in result['timeofuse']:
762
                add_timeofuse = (" INSERT INTO tbl_tariffs_timeofuses "
763
                                 "             (tariff_id, start_time_of_day, end_time_of_day, peak_type, price) "
764
                                 " VALUES (%s, %s, %s, %s, %s) ")
765
                cursor.execute(add_timeofuse, (new_id,
766
                                               timeofuse['start_time_of_day'],
767
                                               timeofuse['end_time_of_day'],
768
                                               timeofuse['peak_type'],
769
                                               timeofuse['price']))
770
                cnx.commit()
771
772
        cursor.close()
773
        cnx.close()
774
775
        resp.status = falcon.HTTP_201
776
        resp.location = '/tariffs/' + str(new_id)
777