core.tariff.TariffItem.on_put()   F
last analyzed

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