first commit
This commit is contained in:
0
api_events/events/decision_book/__init__.py
Normal file
0
api_events/events/decision_book/__init__.py
Normal file
220
api_events/events/decision_book/decision_book_decision_book.py
Normal file
220
api_events/events/decision_book/decision_book_decision_book.py
Normal file
@@ -0,0 +1,220 @@
|
||||
import typing
|
||||
|
||||
from fastapi import status, HTTPException
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from databases import (
|
||||
Build,
|
||||
BuildDecisionBook,
|
||||
Companies,
|
||||
OccupantTypes,
|
||||
)
|
||||
|
||||
from validations import (
|
||||
InsertDecisionBook,
|
||||
ListOptions,
|
||||
)
|
||||
|
||||
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
|
||||
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject
|
||||
from api_validations.core_response import return_json_response_from_alchemy
|
||||
from api_library.date_time_actions.date_functions import DateTimeLocal
|
||||
|
||||
|
||||
class DecisionBookListEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "SELECT"
|
||||
__event_keys__ = {
|
||||
"5c10d6ae-2aee-4243-a7c3-94826d028d13": "building_decision_book_list",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def building_decision_book_list(
|
||||
cls,
|
||||
list_options: ListOptions,
|
||||
token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
|
||||
):
|
||||
records = []
|
||||
if isinstance(token_dict, EmployeeTokenObject):
|
||||
|
||||
build_id_list_query = Build.select_action(
|
||||
employee_id=token_dict.selected_company.employee_id
|
||||
)
|
||||
build_id_list = build_id_list_query.all()
|
||||
if not build_id_list:
|
||||
raise HTTPException(
|
||||
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(
|
||||
BuildDecisionBook.build_id.in_([build.id for build in build_id_list]),
|
||||
*BuildDecisionBook.get_smart_query(list_options.query),
|
||||
)
|
||||
elif isinstance(token_dict, OccupantTokenObject):
|
||||
records = BuildDecisionBook.filter_active(
|
||||
BuildDecisionBook.build_id == token_dict.selected_occupant.build_id,
|
||||
*BuildDecisionBook.get_smart_query(list_options.query),
|
||||
)
|
||||
return return_json_response_from_alchemy(
|
||||
response=records, pagination=list_options
|
||||
)
|
||||
|
||||
|
||||
class DecisionBookCreateEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "CREATE"
|
||||
__event_keys__ = {
|
||||
"0a68cb44-271a-4829-81f6-cd99a5f326b4": "building_decision_book_create",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def building_decision_book_create(
|
||||
cls,
|
||||
data: InsertDecisionBook,
|
||||
token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
|
||||
):
|
||||
data_dict = data.excluded_dump()
|
||||
if isinstance(token_dict, EmployeeTokenObject):
|
||||
Build.pre_query = Build.select_action(
|
||||
employee_id=token_dict.selected_company.employee_id
|
||||
)
|
||||
build = Build.filter_active(
|
||||
Build.uu_id == data.build_uu_id,
|
||||
)
|
||||
if not build.data:
|
||||
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
|
||||
if data.resp_company_uu_id:
|
||||
Companies.pre_query = Companies.select_action(
|
||||
duty_id_list=[
|
||||
token_dict.selected_company.duty_id,
|
||||
token_dict.selected_company.bulk_duties_id,
|
||||
]
|
||||
)
|
||||
company = Companies.filter_active(
|
||||
Companies.uu_id == data.resp_company_uu_id
|
||||
)
|
||||
if not company.data:
|
||||
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)
|
||||
|
||||
build_object = build.data[0]
|
||||
decision_period_date = DateTimeLocal.get(build_object.decision_period_date)
|
||||
data_dict["expiry_starts"] = DateTimeLocal.get(
|
||||
DateTimeLocal.now().date().year,
|
||||
int(decision_period_date.date().month),
|
||||
int(decision_period_date.date().day),
|
||||
)
|
||||
data_dict["expiry_ends"] = str(
|
||||
data_dict["expiry_starts"].shift(years=1, days=-1)
|
||||
)
|
||||
data_dict["expiry_starts"] = str(data_dict["expiry_starts"])
|
||||
build_decision_book = BuildDecisionBook.find_or_create(**data_dict)
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_200_OK,
|
||||
content=dict(
|
||||
message="Decision Book has created",
|
||||
completed=True,
|
||||
data=build_decision_book.get_dict(),
|
||||
),
|
||||
)
|
||||
elif isinstance(token_dict, OccupantTokenObject):
|
||||
occupant_manager = OccupantTypes.find_one(
|
||||
occupant_category_type="BU", occupant_code="BU-MNG"
|
||||
)
|
||||
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",
|
||||
)
|
||||
|
||||
occupant_build = Build.find_one(id=token_dict.selected_occupant.build_id)
|
||||
occupant_company = Companies.find_one(
|
||||
id=token_dict.selected_occupant.responsible_company_id
|
||||
)
|
||||
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(
|
||||
occupant_build.decision_period_date
|
||||
)
|
||||
data_dict["expiry_starts"] = DateTimeLocal.get(
|
||||
DateTimeLocal.now().date().year,
|
||||
int(decision_period_date.date().month),
|
||||
int(decision_period_date.date().day),
|
||||
)
|
||||
data_dict["expiry_ends"] = str(
|
||||
data_dict["expiry_starts"].shift(years=1, days=-1)
|
||||
)
|
||||
data_dict["expiry_starts"] = str(data_dict["expiry_starts"])
|
||||
build_decision_book = BuildDecisionBook.find_or_create(**data_dict)
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_200_OK,
|
||||
content=dict(
|
||||
message="Decision Book has created",
|
||||
completed=True,
|
||||
data=build_decision_book.get_dict(),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class DecisionBookUpdateEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "UPDATE"
|
||||
__event_keys__ = {
|
||||
"6bc7035c-3b53-4c0a-8cc9-1ec9c6af1e29": "building_decision_book_update",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def building_decision_book_update(cls, data: InsertDecisionBook, token_dict: dict):
|
||||
return
|
||||
|
||||
|
||||
class DecisionBookPatchEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "PATCH"
|
||||
__event_keys__ = {
|
||||
"7b58ed84-9a65-4588-994d-30df8366b050": "building_decision_book_patch",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def building_decision_book_patch(cls, data: InsertDecisionBook, token_dict: dict):
|
||||
return
|
||||
|
||||
|
||||
class DecisionBookApprovalEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "UPDATE"
|
||||
__event_keys__ = {
|
||||
"fc745142-3437-4ca2-89fa-c5a3e2b5c6c2": "building_decision_book_approval",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def building_decision_book_approval(cls, data, token_dict):
|
||||
return
|
||||
|
||||
|
||||
DecisionBookListEventMethod = DecisionBookListEventMethods(
|
||||
action=ActionsSchema(endpoint="/build/decision_book/list")
|
||||
)
|
||||
DecisionBookCreateEventMethod = DecisionBookCreateEventMethods(
|
||||
action=ActionsSchema(endpoint="/build/decision_book/create")
|
||||
)
|
||||
DecisionBookUpdateEventMethod = DecisionBookUpdateEventMethods(
|
||||
action=ActionsSchema(endpoint="/build/decision_book/update")
|
||||
)
|
||||
DecisionBookPatchEventMethod = DecisionBookPatchEventMethods(
|
||||
action=ActionsSchema(endpoint="/build/decision_book/patch")
|
||||
)
|
||||
DecisionBookApprovalEventMethod = DecisionBookApprovalEventMethods(
|
||||
action=ActionsSchema(endpoint="/build/decision_book/approval")
|
||||
)
|
||||
@@ -0,0 +1,473 @@
|
||||
import typing
|
||||
|
||||
from fastapi import status, HTTPException
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from databases import (
|
||||
Build,
|
||||
BuildParts,
|
||||
BuildDecisionBook,
|
||||
BuildDecisionBookItems,
|
||||
BuildDecisionBookPerson,
|
||||
BuildDecisionBookPayments,
|
||||
BuildDecisionBookProjects,
|
||||
BuildDecisionBookProjectPerson,
|
||||
ApiEnumDropdown,
|
||||
OccupantTypes,
|
||||
Companies,
|
||||
BuildLivingSpace,
|
||||
)
|
||||
|
||||
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
|
||||
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject
|
||||
from api_validations.core_response import return_json_response_from_alchemy
|
||||
from api_library.date_time_actions.date_functions import DateTimeLocal
|
||||
|
||||
from validations import (
|
||||
InsertBuildDecisionBookItems,
|
||||
ListDecisionBook,
|
||||
)
|
||||
|
||||
|
||||
class DecisionBookDecisionBookItemsListEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "SELECT"
|
||||
__event_keys__ = {
|
||||
"eb36de59-8268-4d96-80b6-5d01c12bf0b1": "building_decision_book_items_list",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def building_decision_book_items_list(
|
||||
cls,
|
||||
data: ListDecisionBook,
|
||||
token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
|
||||
):
|
||||
decision_book = BuildDecisionBook.find_one(uu_id=data.build_decision_book_uu_id)
|
||||
if not decision_book:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"No Decision Book is match with given UUID {data.build_decision_book_uu_id}",
|
||||
)
|
||||
if isinstance(token_dict, EmployeeTokenObject):
|
||||
Build.pre_query = Build.select_action(
|
||||
employee_id=token_dict.selected_company.employee_id,
|
||||
filter_expr=[
|
||||
Build.uu_id == decision_book.build_decision_book_uu_id,
|
||||
],
|
||||
)
|
||||
reachable_building = Build.filter_active()
|
||||
if not reachable_building.data:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"No building is match with given Employee UUID {token_dict.selected_company.employee_uu_id}",
|
||||
)
|
||||
|
||||
Companies.pre_query = Companies.select_action(
|
||||
duty_id_list=[
|
||||
token_dict.selected_company.duty_id,
|
||||
token_dict.selected_company.bulk_duties_id,
|
||||
],
|
||||
filter_expr=[Companies.id == decision_book.company_id],
|
||||
)
|
||||
reachable_companies = Companies.filter_active()
|
||||
if not reachable_companies.data:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"No company is match with given Employee UUID {token_dict.selected_company.employee_uu_id}",
|
||||
)
|
||||
|
||||
records = BuildDecisionBookItems.filter_active(
|
||||
BuildDecisionBookItems.build_decision_book_id == decision_book.id
|
||||
)
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_200_OK,
|
||||
content=dict(
|
||||
total_count=records.count,
|
||||
count=len(records.data),
|
||||
message=f"Decision Book Items has found from given Decision Book UUID {data.build_decision_book_uu_id}",
|
||||
completed=True,
|
||||
data=[record.get_dict() for record in records.data],
|
||||
),
|
||||
)
|
||||
else:
|
||||
# BuildDecisionBookItems.pre_query = BuildDecisionBookItems.select_action(
|
||||
# occupant_id=token_dict.occupant_list["occupant_id"]
|
||||
# )
|
||||
# records = BuildDecisionBookItems.filter_active(
|
||||
# *BuildDecisionBookItems.get_smart_query(list_options.query)
|
||||
# )
|
||||
# return return_json_response_from_alchemy(response=records, pagination=list_options)
|
||||
return
|
||||
|
||||
|
||||
class DecisionBookDecisionBookItemsCreateEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "CREATE"
|
||||
__event_keys__ = {
|
||||
"dce10509-0da5-46fb-af3c-a81d54d5481c": "building_decision_book_items_create",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def iterate_over_build_parts(
|
||||
cls,
|
||||
build_parts_list,
|
||||
payment_types,
|
||||
local_date,
|
||||
end_date,
|
||||
unit_price,
|
||||
unit_type,
|
||||
book_payment_dict,
|
||||
unit_price_is_fixed
|
||||
):
|
||||
start_date, payment_return_dict = local_date, {}
|
||||
for build_part_single in build_parts_list:
|
||||
local_date = start_date
|
||||
while local_date.is_between(start_date, end_date, "[]"):
|
||||
local_date = DateTimeLocal.find_last_day_of_month(local_date)
|
||||
payment_amount = unit_price
|
||||
if not unit_price_is_fixed:
|
||||
unit_amount = str(build_part_single.due_part_key).replace(" ", "")
|
||||
unit_amount = unit_amount.replace(str(unit_type).upper(), "")
|
||||
payment_amount = abs(unit_price * float(unit_amount)) * -1
|
||||
payment_amount = -1 * (abs(payment_amount) + (50 - float(abs(payment_amount)) % 50))
|
||||
BuildDecisionBookPayments.create(
|
||||
build_parts_id=build_part_single.id,
|
||||
build_parts_uu_id=str(build_part_single.uu_id),
|
||||
payment_amount=payment_amount,
|
||||
payment_types_id=payment_types.id,
|
||||
payment_types_uu_id=str(payment_types.uu_id),
|
||||
process_date=str(local_date),
|
||||
process_date_m=int(local_date.month),
|
||||
process_date_y=int(local_date.year),
|
||||
period_time=f"{local_date.year}-{str(local_date.month).zfill(2)}",
|
||||
**book_payment_dict
|
||||
)
|
||||
local_date = local_date.shift(days=2)
|
||||
part_key = str(build_part_single.due_part_key).upper()
|
||||
if part_key not in payment_return_dict:
|
||||
payment_return_dict[part_key] = payment_amount
|
||||
|
||||
return payment_return_dict
|
||||
|
||||
@classmethod
|
||||
def create_payment_records_for_each_build_part(
|
||||
cls,
|
||||
data_info_type,
|
||||
build_id,
|
||||
unit_price,
|
||||
unit_type,
|
||||
decision_book,
|
||||
decision_book_item,
|
||||
unit_price_is_fixed,
|
||||
currency,
|
||||
debit_start_date: str = None,
|
||||
debit_end_date: str = None,
|
||||
):
|
||||
build_parts_list = BuildParts.filter_active(
|
||||
BuildParts.human_livable == True,
|
||||
BuildParts.build_id == build_id,
|
||||
)
|
||||
book_payment_dict = dict(
|
||||
payment_plan_time_periods=str(data_info_type.key),
|
||||
build_decision_book_item_id=decision_book_item.id,
|
||||
build_decision_book_item_uu_id=str(decision_book_item.uu_id),
|
||||
is_confirmed=True,
|
||||
currency=currency,
|
||||
)
|
||||
payment_types = ApiEnumDropdown.get_debit_search(search_debit="DT-D")
|
||||
if data_info_type.key == "BDT-D":
|
||||
local_date = DateTimeLocal.get(DateTimeLocal.get(decision_book.expiry_starts).date())
|
||||
end_date = DateTimeLocal.get(DateTimeLocal.get(decision_book.expiry_ends).date())
|
||||
return cls.iterate_over_build_parts(
|
||||
build_parts_list=build_parts_list.data,
|
||||
payment_types=payment_types,
|
||||
local_date=local_date,
|
||||
end_date=end_date,
|
||||
unit_price=unit_price,
|
||||
unit_type=unit_type,
|
||||
unit_price_is_fixed=unit_price_is_fixed,
|
||||
book_payment_dict=book_payment_dict,
|
||||
)
|
||||
elif data_info_type.key == "BDT-A":
|
||||
local_date = DateTimeLocal.get(DateTimeLocal.get(debit_start_date).date())
|
||||
end_date = DateTimeLocal.get(DateTimeLocal.get(debit_end_date).date())
|
||||
return cls.iterate_over_build_parts(
|
||||
build_parts_list=build_parts_list.data,
|
||||
payment_types=payment_types,
|
||||
local_date=local_date,
|
||||
end_date=end_date,
|
||||
unit_price=unit_price,
|
||||
unit_type=unit_type,
|
||||
unit_price_is_fixed=unit_price_is_fixed,
|
||||
book_payment_dict=book_payment_dict,
|
||||
)
|
||||
elif data_info_type.key == "BDT-R" or data_info_type.key == "BDT-L":
|
||||
local_date = DateTimeLocal.get(DateTimeLocal.get(debit_start_date).date())
|
||||
end_date = DateTimeLocal.get(DateTimeLocal.get(debit_end_date).date())
|
||||
decision_date = DateTimeLocal.get(decision_book.expiry_starts).date()
|
||||
meeting_date = DateTimeLocal.get(decision_book.meeting_date).date()
|
||||
|
||||
already_book_projects = BuildDecisionBookProjects.filter_all(
|
||||
BuildDecisionBookProjects.build_decision_book_id==decision_book.id,
|
||||
BuildDecisionBookProjects.project_type==f"{decision_book.decision_type}_{data_info_type.key}",
|
||||
)
|
||||
management_room = BuildParts.find_one(
|
||||
build_id=build_id, part_no=0, active=True, is_confirmed=True
|
||||
)
|
||||
occupant_man = OccupantTypes.find_one(
|
||||
occupant_code="MT-VPR", occupant_category_type="MT"
|
||||
)
|
||||
manager_living_space = BuildLivingSpace.filter_by_active(
|
||||
build_parts_id=management_room.id, occupant_type=occupant_man.id,
|
||||
)
|
||||
if not manager_living_space.data:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"{occupant_man.occupant_description} Living Space is not found. Check manager living space and try again",
|
||||
)
|
||||
already_book_project_count = already_book_projects.count + 1
|
||||
manager_living_space = manager_living_space.get(1)
|
||||
book_project_dict = dict(
|
||||
project_no=f"{data_info_type.key}_{decision_date.year}_{already_book_project_count}",
|
||||
project_name=f"{str(meeting_date)}_{decision_book.decision_type} Project {already_book_projects.count + 1}",
|
||||
project_start_date=str(local_date),
|
||||
project_stop_date=str(end_date),
|
||||
project_type=f"{decision_book.decision_type}_{data_info_type.key}",
|
||||
project_note=f"Fill later",
|
||||
build_decision_book_id=decision_book.id,
|
||||
build_decision_book_uu_id=str(decision_book.uu_id),
|
||||
build_decision_book_item_id=decision_book_item.id,
|
||||
build_decision_book_item_uu_id=str(decision_book_item.uu_id),
|
||||
project_response_living_space_id=manager_living_space.id,
|
||||
project_response_living_space_uu_id=str(manager_living_space.uu_id),
|
||||
)
|
||||
book_project_created = BuildDecisionBookProjects.find_or_create(**book_project_dict)
|
||||
if not book_project_created.is_found:
|
||||
decision_book_item.update(
|
||||
item_comment=f"{book_project_created.project_no}_{book_project_created.project_name} "
|
||||
f"is assigned to {occupant_man.occupant_description}"
|
||||
)
|
||||
project_lead = ApiEnumDropdown.find_one(
|
||||
key="PTT-LDR", enum_class="ProjectTeamTypes"
|
||||
)
|
||||
project_person = BuildDecisionBookProjectPerson.find_or_create(
|
||||
build_decision_book_project_id=book_project_created.id,
|
||||
build_decision_book_project_uu_id=str(book_project_created.uu_id),
|
||||
living_space_id=manager_living_space.id,
|
||||
living_space_uu_id=str(manager_living_space.uu_id),
|
||||
project_team_type_id=project_lead.id,
|
||||
project_team_type_uu_id=str(project_lead.uu_id),
|
||||
)
|
||||
|
||||
elif data_info_type.key == "BDT-SF":
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="BDT-SF is not implemented yet. Check info type and try again",
|
||||
)
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Payment Info Type is not valid. Check payment type and try again",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def building_decision_book_items_create(
|
||||
cls,
|
||||
data: InsertBuildDecisionBookItems,
|
||||
token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
|
||||
):
|
||||
|
||||
if isinstance(token_dict, EmployeeTokenObject):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_406_NOT_ACCEPTABLE,
|
||||
detail="No employee can reach this event. An notification is send to admin about event registration",
|
||||
)
|
||||
elif isinstance(token_dict, OccupantTokenObject):
|
||||
data_dict = data.dump()
|
||||
occupant_wrt = OccupantTypes.find_one(
|
||||
occupant_code="MT-WRT", occupant_category_type="MT"
|
||||
)
|
||||
|
||||
if token_dict.selected_occupant.occupant_type_id != occupant_wrt.id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Only WRITER can create decision book item. Check your occupant type and try again",
|
||||
)
|
||||
|
||||
decision_book_person = BuildDecisionBookPerson.find_one(token=data.token)
|
||||
decision_book = BuildDecisionBook.find_one(
|
||||
id=decision_book_person.build_decision_book_id
|
||||
)
|
||||
BuildDecisionBookItems.check_meeting_is_valid_to_start_add_attendance(
|
||||
decision_book=decision_book,
|
||||
token_dict=token_dict,
|
||||
)
|
||||
book_items = BuildDecisionBookItems.filter_active(
|
||||
BuildDecisionBookItems.build_decision_book_id == decision_book.id,
|
||||
)
|
||||
|
||||
data_dict["item_order"] = int(book_items.count) + 1
|
||||
data_dict["build_decision_book_id"] = decision_book.id
|
||||
data_dict["build_decision_book_uu_id"] = str(decision_book.uu_id)
|
||||
data_dict["is_confirmed"] = True
|
||||
|
||||
data_info_types, data_info_type = ApiEnumDropdown.due_type_search(), None
|
||||
for info_type in data_info_types:
|
||||
if str(info_type.uu_id) == data_dict["info_type_uu_id"]:
|
||||
data_info_type = info_type
|
||||
break
|
||||
if not data_info_type:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Info Type is not valid. Check info type and try again",
|
||||
)
|
||||
|
||||
if str(data_info_type.key).upper() in ["BDT-A", "BDT-R", "BDT-L", "BDT-SF"]:
|
||||
if not data_dict["debit_start_date"] or not data_dict["debit_end_date"]:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Debit Start Date and Debit End Date is required for this payment type. "
|
||||
"Check debit start date and debit end date and try again",
|
||||
)
|
||||
|
||||
data_dict["info_type_id"] = data_info_type.id
|
||||
data_dict["info_type_uu_id"] = str(data_info_type.uu_id)
|
||||
unit_price, unit_type = float(data_dict["unit_price"]), str(data_dict["unit_type"])
|
||||
debit_start_date, debit_end_date = data_dict["debit_start_date"], data_dict["debit_end_date"]
|
||||
currency = data_dict["currency"]
|
||||
del (
|
||||
data_dict["token"],
|
||||
data_dict["unit_price"],
|
||||
data_dict["unit_type"],
|
||||
data_dict["unit_price_is_fixed"],
|
||||
data_dict["debit_start_date"],
|
||||
data_dict["debit_end_date"],
|
||||
data_dict["currency"]
|
||||
)
|
||||
|
||||
if new_decision_book_item := BuildDecisionBookItems.find_or_create(**data_dict):
|
||||
if new_decision_book_item.is_found:
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_200_OK,
|
||||
content=dict(
|
||||
message=f"Decision Book Item is already exist for given Decision Book UUID {decision_book.uu_id}",
|
||||
completed=True,
|
||||
data=new_decision_book_item.get_dict(),
|
||||
),
|
||||
)
|
||||
if created_payment_records_dict := cls.create_payment_records_for_each_build_part(
|
||||
data_info_type=data_info_type,
|
||||
build_id=decision_book.build_id,
|
||||
unit_price=unit_price,
|
||||
unit_type=unit_type.upper(),
|
||||
decision_book=decision_book,
|
||||
decision_book_item=new_decision_book_item,
|
||||
unit_price_is_fixed=data.unit_price_is_fixed,
|
||||
debit_start_date=debit_start_date,
|
||||
debit_end_date=debit_end_date,
|
||||
currency=currency
|
||||
):
|
||||
if data_info_type.key == "BDT-A" or data_info_type.key == "BDT-D":
|
||||
if data_info_type.key == "BDT-D":
|
||||
item_comment = "Regular Payment Plan : "
|
||||
else:
|
||||
item_comment = "Additional Payment Plan : "
|
||||
for key, value in dict(sorted(
|
||||
created_payment_records_dict.items(),
|
||||
key=lambda x: x[1],
|
||||
reverse=True
|
||||
)).items():
|
||||
item_comment += f" {key} | {abs(float(value))} {currency}, "
|
||||
item_comment = item_comment[:-2]
|
||||
new_decision_book_item.update(
|
||||
item_comment=item_comment
|
||||
)
|
||||
new_decision_book_item.update(is_payment_created=True)
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_200_OK,
|
||||
content=dict(
|
||||
message=f"Decision Book Item has created for given Decision Book UUID {decision_book.uu_id}",
|
||||
completed=True,
|
||||
data=new_decision_book_item.get_dict(),
|
||||
),
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Decision Book Item is not created. Check info type and info no and try again. Unique constraint index is implemented for info type and info no",
|
||||
)
|
||||
|
||||
|
||||
class DecisionBookDecisionBookItemsUpdateEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "UPDATE"
|
||||
__event_keys__ = {
|
||||
"f0fdfe1b-806b-4175-ad50-a1a165c0dfb7": "building_decision_book_items_update",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def building_decision_book_items_update(
|
||||
cls,
|
||||
data: InsertBuildDecisionBookItems,
|
||||
token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
|
||||
):
|
||||
return
|
||||
|
||||
|
||||
class DecisionBookDecisionBookItemsPatchEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "PATCH"
|
||||
__event_keys__ = {
|
||||
"42328809-b516-477b-82cc-2d6fadf28843": "building_decision_book_items_patch",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def building_decision_book_items_patch(
|
||||
cls,
|
||||
data: InsertBuildDecisionBookItems,
|
||||
token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
|
||||
):
|
||||
return
|
||||
|
||||
|
||||
DecisionBookDecisionBookItemsListEventMethod = (
|
||||
DecisionBookDecisionBookItemsListEventMethods(
|
||||
action=ActionsSchema(endpoint="/build/decision_book/items/list")
|
||||
)
|
||||
)
|
||||
DecisionBookDecisionBookItemsCreateEventMethod = (
|
||||
DecisionBookDecisionBookItemsCreateEventMethods(
|
||||
action=ActionsSchema(endpoint="/build/decision_book/items/create")
|
||||
)
|
||||
)
|
||||
DecisionBookDecisionBookItemsUpdateEventMethod = (
|
||||
DecisionBookDecisionBookItemsUpdateEventMethods(
|
||||
action=ActionsSchema(endpoint="/build/decision_book/items/update")
|
||||
)
|
||||
)
|
||||
DecisionBookDecisionBookItemsPatchEventMethod = (
|
||||
DecisionBookDecisionBookItemsPatchEventMethods(
|
||||
action=ActionsSchema(endpoint="/build/decision_book/items/patch")
|
||||
)
|
||||
)
|
||||
|
||||
# if data.info_no is None:
|
||||
# data_dict["info_no"] = data_dict["item_order"]
|
||||
# elif data.occupant_types_uu_id:
|
||||
# data_dict["info_type"] = None
|
||||
# if occupant_type := OccupantTypes.find_one(
|
||||
# uu_id=data.occupant_types_uu_id
|
||||
# ):
|
||||
# if (
|
||||
# str(data.occupant_types_uu_id)
|
||||
# in OccupantTypes.get_manager_occupant_type()
|
||||
# ):
|
||||
# if BuildDecisionBookItems.find_one(
|
||||
# build_decision_book_id=decision_book.id,
|
||||
# occupant_type=occupant_type.id,
|
||||
# ):
|
||||
# raise HTTPException(
|
||||
# status_code=status.HTTP_400_BAD_REQUEST,
|
||||
# detail="This Occupant Type is already exist for given Decision Book UUID. Check occupant type and try again",
|
||||
# )
|
||||
# data_dict["occupant_type"] = occupant_type.id
|
||||
# data_dict["occupant_type_uu_id"] = str(occupant_type.uu_id)
|
||||
@@ -0,0 +1,5 @@
|
||||
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
|
||||
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject
|
||||
|
||||
|
||||
class DecisionBookDecisionBookItemsDebitsEvents(MethodToEvent): ...
|
||||
@@ -0,0 +1,443 @@
|
||||
import typing
|
||||
|
||||
from fastapi import status, HTTPException
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from databases import (
|
||||
BuildDecisionBook,
|
||||
BuildDecisionBookPerson,
|
||||
BuildDecisionBookInvitations,
|
||||
Users,
|
||||
BuildLivingSpace,
|
||||
BuildParts,
|
||||
BuildDecisionBookPersonOccupants,
|
||||
People,
|
||||
OccupantTypes,
|
||||
)
|
||||
|
||||
from api_validations import (
|
||||
ListOptions,
|
||||
RemoveDecisionBookPerson,
|
||||
DecisionBookDecisionBookInvitationsAttend,
|
||||
DecisionBookDecisionBookInvitationsUpdate,
|
||||
DecisionBookDecisionBookInvitationsAssign,
|
||||
)
|
||||
|
||||
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
|
||||
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject
|
||||
from api_validations.core_response import return_json_response_from_alchemy
|
||||
|
||||
|
||||
class DecisionBookPersonListEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "SELECT"
|
||||
__event_keys__ = {
|
||||
"ea324dc0-3b08-4896-9040-7fa0401a176f": "building_decision_book_person_list",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def building_decision_book_person_list(
|
||||
cls, data: ListOptions, token_dict: EmployeeTokenObject
|
||||
):
|
||||
return
|
||||
|
||||
|
||||
class DecisionBookPersonAddEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "CREATE"
|
||||
__event_keys__ = {
|
||||
"e346f720-880b-4b07-93d6-9ac76fbbaa33": "building_decision_book_person_add",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def building_decision_book_person_add(
|
||||
cls,
|
||||
data: DecisionBookDecisionBookInvitationsUpdate,
|
||||
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",
|
||||
)
|
||||
elif isinstance(token_dict, OccupantTokenObject):
|
||||
decision_book = BuildDecisionBook.find_one(
|
||||
uu_id=data.build_decision_book_uu_id
|
||||
)
|
||||
if not decision_book:
|
||||
raise HTTPException(
|
||||
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(
|
||||
occupant_code="BU-MNG", occupant_category_type="BU"
|
||||
)
|
||||
if (
|
||||
not manager_occupant_type.uu_id
|
||||
== token_dict.selected_occupant.occupant_type_uu_id
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Only Build Manager can update the invitation",
|
||||
)
|
||||
|
||||
assign_occupant_type = OccupantTypes.find_or_abort(
|
||||
uu_id=data.occupant_type_uu_id,
|
||||
occupant_category_type="MT",
|
||||
)
|
||||
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,
|
||||
)
|
||||
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,
|
||||
)
|
||||
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,
|
||||
)
|
||||
if not selected_book_person:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Selected person is not in the invitation list. Please check {data.person_uu_id}",
|
||||
)
|
||||
selected_book_person.update(
|
||||
occupant_type=assign_occupant_type.id,
|
||||
occupant_type_uu_id=str(assign_occupant_type.uu_id),
|
||||
)
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_200_OK,
|
||||
content={
|
||||
"completed": True,
|
||||
"message": "Invitation is updated",
|
||||
"data": selected_book_person.get_dict(),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class DecisionBookPersonRemoveEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "DELETE"
|
||||
__event_keys__ = {
|
||||
"30588869-04cd-48ea-ad00-0e4f8dd7f735": "building_decision_book_people_remove",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def building_decision_book_people_remove(
|
||||
cls, data: RemoveDecisionBookPerson, token_dict: EmployeeTokenObject
|
||||
):
|
||||
return
|
||||
|
||||
|
||||
class DecisionBookPersonAttendEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "UPDATE"
|
||||
__event_keys__ = {
|
||||
"bdcba521-0116-441c-ace1-84c5b68c86c7": "decision_book_invitations_attend",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def decision_book_invitations_attend(
|
||||
cls,
|
||||
data: DecisionBookDecisionBookInvitationsAttend,
|
||||
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",
|
||||
)
|
||||
|
||||
token_user = Users.find_one(id=token_dict.user_id)
|
||||
invitation_person = BuildDecisionBookPerson.find_one(
|
||||
token=data.token, active=True, is_confirmed=True
|
||||
)
|
||||
if not invitation_person:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Invitation for the this specific user is not found. Please check token",
|
||||
)
|
||||
|
||||
# is_token_valid = token_dict.person_id == invitation_person.person_id
|
||||
# if not invitation_person.vicarious_person_id:
|
||||
# if not invitation_person or not is_token_valid:
|
||||
# raise HTTPException(
|
||||
# status_code=status.HTTP_404_NOT_FOUND,
|
||||
# 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,
|
||||
)
|
||||
if not invitation:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Invitation not found. Please check invitation uuid : {invitation.uu_id}",
|
||||
)
|
||||
invitation_person.update(
|
||||
is_attending=bool(data.is_attend), vicarious_person_id=None
|
||||
)
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_200_OK,
|
||||
content={
|
||||
"completed": True,
|
||||
"message": "Attendance is updated. Thank you for your response",
|
||||
"data": {
|
||||
"is_attending": bool(data.is_attend),
|
||||
"user_uuid": str(token_user.uu_id),
|
||||
"invitation_uuid": str(invitation.uu_id),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class DecisionBookPersonAssignOccupantEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "UPDATE"
|
||||
__event_keys__ = {
|
||||
"c0b65098-9c79-4212-b1d0-c7e7836cf141": "decision_book_invitations_assign_occupant",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def decision_book_invitations_assign_occupant(
|
||||
cls,
|
||||
data: DecisionBookDecisionBookInvitationsAssign,
|
||||
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",
|
||||
)
|
||||
|
||||
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(
|
||||
occupant_code="BU-MNG", occupant_category_type="BU"
|
||||
)
|
||||
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,
|
||||
)
|
||||
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
|
||||
)
|
||||
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(
|
||||
BuildParts.build_id == token_dict.selected_occupant.build_id,
|
||||
)
|
||||
selected_living_space = BuildLivingSpace.filter_active(
|
||||
BuildLivingSpace.uu_id == data.build_living_space_uu_id,
|
||||
BuildLivingSpace.build_parts_id.in_(
|
||||
[build.id for build in build_parts_of_token.data]
|
||||
),
|
||||
)
|
||||
|
||||
if not selected_living_space.data:
|
||||
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,
|
||||
)
|
||||
)
|
||||
if not book_person_to_assign:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Person not found in the invitation list. Please check person uuid: {data.person_uu_id}",
|
||||
)
|
||||
if not book_person_to_assign.is_attending:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"Person is declined the invitation. This person is not attending the meeting. "
|
||||
f"Please check person uuid: {data.person_uu_id}. Invite UUID: {invitation.uu_id}",
|
||||
)
|
||||
|
||||
if assign_occupant_type.occupant_code in ("MT-PRS", "MT-WRT"):
|
||||
occupant_type_unique = OccupantTypes.find_or_abort(
|
||||
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,
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"Only one person can be assigned to {assign_occupant_type.occupant_code} type"
|
||||
f" {assigned_book_person_occupant.uu_id} is already assigned",
|
||||
)
|
||||
|
||||
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.delete(destroy=True)
|
||||
|
||||
book_person_to_assign.add_occupant_type(
|
||||
occupant_type=assign_occupant_type,
|
||||
build_living_space_id=selected_living_space.id,
|
||||
)
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_200_OK,
|
||||
content={
|
||||
"completed": True,
|
||||
"message": "Invitation is updated",
|
||||
"data": book_person_to_assign.get_dict(),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
DecisionBookPersonListEventMethod = DecisionBookPersonListEventMethods(
|
||||
action=ActionsSchema(endpoint="/build/decision_book/people/list")
|
||||
)
|
||||
DecisionBookPersonAddEventMethod = DecisionBookPersonAddEventMethods(
|
||||
action=ActionsSchema(endpoint="/build/decision_book/people/add")
|
||||
)
|
||||
DecisionBookPersonRemoveEventMethod = DecisionBookPersonRemoveEventMethods(
|
||||
action=ActionsSchema(endpoint="/build/decision_book/people/remove")
|
||||
)
|
||||
DecisionBookPersonAttendEventMethod = DecisionBookPersonAttendEventMethods(
|
||||
action=ActionsSchema(endpoint="/build/decision_book/invitations/attend")
|
||||
)
|
||||
DecisionBookPersonAssignOccupantEventMethod = (
|
||||
DecisionBookPersonAssignOccupantEventMethods(
|
||||
action=ActionsSchema(endpoint="/build/decision_book/invitations/assign")
|
||||
)
|
||||
)
|
||||
|
||||
# Build.pre_query = Build.select_action(
|
||||
# employee_id=token_dict.selected_company.employee_id,
|
||||
# filter_expr=[
|
||||
# Build.id == decision_book.build_id,
|
||||
# ],
|
||||
# )
|
||||
# reachable_building = Build.filter_active()
|
||||
# if not reachable_building.data:
|
||||
# raise HTTPException(
|
||||
# status_code=status.HTTP_404_NOT_FOUND,
|
||||
# detail=f"No building is match with given Employee UUID {token_dict.selected_company.employee_uu_id}",
|
||||
# )
|
||||
#
|
||||
# Companies.pre_query = Companies.select_action(
|
||||
# duty_id_list=[
|
||||
# token_dict.selected_company.duty_id,
|
||||
# token_dict.selected_company.bulk_duties_id,
|
||||
# ],
|
||||
# filter_expr=[Companies.id == decision_book.resp_company_id],
|
||||
# )
|
||||
# reachable_companies = Companies.filter_active()
|
||||
# if not reachable_companies.data:
|
||||
# raise HTTPException(
|
||||
# status_code=status.HTTP_404_NOT_FOUND,
|
||||
# detail=f"No company is match with given Employee UUID {token_dict.selected_company.employee_uu_id}",
|
||||
# )
|
||||
# person_to_add = People.find_one(uu_id=data.person_uu_id)
|
||||
# if not person_to_add:
|
||||
# raise HTTPException(
|
||||
# status_code=status.HTTP_404_NOT_FOUND,
|
||||
# detail=f"No person is match with given UUID {data.person_uu_id}",
|
||||
# )
|
||||
# management_typecode = ApiEnumDropdown.filter_active(
|
||||
# ApiEnumDropdown.uu_id == data.management_typecode_uu_id,
|
||||
# ApiEnumDropdown.enum_class.in_("BuildManagementType", "BuildDuesTypes"),
|
||||
# )
|
||||
# if not management_typecode.data:
|
||||
# raise HTTPException(
|
||||
# status_code=status.HTTP_404_NOT_FOUND,
|
||||
# detail=f"No management type is match with given UUID {data.management_typecode_uu_id}",
|
||||
# )
|
||||
# condition_to_met = (
|
||||
# data.management_typecode_uu_id
|
||||
# in ApiEnumDropdown.get_management_type_codes_list()
|
||||
# )
|
||||
# any_type_already = BuildDecisionBookPerson.find_one(
|
||||
# build_decision_book_id=decision_book.id,
|
||||
# management_typecode=data.management_typecode_uu_id,
|
||||
# )
|
||||
# if condition_to_met and any_type_already:
|
||||
# raise HTTPException(
|
||||
# status_code=status.HTTP_400_BAD_REQUEST,
|
||||
# detail=f"Management type is already exist in given Decision Book UUID {data.build_decision_book_uu_id}.",
|
||||
# )
|
||||
#
|
||||
# data_dict.pop("build_decision_book_uu_id", None)
|
||||
# data_dict.pop("person_uu_id", None)
|
||||
# data_dict["management_typecode"] = data_dict.pop(
|
||||
# "management_typecode_uu_id", None
|
||||
# )
|
||||
# data_dict["build_decision_book_id"] = decision_book.id
|
||||
# data_dict["person_id"] = person_to_add.id
|
||||
#
|
||||
# created = BuildDecisionBookPerson.find_or_create(**data_dict)
|
||||
# if created.is_found:
|
||||
# raise HTTPException(
|
||||
# status_code=status.HTTP_400_BAD_REQUEST,
|
||||
# detail=f"Decision Book Person is already exist in given Decision Book UUID {data.build_decision_book_uu_id}.",
|
||||
# )
|
||||
# return JSONResponse(
|
||||
# status_code=status.HTTP_200_OK,
|
||||
# content=dict(
|
||||
# message=f"Decision Book Person has added for given Decision Book UUID {data.build_decision_book_uu_id}",
|
||||
# completed=True,
|
||||
# data=created.get_dict(),
|
||||
# ),
|
||||
# )
|
||||
286
api_events/events/decision_book/decision_book_invitations.py
Normal file
286
api_events/events/decision_book/decision_book_invitations.py
Normal file
@@ -0,0 +1,286 @@
|
||||
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 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 return_json_response_from_alchemy
|
||||
from api_library.date_time_actions.date_functions import DateTimeLocal
|
||||
|
||||
|
||||
class BuildDecisionBookInvitationsListEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "SELECT"
|
||||
__event_keys__ = {
|
||||
"e2277528-8c9c-4c0c-ae64-3ce80cae664b": "decision_book_invitations_list",
|
||||
}
|
||||
|
||||
@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",
|
||||
}
|
||||
|
||||
@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.find_one(
|
||||
occupant_category_type="BU", occupant_code="BU-MNG"
|
||||
)
|
||||
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.find_one(
|
||||
uu_id=data.build_decision_book_uu_id,
|
||||
build_id=token_dict.selected_occupant.build_id,
|
||||
)
|
||||
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)
|
||||
|
||||
# Check meeting type is valid
|
||||
meeting_type = ApiEnumDropdown.find_one(
|
||||
enum_class="MeetingTypes",
|
||||
)
|
||||
if not meeting_type:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Meeting type not found",
|
||||
)
|
||||
|
||||
# Check planned decision book date is valid
|
||||
if (
|
||||
not DateTimeLocal.get(data.planned_date).date()
|
||||
>= DateTimeLocal.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
|
||||
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=meeting_type.key,
|
||||
living_part_count=occupant_building.livable_part_count,
|
||||
living_part_percentage=0.51,
|
||||
message=data.message,
|
||||
planned_date=data.planned_date,
|
||||
planned_date_expires=str(
|
||||
DateTimeLocal.get(data.planned_date).shift(days=15).date()
|
||||
),
|
||||
expiry_ends=str(DateTimeLocal.get(data.planned_date).shift(days=15).date()),
|
||||
is_confirmed=True,
|
||||
)
|
||||
if book_invitation.is_found:
|
||||
detail_message = (
|
||||
f"Invitation with: {str(book_invitation.planned_date)} already exists"
|
||||
f" for {book_invitation.invitation_type}"
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=detail_message,
|
||||
)
|
||||
|
||||
# Get all the parts of the building that is occupant in token
|
||||
build_parts = BuildParts.filter_active(
|
||||
BuildParts.build_id == occupant_building.id
|
||||
)
|
||||
|
||||
# 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()
|
||||
)
|
||||
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.find_or_abort(
|
||||
occupant_code="MT-ATT", occupant_category_type="MT"
|
||||
)
|
||||
manager_occupant_type = OccupantTypes.find_or_abort(
|
||||
occupant_code="BU-MNG", occupant_category_type="BU"
|
||||
)
|
||||
|
||||
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(DateTimeLocal.now().date()),
|
||||
expiry_starts=decision_book.expiry_starts,
|
||||
expiry_ends=decision_book.expiry_ends,
|
||||
is_confirmed=True,
|
||||
)
|
||||
# Check if the invitation is already created at database
|
||||
for build_living_spaces_user in build_living_spaces_people:
|
||||
if invite := BuildDecisionBookPerson.find_one(
|
||||
invite_id=book_invitation.id,
|
||||
build_living_space_id=build_living_spaces_user.id,
|
||||
):
|
||||
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.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,
|
||||
)
|
||||
# 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(
|
||||
BuildLivingSpace.person_id == token_dict.person_id,
|
||||
)
|
||||
manager_people = BuildDecisionBookPerson.filter_active(
|
||||
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
|
||||
]
|
||||
),
|
||||
)
|
||||
manager_people_occupants = BuildDecisionBookPersonOccupants.filter_active(
|
||||
BuildDecisionBookPersonOccupants.build_decision_book_person_id
|
||||
== manager_people.get(1).id
|
||||
)
|
||||
dlt = [
|
||||
occupants.delete(destroy=True)
|
||||
for occupants in manager_people_occupants.data
|
||||
]
|
||||
dlt = [occupants.delete(destroy=True) for occupants in manager_people.data]
|
||||
|
||||
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.add_occupant_type(occupant_type=manager_occupant_type)
|
||||
print(f"Manager Token : {book_person_manager.token}")
|
||||
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",
|
||||
}
|
||||
|
||||
@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")
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,6 @@
|
||||
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
|
||||
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject
|
||||
from api_validations.core_response import return_json_response_from_alchemy
|
||||
|
||||
|
||||
class ProjectDecisionBookProjectDecisionBookEvents(MethodToEvent): ...
|
||||
@@ -0,0 +1,6 @@
|
||||
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
|
||||
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject
|
||||
from api_validations.core_response import return_json_response_from_alchemy
|
||||
|
||||
|
||||
class ProjectDecisionBookProjectDecisionBookPersonEvents(MethodToEvent): ...
|
||||
Reference in New Issue
Block a user