CostCenterTariffCollection.on_options()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 5
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nop 3
1
import uuid
2
import falcon
3
import mysql.connector
4
import simplejson as json
5
import redis
6
from core.useractivity import user_logger, admin_control, access_control, api_key_control
7
import config
8
9
10 View Code Duplication
def clear_costcenter_cache(cost_center_id=None):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
11
    """
12
    Clear cost center-related cache after data modification
13
14
    Args:
15
        cost_center_id: Cost center ID (optional, for specific cost center cache)
16
    """
17
    # Check if Redis is enabled
18
    if not config.redis.get('is_enabled', False):
19
        return
20
21
    redis_client = None
22
    try:
23
        redis_client = redis.Redis(
24
            host=config.redis['host'],
25
            port=config.redis['port'],
26
            password=config.redis['password'] if config.redis['password'] else None,
27
            db=config.redis['db'],
28
            decode_responses=True,
29
            socket_connect_timeout=2,
30
            socket_timeout=2
31
        )
32
        redis_client.ping()
33
34
        # Clear cost center list cache
35
        list_cache_key_pattern = 'costcenter:list*'
36
        matching_keys = redis_client.keys(list_cache_key_pattern)
37
        if matching_keys:
38
            redis_client.delete(*matching_keys)
39
40
        # Clear specific cost center item cache if cost_center_id is provided
41
        if cost_center_id:
42
            item_cache_key = f'costcenter:item:{cost_center_id}'
43
            redis_client.delete(item_cache_key)
44
            # Also clear tariff list cache for this cost center
45
            tariff_list_cache_key = f'costcenter:tariff:list:{cost_center_id}'
46
            redis_client.delete(tariff_list_cache_key)
47
48
    except Exception:
49
        # If cache clear fails, ignore and continue
50
        pass
51
52
53
class CostCenterCollection:
54
    """
55
    Cost Center Collection Resource
56
57
    This class handles CRUD operations for cost center collection.
58
    It provides endpoints for listing all cost centers and creating new cost centers.
59
    Cost centers represent organizational units for cost allocation in the energy management system.
60
    """
61
    def __init__(self):
62
        """Initialize CostCenterCollection"""
63
        pass
64
65
    @staticmethod
66
    def on_options(req, resp):
67
        """Handle OPTIONS requests for CORS preflight"""
68
        _ = req
69
        resp.status = falcon.HTTP_200
70
71
    @staticmethod
72
    def on_get(req, resp):
73
        """Handles GET requests"""
74
        if 'API-KEY' not in req.headers or \
75
                not isinstance(req.headers['API-KEY'], str) or \
76
                len(str.strip(req.headers['API-KEY'])) == 0:
77
            access_control(req)
78
        else:
79
            api_key_control(req)
80
81
        # Redis cache key
82
        cache_key = 'costcenter:list'
83
        cache_expire = 28800  # 8 hours in seconds (long-term cache)
84
85
        # Try to get from Redis cache (only if Redis is enabled)
86
        redis_client = None
87
        if config.redis.get('is_enabled', False):
88
            try:
89
                redis_client = redis.Redis(
90
                    host=config.redis['host'],
91
                    port=config.redis['port'],
92
                    password=config.redis['password'] if config.redis['password'] else None,
93
                    db=config.redis['db'],
94
                    decode_responses=True,
95
                    socket_connect_timeout=2,
96
                    socket_timeout=2
97
                )
98
                redis_client.ping()
99
                cached_result = redis_client.get(cache_key)
100
                if cached_result:
101
                    resp.text = cached_result
102
                    return
103
            except Exception:
104
                # If Redis connection fails, continue to database query
105
                pass
106
107
        # Cache miss or Redis error - query database
108
        cnx = mysql.connector.connect(**config.myems_system_db)
109
        cursor = cnx.cursor()
110
111
        query = (" SELECT id, name, uuid, external_id "
112
                 " FROM tbl_cost_centers "
113
                 " ORDER BY id")
114
        cursor.execute(query)
115
        rows = cursor.fetchall()
116
        cursor.close()
117
        cnx.close()
118
119
        result = list()
120
        if rows is not None and len(rows) > 0:
121
            for row in rows:
