import typing from fastapi import status, HTTPException from fastapi.responses import JSONResponse from databases import ( Build, BuildLivingSpace, BuildParts, BuildDecisionBookInvitations, BuildDecisionBookPerson, BuildDecisionBook, BuildDecisionBookPersonOccupants, OccupantTypes, Users, ApiEnumDropdown, ) from api_validations.validations_request import ( DecisionBookDecisionBookInvitationsUpdate, DecisionBookDecisionBookInvitations, ) 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 system_arrow class BuildDecisionBookInvitationsListEventMethods(MethodToEvent): event_type = "SELECT" __event_keys__ = { "e2277528-8c9c-4c0c-ae64-3ce80cae664b": "decision_book_invitations_list", } __event_validation__ = {"e2277528-8c9c-4c0c-ae64-3ce80cae664b": None} @classmethod def decision_book_invitations_list( cls, data, token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], ): return class BuildDecisionBookInvitationsCreateEventMethods(MethodToEvent): event_type = "CREATE" __event_keys__ = { "d0bfa20c-841d-421c-98e6-d308f938d16a": "decision_book_invitations_create", } __event_validation__ = { "d0bfa20c-841d-421c-98e6-d308f938d16a": DecisionBookDecisionBookInvitations } @classmethod def decision_book_invitations_create( cls, data: DecisionBookDecisionBookInvitations, token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], ): if isinstance(token_dict, EmployeeTokenObject): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Employee cannot create decision book invitations", ) # Check token posses the occupant type of Build Manager occupant_manager = OccupantTypes.filter_by_one( system=True, occupant_category_type="BU", occupant_code="BU-MNG" ).data if not token_dict.selected_occupant.occupant_type_id == occupant_manager.id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Only Build Manager can create decision book", ) # Check decision book is valid for this token and building decision_book = BuildDecisionBook.filter_one( BuildDecisionBook.uu_id == data.build_decision_book_uu_id, BuildDecisionBook.build_id == token_dict.selected_occupant.build_id, ).data 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.filter_one( Build.id == token_dict.selected_occupant.build_id ).data # Check planned decision book date is valid if ( not system_arrow.get(data.planned_date).date() >= system_arrow.now().shift(days=1).date() ): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Planned date must be greater than today", ) # 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, decision_book_id=decision_book.id, decision_book_uu_id=str(decision_book.uu_id), invitation_type=str(decision_book.decision_type), living_part_count=occupant_building.livable_part_count, living_part_percentage=0.51, message=data.message, planned_date=str(system_arrow.get(data.planned_date)), planned_date_expires=planned_date_expires, expiry_ends=str(system_arrow.get(data.planned_date).shift(days=15).date()), ) book_invitation.save_and_confirm() # Get all the parts of the building that is occupant in token build_parts = BuildParts.filter_all( BuildParts.build_id == occupant_building.id, ) # Get all build living spaces that is found in building with distinct person id 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, detail="No living spaces found for the building", ) print( f"Tnvite UUID : {book_invitation.uu_id} Message : {data.message} Planned date : {data.planned_date}" ) # Send invitation to all the users as attend and update the manager as build manager attendance_occupant_type = OccupantTypes.filter_by_one( system=True, occupant_code="MT-ATT", occupant_category_type="MT" ).data manager_occupant_type = OccupantTypes.filter_by_one( system=True, occupant_code="BU-MNG", occupant_category_type="BU" ).data build_decision_book_person_dict = dict( build_decision_book_id=decision_book.id, build_decision_book_uu_id=str(decision_book.uu_id), invite_id=book_invitation.id, invite_uu_id=str(book_invitation.uu_id), send_date=str(system_arrow.now().date()), expiry_starts=decision_book.expiry_starts, expiry_ends=decision_book.expiry_ends, ) # Check if the invitation is already created at database for build_living_spaces_user in build_living_spaces_people: if invite := BuildDecisionBookPerson.filter_one( BuildDecisionBookPerson.invite_id == book_invitation.id, BuildDecisionBookPerson.build_living_space_id == build_living_spaces_user.id, ).data: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Invitation already send to {build_living_spaces_user.email} " f"for invite {invite.uu_id} date : {str(book_invitation.planned_date)}", ) invitations_person = BuildDecisionBookPerson.find_or_create( **build_decision_book_person_dict, build_living_space_id=build_living_spaces_user.id, build_living_space_uu_id=str(build_living_spaces_user.uu_id), person_id=build_living_spaces_user.person_id, token=Users.generate_token(40), ) invitations_person.save_and_confirm() invitations_person.add_occupant_type(occupant_type=attendance_occupant_type) if invitations_person: print(f'"{invitations_person.token}",') spaces_user = Users.filter_one( 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_all( BuildLivingSpace.person_id == token_dict.person_id, ) manager_people = BuildDecisionBookPerson.filter_all( BuildDecisionBookPerson.invite_id == book_invitation.id, BuildDecisionBookPerson.build_living_space_id.in_( [ manager_living_space.id for manager_living_space in manager_living_spaces.data ] ), system=True, ) manager_people_occupants = BuildDecisionBookPersonOccupants.filter_all( BuildDecisionBookPersonOccupants.build_decision_book_person_id == manager_people.get(1).id, system=True, ) if manager_people_occupants.count: manager_people_occupants.query.delete() BuildDecisionBookPersonOccupants.save() if manager_people.count: manager_people.query.delete() BuildDecisionBookPerson.save() if book_person_manager := BuildDecisionBookPerson.find_or_create( **build_decision_book_person_dict, build_living_space_id=token_dict.selected_occupant.living_space_id, build_living_space_uu_id=str( token_dict.selected_occupant.living_space_uu_id ), person_id=token_dict.person_id, token=Users.generate_token(40), ): book_person_manager.save_and_confirm() book_person_manager.add_occupant_type(occupant_type=manager_occupant_type) print(f"Manager Token : {book_person_manager.token}") BuildDecisionBookPerson.save() return JSONResponse( status_code=status.HTTP_200_OK, content={ "completed": True, "message": "Invitation are send to people related with building", "data": book_invitation.get_dict(), }, ) class BuildDecisionBookInvitationsUpdateEventMethods(MethodToEvent): event_type = "UPDATE" __event_keys__ = { "92413636-53a8-4a05-842c-1485a64e00d1": "decision_book_invitations_attend", } __event_validation__ = { "92413636-53a8-4a05-842c-1485a64e00d1": DecisionBookDecisionBookInvitationsUpdate } @classmethod def decision_book_invitations_attend( cls, data: DecisionBookDecisionBookInvitationsUpdate, token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], ): return BuildDecisionBookInvitationsListEventMethod = ( BuildDecisionBookInvitationsListEventMethods( action=ActionsSchema(endpoint="/build/decision_book/invite/list") ) ) BuildDecisionBookInvitationsCreateEventMethod = ( BuildDecisionBookInvitationsCreateEventMethods( action=ActionsSchema(endpoint="/build/decision_book/invite/create") ) ) BuildDecisionBookInvitationsUpdateEventMethod = ( BuildDecisionBookInvitationsUpdateEventMethods( action=ActionsSchema(endpoint="/build/decision_book/invite/update") ) )