diff --git a/api_events/events/address/address.py b/api_events/events/address/address.py index a6df64b..fadc91e 100644 --- a/api_events/events/address/address.py +++ b/api_events/events/address/address.py @@ -1,3 +1,5 @@ +from typing import Union + from fastapi.exceptions import HTTPException from fastapi.responses import JSONResponse @@ -31,7 +33,11 @@ class AddressListEventMethods(MethodToEvent): } @classmethod - def address_list_super_user(cls, list_options: ListOptions, token_dict): + def address_list_super_user( + cls, + list_options: ListOptions, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): from sqlalchemy import select post_code_list = RelationshipEmployee2PostCode.filter_all( @@ -45,17 +51,29 @@ class AddressListEventMethods(MethodToEvent): detail="User has no post code registered. User can not list addresses.", ) - get_street_ids = AddressPostcode.session.execute( - select(AddressPostcode.street_id).where( - AddressPostcode.id.in_(post_code_id_list) + get_street_ids = [ + street_id[0] + for street_id in AddressPostcode.select_only( + AddressPostcode.id.in_(post_code_id_list), + AddressPostcode.active == True, + select_args=[AddressPostcode.street_id], + order_by=AddressPostcode.street_id.desc(), + ).data + ] + if not get_street_ids: + raise HTTPException( + status_code=404, + detail="User has no street registered. User can not list addresses.", ) - ).all() - Addresses.pre_query = Addresses.filter_active( - Addresses.street_id.in_(*get_street_ids) if get_street_ids else None + + Addresses.pre_query = Addresses.filter_all( + Addresses.street_id.in_(*get_street_ids), + Addresses.active == True, ).query Addresses.filter_attr = list_options - records = Addresses.filter_active( - *Addresses.get_smart_query(list_options.query) + records = Addresses.filter_all( + *Addresses.get_smart_query(list_options.query), + Addresses.active == True, ) return AlchemyJsonResponse( completed=True, @@ -64,7 +82,11 @@ class AddressListEventMethods(MethodToEvent): ) @classmethod - def address_list_employee(cls, list_options: ListOptions, token_dict): + def address_list_employee( + cls, + list_options: ListOptions, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): Addresses.filter_attr = list_options records = Addresses.list_via_employee( token_dict=token_dict, @@ -76,6 +98,7 @@ class AddressListEventMethods(MethodToEvent): result=records, ) + class AddressCreateEventMethods(MethodToEvent): event_type = "CREATE" @@ -84,8 +107,15 @@ class AddressCreateEventMethods(MethodToEvent): } @classmethod - def create_address(cls, data: InsertAddress, token_dict): - post_code = AddressPostcode.find_one(uu_id=data.post_code_uu_id) + def create_address( + cls, + data: InsertAddress, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + post_code = AddressPostcode.filter_one( + AddressPostcode.uu_id==data.post_code_uu_id, + AddressPostcode.active == True, + ).data if not post_code: raise HTTPException( status_code=404, @@ -95,15 +125,14 @@ class AddressCreateEventMethods(MethodToEvent): data_dict = data.excluded_dump() data_dict["street_id"] = post_code.street_id del data_dict["post_code_uu_id"] - + data_dict["is_confirmed"] = True address = Addresses.find_or_create(**data_dict) - if not address.is_found: - RelationshipEmployee2PostCode.find_or_create( - employee_id=token_dict.selected_company.employee_id, - member_id=post_code.id, - company_id=token_dict.selected_company.company_id, - is_confirmed=True, - ) + RelationshipEmployee2PostCode.find_or_create( + employee_id=token_dict.selected_company.employee_id, + member_id=post_code.id, + company_id=token_dict.selected_company.company_id, + is_confirmed=True, + ) Addresses.save() return JSONResponse( content={ @@ -123,7 +152,11 @@ class AddressSearchEventMethods(MethodToEvent): } @classmethod - def search_address(cls, data: SearchAddress, token_dict): + def search_address( + cls, + data: SearchAddress, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): import databases as database_sql_models from time import perf_counter @@ -191,11 +224,16 @@ class AddressUpdateEventMethods(MethodToEvent): } @classmethod - def update_address(cls, address_uu_id: str, data: InsertAddress, token_dict): + def update_address( + cls, + address_uu_id: str, + data: InsertAddress, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): address = Addresses.find_one_or_abort(uu_id=address_uu_id) - post_code = RelationshipEmployee2PostCode.postcode.find_one( - member_id=address.post_code_id - ) + post_code = RelationshipEmployee2PostCode.filter_one( + RelationshipEmployee2PostCode.member_id==address.post_code_id + ).data if not post_code: raise HTTPException( status_code=404, @@ -205,7 +243,7 @@ class AddressUpdateEventMethods(MethodToEvent): data_dict = data.excluded_dump() data_dict["post_code_id"] = post_code.id del data_dict["post_code_uu_id"] - + data_dict["is_confirmed"] = True updated_address = address.update(**data_dict) updated_address.save() return JSONResponse( @@ -226,7 +264,12 @@ class AddressPatchEventMethods(MethodToEvent): } @classmethod - def patch_address(cls, address_uu_id: str, data: InsertAddress, token_dict): + def patch_address( + cls, + address_uu_id: str, + data: InsertAddress, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): address = Addresses.find_one_or_abort(uu_id=address_uu_id) post_code = RelationshipEmployee2PostCode.filter_one( RelationshipEmployee2PostCode.member_id == address.post_code_id @@ -260,9 +303,13 @@ class AddressPostCodeCreateEventMethods(MethodToEvent): } @classmethod - def create_post_code_address(cls, data: InsertPostCode, token_dict): + def create_post_code_address( + cls, + data: InsertPostCode, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): data_dump = data.excluded_dump() - street = AddressStreet.find_one(uu_id=data.street_uu_id) + street = AddressStreet.filter_one(AddressStreet.uu_id==data.street_uu_id).data if not street: raise HTTPException( status_code=404, @@ -273,13 +320,12 @@ class AddressPostCodeCreateEventMethods(MethodToEvent): del data_dump["street_uu_id"], data_dump["post_code"] post_code = AddressPostcode.find_or_create(**data_dump) - if not post_code.is_found: - AddressPostcode.__many__table__.find_or_create( - member_id=post_code.id, - employee_id=token_dict.selected_company.employee_id, - company_id=token_dict.selected_company.company_id, - is_confirmed=True, - ) + AddressPostcode.__many__table__.find_or_create( + member_id=post_code.id, + employee_id=token_dict.selected_company.employee_id, + company_id=token_dict.selected_company.company_id, + is_confirmed=True, + ) AddressStreet.save() return JSONResponse( content={ @@ -300,10 +346,13 @@ class AddressPostCodeUpdateEventMethods(MethodToEvent): @classmethod def update_post_code_address( - cls, post_code_uu_id: str, data: InsertPostCode, token_dict + cls, + post_code_uu_id: str, + data: InsertPostCode, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], ): - post_code = AddressPostcode.find_one_or_abort(uu_id=post_code_uu_id) - street = AddressStreet.find_one(uu_id=data.street_uu_id) + post_code = AddressPostcode.filter_one(AddressPostcode.uu_id==post_code_uu_id).data + street = AddressStreet.filter_one(AddressPostcode.uu_id==data.street_uu_id).data if not street: raise HTTPException( status_code=404, @@ -330,8 +379,12 @@ class AddressPostCodeListEventMethods(MethodToEvent): } @classmethod - def list_post_code_address(cls, list_options: ListOptions, token_dict): - post_code_list = AddressPostcode.__many__table__.filter_active( + def list_post_code_address( + cls, + list_options: ListOptions, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + post_code_list = AddressPostcode.__many__table__.filter_all( AddressPostcode.__many__table__.company_id == token_dict.selected_company.company_id ).data @@ -341,13 +394,14 @@ class AddressPostCodeListEventMethods(MethodToEvent): detail="User has no post code registered or not yet any post code created.", ) - AddressPostcode.pre_query = AddressPostcode.filter_active( + AddressPostcode.pre_query = AddressPostcode.filter_all( AddressPostcode.id.in_( [post_code.member_id for post_code in post_code_list] - ) + ), + AddressPostcode.active == True, ).query AddressPostcode.filter_attr = list_options - records = AddressPostcode.filter_active( + records = AddressPostcode.filter_all( *Addresses.get_smart_query(list_options.query) ) return AlchemyJsonResponse( diff --git a/api_events/events/application/authentication.py b/api_events/events/application/authentication.py index c481f2d..2e7dfa9 100644 --- a/api_events/events/application/authentication.py +++ b/api_events/events/application/authentication.py @@ -37,7 +37,7 @@ from api_services import ( from api_events.events.abstract_class import MethodToEvent, ActionsSchema from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject -from api_library.date_time_actions.date_functions import DateTimeLocal +from api_library.date_time_actions.date_functions import DateTimeLocal, system_arrow from api_configs import ApiStatic, Auth from databases.no_sql_models.login_handlers import load_user_with_erp_details @@ -51,6 +51,7 @@ from api_validations.validations_request import ( OccupantSelection, EmployeeSelection, ) +from databases.sql_models.building.build import RelationshipEmployee2Build class AuthenticationLoginEventMethods(MethodToEvent): @@ -98,8 +99,8 @@ class AuthenticationSelectEventMethods(MethodToEvent): def authentication_select_company_or_occupant_type( cls, request: Request, - data: typing.Union[EmployeeSelection, OccupantSelection], - token_dict: dict = None, + data, + token_dict: typing.Union[EmployeeSelection, OccupantSelection], ): from api_objects import OccupantToken, CompanyToken @@ -116,38 +117,39 @@ class AuthenticationSelectEventMethods(MethodToEvent): if selected_company := Companies.find_one(uu_id=data.company_uu_id): department_ids = [ department.id - for department in Departments.filter_by_active( - company_id=selected_company.id + for department in Departments.filter_all( + Departments.company_id==selected_company.id ).data ] duties_ids = [ duties.id - for duties in Duties.filter_active( + for duties in Duties.filter_all( Duties.company_id == selected_company.id, Duties.department_id.in_(department_ids), ).data ] staff_ids = [ staff.id - for staff in Staff.filter_active( + for staff in Staff.filter_all( Staff.duties_id.in_(duties_ids) ).data ] - employee = Employees.filter_active( + employee = Employees.filter_one( Employees.people_id == token_user.person_id, Employees.staff_id.in_(staff_ids), - ).data[0] + ).data reachable_event_list_id, reachable_event_list_uu_id = ( Event2Employee.get_event_id_by_employee_id(employee_id=employee.id) ) - staff = Staff.find_one(id=employee.staff_id) - duties = Duties.find_one(id=staff.duties_id) - department = Departments.find_one(id=duties.department_id) - bulk_id = Duty.find_one(duty_code="BULK") - bulk_duty_id = Duties.find_one( - company_id=selected_company.id, duties_id=bulk_id.id - ) + staff = Staff.filter_one(Staff.id==employee.staff_id).data + duties = Duties.find_one(Duties.id==staff.duties_id).data + department = Departments.find_one(Departments.id==duties.department_id).data + bulk_id = Duty.filter_one(Duty.duty_code=="BULK").data + bulk_duty_id = Duties.filter_one( + Duties.company_id==selected_company.id, + Duties.duties_id==bulk_id.id + ).data update_selected_to_redis( request=request, add_payload=CompanyToken( @@ -174,30 +176,36 @@ class AuthenticationSelectEventMethods(MethodToEvent): status_code=status.HTTP_200_OK, ) elif token_user.user_type == 2: - occupant_type = OccupantTypes.find_one(uu_id=data.occupant_uu_id) + occupant_type = OccupantTypes.filter_one(OccupantTypes.uu_id==data.occupant_uu_id).data if not occupant_type: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Occupant Type is not found", ) - build_part = BuildParts.find_one(uu_id=data.build_part_uu_id) + build_part = BuildParts.filter_one(BuildParts.uu_id==data.build_part_uu_id).data if not build_part: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Build Part is not found", ) - build = Build.find_one(id=build_part.build_id) - related_company = RelationshipEmployee2Build.find_one(member_id=build.id) - company_related = Companies.find_one(id=related_company.company_id) - responsible_employee = Employees.find_one(id=related_company.employee_id) - if selected_occupant_type := BuildLivingSpace.find_one( - occupant_type=occupant_type.id, - person_id=token_user.person_id, - build_parts_id=build_part.id, - ): + build = Build.filter_one(Build.id==build_part.build_id).data + related_company = RelationshipEmployee2Build.filter_one( + RelationshipEmployee2Build.member_id==build.id + ).data + company_related = Companies.filter_one( + Companies.id==related_company.company_id + ).data + responsible_employee = Employees.filter_one( + Employees.id==related_company.employee_id + ).data + if selected_occupant_type := BuildLivingSpace.filter_one( + BuildLivingSpace.occupant_type==occupant_type.id, + BuildLivingSpace.person_id==token_user.person_id, + BuildLivingSpace.build_parts_id==build_part.id, + ).data: reachable_event_list_id, reachable_event_list_uu_id = ( Event2Occupant.get_event_id_by_build_living_space_id( - build_living_space_id=selected_occupant_type.id + Event2Occupant.build_living_space_id==selected_occupant_type.id ) ) update_selected_to_redis( @@ -242,7 +250,7 @@ class AuthenticationCheckTokenEventMethods(MethodToEvent): @classmethod def authentication_login_with_domain_and_creds( - cls, request, token_dict: dict = None + cls, request, token_dict: typing.Union[EmployeeSelection, OccupantSelection], ): if get_object_via_access_key(request=request): return JSONResponse( @@ -263,15 +271,17 @@ class AuthenticationRefreshEventMethods(MethodToEvent): } @classmethod - def authentication_refresh_user_info(cls, request, token_dict: dict = None): + def authentication_refresh_user_info( + cls, request, token_dict: typing.Union[EmployeeSelection, OccupantSelection], + ): access_token = str(request.headers.get(Auth.ACCESS_TOKEN_TAG)) if token_user := get_object_via_access_key(request=request): - if found_user := Users.find_one(uu_id=token_user.get("uu_id")): - user_token = UsersTokens.find_one( - domain=found_user.domain_name, - user_id=found_user.id, - token_type="RememberMe", - ) + if found_user := Users.filter_one(Users.uu_id==token_user.get("uu_id")).data: + user_token = UsersTokens.filter_one( + UsersTokens.domain==found_user.domain_name, + UsersTokens.user_id==found_user.id, + UsersTokens.token_type=="RememberMe", + ).data access_dict = { "access_token": access_token, "refresh_token": getattr(user_token, "token", None), @@ -299,11 +309,11 @@ class AuthenticationChangePasswordEventMethods(MethodToEvent): @classmethod def authentication_change_password( - cls, request, data: ChangePassword, token_dict: dict = None + cls, request, data: ChangePassword, token_dict: typing.Union[EmployeeSelection, OccupantSelection], ): token_user = get_object_via_access_key(request=request) if token_user.user_type == 1: - if found_user := Users.find_one(uu_id=token_user.uu_id): + if found_user := Users.filter_one(Users.uu_id==token_user.uu_id).data: if found_user.check_password(data.old_password): found_user.set_password(data.new_password) return JSONResponse( @@ -342,10 +352,12 @@ class AuthenticationCreatePasswordEventMethods(MethodToEvent): raise HTTPException( status_code=status.HTTP_406_NOT_ACCEPTABLE, detail="Password must match" ) - if found_user := Users.find_one(password_token=data.password_token): + if found_user := Users.filter_one( + Users.password_token==data.password_token + ).data: found_user.create_password(password=data.password) found_user.password_token = None - found_user.save() + Users.save() send_email_completed = send_email( subject=f"Dear {found_user.user_tag}, your password has been changed.", receivers=[str(found_user.email)], @@ -386,7 +398,9 @@ class AuthenticationDisconnectUserEventMethods(MethodToEvent): ): if token_user := get_object_via_access_key(request=request): - found_user = Users.find_one(uu_id=token_user.get("uu_id")) + found_user = Users.filter_one( + Users.uu_id==token_user.get("uu_id") + ).data if not found_user: return JSONResponse( content={ @@ -400,7 +414,9 @@ class AuthenticationDisconnectUserEventMethods(MethodToEvent): for key in already_tokens: token_user = json.loads(redis_cli.get(key) or {}) redis_cli.delete(key) - selected_user = Users.find_one(uu_id=token_user.get("uu_id")) + selected_user = Users.filter_one( + Users.uu_id==token_user.get("uu_id") + ).data selected_user.remove_refresher_token( domain=data.domain, disconnect=True ) @@ -449,7 +465,9 @@ class AuthenticationLogoutEventMethods(MethodToEvent): token_user = json.loads(redis_cli.get(key) or {}) if token_user.get("domain") == data.domain: redis_cli.delete(key) - selected_user = Users.find_one(uu_id=token_user.get("uu_id")) + selected_user = Users.filter_one( + Users.uu_id==token_user.get("uu_id") + ).data selected_user.remove_refresher_token(domain=data.domain) # UserLogger.log_error( # str( @@ -503,7 +521,9 @@ class AuthenticationRefreshTokenEventMethods(MethodToEvent): content={"completed": False, "message": "Invalid data", "data": {}}, status_code=status.HTTP_202_ACCEPTED, ) - if found_user := Users.find_one(id=token_refresher.user_id): + if found_user := Users.filter_one( + Users.id==token_refresher.user_id + ).data: found_user: Users = found_user access_key = save_access_token_to_redis( request=request, found_user=found_user, domain=data.domain @@ -513,7 +533,7 @@ class AuthenticationRefreshTokenEventMethods(MethodToEvent): found_user.last_remote_addr = getattr( request, "remote_addr", None ) or request.headers.get("X-Forwarded-For", None) - found_user.last_seen = str(DateTimeLocal.now()) + found_user.last_seen = str(system_arrow.now()) # UserLogger.log_error( # str( # dict( @@ -595,7 +615,7 @@ class AuthenticationForgotPasswordEventMethods(MethodToEvent): ) found_user.password_token = forgot_key - found_user.password_token_is_valid = str(DateTimeLocal.shift(days=1)) + found_user.password_token_is_valid = str(system_arrow.shift(days=1)) found_user.save() return JSONResponse( @@ -632,13 +652,13 @@ class AuthenticationDownloadAvatarEventMethods(MethodToEvent): "remember_me": found_user.remember_me, "expiry_ends": str(found_user.expiry_ends), "expired_str": str( - DateTimeLocal.now() - - DateTimeLocal.get(str(found_user.expiry_ends)) + system_arrow.now() + - system_arrow.get(str(found_user.expiry_ends)) ), "expired_int": int( ( - DateTimeLocal.now() - - DateTimeLocal.get(str(found_user.expiry_ends)) + system_arrow.now() + - system_arrow.get(str(found_user.expiry_ends)) ).days ), }, diff --git a/api_events/events/building/building_build.py b/api_events/events/building/building_build.py index 47a7157..b5ea9b7 100644 --- a/api_events/events/building/building_build.py +++ b/api_events/events/building/building_build.py @@ -39,16 +39,18 @@ class BuildListEventMethods(MethodToEvent): token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], ): if isinstance(token_dict, OccupantTokenObject): - Build.pre_query = Build.filter_active( - Build.id == token_dict.selected_occupant.build_id + Build.pre_query = Build.filter_all( + Build.id == token_dict.selected_occupant.build_id, + Build.active == True, ).query elif isinstance(token_dict, EmployeeTokenObject): Build.pre_query = Build.select_action( employee_id=token_dict.selected_company.employee_id ) Build.filter_attr = list_options - records = Build.filter_active( - *Build.get_smart_query(smart_query=list_options.query) + records = Build.filter_all( + *Build.get_smart_query(smart_query=list_options.query), + Build.active == True, ) return AlchemyJsonResponse( completed=True, @@ -81,13 +83,13 @@ class BuildCreateEventMethods(MethodToEvent): created_build = Build.create_action(data=data, token=token_dict) if not created_build.is_found: - build_type = BuildTypes.find_one(type_code="APT_YNT") + build_type = BuildTypes.filter_by_one(type_code="APT_YNT").data if not build_type: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Build type APT_YNT is not found. Please contact with your system administrator.", ) - api_enum = ApiEnumDropdown.find_one(enum_class="Directions", key="NN") + api_enum = ApiEnumDropdown.filter_by_one(enum_class="Directions", key="NN").data if not api_enum: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, @@ -107,8 +109,8 @@ class BuildCreateEventMethods(MethodToEvent): is_confirmed=True, ) man_build_part = BuildParts.find_or_create(**build_parts) - if not man_build_part.is_found: - created_build.update(management_room_id=man_build_part.id) + created_build.update(management_room_id=man_build_part.id) + BuildParts.save() return JSONResponse( content={ "completed": True, @@ -148,24 +150,19 @@ class BuildCreateEventMethods(MethodToEvent): ) created_build = Build.create_action(data=data, token=token_dict) - if not created_build.is_found: - RelationshipEmployee2Build.find_or_create( - company_id=token_dict.selected_company.company_id, - member_id=created_build.id, - employee_id=token_dict.selected_company.employee_id, - is_confirmed=True, - ) - return JSONResponse( - content={ - "completed": True, - "message": "Create Build record completed. This build is assigned to you.", - "data": created_build.get_dict(), - }, - status_code=status.HTTP_200_OK, - ) - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail=f"Build record create not successful for {token_dict.selected_company.employee_uu_id}", + RelationshipEmployee2Build.find_or_create( + company_id=token_dict.selected_company.company_id, + member_id=created_build.id, + employee_id=token_dict.selected_company.employee_id, + is_confirmed=True, + ) + return JSONResponse( + content={ + "completed": True, + "message": "Create Build record completed. This build is assigned to you.", + "data": created_build.get_dict(), + }, + status_code=status.HTTP_200_OK, ) @@ -181,10 +178,12 @@ class BuildUpdateEventMethods(MethodToEvent): Build.pre_query = Build.select_action( employee_id=token_dict.selected_company.employee_id ) - if Build.filter_active(Build.person_id == token_dict.person_id): + if Build.filter_all(Build.person_id == token_dict.person_id): + Build.pre_query = None if updated_build := Build.update_action( data=data, token=token_dict, build_uu_id=build_uu_id ): + Build.save() return JSONResponse( content={ "completed": True, diff --git a/api_events/events/building/building_build_parts.py b/api_events/events/building/building_build_parts.py index 1a18118..230b0a1 100644 --- a/api_events/events/building/building_build_parts.py +++ b/api_events/events/building/building_build_parts.py @@ -1,3 +1,5 @@ +from typing import Union + from fastapi.responses import JSONResponse from fastapi import status @@ -23,7 +25,9 @@ class BuildingBuildPartsListEventMethods(MethodToEvent): } @classmethod - def building_build_parts_list(cls, list_options: ListOptions, token_dict): + def building_build_parts_list( + cls, list_options: ListOptions, token_dict: Union[EmployeeTokenObject, OccupantTokenObject] + ): build_list_query = Build.select_action( employee_id=token_dict.selected_company.employee_id, ) @@ -49,7 +53,9 @@ class BuildingBuildPartsCreateEventMethods(MethodToEvent): } @classmethod - def building_build_parts_create(cls, data: InsertBuildParts, token_dict: dict): + def building_build_parts_create( + cls, data: InsertBuildParts, token_dict: Union[EmployeeTokenObject, OccupantTokenObject] + ): created_build = BuildParts.create_action(data=data, token=token_dict) if not created_build: return JSONResponse( @@ -79,7 +85,9 @@ class BuildingBuildPartsUpdateEventMethods(MethodToEvent): } @classmethod - def building_build_parts_update(cls, data: InsertBuildParts, token_dict: dict): + def building_build_parts_update( + cls, data: InsertBuildParts, token_dict: Union[EmployeeTokenObject, OccupantTokenObject] + ): if updated_build := BuildParts.update_action(data=data, token=token_dict): updated_build.save() return JSONResponse( @@ -109,7 +117,7 @@ class BuildingBuildPartsPatchEventMethods(MethodToEvent): @classmethod def building_build_parts_patch(cls, data, token_dict): - find_one_build = BuildParts.find_one(uu_id=data.uu_id) + find_one_build = BuildParts.filter_one(BuildParts.uu_id==data.uu_id).data access_authorized_build = BuildParts.select_action( duty_id=token_dict.selected_company.duty_id, filter_expr=[BuildParts.id == find_one_build.id], diff --git a/api_events/events/building/building_living_spaces.py b/api_events/events/building/building_living_spaces.py index 7944699..7c03042 100644 --- a/api_events/events/building/building_living_spaces.py +++ b/api_events/events/building/building_living_spaces.py @@ -35,17 +35,19 @@ class BuildingLivingSpacesPartsListEventMethods(MethodToEvent): employee_id=token_dict.selected_company.employee_id ) Build.filter_attr = list_options - build_part_id_list_query = BuildParts.filter_active( + build_part_id_list_query = BuildParts.filter_all( BuildParts.build_id.in_([build.id for build in build_id_list_query.all()]), - ) + BuildParts.active == True, + ).data list_options.query.pop("expiry_starts", None) list_options.query.pop("expiry_ends", None) - records = BuildLivingSpace.filter_active( + records = BuildLivingSpace.filter_all( BuildLivingSpace.build_parts_id.in_( - [build_part.id for build_part in build_part_id_list_query.data] + [build_part.id for build_part in build_part_id_list_query] ), + BuildLivingSpace.active == True, *BuildLivingSpace.get_smart_query(smart_query=list_options.query), ) return AlchemyJsonResponse( @@ -62,17 +64,17 @@ class BuildingLivingSpacesPartsListEventMethods(MethodToEvent): employee_id=token_dict.selected_company.employee_id ) Build.filter_attr = list_options - build_part_id_list_query = BuildParts.filter_active( + build_part_id_list_query = BuildParts.filter_all( BuildParts.build_id.in_([build.id for build in build_id_list_query.all()]), - ) + BuildParts.active == True, + ).data - records = BuildLivingSpace.filter_active( + records = BuildLivingSpace.filter_all( BuildLivingSpace.build_parts_id.in_( - [build_part.id for build_part in build_part_id_list_query.data] + [build_part.id for build_part in build_part_id_list_query] ), *BuildLivingSpace.get_smart_query(smart_query=list_options.query), - expired=False, - ) + ).data return AlchemyJsonResponse( completed=True, message="Building Living Spaces are listed successfully", @@ -103,15 +105,14 @@ class BuildingLivingSpacesPartsCreateEventMethods(MethodToEvent): build_part = BuildParts.filter_one( BuildParts.uu_id == data.build_parts_uu_id, BuildParts.build_id.in_([build.id for build in build_id_list_query.all()]), - ) - if not build_part.data: + ).data + if not build_part: raise HTTPException( status_code=status.HTTP_418_IM_A_TEAPOT, detail=f"{data.build_parts_uu_id} - Build Part is not found in database. Check build part uu_id", ) - build_part = build_part.data - life_person = People.find_one(uu_id=data.person_uu_id or "") + life_person = People.filter_one(People.uu_id==data.person_uu_id or "").data if not life_person: raise HTTPException( status_code=status.HTTP_418_IM_A_TEAPOT, @@ -119,7 +120,7 @@ class BuildingLivingSpacesPartsCreateEventMethods(MethodToEvent): f"Check build live person uu_id", ) - occupant_type = OccupantTypes.find_one(uu_id=data.occupant_type_uu_id) + occupant_type = OccupantTypes.filter_by_one(uu_id=data.occupant_type_uu_id).data if not occupant_type: raise HTTPException( status_code=status.HTTP_418_IM_A_TEAPOT, @@ -134,21 +135,18 @@ class BuildingLivingSpacesPartsCreateEventMethods(MethodToEvent): data_dict["person_id"] = life_person.id data_dict["person_uu_id"] = str(life_person.uu_id) - living_space_id = BuildLivingSpace.session.execute( - select(BuildLivingSpace.id) - .where( - *[ - BuildLivingSpace.build_parts_id == build_part.id, - BuildLivingSpace.person_id == life_person.id, - BuildLivingSpace.occupant_type == occupant_type.id, - BuildLivingSpace.active == True, - BuildLivingSpace.is_confirmed == True, - str(system_arrow.now()) < BuildLivingSpace.expiry_ends, - str(system_arrow.now()) >= BuildLivingSpace.expiry_starts, - ] - ) - .order_by(BuildLivingSpace.expiry_starts.desc()) - ).first() + living_space_id = BuildLivingSpace.select_only( + BuildLivingSpace.build_parts_id == build_part.id, + BuildLivingSpace.person_id == life_person.id, + BuildLivingSpace.occupant_type == occupant_type.id, + BuildLivingSpace.active == True, + BuildLivingSpace.is_confirmed == True, + str(system_arrow.now()) < BuildLivingSpace.expiry_ends, + str(system_arrow.now()) >= BuildLivingSpace.expiry_starts, + select_args=[BuildLivingSpace.id], + order_by=BuildLivingSpace.expiry_starts.desc(), + limit=1 + ).data last_living_space = BuildLivingSpace.filter_one( BuildLivingSpace.id == living_space_id[0] if living_space_id else None @@ -160,11 +158,11 @@ class BuildingLivingSpacesPartsCreateEventMethods(MethodToEvent): ) if last_living_space: - if last_living_space.expiry_ends > system_arrow.now(): + if last_living_space.expiry_ends > str(system_arrow.now()): last_living_space.expiry_ends = str(system_arrow.shift(minutes=-10)) last_living_space.save() - user_module = Modules.filter_one(Modules.module_code == "USR-PUB") + user_module = Modules.filter_one(Modules.module_code == "USR-PUB", system=True).data ModulesBindOccupantEventMethods.modules_bind_occupant_system( build_living_space_id=created_living_space.id, modules_id=user_module.id, @@ -189,18 +187,18 @@ class BuildingLivingSpacesPartsUpdateEventMethods(MethodToEvent): build_id_list_query = Build.select_action( employee_id=token_dict.selected_company.employee_id ) - build_part = BuildParts.filter_active( + build_part = BuildParts.filter_one( BuildParts.uu_id == data.build_parts_uu_id, BuildParts.build_id.in_([build.id for build in build_id_list_query.all()]), - ) - if not build_part.get(1): + BuildParts.active == True, + ).data + if not build_part: raise HTTPException( status_code=status.HTTP_418_IM_A_TEAPOT, detail=f"{data.build_parts_uu_id} - Build Part is not found in database. Check build part uu_id", ) - build_part = build_part.get(1) - life_person = People.find_one(uu_id=data.life_person_uu_id or "") + life_person = People.filter_one(People.uu_id==data.life_person_uu_id or "").data if not life_person: raise HTTPException( status_code=status.HTTP_418_IM_A_TEAPOT, @@ -208,15 +206,15 @@ class BuildingLivingSpacesPartsUpdateEventMethods(MethodToEvent): f"Check build live person uu_id", ) - living_spaces = select(BuildLivingSpace.id).order_by( - BuildLivingSpace.expiry_starts.desc() - ) - living_space_id = BuildLivingSpace.session.execute(living_spaces).first() + living_space_id = BuildLivingSpace.select_only( + select_args=[BuildLivingSpace.id], + order_by=BuildLivingSpace.expiry_starts.desc(), + limit=1 + ).get(1) + last_living_space = BuildLivingSpace.filter_one( - BuildLivingSpace.id == getattr(living_space_id[0], "id", None) - if living_space_id - else None - ) + BuildLivingSpace.id == living_space_id if living_space_id else None + ).data data_dict["expiry_starts"] = str(system_arrow.now()) data_dict["is_tenant_live"] = bool(data.is_tenant_live) diff --git a/api_events/events/decision_book/decision_book_decision_book.py b/api_events/events/decision_book/decision_book_decision_book.py index d183740..c2086be 100644 --- a/api_events/events/decision_book/decision_book_decision_book.py +++ b/api_events/events/decision_book/decision_book_decision_book.py @@ -18,7 +18,7 @@ from api_validations.validations_request import ( from api_events.events.abstract_class import MethodToEvent, ActionsSchema from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject from api_validations.core_response import AlchemyJsonResponse -from api_library.date_time_actions.date_functions import DateTimeLocal +from api_library.date_time_actions.date_functions import DateTimeLocal, system_arrow class DecisionBookListEventMethods(MethodToEvent): @@ -46,15 +46,17 @@ class DecisionBookListEventMethods(MethodToEvent): status_code=status.HTTP_404_NOT_FOUND, detail=f"No building is match with given Employee UUID {token_dict.selected_company.employee_uu_id}", ) - records = BuildDecisionBook.filter_active( + records = BuildDecisionBook.filter_all( BuildDecisionBook.build_id.in_([build.id for build in build_id_list]), *BuildDecisionBook.get_smart_query(list_options.query), - ) + BuildDecisionBook.active == True, + ).data elif isinstance(token_dict, OccupantTokenObject): - records = BuildDecisionBook.filter_active( + records = BuildDecisionBook.filter_all( BuildDecisionBook.build_id == token_dict.selected_occupant.build_id, *BuildDecisionBook.get_smart_query(list_options.query), - ) + BuildDecisionBook.active == True, + ).data return AlchemyJsonResponse( completed=True, message="DecisionBook are listed successfully", @@ -80,15 +82,16 @@ class DecisionBookCreateEventMethods(MethodToEvent): Build.pre_query = Build.select_action( employee_id=token_dict.selected_company.employee_id ) - build = Build.filter_active( + build = Build.filter_one( Build.uu_id == data.build_uu_id, - ) - if not build.data: + Build.active == True, + ).get(1) + if not build: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Emloyee UUID {token_dict.selected_company.employee_uu_id} has no build with given UUID {data_dict.get('build_uu_id')}", ) - data_dict["build_id"] = build.data[0].id + data_dict["build_id"] = build.id if data.resp_company_uu_id: Companies.pre_query = Companies.select_action( duty_id_list=[ @@ -96,21 +99,22 @@ class DecisionBookCreateEventMethods(MethodToEvent): token_dict.selected_company.bulk_duties_id, ] ) - company = Companies.filter_active( - Companies.uu_id == data.resp_company_uu_id - ) - if not company.data: + company = Companies.filter_one( + Companies.uu_id == data.resp_company_uu_id, + Companies.active == True, + ).get(1) + if not company: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Duty UUID {token_dict.selected_company.duty_uu_id} has no company with given UUID {data_dict.get('resp_company_uu_id')}", ) - data_dict["resp_company_id"] = company.data[0].id - data_dict["resp_company_uu_id"] = str(company.data[0].uu_id) + data_dict["resp_company_id"] = company.id + data_dict["resp_company_uu_id"] = str(company.uu_id) - build_object = build.data[0] - decision_period_date = DateTimeLocal.get(build_object.decision_period_date) + + decision_period_date = DateTimeLocal.get(build.decision_period_date) data_dict["expiry_starts"] = DateTimeLocal.get( - DateTimeLocal.now().date().year, + system_arrow.now().date().year, int(decision_period_date.date().month), int(decision_period_date.date().day), ) @@ -138,20 +142,24 @@ class DecisionBookCreateEventMethods(MethodToEvent): detail="Only Build Manager can create decision book", ) - occupant_build = Build.find_one(id=token_dict.selected_occupant.build_id) + occupant_build = Build.filter_one( + Build.id==token_dict.selected_occupant.build_id, + Build.active == True, + ).get(1) occupant_company = Companies.find_one( - id=token_dict.selected_occupant.responsible_company_id - ) + Companies.id==token_dict.selected_occupant.responsible_company_id, + Companies.active == True, + ).get(1) data_dict["build_id"] = occupant_build.id data_dict["build_uu_id"] = str(occupant_build.uu_id) data_dict["resp_company_id"] = occupant_company.id data_dict["resp_company_uu_id"] = str(occupant_company.uu_id) - decision_period_date = DateTimeLocal.get( + decision_period_date = system_arrow.get( occupant_build.decision_period_date ) data_dict["expiry_starts"] = DateTimeLocal.get( - DateTimeLocal.now().date().year, + system_arrow.now().date().year, int(decision_period_date.date().month), int(decision_period_date.date().day), ) diff --git a/api_events/events/decision_book/decision_book_decision_book_items.py b/api_events/events/decision_book/decision_book_decision_book_items.py index 33d5b9d..78d0ab2 100644 --- a/api_events/events/decision_book/decision_book_decision_book_items.py +++ b/api_events/events/decision_book/decision_book_decision_book_items.py @@ -75,7 +75,9 @@ class DecisionBookDecisionBookItemsListEventMethods(MethodToEvent): status_code=status.HTTP_404_NOT_FOUND, detail=f"No company is match with given Employee UUID {token_dict.selected_company.employee_uu_id}", ) - BuildDecisionBookItems.filter_attr = BuildDecisionBookItems.FilterModel(**data.dump()) + BuildDecisionBookItems.filter_attr = BuildDecisionBookItems.FilterModel( + **data.dump() + ) records = BuildDecisionBookItems.filter_active( BuildDecisionBookItems.build_decision_book_id == decision_book.id ) diff --git a/api_events/events/decision_book/decision_book_decision_book_items_debits.py b/api_events/events/decision_book/decision_book_decision_book_items_debits.py index 96ca46f..5d849fd 100644 --- a/api_events/events/decision_book/decision_book_decision_book_items_debits.py +++ b/api_events/events/decision_book/decision_book_decision_book_items_debits.py @@ -5,7 +5,6 @@ from databases import ( BuildParts, BuildDecisionBook, BuildDecisionBookItems, - BuildDecisionBookPerson, BuildDecisionBookPayments, BuildDecisionBookProjects, @@ -21,6 +20,7 @@ from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObj from api_validations.core_response import AlchemyJsonResponse from api_library.date_time_actions.date_functions import system_arrow, client_arrow + class DecisionBookDecisionBookItemsDebitsListEventMethods(MethodToEvent): event_type = "SELECT" @@ -47,6 +47,7 @@ class DecisionBookDecisionBookItemsDebitsListEventMethods(MethodToEvent): result=records, ) + class DecisionBookDecisionBookItemsDebitsCreateEventMethods(MethodToEvent): event_type = "CREATE" @@ -100,4 +101,3 @@ class DecisionBookDecisionBookItemsDebitsCreateEventMethods(MethodToEvent): message="Decision Book Items Debits are listed", result=records, ) - diff --git a/api_events/events/decision_book/decision_book_decision_book_person.py b/api_events/events/decision_book/decision_book_decision_book_person.py index 06c49c7..45e5432 100644 --- a/api_events/events/decision_book/decision_book_decision_book_person.py +++ b/api_events/events/decision_book/decision_book_decision_book_person.py @@ -69,9 +69,9 @@ class DecisionBookPersonAddEventMethods(MethodToEvent): status_code=status.HTTP_404_NOT_FOUND, detail=f"No Decision Book is match with given UUID {data.build_decision_book_uu_id}", ) - manager_occupant_type = OccupantTypes.find_or_abort( + manager_occupant_type = OccupantTypes.filter_by_one( occupant_code="BU-MNG", occupant_category_type="BU" - ) + ).get(1) if ( not manager_occupant_type.uu_id == token_dict.selected_occupant.occupant_type_uu_id @@ -81,42 +81,42 @@ class DecisionBookPersonAddEventMethods(MethodToEvent): detail="Only Build Manager can update the invitation", ) - assign_occupant_type = OccupantTypes.find_or_abort( + assign_occupant_type = OccupantTypes.filter_by_one( uu_id=data.occupant_type_uu_id, occupant_category_type="MT", - ) + ).get(1) if not assign_occupant_type: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Occupant type must be a Meeting Type {data.occupant_type_uu_id} is not a MT type occupant", ) - manger_book_person = BuildDecisionBookPerson.find_one( - token=data.token, - build_decision_book_uu_id=data.build_decision_book_uu_id, - is_confirmed=True, - active=True, - ) + manger_book_person = BuildDecisionBookPerson.filter_one( + BuildDecisionBookPerson.token==data.token, + BuildDecisionBookPerson.build_decision_book_uu_id==data.build_decision_book_uu_id, + BuildDecisionBookPerson.is_confirmed==True, + BuildDecisionBookPerson.active==True, + ).get(1) if not manger_book_person: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Manager person not found. Please check token", ) - book_invite = BuildDecisionBookInvitations.find_one( - id=manger_book_person.invite_id, - build_id=token_dict.selected_occupant.build_id, - ) + book_invite = BuildDecisionBookInvitations.filter_one( + BuildDecisionBookInvitations.id==manger_book_person.invite_id, + BuildDecisionBookInvitations.build_id==token_dict.selected_occupant.build_id, + ).get(1) if not book_invite: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Invitation not found. Please check token", ) - selected_book_person = BuildDecisionBookPerson.find_one( - invite_id=book_invite.id, - person_uu_id=data.person_uu_id, - is_confirmed=True, - active=True, - ) + selected_book_person = BuildDecisionBookPerson.filter_one( + BuildDecisionBookPerson.invite_id==book_invite.id, + BuildDecisionBookPerson.person_uu_id==data.person_uu_id, + BuildDecisionBookPerson.is_confirmed==True, + BuildDecisionBookPerson.active==True, + ).get(1) if not selected_book_person: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, @@ -171,10 +171,12 @@ class DecisionBookPersonAttendEventMethods(MethodToEvent): detail="Employee cannot create decision book invitations", ) - token_user = Users.find_one(id=token_dict.user_id) - invitation_person = BuildDecisionBookPerson.find_one( - token=data.token, active=True, is_confirmed=True - ) + token_user = Users.filter_one(Users.id==token_dict.user_id).get(1) + invitation_person = BuildDecisionBookPerson.filter_one( + BuildDecisionBookPerson.token==data.token, + BuildDecisionBookPerson.active==True, + BuildDecisionBookPerson.is_confirmed==True + ).get(1) if not invitation_person: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, @@ -189,10 +191,11 @@ class DecisionBookPersonAttendEventMethods(MethodToEvent): # detail=f"Invitation for the user {token_user.email} is not valid. Please check token", # ) # todo check if vicarious person is valid - invitation = BuildDecisionBookInvitations.find_one( - id=invitation_person.invite_id, - build_id=token_dict.selected_occupant.build_id, - ) + invitation = BuildDecisionBookInvitations.filter_one( + BuildDecisionBookInvitations.id==invitation_person.invite_id, + BuildDecisionBookInvitations.build_id==token_dict.selected_occupant.build_id, + BuildDecisionBookInvitations.active==True, + ).get(1) if not invitation: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, @@ -236,66 +239,60 @@ class DecisionBookPersonAssignOccupantEventMethods(MethodToEvent): detail="Employee cannot create decision book invitations", ) - book_person_manager = BuildDecisionBookPerson.find_one( - token=data.token, - build_living_space_id=token_dict.selected_occupant.living_space_id, - active=True, - is_confirmed=True, - ) - manager_occupant_type = OccupantTypes.find_or_abort( + book_person_manager = BuildDecisionBookPerson.filter_one( + BuildDecisionBookPerson.token==data.token, + BuildDecisionBookPerson.build_living_space_id==token_dict.selected_occupant.living_space_id, + BuildDecisionBookPerson.active==True, + BuildDecisionBookPerson.is_confirmed==True, + ).get(1) + manager_occupant_type = OccupantTypes.filter_by_one( occupant_code="BU-MNG", occupant_category_type="BU" - ) + ).get(1) book_person_manager.check_occupant_type(manager_occupant_type) # supervisor_occupant_type = OccupantTypes.find_or_abort(occupant_code="BU-SPV", occupant_category_type="BU") # book_person_supervisor.check_occupant_type(supervisor_occupant_type) - invitation = BuildDecisionBookInvitations.find_one( - id=book_person_manager.invite_id, - build_id=token_dict.selected_occupant.build_id, - active=True, - is_confirmed=True, - ) + invitation = BuildDecisionBookInvitations.filter_one( + BuildDecisionBookInvitations.id==book_person_manager.invite_id, + BuildDecisionBookInvitations.build_id==token_dict.selected_occupant.build_id, + BuildDecisionBookInvitations.active==True, + ).get(1) if not invitation: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Invitation not found. Please check token", ) - assign_occupant_type = OccupantTypes.find_or_abort( - uu_id=data.occupant_type_uu_id, is_confirmed=True, active=True - ) + assign_occupant_type = OccupantTypes.filter_by_one( + uu_id=data.occupant_type_uu_id, active=True + ).get(1) if not assign_occupant_type: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Occupant type must be a Meeting Type {data.occupant_type_uu_id} is not a MT type occupant", ) - build_parts_of_token = BuildParts.filter_active( + build_parts_of_token = BuildParts.filter_all( BuildParts.build_id == token_dict.selected_occupant.build_id, - ) - selected_living_space = BuildLivingSpace.filter_active( + ).data + selected_living_space = BuildLivingSpace.filter_one( BuildLivingSpace.uu_id == data.build_living_space_uu_id, BuildLivingSpace.build_parts_id.in_( - [build.id for build in build_parts_of_token.data] + [build.id for build in build_parts_of_token] ), - ) - - if not selected_living_space.data: + ).get(1) + if not selected_living_space: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Person not found. Please check person uuid", ) - selected_living_space = selected_living_space.get(1) - book_person_to_assign: BuildDecisionBookPerson = ( - BuildDecisionBookPerson.find_one( - build_living_space_id=selected_living_space.id, - invite_id=invitation.id, - active=True, - is_confirmed=True, - ) - ) + book_person_to_assign: BuildDecisionBookPerson = BuildDecisionBookPerson.filter_one( + BuildDecisionBookPerson.build_living_space_id==selected_living_space.id, + BuildDecisionBookPerson.invite_id==invitation.id, + BuildDecisionBookPerson.active==True + ).get(1) if not book_person_to_assign: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, @@ -309,16 +306,16 @@ class DecisionBookPersonAssignOccupantEventMethods(MethodToEvent): ) if assign_occupant_type.occupant_code in ("MT-PRS", "MT-WRT"): - occupant_type_unique = OccupantTypes.find_or_abort( + occupant_type_unique = OccupantTypes.filter_by_one( occupant_code=assign_occupant_type.occupant_code, occupant_category_type="MT", - ) - if assigned_book_person_occupant := BuildDecisionBookPersonOccupants.find_one( - invite_id=invitation.id, - occupant_type_id=occupant_type_unique.id, - active=True, - is_confirmed=True, - ): + ).get(1) + if assigned_book_person_occupant := BuildDecisionBookPersonOccupants.filter_one( + BuildDecisionBookPersonOccupants.invite_id==invitation.id, + BuildDecisionBookPersonOccupants.occupant_type_id==occupant_type_unique.id, + BuildDecisionBookPersonOccupants.active==True, + BuildDecisionBookPersonOccupants.is_confirmed==True, + ).get(1): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Only one person can be assigned to {assign_occupant_type.occupant_code} type" @@ -326,13 +323,13 @@ class DecisionBookPersonAssignOccupantEventMethods(MethodToEvent): ) if assign_occupant_type.occupant_code == "BU-MNG": - person_occupant_manager = BuildDecisionBookPersonOccupants.find_one( - invite_id=invitation.id, - occupant_type_id=manager_occupant_type.id, - active=True, - is_confirmed=True, + person_occupant_manager = BuildDecisionBookPersonOccupants.filter_one( + BuildDecisionBookPersonOccupants.invite_id==invitation.id, + BuildDecisionBookPersonOccupants.occupant_type_id==manager_occupant_type.id, + BuildDecisionBookPersonOccupants.active==True, + BuildDecisionBookPersonOccupants.is_confirmed==True, ) - person_occupant_manager.delete(destroy=True) + person_occupant_manager.query.delete() book_person_to_assign.add_occupant_type( occupant_type=assign_occupant_type, diff --git a/api_events/events/decision_book/decision_book_invitations.py b/api_events/events/decision_book/decision_book_invitations.py index 3669913..fa59ece 100644 --- a/api_events/events/decision_book/decision_book_invitations.py +++ b/api_events/events/decision_book/decision_book_invitations.py @@ -62,9 +62,9 @@ class BuildDecisionBookInvitationsCreateEventMethods(MethodToEvent): detail="Employee cannot create decision book invitations", ) # Check token posses the occupant type of Build Manager - occupant_manager = OccupantTypes.find_one( + occupant_manager = OccupantTypes.filter_by_one( occupant_category_type="BU", occupant_code="BU-MNG" - ) + ).get(1) if not token_dict.selected_occupant.occupant_type_id == occupant_manager.id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, @@ -72,21 +72,24 @@ class BuildDecisionBookInvitationsCreateEventMethods(MethodToEvent): ) # Check decision book is valid for this token and building - decision_book = BuildDecisionBook.find_one( - uu_id=data.build_decision_book_uu_id, - build_id=token_dict.selected_occupant.build_id, - ) + decision_book = BuildDecisionBook.filter_one( + BuildDecisionBook.uu_id==data.build_decision_book_uu_id, + BuildDecisionBook.build_id==token_dict.selected_occupant.build_id, + BuildDecisionBook.active==True, + ).get(1) if not decision_book: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Decision book not found. Please create decision book first", ) - occupant_building = Build.find_one(id=token_dict.selected_occupant.build_id) + occupant_building = Build.filter_one( + Build.id==token_dict.selected_occupant.build_id + ).get(1) # Check meeting type is valid - meeting_type = ApiEnumDropdown.find_one( + meeting_type = ApiEnumDropdown.filter_by_one( enum_class="MeetingTypes", - ) + ).get(1) if not meeting_type: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -104,6 +107,9 @@ class BuildDecisionBookInvitationsCreateEventMethods(MethodToEvent): ) # Create an invitation for specific invitation type to start invite sending process + planned_date_expires = str( + system_arrow.get(data.planned_date).shift(days=15).date() + ), book_invitation = BuildDecisionBookInvitations.find_or_create( build_id=token_dict.selected_occupant.build_id, build_uu_id=token_dict.selected_occupant.build_uuid, @@ -114,9 +120,7 @@ class BuildDecisionBookInvitationsCreateEventMethods(MethodToEvent): living_part_percentage=0.51, message=data.message, planned_date=data.planned_date, - planned_date_expires=str( - system_arrow.get(data.planned_date).shift(days=15).date() - ), + planned_date_expires=planned_date_expires, expiry_ends=str(system_arrow.get(data.planned_date).shift(days=15).date()), is_confirmed=True, ) @@ -131,25 +135,22 @@ class BuildDecisionBookInvitationsCreateEventMethods(MethodToEvent): ) # Get all the parts of the building that is occupant in token - build_parts = BuildParts.filter_active( - BuildParts.build_id == occupant_building.id - ) + build_parts = BuildParts.filter_all( + BuildParts.build_id == occupant_building.id, + BuildParts.active == True + ).data # Get all build living spaces that is found in building with distinct person id - occupants = OccupantTypes.filter_all() - build_living_spaces_people = ( - BuildLivingSpace.filter_active( - BuildLivingSpace.build_parts_id.in_( - [build_part.id for build_part in build_parts.data] - ), - BuildLivingSpace.occupant_type.in_( - [occupant.id for occupant in occupants.data] - ), - filter_records=False, - ) - .query.distinct(BuildLivingSpace.person_id) - .all() - ) + occupants = OccupantTypes.filter_all(system=True) + BuildLivingSpace.filter_attr = None + build_living_spaces_people = BuildLivingSpace.filter_all( + BuildLivingSpace.build_parts_id.in_( + [build_part.id for build_part in build_parts.data] + ), + BuildLivingSpace.occupant_type.in_( + [occupant.id for occupant in occupants.data] + ), + ).query.distinct(BuildLivingSpace.person_id).all() if not build_living_spaces_people: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -199,21 +200,22 @@ class BuildDecisionBookInvitationsCreateEventMethods(MethodToEvent): invitations_person.add_occupant_type(occupant_type=attendance_occupant_type) if invitations_person and not invitations_person.is_found: print(f'"{invitations_person.token}",') - spaces_user = Users.find_one( - active=True, - is_confirmed=True, - person_id=build_living_spaces_user.person_id, - ) + spaces_user = Users.filter_one( + Users.active==True, + Users.is_confirmed==True, + Users.person_id==build_living_spaces_user.person_id, + ).data # print( # f"Invitation is send : {spaces_user.email} " # f"Token : {invitations_person.token} " # f"Send Date : {str(invitations_person.send_date.date())}" # ) - manager_living_spaces = BuildLivingSpace.filter_active( + manager_living_spaces = BuildLivingSpace.filter_all( BuildLivingSpace.person_id == token_dict.person_id, - ) - manager_people = BuildDecisionBookPerson.filter_active( + BuildLivingSpace.active == True, + ).data + manager_people = BuildDecisionBookPerson.filter_all( BuildDecisionBookPerson.invite_id == book_invitation.id, BuildDecisionBookPerson.build_living_space_id.in_( [ @@ -221,16 +223,15 @@ class BuildDecisionBookInvitationsCreateEventMethods(MethodToEvent): for manager_living_space in manager_living_spaces.data ] ), + BuildLivingSpace.active == True, ) - manager_people_occupants = BuildDecisionBookPersonOccupants.filter_active( + manager_people_occupants = BuildDecisionBookPersonOccupants.filter_all( BuildDecisionBookPersonOccupants.build_decision_book_person_id - == manager_people.get(1).id + == manager_people.get(1).id, + BuildDecisionBookPersonOccupants.active == True, ) - dlt = [ - occupants.delete(destroy=True) - for occupants in manager_people_occupants.data - ] - dlt = [occupants.delete(destroy=True) for occupants in manager_people.data] + manager_people_occupants.query.delete() + manager_people.query.delete() if book_person_manager := BuildDecisionBookPerson.find_or_create( **build_decision_book_person_dict, diff --git a/api_validations/core_response.py b/api_validations/core_response.py index 9837dbe..c94fbca 100644 --- a/api_validations/core_response.py +++ b/api_validations/core_response.py @@ -12,15 +12,16 @@ class AlchemyJsonResponse: completed: bool filter_attributes: Any = None response_model: Any = None + def __new__( - cls, - message: str, - status_code: str = 'HTTP_200_OK', - result: Union[Any, list] = None, - completed: bool = True, - response_model: Any = None + cls, + message: str, + status_code: str = "HTTP_200_OK", + result: Union[Any, list] = None, + completed: bool = True, + response_model: Any = None, ): - cls.status_code = getattr(status, status_code, 'HTTP_200_OK') + cls.status_code = getattr(status, status_code, "HTTP_200_OK") cls.message = message cls.result = result cls.completed = completed @@ -76,13 +77,17 @@ class AlchemyJsonResponse: "order_type": filter_model.order_type, } include_joins = dict( - include_joins=filter_model.include_joins if filter_model.include_joins else [] + include_joins=( + filter_model.include_joins if filter_model.include_joins else [] + ) ) data = [] for data_object in cls.result.data: data_dict = data_object.get_dict(include_joins=include_joins) if cls.response_model: - data_dict = cls.response_model(**data_object.get_dict(include_joins=include_joins)).dump() + data_dict = cls.response_model( + **data_object.get_dict(include_joins=include_joins) + ).dump() data.append(data_dict) return JSONResponse( status_code=cls.status_code, diff --git a/databases/extensions/auth.py b/databases/extensions/auth.py index 103a499..bba30cd 100644 --- a/databases/extensions/auth.py +++ b/databases/extensions/auth.py @@ -46,50 +46,42 @@ class AuthModule(PasswordModule): @classmethod def check_user_exits(cls, access_key, domain): - - found_user: Users = cls.filter_active( + found_user: Users = cls.filter_one( or_( cls.email == str(access_key).lower(), cls.phone_number == str(access_key).replace(" ", ""), ), - filter_records=False, - ) - if not found_user.data: + ).data + if not found_user: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Given access key or domain is not matching with the any user record.", ) - found_user = found_user.data[0] + other_domains_list = found_user.get_main_domain_and_other_domains( get_main_domain=False ) - if domain not in other_domains_list: raise HTTPException( status_code=401, detail=dict(message="Unauthorized User attempts to connect api"), ) - - if not found_user: - raise HTTPException( - status_code=401, - detail="Given access key or domain is not matching with the any user record.", - ) return found_user def generate_access_token(self): return self.generate_token(Auth.ACCESS_TOKEN_LENGTH) def remove_refresher_token(self, domain, disconnect: bool = False): - registered_tokens = ([], 0) if disconnect: - registered_tokens = UsersTokens.filter_by(user_id=self.id) + registered_tokens = UsersTokens.filter_all( + UsersTokens.user_id==self.id, system=True + ) else: - registered_tokens = UsersTokens.filter_by(domain=domain, user_id=self.id) - for token in registered_tokens[0]: - token.session.delete(token) - token.session.commit() - token.session.flush() + registered_tokens = UsersTokens.filter_all( + UsersTokens.domain==domain, UsersTokens.user_id==self.id, system=True + ) + registered_tokens.query.delete() + UsersTokens.save() def check_password(self, password): main_domain = self.get_main_domain_and_other_domains(get_main_domain=True) @@ -182,6 +174,7 @@ class AuthModule(PasswordModule): token=refresh_token, domain=domain, ) + UsersTokens.save() return refresh_token return None diff --git a/databases/sql_models/account/account.py b/databases/sql_models/account/account.py index 8145957..3f590bd 100644 --- a/databases/sql_models/account/account.py +++ b/databases/sql_models/account/account.py @@ -10,7 +10,6 @@ from sqlalchemy import ( Boolean, TIMESTAMP, Numeric, - Identity, UUID, ) @@ -23,9 +22,7 @@ class AccountBooks(CrudCollection): country: Mapped[str] = mapped_column(String, nullable=False) branch_type: Mapped[str] = mapped_column(SmallInteger, server_default="0") - company_id: Mapped[int] = mapped_column( - ForeignKey("companies.id"), nullable=False - ) + company_id: Mapped[int] = mapped_column(ForeignKey("companies.id"), nullable=False) company_uu_id: Mapped[UUID] = mapped_column(String, nullable=False) branch_id: Mapped[int] = mapped_column(ForeignKey("companies.id")) branch_uu_id: Mapped[UUID] = mapped_column(String, comment="Branch UU ID") @@ -466,9 +463,7 @@ class AccountRecords(CrudCollection): send_person_uu_id = mapped_column( String, nullable=True, comment="Send Person UU ID" ) - approving_accounting_person: Mapped[int] = mapped_column( - ForeignKey("people.id") - ) + approving_accounting_person: Mapped[int] = mapped_column(ForeignKey("people.id")) approving_accounting_person_uu_id = mapped_column( String, nullable=True, comment="Approving Accounting Person UU ID" ) @@ -537,7 +532,7 @@ class AccountRecords(CrudCollection): "comment": "Bank Records that are related to building and financial transactions" }, ) - + # def payment_budget_record_close(self): # from database_sql_models import ( # DecisionBookProjectPaymentsMaster, diff --git a/databases/sql_models/building/build.py b/databases/sql_models/building/build.py index 52512b6..a075d34 100644 --- a/databases/sql_models/building/build.py +++ b/databases/sql_models/building/build.py @@ -16,7 +16,6 @@ from sqlalchemy import ( TIMESTAMP, Text, Numeric, - Identity, ) from databases.sql_models.core_mixin import CrudCollection @@ -331,25 +330,27 @@ class Build(CrudCollection, SelectActionWithEmployee): data_dict["build_types_id"] = build_type.id del data_dict["build_types_uu_id"] build_created = cls.find_or_create(**data_dict) - if not build_created.is_found: - cls.__many__table__.find_or_create( - company_id=token.selected_company.company_id, - employee_id=token.selected_company.employee_id, - member_id=build_created.id, - is_confirmed=True, - ) + cls.__many__table__.find_or_create( + company_id=token.selected_company.company_id, + employee_id=token.selected_company.employee_id, + member_id=build_created.id, + is_confirmed=True, + ) return build_created @classmethod def update_action(cls, data: UpdateBuild, build_uu_id: str, token): from databases import Addresses - data_dict = data.excluded_dump() if data.official_address_uu_id: - official_address = Addresses.find_one(uu_id=data.address_uu_id) - data_dict["address_id"] = official_address.id + official_address = Addresses.filter_one( + Addresses.uu_id==data.address_uu_id + ).data + data_dict["address_id"] = official_address.id if official_address else None del data_dict["address_uu_id"] - if build_to_update := cls.find_one(uu_id=build_uu_id, person_id=token.id): + if build_to_update := cls.filter_one( + cls.uu_id==build_uu_id, cls.person_id==token.id + ).data: return build_to_update.update(**data_dict) @property @@ -489,7 +490,9 @@ class BuildParts(CrudCollection): "Check with your supervisor.", ) - if build_types := BuildTypes.find_one(uu_id=data.build_part_type_uu_id): + if build_types := BuildTypes.filter_one( + BuildTypes.uu_id==data.build_part_type_uu_id + ).data: part_direction = ApiEnumDropdown.get_by_uuid( uuid=str(data.part_direction_uu_id) ) @@ -516,13 +519,13 @@ class BuildParts(CrudCollection): if not data_dict["part_gross_size"]: raise HTTPException( - status_code=status.HTTP_418_IM_A_TEAPOT, + status_code=status.HTTP_406_NOT_ACCEPTABLE, detail="Part Gross Size can not be empty.", ) if not data_dict["part_net_size"]: raise HTTPException( - status_code=status.HTTP_418_IM_A_TEAPOT, + status_code=status.HTTP_406_NOT_ACCEPTABLE, detail="Part Net Size can not be empty.", ) pt = int(data_dict["part_net_size"]) diff --git a/databases/sql_models/building/decision_book.py b/databases/sql_models/building/decision_book.py index 985a372..c270717 100644 --- a/databases/sql_models/building/decision_book.py +++ b/databases/sql_models/building/decision_book.py @@ -26,7 +26,6 @@ from sqlalchemy import ( Text, Numeric, Integer, - Identity, ) from sqlalchemy.orm import mapped_column, Mapped, relationship @@ -406,15 +405,17 @@ class BuildDecisionBookPerson(CrudCollection): if person_occupants := BuildDecisionBookPersonOccupants.find_or_create( **book_dict ): - decision_book = BuildDecisionBook.find_one( - id=self.build_decision_book_id, active=True, is_confirmed=True - ) + decision_book = BuildDecisionBook.filter_one( + BuildDecisionBook.id==self.build_decision_book_id, + BuildDecisionBook.active==True, + BuildDecisionBook.is_confirmed==True + ).data person_occupants.update( expiry_starts=decision_book.expiry_starts, expiry_ends=decision_book.expiry_ends, ) - if not person_occupants.is_found and build_living_space_id: - related_service = Services.find_one( + if build_living_space_id: + related_service = Services.filter_by_one( related_responsibility=str(occupant_type.occupant_code), active=True, is_confirmed=True, @@ -425,9 +426,11 @@ class BuildDecisionBookPerson(CrudCollection): detail=f"Service is not found for {occupant_type.occupant_code}", ) - decision_build = Build.find_one( - id=decision_book.build_id, active=True, is_confirmed=True - ) + decision_build = Build.filter_one( + Build.id==decision_book.build_id, + Build.active==True, + Build.is_confirmed==True + ).data management_room = decision_build.management_room if not management_room: raise HTTPException( @@ -435,8 +438,16 @@ class BuildDecisionBookPerson(CrudCollection): detail=f"Management Room is not found in {decision_build.build_name}", ) - living_space = BuildLivingSpace.find_one( - id=build_living_space_id, active=True, is_confirmed=True + living_space = BuildLivingSpace.filter_one( + BuildLivingSpace.id==build_living_space_id, + BuildLivingSpace.active==True, + BuildLivingSpace.is_confirmed==True + ).data + expiry_ends = str( + system_arrow.get(decision_book.meeting_date).shift(hours=23) + ) + expiry_starts = str( + system_arrow.get(decision_book.meeting_date) ) related_living_space = BuildLivingSpace.find_or_create( build_parts_id=management_room.id, @@ -445,40 +456,36 @@ class BuildDecisionBookPerson(CrudCollection): occupant_type_uu_id=str(occupant_type.uu_id), person_id=living_space.person_id, person_uu_id=str(living_space.person_uu_id), - expiry_starts=system_arrow.get( - decision_book.meeting_date - ).__str__(), - expiry_ends=system_arrow.get(decision_book.meeting_date) - .shift(hours=23) - .__str__(), + expiry_starts=expiry_starts, + expiry_ends=expiry_ends, is_confirmed=True, active=True, ) + expires_at = str( + system_arrow.get(decision_book.meeting_date).shift(days=15) + ) ServiceBindOccupantEventMethods.bind_services_occupant_system( build_living_space_id=related_living_space.id, service_id=related_service.id, - expires_at=str( - system_arrow.get(decision_book.meeting_date).shift(days=15) - ), + expires_at=expires_at, ) return person_occupants return def get_occupant_types(self): - if occupants := BuildDecisionBookPersonOccupants.filter_active( + if occupants := BuildDecisionBookPersonOccupants.filter_all( BuildDecisionBookPersonOccupants.build_decision_book_person_id == self.id, - filter_records=False, ): return occupants.data return def check_occupant_type(self, occupant_type): - book_person_occupant_type = BuildDecisionBookPersonOccupants.find_one( - build_decision_book_person_id=self.id, - occupant_type_id=occupant_type.id, - active=True, - is_confirmed=True, - ) + book_person_occupant_type = BuildDecisionBookPersonOccupants.filter_one( + BuildDecisionBookPersonOccupants.build_decision_book_person_id==self.id, + BuildDecisionBookPersonOccupants.occupant_type_id==occupant_type.id, + BuildDecisionBookPersonOccupants.active==True, + BuildDecisionBookPersonOccupants.is_confirmed==True, + ).data if not book_person_occupant_type: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, @@ -839,9 +846,7 @@ class BuildDecisionBookPayments(CrudCollection): String, nullable=True, comment="Build Part UUID" ) - budget_records_id: Mapped[int] = mapped_column( - ForeignKey("account_records.id") - ) + budget_records_id: Mapped[int] = mapped_column(ForeignKey("account_records.id")) budget_records_uu_id: Mapped[str] = mapped_column( String, nullable=True, comment="Budget UUID" ) @@ -936,9 +941,7 @@ class BuildDecisionBookLegal(CrudCollection): ForeignKey("people.id"), nullable=False ) resp_attorney_uu_id = mapped_column(String, nullable=True, comment="Attorney UUID") - resp_attorney_company_id: Mapped[int] = mapped_column( - ForeignKey("companies.id") - ) + resp_attorney_company_id: Mapped[int] = mapped_column(ForeignKey("companies.id")) resp_attorney_company_uu_id = mapped_column( String, nullable=True, comment="Company UUID" ) diff --git a/databases/sql_models/company/department.py b/databases/sql_models/company/department.py index 38775d0..f97c82d 100644 --- a/databases/sql_models/company/department.py +++ b/databases/sql_models/company/department.py @@ -18,9 +18,7 @@ class Departments(CrudCollection): ) department_description: Mapped[str] = mapped_column(String, server_default="") - company_id: Mapped[int] = mapped_column( - ForeignKey("companies.id"), nullable=False - ) + company_id: Mapped[int] = mapped_column(ForeignKey("companies.id"), nullable=False) company_uu_id: Mapped[str] = mapped_column( String, nullable=False, comment="Company UUID" ) diff --git a/databases/sql_models/company/employee.py b/databases/sql_models/company/employee.py index 52120f1..1a09c8c 100644 --- a/databases/sql_models/company/employee.py +++ b/databases/sql_models/company/employee.py @@ -3,7 +3,6 @@ from sqlalchemy import ( ForeignKey, Index, Numeric, - Identity, ) from sqlalchemy.orm import mapped_column, Mapped from databases.sql_models.core_mixin import CrudCollection diff --git a/databases/sql_models/core_mixin.py b/databases/sql_models/core_mixin.py index e13c293..058d7d0 100644 --- a/databases/sql_models/core_mixin.py +++ b/databases/sql_models/core_mixin.py @@ -1,15 +1,17 @@ +import datetime +from decimal import Decimal + from sqlalchemy import ( TIMESTAMP, NUMERIC, func, - Identity, + text, UUID, String, Integer, Boolean, SmallInteger, ) - from sqlalchemy.orm import ( Mapped, mapped_column, @@ -63,6 +65,18 @@ class CrudMixin(Base, SmartQueryMixin, SessionMixin, FilterAttributes): "updated_by_id", "replication_id", ) + __system_default_model__ = [ + "cryp_uu_id", + "is_confirmed", + "deleted", + "is_notification_send", + "replication_id", + "is_email_send", + "confirmed_by_id", + "confirmed_by", + "updated_by_id", + "created_by_id", + ] creds: Credentials = None # The credentials to use in the model. client_arrow: DateTimeLocal = None # The arrow to use in the model. @@ -74,6 +88,17 @@ class CrudMixin(Base, SmartQueryMixin, SessionMixin, FilterAttributes): TIMESTAMP, default="2099-12-31", server_default="2099-12-31" ) + @classmethod + def remove_non_related_inputs(cls, kwargs): + """ + Removes the non-related inputs from the given attributes. + """ + return { + key: value + for key, value in kwargs.items() + if key in cls.columns + cls.hybrid_properties + cls.settable_relations + } + @classmethod def extract_system_fields(cls, filter_kwargs: dict, create: bool = True): """ @@ -87,6 +112,47 @@ class CrudMixin(Base, SmartQueryMixin, SessionMixin, FilterAttributes): system_fields.pop(field, None) return system_fields + @classmethod + def iterate_over_variables(cls, val, key): + key_ = cls.__annotations__.get(key, None) + is_primary, value_type = key in cls.primary_keys, type(val) + row_attr = bool(getattr(getattr(cls, key), "foreign_keys", None)) + if is_primary or row_attr and key_ == Mapped[int]: + return None + if key_: + if key_ == Mapped[int]: + return int(val) if val else None + elif key_ == Mapped[bool]: + return bool(val) if val else None + elif key_ == Mapped[float] or key_ == Mapped[NUMERIC]: + return round(float(val), 3) if val else None + elif key_ == Mapped[int]: + return int(val) if val else None + elif key_ == Mapped[TIMESTAMP]: + formatted_date = client_arrow.get(str(val)).format( + "DD-MM-YYYY HH:mm:ss" + ) + return str(formatted_date) if val else None + else: + if isinstance(val, datetime.datetime): + formatted_date = client_arrow.get(str(val)).format( + "DD-MM-YYYY HH:mm:ss" + ) + print(key, "isinstance(value_type, datetime) | ", formatted_date) + return str(formatted_date) if val else None + elif isinstance(value_type, bool): + return bool(val) if val else None + elif isinstance(value_type, float) or isinstance(value_type, Decimal): + return round(float(val), 3) if val else None + elif isinstance(value_type, int): + return int(val) if val else None + elif isinstance(value_type, str): + return str(val) if val else None + elif isinstance(value_type, type(None)): + return None + + return str(val) if val else None + @classmethod def find_or_create(cls, **kwargs): from api_library.date_time_actions.date_functions import system_arrow @@ -97,19 +163,18 @@ class CrudMixin(Base, SmartQueryMixin, SessionMixin, FilterAttributes): is_found can be used to check if the record was found or created. """ check_kwargs = cls.extract_system_fields(kwargs) - cls.pre_query = cls.query.filter( - system_arrow.get(cls.expiry_ends).date() < system_arrow.now().date() - ) - already_record = cls.filter_by_one(**check_kwargs) + cls.pre_query = cls.query.filter(cls.expiry_ends < system_arrow.now().date()) + already_record = cls.filter_by_one(**check_kwargs, system=True) + cls.pre_query = None if already_record := already_record.data: - if already_record.is_deleted: + if already_record.deleted: cls.raise_http_exception( status_code="HTTP_406_NOT_ACCEPTABLE", error_case="DeletedRecord", data=check_kwargs, message="Record exits but is deleted. Contact with authorized user", ) - elif already_record.is_confirmed: + elif not already_record.is_confirmed: cls.raise_http_exception( status_code="HTTP_406_NOT_ACCEPTABLE", error_case="IsNotConfirmed", @@ -122,6 +187,7 @@ class CrudMixin(Base, SmartQueryMixin, SessionMixin, FilterAttributes): data=check_kwargs, message="Record already exits. Refresh data and try again", ) + check_kwargs = cls.remove_non_related_inputs(check_kwargs) created_record = cls() for key, value in check_kwargs.items(): setattr(created_record, key, value) @@ -130,28 +196,8 @@ class CrudMixin(Base, SmartQueryMixin, SessionMixin, FilterAttributes): cls.created_by = cls.creds.person_name return created_record - @classmethod - def iterate_over_variables(cls, val, key): - key_ = cls.__annotations__.get(key, None) - is_primary, is_foreign_key = key in cls.primary_keys and bool(getattr(cls, key).foreign_keys) - if is_primary or is_foreign_key and key_ == Mapped[int]: - return None - elif key_ == Mapped[UUID]: - return str(val) if val else None - elif key_ == Mapped[int]: - return int(val) if val else None - elif key_ == Mapped[bool]: - return bool(val) if val else None - elif key_ == Mapped[float] or key_ == Mapped[NUMERIC]: - return float(val) if val else None - elif key_ == Mapped[int]: - return int(val) if val else None - elif key_ == Mapped[TIMESTAMP]: - return str(client_arrow.get(val).format("DD-MM-YYYY HH:mm:ss")) if val else None - return str(val) if val else None - - def update(self, **kwargs): + check_kwargs = self.remove_non_related_inputs(kwargs) """Updates the record with the given attributes.""" is_confirmed_argument = kwargs.get("is_confirmed", None) if is_confirmed_argument and not len(kwargs) == 1: @@ -161,7 +207,7 @@ class CrudMixin(Base, SmartQueryMixin, SessionMixin, FilterAttributes): data=kwargs, message="Confirm field can not be updated with other fields", ) - check_kwargs = self.extract_system_fields(kwargs, create=False) + check_kwargs = self.extract_system_fields(check_kwargs, create=False) for key, value in check_kwargs.items(): setattr(self, key, value) @@ -178,24 +224,48 @@ class CrudMixin(Base, SmartQueryMixin, SessionMixin, FilterAttributes): self, exclude: list = None, include: list = None, include_joins: list = None ): return_dict = {} - if exclude: - exclude.extend(list(set(self.__exclude__fields__).difference(exclude))) - else: - exclude = self.__exclude__fields__ - include = include or [] if include: - include.extend(["uu_id", "active"]) - include = list(set(include).difference(self.__exclude__fields__)) - for key, val in self.to_dict().items(): - if key in include: - if value_of_database := self.iterate_over_variables(val, key): - return_dict[key] = value_of_database + exclude_list = [ + element + for element in self.__system_default_model__ + if str(element)[-2:] == "id" + ] + columns_include_list = list(set(include).difference(set(exclude_list))) + columns_include_list.extend(["uu_id", "active"]) + for key in list(columns_include_list): + val = getattr(self, key) + value_of_database = self.iterate_over_variables(val, key) + if value_of_database is not None: + return_dict[key] = value_of_database + elif exclude: + exclude.extend( + list(set(self.__exclude__fields__ or []).difference(exclude)) + ) + for i in self.__system_default_model__: + print("i", str(i)[-2:]) + exclude.extend( + [ + element + for element in self.__system_default_model__ + if str(element)[-2:] == "id" + ] + ) + columns_excluded_list = set(self.columns).difference(set(exclude)) + for key in list(columns_excluded_list): + val = getattr(self, key) + value_of_database = self.iterate_over_variables(val, key) + if value_of_database is not None: + return_dict[key] = value_of_database else: - exclude.extend(["is_confirmed", "deleted", "cryp_uu_id"]) - for key, val in self.to_dict().items(): - if key not in exclude: - if value_of_database := self.iterate_over_variables(val, key): - return_dict[key] = value_of_database + exclude_list = ( + self.__exclude__fields__ or [] + self.__system_default_model__ + ) + columns_list = list(set(self.columns).difference(set(exclude_list))) + for key in list(columns_list): + val = getattr(self, key) + value_of_database = self.iterate_over_variables(val, key) + if value_of_database is not None: + return_dict[key] = value_of_database all_arguments = [ record @@ -218,15 +288,15 @@ class CrudMixin(Base, SmartQueryMixin, SessionMixin, FilterAttributes): return_dict[all_argument] = ( populate_arg.get_dict() if populate_arg else [] ) - return return_dict + return dict(sorted(return_dict.items(), reverse=False)) -class BaseMixin(CrudMixin, ReprMixin, SerializeMixin): +class BaseMixin(CrudMixin, ReprMixin, SerializeMixin, FilterAttributes): __abstract__ = True -class BaseCollection(CrudMixin, BaseMixin): +class BaseCollection(BaseMixin): __abstract__ = True __repr__ = ReprMixin.__repr__ @@ -234,14 +304,14 @@ class BaseCollection(CrudMixin, BaseMixin): id: Mapped[int] = mapped_column(primary_key=True) -class CrudCollection(CrudMixin, BaseMixin, SmartQueryMixin): +class CrudCollection(BaseMixin, SmartQueryMixin): __abstract__ = True __repr__ = ReprMixin.__repr__ id: Mapped[int] = mapped_column(primary_key=True) uu_id: Mapped[UUID] = mapped_column( - UUID, server_default=func.text("gen_random_uuid()"), index=True, unique=True + UUID, server_default=text("gen_random_uuid()"), index=True, unique=True ) ref_id: Mapped[UUID] = mapped_column(String(100), nullable=True, index=True) diff --git a/databases/sql_models/event/event.py b/databases/sql_models/event/event.py index 6cd1cc6..6416377 100644 --- a/databases/sql_models/event/event.py +++ b/databases/sql_models/event/event.py @@ -8,7 +8,6 @@ from sqlalchemy import ( Boolean, Integer, Index, - Identity, ) from sqlalchemy.orm import mapped_column, Mapped @@ -92,9 +91,7 @@ class Services(CrudCollection): __tablename__ = "services" __exclude__fields__ = [] - module_id: Mapped[int] = mapped_column( - ForeignKey("modules.id"), nullable=False - ) + module_id: Mapped[int] = mapped_column(ForeignKey("modules.id"), nullable=False) module_uu_id: Mapped[str] = mapped_column( String, nullable=False, comment="Module UUID" ) @@ -118,9 +115,7 @@ class Service2Events(CrudCollection): __tablename__ = "services2events" __exclude__fields__ = [] - service_id: Mapped[int] = mapped_column( - ForeignKey("services.id"), nullable=False - ) + service_id: Mapped[int] = mapped_column(ForeignKey("services.id"), nullable=False) service_uu_id = mapped_column(String, nullable=False, comment="Service UUID") event_id: Mapped[int] = mapped_column(ForeignKey("events.id"), nullable=False) event_uu_id = mapped_column(String, nullable=False, comment="Event UUID") @@ -148,9 +143,9 @@ class Event2Employee(CrudCollection): @classmethod def get_event_id_by_employee_id(cls, employee_id) -> (list, list): - active_events = cls.filter_active(cls.employee_id == employee_id) + active_events = cls.filter_all(cls.employee_id == employee_id) active_events_id = [event.event_id for event in active_events.data] - active_events = Events.filter_active(Events.id.in_(active_events_id)) + active_events = Events.filter_all(Events.id.in_(active_events_id)) active_events_uu_id = [str(event.uu_id) for event in active_events.data] return active_events_id, active_events_uu_id @@ -205,13 +200,9 @@ class ModulePrice(CrudCollection): __exclude__fields__ = [] campaign_code = mapped_column(String, nullable=False, comment="Campaign Code") - module_id: Mapped[int] = mapped_column( - ForeignKey("modules.id"), nullable=False - ) + module_id: Mapped[int] = mapped_column(ForeignKey("modules.id"), nullable=False) module_uu_id = mapped_column(String, nullable=False, comment="Module UUID") - service_id: Mapped[int] = mapped_column( - ForeignKey("services.id"), nullable=False - ) + service_id: Mapped[int] = mapped_column(ForeignKey("services.id"), nullable=False) service_uu_id = mapped_column(String, nullable=False, comment="Service UUID") event_id: Mapped[int] = mapped_column(ForeignKey("events.id"), nullable=False) event_uu_id = mapped_column(String, nullable=False, comment="Event UUID") diff --git a/databases/sql_models/identity/identity.py b/databases/sql_models/identity/identity.py index caf1c04..22447d4 100644 --- a/databases/sql_models/identity/identity.py +++ b/databases/sql_models/identity/identity.py @@ -20,7 +20,6 @@ from sqlalchemy import ( Integer, Text, or_, - Identity, ) from sqlalchemy.orm import mapped_column, relationship, Mapped @@ -425,9 +424,7 @@ class RelationshipEmployee2PostCode(CrudCollection): company_id: Mapped[int] = mapped_column( ForeignKey("companies.id"), nullable=True ) # 1, 2, 3 - employee_id: Mapped[int] = mapped_column( - ForeignKey("employees.id"), nullable=False - ) + employee_id: Mapped[int] = mapped_column(ForeignKey("employees.id"), nullable=False) member_id: Mapped[int] = mapped_column( ForeignKey("address_postcode.id"), nullable=False ) @@ -465,13 +462,25 @@ class Addresses(CrudCollection): __tablename__ = "addresses" __exclude__fields__ = [] - build_number: Mapped[str] = mapped_column(String(24), nullable=False, comment="Build Number") - door_number: Mapped[str] = mapped_column(String(24), nullable=True, comment="Door Number") - floor_number: Mapped[str] = mapped_column(String(24), nullable=True, comment="Floor Number") + build_number: Mapped[str] = mapped_column( + String(24), nullable=False, comment="Build Number" + ) + door_number: Mapped[str] = mapped_column( + String(24), nullable=True, comment="Door Number" + ) + floor_number: Mapped[str] = mapped_column( + String(24), nullable=True, comment="Floor Number" + ) - comment_address: Mapped[str] = mapped_column(String, nullable=False, comment="Address") - letter_address: Mapped[str] = mapped_column(String, nullable=False, comment="Address") - short_letter_address: Mapped[str] = mapped_column(String, nullable=False, comment="Address") + comment_address: Mapped[str] = mapped_column( + String, nullable=False, comment="Address" + ) + letter_address: Mapped[str] = mapped_column( + String, nullable=False, comment="Address" + ) + short_letter_address: Mapped[str] = mapped_column( + String, nullable=False, comment="Address" + ) latitude: Mapped[float] = mapped_column(Numeric(20, 12), server_default="0") longitude: Mapped[float] = mapped_column(Numeric(20, 12), server_default="0") @@ -483,9 +492,10 @@ class Addresses(CrudCollection): @classmethod def list_via_employee(cls, token_dict, filter_expr): - post_code_list = RelationshipEmployee2PostCode.filter_active( + post_code_list = RelationshipEmployee2PostCode.filter_all( RelationshipEmployee2PostCode.employee_id == token_dict.selected_company.employee_id, + RelationshipEmployee2PostCode.active==True, ).data post_code_id_list = [post_code.member_id for post_code in post_code_list] if not post_code_id_list: @@ -493,10 +503,10 @@ class Addresses(CrudCollection): status_code=404, detail="User has no post code registered. User can not list addresses.", ) - cls.pre_query = Addresses.filter_active( - cls.post_code_id.in_(post_code_id_list) - ).query - return cls.filter_active(*filter_expr) + cls.pre_query = cls.filter_active(cls.post_code_id.in_(post_code_id_list)).query + filter_cls = cls.filter_all(*filter_expr) + cls.pre_query = None + return filter_cls # buildings: Mapped["Build"] = relationship( # "Build", back_populates="addresses", foreign_keys="Build.address_id" diff --git a/databases/sql_models/others/enums.py b/databases/sql_models/others/enums.py index f353575..713134f 100644 --- a/databases/sql_models/others/enums.py +++ b/databases/sql_models/others/enums.py @@ -4,7 +4,6 @@ from sqlalchemy import ( UUID, String, text, - Identity, ) from sqlalchemy.orm import ( Mapped, @@ -40,22 +39,26 @@ class ApiEnumDropdown(BaseCollection): if search := cls.query.filter( cls.enum_class.in_(["DebitTypes"]), cls.uu_id == search_uu_id, + cls.active == True, ).first(): return search elif search_debit: if search := cls.query.filter( cls.enum_class.in_(["DebitTypes"]), cls.key == search_debit, + cls.active == True, ).first(): return search return cls.query.filter( cls.enum_class.in_(["DebitTypes"]), + cls.active == True, ).all() @classmethod def get_due_types(cls): - if due_list := cls.filter_active( - cls.enum_class == "BuildDuesTypes", cls.key.in_(["BDT-A", "BDT-D"]) + if due_list := cls.filter_all( + cls.enum_class == "BuildDuesTypes", cls.key.in_(["BDT-A", "BDT-D"]), + cls.active == True, ).data: return [due.uu_id.__str__() for due in due_list] raise HTTPException( @@ -69,16 +72,19 @@ class ApiEnumDropdown(BaseCollection): if search := cls.query.filter( cls.enum_class.in_(["BuildDuesTypes"]), cls.uu_id == search_uu_id, + cls.active == True, ).first(): return search elif search_management: if search := cls.query.filter( cls.enum_class.in_(["BuildDuesTypes"]), cls.key == search_management, + cls.active == True, ).first(): return search return cls.query.filter( cls.enum_class.in_(["BuildDuesTypes"]), + cls.active == True, ).all() def get_enum_dict(self): @@ -92,7 +98,9 @@ class ApiEnumDropdown(BaseCollection): @classmethod def uuid_of_enum(cls, enum_class: str, key: str): - return str(getattr(cls.find_one(enum_class=enum_class, key=key), "uu_id", None)) + return str(getattr(cls.filter_one( + cls.enum_class==enum_class, cls.key==key + ).data, "uu_id", None)) ApiEnumDropdown.set_session(ApiEnumDropdown.__session__) diff --git a/databases/sql_models/sql_operations.py b/databases/sql_models/sql_operations.py index 1c76957..66bd531 100644 --- a/databases/sql_models/sql_operations.py +++ b/databases/sql_models/sql_operations.py @@ -1,3 +1,4 @@ +from sqlalchemy import SQLColumnExpression from sqlalchemy.exc import SQLAlchemyError from api_validations.validations_request import ListOptions @@ -90,24 +91,51 @@ class FilterAttributes: } @classmethod - def get_not_expired_query_arg(cls, *arg, expired=True): + def add_new_arg_to_args(cls, args_list, argument, value): + new_arg_list = list( + args_ for args_ in list(args_list) if isinstance(args_, SQLColumnExpression) + ) + if not any(True for arg in new_arg_list if arg.left.key == argument): + new_arg_list.append(value) + return tuple(new_arg_list) + + @classmethod + def get_not_expired_query_arg(cls, arg): """Add expiry_starts and expiry_ends to the query.""" from api_library.date_time_actions.date_functions import system_arrow - if expired: - arg_add = ( - *arg[0], - system_arrow.get(cls.expiry_ends) >= system_arrow.now(), - system_arrow.now() >= system_arrow.get(cls.expiry_starts), - ) - return arg_add - return arg[0] + arg = cls.add_new_arg_to_args( + arg, "expiry_ends", cls.expiry_ends >= str(system_arrow.now()) + ) + arg = cls.add_new_arg_to_args( + arg, "expiry_starts", cls.expiry_starts <= str(system_arrow.now()) + ) + return arg @classmethod - def filter_by_all(cls, **kwargs): + def select_only( + cls, *args, select_args: list, order_by=None, limit=None, system=False + ): + if not system: + args = cls.add_new_arg_to_args( + args, "is_confirmed", cls.is_confirmed == True + ) + args = cls.get_not_expired_query_arg(args) + query = cls._query().filter(*args).with_entities(*select_args) + if order_by is not None: + query = query.order_by(order_by) + if limit: + query = query.limit(limit) + return AlchemyResponse(query=query, first=False) + + @classmethod + def filter_by_all(cls, system=False, **kwargs): """ Filters all the records regardless of is_deleted, is_confirmed. """ + if "is_confirmed" not in kwargs and not system: + kwargs["is_confirmed"] = True + kwargs.pop("system", None) query = cls._query().filter_by(**kwargs) if cls.filter_attr: filter_list = cls.get_filter_attributes() @@ -116,18 +144,27 @@ class FilterAttributes: return AlchemyResponse(query=query, first=False) @classmethod - def filter_by_one(cls, **kwargs): + def filter_by_one(cls, system=False, **kwargs): """ Filters one record regardless of is_deleted, is_confirmed. """ + if "is_confirmed" not in kwargs and not system: + kwargs["is_confirmed"] = True + kwargs.pop("system", None) query = cls._query().filter_by(**kwargs) return AlchemyResponse(query=query, first=True) @classmethod - def filter_all(cls, *args, expired: bool = False): + def filter_all(cls, *args, system=False): """ Filters all the records regardless of is_deleted, is_confirmed. """ + if not system: + args = cls.add_new_arg_to_args( + args, "is_confirmed", cls.is_confirmed == True + ) + args = cls.get_not_expired_query_arg(args) + query = cls._query().filter(*args) if cls.filter_attr: filter_list = cls.get_filter_attributes() @@ -136,12 +173,16 @@ class FilterAttributes: return AlchemyResponse(query=query, first=False) @classmethod - def filter_one(cls, *args, expired: bool = False): + def filter_one(cls, *args, system=False, expired: bool = False): """ Filters one record regardless of is_deleted, is_confirmed. """ - arg = cls.get_not_expired_query_arg(args, expired=expired) - query = cls._query().filter(*arg) + if not system: + args = cls.add_new_arg_to_args( + args, "is_confirmed", cls.is_confirmed == True + ) + args = cls.get_not_expired_query_arg(args) + query = cls._query().filter(*args) return AlchemyResponse(query=query, first=True) @classmethod diff --git a/service_app/app.py b/service_app/app.py index b765d77..452d46c 100644 --- a/service_app/app.py +++ b/service_app/app.py @@ -10,6 +10,7 @@ from handlers_exception import ( exception_handler_exception, ) from prometheus_fastapi_instrumentator import Instrumentator + # from prometheus_client import Counter, Histogram from .app_runner_init import create_endpoints_from_api_functions