122
                meta_result = {"id": row[0],
123
                               "name": row[1],
124
                               "uuid": row[2],
125
                               "external_id": row[3]}
126
                result.append(meta_result)
127
128
        # Store result in Redis cache
129
        result_json = json.dumps(result)
130
        if redis_client:
131
            try:
132
                redis_client.setex(cache_key, cache_expire, result_json)
133
            except Exception:
134
                # If cache set fails, ignore and continue
135
                pass
136
137
        resp.text = result_json
138
139
    @staticmethod
140
    @user_logger
141
    def on_post(req, resp):
142
        """Handles POST requests"""
143
        admin_control(req)
144
        try:
145
            raw_json = req.stream.read().decode('utf-8')
146
147
        except UnicodeDecodeError as ex:
148
            print("Failed to decode request")
149
            raise falcon.HTTPError(status=falcon.HTTP_400,
150
                                   title='API.BAD_REQUEST',
151
                                   description='API.INVALID_ENCODING')
152
        except Exception as ex:
153
            print("Unexpected error reading request stream")
154
            raise falcon.HTTPError(status=falcon.HTTP_400,
155
                                   title='API.BAD_REQUEST',
156
                                   description='API.FAILED_TO_READ_REQUEST_STREAM')
157
158
        new_values = json.loads(raw_json)
159
160
        if 'name' not in new_values['data'].keys() or len(new_values['data']['name']) <= 0:
161
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
162
                                   description='API.INVALID_NAME_VALUE')
163
        name = str.strip(new_values['data']['name'])
164
165
        if 'external_id' in new_values['data'].keys() and \
166
                new_values['data']['external_id'] is not None and \
167
                len(str(new_values['data']['external_id'])) > 0:
168
            external_id = str.strip(new_values['data']['external_id'])
169
        else:
170
            external_id = None
171
172
        cnx = mysql.connector.connect(**config.myems_system_db)
173
        cursor = cnx.cursor()
174
175
        cursor.execute(" SELECT name "
176
                       " FROM tbl_cost_centers "
177
                       " WHERE name = %s ", (name, ))
178
        if cursor.fetchone() is not None:
179
            cursor.close()
180
            cnx.close()
181
            raise falcon.HTTPError(status=falcon.HTTP_400,
182
                                   title='API.BAD_REQUEST',
183
                                   description='API.COST_CENTER_NAME_EXISTS')
184
        if external_id is not None:
185
            cursor.execute(" SELECT name "
186
                           " FROM tbl_cost_centers "
187
                           " WHERE external_id = %s ", (external_id, ))
188
            if cursor.fetchone() is not None:
189
                cursor.close()
190
                cnx.close()
191
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
192
                                       description='API.COST_CENTER_EXTERNAL_ID_EXISTS')
193
194
        add_row = (" INSERT INTO tbl_cost_centers "
195
                   "     (name, uuid, external_id) "
196
                   " VALUES (%s, %s, %s) ")
197
        cursor.execute(add_row, (name,
198
                                 str(uuid.uuid4()),
199
                                 external_id,))
200
        new_id = cursor.lastrowid
201
        cnx.commit()
202
        cursor.close()
203
        cnx.close()
204
205
        # Clear cache after creating new cost center
206
        clear_costcenter_cache()
207
208
        resp.status = falcon.HTTP_201
209
        resp.location = '/costcenters/' + str(new_id)
210
211
212
class CostCenterItem:
213
    def __init__(self):
214
        pass
215
216
    @staticmethod
217
    def on_options(req, resp, id_):
218
        _ = req
219
        resp.status = falcon.HTTP_200
220
        _ = id_
221
222
    @staticmethod
223
    def on_get(req, resp, id_):
224
        """Handles GET requests"""
225
        if 'API-KEY' not in req.headers or \
226
                not isinstance(req.headers['API-KEY'], str) or \
227
                len(str.strip(req.headers['API-KEY'])) == 0:
228
            access_control(req)
229
        else:
230
            api_key_control(req)
231
        if not id_.isdigit() or int(id_) <= 0:
232
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
233
                                   description='API.INVALID_COST_CENTER_ID')
234
235
        # Redis cache key
236
        cache_key = f'costcenter:item:{id_}'
237
        cache_expire = 28800  # 8 hours in seconds (long-term cache)
238
239
        # Try to get from Redis cache (only if Redis is enabled)
240
        redis_client = None
241
        if config.redis.get('is_enabled', False):
242
            try:
243
                redis_client = redis.Redis(
244
                    host=config.redis['host'],
245
                    port=config.redis['port'],
246
                    password=config.redis['password'] if config.redis['password'] else None,
247
                    db=config.redis['db'],
248
                    decode_responses=True,
249
                    socket_connect_timeout=2,
250
                    socket_timeout=2
251
                )
252
                redis_client.ping()
253
                cached_result = redis_client.get(cache_key)
254
                if cached_result:
255
                    resp.text = cached_result
256
                    return
257
            except Exception:
258
                # If Redis connection fails, continue to database query
259
                pass
260
261
        # Cache miss or Redis error - query database
262
        cnx = mysql.connector.connect(**config.myems_system_db)
263
        cursor = cnx.cursor()
264
265
        query = (" SELECT id, name, uuid, external_id "
266
                 " FROM tbl_cost_centers "
267
                 " WHERE id = %s ")
268
        cursor.execute(query, (id_,))
269
        row = cursor.fetchone()
270
        cursor.close()
271
        cnx.close()
272
273
        if row is None:
274
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
275
                                   description='API.COST_CENTER_NOT_FOUND')
276
277
        result = {"id": row[0],
278
                  "name": row[1],
279
                  "uuid": row[2],
280
                  "external_id": row[3]}
281
282
        # Store result in Redis cache
283
        result_json = json.dumps(result)
284
        if redis_client:
285
            try:
286
                redis_client.setex(cache_key, cache_expire, result_json)
287
            except Exception:
288
                # If cache set fails, ignore and continue
289
                pass
290
291
        resp.text = result_json
292
293
    @staticmethod
294
    @user_logger
295
    def on_delete(req, resp, id_):
296
        """Handles DELETE requests"""
297
        admin_control(req)
298
        if not id_.isdigit() or int(id_) <= 0:
299
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
300
                                   description='API.INVALID_COST_CENTER_ID')
301
302
        cnx = mysql.connector.connect(**config.myems_system_db)
303
        cursor = cnx.cursor()
304
305
        cursor.execute(" SELECT name "
306
                       " FROM tbl_cost_centers "
307
                       " WHERE id = %s ", (id_,))
308
        if cursor.fetchone() is None:
309
            cursor.close()
310
            cnx.close()
311
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
312
                                   description='API.COST_CENTER_NOT_FOUND')
313
314
        # check relation with charging_stations
315
        cursor.execute(" SELECT id "
316
                       " FROM tbl_charging_stations "
317
                       " WHERE cost_center_id = %s ", (id_,))
318
        rows_charging_stations = cursor.fetchall()
319
        if rows_charging_stations is not None and len(rows_charging_stations) > 0:
320
            cursor.close()
321
            cnx.close()
322
            raise falcon.HTTPError(status=falcon.HTTP_400,
323
                                   title='API.BAD_REQUEST',
324
                                   description='API.THERE_IS_RELATION_WITH_CHARGING_STATIONS')
325
326
        # check relation with energy_storage_containers
327
        cursor.execute(" SELECT id "
328
                       " FROM tbl_energy_storage_containers "
329
                       " WHERE cost_center_id = %s ", (id_,))
330
        rows_energy_storage_containers = cursor.fetchall()
331
        if rows_energy_storage_containers is not None and len(rows_energy_storage_containers) > 0:
332
            cursor.close()
333
            cnx.close()
334
            raise falcon.HTTPError(status=falcon.HTTP_400,
335
                                   title='API.BAD_REQUEST',
336
                                   description='API.THERE_IS_RELATION_WITH_ENERGY_STORAGE_CONTAINERS')
337
338
        # check relation with energy_storage_power_stations
339
        cursor.execute(" SELECT id "
340
                       " FROM tbl_energy_storage_power_stations "
341
                       " WHERE cost_center_id = %s ", (id_,))
342
        rows_energy_storage_power_stations = cursor.fetchall()
343
        if rows_energy_storage_power_stations is not None and len(rows_energy_storage_power_stations) > 0:
344
            cursor.close()
345
            cnx.close()
346
            raise falcon.HTTPError(status=falcon.HTTP_400,
347
                                   title='API.BAD_REQUEST',
348
                                   description='API.THERE_IS_RELATION_WITH_ENERGY_STORAGE_POWER_STATIONS')
349
350
        # check relation with microgrids
351
        cursor.execute(" SELECT id "
352
                       " FROM tbl_microgrids "
353
                       " WHERE cost_center_id = %s ", (id_,))
354
        rows_microgrids = cursor.fetchall()
355
        if rows_microgrids is not None and len(rows_microgrids) > 0:
356
            cursor.close()
357
            cnx.close()
358
            raise falcon.HTTPError(status=falcon.HTTP_400,
359
                                   title='API.BAD_REQUEST',
360
                                   description='API.THERE_IS_RELATION_WITH_MICROGRIDS')
361
362
        # check relation with photovoltaic_power_stations
363
        cursor.execute(" SELECT id "
364
                       " FROM tbl_photovoltaic_power_stations "
365
                       " WHERE cost_center_id = %s ", (id_,))
366
        rows_photovoltaic_power_stations = cursor.fetchall()
367
        if rows_photovoltaic_power_stations is not None and len(rows_photovoltaic_power_stations) > 0:
368
            cursor.close()
369
            cnx.close()
370
            raise falcon.HTTPError(status=falcon.HTTP_400,
371
                                   title='API.BAD_REQUEST',
372
                                   description='API.THERE_IS_RELATION_WITH_PHOTOVOLTAIC_POWER_STATIONS')
373
374
        # check relation with virtual_power_plants
375
        cursor.execute(" SELECT id "
376
                       " FROM tbl_virtual_power_plants "
377
                       " WHERE cost_center_id = %s ", (id_,))
378
        rows_virtual_power_plants = cursor.fetchall()
379
        if rows_virtual_power_plants is not None and len(rows_virtual_power_plants) > 0:
380
            cursor.close()
381
            cnx.close()
382
            raise falcon.HTTPError(status=falcon.HTTP_400,
383
                                   title='API.BAD_REQUEST',
384
                                   description='API.THERE_IS_RELATION_WITH_VIRTUAL_POWER_PLANTS')
385
386
        # check relation with wind_farms
387
        cursor.execute(" SELECT id "
388
                       " FROM tbl_wind_farms "
389
                       " WHERE cost_center_id = %s ", (id_,))
390
        rows_wind_farms = cursor.fetchall()
391
        if rows_wind_farms is not None and len(rows_wind_farms) > 0:
392
            cursor.close()
393
            cnx.close()
394
            raise falcon.HTTPError(status=falcon.HTTP_400,
395
                                   title='API.BAD_REQUEST',
396
                                   description='API.THERE_IS_RELATION_WITH_WIND_FARMS')
397
398
        # check relation with equipments
399
        cursor.execute(" SELECT id "
400
                       " FROM tbl_equipments "
401
                       " WHERE cost_center_id = %s ", (id_,))
402
        rows_equipments = cursor.fetchall()
403
        if rows_equipments is not None and len(rows_equipments) > 0:
404
            cursor.close()
405
            cnx.close()
406
            raise falcon.HTTPError(status=falcon.HTTP_400,
407
                                   title='API.BAD_REQUEST',
408
                                   description='API.THERE_IS_RELATION_WITH_EQUIPMENTS')
409
410
        # check relation with combined equipments
411
        cursor.execute(" SELECT id "
412
                       " FROM tbl_combined_equipments "
413
                       " WHERE cost_center_id = %s ", (id_,))
414
        rows_combined_equipments = cursor.fetchall()
415
        if rows_combined_equipments is not None and len(rows_combined_equipments) > 0:
416
            cursor.close()
417
            cnx.close()
418
            raise falcon.HTTPError(status=falcon.HTTP_400,
419
                                   title='API.BAD_REQUEST',
420
                                   description='API.THERE_IS_RELATION_WITH_COMBINED_EQUIPMENTS')
421
422
        # check relation with meters
423
        cursor.execute(" SELECT id "
424
                       " FROM tbl_meters "
425
                       " WHERE cost_center_id = %s ", (id_,))
426
        rows_meters = cursor.fetchall()
427
        if rows_meters is not None and len(rows_meters) > 0:
428
            cursor.close()
429
            cnx.close()
430
            raise falcon.HTTPError(status=falcon.HTTP_400,
431
                                   title='API.BAD_REQUEST',
432
                                   description='API.THERE_IS_RELATION_WITH_METERS')
433
434
        # check relation with offline meters
435
        cursor.execute(" SELECT id "
436
                       " FROM tbl_offline_meters "
437
                       " WHERE cost_center_id = %s ", (id_,))
438
        rows_offline_meters = cursor.fetchall()
439
        if rows_offline_meters is not None and len(rows_offline_meters) > 0:
440
            cursor.close()
441
            cnx.close()
442
            raise falcon.HTTPError(status=falcon.HTTP_400,
443
                                   title='API.BAD_REQUEST',
444
                                   description='API.THERE_IS_RELATION_WITH_OFFLINE_METERS')
445
446
        # check relation with virtual meters
447
        cursor.execute(" SELECT id "
448
                       " FROM tbl_virtual_meters "
449
                       " WHERE cost_center_id = %s ", (id_,))
450
        rows_virtual_meters = cursor.fetchall()
451
        if rows_virtual_meters is not None and len(rows_virtual_meters) > 0:
452
            cursor.close()
453
            cnx.close()
454
            raise falcon.HTTPError(status=falcon.HTTP_400,
455
                                   title='API.BAD_REQUEST',
456
                                   description='API.THERE_IS_RELATION_WITH_OFFLINE_METERS')
457
458
        # check relation with tenants
459
        cursor.execute(" SELECT id "
460
                       " FROM tbl_tenants "
461
                       " WHERE cost_center_id = %s ", (id_,))
462
        rows_tenants = cursor.fetchall()
463
        if rows_tenants is not None and len(rows_tenants) > 0:
464
            cursor.close()
465
            cnx.close()
466
            raise falcon.HTTPError(status=falcon.HTTP_400,
467
                                   title='API.BAD_REQUEST',
468
                                   description='API.THERE_IS_RELATION_WITH_TENANTS')
469
470
        # check relation with stores
471
        cursor.execute(" SELECT id "
472
                       " FROM tbl_stores "
473
                       " WHERE cost_center_id = %s ", (id_,))
474
        rows_stores = cursor.fetchall()
475
        if rows_stores is not None and len(rows_stores) > 0:
476
            cursor.close()
477
            cnx.close()
478
            raise falcon.HTTPError(status=falcon.HTTP_400,
479
                                   title='API.BAD_REQUEST',
480
                                   description='API.THERE_IS_RELATION_WITH_STORES')
481
482
        # check relation with spaces
483
        cursor.execute(" SELECT id "
484
                       " FROM tbl_spaces "
485
                       " WHERE cost_center_id = %s ", (id_,))
486
        rows_factories = cursor.fetchall()
487
        if rows_factories is not None and len(rows_factories) > 0:
488
            cursor.close()
489
            cnx.close()
490
            raise falcon.HTTPError(status=falcon.HTTP_400,
491
                                   title='API.BAD_REQUEST',
492
                                   description='API.THERE_IS_RELATION_WITH_SPACES')
493
494
        # check relation with shopfloors
495
        cursor.execute(" SELECT id "
496
                       " FROM tbl_shopfloors "
497
                       " WHERE cost_center_id = %s ", (id_,))
498
        rows_shopfloors = cursor.fetchall()
499
        if rows_shopfloors is not None and len(rows_shopfloors) > 0:
500
            cursor.close()
501
            cnx.close()
502
            raise falcon.HTTPError(status=falcon.HTTP_400,
503
                                   title='API.BAD_REQUEST',
504
                                   description='API.THERE_IS_RELATION_WITH_SHOPFLOORS')
505
506
        # delete relation with tariffs
507
        cursor.execute(" DELETE FROM tbl_cost_centers_tariffs WHERE cost_center_id = %s ", (id_,))
508
509
        cursor.execute(" DELETE FROM tbl_cost_centers WHERE id = %s ", (id_,))
510
        cnx.commit()
511
512
        cursor.close()
513
        cnx.close()
514
515
        # Clear cache after deleting cost center
516
        clear_costcenter_cache(cost_center_id=id_)
517
518
        resp.status = falcon.HTTP_204
519
520
    @staticmethod
521
    @user_logger
522
    def on_put(req, resp, id_):
523
        """Handles PUT requests"""
524
        admin_control(req)
525
        try:
526
            raw_json = req.stream.read().decode('utf-8')
527
        except UnicodeDecodeError as ex:
528
            print("Failed to decode request")
529
            raise falcon.HTTPError(status=falcon.HTTP_400,
530
                                   title='API.BAD_REQUEST',
531
                                   description='API.INVALID_ENCODING')
532
        except Exception as ex:
533
            print("Unexpected error reading request stream")
534
            raise falcon.HTTPError(status=falcon.HTTP_400,
535
                                   title='API.BAD_REQUEST',
536
                                   description='API.FAILED_TO_READ_REQUEST_STREAM')
537
538
        if not id_.isdigit() or int(id_) <= 0:
539
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
540
                                   description='API.INVALID_COST_CENTER_ID')
541
542
        new_values = json.loads(raw_json)
543
544
        if 'name' not in new_values['data'].keys() or len(new_values['data']['name']) <= 0:
545
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
546
                                   description='API.INVALID_NAME_VALUE')
547
        name = str.strip(new_values['data']['name'])
548
549
        if 'external_id' in new_values['data'].keys() and \
550
                new_values['data']['external_id'] is not None and \
551
                len(str(new_values['data']['external_id'])) > 0:
552
            external_id = str.strip(new_values['data']['external_id'])
553
        else:
554
            external_id = None
555
556
        cnx = mysql.connector.connect(**config.myems_system_db)
557
        cursor = cnx.cursor()
558
559
        cursor.execute(" SELECT name "
560
                       " FROM tbl_cost_centers "
561
                       " WHERE id = %s ", (id_,))
562
        if cursor.fetchone() is None:
563
            cursor.close()
564
            cnx.close()
565
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
566
                                   description='API.COST_CENTER_NOT_FOUND')
567
568
        cursor.execute(" SELECT name "
569
                       " FROM tbl_cost_centers "
570
                       " WHERE name = %s AND id != %s ",
571
                       (name, id_, ))
572
        if cursor.fetchone() is not None:
573
            cursor.close()
574
            cnx.close()
575
            raise falcon.HTTPError(status=falcon.HTTP_400,
576
                                   title='API.BAD_REQUEST',
577
                                   description='API.COST_CENTER_NAME_EXISTS')
578
        if external_id is not None:
579
            cursor.execute(" SELECT name "
580
                           " FROM tbl_cost_centers "
581
                           " WHERE external_id = %s AND id != %s ",
582
                           (external_id, id_, ))
583
            if cursor.fetchone() is not None:
584
                cursor.close()
585
                cnx.close()
586
                raise falcon.HTTPError(status=falcon.HTTP_400,
587
                                       title='API.BAD_REQUEST',
588
                                       description='API.COST_CENTER_EXTERNAL_ID_EXISTS')
589
590
        cursor.execute(" SELECT name "
591
                       " FROM tbl_cost_centers "
592
                       " WHERE id = %s ", (id_,))
593
        if cursor.fetchone() is None:
594
            cursor.close()
595
            cnx.close()
596
            raise falcon.HTTPError(status=falcon.HTTP_404,
597
                                   title='API.NOT_FOUND',
598
                                   description='API.COST_CENTER_NOT_FOUND')
599
600
        update_row = (" UPDATE tbl_cost_centers "
601
                      " SET name = %s, external_id = %s "
602
                      " WHERE id = %s ")
603
604
        cursor.execute(update_row, (name,
605
                                    external_id,
606
                                    id_,))
607
        cnx.commit()
608
609
        cursor.close()
610
        cnx.close()
611
612
        # Clear cache after updating cost center
613
        clear_costcenter_cache(cost_center_id=id_)
614
615
        resp.status = falcon.HTTP_200
616
617
618
class CostCenterTariffCollection:
619
    def __init__(self):
620
        pass
621
622
    @staticmethod
623
    def on_options(req, resp, id_):
624
        _ = req
625
        resp.status = falcon.HTTP_200
626
        _ = id_
627
628 View Code Duplication
    @staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
629
    def on_get(req, resp, id_):
630
        """Handles GET requests"""
631
        if 'API-KEY' not in req.headers or \
632
                not isinstance(req.headers['API-KEY'], str) or \
633
                len(str.strip(req.headers['API-KEY'])) == 0:
634
            access_control(req)
635
        else:
636
            api_key_control(req)
637
        if not id_.isdigit() or int(id_) <= 0:
638
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
639
                                   description='API.INVALID_COST_CENTER_ID')
640
641
        # Redis cache key
642
        cache_key = f'costcenter:tariff:list:{id_}'
643
        cache_expire = 28800  # 8 hours in seconds (long-term cache)
644
645
        # Try to get from Redis cache (only if Redis is enabled)
646
        redis_client = None
647
        if config.redis.get('is_enabled', False):
648
            try:
649
                redis_client = redis.Redis(
650
                    host=config.redis['host'],
651
                    port=config.redis['port'],
652
                    password=config.redis['password'] if config.redis['password'] else None,
653
                    db=config.redis['db'],
654
                    decode_responses=True,
655
                    socket_connect_timeout=2,
656
                    socket_timeout=2
657
                )
658
                redis_client.ping()
659
                cached_result = redis_client.get(cache_key)
660
                if cached_result:
661
                    resp.text = cached_result
662
                    return
663
            except Exception:
664
                # If Redis connection fails, continue to database query
665
                pass
666
667
        # Cache miss or Redis error - query database
668
        cnx = mysql.connector.connect(**config.myems_system_db)
669
        cursor = cnx.cursor()
670
671
        query = (" SELECT t.id, t.name, t.uuid, "
672
                 "        t.tariff_type, t.unit_of_price "
673
                 " FROM tbl_tariffs t, tbl_cost_centers_tariffs ct "
674
                 " WHERE t.id = ct.tariff_id AND ct.cost_center_id = %s "
675
                 " ORDER BY t.name ")
676
        cursor.execute(query, (id_,))
677
        rows = cursor.fetchall()
678
679
        cursor.close()
680
        cnx.close()
681
682
        result = list()
683
        if rows is not None and len(rows) > 0:
684
            for row in rows:
685
                meta_result = {"id": row[0],
686
                               "name": row[1],
687
                               "uuid": row[2],
688
                               "tariff_type": row[3],
689
                               "unit_of_price": row[4]}
690
                result.append(meta_result)
691
692
        # Store result in Redis cache
693
        result_json = json.dumps(result)
694
        if redis_client:
695
            try:
696
                redis_client.setex(cache_key, cache_expire, result_json)
697
            except Exception:
698
                # If cache set fails, ignore and continue
699
                pass
700
701
        resp.text = result_json
702
703 View Code Duplication
    @staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
704
    @user_logger
705
    def on_post(req, resp, id_):
706
        """Handles POST requests"""
707
        admin_control(req)
708
        try:
709
            raw_json = req.stream.read().decode('utf-8')
710
        except UnicodeDecodeError as ex:
711
            print("Failed to decode request")
712
            raise falcon.HTTPError(status=falcon.HTTP_400,
713
                                   title='API.BAD_REQUEST',
714
                                   description='API.INVALID_ENCODING')
715
        except Exception as ex:
716
            print("Unexpected error reading request stream")
717
            raise falcon.HTTPError(status=falcon.HTTP_400,
718
                                   title='API.BAD_REQUEST',
719
                                   description='API.FAILED_TO_READ_REQUEST_STREAM')
720
721
        if not id_.isdigit() or int(id_) <= 0:
722
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
723
                                   description='API.INVALID_COST_CENTER_ID')
724
725
        new_values = json.loads(raw_json)
726
727
        cnx = mysql.connector.connect(**config.myems_system_db)
728
        cursor = cnx.cursor()
729
730
        cursor.execute(" SELECT name "
731
                       " FROM tbl_cost_centers "
732
                       " WHERE id = %s ", (id_,))
733
        if cursor.fetchone() is None:
734
            cursor.close()
735
            cnx.close()
736
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
737
                                   description='API.COST_CENTER_NOT_FOUND')
738
739
        cursor.execute(" SELECT name "
740
                       " FROM tbl_tariffs "
741
                       " WHERE id = %s ", (new_values['data']['tariff_id'],))
742
        if cursor.fetchone() is None:
743
            cursor.close()
744
            cnx.close()
745
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
746
                                   description='API.TARIFF_NOT_FOUND')
747
748
        cursor.execute(" SELECT id "
749
                       " FROM tbl_cost_centers_tariffs "
750
                       " WHERE cost_center_id = %s AND tariff_id = %s ", (id_, new_values['data']['tariff_id']))
751
        rows = cursor.fetchall()
752
        if rows is not None and len(rows) > 0:
753
            cursor.close()
754
            cnx.close()
755
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
756
                                   description='API.TARIFF_IS_ALREADY_ASSOCIATED_WITH_COST_CENTER')
757
758
        add_row = (" INSERT INTO tbl_cost_centers_tariffs "
759
                   "             (cost_center_id, tariff_id) "
760
                   " VALUES (%s, %s) ")
761
        cursor.execute(add_row, (id_, new_values['data']['tariff_id'],))
762
        cnx.commit()
763
764
        cursor.close()
765
        cnx.close()
766
767
        # Clear cache after adding tariff to cost center
768
        clear_costcenter_cache(cost_center_id=id_)
769
770
        resp.status = falcon.HTTP_201
771
        resp.location = '/costcenters/' + str(id_) + '/tariffs/' + str(new_values['data']['tariff_id'])
772
773
774
class CostCenterTariffItem:
775
    def __init__(self):
776
        pass
777
778
    @staticmethod
779
    def on_options(req, resp, id_, tid):
780
        _ = req
781
        resp.status = falcon.HTTP_200
782
        _ = id_
783
784
    @staticmethod
785
    @user_logger
786
    def on_delete(req, resp, id_, tid):
787
        """Handles DELETE requests"""
788
        admin_control(req)
789
        if not id_.isdigit() or int(id_) <= 0:
790
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
791
                                   description='API.INVALID_COST_CENTER_ID')
792
793
        if not tid.isdigit() or int(tid) <= 0:
794
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
795
                                   description='API.INVALID_TARIFF_ID')
796
797
        cnx = mysql.connector.connect(**config.myems_system_db)
798
        cursor = cnx.cursor()
799
800
        cursor.execute(" SELECT name "
801
                       " FROM tbl_cost_centers "
802
                       " WHERE id = %s ", (id_,))
803
        if cursor.fetchone() is None:
804
            cursor.close()
805
            cnx.close()
806
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
807
                                   description='API.COST_CENTER_NOT_FOUND')
808
809
        cursor.execute(" SELECT name "
810
                       " FROM tbl_tariffs "
811
                       " WHERE id = %s ", (tid,))
812
        if cursor.fetchone() is None:
813
            cursor.close()
814
            cnx.close()
815
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
816
                                   description='API.TARIFF_NOT_FOUND')
817
818
        cursor.execute(" SELECT id "
819
                       " FROM tbl_cost_centers_tariffs "
820
                       " WHERE cost_center_id = %s AND tariff_id = %s ", (id_, tid))
821
        if cursor.fetchone() is None:
822
            cursor.close()
823
            cnx.close()
824
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
825
                                   description='API.TARIFF_IS_NOT_ASSOCIATED_WITH_COST_CENTER')
826
827
        cursor.execute(" DELETE FROM tbl_cost_centers_tariffs "
828
                       " WHERE cost_center_id = %s AND tariff_id = %s ", (id_, tid))
829
        cnx.commit()
830
831
        cursor.close()
832
        cnx.close()
833
834
        # Clear cache after removing tariff from cost center
835
        clear_costcenter_cache(cost_center_id=id_)
836
837
        resp.status = falcon.HTTP_204
838