From 08896e4c61574d3c5a4d02a925ea2135fb51c0d5 Mon Sep 17 00:00:00 2001 From: berkay Date: Wed, 8 Jan 2025 21:35:11 +0300 Subject: [PATCH] database and services updated and tested --- ApiServices/AuthService/Dockerfile | 21 +- .../AuthService/application/create_file.py | 14 +- ApiServices/AuthService/routers/__init__.py | 1 + ApiServices/EventService/Dockerfile | 21 +- ApiServices/EventService/routers/__init__.py | 1 + ApiServices/ValidationService/Dockerfile | 21 +- .../ValidationService/routers/__init__.py | 1 + ApiServices/__init__.py | 0 ApiServices/api_handlers/__init__.py | 0 ApiServices/api_handlers/core_response.py | 147 +++ ApiServices/local-docker-compose.yml | 29 - README.md | 13 +- .../later_use_codes/authentication.py | 1 - .../later_use_codes/events_bind_events.py | 1 - ...cker-compose.yml => api-docker-compose.yml | 14 +- api_configs/__init__.py | 52 +- api_configs/databaseConfigs.py | 2 + api_configs/emailConfigs.py | 6 + api_events/__init__.py | 0 api_events/events/__init__.py | 291 ++++++ api_events/events/abstract_class.py | 72 ++ api_events/events/account/__init__.py | 0 api_events/events/account/account_records.py | 347 +++++++ api_events/events/address/__init__.py | 0 api_events/events/address/address.py | 499 +++++++++++ api_events/events/application/__init__.py | 0 api_events/events/application/api.py | 5 + api_events/events/application/application.py | 5 + .../events/application/authentication.py | 844 ++++++++++++++++++ api_events/events/application/rules.py | 5 + api_events/events/building/__init__.py | 0 api_events/events/building/building_build.py | 308 +++++++ .../events/building/building_build_area.py | 176 ++++ .../events/building/building_build_parts.py | 165 ++++ .../events/building/building_build_sites.py | 175 ++++ .../events/building/building_build_types.py | 48 + .../events/building/building_living_spaces.py | 307 +++++++ api_events/events/company/__init__.py | 0 api_events/events/company/company_company.py | 189 ++++ .../events/company/company_department.py | 178 ++++ api_events/events/company/company_duties.py | 232 +++++ api_events/events/company/company_duty.py | 163 ++++ api_events/events/company/company_employee.py | 343 +++++++ api_events/events/company/company_staff.py | 156 ++++ api_events/events/decision_book/__init__.py | 0 .../decision_book_decision_book.py | 229 +++++ .../decision_book_decision_book_items.py | 570 ++++++++++++ ...ecision_book_decision_book_items_debits.py | 105 +++ .../decision_book_decision_book_person.py | 456 ++++++++++ .../decision_book_invitations.py | 282 ++++++ .../decision_book/decision_book_payment.py | 169 ++++ .../decision_book/project_decision_book.py | 372 ++++++++ .../project_decision_book_items.py | 156 ++++ .../project_decision_book_person.py | 189 ++++ api_events/events/events/__init__.py | 0 .../events/events/events_bind_modules.py | 157 ++++ .../events/events/events_bind_services.py | 321 +++++++ api_events/events/events/events_events.py | 270 ++++++ api_events/events/events/events_models.py | 28 + api_events/events/events/events_modules.py | 24 + api_events/events/events/events_services.py | 64 ++ api_events/events/identity/__init__.py | 0 api_events/events/identity/people.py | 219 +++++ api_events/events/identity/users.py | 217 +++++ api_events/tasks2events/__init__.py | 49 + .../tasks2events/common_tasks/__init__.py | 0 .../tasks2events/common_tasks/default_user.py | 22 + api_events/tasks2events/default_abstract.py | 14 + .../tasks2events/employee_tasks/__init__.py | 0 .../tasks2events/employee_tasks/super_user.py | 89 ++ .../tasks2events/occupant_tasks/__init__.py | 0 api_events/tasks2events/occupant_tasks/asd.py | 37 + .../occupant_tasks/build_manager.py | 21 + .../occupant_tasks/build_owner.py | 13 + .../occupant_tasks/build_represent.py | 13 + .../occupant_tasks/build_resident.py | 13 + .../occupant_tasks/build_tenant.py | 12 + .../occupant_tasks/meeting_advisor.py | 13 + .../occupant_tasks/meeting_attendance.py | 13 + .../occupant_tasks/meeting_president.py | 13 + .../occupant_tasks/meeting_voted_president.py | 12 + .../occupant_tasks/meeting_writer.py | 14 + .../occupant_tasks/project_employee.py | 15 + .../occupant_tasks/project_finance.py | 15 + .../occupant_tasks/project_leader.py | 22 + .../occupant_tasks/project_responsiable.py | 15 + .../occupant_tasks/project_technical.py | 15 + api_services/__init__.py | 0 api_services/email/config.py | 9 + api_services/email/service.py | 32 + api_services/redis/conn.py | 31 + api_services/redis/functions.py | 240 +++++ api_services/redis/old_functions.py | 96 ++ api_services/templates/password_templates.py | 243 +++++ api_validations/__init__.py | 0 api_validations/core_validations.py | 22 + .../validations_by_user/__init__.py | 0 .../validations_request/__init__.py | 245 +++++ .../validations_request/account_records.py | 162 ++++ .../validations_request/address.py | 130 +++ .../validations_request/application.py | 69 ++ api_validations/validations_request/area.py | 76 ++ .../validations_request/authentication.py | 104 +++ .../validations_request/build_living_space.py | 52 ++ .../validations_request/build_part.py | 139 +++ .../validations_request/building.py | 102 +++ .../validations_request/company.py | 74 ++ .../core_request_validations.py | 116 +++ .../validations_request/create_model.py | 73 ++ .../validations_request/decision_book.py | 356 ++++++++ .../validations_request/departments.py | 40 + .../validations_request/employee.py | 251 ++++++ api_validations/validations_request/events.py | 37 + .../validations_request/modules.py | 36 + api_validations/validations_request/people.py | 98 ++ .../project_decision_book.py | 276 ++++++ api_validations/validations_request/rules.py | 24 + .../validations_request/services.py | 36 + api_validations/validations_request/staff.py | 42 + api_validations/validations_request/user.py | 70 ++ .../validations_response/__init__.py | 5 + .../validations_response/account.py | 136 +++ .../validations_response/address.py | 23 + .../validations_response/building.py | 123 +++ .../validations_response/living_space.py | 52 ++ api_validations/validations_response/parts.py | 54 ++ .../validations_response/people.py | 57 ++ databases/no_sql_models/__init__.py | 0 databases/no_sql_models/identity.py | 136 +++ databases/no_sql_models/login_handlers.py | 88 ++ databases/no_sql_models/mongo_database.py | 312 +++++++ databases/no_sql_models/validations.py | 19 + 132 files changed, 13302 insertions(+), 95 deletions(-) create mode 100644 ApiServices/__init__.py create mode 100644 ApiServices/api_handlers/__init__.py create mode 100644 ApiServices/api_handlers/core_response.py delete mode 100644 ApiServices/local-docker-compose.yml rename ApiServices/debian-docker-compose.yml => api-docker-compose.yml (62%) create mode 100644 api_configs/emailConfigs.py create mode 100644 api_events/__init__.py create mode 100644 api_events/events/__init__.py create mode 100644 api_events/events/abstract_class.py create mode 100644 api_events/events/account/__init__.py create mode 100644 api_events/events/account/account_records.py create mode 100644 api_events/events/address/__init__.py create mode 100644 api_events/events/address/address.py create mode 100644 api_events/events/application/__init__.py create mode 100644 api_events/events/application/api.py create mode 100644 api_events/events/application/application.py create mode 100644 api_events/events/application/authentication.py create mode 100644 api_events/events/application/rules.py create mode 100644 api_events/events/building/__init__.py create mode 100644 api_events/events/building/building_build.py create mode 100644 api_events/events/building/building_build_area.py create mode 100644 api_events/events/building/building_build_parts.py create mode 100644 api_events/events/building/building_build_sites.py create mode 100644 api_events/events/building/building_build_types.py create mode 100644 api_events/events/building/building_living_spaces.py create mode 100644 api_events/events/company/__init__.py create mode 100644 api_events/events/company/company_company.py create mode 100644 api_events/events/company/company_department.py create mode 100644 api_events/events/company/company_duties.py create mode 100644 api_events/events/company/company_duty.py create mode 100644 api_events/events/company/company_employee.py create mode 100644 api_events/events/company/company_staff.py create mode 100644 api_events/events/decision_book/__init__.py create mode 100644 api_events/events/decision_book/decision_book_decision_book.py create mode 100644 api_events/events/decision_book/decision_book_decision_book_items.py create mode 100644 api_events/events/decision_book/decision_book_decision_book_items_debits.py create mode 100644 api_events/events/decision_book/decision_book_decision_book_person.py create mode 100644 api_events/events/decision_book/decision_book_invitations.py create mode 100644 api_events/events/decision_book/decision_book_payment.py create mode 100644 api_events/events/decision_book/project_decision_book.py create mode 100644 api_events/events/decision_book/project_decision_book_items.py create mode 100644 api_events/events/decision_book/project_decision_book_person.py create mode 100644 api_events/events/events/__init__.py create mode 100644 api_events/events/events/events_bind_modules.py create mode 100644 api_events/events/events/events_bind_services.py create mode 100644 api_events/events/events/events_events.py create mode 100644 api_events/events/events/events_models.py create mode 100644 api_events/events/events/events_modules.py create mode 100644 api_events/events/events/events_services.py create mode 100644 api_events/events/identity/__init__.py create mode 100644 api_events/events/identity/people.py create mode 100644 api_events/events/identity/users.py create mode 100644 api_events/tasks2events/__init__.py create mode 100644 api_events/tasks2events/common_tasks/__init__.py create mode 100644 api_events/tasks2events/common_tasks/default_user.py create mode 100644 api_events/tasks2events/default_abstract.py create mode 100644 api_events/tasks2events/employee_tasks/__init__.py create mode 100644 api_events/tasks2events/employee_tasks/super_user.py create mode 100644 api_events/tasks2events/occupant_tasks/__init__.py create mode 100644 api_events/tasks2events/occupant_tasks/asd.py create mode 100644 api_events/tasks2events/occupant_tasks/build_manager.py create mode 100644 api_events/tasks2events/occupant_tasks/build_owner.py create mode 100644 api_events/tasks2events/occupant_tasks/build_represent.py create mode 100644 api_events/tasks2events/occupant_tasks/build_resident.py create mode 100644 api_events/tasks2events/occupant_tasks/build_tenant.py create mode 100644 api_events/tasks2events/occupant_tasks/meeting_advisor.py create mode 100644 api_events/tasks2events/occupant_tasks/meeting_attendance.py create mode 100644 api_events/tasks2events/occupant_tasks/meeting_president.py create mode 100644 api_events/tasks2events/occupant_tasks/meeting_voted_president.py create mode 100644 api_events/tasks2events/occupant_tasks/meeting_writer.py create mode 100644 api_events/tasks2events/occupant_tasks/project_employee.py create mode 100644 api_events/tasks2events/occupant_tasks/project_finance.py create mode 100644 api_events/tasks2events/occupant_tasks/project_leader.py create mode 100644 api_events/tasks2events/occupant_tasks/project_responsiable.py create mode 100644 api_events/tasks2events/occupant_tasks/project_technical.py create mode 100644 api_services/__init__.py create mode 100644 api_services/email/config.py create mode 100644 api_services/email/service.py create mode 100644 api_services/redis/conn.py create mode 100644 api_services/redis/functions.py create mode 100644 api_services/redis/old_functions.py create mode 100644 api_services/templates/password_templates.py create mode 100644 api_validations/__init__.py create mode 100644 api_validations/core_validations.py create mode 100644 api_validations/validations_by_user/__init__.py create mode 100644 api_validations/validations_request/__init__.py create mode 100644 api_validations/validations_request/account_records.py create mode 100644 api_validations/validations_request/address.py create mode 100644 api_validations/validations_request/application.py create mode 100644 api_validations/validations_request/area.py create mode 100644 api_validations/validations_request/authentication.py create mode 100644 api_validations/validations_request/build_living_space.py create mode 100644 api_validations/validations_request/build_part.py create mode 100644 api_validations/validations_request/building.py create mode 100644 api_validations/validations_request/company.py create mode 100644 api_validations/validations_request/core_request_validations.py create mode 100644 api_validations/validations_request/create_model.py create mode 100644 api_validations/validations_request/decision_book.py create mode 100644 api_validations/validations_request/departments.py create mode 100644 api_validations/validations_request/employee.py create mode 100644 api_validations/validations_request/events.py create mode 100644 api_validations/validations_request/modules.py create mode 100644 api_validations/validations_request/people.py create mode 100644 api_validations/validations_request/project_decision_book.py create mode 100644 api_validations/validations_request/rules.py create mode 100644 api_validations/validations_request/services.py create mode 100644 api_validations/validations_request/staff.py create mode 100644 api_validations/validations_request/user.py create mode 100644 api_validations/validations_response/__init__.py create mode 100644 api_validations/validations_response/account.py create mode 100644 api_validations/validations_response/address.py create mode 100644 api_validations/validations_response/building.py create mode 100644 api_validations/validations_response/living_space.py create mode 100644 api_validations/validations_response/parts.py create mode 100644 api_validations/validations_response/people.py create mode 100644 databases/no_sql_models/__init__.py create mode 100644 databases/no_sql_models/identity.py create mode 100644 databases/no_sql_models/login_handlers.py create mode 100644 databases/no_sql_models/mongo_database.py create mode 100644 databases/no_sql_models/validations.py diff --git a/ApiServices/AuthService/Dockerfile b/ApiServices/AuthService/Dockerfile index 18d9b89..f25db95 100644 --- a/ApiServices/AuthService/Dockerfile +++ b/ApiServices/AuthService/Dockerfile @@ -5,20 +5,21 @@ ENV PYTHONUNBUFFERED 1 COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ -COPY ../service_app/requirements.txt . +COPY ApiServices/AuthService/pyproject.toml . RUN uv venv -RUN uv pip install -r requirements.txt +RUN uv pip install -r pyproject.toml -COPY ../service_app ./service_app +COPY ApiServices/AuthService ./service_app +COPY ApiServices/api_handlers ./service_app/api_handlers -COPY ../databases ./service_app/databases -COPY ../api_services ./service_app/api_services -COPY ../api_objects ./service_app/api_objects -COPY ../api_configs ./service_app/api_configs -COPY ../api_events ./service_app/api_events -COPY ../api_library ./service_app/api_library -COPY ../api_validations ./service_app/api_validations +COPY databases ./service_app/databases +COPY api_services ./service_app/api_services +COPY api_objects ./service_app/api_objects +COPY api_configs ./service_app/api_configs +COPY api_events ./service_app/api_events +COPY api_library ./service_app/api_library +COPY api_validations ./service_app/api_validations WORKDIR /service_app diff --git a/ApiServices/AuthService/application/create_file.py b/ApiServices/AuthService/application/create_file.py index b492475..4ef80ce 100644 --- a/ApiServices/AuthService/application/create_file.py +++ b/ApiServices/AuthService/application/create_file.py @@ -1,11 +1,11 @@ +from fastapi import FastAPI +from fastapi.responses import JSONResponse +from fastapi.openapi.utils import get_openapi +from fastapi.responses import RedirectResponse +from api_configs.configs import Config + + def create_app(routers): - from fastapi import FastAPI - from fastapi.responses import JSONResponse - from fastapi.openapi.utils import get_openapi - from fastapi.responses import RedirectResponse - - from api_configs import Config - api_app = FastAPI(title=str(Config.TITLE), default_response_class=JSONResponse) @api_app.get("/", include_in_schema=False, summary=str(Config.DESCRIPTION)) diff --git a/ApiServices/AuthService/routers/__init__.py b/ApiServices/AuthService/routers/__init__.py index e69de29..a9a2c5b 100644 --- a/ApiServices/AuthService/routers/__init__.py +++ b/ApiServices/AuthService/routers/__init__.py @@ -0,0 +1 @@ +__all__ = [] diff --git a/ApiServices/EventService/Dockerfile b/ApiServices/EventService/Dockerfile index 18d9b89..56267db 100644 --- a/ApiServices/EventService/Dockerfile +++ b/ApiServices/EventService/Dockerfile @@ -5,20 +5,21 @@ ENV PYTHONUNBUFFERED 1 COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ -COPY ../service_app/requirements.txt . +COPY ApiServices/EventService/pyproject.toml . RUN uv venv -RUN uv pip install -r requirements.txt +RUN uv pip install -r pyproject.toml -COPY ../service_app ./service_app +COPY ApiServices/EventService ./service_app +COPY ApiServices/api_handlers ./service_app/api_handlers -COPY ../databases ./service_app/databases -COPY ../api_services ./service_app/api_services -COPY ../api_objects ./service_app/api_objects -COPY ../api_configs ./service_app/api_configs -COPY ../api_events ./service_app/api_events -COPY ../api_library ./service_app/api_library -COPY ../api_validations ./service_app/api_validations +COPY databases ./service_app/databases +COPY api_services ./service_app/api_services +COPY api_objects ./service_app/api_objects +COPY api_configs ./service_app/api_configs +COPY api_events ./service_app/api_events +COPY api_library ./service_app/api_library +COPY api_validations ./service_app/api_validations WORKDIR /service_app diff --git a/ApiServices/EventService/routers/__init__.py b/ApiServices/EventService/routers/__init__.py index e69de29..b680692 100644 --- a/ApiServices/EventService/routers/__init__.py +++ b/ApiServices/EventService/routers/__init__.py @@ -0,0 +1 @@ +__all__ = [] \ No newline at end of file diff --git a/ApiServices/ValidationService/Dockerfile b/ApiServices/ValidationService/Dockerfile index 18d9b89..99cf4e3 100644 --- a/ApiServices/ValidationService/Dockerfile +++ b/ApiServices/ValidationService/Dockerfile @@ -5,20 +5,21 @@ ENV PYTHONUNBUFFERED 1 COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ -COPY ../service_app/requirements.txt . +COPY ApiServices/ValidationService/pyproject.toml . RUN uv venv -RUN uv pip install -r requirements.txt +RUN uv pip install -r pyproject.toml -COPY ../service_app ./service_app +COPY ApiServices/ValidationService ./service_app +COPY ApiServices/api_handlers ./service_app/api_handlers -COPY ../databases ./service_app/databases -COPY ../api_services ./service_app/api_services -COPY ../api_objects ./service_app/api_objects -COPY ../api_configs ./service_app/api_configs -COPY ../api_events ./service_app/api_events -COPY ../api_library ./service_app/api_library -COPY ../api_validations ./service_app/api_validations +COPY databases ./service_app/databases +COPY api_services ./service_app/api_services +COPY api_objects ./service_app/api_objects +COPY api_configs ./service_app/api_configs +COPY api_events ./service_app/api_events +COPY api_library ./service_app/api_library +COPY api_validations ./service_app/api_validations WORKDIR /service_app diff --git a/ApiServices/ValidationService/routers/__init__.py b/ApiServices/ValidationService/routers/__init__.py index e69de29..a9a2c5b 100644 --- a/ApiServices/ValidationService/routers/__init__.py +++ b/ApiServices/ValidationService/routers/__init__.py @@ -0,0 +1 @@ +__all__ = [] diff --git a/ApiServices/__init__.py b/ApiServices/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ApiServices/api_handlers/__init__.py b/ApiServices/api_handlers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ApiServices/api_handlers/core_response.py b/ApiServices/api_handlers/core_response.py new file mode 100644 index 0000000..851b8da --- /dev/null +++ b/ApiServices/api_handlers/core_response.py @@ -0,0 +1,147 @@ +from typing import Any, Union +from fastapi import status +from fastapi.responses import JSONResponse + +from databases.sql_models.response_model import AlchemyResponse + + +class AlchemyJsonResponse: + status_code: status + message: str + result: AlchemyResponse + completed: bool + filter_attributes: Any = None + response_model: Any = None + cls_object: Any = None + + @staticmethod + def get_total_count(cls_object, filter_attributes): + total_page_number = 1 + count_to_use = cls_object.total_count / int(filter_attributes.size) + if cls_object.total_count > int(filter_attributes.size): + if isinstance(count_to_use, int): + total_page_number = round(count_to_use, 0) + elif isinstance(count_to_use, float): + total_page_number = round(count_to_use, 0) + 1 + return total_page_number + + def __new__( + cls, + message: str, + status_code: str = "HTTP_200_OK", + result: Union[Any, list] = None, + completed: bool = True, + response_model: Any = None, + cls_object: Any = None, + filter_attributes: Any = None, + ): + cls.status_code = getattr(status, status_code, "HTTP_200_OK") + cls.message = message + cls.result = result + cls.completed = completed + cls.response_model = response_model + + pagination_dict = { + "size/total_count": [10, 10], + "page/total_page": [1, 1], + "order_field": "id", + "order_type": "asc", + } + if filter_attributes: + total_page_number = cls.get_total_count(cls_object, filter_attributes) + pagination_dict = { + "size/total_count": [filter_attributes.size, cls_object.total_count], + "page/total_page": [filter_attributes.page, total_page_number], + "order_field": filter_attributes.order_field, + "order_type": filter_attributes.order_type, + } + + if isinstance(cls.result, dict) or isinstance(cls.result, list): + return JSONResponse( + status_code=cls.status_code, + content=dict( + total_count=len(cls.result), + count=len(cls.result), + pagination=pagination_dict, + completed=cls.completed, + message=cls.message, + data=cls.result, + ), + ) + + first_item = getattr(cls.result, "data", None) + if not first_item: + return JSONResponse( + status_code=cls.status_code, + content=dict( + total_count=0, + count=0, + pagination=pagination_dict, + completed=cls.completed, + message=cls.message, + data=[], + ), + ) + + if cls.result.first: + return JSONResponse( + status_code=cls.status_code, + content=dict( + total_count=1, + count=1, + pagination=pagination_dict, + completed=cls.completed, + message=cls.message, + data=cls.result.data.get_dict(), + ), + ) + + if not cls.result.get(1).filter_attr and isinstance(cls.result.data, list): + counts = cls.result.count + return JSONResponse( + status_code=cls.status_code, + content=dict( + total_count=counts, + count=counts, + pagination=pagination_dict, + completed=cls.completed, + message=cls.message, + data=[result_data.get_dict() for result_data in cls.result.data], + ), + ) + + # filter_model = cls.result.get(1).filter_attr + total_count = cls.result.get(1).query.limit(None).offset(None).count() + total_page_number = cls.get_total_count(cls_object, filter_attributes) + pagination_dict = { + "size/total_count": [filter_attributes.size, cls_object.total_count], + "page/total_page": [filter_attributes.page, total_page_number], + "order_field": filter_attributes.order_field, + "order_type": filter_attributes.order_type, + } + include_joins = dict( + include_joins=( + filter_attributes.include_joins + if filter_attributes.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.append(data_dict) + return JSONResponse( + status_code=cls.status_code, + content=dict( + total_count=total_count or 1, + count=cls.result.count, + pagination=pagination_dict, + message=cls.message, + completed=cls.completed, + data=data, + ), + ) diff --git a/ApiServices/local-docker-compose.yml b/ApiServices/local-docker-compose.yml deleted file mode 100644 index 7caf323..0000000 --- a/ApiServices/local-docker-compose.yml +++ /dev/null @@ -1,29 +0,0 @@ -services: - - wag_management_auth_service: - container_name: wag_management_auth_service - restart: on-failure - build: - context: . - dockerfile: AuthService/Dockerfile - ports: - - "11:41575" - - wag_management_event_service: - container_name: wag_management_event_service - restart: on-failure - build: - context: . - dockerfile: EventService/Dockerfile - ports: - - "12:41575" - - wag_management_validation_service: - container_name: wag_management_validation_service - restart: on-failure - build: - context: . - dockerfile: ValidationService/Dockerfile - ports: - - "13:41575" - diff --git a/README.md b/README.md index 8872145..5ebb4cb 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,11 @@ On Linux Connectors: commercial_main_mongo_service: -http://localhost:11777 +http://10.10.2.36:11777 commercial_main_memory_service: -http://localhost:11222 +http://10.10.2.36:11222 postgres_main_commercial: -http://localhost:5444 +http://10.10.2.36:5444 make sure set lang and timezone on login @@ -24,5 +24,12 @@ BaseMixin || CrudMixin add http_exception = fastapi.HTTPException status = fastapi.status +On debian +> docker compose -f ./ApiServices/debian-docker-compose.yml up --build -d +On Linux +> docker compose -f ./ApiServices/local-docker-compose.yml up --build -d +> http://localhost:1111/docs | wag_management_auth_service +> http://localhost:1112/docs | wag_management_event_service +> http://localhost:1113/docs | wag_management_validation_service diff --git a/a_project_files/later_use_codes/authentication.py b/a_project_files/later_use_codes/authentication.py index 567fab3..439f713 100644 --- a/a_project_files/later_use_codes/authentication.py +++ b/a_project_files/later_use_codes/authentication.py @@ -47,7 +47,6 @@ from api_configs import ApiStatic, Auth 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 system_arrow, client_arrow -from api_validations.core_response import AlchemyJsonResponse class AuthenticationLoginEventMethods(MethodToEvent): diff --git a/a_project_files/later_use_codes/events_bind_events.py b/a_project_files/later_use_codes/events_bind_events.py index 4a4d207..c146b51 100644 --- a/a_project_files/later_use_codes/events_bind_events.py +++ b/a_project_files/later_use_codes/events_bind_events.py @@ -15,7 +15,6 @@ from databases import ( from api_validations.validations_request import RegisterEvents2Occupant 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 class EventBindOccupantEventMethods(MethodToEvent): diff --git a/ApiServices/debian-docker-compose.yml b/api-docker-compose.yml similarity index 62% rename from ApiServices/debian-docker-compose.yml rename to api-docker-compose.yml index 7caf323..2619739 100644 --- a/ApiServices/debian-docker-compose.yml +++ b/api-docker-compose.yml @@ -2,28 +2,28 @@ services: wag_management_auth_service: container_name: wag_management_auth_service - restart: on-failure +# restart: on-failure build: context: . - dockerfile: AuthService/Dockerfile + dockerfile: ApiServices/AuthService/Dockerfile ports: - - "11:41575" + - "1111:41575" wag_management_event_service: container_name: wag_management_event_service restart: on-failure build: context: . - dockerfile: EventService/Dockerfile + dockerfile: ApiServices/EventService/Dockerfile ports: - - "12:41575" + - "1112:41575" wag_management_validation_service: container_name: wag_management_validation_service restart: on-failure build: context: . - dockerfile: ValidationService/Dockerfile + dockerfile: ApiServices/ValidationService/Dockerfile ports: - - "13:41575" + - "1113:41575" diff --git a/api_configs/__init__.py b/api_configs/__init__.py index 5d667a6..46e7b4e 100644 --- a/api_configs/__init__.py +++ b/api_configs/__init__.py @@ -1,29 +1,47 @@ -from api_configs.configs import ( - Config, - ApiStatic, - Auth, +from .databaseConfigs import ( WagDatabase, WagRedis, - TestRedis, - HagRedis, MongoConfig, - TestMongo, - RelationAccess, + +) +from .emailConfigs import ( EmailConfig, - TestDatabase, +) +from .configs import ( + Config, ) __all__ = [ - "Config", - "ApiStatic", - "Auth", "WagDatabase", "WagRedis", - "TestRedis", - "HagRedis", "MongoConfig", - "TestMongo", - "RelationAccess", "EmailConfig", - "TestDatabase", + "Config", ] + +# from api_configs.configs import ( +# Config, +# ApiStatic, +# Auth, +# WagDatabase, +# WagRedis, +# TestRedis, +# HagRedis, +# MongoConfig, +# TestMongo, +# RelationAccess, +# EmailConfig, +# TestDatabase, +# ) +# "Config", +# "ApiStatic", +# "Auth", +# "WagDatabase", +# "WagRedis", +# "TestRedis", +# "HagRedis", +# "MongoConfig", +# "TestMongo", +# "RelationAccess", +# "EmailConfig", +# "TestDatabase", \ No newline at end of file diff --git a/api_configs/databaseConfigs.py b/api_configs/databaseConfigs.py index c930eb4..5ef24b6 100644 --- a/api_configs/databaseConfigs.py +++ b/api_configs/databaseConfigs.py @@ -1,3 +1,5 @@ + + storeHost = "10.10.2.36" diff --git a/api_configs/emailConfigs.py b/api_configs/emailConfigs.py new file mode 100644 index 0000000..3cc27aa --- /dev/null +++ b/api_configs/emailConfigs.py @@ -0,0 +1,6 @@ + + +class EmailConfig: + EMAIL_HOST: str = "10.10.2.34" + EMAIL_USERNAME: str = "karatay@mehmetkaratay.com.tr" + EMAIL_PASSWORD: str = "system" diff --git a/api_events/__init__.py b/api_events/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_events/events/__init__.py b/api_events/events/__init__.py new file mode 100644 index 0000000..415a028 --- /dev/null +++ b/api_events/events/__init__.py @@ -0,0 +1,291 @@ +from api_events.events.identity.people import ( + PeopleListEventMethod, + PeopleCreateEventMethod, + PeopleUpdateEventMethod, + PeoplePatchEventMethod, +) +from api_events.events.address.address import ( + AddressListEventMethod, + AddressCreateEventMethod, + AddressUpdateEventMethod, + AddressPatchEventMethod, + AddressSearchEventMethod, + AddressPostCodeCreateEventMethod, + AddressPostCodeUpdateEventMethod, + AddressPostCodeListEventMethod, +) +from api_events.events.application.authentication import ( + AuthenticationLoginEventMethod, + AuthenticationSelectEventMethod, + AuthenticationCheckTokenEventMethod, + AuthenticationRefreshEventMethod, + AuthenticationChangePasswordEventMethod, + AuthenticationCreatePasswordEventMethod, + AuthenticationResetPasswordEventMethod, + AuthenticationDisconnectUserEventMethod, + AuthenticationLogoutEventMethod, + AuthenticationRefreshTokenEventMethod, + AuthenticationForgotPasswordEventMethod, + AuthenticationDownloadAvatarEventMethod, +) +from api_events.events.account.account_records import ( + AccountRecordsListEventMethod, + AccountRecordsCreateEventMethod, + AccountRecordsUpdateEventMethod, + AccountRecordsPatchEventMethod, +) +from api_events.events.identity.users import ( + UserListEventMethod, + UserCreateEventMethod, + UserUpdateEventMethod, + UserPatchEventMethod, +) +from api_events.events.building.building_build import ( + BuildListEventMethod, + BuildCreateEventMethod, + BuildUpdateEventMethod, + BuildPatchEventMethod, +) +from api_events.events.building.building_build_parts import ( + BuildingBuildPartsListEventMethod, + BuildingBuildPartsCreateEventMethod, + BuildingBuildPartsUpdateEventMethod, + BuildingBuildPartsPatchEventMethod, +) +from api_events.events.building.building_build_area import ( + BuildAreaListEventMethod, + BuildAreaCreateEventMethod, + BuildAreaUpdateEventMethod, + BuildAreaPatchEventMethod, +) +from api_events.events.building.building_build_sites import ( + BuildSitesListEventMethod, + BuildSitesCreateEventMethod, + BuildSitesUpdateEventMethod, +) +from api_events.events.building.building_build_types import ( + BuildTypesListEventMethod, +) +from api_events.events.company.company_company import ( + CompanyListEventMethod, + CompanyCreateEventMethod, + CompanyUpdateEventMethod, + CompanyPatchEventMethod, +) +from api_events.events.company.company_department import ( + DepartmentListEventMethod, + DepartmentCreateEventMethod, + DepartmentUpdateEventMethod, + DepartmentPatchEventMethod, +) +from api_events.events.company.company_duties import ( + DutiesListEventMethod, + DutiesGetByUUIDEventMethod, + DutiesCreateEventMethod, + DutiesUpdateEventMethod, + DutiesPatchEventMethod, +) +from api_events.events.company.company_duty import ( + DutyListEventMethod, + DutyCreateEventMethod, + DutyUpdateEventMethod, + DutyPatchEventMethod, +) +from api_events.events.company.company_employee import ( + EmployeeListEventMethod, + EmployeeCreateEventMethod, + EmployeeUpdateEventMethod, + EmployeePatchEventMethod, + Employee2PeopleEmployEventMethod, + Employee2PeopleFireEventMethod, +) +from api_events.events.company.company_staff import ( + StaffListEventMethod, + StaffCreateEventMethod, + StaffGetByUUIDEventMethod, + StaffUpdateEventMethod, + StaffPatchEventMethod, +) +from api_events.events.building.building_living_spaces import ( + BuildingLivingSpacesListEventMethod, + BuildingLivingSpacesCreateEventMethod, + BuildingLivingSpacesUpdateEventMethod, +) +from api_events.events.decision_book.decision_book_decision_book import ( + DecisionBookListEventMethod, + DecisionBookCreateEventMethod, + DecisionBookUpdateEventMethod, + DecisionBookPatchEventMethod, + DecisionBookApprovalEventMethod, +) +from api_events.events.decision_book.decision_book_decision_book_items import ( + DecisionBookDecisionBookItemsListEventMethod, + DecisionBookDecisionBookItemsCreateEventMethod, + DecisionBookDecisionBookItemsUpdateEventMethod, + DecisionBookDecisionBookItemsPatchEventMethod, +) +from api_events.events.decision_book.project_decision_book import ( + ProjectDecisionBookListEventMethod, + ProjectDecisionBookCreateEventMethod, + ProjectDecisionBookUpdateEventMethod, + ProjectDecisionBookApprovalEventMethod, + ProjectDecisionBookPatchEventMethod, +) +from api_events.events.decision_book.project_decision_book_person import ( + ProjectDecisionBookPersonListEventMethod, + ProjectDecisionBookPersonCreateEventMethod, + ProjectDecisionBookPersonUpdateEventMethod, + ProjectDecisionBookPersonPatchEventMethod, +) +from api_events.events.decision_book.project_decision_book_items import ( + BuildDecisionBookProjectItemsPatchEventMethod, + BuildDecisionBookProjectItemsUpdateEventMethod, + BuildDecisionBookProjectItemsCreateEventMethod, + BuildDecisionBookProjectItemsListEventMethod, +) + +# from api_events.events.events.events_ import ( +# EventBindOccupantEventMethod, +# EventBindEmployeeEventMethod, +# ) +from api_events.events.events.events_bind_services import ( + ServiceBindOccupantEventMethod, + ServiceBindEmployeeEventMethod, +) +from api_events.events.decision_book.decision_book_decision_book_person import ( + DecisionBookPersonListEventMethod, + DecisionBookPersonAddEventMethod, + DecisionBookPersonRemoveEventMethod, + DecisionBookPersonAttendEventMethod, + DecisionBookPersonAssignOccupantEventMethod, +) +from api_events.events.decision_book.decision_book_invitations import ( + BuildDecisionBookInvitationsListEventMethod, + BuildDecisionBookInvitationsCreateEventMethod, + BuildDecisionBookInvitationsUpdateEventMethod, +) +from api_events.events.events.events_events import ( + EventsBindEventToEmployeeMethod, + EventsBindEventToOccupantMethod, + EventsListEventMethod, +) + + +__all__ = [ + "AddressListEventMethod", + "AddressCreateEventMethod", + "AddressUpdateEventMethod", + "AddressPatchEventMethod", + "AddressSearchEventMethod", + "AddressPostCodeCreateEventMethod", + "AddressPostCodeUpdateEventMethod", + "AddressPostCodeListEventMethod", + "PeopleListEventMethod", + "PeopleUpdateEventMethod", + "PeoplePatchEventMethod", + "PeopleCreateEventMethod", + "AuthenticationLoginEventMethod", + "AuthenticationSelectEventMethod", + "AuthenticationCheckTokenEventMethod", + "AuthenticationRefreshEventMethod", + "AuthenticationChangePasswordEventMethod", + "AuthenticationCreatePasswordEventMethod", + "AuthenticationResetPasswordEventMethod", + "AuthenticationDisconnectUserEventMethod", + "AuthenticationLogoutEventMethod", + "AuthenticationRefreshTokenEventMethod", + "AuthenticationForgotPasswordEventMethod", + "AuthenticationDownloadAvatarEventMethod", + "AccountRecordsListEventMethod", + "AccountRecordsCreateEventMethod", + "AccountRecordsUpdateEventMethod", + "AccountRecordsPatchEventMethod", + "UserListEventMethod", + "UserCreateEventMethod", + "UserUpdateEventMethod", + "UserPatchEventMethod", + "BuildListEventMethod", + "BuildCreateEventMethod", + "BuildUpdateEventMethod", + "BuildPatchEventMethod", + "BuildingBuildPartsListEventMethod", + "BuildingBuildPartsCreateEventMethod", + "BuildingBuildPartsUpdateEventMethod", + "BuildingBuildPartsPatchEventMethod", + "BuildingLivingSpacesListEventMethod", + "BuildingLivingSpacesCreateEventMethod", + "BuildingLivingSpacesUpdateEventMethod", + "BuildAreaListEventMethod", + "BuildAreaCreateEventMethod", + "BuildAreaUpdateEventMethod", + "BuildAreaPatchEventMethod", + "BuildSitesListEventMethod", + "BuildSitesCreateEventMethod", + "BuildSitesUpdateEventMethod", + "BuildTypesListEventMethod", + "DecisionBookListEventMethod", + "DecisionBookCreateEventMethod", + "DecisionBookUpdateEventMethod", + "DecisionBookPatchEventMethod", + "DecisionBookApprovalEventMethod", + "DecisionBookPersonListEventMethod", + "DecisionBookPersonAddEventMethod", + "DecisionBookPersonRemoveEventMethod", + "DecisionBookDecisionBookItemsListEventMethod", + "DecisionBookDecisionBookItemsCreateEventMethod", + "DecisionBookDecisionBookItemsUpdateEventMethod", + "DecisionBookDecisionBookItemsPatchEventMethod", + "ProjectDecisionBookListEventMethod", + "ProjectDecisionBookCreateEventMethod", + "ProjectDecisionBookUpdateEventMethod", + "ProjectDecisionBookApprovalEventMethod", + "ProjectDecisionBookPatchEventMethod", + "ProjectDecisionBookPersonListEventMethod", + "ProjectDecisionBookPersonCreateEventMethod", + "ProjectDecisionBookPersonUpdateEventMethod", + "ProjectDecisionBookPersonPatchEventMethod", + "BuildDecisionBookProjectItemsPatchEventMethod", + "BuildDecisionBookProjectItemsUpdateEventMethod", + "BuildDecisionBookProjectItemsCreateEventMethod", + "BuildDecisionBookProjectItemsListEventMethod", + "CompanyPatchEventMethod", + "CompanyCreateEventMethod", + "CompanyUpdateEventMethod", + "CompanyListEventMethod", + "DepartmentListEventMethod", + "DepartmentCreateEventMethod", + "DepartmentUpdateEventMethod", + "DepartmentPatchEventMethod", + "DutiesListEventMethod", + "DutiesGetByUUIDEventMethod", + "DutiesCreateEventMethod", + "DutiesUpdateEventMethod", + "DutiesPatchEventMethod", + "DutyListEventMethod", + "DutyCreateEventMethod", + "DutyUpdateEventMethod", + "DutyPatchEventMethod", + "EmployeeListEventMethod", + "EmployeeCreateEventMethod", + "EmployeeUpdateEventMethod", + "EmployeePatchEventMethod", + "Employee2PeopleEmployEventMethod", + "Employee2PeopleFireEventMethod", + "StaffListEventMethod", + "StaffCreateEventMethod", + "StaffGetByUUIDEventMethod", + "StaffUpdateEventMethod", + "StaffPatchEventMethod", + # "EventBindOccupantEventMethod", + # "EventBindEmployeeEventMethod", + "ServiceBindOccupantEventMethod", + "ServiceBindEmployeeEventMethod", + "BuildDecisionBookInvitationsListEventMethod", + "BuildDecisionBookInvitationsCreateEventMethod", + "BuildDecisionBookInvitationsUpdateEventMethod", + "DecisionBookPersonAttendEventMethod", + "DecisionBookPersonAssignOccupantEventMethod", + "EventsBindEventToEmployeeMethod", + "EventsBindEventToOccupantMethod", + "EventsListEventMethod", +] diff --git a/api_events/events/abstract_class.py b/api_events/events/abstract_class.py new file mode 100644 index 0000000..e2c8a16 --- /dev/null +++ b/api_events/events/abstract_class.py @@ -0,0 +1,72 @@ +import typing +from abc import ABC +from fastapi.exceptions import HTTPException + +from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject + + +class ActionsSchema(ABC): + + def __init__(self, endpoint: str = None): + self.endpoint = endpoint + + def retrieve_action_from_endpoint(self): + from databases import EndpointRestriction + + endpoint_restriction = EndpointRestriction.filter_one( + EndpointRestriction.endpoint_name.ilike(f"%{self.endpoint}%"), system=True + ).data + if not endpoint_restriction: + raise HTTPException( + status_code=404, + detail=f"Endpoint {self.endpoint} not found in the database", + ) + return endpoint_restriction + + +class ActionsSchemaFactory: + + def __init__(self, action: ActionsSchema): + self.action = action + try: + self.action_match = self.action.retrieve_action_from_endpoint() + except Exception as e: + err = e + print(f"ActionsSchemaFactory Error: {e}") + + +class MethodToEvent(ABC, ActionsSchemaFactory): + + action_key: str = None + event_type: str = None + event_description: str = "" + event_category: str = "" + + __event_keys__: dict = {} + __event_validation__: dict = {} + + @classmethod + def call_event_method(cls, method_uu_id: str, *args, **kwargs): + function_name = cls.__event_keys__.get(method_uu_id) + return getattr(cls, function_name)(*args, **kwargs) + + @classmethod + def ban_token_objects( + cls, + token: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ban_list: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + from fastapi import status + from fastapi.exceptions import HTTPException + + if token.user_type == ban_list.user_type: + if isinstance(token, 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", + ) + if isinstance(token, OccupantTokenObject): + raise HTTPException( + status_code=status.HTTP_406_NOT_ACCEPTABLE, + detail="No occupant can reach this event. An notification is send to admin about event registration", + ) diff --git a/api_events/events/account/__init__.py b/api_events/events/account/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_events/events/account/account_records.py b/api_events/events/account/account_records.py new file mode 100644 index 0000000..a7d6fa0 --- /dev/null +++ b/api_events/events/account/account_records.py @@ -0,0 +1,347 @@ +import typing + +from api_library.date_time_actions.date_functions import system_arrow +from api_validations.validations_request import ( + InsertAccountRecord, + UpdateAccountRecord, + ListOptions, +) + +from api_validations.core_response import AlchemyJsonResponse +from api_events.events.abstract_class import MethodToEvent, ActionsSchema +from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject +from api_validations.validations_response.account import AccountListResponse +from databases import ( + AccountRecords, + BuildIbans, +) +from databases.sql_models.building.build import Build, BuildLivingSpace +from databases.sql_models.building.decision_book import BuildDecisionBookPayments +from databases.sql_models.others.enums import ApiEnumDropdown + + +class AccountRecordsListEventMethods(MethodToEvent): + + event_type = "SELECT" + event_description = "" + event_category = "" + + __event_keys__ = { + "7192c2aa-5352-4e36-98b3-dafb7d036a3d": "account_records_list", + "208e6273-17ef-44f0-814a-8098f816b63a": "account_records_list_flt_res", + } + __event_validation__ = { + "7192c2aa-5352-4e36-98b3-dafb7d036a3d": AccountListResponse, + "208e6273-17ef-44f0-814a-8098f816b63a": AccountListResponse, + } + + @classmethod + def account_records_list( + cls, + list_options: ListOptions, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, OccupantTokenObject): + AccountRecords.pre_query = AccountRecords.filter_all( + AccountRecords.company_id + == token_dict.selected_occupant.responsible_company_id, + ) + elif isinstance(token_dict, EmployeeTokenObject): + AccountRecords.pre_query = AccountRecords.filter_all( + AccountRecords.company_id == token_dict.selected_company.company_id, + ) + AccountRecords.filter_attr = list_options + records = AccountRecords.filter_all() + return AlchemyJsonResponse( + completed=True, message="List Build record", result=records + ) + + @classmethod + def account_records_list_flt_res( + cls, + list_options: ListOptions, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + if not isinstance(token_dict, OccupantTokenObject): + raise AccountRecords().raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="UNAUTHORIZED", + message="Only Occupant can see this data", + data={}, + ) + + return_list = [] + living_space: BuildLivingSpace = BuildLivingSpace.filter_by_one( + id=token_dict.selected_occupant.living_space_id + ).data + if not living_space: + raise AccountRecords().raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="UNAUTHORIZED", + message="Living space not found", + data={}, + ) + + if not list_options: + list_options = ListOptions() + + main_filters = [ + AccountRecords.living_space_id + == token_dict.selected_occupant.living_space_id, + BuildDecisionBookPayments.process_date + >= str(system_arrow.now().shift(months=-3).date()), + BuildDecisionBookPayments.process_date + < str(system_arrow.find_last_day_of_month(living_space.expiry_ends)), + BuildDecisionBookPayments.process_date + >= str(system_arrow.get(living_space.expiry_starts)), + BuildDecisionBookPayments.is_confirmed == True, + AccountRecords.active == True, + ] + order_type = "desc" + if list_options.order_type: + order_type = "asc" if list_options.order_type[0] == "a" else "desc" + + order_by_list = BuildDecisionBookPayments.process_date.desc() + if list_options.order_field: + if list_options.order_field == "process_date": + order_by_list = ( + BuildDecisionBookPayments.process_date.asc() + if order_type == "asc" + else BuildDecisionBookPayments.process_date.desc() + ) + if list_options.order_field == "bank_date": + order_by_list = ( + AccountRecords.bank_date.desc() + if order_type == "asc" + else AccountRecords.bank_date.asc() + ) + if list_options.order_field == "currency_value": + order_by_list = ( + AccountRecords.currency_value.desc() + if order_type == "asc" + else AccountRecords.currency_value.asc() + ) + if list_options.order_field == "process_comment": + order_by_list = ( + AccountRecords.process_comment.desc() + if order_type == "asc" + else AccountRecords.process_comment.asc() + ) + if list_options.order_field == "payment_amount": + order_by_list = ( + BuildDecisionBookPayments.payment_amount.desc() + if order_type == "asc" + else BuildDecisionBookPayments.payment_amount.asc() + ) + + if list_options.query: + for key, value in list_options.query.items(): + if key == "process_date": + main_filters.append(BuildDecisionBookPayments.process_date == value) + if key == "bank_date": + main_filters.append(AccountRecords.bank_date == value) + if key == "currency": + main_filters.append(BuildDecisionBookPayments.currency == value) + if key == "currency_value": + main_filters.append(AccountRecords.currency_value == value) + if key == "process_comment": + main_filters.append(AccountRecords.process_comment == value) + if key == "payment_amount": + main_filters.append( + BuildDecisionBookPayments.payment_amount == value + ) + + query = ( + AccountRecords.session.query( + BuildDecisionBookPayments.process_date, + BuildDecisionBookPayments.payment_amount, + BuildDecisionBookPayments.currency, + AccountRecords.bank_date, + AccountRecords.currency_value, + AccountRecords.process_comment, + BuildDecisionBookPayments.uu_id, + ) + .join( + AccountRecords, + AccountRecords.id == BuildDecisionBookPayments.account_records_id, + ) + .filter(*main_filters) + ).order_by(order_by_list) + + query.limit(list_options.size or 5).offset( + (list_options.page or 1 - 1) * list_options.size or 5 + ) + for list_of_values in query.all() or []: + return_list.append( + { + "process_date": list_of_values[0], + "payment_amount": list_of_values[1], + "currency": list_of_values[2], + "bank_date": list_of_values[3], + "currency_value": list_of_values[4], + "process_comment": list_of_values[5], + } + ) + return dict(completed=True, message="List Build record", result=return_list) + + +class AccountRecordsCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + event_description = "" + event_category = "" + + __event_keys__ = { + "31f4f32f-0cd4-4995-8a6a-f9f56335848a": "account_records_create", + } + __event_validation__ = { + "31f4f32f-0cd4-4995-8a6a-f9f56335848a": InsertAccountRecord, + } + + @classmethod + def account_records_create( + cls, + data: InsertAccountRecord, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + data_dict = data.excluded_dump() + if isinstance(token_dict, OccupantTokenObject): + build_iban = BuildIbans.filter_one( + BuildIbans.iban == data.iban, + BuildIbans.build_id == token_dict.selected_occupant.build_id, + ).data + if not build_iban: + BuildIbans.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="UNAUTHORIZED", + message=f"{data.iban} is not found in company related to your organization", + data={ + "iban": data.iban, + }, + ) + account_record = AccountRecords.find_or_create(**data.excluded_dump()) + return AlchemyJsonResponse( + completed=True, + message="Update Build record", + result=account_record.get_dict(), + ) + elif isinstance(token_dict, EmployeeTokenObject): + # Build.pre_query = Build.select_action( + # employee_id=token_dict.selected_employee.employee_id, + # ) + # build_ids_list = Build.filter_all( + # ) + # build_iban = BuildIbans.filter_one( + # BuildIbans.iban == data.iban, + # BuildIbans.build_id.in_([build.id for build in build_ids_list.data]), + # ).data + # if not build_iban: + # BuildIbans.raise_http_exception( + # status_code="HTTP_404_NOT_FOUND", + # error_case="UNAUTHORIZED", + # message=f"{data.iban} is not found in company related to your organization", + # data={ + # "iban": data.iban, + # }, + # ) + bank_date = system_arrow.get(data.bank_date) + data_dict["bank_date_w"] = bank_date.weekday() + data_dict["bank_date_m"] = bank_date.month + data_dict["bank_date_d"] = bank_date.day + data_dict["bank_date_y"] = bank_date.year + + if int(data.currency_value) < 0: + debit_type = ApiEnumDropdown.filter_by_one( + system=True, enum_class="DebitTypes", key="DT-D" + ).data + data_dict["receive_debit"] = debit_type.id + data_dict["receive_debit_uu_id"] = str(debit_type.uu_id) + else: + debit_type = ApiEnumDropdown.filter_by_one( + system=True, enum_class="DebitTypes", key="DT-R" + ).data + data_dict["receive_debit"] = debit_type.id + data_dict["receive_debit_uu_id"] = str(debit_type.uu_id) + + account_record = AccountRecords.find_or_create(**data_dict) + account_record.save() + account_record.update(is_confirmed=True) + account_record.save() + return AlchemyJsonResponse( + completed=True, + message="Create Account record are successful", + result=account_record.get_dict(), + ) + + +class AccountRecordsUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + event_description = "" + event_category = "" + + __event_keys__ = { + "ec98ef2c-bcd0-432d-a8f4-1822a56c33b2": "account_records_update", + } + __event_validation__ = { + "ec98ef2c-bcd0-432d-a8f4-1822a56c33b2": UpdateAccountRecord, + } + + @classmethod + def build_area_update( + cls, + build_uu_id: str, + data: UpdateAccountRecord, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, OccupantTokenObject): + pass + elif isinstance(token_dict, EmployeeTokenObject): + pass + + return AlchemyJsonResponse( + completed=False, + message="Update Build record", + result=None, + ) + + +class AccountRecordsPatchEventMethods(MethodToEvent): + + event_type = "PATCH" + event_description = "" + event_category = "" + + __event_keys__ = { + "34c38937-42a2-45f1-b2ef-a23978650aee": "account_records_patch", + } + __event_validation__ = { + "34c38937-42a2-45f1-b2ef-a23978650aee": None, + } + + @classmethod + def build_area_patch( + cls, + build_uu_id: str, + data, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + return AlchemyJsonResponse( + completed=False, + message="Patch Build record", + result=None, + ) + + +AccountRecordsListEventMethod = AccountRecordsListEventMethods( + action=ActionsSchema(endpoint="/account/records/list") +) +AccountRecordsCreateEventMethod = AccountRecordsCreateEventMethods( + action=ActionsSchema(endpoint="/account/records/create") +) +AccountRecordsUpdateEventMethod = AccountRecordsUpdateEventMethods( + action=ActionsSchema(endpoint="/account/records/update") +) +AccountRecordsPatchEventMethod = AccountRecordsPatchEventMethods( + action=ActionsSchema(endpoint="/account/records/patch") +) diff --git a/api_events/events/address/__init__.py b/api_events/events/address/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_events/events/address/address.py b/api_events/events/address/address.py new file mode 100644 index 0000000..0e290d6 --- /dev/null +++ b/api_events/events/address/address.py @@ -0,0 +1,499 @@ +from typing import Union + +from fastapi.exceptions import HTTPException +from fastapi.responses import JSONResponse + +from api_validations.validations_response.address import ( + ListAddressResponse, + AddressPostCodeResponse, +) +from databases import ( + AddressPostcode, + Addresses, + RelationshipEmployee2PostCode, + AddressStreet, +) + +from api_validations.validations_request import ( + ListOptions, + InsertAddress, + UpdateAddress, + InsertPostCode, + UpdatePostCode, + SearchAddress, +) +from api_validations.core_response import AlchemyJsonResponse +from api_events.events.abstract_class import MethodToEvent, ActionsSchema +from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject + + +class AddressListEventMethods(MethodToEvent): + + event_type = "SELECT" + event_description = "List Address records" + event_category = "Address" + + __event_keys__ = { + "9c251d7d-da70-4d63-a72c-e69c26270442": "address_list_super_user", + "52afe375-dd95-4f4b-aaa2-4ec61bc6de52": "address_list_employee", + } + __event_validation__ = { + "9c251d7d-da70-4d63-a72c-e69c26270442": ListAddressResponse, + "52afe375-dd95-4f4b-aaa2-4ec61bc6de52": ListAddressResponse, + } + + @classmethod + def address_list_super_user( + cls, + list_options: ListOptions, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + post_code_list = RelationshipEmployee2PostCode.filter_all( + RelationshipEmployee2PostCode.company_id + == token_dict.selected_company.company_id, + ).data + post_code_id_list = [post_code.member_id for post_code in post_code_list] + if not post_code_id_list: + raise HTTPException( + status_code=404, + detail="User has no post code registered. User can not list addresses.", + ) + get_street_ids = [ + street_id[0] + for street_id in AddressPostcode.select_only( + AddressPostcode.id.in_(post_code_id_list), + 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.", + ) + Addresses.pre_query = Addresses.filter_all( + Addresses.street_id.in_(get_street_ids), + ).query + Addresses.filter_attr = list_options + records = Addresses.filter_all().data + return AlchemyJsonResponse( + completed=True, + message="List Address records", + result=records, + ) + + @classmethod + 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, + ) + return AlchemyJsonResponse( + completed=True, + message="List Address records", + result=records, + ) + + +class AddressCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + event_description = "" + event_category = "" + + __event_keys__ = { + "ffdc445f-da10-4ce4-9531-d2bdb9a198ae": "create_address", + } + __event_validation__ = { + "ffdc445f-da10-4ce4-9531-d2bdb9a198ae": InsertAddress, + } + + @classmethod + def create_address( + cls, + data: InsertAddress, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + post_code = AddressPostcode.filter_one( + AddressPostcode.uu_id == data.post_code_uu_id, + ).data + if not post_code: + raise HTTPException( + status_code=404, + detail="Post code not found. User can not create address without post code.", + ) + + data_dict = data.excluded_dump() + data_dict["street_id"] = post_code.street_id + data_dict["street_uu_id"] = str(post_code.street_uu_id) + del data_dict["post_code_uu_id"] + address = Addresses.find_or_create(**data_dict) + address.save() + address.update(is_confirmed=True) + address.save() + return JSONResponse( + content={ + "completed": True, + "message": "Create Address record", + "data": address.get_dict(), + }, + status_code=200, + ) + + +class AddressSearchEventMethods(MethodToEvent): + + event_type = "SEARCH" + event_description = "" + event_category = "" + + __event_keys__ = { + "e0ac1269-e9a7-4806-9962-219ac224b0d0": "search_address", + } + __event_validation__ = { + "e0ac1269-e9a7-4806-9962-219ac224b0d0": SearchAddress, + } + + @classmethod + def search_address( + cls, + data: SearchAddress, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + import databases.sql_models + from time import perf_counter + + st = perf_counter() + + pre_query_first = AddressStreet.search_address_text(search_text=data.search) + query, schemas, new_data_list = ( + pre_query_first.get("query"), + pre_query_first.get("schema"), + [], + ) + filter_list = data.list_options.dump() + filter_table = AddressStreet + if filter_list.get("order_field") not in schemas: + filter_list["order_field"] = "uu_id" + else: + filter_table = getattr( + databases.sql_models, str(filter_list.get("order_field")).split(".")[0] + ) + filter_list["order_field"] = str(filter_list.get("order_field")).split(".")[ + 1 + ] + + order = ( + getattr(filter_table, filter_list.get("order_field")).desc() + if str(filter_list.get("order_type"))[0] == "d" + else getattr(filter_table, filter_list.get("order_field")).asc() + ) + + query = ( + query.order_by(order) + .limit(int(filter_list.get("size"))) + .offset(int((filter_list.get("page")) - 1) * int(filter_list.get("size"))) + .populate_existing() + ) + + records = list(query.all()) + print(perf_counter() - st) + + for item in records: + new_data_dict = {} + for index, schema in enumerate(schemas): + new_data_dict[schema] = str(item[index]) + if "uu_id" in str(item[index]): + new_data_dict[schema] = str(new_data_dict.get(schema)) + new_data_list.append(new_data_dict) + + return JSONResponse( + content={ + "completed": True, + "pagination": filter_list, + "count": len(new_data_list), + "data": new_data_list, + "message": "Search Address records", + }, + status_code=200, + ) + + +class AddressUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + event_description = "" + event_category = "" + + __event_keys__ = { + "1f9c3a9c-e5bd-4dcd-9b9a-3742d7e03a27": "update_address", + } + __event_validation__ = { + "1f9c3a9c-e5bd-4dcd-9b9a-3742d7e03a27": UpdateAddress, + } + + @classmethod + def update_address( + cls, + address_uu_id: str, + data: UpdateAddress, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, EmployeeTokenObject): + address = Addresses.filter_one( + Addresses.uu_id == address_uu_id, + ).data + if not address: + raise HTTPException( + status_code=404, + detail=f"Address not found. User can not update with given address uuid : {address_uu_id}", + ) + + data_dict = data.excluded_dump() + updated_address = address.update(**data_dict) + updated_address.save() + return JSONResponse( + content={ + "completed": True, + "message": "Update Address record", + "data": updated_address.get_dict(), + }, + status_code=200, + ) + elif isinstance(token_dict, OccupantTokenObject): + raise HTTPException( + status_code=403, + detail="Occupant can not update address.", + ) + + +class AddressPatchEventMethods(MethodToEvent): + + event_type = "PATCH" + event_description = "" + event_category = "" + + __event_keys__ = { + "b0e55a7e-af81-468c-b46c-a6b3a6b68d5d": "patch_address", + } + __event_validation__ = { + "b0e55a7e-af81-468c-b46c-a6b3a6b68d5d": None, + } + + @classmethod + def patch_address( + cls, + address_uu_id: str, + data: InsertAddress, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + address = Addresses.filter_one( + Addresses.uu_id == address_uu_id, + ).data + post_code = RelationshipEmployee2PostCode.filter_one( + RelationshipEmployee2PostCode.member_id == address.post_code_id, + ) + if not post_code: + raise HTTPException( + status_code=404, + detail="Post code not found. User can not patch address without post code.", + ) + + data_dict = data.excluded_dump() + data_dict["post_code_id"] = post_code.id + del data_dict["post_code_uu_id"] + + patched_address = address.patch(**data_dict) + return JSONResponse( + content={ + "completed": True, + "message": "Patch Address record", + "data": patched_address.get_dict(), + }, + status_code=200, + ) + + +class AddressPostCodeCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + event_description = "" + event_category = "" + + __event_keys__ = { + "6f1406ac-577d-4f2c-8077-71fff2252c5f": "create_post_code_address", + } + __event_validation__ = { + "6f1406ac-577d-4f2c-8077-71fff2252c5f": InsertPostCode, + } + + @classmethod + def create_post_code_address( + cls, + data: InsertPostCode, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + data_dump = data.excluded_dump() + street = AddressStreet.filter_one( + AddressStreet.uu_id == data.street_uu_id, + ).data + if not street: + raise HTTPException( + status_code=404, + detail="Street not found. User can not create post code without street.", + ) + data_dump["street_id"] = street.id + data_dump["postcode"] = data.post_code + del data_dump["post_code"] + + post_code = AddressPostcode.find_or_create(**data_dump) + relation_table = 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, + ) + post_code.save() + post_code.update(is_confirmed=True) + post_code.save() + relation_table.update(is_confirmed=True) + relation_table.save() + return JSONResponse( + content={ + "completed": True, + "message": "Create Post Code record", + "data": post_code.get_dict(), + }, + status_code=200, + ) + + +class AddressPostCodeUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + event_description = "" + event_category = "" + + __event_keys__ = { + "df18e489-a63c-477f-984c-aa52d30640ad": "update_post_code_address", + } + __event_validation__ = { + "df18e489-a63c-477f-984c-aa52d30640ad": UpdatePostCode, + } + + @classmethod + def update_post_code_address( + cls, + post_code_uu_id: str, + data: UpdatePostCode, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, EmployeeTokenObject): + AddressPostcode.pre_query = AddressPostcode.select_action( + employee_id=token_dict.selected_company.employee_id, + ) + post_code = AddressPostcode.filter_one( + AddressPostcode.uu_id == post_code_uu_id, + ).data + if not post_code: + raise HTTPException( + status_code=404, + detail="Street not found. User can not update post code without street.", + ) + + data_dict = data.excluded_dump() + updated_post_code = post_code.update(**data_dict) + updated_post_code.save() + return JSONResponse( + content={ + "completed": True, + "message": "Update Post Code record", + "data": updated_post_code.get_dict(), + }, + status_code=200, + ) + elif isinstance(token_dict, OccupantTokenObject): + raise HTTPException( + status_code=403, + detail="Occupant can not update post code.", + ) + return JSONResponse( + content={ + "completed": True, + "message": "Update Post Code record", + "data": {}, + }, + status_code=404, + ) + + +class AddressPostCodeListEventMethods(MethodToEvent): + + event_type = "SELECT" + event_description = "" + event_category = "" + + __event_keys__ = { + "88d37b78-1ac4-4513-9d25-090ac3a24f31": "list_post_code_address", + } + __event_validation__ = { + "88d37b78-1ac4-4513-9d25-090ac3a24f31": AddressPostCodeResponse, + } + + @classmethod + 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 + if not post_code_list: + raise HTTPException( + status_code=404, + detail="User has no post code registered or not yet any post code created.", + ) + + AddressPostcode.pre_query = AddressPostcode.filter_all( + AddressPostcode.id.in_( + [post_code.member_id for post_code in post_code_list] + ), + ).query + AddressPostcode.filter_attr = list_options + records = AddressPostcode.filter_all().data + return AlchemyJsonResponse( + completed=True, + message="List Address records", + result=records, + ) + + +AddressListEventMethod = AddressListEventMethods( + action=ActionsSchema(endpoint="/address/list") +) +AddressCreateEventMethod = AddressCreateEventMethods( + action=ActionsSchema(endpoint="/address/create") +) +AddressUpdateEventMethod = AddressUpdateEventMethods( + action=ActionsSchema(endpoint="/address/update") +) +AddressPatchEventMethod = AddressPatchEventMethods( + action=ActionsSchema(endpoint="/address/patch") +) +AddressPostCodeCreateEventMethod = AddressPostCodeCreateEventMethods( + action=ActionsSchema(endpoint="/postcode/create") +) +AddressPostCodeUpdateEventMethod = AddressPostCodeUpdateEventMethods( + action=ActionsSchema(endpoint="/postcode/update") +) +AddressPostCodeListEventMethod = AddressPostCodeListEventMethods( + action=ActionsSchema(endpoint="/postcode/list") +) +AddressSearchEventMethod = AddressSearchEventMethods( + action=ActionsSchema(endpoint="/address/search") +) diff --git a/api_events/events/application/__init__.py b/api_events/events/application/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_events/events/application/api.py b/api_events/events/application/api.py new file mode 100644 index 0000000..d250455 --- /dev/null +++ b/api_events/events/application/api.py @@ -0,0 +1,5 @@ +from api_events.events.abstract_class import MethodToEvent, ActionsSchema +from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject + + +class DecisionBookEvents(MethodToEvent): ... diff --git a/api_events/events/application/application.py b/api_events/events/application/application.py new file mode 100644 index 0000000..9dbf257 --- /dev/null +++ b/api_events/events/application/application.py @@ -0,0 +1,5 @@ +from api_events.events.abstract_class import MethodToEvent, ActionsSchema +from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject + + +class ApplicationEvents(MethodToEvent): ... diff --git a/api_events/events/application/authentication.py b/api_events/events/application/authentication.py new file mode 100644 index 0000000..c7fbf40 --- /dev/null +++ b/api_events/events/application/authentication.py @@ -0,0 +1,844 @@ +import datetime +import json +import typing +from typing import Union + +import arrow +from fastapi import status +from fastapi.requests import Request +from fastapi.exceptions import HTTPException +from fastapi.responses import JSONResponse + +from databases import ( + Companies, + Staff, + Duties, + Departments, + Employees, + BuildLivingSpace, + BuildParts, + Build, + Duty, + Event2Occupant, + Event2Employee, + Users, + UsersTokens, + OccupantTypes, + RelationshipEmployee2Build, +) + +from api_services import ( + redis_cli, + send_email, + get_object_via_access_key, + get_object_via_user_uu_id, + save_access_token_to_redis, + update_selected_to_redis, + password_is_changed_template, + change_your_password_template, +) + +from api_configs import ApiStatic, Auth +from api_events.events.abstract_class import MethodToEvent, ActionsSchema +from api_objects import ( + OccupantToken, + CompanyToken, + EmployeeTokenObject, + OccupantTokenObject, +) +from api_library.date_time_actions.date_functions import system_arrow + +from databases.no_sql_models.login_handlers import load_user_with_erp_details + +from api_validations.validations_request import ( + Login, + Logout, + ChangePassword, + Remember, + Forgot, + CreatePassword, + OccupantSelection, + EmployeeSelection, +) + + +class AuthenticationLoginEventMethods(MethodToEvent): + + event_type = "LOGIN" + event_description = "Login via domain and access key : [email] | [phone]" + event_category = "AUTHENTICATION" + + __event_keys__ = { + "e672846d-cc45-4d97-85d5-6f96747fac67": "authentication_login_with_domain_and_creds", + } + __event_validation__ = { + "e672846d-cc45-4d97-85d5-6f96747fac67": "authentication_login_with_domain_and_creds", + } + + @classmethod + def authentication_login_with_domain_and_creds( + cls, + data: Login, + request, + ): + access_dict = Users.login_user_with_credentials(data=data, request=request) + found_user = access_dict.get("user", None) + if not found_user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials" + ) + + return JSONResponse( + content={ + "completed": True, + "message": "User is logged in successfully", + "access_token": access_dict.get("access_token"), + "refresh_token": access_dict.get("refresher_token"), + "access_object": access_dict.get("access_object"), + "user": found_user.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + + +class AuthenticationSelectEventMethods(MethodToEvent): + + event_type = "LOGIN" + event_description = "Select Employee Duty or Occupant Type" + event_category = "AUTHENTICATION" + + __event_keys__ = { + "cee96b9b-8487-4e9f-aaed-2e8c79687bf9": "authentication_select_company_or_occupant_type", + } + __event_validation__ = { + "cee96b9b-8487-4e9f-aaed-2e8c79687bf9": "authentication_select_company_or_occupant_type", + } + + @classmethod + def authentication_select_company_or_occupant_type( + cls, + request: Request, + data: Union[EmployeeSelection, OccupantSelection], + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + from api_objects import OccupantToken, CompanyToken + + if isinstance(token_dict, EmployeeTokenObject): + if data.company_uu_id not in token_dict.companies_uu_id_list: + return JSONResponse( + content={ + "completed": False, + "message": "Company is not found in users company list", + }, + status_code=status.HTTP_401_UNAUTHORIZED, + ) + if selected_company := Companies.filter_one( + Companies.uu_id == data.company_uu_id, + ).data: + department_ids = [ + department.id + for department in Departments.filter_all( + Departments.company_id == selected_company.id, + ).data + ] + duties_ids = [ + duties.id + for duties in Duties.filter_all( + Duties.company_id == selected_company.id, + ).data + ] + staff_ids = [ + staff.id + for staff in Staff.filter_all( + Staff.duties_id.in_(duties_ids), + ).data + ] + employee = Employees.filter_one( + Employees.people_id == token_dict.person_id, + Employees.staff_id.in_(staff_ids), + ).data + reachable_event_list_id = Event2Employee.get_event_id_by_employee_id( + employee_id=employee.id + ) + staff = Staff.filter_one( + Staff.id == employee.staff_id, + ).data + duties = Duties.filter_one( + Duties.id == staff.duties_id, + ).data + department = Departments.filter_one( + Departments.id == duties.department_id, + ).data + bulk_id = Duty.filter_by_one(system=True, duty_code="BULK").data + bulk_duty_id = Duties.filter_by_one( + company_id=selected_company.id, + duties_id=bulk_id.id, + **Duties.valid_record_dict, + ).data + update_selected_to_redis( + request=request, + add_payload=CompanyToken( + company_uu_id=selected_company.uu_id.__str__(), + company_id=selected_company.id, + department_id=department.id, + department_uu_id=department.uu_id.__str__(), + duty_id=duties.id, + duty_uu_id=duties.uu_id.__str__(), + bulk_duties_id=bulk_duty_id.id, + staff_id=staff.id, + staff_uu_id=staff.uu_id.__str__(), + employee_id=employee.id, + employee_uu_id=employee.uu_id.__str__(), + reachable_event_list_id=reachable_event_list_id, + ), + ) + return JSONResponse( + content={ + "completed": True, + "message": "Company is selected successfully", + }, + status_code=status.HTTP_200_OK, + ) + elif isinstance(token_dict, OccupantTokenObject): + occupant_type = OccupantTypes.filter_by_one( + system=True, 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.filter_by_one( + system=True, 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.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_dict.person_id, + BuildLivingSpace.build_parts_id == build_part.id, + ).data: + reachable_event_list_id = ( + Event2Occupant.get_event_id_by_build_living_space_id( + build_living_space_id=selected_occupant_type.id + ) + ) + update_selected_to_redis( + request=request, + add_payload=OccupantToken( + living_space_id=selected_occupant_type.id, + living_space_uu_id=selected_occupant_type.uu_id.__str__(), + occupant_type_id=occupant_type.id, + occupant_type_uu_id=occupant_type.uu_id.__str__(), + occupant_type=occupant_type.occupant_type, + build_id=build.id, + build_uuid=build.uu_id.__str__(), + build_part_id=build_part.id, + build_part_uuid=build_part.uu_id.__str__(), + responsible_employee_id=responsible_employee.id, + responsible_employee_uuid=responsible_employee.uu_id.__str__(), + responsible_company_id=company_related.id, + responsible_company_uuid=company_related.uu_id.__str__(), + reachable_event_list_id=reachable_event_list_id, + ), + ) + return JSONResponse( + content={ + "completed": True, + "message": "Occupant is selected successfully", + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={"completed": False, "message": "Invalid data provided"}, + status_code=status.HTTP_418_IM_A_TEAPOT, + ) + + +class AuthenticationCheckTokenEventMethods(MethodToEvent): + + event_type = "LOGIN" + event_description = "Check Token is valid for user" + event_category = "AUTHENTICATION" + + __event_keys__ = { + "73d77e45-a33f-4f12-909e-3b56f00d8a12": "authentication_check_token_is_valid", + } + __event_validation__ = { + "73d77e45-a33f-4f12-909e-3b56f00d8a12": "authentication_check_token_is_valid", + } + + @classmethod + def authentication_check_token_is_valid( + cls, + request, + ): + if get_object_via_access_key(request=request): + return JSONResponse( + content={"completed": True, "message": "Access Token is valid"}, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={"completed": False, "message": "Access Token is NOT valid"}, + status_code=status.HTTP_401_UNAUTHORIZED, + ) + + +class AuthenticationRefreshEventMethods(MethodToEvent): + + event_type = "LOGIN" + event_description = ( + "Refresher Token for refreshing access token without credentials" + ) + event_category = "AUTHENTICATION" + + __event_keys__ = { + "48379bb2-ba81-4d8e-a9dd-58837cfcbf67": "authentication_refresh_user_info", + } + __event_validation__ = { + "48379bb2-ba81-4d8e-a9dd-58837cfcbf67": "authentication_refresh_user_info", + } + + @classmethod + 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.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), + } + return JSONResponse( + content={ + "completed": True, + "message": "User is logged in successfully via refresh token", + "data": load_user_with_erp_details(found_user, access_dict), + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={"completed": False, "message": "Invalid data", "data": {}}, + status_code=status.HTTP_401_UNAUTHORIZED, + ) + + +class AuthenticationChangePasswordEventMethods(MethodToEvent): + + event_type = "LOGIN" + event_description = "Change password with access token implemented on request headers without password reset token" + event_category = "AUTHENTICATION" + + __event_keys__ = { + "f09f7c1a-bee6-4e32-8444-962ec8f39091": "authentication_change_password", + } + __event_validation__ = { + "f09f7c1a-bee6-4e32-8444-962ec8f39091": "authentication_change_password", + } + + @classmethod + def authentication_change_password( + cls, + data: ChangePassword, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, EmployeeTokenObject): + if found_user := Users.filter_one(Users.uu_id == token_dict.uu_id).data: + if found_user.check_password(data.old_password): + found_user.set_password(data.new_password) + return JSONResponse( + content={ + "completed": True, + "message": "Password is changed successfully", + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={ + "completed": False, + "message": "Old password is not correct", + }, + status_code=status.HTTP_401_UNAUTHORIZED, + ) + return JSONResponse( + content={"completed": False, "message": "Invalid data"}, + status_code=status.HTTP_401_UNAUTHORIZED, + ) + + +class AuthenticationCreatePasswordEventMethods(MethodToEvent): + + event_type = "LOGIN" + event_description = "Create password with password reset token requested via email" + event_category = "AUTHENTICATION" + + __event_keys__ = { + "c519f9af-92e1-47b2-abf7-5a3316d075f7": "authentication_create_password", + } + __event_validation__ = { + "c519f9af-92e1-47b2-abf7-5a3316d075f7": "authentication_create_password", + } + + @classmethod + def authentication_create_password(cls, data: CreatePassword): + + if not data.re_password == data.password: + raise HTTPException( + status_code=status.HTTP_406_NOT_ACCEPTABLE, detail="Password must match" + ) + if found_user := Users.filter_one( + Users.password_token == data.password_token + ).data: + found_user.create_password(found_user=found_user, password=data.password) + found_user.password_token = "" + found_user.save() + send_email_completed = send_email( + subject=f"Dear {found_user.user_tag}, your password has been changed.", + receivers=[str(found_user.email)], + html=password_is_changed_template(user_name=found_user.user_tag), + ) + if not send_email_completed: + raise HTTPException( + status_code=400, detail="Email can not be sent. Try again later" + ) + return JSONResponse( + content={ + "completed": True, + "message": "Password is created successfully", + "data": found_user.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={ + "completed": False, + "message": "Record not found", + "data": {}, + }, + status_code=status.HTTP_202_ACCEPTED, + ) + + +class AuthenticationDisconnectUserEventMethods(MethodToEvent): + + event_type = "LOGIN" + event_description = "Disconnect all sessions of user in access token" + event_category = "AUTHENTICATION" + + __event_keys__ = { + "8b586848-2fb3-4161-abbe-642157eec7ce": "authentication_disconnect_user", + } + __event_validation__ = { + "8b586848-2fb3-4161-abbe-642157eec7ce": "authentication_disconnect_user", + } + + @classmethod + def authentication_disconnect_user( + cls, data: Logout, token_dict: Union[EmployeeTokenObject, OccupantTokenObject] + ): + found_user = Users.filter_one(Users.uu_id == token_dict.user_uu_id).data + if not found_user: + return JSONResponse( + content={ + "completed": False, + "message": "Invalid data", + "data": None, + }, + status_code=status.HTTP_202_ACCEPTED, + ) + if already_tokens := get_object_via_user_uu_id(user_id=str(found_user.uu_id)): + for key, token_user in already_tokens.items(): + redis_cli.delete(key) + selected_user = Users.filter_one( + Users.uu_id == token_user.get("uu_id"), + ).data + selected_user.remove_refresher_token( + domain=data.domain, disconnect=True + ) + return JSONResponse( + content={ + "completed": True, + "message": "All sessions are disconnected", + "data": selected_user.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={"completed": False, "message": "Invalid data", "data": None}, + status_code=status.HTTP_202_ACCEPTED, + ) + + +class AuthenticationLogoutEventMethods(MethodToEvent): + + event_type = "LOGIN" + event_description = "Logout only single session of user which domain is provided" + event_category = "AUTHENTICATION" + + __event_keys__ = { + "5cc22e4e-a0f7-4077-be41-1871feb3dfd1": "authentication_logout_user", + } + __event_validation__ = { + "5cc22e4e-a0f7-4077-be41-1871feb3dfd1": "authentication_logout_user", + } + + @classmethod + def authentication_logout_user( + cls, request: Request, data: Logout, token_dict: dict = None + ): + token_user = None + if already_tokens := get_object_via_access_key(request=request): + for key in already_tokens: + token_user = json.loads(redis_cli.get(key) or {}) + if token_user.get("domain") == data.domain: + redis_cli.delete(key) + selected_user = Users.filter_one( + Users.uu_id == token_user.get("uu_id"), + ).data + selected_user.remove_refresher_token(domain=data.domain) + + return JSONResponse( + content={ + "completed": True, + "message": "Session is logged out", + "data": token_user, + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={ + "completed": False, + "message": "Logout is not successfully completed", + "data": None, + }, + status_code=status.HTTP_202_ACCEPTED, + ) + + +class AuthenticationRefreshTokenEventMethods(MethodToEvent): + + event_type = "LOGIN" + event_description = "Refresh access token with refresher token" + event_category = "AUTHENTICATION" + + __event_keys__ = { + "c90f3334-10c9-4181-b5ff-90d98a0287b2": "authentication_refresher_token", + } + __event_validation__ = { + "c90f3334-10c9-4181-b5ff-90d98a0287b2": "authentication_refresher_token", + } + + @classmethod + def authentication_refresher_token( + cls, request: Request, data: Remember, token_dict: dict = None + ): + token_refresher = UsersTokens.filter_by_one( + token=data.refresh_token, + domain=data.domain, + **UsersTokens.valid_record_dict, + ).data + if not token_refresher: + return JSONResponse( + content={"completed": False, "message": "Invalid data", "data": {}}, + status_code=status.HTTP_202_ACCEPTED, + ) + 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 + ) + found_user.last_agent = request.headers.get("User-Agent", None) + found_user.last_platform = request.headers.get("Origin", None) + found_user.last_remote_addr = getattr( + request, "remote_addr", None + ) or request.headers.get("X-Forwarded-For", None) + found_user.last_seen = str(system_arrow.now()) + return JSONResponse( + content={ + "completed": True, + "message": "User is logged in successfully via refresher token", + "data": load_user_with_erp_details( + found_user, + { + "access_token": access_key, + "refresh_token": data.refresh_token, + }, + ), + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={"completed": False, "message": "Invalid data", "data": {}}, + status_code=status.HTTP_202_ACCEPTED, + ) + + +class AuthenticationForgotPasswordEventMethods(MethodToEvent): + + event_type = "LOGIN" + event_description = "Send an email to user for a valid password reset token" + event_category = "AUTHENTICATION" + + __event_keys__ = { + "e3ca6e24-b9f8-4127-949c-3bfa364e3513": "authentication_forgot_password", + } + __event_validation__ = { + "e3ca6e24-b9f8-4127-949c-3bfa364e3513": "authentication_forgot_password", + } + + @classmethod + def authentication_forgot_password( + cls, + request: Request, + data: Forgot, + ): + found_user: Users = Users.check_user_exits( + access_key=data.access_key, domain=data.domain + ) + forgot_key = save_access_token_to_redis( + request=request, found_user=found_user, domain=data.domain + ) + forgot_link = ApiStatic.forgot_link(forgot_key=forgot_key) + send_email_completed = send_email( + subject=f"Dear {found_user.user_tag}, your forgot password link has been sent.", + receivers=[str(found_user.email)], + html=change_your_password_template( + user_name=found_user.user_tag, forgot_link=forgot_link + ), + ) + if not send_email_completed: + raise HTTPException( + status_code=400, detail="Email can not be sent. Try again later" + ) + found_user.password_token = forgot_key + found_user.password_token_is_valid = str(system_arrow.shift(days=1)) + found_user.save() + + return JSONResponse( + content={ + "completed": True, + "message": "Password is change link is sent to your email or phone", + "data": {}, + }, + status_code=status.HTTP_200_OK, + ) + + +class AuthenticationResetPasswordEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "af9e121e-24bb-44ac-a616-471d5754360e": "authentication_reset_password", + } + + @classmethod + def authentication_reset_password(cls, data: Forgot): + from sqlalchemy import or_ + + found_user = Users.query.filter( + or_( + Users.email == str(data.access_key).lower(), + Users.phone_number == str(data.access_key).replace(" ", ""), + ), + ).first() + 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.", + ) + + reset_password_token = found_user.reset_password_token(found_user=found_user) + send_email_completed = send_email( + subject=f"Dear {found_user.user_tag}, a password reset request has been received.", + receivers=[str(found_user.email)], + html=change_your_password_template( + user_name=found_user.user_tag, + forgot_link=ApiStatic.forgot_link(forgot_key=reset_password_token), + ), + ) + if not send_email_completed: + raise found_user.raise_http_exception( + status_code=400, message="Email can not be sent. Try again later" + ) + return JSONResponse( + content={ + "completed": True, + "message": "Password change link is sent to your email or phone", + "data": found_user.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + + +class AuthenticationDownloadAvatarEventMethods(MethodToEvent): + + event_type = "LOGIN" + event_description = "Download avatar icon and profile info of user" + event_category = "AUTHENTICATION" + + __event_keys__ = { + "c140cd5f-307f-4046-a93e-3ade032a57a7": "authentication_download_avatar", + } + __event_validation__ = { + "c140cd5f-307f-4046-a93e-3ade032a57a7": "authentication_download_avatar", + } + + @classmethod + def authentication_download_avatar( + cls, token_dict: Union[EmployeeTokenObject, OccupantTokenObject] + ): + if found_user := Users.filter_one(Users.id == token_dict.user_id).data: + expired_starts = str( + system_arrow.now() - system_arrow.get(str(found_user.expiry_ends)) + ) + expired_int = ( + system_arrow.now() - system_arrow.get(str(found_user.expiry_ends)) + ).days + + return JSONResponse( + content={ + "completed": True, + "message": "Avatar and profile is shared via user credentials", + "data": { + "lang": token_dict.lang, + "full_name": found_user.person.full_name, + "avatar": found_user.avatar, + "remember_me": found_user.remember_me, + "expiry_ends": str(found_user.expiry_ends), + "expired_str": expired_starts, + "expired_int": int(expired_int), + }, + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={"completed": False, "message": "Invalid data", "data": {}}, + status_code=status.HTTP_202_ACCEPTED, + ) + + +AuthenticationLoginEventMethod = AuthenticationLoginEventMethods( + action=ActionsSchema(endpoint="/authentication/login") +) +AuthenticationSelectEventMethod = AuthenticationSelectEventMethods( + action=ActionsSchema(endpoint="/authentication/select") +) +AuthenticationCheckTokenEventMethod = AuthenticationCheckTokenEventMethods( + action=ActionsSchema(endpoint="/authentication/valid") +) +AuthenticationRefreshEventMethod = AuthenticationRefreshEventMethods( + action=ActionsSchema(endpoint="/authentication/refresh") +) +AuthenticationChangePasswordEventMethod = AuthenticationChangePasswordEventMethods( + action=ActionsSchema(endpoint="/authentication/change_password") +) +AuthenticationCreatePasswordEventMethod = AuthenticationCreatePasswordEventMethods( + action=ActionsSchema(endpoint="/authentication/create_password") +) +AuthenticationDisconnectUserEventMethod = AuthenticationDisconnectUserEventMethods( + action=ActionsSchema(endpoint="/authentication/disconnect") +) +AuthenticationLogoutEventMethod = AuthenticationLogoutEventMethods( + action=ActionsSchema(endpoint="/authentication/logout") +) +AuthenticationRefreshTokenEventMethod = AuthenticationRefreshTokenEventMethods( + action=ActionsSchema(endpoint="/authentication/refresher") +) +AuthenticationForgotPasswordEventMethod = AuthenticationForgotPasswordEventMethods( + action=ActionsSchema(endpoint="/authentication/forgot") +) +AuthenticationDownloadAvatarEventMethod = AuthenticationDownloadAvatarEventMethods( + action=ActionsSchema(endpoint="/authentication/avatar") +) +AuthenticationResetPasswordEventMethod = AuthenticationResetPasswordEventMethods( + action=ActionsSchema(endpoint="/authentication/reset_password") +) + +# UserLogger.log_error( +# str( +# dict( +# user_id=found_user.id, +# domain=data.domain, +# access_key=token_user.get("access_input"), +# agent=request.headers.get("User-Agent", None), +# ip=getattr(request, "remote_addr", None) +# or request.headers.get("X-Forwarded-For", None), +# platform=request.headers.get("Origin", None), +# login_date=datetime.datetime.utcnow().__str__(), +# is_login=False, +# ) +# ) +# ) + +# UserLogger.log_error( +# str( +# dict( +# user_id=found_user.id, +# domain=data.domain, +# access_key=data.access_key, +# agent=request.headers.get("User-Agent", None), +# ip=getattr(request, "remote_addr", None) +# or request.headers.get("X-Forwarded-For", None), +# platform=request.headers.get("Origin", None), +# login_date=str(DateTimeLocal.now()), +# is_login=False, +# ) +# ) +# ) +# UserLogger.log_error( +# str( +# dict( +# user_id=found_user.id, +# domain=data.domain, +# access_key="via_refresher", +# agent=request.headers.get("User-Agent", None), +# ip=getattr(request, "remote_addr", None) +# or request.headers.get("X-Forwarded-For", None), +# platform=request.headers.get("Origin", None), +# login_date=datetime.datetime.utcnow().__str__(), +# is_login=False, +# ) +# ) +# ) +# UserLogger.log_error( +# str( +# dict( +# user_id=selected_user.id, +# domain=data.domain, +# access_key=token_user.get("access_input"), +# agent=request.headers.get("User-Agent", None), +# ip=getattr(request, "remote_addr", None) +# or request.headers.get("X-Forwarded-For", None), +# platform=request.headers.get("Origin", None), +# login_date=datetime.datetime.utcnow().__str__(), +# is_login=False, +# ) +# ) +# ) diff --git a/api_events/events/application/rules.py b/api_events/events/application/rules.py new file mode 100644 index 0000000..61e684a --- /dev/null +++ b/api_events/events/application/rules.py @@ -0,0 +1,5 @@ +from api_events.events.abstract_class import MethodToEvent, ActionsSchema +from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject + + +class RulesEvents(MethodToEvent): ... diff --git a/api_events/events/building/__init__.py b/api_events/events/building/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_events/events/building/building_build.py b/api_events/events/building/building_build.py new file mode 100644 index 0000000..e492d2f --- /dev/null +++ b/api_events/events/building/building_build.py @@ -0,0 +1,308 @@ +import typing +from typing import Union + +from fastapi import status, HTTPException +from fastapi.responses import JSONResponse + +from databases import ( + Build, + RelationshipEmployee2Build, + Addresses, + BuildParts, + BuildTypes, + ApiEnumDropdown, +) + +from api_validations.validations_request import ( + InsertBuild, + UpdateBuild, + PatchRecord, + ListOptions, +) +from api_validations.validations_response import ListBuildingResponse + +from api_validations.core_response import AlchemyJsonResponse +from api_events.events.abstract_class import MethodToEvent, ActionsSchema +from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject + + +class BuildListEventMethods(MethodToEvent): + + event_type = "SELECT" + event_description = "" + event_category = "" + + __event_keys__ = { + "68b3b5ed-b74c-4a27-820f-3959214e94e9": "build_list", + } + __event_validation__ = { + "68b3b5ed-b74c-4a27-820f-3959214e94e9": ListBuildingResponse, + } + + @classmethod + def build_list( + cls, + list_options: ListOptions, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, OccupantTokenObject): + Build.pre_query = Build.filter_all( + Build.id == token_dict.selected_occupant.build_id, + ).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_all() + return AlchemyJsonResponse( + completed=True, + message="Building Records are listed", + result=records, + response_model=ListBuildingResponse, + ) + + +class BuildCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + event_description = "" + event_category = "" + __event_keys__ = { + "a2271854-6b90-43da-a440-a62b70d90528": "build_create", + "b67ee709-0992-4604-9f90-fb1da10d5cf9": "create_building_employee", + } + __event_validation__ = { + "a2271854-6b90-43da-a440-a62b70d90528": InsertBuild, + "b67ee709-0992-4604-9f90-fb1da10d5cf9": InsertBuild, + } + + @classmethod + def build_create(cls, data: InsertBuild, token_dict: EmployeeTokenObject): + if not token_dict.selected_company.employee_id: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=f"Employee id is not found for {token_dict.selected_company.employee_uu_id}", + ) + + if not token_dict.selected_company.company_id: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=f"Company id is not found for {token_dict.selected_company.company_uu_id}", + ) + + created_build = Build.create_action(data=data, token=token_dict) + build_type = BuildTypes.filter_by_one( + **BuildTypes.valid_record_dict, 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.filter_by_one(enum_class="Directions", key="NN").data + if not api_enum: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Api Enum NN is not found. Please contact with your system administrator.", + ) + build_parts = dict( + address_gov_code=f"{data.gov_address_code}-M", + build_id=int(created_build.id), + build_uu_id=str(created_build.uu_id), + part_no="0", + part_type_id=int(build_type.id), + part_type_uu_id=str(build_type.uu_id), + part_direction_id=int(api_enum.id), + part_direction_uu_id=str(api_enum.uu_id), + part_code="MAN-ROOM", + human_livable=False, + ) + man_build_part = BuildParts.find_or_create(**build_parts) + created_build.save() + created_build.update(management_room_id=man_build_part.id) + created_build.save() + man_build_part.update(is_confirmed=True) + man_build_part.save() + # created_build_relation = 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, + # ) + # created_build_relation.update(is_confirmed=True) + # created_build_relation.save() + 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, + ) + + @classmethod + def create_building_employee( + cls, data: InsertBuild, token_dict: EmployeeTokenObject + ): + records = Addresses.list_via_employee( + token_dict=token_dict, filter_expr=[Addresses.uu_id == data.address_uu_id] + ).data + if not records: + raise HTTPException( + status_code=404, + detail=f"This address {data.address_uu_id} is not found in the user's address list.", + ) + + if not token_dict.selected_company.employee_id: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=f"Employee id is not found for {token_dict.selected_company.employee_uu_id}", + ) + + if not token_dict.selected_company.company_id: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=f"Company id is not found for {token_dict.selected_company.company_uu_id}", + ) + + created_build = Build.create_action(data=data, token=token_dict) + + created_build_relation = 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, + ) + created_build.save() + 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, + ) + + +class BuildUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + event_description = "" + event_category = "" + + __class_key__ = "" + __event_keys__ = { + "5ad38a66-1189-451e-babb-77de2d63d757": "build_update", + } + __event_validation__ = { + "5ad38a66-1189-451e-babb-77de2d63d757": UpdateBuild, + } + + @classmethod + def build_update( + cls, + build_uu_id: str, + data: UpdateBuild, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, OccupantTokenObject): + Build.pre_query = Build.select_action( + employee_id=token_dict.selected_company.employee_id + ) + updated_build = Build.update_action( + data=data, token=token_dict, build_uu_id=build_uu_id + ) + Build.save() + return JSONResponse( + content={ + "completed": True, + "message": "Update Build record", + "data": updated_build.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + elif isinstance(token_dict, EmployeeTokenObject): + find_one_build = Build.filter_one( + Build.uu_id == build_uu_id, + ).data + access_authorized_build = Build.select_action( + employee_id=token_dict.selected_company.employee_id, + filter_expr=[Build.id == find_one_build.id], + ) + if access_authorized_build.count: + updated_build = Build.update_action( + data=data, token=token_dict, build_uu_id=build_uu_id + ) + return JSONResponse( + content={ + "completed": True, + "message": "Update Build record", + "data": updated_build.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=f"This user can not modify {build_uu_id} - building.", + ) + + +class BuildPatchEventMethods(MethodToEvent): + + event_type = "PATCH" + event_description = "" + event_category = "" + + __event_keys__ = { + "e3876bfe-8847-4dea-ae36-e709f7431930": "build_patch", + } + __event_validation__ = { + "e3876bfe-8847-4dea-ae36-e709f7431930": "build_patch", + } + + @classmethod + def build_patch(cls, build_uu_id: str, data: PatchRecord, token_dict): + find_one_build = Build.filter_one( + Build.uu_id == build_uu_id, + ) + access_authorized_build = Build.select_action( + employee_id=token_dict.selected_company.employee_id, + filter_expr=[Build.id == find_one_build.id], + ) + if access_authorized_build.count: + action = data.excluded_dump() + find_one_build.active = bool(action.get("active", find_one_build.active)) + find_one_build.is_confirmed = bool( + action.get("confirm", find_one_build.is_confirmed) + ) + find_one_build.deleted = bool(action.get("delete", find_one_build.deleted)) + find_one_build.save() + return JSONResponse( + content={ + "completed": True, + "message": "Patch Build record completed", + "data": find_one_build.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={ + "completed": False, + "message": "Patch Build record failed", + "data": {}, + }, + status_code=status.HTTP_200_OK, + ) + + +BuildListEventMethod = BuildListEventMethods( + action=ActionsSchema(endpoint="/building/build/list") +) +BuildCreateEventMethod = BuildCreateEventMethods( + action=ActionsSchema(endpoint="/building/build/create") +) +BuildUpdateEventMethod = BuildUpdateEventMethods( + action=ActionsSchema(endpoint="/building/build/update") +) +BuildPatchEventMethod = BuildPatchEventMethods( + action=ActionsSchema(endpoint="/building/build/patch") +) diff --git a/api_events/events/building/building_build_area.py b/api_events/events/building/building_build_area.py new file mode 100644 index 0000000..735e4d8 --- /dev/null +++ b/api_events/events/building/building_build_area.py @@ -0,0 +1,176 @@ +import typing + +from databases import ( + Build, + BuildArea, +) + +from api_validations.validations_request import ( + InsertBuildArea, + UpdateBuildArea, + ListOptions, +) + +from api_validations.core_response import AlchemyJsonResponse +from api_events.events.abstract_class import MethodToEvent, ActionsSchema +from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject + + +class BuildAreaListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "0bb51845-65a2-4340-8872-a3b5aad95468": "build_area_list", + } + __event_validation__ = { + "0bb51845-65a2-4340-8872-a3b5aad95468": None, + } + + @classmethod + def build_area_list( + cls, + list_options: ListOptions, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, OccupantTokenObject): + build_ids = Build.filter_all( + Build.id == token_dict.selected_occupant.build_id, + ).data + BuildArea.pre_query = BuildArea.filter_all( + BuildArea.build_id.in_([build.id for build in build_ids]), + ).query + elif isinstance(token_dict, EmployeeTokenObject): + build_ids = Build.select_action( + employee_id=token_dict.selected_company.employee_id + ) + BuildArea.pre_query = BuildArea.filter_all( + BuildArea.build_id.in_([build.id for build in build_ids]), + ).query + BuildArea.filter_attr = list_options + records = BuildArea.filter_all() + return AlchemyJsonResponse( + completed=True, message="List of Build Area", result=records + ) + + +class BuildAreaCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "a10571fa-ac1d-4546-9272-cacb911d8004": "build_area_create", + } + __event_validation__ = { + "a10571fa-ac1d-4546-9272-cacb911d8004": InsertBuildArea, + } + + @classmethod + def build_area_create( + cls, + data: InsertBuildArea, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + data_dict = data.excluded_dump() + selected_build = None + if isinstance(token_dict, OccupantTokenObject): + if not token_dict.selected_occupant.build_uuid == data.build_uu_id: + BuildArea.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="UNAUTHORIZED", + message=f"Occupant can not create build area for {data.build_uu_id}", + data={ + "build_uu_id": data.build_uu_id, + }, + ) + selected_build = Build.filter_by_one( + system=True, uu_id=data.build_uu_id + ).data + elif isinstance(token_dict, EmployeeTokenObject): + build_ids = Build.select_action( + employee_id=token_dict.selected_company.employee_id + ).all() + if not str(data.build_uu_id) in [str(build.uu_id) for build in build_ids]: + BuildArea.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="UNAUTHORIZED", + message=f"Employee can not create build area for {data.build_uu_id}", + data={ + "build_uu_id": data.build_uu_id, + }, + ) + selected_build = Build.filter_by_one( + system=True, uu_id=data.build_uu_id + ).data + + data_dict["build_id"] = selected_build.id + data_dict["build_uu_id"] = str(selected_build.uu_id) + created_build_part = BuildArea.find_or_create(**data_dict) + created_build_part.save() + created_build_part.update(is_confirmed=True) + created_build_part.save() + return AlchemyJsonResponse( + completed=True, + message="Created Build Area", + result=created_build_part.get_dict(), + ) + + +class BuildAreaUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "58178738-7489-4f8f-954e-5c8f083c1845": "build_area_update", + } + __event_validation__ = { + "58178738-7489-4f8f-954e-5c8f083c1845": UpdateBuildArea, + } + + @classmethod + def build_area_update( + cls, + build_uu_id: str, + data: UpdateBuildArea, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + return AlchemyJsonResponse( + completed=False, + message="Update Build record", + result=None, + ) + + +class BuildAreaPatchEventMethods(MethodToEvent): + + event_type = "PATCH" + __event_keys__ = { + "d6bd8a5f-fa76-49da-b82e-4a95f1bcce39": "build_area_patch", + } + __event_validation__ = { + "d6bd8a5f-fa76-49da-b82e-4a95f1bcce39": None, + } + + @classmethod + def build_area_patch( + cls, + build_uu_id: str, + data, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + return AlchemyJsonResponse( + completed=False, + message="Patch Build record", + result=None, + ) + + +BuildAreaListEventMethod = BuildAreaListEventMethods( + action=ActionsSchema(endpoint="/building/area/list") +) +BuildAreaCreateEventMethod = BuildAreaCreateEventMethods( + action=ActionsSchema(endpoint="/building/area/create") +) +BuildAreaUpdateEventMethod = BuildAreaUpdateEventMethods( + action=ActionsSchema(endpoint="/building/area/update") +) +BuildAreaPatchEventMethod = BuildAreaPatchEventMethods( + action=ActionsSchema(endpoint="/building/area/patch") +) diff --git a/api_events/events/building/building_build_parts.py b/api_events/events/building/building_build_parts.py new file mode 100644 index 0000000..49e23f6 --- /dev/null +++ b/api_events/events/building/building_build_parts.py @@ -0,0 +1,165 @@ +from typing import Union + +from fastapi.responses import JSONResponse +from fastapi import status + +from api_validations.validations_response.parts import BuildPartsListResponse +from databases import ( + Build, + BuildParts, +) +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_validations.validations_request import ( + InsertBuildParts, + UpdateBuildParts, + ListOptions, +) + + +class BuildingBuildPartsListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "b860e37a-e19b-4c45-9543-461241f7587c": "building_build_parts_list" + } + __event_validation__ = { + "b860e37a-e19b-4c45-9543-461241f7587c": BuildPartsListResponse + } + + @classmethod + 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, + ) + build_list_ids = [build.id for build in build_list_query.all()] + BuildParts.pre_query = BuildParts.filter_all( + BuildParts.build_id.in_(build_list_ids), + ).query + BuildParts.filter_attr = list_options + records = BuildParts.filter_all() + return AlchemyJsonResponse( + completed=True, + message="Building Parts Records are listed", + result=records, + cls_object=BuildParts, + response_model=BuildPartsListResponse, + filter_attributes=list_options, + ) + + +class BuildingBuildPartsCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "fb403f69-11ed-4f4f-ad71-5e6fb4a793d2": "building_build_parts_create" + } + __event_validation__ = {"fb403f69-11ed-4f4f-ad71-5e6fb4a793d2": InsertBuildParts} + + @classmethod + def building_build_parts_create( + cls, + data: InsertBuildParts, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + created_build = BuildParts.create_action(data=data, token=token_dict) + created_build.save() + created_build.update(is_confirmed=True) + created_build.save() + return JSONResponse( + content={ + "completed": True, + "message": "Create Build Parts record", + "data": created_build.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + + +class BuildingBuildPartsUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "58fdf95e-2110-4ed6-9c26-95f4be87eaee": "building_build_parts_update" + } + __event_validation__ = {"58fdf95e-2110-4ed6-9c26-95f4be87eaee": UpdateBuildParts} + + @classmethod + def building_build_parts_update( + cls, + data: UpdateBuildParts, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + updated_build = BuildParts.update_action(data=data, token=token_dict) + updated_build.save() + return JSONResponse( + content={ + "completed": True, + "message": "Update Build Parts record", + "data": updated_build, + }, + status_code=status.HTTP_200_OK, + ) + + +class BuildingBuildPartsPatchEventMethods(MethodToEvent): + + event_type = "PATCH" + __event_keys__ = { + "87a15ade-3474-4206-b574-bbf8580cbb14": "building_build_parts_patch" + } + __event_validation__ = {"87a15ade-3474-4206-b574-bbf8580cbb14": None} + + @classmethod + def building_build_parts_patch(cls, data, token_dict): + 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], + ) + if access_authorized_build.count: + action = data.excluded_dump() + find_one_build.active = bool(action.get("active", find_one_build.active)) + find_one_build.is_confirmed = bool( + action.get("confirm", find_one_build.is_confirmed) + ) + find_one_build.deleted = bool(action.get("delete", find_one_build.deleted)) + find_one_build.save() + return JSONResponse( + content={ + "completed": True, + "message": "Update Build Parts record", + "data": find_one_build.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={ + "completed": False, + "message": "Update Build Parts record", + "data": {}, + }, + status_code=status.HTTP_200_OK, + ) + + +BuildingBuildPartsListEventMethod = BuildingBuildPartsListEventMethods( + action=ActionsSchema(endpoint="/building/parts/list") +) +BuildingBuildPartsCreateEventMethod = BuildingBuildPartsCreateEventMethods( + action=ActionsSchema(endpoint="/building/parts/create") +) +BuildingBuildPartsUpdateEventMethod = BuildingBuildPartsUpdateEventMethods( + action=ActionsSchema(endpoint="/building/parts/update") +) +BuildingBuildPartsPatchEventMethod = BuildingBuildPartsPatchEventMethods( + action=ActionsSchema(endpoint="/building/parts/patch") +) diff --git a/api_events/events/building/building_build_sites.py b/api_events/events/building/building_build_sites.py new file mode 100644 index 0000000..f8a5a61 --- /dev/null +++ b/api_events/events/building/building_build_sites.py @@ -0,0 +1,175 @@ +import typing + +from databases import ( + Build, + BuildSites, +) + +from api_validations.validations_request import ( + InsertBuildArea, + UpdateBuildArea, + ListOptions, +) + +from api_validations.core_response import AlchemyJsonResponse +from api_events.events.abstract_class import MethodToEvent, ActionsSchema +from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject +from databases.sql_models.identity.identity import Addresses + + +class BuildSitesListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "6798414c-6c7d-47f0-9d8b-6935a0f51c2e": "build_sites_list", + } + __event_validation__ = { + "6798414c-6c7d-47f0-9d8b-6935a0f51c2e": None, + } + + @classmethod + def build_sites_list( + cls, + list_options: ListOptions, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, OccupantTokenObject): + occupants_build = Build.filter_one( + Build.id == token_dict.selected_occupant.build_id, + ).data + BuildSites.pre_query = BuildSites.filter_all( + BuildSites.address_id == occupants_build.address_id, + ).query + elif isinstance(token_dict, EmployeeTokenObject): + employees_build = Build.select_action( + employee_id=token_dict.selected_company.employee_id + ) + employees_build_list = [build.address_id for build in employees_build.all()] + if not employees_build_list: + BuildSites.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="NOT_FOUND", + message="Employee has no build sites registered", + data={}, + ) + BuildSites.pre_query = BuildSites.filter_all( + BuildSites.address_id.in_(employees_build_list) + ).query + BuildSites.filter_attr = list_options + records = BuildSites.filter_all() + return AlchemyJsonResponse( + completed=True, message="Update Build record", result=records + ) + + +class BuildSitesCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "57edc8bf-8f29-4e75-b5e1-9ca0139a3fda": "build_sites_create", + } + __event_validation__ = { + "57edc8bf-8f29-4e75-b5e1-9ca0139a3fda": InsertBuildArea, + } + + @classmethod + def build_area_create( + cls, + data: InsertBuildArea, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, OccupantTokenObject): + if not token_dict.selected_occupant.build_uuid == data.build_uu_id: + BuildSites.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="UNAUTHORIZED", + message=f"Occupant can not create build sites for {data.build_uu_id}", + data={ + "build_uu_id": data.build_uu_id, + }, + ) + elif isinstance(token_dict, EmployeeTokenObject): + build_ids = Build.select_action( + employee_id=token_dict.selected_company.employee_id + ).all() + if not str(data.build_uu_id) in [str(build.uu_id) for build in build_ids]: + BuildSites.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="UNAUTHORIZED", + message=f"Employee can not create build sites for {data.build_uu_id}", + data={ + "build_uu_id": data.build_uu_id, + }, + ) + data_dict = data.excluded_dump() + created_build_part = BuildSites.find_or_create(**data_dict) + created_build_part.save() + created_build_part.update(is_confirmed=True) + created_build_part.save() + return AlchemyJsonResponse( + completed=True, + message="Update Build record", + result=created_build_part, + ) + + +class BuildSitesUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "b18e8e37-a62b-4a84-9972-ba17121ed393": "build_sites_update", + } + __event_validation__ = { + "b18e8e37-a62b-4a84-9972-ba17121ed393": UpdateBuildArea, + } + + @classmethod + def build_area_update( + cls, + build_uu_id: str, + data: UpdateBuildArea, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + return AlchemyJsonResponse( + completed=False, + message="Update Build record", + result=None, + ) + + +class BuildSitesPatchEventMethods(MethodToEvent): + + event_type = "PATCH" + __event_keys__ = { + "39ba1d78-ff0d-4ec7-a363-b457cbf199a0": "build_sites_patch", + } + __event_validation__ = { + "39ba1d78-ff0d-4ec7-a363-b457cbf199a0": None, + } + + @classmethod + def build_area_patch( + cls, + build_uu_id: str, + data, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + return AlchemyJsonResponse( + completed=False, + message="Patch Build record", + result=None, + ) + + +BuildSitesListEventMethod = BuildSitesListEventMethods( + action=ActionsSchema(endpoint="/building/sites/list") +) +BuildSitesCreateEventMethod = BuildSitesCreateEventMethods( + action=ActionsSchema(endpoint="/building/sites/create") +) +BuildSitesUpdateEventMethod = BuildSitesUpdateEventMethods( + action=ActionsSchema(endpoint="/building/sites/update") +) +BuildSitesPatchEventMethod = BuildSitesPatchEventMethods( + action=ActionsSchema(endpoint="/building/sites/patch") +) diff --git a/api_events/events/building/building_build_types.py b/api_events/events/building/building_build_types.py new file mode 100644 index 0000000..a2fa3a8 --- /dev/null +++ b/api_events/events/building/building_build_types.py @@ -0,0 +1,48 @@ +from typing import Union + +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_validations.validations_request import ( + ListOptions, +) +from databases.sql_models.building.build import BuildTypes + + +class BuildTypesListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "5344d03c-fc47-43ec-8c44-6c2acd7e5d9f": "build_types_list", + } + __event_validation__ = {"5344d03c-fc47-43ec-8c44-6c2acd7e5d9f": None} + + @classmethod + def build_types_list( + cls, + list_options: ListOptions, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + from fastapi.exceptions import HTTPException + + if isinstance(token_dict, EmployeeTokenObject): + BuildTypes.filter_attr = list_options + results = BuildTypes.filter_all() + return AlchemyJsonResponse( + completed=True, + result=results, + message="Build Types are listed successfully", + ) + elif isinstance(token_dict, OccupantTokenObject): + raise HTTPException( + status_code=403, detail="You are not authorized to access this endpoint" + ) + else: + raise HTTPException( + status_code=403, detail="You are not authorized to access this endpoint" + ) + + +BuildTypesListEventMethod = BuildTypesListEventMethods( + action=ActionsSchema(endpoint="/building/types/list") +) diff --git a/api_events/events/building/building_living_spaces.py b/api_events/events/building/building_living_spaces.py new file mode 100644 index 0000000..5d5602a --- /dev/null +++ b/api_events/events/building/building_living_spaces.py @@ -0,0 +1,307 @@ +from typing import Union + + +from api_events.events.events.events_bind_services import ( + ServiceBindOccupantEventMethods, +) +from databases import ( + Modules, + BuildParts, + Build, + BuildLivingSpace, + OccupantTypes, + People, +) +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_validations.validations_request import ( + InsertBuildLivingSpace, + UpdateBuildLivingSpace, + ListOptions, +) +from api_validations.validations_response.living_space import LivingSpaceListResponse +from databases.sql_models.event.event import Services + + +class BuildingLivingSpacesListEventMethods(MethodToEvent): + + event_type = "SELECT" + event_description = "" + event_category = "" + __event_keys__ = { + "36961d8a-cefa-46cc-9f7c-9d841d6351b6": "building_live_space_list", + } + __event_validation__ = { + "36961d8a-cefa-46cc-9f7c-9d841d6351b6": LivingSpaceListResponse + } + + @classmethod + def building_live_space_list( + cls, + list_options: ListOptions, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + records, Build.filter_attr = [], None + if isinstance(token_dict, OccupantTokenObject): + occupants_build_id = Build.filter_one( + Build.id == token_dict.selected_occupant.build_id, + ).data + if not occupants_build_id: + Build.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="UNAUTHORIZED", + message=f"Occupant has no build registered in the system. Contact with your company.", + data={}, + ) + occupants_build_parts = BuildParts.filter_all( + BuildParts.build_id.in_(occupants_build_id.id), + ).data + if not occupants_build_parts: + Build.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="UNAUTHORIZED", + message=f"Occupant has no build parts registered in the system. Contact with your company.", + data={}, + ) + BuildLivingSpace.pre_query = BuildLivingSpace.filter_all( + BuildLivingSpace.build_parts_id.in_( + [build_part.id for build_part in occupants_build_parts] + ), + ).query + BuildLivingSpace.filter_attr = list_options + records = BuildLivingSpace.filter_all() + elif isinstance(token_dict, EmployeeTokenObject): + build_id_list_query = Build.select_action( + employee_id=token_dict.selected_company.employee_id + ) + if not build_id_list_query: + Build.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="UNAUTHORIZED", + message=f"Employee has no build registered in the system. Contact with your supervisor.", + data={}, + ) + build_part_id_list_query = BuildParts.filter_all( + BuildParts.build_id.in_( + [build.id for build in build_id_list_query.all()] + ), + ).data + if not build_part_id_list_query: + Build.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="UNAUTHORIZED", + message=f"Employee has no build parts registered in the system. Contact with your supervisor.", + data={}, + ) + BuildLivingSpace.pre_query = BuildLivingSpace.filter_all( + BuildLivingSpace.build_parts_id.in_( + [build_part.id for build_part in build_part_id_list_query] + ), + ).query + BuildLivingSpace.filter_attr = list_options + records = BuildLivingSpace.filter_all() + return AlchemyJsonResponse( + completed=True, + message="Building Living Spaces are listed successfully", + result=records, + response_model=LivingSpaceListResponse, + cls_object=BuildLivingSpace, + filter_attributes=list_options, + ) + + +class BuildingLivingSpacesCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "46d90119-3b23-4784-8053-fe11da4a3584": "building_live_space_create" + } + __event_validation__ = { + "46d90119-3b23-4784-8053-fe11da4a3584": InsertBuildLivingSpace + } + + @classmethod + def building_live_space_create( + cls, + data: InsertBuildLivingSpace, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + from api_library.date_time_actions.date_functions import system_arrow + + data_dict = data.excluded_dump() + build_id_list_query = Build.select_action( + employee_id=token_dict.selected_company.employee_id + ) + 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()]), + ).data + if not build_part: + BuildLivingSpace.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="UNAUTHORIZED", + message=f"{data.build_parts_uu_id} - Build Part is not found in database. Check build part uu_id", + data={ + "build_parts_uu_id": data.build_parts_uu_id, + }, + ) + life_person = People.filter_one( + People.uu_id == data.person_uu_id, + ).data + if not life_person: + BuildLivingSpace.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="UNAUTHORIZED", + message=f"{data.person_uu_id} - Living Person is not found in database.", + data={ + "person_uu_id": data.person_uu_id, + }, + ) + occupant_type = OccupantTypes.filter_by_one(uu_id=data.occupant_type_uu_id).data + if not occupant_type: + BuildLivingSpace.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="UNAUTHORIZED", + message=f"{data.occupant_type_uu_id} - Occupant Type is not found in database. Check occupant type uu_id", + data={ + "occupant_type_uu_id": data.occupant_type_uu_id, + }, + ) + + data_dict["occupant_type"] = occupant_type.id + data_dict["occupant_type_uu_id"] = str(occupant_type.uu_id) + data_dict["build_parts_id"] = build_part.id + data_dict["build_parts_uu_id"] = str(build_part.uu_id) + data_dict["person_id"] = life_person.id + data_dict["person_uu_id"] = str(life_person.uu_id) + + 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, + 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, + ).data + created_living_space = BuildLivingSpace.create_action( + data=data_dict, token_dict=token_dict + ) + if last_living_space: + dt = system_arrow.get(last_living_space.expiry_ends) + if dt > system_arrow.now(): + minute_df = int(dt.time().minute) - 10 + last_living_space.expiry_ends = str( + dt.replace( + minute=60 - abs(minute_df) if minute_df < 0 else minute_df + ) + ) + last_living_space.save() + + created_living_space.save_and_confirm() + occupants_service = Services.retrieve_service_via_occupant_code( + occupant_code=occupant_type.occupant_code + ) + ServiceBindOccupantEventMethods.bind_services_occupant_system( + build_living_space_id=created_living_space.id, + service_id=occupants_service.id, + ) + return created_living_space + + +class BuildingLivingSpacesUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "c786e15c-c03e-4e8f-936c-7e5e5ec9bbcc": "building_live_space_update", + } + __event_validation__ = { + "c786e15c-c03e-4e8f-936c-7e5e5ec9bbcc": UpdateBuildLivingSpace + } + + @classmethod + def building_live_space_update( + cls, + build_uu_id: str, + data: UpdateBuildLivingSpace, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + from api_library.date_time_actions.date_functions import system_arrow + + if isinstance(token_dict, OccupantTokenObject): + data_dict = data.dump() + build_id_list_query = Build.select_action( + employee_id=token_dict.selected_company.employee_id + ) + 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()] + ), + ).data + if not build_part: + BuildLivingSpace.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="UNAUTHORIZED", + message=f"{data.life_person_uu_id} - Living Person is not found in database.", + data={ + "person_uu_id": data.life_person_uu_id, + }, + ) + life_person = People.filter_one( + People.uu_id == data.life_person_uu_id or "" + ).data + if not life_person: + BuildLivingSpace.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="UNAUTHORIZED", + message=f"{data.life_person_uu_id} - Living Person is not found in database.", + data={ + "person_uu_id": data.life_person_uu_id, + }, + ) + + living_space_id = BuildLivingSpace.select_only( + *BuildLivingSpace.valid_record_args(BuildLivingSpace), + select_args=[BuildLivingSpace.id], + order_by=BuildLivingSpace.expiry_starts.desc(), + limit=1, + ).get(1) + + last_living_space = BuildLivingSpace.filter_one( + 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) + data_dict["build_parts_id"] = build_part.id + if data_dict["is_tenant_live"]: + owner_person = getattr(last_living_space, "owner_person_id", None) + if not owner_person: + BuildLivingSpace.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="UNAUTHORIZED", + message="Owner person of build part is not defined. Please register owner of part first.", + data=build_part.get_dict(), + ) + data_dict["life_person_id"] = life_person.id + data_dict["owner_person_id"] = owner_person + else: + data_dict["life_person_id"] = life_person.id + data_dict["owner_person_id"] = life_person.id + del data_dict["build_parts_uu_id"], data_dict["life_person_uu_id"] + + +BuildingLivingSpacesListEventMethod = BuildingLivingSpacesListEventMethods( + action=ActionsSchema(endpoint="/building/living_space/list") +) +BuildingLivingSpacesCreateEventMethod = BuildingLivingSpacesCreateEventMethods( + action=ActionsSchema(endpoint="/building/living_space/create") +) +BuildingLivingSpacesUpdateEventMethod = BuildingLivingSpacesUpdateEventMethods( + action=ActionsSchema(endpoint="/building/living_space/update") +) diff --git a/api_events/events/company/__init__.py b/api_events/events/company/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_events/events/company/company_company.py b/api_events/events/company/company_company.py new file mode 100644 index 0000000..52a68a3 --- /dev/null +++ b/api_events/events/company/company_company.py @@ -0,0 +1,189 @@ +import typing + +from fastapi import status +from fastapi.responses import JSONResponse + +from databases import Companies + +from api_validations.validations_request import ( + InsertCompany, + UpdateCompany, + ListOptions, + PatchRecord, +) + +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 + + +class CompanyListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "f6900cb5-ac5b-478e-8e7c-fa87e65cd2e5": "company_list", + } + __event_validation__ = {"f6900cb5-ac5b-478e-8e7c-fa87e65cd2e5": None} + + @classmethod + def company_list( + cls, + list_options: ListOptions, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, EmployeeTokenObject): + Companies.pre_query = Companies.select_action( + duty_id_list=[ + token_dict.selected_company.duty_id, + token_dict.selected_company.bulk_duties_id, + ] + ) + elif isinstance(token_dict, OccupantTokenObject): + Companies.pre_query = Companies.filter_all( + Companies.id == token_dict.selected_occupant.responsible_company_id + ).query + Companies.filter_attr = list_options + records = Companies.filter_all() + return AlchemyJsonResponse( + completed=True, + message="Building Living Spaces are listed successfully", + result=records, + ) + + +class CompanyCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "76f11a08-5f4a-4e1f-961f-aaef21699acd": "company_create", + } + __event_validation__ = {"76f11a08-5f4a-4e1f-961f-aaef21699acd": InsertCompany} + + @classmethod + def company_create( + cls, + data: InsertCompany, + token_dict: EmployeeTokenObject, + ): + created_company = Companies.create_action(data=data, token=token_dict) + created_company.update( + related_company=token_dict.selected_company.company_uu_id + ) + created_company.save() + return JSONResponse( + content={ + "completed": True, + "message": "Create Company record", + "data": created_company.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + + +class CompanyUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "41ea7f29-006a-4310-b5c4-b2a0e1a504bd": "company_update", + } + __event_validation__ = { + "41ea7f29-006a-4310-b5c4-b2a0e1a504bd": UpdateCompany, + } + + @classmethod + def company_update( + cls, company_uu_id: str, data: UpdateCompany, token_dict: EmployeeTokenObject + ): + Companies.pre_query = Companies.select_action( + duty_id_list=[ + token_dict.selected_company.bulk_duties_id, + token_dict.selected_company.duty_id, + ], + ) + find_one_company = Companies.filter_one( + Companies.uu_id == company_uu_id, + ).data + if not find_one_company: + return JSONResponse( + content={ + "completed": True, + "message": "Update Company record", + "data": {}, + }, + status_code=200, + ) + updated_company = find_one_company.update(**data.excluded_dump()) + Companies.save() + return JSONResponse( + content={ + "completed": True, + "message": "Update Company record", + "data": updated_company, + }, + status_code=200, + ) + + +class CompanyPatchEventMethods(MethodToEvent): + + event_type = "PATCH" + __event_keys__ = { + "6320d696-1fd1-49f9-860a-8f22e5b8a68d": "company_patch", + } + __event_validation__ = {"6320d696-1fd1-49f9-860a-8f22e5b8a68d": None} + + @classmethod + def company_patch( + cls, company_uu_id: str, data: PatchRecord, token_dict: EmployeeTokenObject + ): + find_one_company = Companies.filter_one( + Companies.uu_id == company_uu_id, + ).data + access_authorized_company = Companies.select_action( + duty_id_list=[ + token_dict.selected_company.bulk_duties_id, + token_dict.selected_company.duty_id, + ], + ) + if access_authorized_company.count: + action = data.excluded_dump() + find_one_company.active = bool( + action.get("active", find_one_company.active) + ) + find_one_company.is_confirmed = bool( + action.get("confirm", find_one_company.is_confirmed) + ) + find_one_company.deleted = bool( + action.get("delete", find_one_company.deleted) + ) + find_one_company.save() + return JSONResponse( + content={ + "completed": True, + "message": "Patch Company record completed", + "data": find_one_company.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={ + "completed": False, + "message": "Patch Company record failed", + "data": {}, + }, + status_code=status.HTTP_200_OK, + ) + + +CompanyPatchEventMethod = CompanyListEventMethods( + action=ActionsSchema(endpoint="/company/list") +) +CompanyCreateEventMethod = CompanyCreateEventMethods( + action=ActionsSchema(endpoint="/company/create") +) +CompanyUpdateEventMethod = CompanyUpdateEventMethods( + action=ActionsSchema(endpoint="/company/update") +) +CompanyListEventMethod = CompanyPatchEventMethods( + action=ActionsSchema(endpoint="/company/patch") +) diff --git a/api_events/events/company/company_department.py b/api_events/events/company/company_department.py new file mode 100644 index 0000000..71bd027 --- /dev/null +++ b/api_events/events/company/company_department.py @@ -0,0 +1,178 @@ +from typing import Optional +from fastapi import status +from fastapi.responses import JSONResponse + +from api_validations.validations_request import ( + DepartmentsPydantic, + PatchRecord, + ListOptions, + BaseModelRegular, +) + +from databases import Departments + +from api_events.events.abstract_class import MethodToEvent, ActionsSchema +from api_objects.auth.token_objects import EmployeeTokenObject +from api_validations.core_response import AlchemyJsonResponse + + +class DepartmentListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "2cb90331-c1b4-4923-8314-8111326b621a": "department_list", + } + __event_validation__ = {"2cb90331-c1b4-4923-8314-8111326b621a": None} + + @classmethod + def department_list( + cls, + list_options: ListOptions, + token_dict: EmployeeTokenObject, + ): + Departments.filter_attr = list_options + records = Departments.filter_all( + Departments.company_id == token_dict.selected_company.company_id, + ) + return AlchemyJsonResponse( + completed=True, + message="Departments are listed successfully", + result=records, + ) + + +class AdminUserInsertDepartments(BaseModelRegular): + department_code: str + department_name: str + company_uu_id: Optional[str] = None + + department_description: str + parent_department_uu_id: Optional[int] = None + + +class DepartmentCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "d8bd3985-7f3b-4267-a74e-d5017e4ea9f8": "super_user_department_create", + } + __event_validation__ = {"d8bd3985-7f3b-4267-a74e-d5017e4ea9f8": DepartmentsPydantic} + + @classmethod + def super_user_department_create( + cls, + data: DepartmentsPydantic, + token_dict: EmployeeTokenObject, + ): + data_dict = data.excluded_dump() + data_dict["company_id"] = token_dict.selected_company.company_id + data_dict["company_uu_id"] = token_dict.selected_company.company_uu_id + created_department = Departments.find_or_create(**data_dict) + Departments.save() + return JSONResponse( + content={ + "completed": False, + "message": "Company record already exits here is the record", + "data": created_department.get_dict(), + }, + status_code=status.HTTP_202_ACCEPTED, + ) + + +class DepartmentUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "4172706f-06c9-4c38-9ac8-59085a72f80a": "department_update", + } + __event_validation__ = {"4172706f-06c9-4c38-9ac8-59085a72f80a": DepartmentsPydantic} + + @classmethod + def department_update( + cls, + company_uu_id: str, + data: DepartmentsPydantic, + token_dict: EmployeeTokenObject, + ): + find_one_company = Departments.filter_one(Departments.uu_id == company_uu_id) + access_authorized_company = Departments.select_action( + duty_id=getattr(token_dict, "duty_id", 5), + filter_expr=[Departments.id == token_dict.get("")], + ) + if access_authorized_company.count: + data_dict = data.excluded_dump() + updated_company = find_one_company.update(**data_dict) + Departments.save() + return JSONResponse( + content={ + "completed": True, + "message": "Update Company record", + "data": updated_company, + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={"completed": True, "message": "Update Company record", "data": {}}, + status_code=status.HTTP_200_OK, + ) + + +class DepartmentPatchEventMethods(MethodToEvent): + + event_type = "PATCH" + __event_keys__ = { + "1e272e4f-6c1e-418b-91a7-be8b06c875da": "department_patch", + } + __event_validation__ = {"1e272e4f-6c1e-418b-91a7-be8b06c875da": None} + + @classmethod + def department_patch( + cls, company_uu_id: str, data: PatchRecord, token_dict: EmployeeTokenObject + ): + find_one_company = Departments.find_one_or_abort(uu_id=company_uu_id) + access_authorized_company = Departments.select_action( + duty_id=getattr(token_dict, "duty_id", 5), + filter_expr=[Departments.id == find_one_company.id], + ) + if access_authorized_company.count: + action = data.excluded_dump() + find_one_company.active = bool( + action.get("active", find_one_company.active) + ) + find_one_company.is_confirmed = bool( + action.get("confirm", find_one_company.is_confirmed) + ) + find_one_company.deleted = bool( + action.get("delete", find_one_company.deleted) + ) + find_one_company.save() + return JSONResponse( + content={ + "completed": True, + "message": "Patch Company record completed", + "data": find_one_company.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={ + "completed": False, + "message": "Patch Company record failed", + "data": {}, + }, + status_code=status.HTTP_200_OK, + ) + + +DepartmentListEventMethod = DepartmentListEventMethods( + action=ActionsSchema(endpoint="/department/list") +) +DepartmentCreateEventMethod = DepartmentCreateEventMethods( + action=ActionsSchema(endpoint="/department/create") +) +DepartmentUpdateEventMethod = DepartmentUpdateEventMethods( + action=ActionsSchema(endpoint="/department/update") +) +DepartmentPatchEventMethod = DepartmentPatchEventMethods( + action=ActionsSchema(endpoint="/department/patch") +) diff --git a/api_events/events/company/company_duties.py b/api_events/events/company/company_duties.py new file mode 100644 index 0000000..743642a --- /dev/null +++ b/api_events/events/company/company_duties.py @@ -0,0 +1,232 @@ +from fastapi import status +from fastapi.responses import JSONResponse + +from api_validations.core_response import AlchemyJsonResponse +from api_validations.validations_request import ( + InsertDuties, + UpdateDuties, + SelectDuties, + PatchRecord, + ListOptions, +) + +from databases import Departments, Duty, Duties + +from api_events.events.abstract_class import MethodToEvent, ActionsSchema +from api_objects.auth.token_objects import EmployeeTokenObject + + +class DutiesListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "44b72beb-53a8-407b-a12a-76e74b65794d": "duties_list", + } + __event_validation__ = {"44b72beb-53a8-407b-a12a-76e74b65794d": None} + + @classmethod + def duties_list( + cls, + list_options: ListOptions, + token_dict: EmployeeTokenObject, + ): + Duties.filter_attr = list_options + records = Duties.filter_all( + Duties.company_id == token_dict.selected_company.company_id, + ) + return AlchemyJsonResponse( + completed=True, + result=records, + message="List of Duties records", + ) + + +class DutiesGetByUUIDEventMethods(MethodToEvent): + + event_type = "GET" + __event_keys__ = { + "30c54cce-3303-4d36-959a-b64e383ae177": "duties_get_by_uuid", + } + __event_validation__ = {"30c54cce-3303-4d36-959a-b64e383ae177": SelectDuties} + + @classmethod + def duties_get_by_uuid( + cls, + data: SelectDuties, + token_dict: EmployeeTokenObject, + ): + + duty = Duty.filter_one(Duty.uu_id == data.duty_uu_id).data + if not duty: + return JSONResponse( + content={ + "completed": False, + "message": "Duty record is not found", + "data": {}, + }, + status_code=status.HTTP_404_NOT_FOUND, + ) + + records = Duties.filter_all( + Duties.duties_id == duty.id, + Duties.company_id == token_dict.selected_company.company_id, + ) + if not records.data: + return JSONResponse( + content={ + "completed": False, + "message": "Duties record is not found", + "data": {}, + }, + status_code=status.HTTP_404_NOT_FOUND, + ) + return { + "completed": True, + "status": "success", + "data": [record.get_dict() for record in records.data], + } + + +class DutiesCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "3524ae42-0825-4af7-be85-7c890a4f65d3": "duties_create", + } + __event_validation__ = {"3524ae42-0825-4af7-be85-7c890a4f65d3": InsertDuties} + + @classmethod + def duties_create( + cls, + data: InsertDuties, + token_dict: EmployeeTokenObject, + ): + duty = Duty.filter_one(Duty.uu_id == data.duties_uu_id).data + department = Departments.filter_one(Duty.uu_id == data.department_uu_id).data + + created_duties = Duties.find_or_create( + company_id=token_dict.selected_company.company_id, + company_uu_id=token_dict.selected_company.company_uu_id, + duties_id=duty.id, + duties_uu_id=str(duty.uu_id), + department_id=department.id, + department_uu_id=str(department.uu_id), + is_confirmed=data.is_confirmed, + ) + if data.is_default_duty: + created_duties.update(users_default_duty=created_duties.id) + + if not created_duties: + Duty.save() + return JSONResponse( + content={ + "completed": False, + "message": "Failed to create Duties record", + "data": {}, + }, + status_code=status.HTTP_400_BAD_REQUEST, + ) + return { + "completed": created_duties.is_found, + "message": ( + "Create Duties record" + if created_duties.is_found + else "This record is already created" + ), + "data": created_duties.get_dict(), + } + + +class DutiesUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "3fc77829-f1ee-4511-a2ca-582daa03125b": "duties_update", + } + __event_validation__ = {"3fc77829-f1ee-4511-a2ca-582daa03125b": UpdateDuties} + + @classmethod + def duties_update( + cls, + duties_uu_id: str, + data: UpdateDuties, + token_dict: EmployeeTokenObject, + ): + find_one_duties = Duties.find_one_or_abort(uu_id=duties_uu_id) + access_authorized_duties = Duties.select_action( + duty_id=getattr(token_dict, "duty_id", 5), + filter_expr=[Duties.id == find_one_duties.id], + ) + if access_authorized_duties.count: + data_dict = data.excluded_dump() + updated_duties = find_one_duties.update(**data_dict) + Duties.save() + return { + "completed": True, + "message": "Update Duties record", + "data": updated_duties, + } + return { + "completed": False, + "message": "Update Duties record failed", + "data": {}, + } + + +class DutiesPatchEventMethods(MethodToEvent): + + event_type = "PATCH" + __event_keys__ = { + "ca81c6d1-975a-4288-a27b-1069aea84afe": "duties_patch", + } + __event_validation__ = {"ca81c6d1-975a-4288-a27b-1069aea84afe": None} + + @classmethod + def duties_patch( + cls, + duties_uu_id: str, + data: PatchRecord, + token_dict: EmployeeTokenObject, + ): + find_one_duties = Duties.find_one_or_abort(uu_id=duties_uu_id) + access_authorized_duties = Duties.select_action( + duty_id=getattr(token_dict, "duty_id", 5), + filter_expr=[Duties.id == find_one_duties.id], + ) + if access_authorized_duties.count: + action = data.excluded_dump() + find_one_duties.active = bool(action.get("active", find_one_duties.active)) + find_one_duties.is_confirmed = bool( + action.get("confirm", find_one_duties.is_confirmed) + ) + find_one_duties.deleted = bool( + action.get("delete", find_one_duties.deleted) + ) + find_one_duties.save() + return { + "completed": True, + "message": "Patch Duties record completed", + "data": find_one_duties.get_dict(), + } + return { + "completed": False, + "message": "Patch Duties record failed", + "data": {}, + } + + +DutiesListEventMethod = DutiesListEventMethods( + action=ActionsSchema(endpoint="/duties/list") +) +DutiesGetByUUIDEventMethod = DutiesGetByUUIDEventMethods( + action=ActionsSchema(endpoint="/duties/get_by_duty_uuid") +) +DutiesCreateEventMethod = DutiesCreateEventMethods( + action=ActionsSchema(endpoint="/duties/create") +) +DutiesUpdateEventMethod = DutiesUpdateEventMethods( + action=ActionsSchema(endpoint="/duties/update") +) +DutiesPatchEventMethod = DutiesPatchEventMethods( + action=ActionsSchema(endpoint="/duties/patch") +) diff --git a/api_events/events/company/company_duty.py b/api_events/events/company/company_duty.py new file mode 100644 index 0000000..6ca48f2 --- /dev/null +++ b/api_events/events/company/company_duty.py @@ -0,0 +1,163 @@ +from fastapi import status +from fastapi.responses import JSONResponse + +from api_validations.validations_request import ( + InsertCompanyDuty, + PatchRecord, + ListOptions, +) + +from databases import Duty + +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 + + +class DutyListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "23231c7d-4ff2-4b39-b71b-ea350d31fadf": "duty_list", + } + __event_validation__ = {"23231c7d-4ff2-4b39-b71b-ea350d31fadf": None} + + @classmethod + def duty_list( + cls, + list_options: ListOptions, + token_dict: EmployeeTokenObject, + ): + Duty.filter_attr = list_options + records = Duty.filter_all(system=True) + return AlchemyJsonResponse( + completed=True, + message="Duty list is brought successfully", + result=records, + ) + + +class DutyCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "c6ea200e-fa17-4393-b390-37f5337c9c65": "duty_create", + } + __event_validation__ = {"c6ea200e-fa17-4393-b390-37f5337c9c65": InsertCompanyDuty} + + @classmethod + def duty_create( + cls, + data: InsertCompanyDuty, + token_dict: EmployeeTokenObject, + ): + created_duty = Duty.find_or_create(**data.excluded_dump()) + Duty.save() + return JSONResponse( + content={ + "completed": True, + "message": "Create Company record", + "data": created_duty.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + + +class DutyUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "ad952647-bcf8-482d-9e05-b2ee8086483f": "duty_update", + } + __event_validation__ = {"ad952647-bcf8-482d-9e05-b2ee8086483f": None} + + @classmethod + def duty_update( + cls, + company_uu_id: str, + data, + token_dict: EmployeeTokenObject, + ): + find_one_company = Duty.find_one_or_abort(uu_id=company_uu_id) + access_authorized_company = Duty.select_action( + duty_id=getattr(token_dict, "duty_id", 5), # ? + filter_expr=[Duty.id == token_dict.get("")], + ) + if access_authorized_company.count: + data_dict = data.excluded_dump() + updated_company = find_one_company.update(**data_dict) + Duty.save() + return JSONResponse( + content={ + "completed": True, + "message": "Update Company record", + "data": updated_company, + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={"completed": True, "message": "Update Company record", "data": {}}, + status_code=status.HTTP_200_OK, + ) + + +class DutyPatchEventMethods(MethodToEvent): + + event_type = "PATCH" + __event_keys__ = { + "d5c7b5c4-7b4e-4d5b-8e3b-2b9c5f5d0c0b": "duty_patch", + } + __event_validation__ = {"d5c7b5c4-7b4e-4d5b-8e3b-2b9c5f5d0c0b": None} + + @classmethod + def duty_patch( + cls, + company_uu_id: str, + data: PatchRecord, + token_dict: EmployeeTokenObject, + ): + find_one_company = Duty.find_one_or_abort(uu_id=company_uu_id) + access_authorized_company = Duty.select_action( + duty_id=getattr(token_dict, "duty_id", 5), + filter_expr=[Duty.id == find_one_company.id], + ) + if access_authorized_company.count: + action = data.excluded_dump() + find_one_company.active = bool( + action.get("active", find_one_company.active) + ) + find_one_company.is_confirmed = bool( + action.get("confirm", find_one_company.is_confirmed) + ) + find_one_company.deleted = bool( + action.get("delete", find_one_company.deleted) + ) + find_one_company.save() + return JSONResponse( + content={ + "completed": True, + "message": "Patch Company record completed", + "data": find_one_company.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={ + "completed": False, + "message": "Patch Company record failed", + "data": {}, + }, + status_code=status.HTTP_200_OK, + ) + + +DutyListEventMethod = DutyListEventMethods(action=ActionsSchema(endpoint="/duty/list")) +DutyCreateEventMethod = DutyCreateEventMethods( + action=ActionsSchema(endpoint="/duty/create") +) +DutyUpdateEventMethod = DutyUpdateEventMethods( + action=ActionsSchema(endpoint="/duty/update") +) +DutyPatchEventMethod = DutyPatchEventMethods( + action=ActionsSchema(endpoint="/duty/patch") +) diff --git a/api_events/events/company/company_employee.py b/api_events/events/company/company_employee.py new file mode 100644 index 0000000..4724838 --- /dev/null +++ b/api_events/events/company/company_employee.py @@ -0,0 +1,343 @@ +from fastapi import status, HTTPException +from fastapi.responses import JSONResponse + +from api_library.date_time_actions.date_functions import system_arrow +from api_validations.validations_request import ( + InsertEmployees, + BindEmployees2People, + PatchRecord, + ListOptions, +) + +from databases import Employees, Staff, People, EmployeeHistory + +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 + + +class EmployeeListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "cb677c92-6b05-4122-af5c-12766fae8095": "employee_list", + } + __event_validation__ = {"cb677c92-6b05-4122-af5c-12766fae8095": None} + + @classmethod + def employee_list( + cls, + list_options: ListOptions, + token_dict: EmployeeTokenObject, + ): + employees_staff = Staff.filter_all( + Staff.duties_id.in_(token_dict.duty_id_list), + ).data + Employees.filter_attr = list_options + records = Employees.filter_all( + Employees.staff_id.in_([staff.id for staff in employees_staff]), + ) + return AlchemyJsonResponse( + completed=True, + message="Employee are listed successfully", + result=records, + ) + + +class EmployeeCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "1e1632c3-bb0e-46a5-8e45-da3f6d88ac43": "employee_create", + } + __event_validation__ = {"1e1632c3-bb0e-46a5-8e45-da3f6d88ac43": InsertEmployees} + + @classmethod + def employee_create( + cls, + data: InsertEmployees, + token_dict: EmployeeTokenObject, + ): + person = People.filter_one( + People.uu_id == data.people_uu_id, + ).data + staff = Staff.filter_one( + Staff.uu_id == data.staff_uu_id, + ).data + if not staff: + return JSONResponse( + content={ + "completed": False, + "message": "Staff record not found", + "data": {}, + }, + status_code=status.HTTP_404_NOT_FOUND, + ) + created_employee = Employees.find_or_create( + staff_id=staff.id, + staff_uu_id=str(staff.uu_id), + people_id=person.id if person else None, + people_uu_id=str(person.uu_id) if person else None, + ) + Employees.save() + return JSONResponse( + content={ + "completed": True, + "message": "Create Employee record", + "data": created_employee.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + + +class EmployeeUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "9015a076-d78c-463d-9474-ea343a125fb8": "employee_update", + } + __event_validation__ = {"9015a076-d78c-463d-9474-ea343a125fb8": None} + + @classmethod + def employee_update( + cls, + employee_uu_id: str, + data: PatchRecord, + token_dict: EmployeeTokenObject, + ): + find_one_employee = Employees.filter_one( + Employees.uu_id == employee_uu_id, + ).data + access_authorized_employee = Employees.select_action( + employee_id=getattr(token_dict, "employee_id", 5), + filter_expr=[Employees.id == token_dict.get("")], + ) + if access_authorized_employee.count: + data_dict = data.excluded_dump() + updated_employee = find_one_employee.update(**data_dict) + Employees.save() + return JSONResponse( + content={ + "completed": True, + "message": "Update Employee record", + "data": updated_employee, + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={ + "completed": False, + "message": "Update Employee record", + "data": {}, + }, + status_code=status.HTTP_200_OK, + ) + + +class EmployeePatchEventMethods(MethodToEvent): + + event_type = "PATCH" + __event_keys__ = { + "8446ce0b-9310-4b9f-93e2-61f56a9dacd1": "employee_patch", + } + __event_validation__ = {"8446ce0b-9310-4b9f-93e2-61f56a9dacd1": None} + + @classmethod + def employee_patch( + cls, + employee_uu_id: str, + data: PatchRecord, + token_dict: EmployeeTokenObject, + ): + find_one_employee = Employees.find_one_or_abort(uu_id=employee_uu_id) + access_authorized_employee = Employees.select_action( + employee_id=getattr(token_dict, "employee_id", 5), + filter_expr=[Employees.id == find_one_employee.id], + ) + if access_authorized_employee.count: + action = data.excluded_dump() + find_one_employee.active = bool( + action.get("active", find_one_employee.active) + ) + find_one_employee.is_confirmed = bool( + action.get("confirm", find_one_employee.is_confirmed) + ) + find_one_employee.deleted = bool( + action.get("delete", find_one_employee.deleted) + ) + return JSONResponse( + content={ + "completed": True, + "message": "Patch Employee record completed", + "data": find_one_employee.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={ + "completed": False, + "message": "Patch Employee record failed", + "data": {}, + }, + status_code=status.HTTP_200_OK, + ) + + +class Employee2PeopleEmployEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "5eb04057-7a74-4555-b2c6-14eda32dae89": "company_employee_employ", + } + __event_validation__ = { + "5eb04057-7a74-4555-b2c6-14eda32dae89": BindEmployees2People + } + + @classmethod + def company_employee_employ( + cls, + data: BindEmployees2People, + token_dict: EmployeeTokenObject, + ): + selected_staff = Staff.filter_one( + Staff.uu_id == data.staff_uu_id, + ).data + selected_people = People.filter_one(People.uu_id == data.people_uu_id).data + if not selected_staff: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Staff record not found", + ) + if not selected_people: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="People record not found", + ) + + find_one_employee = Employees.filter_all( + Employees.staff_id == selected_staff.id, + ).data + + staff_name_upper = str(selected_staff.staff_name).upper() + if not find_one_employee: + return JSONResponse( + content={ + "completed": False, + "message": f"There is no space for new Employee for given staff : {staff_name_upper}", + "data": {}, + }, + status_code=status.HTTP_406_NOT_ACCEPTABLE, + ) + if not data.expiry_starts: + data.expiry_starts = str(system_arrow.now()) + data.expiry_starts = str(system_arrow.get(str(data.expiry_starts))) + + find_one_employee = find_one_employee.update( + people_id=selected_people.id, + expiry_starts=data.expiry_starts, + **token_dict.update_creds, + ) + Employees.save() + return JSONResponse( + content={ + "completed": True, + "message": "Get Employee to People record", + "data": find_one_employee.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + + +class Employee2PeopleFireEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "caf914fa-0899-4b0b-a85a-3d40fdaa06a5": "company_employee_fire", + } + __event_validation__ = { + "caf914fa-0899-4b0b-a85a-3d40fdaa06a5": BindEmployees2People + } + + @classmethod + def company_employee_fire( + cls, + data: BindEmployees2People, + token_dict: EmployeeTokenObject, + ): + selected_people = People.filter_one( + People.uu_id == data.people_uu_id, + ).data + if not selected_people: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="People record not found", + ) + + find_one_employee: Employees = Employees.filter_one( + Employees.people_id == selected_people.id, + ).data + if not find_one_employee: + return JSONResponse( + content={ + "completed": False, + "message": "Employee record not found for given People", + "data": {}, + }, + status_code=status.HTTP_404_NOT_FOUND, + ) + + find_one_employee = find_one_employee.update( + people_id=None, **token_dict.update_creds + ) + if not find_one_employee.people_id: + employee_history = EmployeeHistory.find_or_create( + staff_id=find_one_employee.staff_id, + expiry_ends=data.expiry_ends, + people_id=selected_people.id, + created_by_id=find_one_employee.created_by_id, + updated_by_id=find_one_employee.updated_by_id, + confirmed_by_id=find_one_employee.confirmed_by_id, + replication_id=find_one_employee.replication_id, + created_by=find_one_employee.created_by, + updated_by=find_one_employee.updated_by, + confirmed_by=find_one_employee.confirmed_by, + active=find_one_employee.active, + is_confirmed=find_one_employee.is_confirmed, + deleted=find_one_employee.deleted, + expiry_starts=find_one_employee.expiry_starts, + is_notification_send=find_one_employee.is_notification_send, + cryp_uu_id=find_one_employee.cryp_uu_id, + ) + Employees.save() + return JSONResponse( + content={ + "completed": True, + "message": "Employee is fired from Staff", + "data": find_one_employee.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Employee record not found for given People", + ) + + +EmployeeListEventMethod = EmployeeListEventMethods( + action=ActionsSchema(endpoint="/employee/list") +) +EmployeeCreateEventMethod = EmployeeCreateEventMethods( + action=ActionsSchema(endpoint="/employee/create") +) +EmployeeUpdateEventMethod = EmployeeUpdateEventMethods( + action=ActionsSchema(endpoint="/employee/update") +) +EmployeePatchEventMethod = EmployeePatchEventMethods( + action=ActionsSchema(endpoint="/employee/patch") +) +Employee2PeopleEmployEventMethod = Employee2PeopleEmployEventMethods( + action=ActionsSchema(endpoint="/employee/employ") +) +Employee2PeopleFireEventMethod = Employee2PeopleFireEventMethods( + action=ActionsSchema(endpoint="/employee/fire") +) diff --git a/api_events/events/company/company_staff.py b/api_events/events/company/company_staff.py new file mode 100644 index 0000000..9236e1e --- /dev/null +++ b/api_events/events/company/company_staff.py @@ -0,0 +1,156 @@ +from fastapi import status +from fastapi.responses import JSONResponse +from fastapi.exceptions import HTTPException + +from api_validations.validations_request import ( + InsertStaff, + SelectStaff, + PatchRecord, + ListOptions, +) + +from databases import Staff, Duties + +from api_events.events.abstract_class import MethodToEvent, ActionsSchema +from api_objects.auth.token_objects import EmployeeTokenObject +from api_validations.core_response import AlchemyJsonResponse + + +class StaffListEventMethods(MethodToEvent): + event_type = "SELECT" + __event_keys__ = { + "8984a519-99bf-4f25-8f34-2e1aebba468c": "staff_list", + } + __event_validation__ = {"8984a519-99bf-4f25-8f34-2e1aebba468c": None} + + @classmethod + def staff_list(cls, list_options: ListOptions, token_dict: EmployeeTokenObject): + Staff.filter_attr = list_options + records = Staff.filter_all() + return AlchemyJsonResponse( + completed=True, + message="Staff are listed successfully", + result=records, + ) + + +class StaffCreateEventMethods(MethodToEvent): + event_type = "CREATE" + __event_keys__ = { + "8f619257-19fd-404f-b713-7392c588dc36": "staff_create", + } + __event_validation__ = {"8f619257-19fd-404f-b713-7392c588dc36": InsertStaff} + + @classmethod + def staff_create(cls, data: InsertStaff, token_dict: EmployeeTokenObject): + data_dict = data.excluded_dump() + duties = Duties.filter_one( + Duties.uu_id == data.duties_uu_id, + ).data + if not duties: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Duties not found", + ) + data_dict["duties_id"] = duties.id + created_duty = Staff.find_or_create(**data_dict) + Staff.save() + return JSONResponse( + content={ + "completed": True, + "message": "Create Staff record", + "data": created_duty.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + + +class StaffGetByUUIDEventMethods(MethodToEvent): + + event_type = "GET" + __event_keys__ = { + "7724cfbb-c0ee-4261-959b-61b84e88a34f": "staff_get_by_uu_id", + } + __event_validation__ = {"7724cfbb-c0ee-4261-959b-61b84e88a34f": SelectStaff} + + @classmethod + def staff_get_by_uu_id(cls, data: SelectStaff, token_dict: EmployeeTokenObject): + if data.duties_uu_id: + duties_id = Duties.filter_one( + Duties.uu_id == data.duties_uu_id, + ).data + selected_staffs = Staff.filter_all(Staff.duties_id == duties_id.id) + return JSONResponse( + content={ + "completed": True, + "message": "Staff records are listed", + "data": [ + selected_staff.get_dict() + for selected_staff in selected_staffs.data + ], + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={ + "completed": False, + "message": "Get Staff record failed", + "data": {}, + }, + status_code=status.HTTP_202_ACCEPTED, + ) + + +class StaffUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "5329f35d-ff9d-4656-a831-ba9c8204e483": "staff_update", + } + __event_validation__ = {"5329f35d-ff9d-4656-a831-ba9c8204e483": None} + + @classmethod + def staff_update(cls, staff_uu_id: str, data, token_dict: EmployeeTokenObject): + return JSONResponse( + content={"completed": True, "message": "Update Staff record", "data": {}}, + status_code=status.HTTP_200_OK, + ) + + +class StaffPatchEventMethods(MethodToEvent): + + event_type = "PATCH" + __event_keys__ = { + "b1cd7c0a-1458-472b-894f-3adc857c8512": "staff_patch", + } + __event_validation__ = {"b1cd7c0a-1458-472b-894f-3adc857c8512": None} + + @classmethod + def staff_patch( + cls, staff_uu_id: str, data: PatchRecord, token_dict: EmployeeTokenObject + ): + return JSONResponse( + content={ + "completed": False, + "message": "Patch Staff record failed", + "data": {}, + }, + status_code=status.HTTP_200_OK, + ) + + +StaffListEventMethod = StaffListEventMethods( + action=ActionsSchema(endpoint="/staff/list") +) +StaffCreateEventMethod = StaffCreateEventMethods( + action=ActionsSchema(endpoint="/staff/create") +) +StaffGetByUUIDEventMethod = StaffGetByUUIDEventMethods( + action=ActionsSchema(endpoint="/staff/get_by_duties_uu_id") +) +StaffUpdateEventMethod = StaffUpdateEventMethods( + action=ActionsSchema(endpoint="/staff/update") +) +StaffPatchEventMethod = StaffPatchEventMethods( + action=ActionsSchema(endpoint="/staff/patch") +) diff --git a/api_events/events/decision_book/__init__.py b/api_events/events/decision_book/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_events/events/decision_book/decision_book_decision_book.py b/api_events/events/decision_book/decision_book_decision_book.py new file mode 100644 index 0000000..41b8dd6 --- /dev/null +++ b/api_events/events/decision_book/decision_book_decision_book.py @@ -0,0 +1,229 @@ +import typing + +from fastapi import status, HTTPException +from fastapi.responses import JSONResponse + +from databases import ( + Build, + BuildDecisionBook, + Companies, + OccupantTypes, +) + +from api_validations.validations_request 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 AlchemyJsonResponse +from api_library.date_time_actions.date_functions import system_arrow + + +class DecisionBookListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "5c10d6ae-2aee-4243-a7c3-94826d028d13": "building_decision_book_list", + } + __event_validation__ = {"5c10d6ae-2aee-4243-a7c3-94826d028d13": None} + + @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}", + ) + BuildDecisionBook.filter_attr = list_options + records = BuildDecisionBook.filter_all( + BuildDecisionBook.build_id.in_([build.id for build in build_id_list]), + ) + elif isinstance(token_dict, OccupantTokenObject): + BuildDecisionBook.filter_attr = list_options + records = BuildDecisionBook.filter_all( + BuildDecisionBook.build_id == token_dict.selected_occupant.build_id, + ) + return AlchemyJsonResponse( + completed=True, + message="DecisionBook are listed successfully", + result=records, + ) + + +class DecisionBookCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "0a68cb44-271a-4829-81f6-cd99a5f326b4": "building_decision_book_create", + } + __event_validation__ = {"0a68cb44-271a-4829-81f6-cd99a5f326b4": InsertDecisionBook} + + @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_one( + Build.uu_id == data.build_uu_id, + ).data + 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.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_one( + Companies.uu_id == data.resp_company_uu_id, + ).data + 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.id + data_dict["resp_company_uu_id"] = str(company.uu_id) + + decision_period_date = system_arrow.get(build.decision_period_date) + data_dict["expiry_starts"] = system_arrow.get( + system_arrow.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) + build_decision_book.save_and_confirm() + 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.filter_by_one( + 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", + ) + + occupant_build = Build.filter_one( + Build.id == token_dict.selected_occupant.build_id, + ).data + occupant_company = Companies.filter_one( + Companies.id == token_dict.selected_occupant.responsible_company_id, + ).data + 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 = system_arrow.get(occupant_build.decision_period_date) + data_dict["expiry_starts"] = system_arrow.get( + system_arrow.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) + build_decision_book.save() + build_decision_book.update(is_confirmed=True) + build_decision_book.save() + 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", + } + __event_validation__ = {"6bc7035c-3b53-4c0a-8cc9-1ec9c6af1e29": None} + + @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", + } + __event_validation__ = {"7b58ed84-9a65-4588-994d-30df8366b050": None} + + @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", + } + __event_validation__ = {"fc745142-3437-4ca2-89fa-c5a3e2b5c6c2": None} + + @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") +) 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 new file mode 100644 index 0000000..fc22c1d --- /dev/null +++ b/api_events/events/decision_book/decision_book_decision_book_items.py @@ -0,0 +1,570 @@ +import typing + +from fastapi import status, HTTPException +from fastapi.responses import JSONResponse + +from api_events.events.events.events_bind_services import ( + ServiceBindOccupantEventMethods, +) +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 AlchemyJsonResponse +from api_library.date_time_actions.date_functions import system_arrow, client_arrow + +from api_validations.validations_request import ( + InsertBuildDecisionBookItems, + ListOptions, + ListDecisionBook, +) +from databases.sql_models.event.event import Services + + +class DecisionBookDecisionBookItemsListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "eb36de59-8268-4d96-80b6-5d01c12bf0b1": "building_decision_book_items_list", + } + __event_validation__ = {"eb36de59-8268-4d96-80b6-5d01c12bf0b1": None} + + @classmethod + def building_decision_book_items_list( + cls, + data: ListOptions, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + decision_book = BuildDecisionBook.filter_one( + BuildDecisionBook.uu_id == data.build_decision_book_uu_id, + ).data + 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 == str(decision_book.uu_id), + ], + ) + reachable_building = Build.filter_all() + 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_all() + 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}", + ) + BuildDecisionBookItems.filter_attr = BuildDecisionBookItems.FilterModel( + **data.dump() + ) + records = BuildDecisionBookItems.filter_all( + BuildDecisionBookItems.build_decision_book_id == decision_book.id + ) + return AlchemyJsonResponse( + completed=True, + message="DecisionBook are listed successfully", + result=records, + ) + # 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"] + # ) + # BuildDecisionBookItems.filter_attr = list_options + # records = BuildDecisionBookItems.filter_all( + # ) + # 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", + } + __event_validation__ = { + "dce10509-0da5-46fb-af3c-a81d54d5481c": InsertBuildDecisionBookItems + } + + @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 = system_arrow.find_last_day_of_month(local_date) + payment_amount = unit_price + if not unit_price_is_fixed: + unit_amount = int(build_part_single.part_net_size) + payment_amount = abs(unit_price * float(unit_amount)) * -1 + payment_amount = -1 * ( + abs(payment_amount) + (50 - float(abs(payment_amount)) % 50) + ) + created_book_payment = BuildDecisionBookPayments.find_or_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, + ) + created_book_payment.save_and_confirm() + 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_all( + BuildParts.human_livable == True, + BuildParts.build_id == build_id, + ) + print("data_info_type.key", data_info_type.key) + 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), + currency=currency, + ) + payment_types = ApiEnumDropdown.get_debit_search(search_debit="DT-D") + if data_info_type.key == "BDT-D": + local_date = system_arrow.get( + system_arrow.get(decision_book.expiry_starts).date() + ) + end_date = system_arrow.get( + system_arrow.get(decision_book.expiry_ends).date() + ) + payment_return_dict = 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, + ) + return payment_return_dict + elif data_info_type.key == "BDT-A": + local_date = system_arrow.get(system_arrow.get(debit_start_date).date()) + end_date = system_arrow.get(system_arrow.get(debit_end_date).date()) + payment_return_dict = 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, + ) + return payment_return_dict + elif data_info_type.key == "BDT-R" or data_info_type.key == "BDT-L": + local_date = system_arrow.get(system_arrow.get(debit_start_date).date()) + end_date = system_arrow.get(system_arrow.get(debit_end_date).date()) + decision_date = system_arrow.get(decision_book.expiry_starts).date() + meeting_date = system_arrow.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}", + system=True, + ) + management_room = BuildParts.filter_one( + BuildParts.build_id == build_id, BuildParts.part_no == 0, system=True + ).data + occupant_man = OccupantTypes.filter_by_one( + system=True, occupant_code="MT-VPR", occupant_category_type="MT" + ).data + manager_living_space = BuildLivingSpace.filter_one( + BuildLivingSpace.build_parts_id == management_room.id, + BuildLivingSpace.occupant_type == occupant_man.id, + ).data + if not manager_living_space: + 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 + 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=str(decision_book_item.item_comment), + 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 + ) + book_project_created.save_and_confirm() + print("book_project_created", book_project_created) + item_comment_at_database = decision_book_item.item_comment + 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} | {item_comment_at_database}" + ) + decision_book_item.save_and_confirm() + project_lead = OccupantTypes.filter_by_one( + system=True, occupant_code="PRJ-LDR", occupant_category_type="PRJ" + ).data + build_new_president = OccupantTypes.filter_by_one( + system=True, occupant_code="MT-VPR", occupant_category_type="MT" + ).data + + new_president = BuildLivingSpace.filter_one( + BuildLivingSpace.occupant_type == build_new_president.id, + BuildLivingSpace.build_parts_id == management_room.id, + ).data + + project_leader = BuildLivingSpace.filter_one( + BuildLivingSpace.occupant_type == project_lead.id, + BuildLivingSpace.build_parts_id == management_room.id, + BuildLivingSpace.person_id == new_president.person_id, + ).data + if not project_leader: + project_leader = BuildLivingSpace.find_or_create( + person_id=new_president.person_id, + person_uu_id=str(new_president.person_uu_id), + build_parts_id=management_room.id, + build_parts_uu_id=str(management_room.uu_id), + occupant_type=project_lead.id, + occupant_type_uu_id=str(project_lead.uu_id), + ) + project_leader.save_and_confirm() + related_service = Services.filter_by_one( + system=True, + related_responsibility=project_lead.occupant_code, + ).data + ServiceBindOccupantEventMethods.bind_services_occupant_system( + service_id=related_service.id, + build_living_space_id=project_leader.id, + ) + 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=project_leader.id, + living_space_uu_id=str(project_leader.uu_id), + ) + project_person.save_and_confirm() + book_project_created.update( + project_response_living_space_id=project_leader.id, + project_response_living_space_uu_id=str(project_leader.uu_id), + ) + book_project_created.save() + return book_project_created + elif data_info_type.key == "BDT-S": + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="BDT-S is not implemented yet. Check info type and try again", + ) + elif data_info_type.key == "BDT-I": + return + 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.filter_by_one( + system=True, occupant_code="MT-WRT", occupant_category_type="MT" + ).data + + 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.filter_one( + BuildDecisionBookPerson.token == data.token, + ).data + decision_book = BuildDecisionBook.filter_one( + BuildDecisionBook.id == decision_book_person.build_decision_book_id, + ).data + + book_items = BuildDecisionBookItems.filter_all( + BuildDecisionBookItems.build_decision_book_id == decision_book.id, + system=True, + ) + if int(book_items.count) < 3: + BuildDecisionBookItems.check_meeting_is_valid_to_start_add_attendance( + decision_book=decision_book, + token_dict=token_dict, + ) + + book_items = BuildDecisionBookItems.filter_all( + BuildDecisionBookItems.build_decision_book_id == decision_book.id, + system=True, + ) + + 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_info_type = ApiEnumDropdown.filter_by_one( + system=True, + enum_class="BuildDuesTypes", + key="BDT-I", + ).data + data_info_types = ApiEnumDropdown.due_type_search() + 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 + + row_is_debit = str(data_info_type.key).upper() in ["BDT-A", "BDT-D"] + row_is_project = str(data_info_type.key).upper() in [ + "BDT-R", + "BDT-L", + "BDT-S", + ] + debit_dates_required = ( + not data_dict["debit_start_date"] or not data_dict["debit_end_date"] + ) + if row_is_project and debit_dates_required: + 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"], + ) + + new_decision_book_item = BuildDecisionBookItems.find_or_create(**data_dict) + new_decision_book_item.save_and_confirm() + print("new_decision_book_item", new_decision_book_item) + 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 row_is_debit: + 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) + elif row_is_project: + project_no = str(created_payment_records_dict.project_no) + item_comment = ( + f"{data.item_comment} | @ Project is created no : {project_no}." + ) + new_decision_book_item.update(item_comment=item_comment) + new_decision_book_item.update(is_payment_created=True) + new_decision_book_item.save_and_confirm() + + 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", + } + __event_validation__ = {"f0fdfe1b-806b-4175-ad50-a1a165c0dfb7": None} + + @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", + } + __event_validation__ = {"42328809-b516-477b-82cc-2d6fadf28843": None} + + @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) 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 new file mode 100644 index 0000000..9678af6 --- /dev/null +++ b/api_events/events/decision_book/decision_book_decision_book_items_debits.py @@ -0,0 +1,105 @@ +import typing + +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 AlchemyJsonResponse +from api_library.date_time_actions.date_functions import system_arrow, client_arrow + + +class DecisionBookDecisionBookItemsDebitsListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "a1d2b1f6-9b8d-4f6b-8f4d-6b1f6a9d8b1a": "decision_book_decision_book_items_debits_list", + } + __event_validation__ = {"a1d2b1f6-9b8d-4f6b-8f4d-6b1f6a9d8b1a": None} + + @classmethod + def decision_book_decision_book_items_debits_list( + cls, + decision_book_id: str, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + BuildDecisionBookItems.pre_query = BuildDecisionBookItems.filter_all( + BuildDecisionBookItems.decision_book_id == decision_book_id, + ).query + BuildDecisionBookItems.filter_attr = None + records = BuildDecisionBookItems.filter_all( + BuildDecisionBookItems.decision_book_id == decision_book_id, + ) + return AlchemyJsonResponse( + completed=True, + message="Decision Book Items Debits are listed", + result=records, + ) + + +class DecisionBookDecisionBookItemsDebitsCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "a1d2b1f6-9b8d-4f6b-8f4d-6b1f6a9d8b1a": "decision_book_decision_book_items_debits_create", + } + __event_validation__ = {"a1d2b1f6-9b8d-4f6b-8f4d-6b1f6a9d8b1a": None} + + @classmethod + def decision_book_decision_book_items_debits_create( + cls, + decision_book_id: str, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + decision_book_items_debits: dict, + ): + 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", + ) + + decision_book_items_debits["decision_book_id"] = decision_book_id + decision_book_items_debits["created_at"] = system_arrow().datetime + decision_book_items_debits["created_by"] = token_dict.employee_id + decision_book_items_debits["updated_at"] = system_arrow().datetime + decision_book_items_debits["updated_by"] = token_dict.employee_id + decision_book_items_debits["is_active"] = True + decision_book_items_debits["is_confirmed"] = False + decision_book_items_debits["is_deleted"] = False + decision_book_items_debits["confirmed_at"] = None + decision_book_items_debits["confirmed_by"] = None + decision_book_items_debits["deleted_at"] = None + decision_book_items_debits["deleted_by"] = None + decision_book_items_debits["confirmed_at"] = None + decision_book_items_debits["confirmed_by"] = None + decision_book_items_debits["deleted_at"] = None + decision_book_items_debits["deleted_by"] = None + decision_book_items_debits["confirmed_at"] = None + decision_book_items_debits["confirmed_by"] = None + decision_book_items_debits["deleted_at"] = None + decision_book_items_debits["deleted_by"] = None + BuildDecisionBookItems.pre_query = BuildDecisionBookItems.filter_all( + BuildDecisionBookItems.decision_book_id == decision_book_id, + ).query + BuildDecisionBookItems.filter_attr = None + records = BuildDecisionBookItems.filter_all( + BuildDecisionBookItems.decision_book_id == decision_book_id, + ) + return AlchemyJsonResponse( + completed=True, + 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 new file mode 100644 index 0000000..3755a87 --- /dev/null +++ b/api_events/events/decision_book/decision_book_decision_book_person.py @@ -0,0 +1,456 @@ +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.validations_request 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 AlchemyJsonResponse + + +class DecisionBookPersonListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "ea324dc0-3b08-4896-9040-7fa0401a176f": "building_decision_book_person_list", + } + __event_validation__ = {"ea324dc0-3b08-4896-9040-7fa0401a176f": None} + + @classmethod + def building_decision_book_person_list( + cls, + data: ListOptions, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + return + + +class DecisionBookPersonAddEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "e346f720-880b-4b07-93d6-9ac76fbbaa33": "building_decision_book_person_add", + } + __event_validation__ = { + "e346f720-880b-4b07-93d6-9ac76fbbaa33": DecisionBookDecisionBookInvitationsUpdate + } + + @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.filter_one( + BuildDecisionBook.uu_id == data.build_decision_book_uu_id, + ).data + 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.filter_by_one( + system=True, occupant_code="BU-MNG", occupant_category_type="BU" + ).data + 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.filter_by_one( + system=True, + uu_id=data.occupant_type_uu_id, + occupant_category_type="MT", + ).data + 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.filter_one( + BuildDecisionBookPerson.token == data.token, + BuildDecisionBookPerson.build_decision_book_uu_id + == data.build_decision_book_uu_id, + ).data + 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.filter_one( + BuildDecisionBookInvitations.id == manger_book_person.invite_id, + BuildDecisionBookInvitations.build_id + == token_dict.selected_occupant.build_id, + ).data + if not book_invite: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Invitation not found. Please check token", + ) + selected_book_person = BuildDecisionBookPerson.filter_one( + BuildDecisionBookPerson.invite_id == book_invite.id, + BuildDecisionBookPerson.person_uu_id == data.person_uu_id, + ).data + 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), + ) + BuildDecisionBookPerson.save() + 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", + } + __event_validation__ = { + "30588869-04cd-48ea-ad00-0e4f8dd7f735": RemoveDecisionBookPerson + } + + @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", + } + __event_validation__ = { + "bdcba521-0116-441c-ace1-84c5b68c86c7": DecisionBookDecisionBookInvitationsAttend + } + + @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.filter_one(Users.id == token_dict.user_id).data + invitation_person = BuildDecisionBookPerson.filter_one( + BuildDecisionBookPerson.token == data.token, + ).data + 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.filter_one( + BuildDecisionBookInvitations.id == invitation_person.invite_id, + BuildDecisionBookInvitations.build_id + == token_dict.selected_occupant.build_id, + ).data + 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 + ) + BuildDecisionBookInvitations.save() + 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", + } + __event_validation__ = { + "c0b65098-9c79-4212-b1d0-c7e7836cf141": DecisionBookDecisionBookInvitationsAssign + } + + @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.filter_one( + BuildDecisionBookPerson.token == data.token, + BuildDecisionBookPerson.build_living_space_id + == token_dict.selected_occupant.living_space_id, + ).data + manager_occupant_type = OccupantTypes.filter_by_one( + system=True, occupant_code="BU-MNG", occupant_category_type="BU" + ).data + 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.filter_one( + BuildDecisionBookInvitations.id == book_person_manager.invite_id, + BuildDecisionBookInvitations.build_id + == token_dict.selected_occupant.build_id, + ).data + if not invitation: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Invitation not found. Please check token", + ) + + assign_occupant_type = OccupantTypes.filter_by_one( + system=True, + uu_id=data.occupant_type_uu_id, + ).data + 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_all( + BuildParts.build_id == token_dict.selected_occupant.build_id, + ).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 + if not selected_living_space: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Person not found. Please check person uuid", + ) + + book_person_to_assign: BuildDecisionBookPerson = ( + BuildDecisionBookPerson.filter_one( + BuildDecisionBookPerson.build_living_space_id + == selected_living_space.id, + BuildDecisionBookPerson.invite_id == invitation.id, + ).data + ) + 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.build_living_space_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.build_living_space_uu_id}. Invite UUID: {invitation.uu_id}", + ) + + if assign_occupant_type.occupant_code in ("MT-PRS", "MT-WRT"): + occupant_type_unique = OccupantTypes.filter_by_one( + system=True, + occupant_code=assign_occupant_type.occupant_code, + occupant_category_type="MT", + ).data + if assigned_book_person_occupant := BuildDecisionBookPersonOccupants.filter_one( + BuildDecisionBookPersonOccupants.invite_id == invitation.id, + BuildDecisionBookPersonOccupants.occupant_type_id + == occupant_type_unique.id, + ).data: + 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.filter_one( + BuildDecisionBookPersonOccupants.invite_id == invitation.id, + BuildDecisionBookPersonOccupants.occupant_type_id + == manager_occupant_type.id, + ) + person_occupant_manager.query.delete() + + book_person_to_assign.add_occupant_type( + occupant_type=assign_occupant_type, + build_living_space_id=selected_living_space.id, + ) + BuildDecisionBookPersonOccupants.save() + 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_all() +# 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_all() +# 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_all( +# 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(), +# ), +# ) diff --git a/api_events/events/decision_book/decision_book_invitations.py b/api_events/events/decision_book/decision_book_invitations.py new file mode 100644 index 0000000..b782e81 --- /dev/null +++ b/api_events/events/decision_book/decision_book_invitations.py @@ -0,0 +1,282 @@ +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") + ) +) diff --git a/api_events/events/decision_book/decision_book_payment.py b/api_events/events/decision_book/decision_book_payment.py new file mode 100644 index 0000000..79b503f --- /dev/null +++ b/api_events/events/decision_book/decision_book_payment.py @@ -0,0 +1,169 @@ +from typing import Union + +from fastapi.responses import JSONResponse +from fastapi import status + +from api_validations.validations_response.parts import BuildPartsListResponse +from databases import ( + Build, + BuildParts, +) +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_validations.validations_request import ( + InsertBuildParts, + UpdateBuildParts, + ListOptions, +) +from databases.sql_models.building.decision_book import BuildDecisionBookPayments + + +class DecisionBookPaymentListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "49bb8ab8-520d-4676-a159-aaf84f37f372": "decision_book_payment_list" + } + __event_validation__ = {"49bb8ab8-520d-4676-a159-aaf84f37f372": None} + + @classmethod + def decision_book_payment_list( + cls, + list_options: ListOptions, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + """ + SELECT payment_plan_time_periods, process_date, payment_amount, currency, payment_types_id, + payment_types_uu_id, period_time, process_date_y, process_date_m, build_decision_book_item_id, + build_decision_book_item_uu_id, decision_book_project_id, decision_book_project_uu_id, build_parts_id, + build_parts_uu_id, id, uu_id, ref_id, created_at, updated_at, cryp_uu_id, created_by, created_by_id, + updated_by, updated_by_id, confirmed_by, confirmed_by_id, is_confirmed, replication_id, deleted, + active, is_notification_send, is_email_send, expiry_starts, expiry_ends, account_records_id, + account_records_uu_id FROM public.build_decision_book_payments; + """ + from sqlalchemy import func, select, union_all, extract, Integer + + build_parts_id, build_decision_book_id = 7, "" + payment_types_id_recv, payment_types_id_deb = 46, 45 + + BuildDecisionBookPayments.filter_attr = list_options + # Define the subqueries + debit_subquery = ( + select( + BuildDecisionBookPayments.payment_plan_time_periods, + func.sum(BuildDecisionBookPayments.payment_amount).label("debit"), + func.cast(0, Integer).label("recv"), + func.max(BuildDecisionBookPayments.process_date).label("ls"), + ) + .where( + BuildDecisionBookPayments.build_parts_id == build_parts_id, + BuildDecisionBookPayments.payment_types_id == payment_types_id_deb, + BuildDecisionBookPayments.build_decision_book_id + == build_decision_book_id, + extract("year", func.current_date()) + == extract("year", BuildDecisionBookPayments.process_date), + extract("month", func.current_date()) + == extract("month", BuildDecisionBookPayments.process_date), + ) + .group_by(BuildDecisionBookPayments.payment_plan_time_periods) + ) + + recv_subquery = ( + select( + BuildDecisionBookPayments.payment_plan_time_periods, + func.cast(0, Integer).label("debit"), + func.sum(BuildDecisionBookPayments.payment_amount).label("recv"), + func.max(BuildDecisionBookPayments.process_date).label("ls"), + ) + .where( + BuildDecisionBookPayments.build_parts_id == build_parts_id, + BuildDecisionBookPayments.payment_types_id == payment_types_id_recv, + BuildDecisionBookPayments.build_decision_book_id + == build_decision_book_id, + extract("year", func.current_date()) + == extract("year", BuildDecisionBookPayments.process_date), + extract("month", func.current_date()) + == extract("month", BuildDecisionBookPayments.process_date), + ) + .group_by(BuildDecisionBookPayments.payment_plan_time_periods) + ) + + # Combine the subqueries using union_all + combined_subquery = union_all(debit_subquery, recv_subquery).alias("AA") + + # Final query + final_query = select( + combined_subquery.c.payment_plan_time_periods, + func.sum(combined_subquery.c.debit).label("debit"), + func.sum(combined_subquery.c.recv).label("recv"), + combined_subquery.c.ls.label("Last Seen"), + ).group_by( + combined_subquery.c.payment_plan_time_periods, combined_subquery.c.ls + ) + + # Execute the query + book_payments_month = BuildDecisionBookPayments.session.execute( + final_query + ).fetchall() + print("book_payments_month", book_payments_month) + + debit_subquery = ( + select( + BuildDecisionBookPayments.payment_plan_time_periods, + func.sum(BuildDecisionBookPayments.payment_amount).label("debit"), + func.cast(0, Integer).label("recv"), + func.max(BuildDecisionBookPayments.process_date).label("ls"), + ) + .where( + BuildDecisionBookPayments.build_parts_id == build_parts_id, + BuildDecisionBookPayments.payment_types_id == payment_types_id_deb, + BuildDecisionBookPayments.build_decision_book_id + == build_decision_book_id, + ) + .group_by(BuildDecisionBookPayments.payment_plan_time_periods) + ) + + recv_subquery = ( + select( + BuildDecisionBookPayments.payment_plan_time_periods, + func.cast(0, Integer).label("debit"), + func.sum(BuildDecisionBookPayments.payment_amount).label("recv"), + func.max(BuildDecisionBookPayments.process_date).label("ls"), + ) + .where( + BuildDecisionBookPayments.build_parts_id == build_parts_id, + BuildDecisionBookPayments.payment_types_id == payment_types_id_recv, + BuildDecisionBookPayments.build_decision_book_id + == build_decision_book_id, + ) + .group_by(BuildDecisionBookPayments.payment_plan_time_periods) + ) + + # Combine the subqueries using union_all + combined_subquery = union_all(debit_subquery, recv_subquery).alias("AA") + + # Final query + final_query = select( + combined_subquery.c.payment_plan_time_periods, + func.sum(combined_subquery.c.debit).label("debit"), + func.sum(combined_subquery.c.recv).label("recv"), + combined_subquery.c.ls.label("Last Seen"), + ).group_by( + combined_subquery.c.payment_plan_time_periods, combined_subquery.c.ls + ) + + # Execute the query + book_payments = BuildDecisionBookPayments.session.execute( + final_query + ).fetchall() + print("book_payments", book_payments) + return AlchemyJsonResponse( + completed=True, + message="Building Parts Records are listed", + result=[book_payments, book_payments_month], + cls_object=BuildParts, + response_model=BuildPartsListResponse, + filter_attributes=list_options, + ) diff --git a/api_events/events/decision_book/project_decision_book.py b/api_events/events/decision_book/project_decision_book.py new file mode 100644 index 0000000..e22f90a --- /dev/null +++ b/api_events/events/decision_book/project_decision_book.py @@ -0,0 +1,372 @@ +from typing import Union + +from api_library.date_time_actions.date_functions import system_arrow, client_arrow +from databases import ( + BuildDecisionBookProjects, + BuildDecisionBookProjectPerson, + BuildDecisionBookPayments, + OccupantTypes, +) + +from api_events.events.abstract_class import MethodToEvent, ActionsSchema +from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject +from api_validations.validations_request import ( + InsertBuildDecisionBookProjects, + UpdateBuildDecisionBookProjects, + ApprovalsBuildDecisionBookProjects, + ListOptions, +) +from api_validations.core_response import AlchemyJsonResponse +from databases import Build, BuildLivingSpace, BuildParts, ApiEnumDropdown +from databases.sql_models.building.decision_book import ( + BuildDecisionBookProjectItems, + BuildDecisionBookItems, + BuildDecisionBook, +) + + +class ProjectDecisionBookListEventMethods(MethodToEvent): + + event_type = "LIST" + + __event_keys__ = { + "96459b36-37f2-4d5b-8370-c459058d5bce": "project_decision_book_list", + } + __event_validation__ = {"96459b36-37f2-4d5b-8370-c459058d5bce": None} + + @classmethod + def project_decision_book_list( + cls, + list_options: ListOptions, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, EmployeeTokenObject): + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="NOT_ALLOWED", + message="Employee cannot create project project decision book", + data={}, + ) + elif isinstance(token_dict, OccupantTokenObject): + build_decision_book = BuildDecisionBook.filter_one( + BuildDecisionBook.build_id == token_dict.selected_occupant.build_id, + ).data + if not build_decision_book: + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="NOT_FOUND", + message="Build decision book not found", + data={}, + ) + BuildDecisionBookProjects.filter_attr = list_options + decision_book_projects = BuildDecisionBookProjects.filter_all( + BuildDecisionBookProjects.build_decision_book_id + == build_decision_book.id, + ) + return AlchemyJsonResponse( + status_code="HTTP_200_OK", + message="Project decision book created successfully", + result=decision_book_projects, + ) + + +class ProjectDecisionBookCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + + __event_keys__ = { + "b8e44bb2-f157-4dd5-8a24-0e02db4877c9": "project_decision_book_create", + } + __event_validation__ = { + "b8e44bb2-f157-4dd5-8a24-0e02db4877c9": InsertBuildDecisionBookProjects + } + + @classmethod + def project_decision_book_create( + cls, + data: InsertBuildDecisionBookProjects, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, EmployeeTokenObject): + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="NOT_ALLOWED", + message="Employee cannot create project project decision book", + data={}, + ) + elif isinstance(token_dict, OccupantTokenObject): + living_space = BuildLivingSpace.filter_one( + BuildLivingSpace.id == token_dict.selected_occupant.living_space_id, + ).data + if not living_space: + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="NOT_FOUND", + message="Living space not found", + data={}, + ) + + occupant_type = OccupantTypes.filter_by_one( + occupant_category_type="PRJ", + occupant_code="PRJ-LDR", + id=living_space.occupant_type, + ).data + if not occupant_type: + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="NOT_FOUND", + message=f"{token_dict.selected_occupant.occupant_type_uu_id} occupant type is not allowed, only PRJ-LDR occupant type is allowed", + data={}, + ) + decision_book_project_person = BuildDecisionBookProjectPerson.filter_one( + BuildDecisionBookProjectPerson.living_space_id + == token_dict.selected_occupant.living_space_id, + ) + return AlchemyJsonResponse( + status_code="HTTP_200_OK", + message="Project decision book created successfully", + result=decision_book_project_person, + ) + + +class ProjectDecisionBookUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + + __event_keys__ = { + "bfe3ef13-030f-495f-b692-94bcb746d700": "project_decision_book_update", + } + __event_validation__ = { + "bfe3ef13-030f-495f-b692-94bcb746d700": UpdateBuildDecisionBookProjects + } + + @classmethod + def project_decision_book_update( + cls, + data: UpdateBuildDecisionBookProjects, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, EmployeeTokenObject): + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="NOT_ALLOWED", + message="Employee cannot create project project decision book", + data={}, + ) + elif isinstance(token_dict, OccupantTokenObject): + living_space = BuildLivingSpace.filter_one( + BuildLivingSpace.id == token_dict.selected_occupant.living_space_id, + ).data + if not living_space: + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="NOT_FOUND", + message="Living space not found", + data={}, + ) + occupant_type = OccupantTypes.filter_by_one( + occupant_category_type="PRJ", + occupant_code="PRJ-LDR", + id=living_space.occupant_type, + ).data + if not occupant_type: + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="NOT_FOUND", + message=f"{token_dict.selected_occupant.occupant_type_uu_id} occupant type is not allowed, only PRJ-LDR occupant type is allowed", + data={}, + ) + decision_book_project_person = BuildDecisionBookProjectPerson.filter_one( + BuildDecisionBookProjectPerson.build_decision_book_project_uu_id + == data.build_decision_book_project_uu_id, + BuildDecisionBookProjectPerson.living_space_id + == token_dict.selected_occupant.living_space_id, + ).data + if not decision_book_project_person: + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="NOT_FOUND", + message="This project is not allowed for this occupant", + data={}, + ) + decision_book_project = BuildDecisionBookProjects.filter_one( + BuildDecisionBookProjects.id + == decision_book_project_person.build_decision_book_project_id, + ) + if decision_book_project.is_completed: + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="NOT_ALLOWED", + message="Project decision book is closed. No modification is allowed", + data={}, + ) + data_dict = data.excluded_dump() + decision_book_project.update(**data_dict) + return AlchemyJsonResponse( + status_code="HTTP_200_OK", + message="Project decision book created successfully", + result=decision_book_project_person, + ) + + +class ProjectDecisionBookApprovalEventMethods(MethodToEvent): + + event_type = "UPDATE" + + __event_keys__ = { + "a83a83fe-8446-4c60-9ae5-d1c06adbf626": "project_decision_book_approval", + } + __event_validation__ = { + "a83a83fe-8446-4c60-9ae5-d1c06adbf626": ApprovalsBuildDecisionBookProjects + } + + @classmethod + def project_decision_book_approval( + cls, + data: ApprovalsBuildDecisionBookProjects, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + BuildDecisionBookPayments.client_arrow = client_arrow + BuildDecisionBookPayments.client_arrow.timezone = token_dict.timezone or "GMT+3" + if isinstance(token_dict, EmployeeTokenObject): + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="NOT_ALLOWED", + message="Employee cannot create project project decision book", + data={}, + ) + elif isinstance(token_dict, OccupantTokenObject): + living_space = BuildLivingSpace.filter_one( + BuildLivingSpace.id == token_dict.selected_occupant.living_space_id, + ).data + if not living_space: + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="NOT_FOUND", + message="Living space not found", + data={}, + ) + occupant_type = OccupantTypes.filter_by_one( + system=True, + occupant_category_type="PRJ", + occupant_code="PRJ-LDR", + id=living_space.occupant_type, + ).data + if not occupant_type: + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="NOT_FOUND", + message=f"{token_dict.selected_occupant.occupant_type_uu_id} occupant type is not allowed, only PRJ-LDR occupant type is allowed", + data={}, + ) + decision_book_project_person = BuildDecisionBookProjectPerson.filter_one( + BuildDecisionBookProjectPerson.build_decision_book_project_uu_id + == data.build_decision_book_project_uu_id, + BuildDecisionBookProjectPerson.living_space_id + == token_dict.selected_occupant.living_space_id, + ).data + if not decision_book_project_person: + raise BuildDecisionBookProjectPerson.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="NOT_FOUND", + message="This project is not allowed for this occupant", + data={}, + ) + + decision_book_project = BuildDecisionBookProjects.filter_one( + BuildDecisionBookProjects.id + == decision_book_project_person.build_decision_book_project_id, + ).data + if decision_book_project.is_completed: + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="NOT_ALLOWED", + message="Project decision book is closed. No modification is allowed", + data={}, + ) + data_dict = data.excluded_dump() + data_dict["is_completed"] = True + + build_parts_list = BuildParts.filter_all( + BuildParts.human_livable == True, + BuildParts.build_id == token_dict.selected_occupant.build_id, + ).data + + decision_book_project_item = BuildDecisionBookItems.filter_one( + BuildDecisionBookItems.id + == decision_book_project.build_decision_book_item_id + ).data + + book_payment_dict = dict( + build_decision_book_item_id=decision_book_project_item.id, + build_decision_book_item_uu_id=str(decision_book_project_item.uu_id), + currency=decision_book_project.currency, + ) + payment_type = ApiEnumDropdown.get_debit_search(search_debit="DT-D") + for final_price in data.final_price_list or []: + for build_part_single in build_parts_list: + local_date = BuildDecisionBookPayments.client_arrow.get( + str(final_price["date"]) + ) + local_date = system_arrow.get(local_date) + payment_amount = abs(float(final_price["price"])) * -1 + created_book_payment = BuildDecisionBookPayments.find_or_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_type.id, + payment_types_uu_id=str(payment_type.uu_id), + process_date=str(local_date), + process_date_m=int(local_date.month), + process_date_y=int(local_date.year), + payment_plan_time_periods=str( + decision_book_project.project_type + ), + period_time=f"{local_date.year}-{str(local_date.month).zfill(2)}", + decision_book_project_id=decision_book_project.id, + decision_book_project_uu_id=str(decision_book_project.uu_id), + **book_payment_dict, + ) + created_book_payment.save_and_confirm() + updated_decision_book_project = decision_book_project.update(**data_dict) + updated_decision_book_project.save_and_confirm() + return AlchemyJsonResponse( + status_code="HTTP_200_OK", + message="Project decision book created successfully", + result=updated_decision_book_project, + ) + + +class ProjectDecisionBookPatchEventMethods(MethodToEvent): + + event_type = "PATCH" + + __event_keys__ = { + "444d67a0-b3a8-4ca2-9d8d-f1acc75011e0": "project_decision_book_patch", + } + __event_validation__ = {"444d67a0-b3a8-4ca2-9d8d-f1acc75011e0": None} + + @classmethod + def project_decision_book_patch( + cls, + data, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + return + + +ProjectDecisionBookListEventMethod = ProjectDecisionBookListEventMethods( + action=ActionsSchema(endpoint="/build/decision_book/project/list") +) +ProjectDecisionBookCreateEventMethod = ProjectDecisionBookCreateEventMethods( + action=ActionsSchema(endpoint="/build/decision_book/project/create") +) +ProjectDecisionBookUpdateEventMethod = ProjectDecisionBookUpdateEventMethods( + action=ActionsSchema(endpoint="/build/decision_book/project/update") +) +ProjectDecisionBookApprovalEventMethod = ProjectDecisionBookApprovalEventMethods( + action=ActionsSchema(endpoint="/build/decision_book/project/approval") +) +ProjectDecisionBookPatchEventMethod = ProjectDecisionBookPatchEventMethods( + action=ActionsSchema(endpoint="/build/decision_book/project/patch") +) diff --git a/api_events/events/decision_book/project_decision_book_items.py b/api_events/events/decision_book/project_decision_book_items.py new file mode 100644 index 0000000..5c1d522 --- /dev/null +++ b/api_events/events/decision_book/project_decision_book_items.py @@ -0,0 +1,156 @@ +from typing import Union + +from databases import ( + BuildDecisionBookProjectItems, + BuildDecisionBookProjectPerson, +) + +from api_validations.validations_request import ( + InsertBuildDecisionBookProjectItems, + UpdateBuildDecisionBookProjectItems, + 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 AlchemyJsonResponse +from databases.sql_models.building.decision_book import BuildDecisionBookProjects + + +class BuildDecisionBookProjectItemsListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "ce3630e4-2bf9-4433-bdab-1ee72117e54b": "build_decision_book_project_items_list", + } + __event_validation__ = {"ce3630e4-2bf9-4433-bdab-1ee72117e54b": None} + + @staticmethod + def build_decision_book_project_items_list( + requester: Union[EmployeeTokenObject, OccupantTokenObject], + list_options: ListOptions, + ): + response = BuildDecisionBookProjectItems.list_items( + requester=requester, + list_options=list_options, + ) + return AlchemyJsonResponse( + message="Build Decision Book Project Items List", + result=response, + ) + + +class BuildDecisionBookProjectItemsCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "b27e4fd0-6e3e-441b-9b33-806ac7082444": "build_decision_book_project_items_create", + } + __event_validation__ = { + "b27e4fd0-6e3e-441b-9b33-806ac7082444": InsertBuildDecisionBookProjectItems, + } + + @staticmethod + def build_decision_book_project_items_create( + data: InsertBuildDecisionBookProjectItems, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, EmployeeTokenObject): + raise BuildDecisionBookProjectItems.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="UNAUTHORIZED", + message=f"No permission to create decision book project items", + data={}, + ) + elif isinstance(token_dict, OccupantTokenObject): + book_project = BuildDecisionBookProjects.filter_one( + BuildDecisionBookProjects.uu_id + == data.build_decision_book_project_uu_id, + BuildDecisionBookProjects.project_response_living_space_id + == token_dict.selected_occupant.living_space_id, + ).data + if not book_project: + raise BuildDecisionBookProjectItems.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="NOT_FOUND", + message=f"This user can not create project item for this project uu_id : {data.build_decision_book_project_uu_id}", + data={}, + ) + data_dict = data.excluded_dump() + data_dict["build_decision_book_project_id"] = book_project.id + created_project_item = BuildDecisionBookProjectItems.find_or_create( + **data_dict + ) + created_project_item.save_and_confirm() + return AlchemyJsonResponse( + message="Build Decision Book Project Items Create", + result=created_project_item.get_dict(), + ) + + +class BuildDecisionBookProjectItemsUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "b2b7cdce-9a0c-4722-90ff-8bef36b4ec6b": "build_decision_book_project_items_update", + } + __event_validation__ = { + "b2b7cdce-9a0c-4722-90ff-8bef36b4ec6b": UpdateBuildDecisionBookProjectItems + } + + @staticmethod + def build_decision_book_project_items_update( + requester: Union[EmployeeTokenObject, OccupantTokenObject], + decision_book_project_items: UpdateBuildDecisionBookProjectItems, + ): + raise BuildDecisionBookProjectItems.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="UNAUTHORIZED", + message=f"No permission to update decision book project items", + data={}, + ) + + +class BuildDecisionBookProjectItemsPatchEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "e59d50df-dd22-4823-aeae-b9490332885c": "build_decision_book_project_items_patch", + } + __event_validation__ = {"e59d50df-dd22-4823-aeae-b9490332885c": None} + + @staticmethod + def build_decision_book_project_items_patch( + requester: Union[EmployeeTokenObject, OccupantTokenObject], + decision_book_project_items: UpdateBuildDecisionBookProjectItems, + ): + response = BuildDecisionBookProjectItems.delete_item( + requester=requester, + decision_book_project_items=decision_book_project_items, + ) + return AlchemyJsonResponse( + message="Build Decision Book Project Items Patch", + result=response, + ) + + +BuildDecisionBookProjectItemsListEventMethod = ( + BuildDecisionBookProjectItemsListEventMethods( + action=ActionsSchema(endpoint="/build/decision_book/project/items/list") + ) +) +BuildDecisionBookProjectItemsCreateEventMethod = ( + BuildDecisionBookProjectItemsCreateEventMethods( + action=ActionsSchema(endpoint="/build/decision_book/project/items/create") + ) +) +BuildDecisionBookProjectItemsUpdateEventMethod = ( + BuildDecisionBookProjectItemsUpdateEventMethods( + action=ActionsSchema(endpoint="/build/decision_book/project/items/update") + ) +) +BuildDecisionBookProjectItemsPatchEventMethod = ( + BuildDecisionBookProjectItemsPatchEventMethods( + action=ActionsSchema(endpoint="/build/decision_book/project/items/patch") + ) +) diff --git a/api_events/events/decision_book/project_decision_book_person.py b/api_events/events/decision_book/project_decision_book_person.py new file mode 100644 index 0000000..0dba3e2 --- /dev/null +++ b/api_events/events/decision_book/project_decision_book_person.py @@ -0,0 +1,189 @@ +from typing import Union + +from databases import ( + BuildDecisionBookProjects, + BuildDecisionBookProjectPerson, +) + +from api_validations.validations_request import ( + InsertBuildDecisionBookProjectPerson, + UpdateBuildDecisionBookProjectPerson, + 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 AlchemyJsonResponse + + +class ProjectDecisionBookPersonListEventMethods(MethodToEvent): + + event_type = "LIST" + + __event_keys__ = { + "7101b5ca-8bef-40f9-8b4d-646d9994e18f": "project_decision_book_person_list", + } + __event_validation__ = {"7101b5ca-8bef-40f9-8b4d-646d9994e18f": None} + + @classmethod + def project_decision_book_person_list( + cls, + list_options: ListOptions, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, EmployeeTokenObject): + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="NOT_ALLOWED", + message="Employee cannot create project project decision book", + data={}, + ) + elif isinstance(token_dict, OccupantTokenObject): + project_person = BuildDecisionBookProjectPerson.filter_all( + BuildDecisionBookProjects.living_space_id + == token_dict.selected_occupant.living_space_id, + ) + decision_book_ids = [ + _.build_decision_book_project_id for _ in project_person.data + ] + decision_book_projects = BuildDecisionBookProjects.filter_all( + BuildDecisionBookProjects.build_decision_book_project_id.in_( + decision_book_ids + ), + ) + return AlchemyJsonResponse( + status_code="HTTP_200_OK", + message="Project decision person book listed successfully", + result=decision_book_projects, + ) + + +class ProjectDecisionBookPersonCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + + __event_keys__ = { + "9c88e314-84e8-435e-8c1e-6a5aae80b2e6": "project_decision_book_person_create", + } + __event_validation__ = { + "9c88e314-84e8-435e-8c1e-6a5aae80b2e6": InsertBuildDecisionBookProjectPerson + } + + @classmethod + def project_decision_book_create( + cls, + data: InsertBuildDecisionBookProjectPerson, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, EmployeeTokenObject): + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="NOT_ALLOWED", + message="Employee cannot create project project decision book", + data={}, + ) + elif isinstance(token_dict, OccupantTokenObject): + decision_book = BuildDecisionBookProjects.filter_one( + BuildDecisionBookProjects.build_decision_book_uu_id + == data.get("build_decision_book_uu_id"), + BuildDecisionBookProjects.project_response_living_space_id + == token_dict.selected_occupant.living_space_id, + ) + return AlchemyJsonResponse( + status_code="HTTP_200_OK", + message="Project decision book created successfully", + result=decision_book, + ) + + +class ProjectDecisionBookPersonUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + + __event_keys__ = { + "7fbd18a0-c099-4494-ada1-bb23e39bb141": "project_decision_book_update_person", + } + __event_validation__ = { + "7fbd18a0-c099-4494-ada1-bb23e39bb141": UpdateBuildDecisionBookProjectPerson + } + + @classmethod + def project_decision_book_update( + cls, + data: UpdateBuildDecisionBookProjectPerson, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, EmployeeTokenObject): + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="NOT_ALLOWED", + message="Employee cannot create project project decision book", + data={}, + ) + elif isinstance(token_dict, OccupantTokenObject): + decision_book_project_person = BuildDecisionBookProjectPerson.filter_one( + BuildDecisionBookProjects.build_decision_book_project_uu_id + == data.get("build_decision_book_uu_id"), + BuildDecisionBookProjects.living_space_id + == token_dict.selected_occupant.living_space_id, + ) + + return AlchemyJsonResponse( + status_code="HTTP_200_OK", + message="Project decision book created successfully", + result=decision_book_project_person, + ) + + +class ProjectDecisionBookPersonPatchEventMethods(MethodToEvent): + + event_type = "PATCH" + + __event_keys__ = { + "a122e84a-5556-4bf7-b680-1f47c438d4f7": "project_decision_book_person_patch", + } + __event_validation__ = {"a122e84a-5556-4bf7-b680-1f47c438d4f7": None} + + @classmethod + def project_decision_book_patch( + cls, + data, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, EmployeeTokenObject): + raise BuildDecisionBookProjects.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + error_case="NOT_ALLOWED", + message="Employee cannot create project project decision book", + data={}, + ) + elif isinstance(token_dict, OccupantTokenObject): + decision_book_project_person = BuildDecisionBookProjectPerson.filter_one( + BuildDecisionBookProjects.build_decision_book_project_uu_id + == data.get("build_decision_book_uu_id"), + BuildDecisionBookProjects.living_space_id + == token_dict.selected_occupant.living_space_id, + ) + return AlchemyJsonResponse( + status_code="HTTP_200_OK", + message="Project decision book created successfully", + result=decision_book_project_person, + ) + + +ProjectDecisionBookPersonListEventMethod = ProjectDecisionBookPersonListEventMethods( + action=ActionsSchema(endpoint="/build/decision_book/project/people/list") +) +ProjectDecisionBookPersonCreateEventMethod = ( + ProjectDecisionBookPersonCreateEventMethods( + action=ActionsSchema(endpoint="/build/decision_book/project/people/create") + ) +) +ProjectDecisionBookPersonUpdateEventMethod = ( + ProjectDecisionBookPersonUpdateEventMethods( + action=ActionsSchema(endpoint="/build/decision_book/project/people/update") + ) +) +ProjectDecisionBookPersonPatchEventMethod = ProjectDecisionBookPersonPatchEventMethods( + action=ActionsSchema(endpoint="/build/decision_book/project/people/patch") +) diff --git a/api_events/events/events/__init__.py b/api_events/events/events/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_events/events/events/events_bind_modules.py b/api_events/events/events/events_bind_modules.py new file mode 100644 index 0000000..6daf315 --- /dev/null +++ b/api_events/events/events/events_bind_modules.py @@ -0,0 +1,157 @@ +import typing + +from databases import ( + Modules, + BuildLivingSpace, +) +from api_validations.validations_request import ( + RegisterModules2Occupant, + RegisterModules2Employee, +) +from api_events.events.abstract_class import MethodToEvent, ActionsSchema +from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject +from api_events.events.events.events_bind_services import ( + ServiceBindOccupantEventMethods, +) +from api_library.date_time_actions.date_functions import system_arrow +from api_validations.core_response import AlchemyJsonResponse +from databases.sql_models.company.employee import Employees +from databases.sql_models.event.event import Event2Occupant, Event2Employee + + +class ModulesBindOccupantEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "91003e90-8ead-4705-98a3-f8731c6ecb38": "modules_bind_occupant", + } + __event_validation__ = { + "91003e90-8ead-4705-98a3-f8731c6ecb38": None, + } + + @classmethod + def bind_default_module_for_first_init_occupant( + cls, build_living_space_id: int, expires_at: str = None + ): + + living_space = BuildLivingSpace.filter_one( + BuildLivingSpace.id == build_living_space_id, system=True + ).data + modules = Modules.filter_all(Modules.is_default_module == True).data + print("living_space", living_space, "modules", modules) + if not living_space or not modules: + print(f"Giving living Space or Modules: Default not found") + return + service_build_dict = dict(build_living_space_id=living_space.id) + if expires_at: + service_build_dict["expires_at"] = str(system_arrow.get(expires_at)) + else: + expiry_ends = str(system_arrow.get(living_space.expiry_ends)) + service_build_dict["expires_at"] = expiry_ends + + for module in modules: + for service in module.retrieve_services(): + event_occupant = Event2Occupant.find_or_create( + event_service_id=service.id, + event_service_uu_id=str(service.uu_id), + build_living_space_id=living_space.id, + build_living_space_uu_id=str(living_space.uu_id), + ) + event_occupant.save_and_confirm() + return True + + # @classmethod + # def modules_bind_occupant_system( + # cls, build_living_space_id: int, modules_id: int, expires_at: str = None + # ): + # + # living_space = BuildLivingSpace.filter_one( + # BuildLivingSpace.id == build_living_space_id, + # ).data + # modules = Modules.filter_one(Modules.id == modules_id).data + # + # if not living_space or not modules: + # print(f"Giving living Space or Modules: {modules.module_name} not found") + # return + # service_build_dict = dict(build_living_space_id=living_space.id) + # if expires_at: + # service_build_dict["expires_at"] = str(system_arrow.get(expires_at)) + # else: + # service_build_dict["expires_at"] = str( + # system_arrow.get(living_space.expiry_ends) + # ) + # + # for service in modules.retrieve_services(): + # ServiceBindOccupantEventMethods.bind_services_occupant_system( + # **service_build_dict, + # service_id=service.id, + # ) + # BuildLivingSpace.save() + # return True + + @classmethod + def modules_bind_occupant( + cls, + data: RegisterModules2Occupant, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + + return + + +class ModulesBindEmployeeEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "d4ed23db-62e9-4015-b7c0-698a7917aa0c": "modules_bind_employee", + } + __event_validation__ = { + "d4ed23db-62e9-4015-b7c0-698a7917aa0c": None, + } + + @classmethod + def bind_default_module_for_first_init_occupant( + cls, employee_id: int, expires_at: str = None + ): + + employee = Employees.filter_one( + Employees.id == employee_id, + ).data + modules = Modules.filter_all(Modules.is_default_module == True).data + print("living_space", employee, "modules", modules) + if not employee or not modules: + print(f"Giving living Space or Modules: Default not found") + return + service_build_dict = dict(build_living_space_id=employee.id) + if expires_at: + service_build_dict["expires_at"] = str(system_arrow.get(expires_at)) + else: + expiry_ends = str(system_arrow.get(employee.expiry_ends)) + service_build_dict["expires_at"] = expiry_ends + + for module in modules: + for service in module.retrieve_services(): + event_employee = Event2Employee.find_or_create( + event_service_id=service.id, + event_service_uu_id=str(service.uu_id), + employee_id=employee.id, + employee_uu_id=str(employee.uu_id), + ) + event_employee.save_and_confirm() + return True + + @classmethod + def modules_bind_employee( + cls, + data: RegisterModules2Employee, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + return + + +ModulesBindOccupantEventMethod = ModulesBindOccupantEventMethods( + action=ActionsSchema(endpoint="/bind/modules/occupant") +) +ModulesBindEmployeeEventMethod = ModulesBindEmployeeEventMethods( + action=ActionsSchema(endpoint="/bind/modules/employee") +) diff --git a/api_events/events/events/events_bind_services.py b/api_events/events/events/events_bind_services.py new file mode 100644 index 0000000..e5997e2 --- /dev/null +++ b/api_events/events/events/events_bind_services.py @@ -0,0 +1,321 @@ +import typing + +from fastapi import status +from fastapi.responses import JSONResponse +from fastapi.exceptions import HTTPException + +from api_library.date_time_actions.date_functions import system_arrow +from databases import ( + Modules, + Employees, + BuildParts, + BuildLivingSpace, + Services, + OccupantTypes, + Event2Employee, + Event2Occupant, +) +from api_validations.validations_request import ( + RegisterServices2Occupant, + RegisterServices2Employee, +) +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 + + +class ServiceBindOccupantEventMethods(MethodToEvent): + event_type = "UPDATE" + __event_keys__ = { + "0d2bc5c9-d4b1-4951-8305-69da4a687fdc": "bind_services_occupant", + } + __event_validation__ = { + "0d2bc5c9-d4b1-4951-8305-69da4a687fdc": RegisterServices2Occupant + } + + @classmethod + def bind_services_occupant_system( + cls, build_living_space_id: int, service_id: int, expires_at: str = None + ): + living_space = BuildLivingSpace.filter_one( + BuildLivingSpace.id == build_living_space_id, + ).data + service = Services.filter_one(Services.id == service_id).data + if not service: + print("Service is not valid. Service can not be binded") + return + + if not living_space: + print("Living Space is not valid. Service is not binded") + return + + if expires_at: + expires_at = str(system_arrow.get(expires_at)) + else: + expires_at = str(system_arrow.get(living_space.expiry_ends)) + + occupants_event = Event2Occupant.find_or_create( + event_service_id=service.id, + event_service_uu_id=str(service.uu_id), + build_living_space_id=living_space.id, + build_living_space_uu_id=str(living_space.uu_id), + expiry_ends=expires_at, + ) + occupants_event.save_and_confirm() + print(f"{service.service_name} is added to occupant {str(living_space.uu_id)}") + + @classmethod + def bind_services_occupant( + cls, + data: RegisterServices2Occupant, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + from sqlalchemy.dialects.postgresql import insert + + if isinstance(token_dict, EmployeeTokenObject): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Employee is not authorized to add service to any occupant", + ) + + occupants_build_part = BuildParts.filter_one( + BuildParts.uu_id == data.build_part_uu_id, + BuildParts.build_id == token_dict.selected_occupant.build_id, + ).data + if not occupants_build_part: + return JSONResponse( + content={ + "completed": False, + "message": "User is not authorized to add service to this occupant or flat", + "data": {}, + }, + status_code=status.HTTP_404_NOT_FOUND, + ) + + occupant_occupant_type = OccupantTypes.filter_by_one( + uu_id=data.occupant_uu_id + ).data + if not occupant_occupant_type: + return JSONResponse( + content={ + "completed": False, + "message": "Occupant Types is not found", + "data": {}, + }, + status_code=status.HTTP_404_NOT_FOUND, + ) + + service = Services.filter_one(Services.uu_id == data.service_uu_id).data + if not service: + return JSONResponse( + content={ + "completed": False, + "message": "Service is not found", + "data": {}, + }, + status_code=status.HTTP_404_NOT_FOUND, + ) + + # service_events = Service2Events.filter_all( + # Service2Events.service_id == service.id, + # ).data + # if not service_events: + # raise HTTPException( + # status_code=status.HTTP_404_NOT_FOUND, + # detail="Service has no events registered. Please contact with your manager", + # ) + + living_space = BuildLivingSpace.filter_one( + BuildLivingSpace.build_parts_id == occupants_build_part.id, + BuildLivingSpace.occupant_types_id == occupant_occupant_type.id, + BuildLivingSpace.person_id == token_dict.person_id, + ).data + if not living_space: + return JSONResponse( + content={ + "completed": False, + "message": "Living Space is not found with given data. Please check flat and occupant type", + "data": {}, + }, + status_code=status.HTTP_404_NOT_FOUND, + ) + + # event_ids_list = [ + # { + # "build_living_space_id": living_space.id, + # "build_living_space_uu_id": str(living_space.uu_id), + # "event_id": service_event.event_id, + # "event_uu_id": str(service_event.event_uu_id), + # "is_confirmed": True, + # } + # for service_event in service_events + # ] + # + # session_execute = Services.session.execute( + # insert(Event2Occupant) + # .values(event_ids_list) + # .on_conflict_do_nothing( + # index_elements=["employee_id", "event_id"], + # ) + # ) + # count_row = session_execute.rowcount + # print(f"{count_row} events are added to employee {str(living_space.uu_id)}") + # Services.save() + + +class ServiceBindEmployeeEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "50f84023-d8ec-4257-bfce-08ddf077c101": "bind_services_employee_super_user", + } + __event_validation__ = {"50f84023-d8ec-4257-bfce-08ddf077c101": None} + + @classmethod + def bind_services_employee(cls, service_id: int, employee_id: int): + employee = Employees.filter_by_one( + id=employee_id, **Employees.valid_record_dict + ).data + service = Services.filter_by_one( + id=service_id, **Services.valid_record_dict + ).data + if not service: + print("Service is not valid. Service can not be binded") + return + + if not employee: + print("Employee is not valid. Service is not binded") + return + + # service_events = Service2Events.filter_all( + # Service2Events.service_id == service.id, + # ).data + # if not service_events: + # raise Exception( + # "Service has no events registered. Please contact with your manager" + # ) + + # event_ids_list = [ + # { + # "employee_id": employee_id, + # "employee_uu_id": str(employee.uu_id), + # "event_id": service_event.event_id, + # "event_uu_id": str(service_event.event_uu_id), + # "is_confirmed": True, + # } + # for service_event in service_events + # ] + # + # session_execute = Services.session.execute( + # insert(Event2Employee) + # .values(event_ids_list) + # .on_conflict_do_nothing( + # index_elements=["employee_id", "event_id"], + # ) + # ) + # count_row = session_execute.rowcount + # print(f"{count_row} events are added to employee {employee.uu_id}") + # for service_event in service_events: + # service_event.save_and_confirm() + + @classmethod + def bind_services_employee_super_user( + cls, + data: RegisterServices2Employee, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, OccupantTokenObject): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Occupant is not authorized to add service to any employee", + ) + + employee = Employees.filter_by_one( + uu_id=data.employee_uu_id, **Employees.valid_record_dict + ).data + if not employee: + return JSONResponse( + content={ + "completed": False, + "message": "This employee is not authorized to add event to this employee", + "data": {}, + }, + status_code=status.HTTP_404_NOT_FOUND, + ) + + service = Services.filter_by_one( + uu_id=data.service_uu_id, **Services.valid_record_dict + ).data + if not service: + return JSONResponse( + content={ + "completed": False, + "message": "Service is not found", + "data": {}, + }, + status_code=status.HTTP_404_NOT_FOUND, + ) + + event_of_employee = Event2Employee.find_or_create( + event_service_id=service.id, + event_service_uu_id=str(service.uu_id), + employee_id=employee.id, + employee_uu_id=str(employee.uu_id), + ) + event_of_employee.save_and_confirm() + print(f"{service.service_name} is added to employee {str(employee.uu_id)}") + + # service_events = Service2Events.filter_all( + # Service2Events.service_id == service.id, + # ).data + # if not service_events: + # raise HTTPException( + # status_code=status.HTTP_404_NOT_FOUND, + # detail="Service has no events registered. Please contact with your manager", + # ) + # + # event_ids_list = [ + # { + # "employee_id": employee.id, + # "employee_uu_id": employee.uu_id, + # "event_id": service_event.event_id, + # "event_uu_id": service_event.event_uu_id, + # "is_confirmed": True, + # } + # for service_event in service_events + # ] + # + # session_execute = Services.session.execute( + # insert(Event2Employee) + # .values(event_ids_list) + # .on_conflict_do_nothing( + # index_elements=["employee_id", "event_id"], + # ) + # ) + # count_row = session_execute.rowcount + # if not count_row: + # Services.save() + # return JSONResponse( + # content={ + # "completed": False, + # "message": "No events are added to employee", + # "data": {}, + # }, + # status_code=status.HTTP_200_OK, + # ) + # return JSONResponse( + # content={ + # "completed": True, + # "message": f"{count_row} events are added to employee", + # "data": {}, + # }, + # status_code=status.HTTP_200_OK, + # ) + + +ServiceBindOccupantEventMethod = ServiceBindOccupantEventMethods( + action=ActionsSchema(endpoint="/bind/services/occupant") +) +ServiceBindEmployeeEventMethod = ServiceBindEmployeeEventMethods( + action=ActionsSchema(endpoint="/bind/services/employee") +) diff --git a/api_events/events/events/events_events.py b/api_events/events/events/events_events.py new file mode 100644 index 0000000..5560e5f --- /dev/null +++ b/api_events/events/events/events_events.py @@ -0,0 +1,270 @@ +from typing import Union + +from fastapi.exceptions import HTTPException + +from api_events.events.events.events_services import ServicesEvents +from databases import ( + Events, + Employees, + Staff, + Duties, + Event2Occupant, + Event2Employee, + BuildLivingSpace, +) +from api_validations.validations_request import ( + RegisterEvents2Employee, + RegisterEvents2Occupant, + 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 AlchemyJsonResponse + + +class EventsListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "9fa01bef-c0e8-4fe1-b9ed-2ff1c4f35faa": "events_list", + } + __event_validation__ = {"9fa01bef-c0e8-4fe1-b9ed-2ff1c4f35faa": None} + + @classmethod + def events_list( + cls, + list_options: ListOptions, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + list_options.page = 1 + list_options.size = 10000 + Events.filter_attr = list_options + if isinstance(token_dict, OccupantTokenObject): + occupant_events = Event2Occupant.filter_all( + Event2Occupant.build_living_space_id + == token_dict.selected_occupant.living_space_id + ).data + records = Events.filter_all( + Events.id.in_([event.event_id for event in occupant_events]) + ) + return AlchemyJsonResponse( + completed=True, + message="Events are listed successfully", + result=records, + ) + elif isinstance(token_dict, EmployeeTokenObject): + employee_events = Event2Employee.filter_all( + Event2Employee.employee_id == token_dict.selected_company.employee_id + ).data + records = Events.filter_all( + Events.id.in_([event.event_id for event in employee_events]) + ) + return AlchemyJsonResponse( + completed=True, + message="Events are listed successfully", + result=records, + ) + return AlchemyJsonResponse( + completed=False, + message="Events are NOT listed successfully", + result=[], + ) + + +class EventsBindEventToOccupantMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "d9aa58aa-37f7-4c27-861d-3105f76f5cdc": "bind_events_employee", + } + __event_validation__ = { + "d9aa58aa-37f7-4c27-861d-3105f76f5cdc": RegisterEvents2Employee + } + + @classmethod + def bind_events_employee(cls, data: RegisterEvents2Employee, token_dict): + events = Events.filter_all( + Events.uu_id.in_(data.event_id), + ).data + if not events: + raise HTTPException( + status_code=401, + detail="No event found. Please contact your super user.", + ) + employee_is_not_valid = False + employee = Employees.filter_one( + Employees.employee_uu_id == data.employee_uu_id, + ).data + if employee: + staff = Staff.filter_one( + Staff.id == employee.staff_id, + ).data + duties = Duties.filter_one( + Duties.id == staff.duties_id, + ).data + if duties.company_id not in token_dict.companies_id_list: + employee_is_not_valid = True + + if employee_is_not_valid: + raise HTTPException( + status_code=401, + detail="This employee can not be reached by this user. Please contact your super user.", + ) + + for event in events: + employee = Event2Employee.find_or_create( + **token_dict.user_creds, employee_id=employee.id, event_id=event.id + ) + Events.save() + return { + "status": "success", + "message": "Events registered successfully.", + "events": [event.uu_id for event in events.data], + } + + +class EventsBindEventToEmployeeMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "8bb4f4fc-b474-427e-90b3-d8681f308bb5": "bind_events_occupant", + } + __event_validation__ = { + "8bb4f4fc-b474-427e-90b3-d8681f308bb5": RegisterEvents2Occupant + } + + @classmethod + def bind_events_occupant(cls, data: RegisterEvents2Occupant, token_dict): + events = Events.filter_all( + Events.uu_id.in_(data.event_id), + ).data + if not events: + raise HTTPException( + status_code=401, + detail="No event found. Please contact your super user.", + ) + occupant = BuildLivingSpace.filter_one( + BuildLivingSpace.uu_id == data.build_living_space_uu_id, + ).data + if not occupant: + raise HTTPException( + status_code=401, + detail="This occupant can not be reached by this user. Please contact your super user.", + ) + for event in events: + occupant = Event2Occupant.find_or_create( + **token_dict.user_creds, + build_living_space_id=occupant.id, + event_id=event.id, + ) + Events.save() + return { + "status": "success", + "message": "Events registered successfully.", + "events": [event.uu_id for event in events.data], + } + + +EventsBindEventToOccupantMethod = EventsBindEventToOccupantMethods( + action=ActionsSchema(endpoint="/bind/events/occupant") +) +EventsBindEventToEmployeeMethod = EventsBindEventToEmployeeMethods( + action=ActionsSchema(endpoint="/bind/events/employee") +) +EventsListEventMethod = EventsListEventMethods( + action=ActionsSchema(endpoint="/event/list") +) + +# EventsCreateEventMethod = EventsCreateEventMethods( +# action=ActionsSchema(endpoint="/event/create") +# ) +# EventsUpdateEventMethod = EventsUpdateEventMethods( +# action=ActionsSchema(endpoint="/event/update") +# ) +# EventsPatchEventMethod = EventsPatchEventMethods( +# action=ActionsSchema(endpoint="/event/patch") +# ) +# + +# class EventsCreateEventMethods(MethodToEvent): +# +# event_type = "CREATE" +# __event_keys__ = { +# "514a9f8f-e5e5-4e10-9d0b-2de8f461fc1b": "events_create", +# } +# +# @classmethod +# def events_create(cls, data: CreateEvents, token_dict): +# event = Events.find_or_create( +# **token_dict.user_creds, +# event_name=data.event_name, +# event_description=data.event_description, +# event_date=data.event_date, +# event_location=data.event_location, +# active=True, +# deleted=False, +# ) +# Events.save() +# return { +# "status": "success", +# "message": "Event created successfully.", +# "event": event.uu_id, +# } +# class EventsUpdateEventMethods(MethodToEvent): +# +# event_type = "UPDATE" +# __event_keys__ = { +# "f94e7b79-2369-4840-bf2b-244934ca3136": "events_update", +# } +# +# @classmethod +# def events_update(cls, data: CreateEvents, token_dict): +# event = Events.filter_by_one(uu_id=data.uu_id, **Events.valid_record_dict).data +# if not event: +# raise HTTPException( +# status_code=404, +# detail="No event found. Please contact your responsible company.", +# ) +# event.update( +# **token_dict.user_creds, +# event_name=data.event_name, +# event_description=data.event_description, +# event_date=data.event_date, +# event_location=data.event_location, +# ) +# Events.save() +# return { +# "status": "success", +# "message": "Event updated successfully.", +# "event": event.uu_id, +# } +# +# +# class EventsPatchEventMethods(MethodToEvent): +# +# event_type = "PATCH" +# __event_keys__ = { +# "41944c63-22d3-4866-affd-34bcd49da58b": "events_patch", +# } +# +# @classmethod +# def events_patch(cls, data: CreateEvents, token_dict): +# event = Events.filter_by_one(uu_id=data.uu_id, **Events.valid_record_dict).data +# if not event: +# raise HTTPException( +# status_code=404, +# detail="No event found. Please contact your responsible company.", +# ) +# event.update( +# **token_dict.user_creds, +# event_name=data.event_name, +# event_description=data.event_description, +# event_date=data.event_date, +# event_location=data.event_location, +# ) +# return { +# "status": "success", +# "message": "Event patched successfully.", +# "event": event.uu_id, +# } diff --git a/api_events/events/events/events_models.py b/api_events/events/events/events_models.py new file mode 100644 index 0000000..595d9b1 --- /dev/null +++ b/api_events/events/events/events_models.py @@ -0,0 +1,28 @@ +from api_validations.validations_request import ( + DepartmentsPydantic, + PatchRecord, + 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 AlchemyJsonResponse + + +class ModelEvents(MethodToEvent): + + @classmethod + def model_list(cls, list_options: ListOptions, token_dict): + return + + @classmethod + def model_create(cls, data: DepartmentsPydantic, token_dict): + return + + @classmethod + def model_update(cls, company_uu_id: str, data: DepartmentsPydantic, token_dict): + return + + @classmethod + def model_patch(cls, company_uu_id: str, data: PatchRecord, token_dict): + return diff --git a/api_events/events/events/events_modules.py b/api_events/events/events/events_modules.py new file mode 100644 index 0000000..62f3114 --- /dev/null +++ b/api_events/events/events/events_modules.py @@ -0,0 +1,24 @@ +from api_validations.validations_request import DepartmentsPydantic, PatchRecord + +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 + + +class ModulesEvents(MethodToEvent): + + @classmethod + def modules_list(cls, request, list_options): + return + + @classmethod + def modules_create(cls, data: DepartmentsPydantic, token_dict): + return + + @classmethod + def modules_update(cls, module_uu_id: str, data: DepartmentsPydantic, token_dict): + return + + @classmethod + def modules_patch(cls, module_uu_id: str, data: PatchRecord, token_dict): + return diff --git a/api_events/events/events/events_services.py b/api_events/events/events/events_services.py new file mode 100644 index 0000000..dfd3174 --- /dev/null +++ b/api_events/events/events/events_services.py @@ -0,0 +1,64 @@ +from typing import Union + +from api_validations.validations_request import ( + DepartmentsPydantic, + PatchRecord, + 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 AlchemyJsonResponse + + +class ServicesEvents(MethodToEvent): + + @classmethod + def services_list( + cls, + list_options: ListOptions, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + return + + @classmethod + def services_create( + cls, + data: DepartmentsPydantic, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + return + + @classmethod + def services_update( + cls, + service_uu_id: str, + data: DepartmentsPydantic, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + return + + @classmethod + def services_patch( + cls, + service_uu_id: str, + data: PatchRecord, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + return + + @classmethod + def bind_service_to_action( + cls, data, token_dict: Union[EmployeeTokenObject, OccupantTokenObject] + ): + return + + @classmethod + def bind_module_to_service( + cls, data, token_dict: Union[EmployeeTokenObject, OccupantTokenObject] + ): + return + + @classmethod + def bind_events_patch(cls, company_uu_id: str, data: PatchRecord): + return diff --git a/api_events/events/identity/__init__.py b/api_events/events/identity/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_events/events/identity/people.py b/api_events/events/identity/people.py new file mode 100644 index 0000000..cb2c2f3 --- /dev/null +++ b/api_events/events/identity/people.py @@ -0,0 +1,219 @@ +from typing import Union + +from fastapi import status +from fastapi.responses import JSONResponse + +from api_validations.validations_response.people import PeopleListResponse +from databases import ( + Build, + People, + Users, + Companies, +) + +from api_validations.validations_request import InsertPerson, UpdateUsers +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 + + +class PeopleListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "0a05f03c-6ed8-4230-a4ff-6e7cf886909b": "super_users_people_list", + "b5612538-0445-4a4a-ab13-d2a06037f7a5": "sales_users_people_list", + "25cbbaf8-117a-470f-a844-2cfc70f71dde": "human_resources_users_people_list", + "cdf62f06-ec50-40de-b19e-adb3dd34bb95": "people_list_only_occupant_tenant_or_owner", + } + __event_validation__ = { + "0a05f03c-6ed8-4230-a4ff-6e7cf886909b": PeopleListResponse, + "b5612538-0445-4a4a-ab13-d2a06037f7a5": None, + "25cbbaf8-117a-470f-a844-2cfc70f71dde": None, + "cdf62f06-ec50-40de-b19e-adb3dd34bb95": None, + } + + @classmethod + def super_users_people_list( + cls, list_options, token_dict: Union[EmployeeTokenObject, OccupantTokenObject] + ): + records = [] + if isinstance(token_dict, EmployeeTokenObject): + People.pre_query = People.select_action( + duty_id_list=[ + token_dict.selected_company.duty_id, + token_dict.selected_company.bulk_duties_id, + ], + ) + People.filter_attr = list_options + records = People.filter_all() + elif isinstance(token_dict, OccupantTokenObject): + related_users = Users.filter_all( + Users.related_company + == token_dict.selected_occupant.responsible_company_id, + ).data + People.pre_query = People.filter_all( + People.id.in_([user.person_id for user in related_users]), + ).query + People.filter_attr = list_options + records = People.filter_all() + return AlchemyJsonResponse( + completed=True, + message="People are listed successfully", + result=records, + cls_object=People, + filter_attributes=list_options, + response_model=PeopleListResponse, + ) + + @classmethod + def sales_users_people_list( + cls, + list_options, + token_dict: EmployeeTokenObject, + ): + People.filter_attr = list_options + records = People.filter_all().data + return AlchemyJsonResponse( + completed=True, + message="People are listed successfully", + result=records, + ) + + @classmethod + def human_resources_users_people_list( + cls, + list_options, + token_dict: EmployeeTokenObject, + ): + if isinstance(token_dict, EmployeeTokenObject): + People.filter_attr = list_options + records = People.filter_all().data + return AlchemyJsonResponse( + completed=True, + message="People are listed successfully", + result=records, + ) + + +class PeopleCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "2d1513f4-44ed-4fa3-84d1-dfbd0eadf9a1": "people_create", + } + __event_validation__ = { + "2d1513f4-44ed-4fa3-84d1-dfbd0eadf9a1": InsertPerson, + } + + @classmethod + def people_create( + cls, + data: InsertPerson, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, EmployeeTokenObject): + created_user = People.create_action(data=data, token=token_dict) + People.save() + elif isinstance(token_dict, OccupantTokenObject): + created_user = People.create_action(data=data, token=token_dict) + People.save() + return JSONResponse( + content={ + "completed": True, + "message": "Create User record", + "data": created_user.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + + +class PeopleUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "e05cf22c-16c4-450b-86c8-417896a26afc": "people_update", + } + __event_validation__ = {"e05cf22c-16c4-450b-86c8-417896a26afc": UpdateUsers} + + @classmethod + def people_update( + cls, + data: UpdateUsers, + user_uu_id: str, + token_dict: Union[EmployeeTokenObject, OccupantTokenObject], + ): + data_dict = data.excluded_dump() + if isinstance(token_dict, EmployeeTokenObject): + find_one_user = Users.filter_one( + Users.uu_id == user_uu_id, + ).data + access_authorized_company = Companies.select_action( + duty_id_list=[ + token_dict.selected_company.duty_id, + token_dict.selected_company.bulk_duties_id, + ], + ) + if access_authorized_company.count: + updated_user = find_one_user.update(**data_dict) + Users.save() + return JSONResponse( + content={ + "completed": True, + "message": "Update User record", + "data": updated_user, + }, + status_code=status.HTTP_200_OK, + ) + elif isinstance(token_dict, OccupantTokenObject): + find_one_user = People.filter_one( + People.uu_id == user_uu_id, + ).data + access_authorized_company = Companies.select_action( + duty_id_list=[getattr(token_dict, "duty_id")], + filter_expr=[Companies.id == find_one_user.id], + ) + if access_authorized_company.count: + data_dict = data.excluded_dump() + updated_user = find_one_user.update(**data_dict) + People.save() + return JSONResponse( + content={"completed": True, "message": "Update User record", "data": {}}, + status_code=status.HTTP_200_OK, + ) + + +class PeoplePatchEventMethods(MethodToEvent): + + event_type = "PATCH" + __event_keys__ = { + "3ae16d66-090b-4d27-b567-cce1b10a1c3b": "people_patch", + } + __event_validation__ = {"3ae16d66-090b-4d27-b567-cce1b10a1c3b": None} + + @classmethod + def people_patch(cls): + return + + +class PeopleDeleteEventMethods(MethodToEvent): + + event_type = "DELETE" + __event_keys__ = { + "7f84c7a2-a120-4867-90d4-6767a41320db": "people_delete", + } + __event_validation__ = {"7f84c7a2-a120-4867-90d4-6767a41320db": None} + + +PeopleListEventMethod = PeopleListEventMethods( + action=ActionsSchema(endpoint="/people/list") +) +PeopleCreateEventMethod = PeopleCreateEventMethods( + action=ActionsSchema(endpoint="/people/create") +) +PeopleUpdateEventMethod = PeopleUpdateEventMethods( + action=ActionsSchema(endpoint="/people/update") +) +PeoplePatchEventMethod = PeoplePatchEventMethods( + action=ActionsSchema(endpoint="/people/patch") +) diff --git a/api_events/events/identity/users.py b/api_events/events/identity/users.py new file mode 100644 index 0000000..7f8c15b --- /dev/null +++ b/api_events/events/identity/users.py @@ -0,0 +1,217 @@ +import typing + +from fastapi import status +from fastapi.responses import JSONResponse + +from api_configs import ApiStatic +from databases import MongoQueryIdentity, Users, Companies, People +from databases.no_sql_models.validations import DomainViaUser + +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_services.email.service import send_email +from api_services.templates.password_templates import change_your_password_template +from api_validations.validations_request import ( + InsertUsers, + UpdateUsers, + PatchRecord, + ListOptions, + RegisterServices2Occupant, +) + + +class UserListEventMethods(MethodToEvent): + + event_type = "SELECT" + __event_keys__ = { + "1483a8a2-d244-4593-b9f8-f1b4bcbefcd5": "user_list", + } + __event_validation__ = {"1483a8a2-d244-4593-b9f8-f1b4bcbefcd5": None} + + @classmethod + def user_list( + cls, + list_options: ListOptions, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + if isinstance(token_dict, OccupantTokenObject): + raise Users.raise_http_exception( + status_code="HTTP_403_FORBIDDEN", + message="Occupant object can not list users", + error_case="NOTAUTHORIZED", + data={}, + ) + if "user_uu_id_list" in list_options.query: + people_ids = list_options.query.pop("user_uu_id_list") + people_id_list = ( + user.person_id + for user in Users.filter_all(Users.uu_id.in_(people_ids)).data + ) + Users.filter_attr = list_options + records = Users.filter_all( + Users.person_id.in_(people_id_list), + ) + return AlchemyJsonResponse( + completed=True, + message="Users are listed successfully", + result=records, + ) + Users.filter_attr = list_options + records = Users.filter_all() + return AlchemyJsonResponse( + completed=True, + message="Users are listed successfully", + result=records, + ) + + +class UserCreateEventMethods(MethodToEvent): + + event_type = "CREATE" + __event_keys__ = { + "8eb50c24-4bdc-4309-9836-f7048daee409": "user_create", + } + __event_validation__ = {"8eb50c24-4bdc-4309-9836-f7048daee409": InsertUsers} + + @classmethod + def user_create( + cls, + data: InsertUsers, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + created_user = Users.create_action(create_user=data, token_dict=token_dict) + domain_via_user = DomainViaUser( + **{"user_uu_id": str(created_user.uu_id), "main_domain": "evyos.com.tr"} + ) + created_user.save_and_confirm() + mongo_query_identity = MongoQueryIdentity( + company_uuid=created_user.related_company, + ) + mongo_query_identity.create_domain_via_user(payload=domain_via_user) + reset_password_token = created_user.reset_password_token( + found_user=created_user + ) + send_email_completed = send_email( + subject=f"Dear {created_user.user_tag}, your password has been changed.", + receivers=[str(created_user.email)], + html=change_your_password_template( + user_name=created_user.user_tag, + forgot_link=ApiStatic.forgot_link(forgot_key=reset_password_token), + ), + ) + if not send_email_completed: + raise created_user.raise_http_exception( + status_code=400, message="Email can not be sent. Try again later" + ) + return JSONResponse( + content={ + "completed": True, + "message": "Create User record", + "data": created_user.get_dict(), + "password_token": { + "password_token": created_user.password_token, + "password_expires_day": str(created_user.password_expires_day), + "password_expiry_begins": str(created_user.password_expiry_begins), + "hash_password": created_user.hash_password, + "related_company": created_user.related_company, + }, + }, + status_code=status.HTTP_200_OK, + ) + + +class UserUpdateEventMethods(MethodToEvent): + + event_type = "UPDATE" + __event_keys__ = { + "d08a9470-1eb0-4890-a9e8-b6686239d7e9": "user_update", + } + __event_validation__ = {"d08a9470-1eb0-4890-a9e8-b6686239d7e9": UpdateUsers} + + @classmethod + def user_update( + cls, + data: UpdateUsers, + user_uu_id: str, + token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject], + ): + find_one_user = Users.filter_one( + Users.uu_id == user_uu_id, + *Users.valid_record_args(Users), + ).data + access_authorized_company = Companies.select_action( + duty_id_list=[getattr(token_dict, "duty_id", 5)], + filter_expr=[Companies.id == token_dict.get("")], + ) + if access_authorized_company.count: + data_dict = data.excluded_dump() + updated_user = find_one_user.update(**data_dict) + Users.save() + return JSONResponse( + content={ + "completed": True, + "message": "Update User record", + "data": updated_user, + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={"completed": True, "message": "Update User record", "data": {}}, + status_code=status.HTTP_200_OK, + ) + + +class UserPatchEventMethods(MethodToEvent): + + event_type = "PATCH" + __event_keys__ = { + "d26a1a3c-eaeb-4d01-b35b-a5ed714e29c0": "user_patch", + } + __event_validation__ = {"d26a1a3c-eaeb-4d01-b35b-a5ed714e29c0": None} + + @classmethod + def user_patch(cls, data: PatchRecord, user_uu_id: str, token_dict): + find_one_user = Users.filter_one( + Users.uu_id == user_uu_id, + ).data + access_authorized_company = Companies.select_action( + duty_id_list=[getattr(token_dict, "duty_id", 5)], + filter_expr=[Companies.id == find_one_user.id], + ) + if access_authorized_company.count: + action = data.excluded_dump() + find_one_user.active = bool(action.get("active", find_one_user.active)) + find_one_user.is_confirmed = bool( + action.get("confirm", find_one_user.is_confirmed) + ) + find_one_user.deleted = bool(action.get("delete", find_one_user.deleted)) + find_one_user.save() + return JSONResponse( + content={ + "completed": True, + "message": "Patch User record completed", + "data": find_one_user.get_dict(), + }, + status_code=status.HTTP_200_OK, + ) + return JSONResponse( + content={ + "completed": False, + "message": "Patch User record failed", + "data": {}, + }, + status_code=status.HTTP_200_OK, + ) + + +UserListEventMethod = UserListEventMethods(action=ActionsSchema(endpoint="/user/list")) +UserCreateEventMethod = UserCreateEventMethods( + action=ActionsSchema(endpoint="/user/create") +) +UserUpdateEventMethod = UserUpdateEventMethods( + action=ActionsSchema(endpoint="/user/update") +) +UserPatchEventMethod = UserPatchEventMethods( + action=ActionsSchema(endpoint="/user/patch") +) diff --git a/api_events/tasks2events/__init__.py b/api_events/tasks2events/__init__.py new file mode 100644 index 0000000..c6f44bb --- /dev/null +++ b/api_events/tasks2events/__init__.py @@ -0,0 +1,49 @@ +from api_events.tasks2events.common_tasks.default_user import AuthDefaultEventBlock +from api_events.tasks2events.employee_tasks.super_user import SuperUserEventBlock + +from api_events.tasks2events.occupant_tasks.build_manager import BuildManager +from api_events.tasks2events.occupant_tasks.build_owner import BuildOwner +from api_events.tasks2events.occupant_tasks.build_resident import BuildResident +from api_events.tasks2events.occupant_tasks.build_tenant import BuildTenant +from api_events.tasks2events.occupant_tasks.build_represent import BuildRepresent +from api_events.tasks2events.occupant_tasks.meeting_writer import BuildMeetingWriter +from api_events.tasks2events.occupant_tasks.meeting_advisor import BuildMeetingAdvisor +from api_events.tasks2events.occupant_tasks.meeting_attendance import ( + BuildMeetingAttendance, +) +from api_events.tasks2events.occupant_tasks.meeting_president import ( + BuildMeetingPresident, +) +from api_events.tasks2events.occupant_tasks.meeting_voted_president import ( + BuildMeetingVotedPresident, +) +from api_events.tasks2events.occupant_tasks.project_leader import ProjectLeader +from api_events.tasks2events.occupant_tasks.project_finance import ( + ProjectFinanceResponsible, +) +from api_events.tasks2events.occupant_tasks.project_employee import ProjectEmployee +from api_events.tasks2events.occupant_tasks.project_technical import ProjectTechnical +from api_events.tasks2events.occupant_tasks.project_responsiable import ( + ProjectResponsible, +) + + +__all__ = [ + "AuthDefaultEventBlock", + "SuperUserEventBlock", + "BuildManager", + "BuildOwner", + "BuildResident", + "BuildTenant", + "BuildRepresent", + "BuildMeetingWriter", + "BuildMeetingPresident", + "BuildMeetingAdvisor", + "BuildMeetingAttendance", + "BuildMeetingVotedPresident", + "ProjectLeader", + "ProjectFinanceResponsible", + "ProjectEmployee", + "ProjectTechnical", + "ProjectResponsible", +] diff --git a/api_events/tasks2events/common_tasks/__init__.py b/api_events/tasks2events/common_tasks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_events/tasks2events/common_tasks/default_user.py b/api_events/tasks2events/common_tasks/default_user.py new file mode 100644 index 0000000..6a1c5eb --- /dev/null +++ b/api_events/tasks2events/common_tasks/default_user.py @@ -0,0 +1,22 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class AuthDefaultEventBlock(AddEventFunctionality): + service_code = "AUTH" + related_code = "DF-USER" + events = [ + {"function_code": "e672846d-cc45-4d97-85d5-6f96747fac67"}, + {"function_code": "cee96b9b-8487-4e9f-aaed-2e8c79687bf9"}, + {"function_code": "48379bb2-ba81-4d8e-a9dd-58837cfcbf67"}, + {"function_code": "f09f7c1a-bee6-4e32-8444-962ec8f39091"}, + {"function_code": "c519f9af-92e1-47b2-abf7-5a3316d075f7"}, + {"function_code": "8b586848-2fb3-4161-abbe-642157eec7ce"}, + {"function_code": "5cc22e4e-a0f7-4077-be41-1871feb3dfd1"}, + {"function_code": "c90f3334-10c9-4181-b5ff-90d98a0287b2"}, + {"function_code": "e3ca6e24-b9f8-4127-949c-3bfa364e3513"}, + {"function_code": "c140cd5f-307f-4046-a93e-3ade032a57a7"}, + {"function_code": "af9e121e-24bb-44ac-a616-471d5754360e"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/default_abstract.py b/api_events/tasks2events/default_abstract.py new file mode 100644 index 0000000..5985085 --- /dev/null +++ b/api_events/tasks2events/default_abstract.py @@ -0,0 +1,14 @@ +class AddEventFunctionality: + + @classmethod + def retrieve_events(cls, events) -> list[tuple[int, str]]: + from databases import Events + + get_event_ids = Events.filter_all( + Events.function_code.in_([event["function_code"] for event in events]), + system=True, + ).data + if get_event_ids: + return [(get_event.id, str(get_event.uu_id)) for get_event in get_event_ids] + else: + raise Exception("No event found") diff --git a/api_events/tasks2events/employee_tasks/__init__.py b/api_events/tasks2events/employee_tasks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_events/tasks2events/employee_tasks/super_user.py b/api_events/tasks2events/employee_tasks/super_user.py new file mode 100644 index 0000000..d709757 --- /dev/null +++ b/api_events/tasks2events/employee_tasks/super_user.py @@ -0,0 +1,89 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class SuperUserEventBlock(AddEventFunctionality): + service_code = "SRE-SUE" + related_code = "SUE" + events = [ + {"function_code": "2d1513f4-44ed-4fa3-84d1-dfbd0eadf9a1"}, + {"function_code": "0a05f03c-6ed8-4230-a4ff-6e7cf886909b"}, + {"function_code": "e05cf22c-16c4-450b-86c8-417896a26afc"}, + {"function_code": "3ae16d66-090b-4d27-b567-cce1b10a1c3b"}, + {"function_code": "1483a8a2-d244-4593-b9f8-f1b4bcbefcd5"}, + {"function_code": "8eb50c24-4bdc-4309-9836-f7048daee409"}, + {"function_code": "d08a9470-1eb0-4890-a9e8-b6686239d7e9"}, + {"function_code": "d26a1a3c-eaeb-4d01-b35b-a5ed714e29c0"}, + {"function_code": "68b3b5ed-b74c-4a27-820f-3959214e94e9"}, + {"function_code": "a2271854-6b90-43da-a440-a62b70d90528"}, + {"function_code": "5ad38a66-1189-451e-babb-77de2d63d757"}, + {"function_code": "e3876bfe-8847-4dea-ae36-e709f7431930"}, + {"function_code": "6320d696-1fd1-49f9-860a-8f22e5b8a68d"}, + {"function_code": "76f11a08-5f4a-4e1f-961f-aaef21699acd"}, + {"function_code": "41ea7f29-006a-4310-b5c4-b2a0e1a504bd"}, + {"function_code": "f6900cb5-ac5b-478e-8e7c-fa87e65cd2e5"}, + {"function_code": "2cb90331-c1b4-4923-8314-8111326b621a"}, + {"function_code": "d8bd3985-7f3b-4267-a74e-d5017e4ea9f8"}, + {"function_code": "4172706f-06c9-4c38-9ac8-59085a72f80a"}, + {"function_code": "1e272e4f-6c1e-418b-91a7-be8b06c875da"}, + {"function_code": "44b72beb-53a8-407b-a12a-76e74b65794d"}, + {"function_code": "30c54cce-3303-4d36-959a-b64e383ae177"}, + {"function_code": "3524ae42-0825-4af7-be85-7c890a4f65d3"}, + {"function_code": "3fc77829-f1ee-4511-a2ca-582daa03125b"}, + {"function_code": "ca81c6d1-975a-4288-a27b-1069aea84afe"}, + {"function_code": "23231c7d-4ff2-4b39-b71b-ea350d31fadf"}, + {"function_code": "c6ea200e-fa17-4393-b390-37f5337c9c65"}, + {"function_code": "ad952647-bcf8-482d-9e05-b2ee8086483f"}, + {"function_code": "d5c7b5c4-7b4e-4d5b-8e3b-2b9c5f5d0c0b"}, + {"function_code": "cb677c92-6b05-4122-af5c-12766fae8095"}, + {"function_code": "1e1632c3-bb0e-46a5-8e45-da3f6d88ac43"}, + {"function_code": "9015a076-d78c-463d-9474-ea343a125fb8"}, + {"function_code": "8446ce0b-9310-4b9f-93e2-61f56a9dacd1"}, + {"function_code": "8984a519-99bf-4f25-8f34-2e1aebba468c"}, + {"function_code": "8f619257-19fd-404f-b713-7392c588dc36"}, + {"function_code": "7724cfbb-c0ee-4261-959b-61b84e88a34f"}, + {"function_code": "5329f35d-ff9d-4656-a831-ba9c8204e483"}, + {"function_code": "b1cd7c0a-1458-472b-894f-3adc857c8512"}, + {"function_code": "5eb04057-7a74-4555-b2c6-14eda32dae89"}, + {"function_code": "caf914fa-0899-4b0b-a85a-3d40fdaa06a5"}, + {"function_code": "ffdc445f-da10-4ce4-9531-d2bdb9a198ae"}, + {"function_code": "b0e55a7e-af81-468c-b46c-a6b3a6b68d5d"}, + {"function_code": "1f9c3a9c-e5bd-4dcd-9b9a-3742d7e03a27"}, + {"function_code": "9c251d7d-da70-4d63-a72c-e69c26270442"}, + {"function_code": "6f1406ac-577d-4f2c-8077-71fff2252c5f"}, + {"function_code": "88d37b78-1ac4-4513-9d25-090ac3a24f31"}, + {"function_code": "df18e489-a63c-477f-984c-aa52d30640ad"}, + {"function_code": "e0ac1269-e9a7-4806-9962-219ac224b0d0"}, + {"function_code": "b860e37a-e19b-4c45-9543-461241f7587c"}, + {"function_code": "fb403f69-11ed-4f4f-ad71-5e6fb4a793d2"}, + {"function_code": "58fdf95e-2110-4ed6-9c26-95f4be87eaee"}, + {"function_code": "70b4666f-4ceb-46ec-b89e-24be8712f0e7"}, + {"function_code": "8fd04d94-68fb-4a07-9549-8b47aee3a870"}, + {"function_code": "b78ca45c-b9f4-41f6-9ddb-2c6f2faa2570"}, + {"function_code": "5c10d6ae-2aee-4243-a7c3-94826d028d13"}, + {"function_code": "0a68cb44-271a-4829-81f6-cd99a5f326b4"}, + {"function_code": "6bc7035c-3b53-4c0a-8cc9-1ec9c6af1e29"}, + {"function_code": "7b58ed84-9a65-4588-994d-30df8366b050"}, + {"function_code": "eb36de59-8268-4d96-80b6-5d01c12bf0b1"}, + {"function_code": "dce10509-0da5-46fb-af3c-a81d54d5481c"}, + {"function_code": "f0fdfe1b-806b-4175-ad50-a1a165c0dfb7"}, + {"function_code": "42328809-b516-477b-82cc-2d6fadf28843"}, + {"function_code": "5702f0a9-fe8f-4aae-922e-6e04b497ef6a"}, + {"function_code": "c93a3009-65a0-498d-9191-04484d5cde81"}, + {"function_code": "6798414c-6c7d-47f0-9d8b-6935a0f51c2e"}, + {"function_code": "57edc8bf-8f29-4e75-b5e1-9ca0139a3fda"}, + {"function_code": "b18e8e37-a62b-4a84-9972-ba17121ed393"}, + {"function_code": "0bb51845-65a2-4340-8872-a3b5aad95468"}, + {"function_code": "a10571fa-ac1d-4546-9272-cacb911d8004"}, + {"function_code": "58178738-7489-4f8f-954e-5c8f083c1845"}, + {"function_code": "36961d8a-cefa-46cc-9f7c-9d841d6351b6"}, + {"function_code": "46d90119-3b23-4784-8053-fe11da4a3584"}, + {"function_code": "c786e15c-c03e-4e8f-936c-7e5e5ec9bbcc"}, + {"function_code": "5344d03c-fc47-43ec-8c44-6c2acd7e5d9f"}, + {"function_code": "31f4f32f-0cd4-4995-8a6a-f9f56335848a"}, + {"function_code": "7192c2aa-5352-4e36-98b3-dafb7d036a3d"}, + {"function_code": "ec98ef2c-bcd0-432d-a8f4-1822a56c33b2"}, + {"function_code": "34c38937-42a2-45f1-b2ef-a23978650aee"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/__init__.py b/api_events/tasks2events/occupant_tasks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_events/tasks2events/occupant_tasks/asd.py b/api_events/tasks2events/occupant_tasks/asd.py new file mode 100644 index 0000000..79bb9b1 --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/asd.py @@ -0,0 +1,37 @@ +""" + +Toplantı Başkanı Toplantı Başkanı MT-PRS Toplantı +Toplantı Katip Toplantıda tutanak tutan kişi MT-WRT Toplantı +Toplantı Katılımcısı Toplantıda sadece katılan kişi MT-ATT Toplantı +Toplantı Danışman Toplantıda danışmanlık yapan kişi MT-ADV Toplantı +Daire Sahibi Daire Sahibi FL-OWN Daire +Daire Kiracısı Daire Kiracısı FL-TEN Daire +Daire Sakini Daire Sakini FL-RES Daire +Daire Sakini Vekili Daire Sakini Vekili FL-REP Daire +Bina Avukatı Bina Avukatı BU-ATT Bina +Bina Avukatı Yardımcısı Bina Avukatı Yardımcısı BU-ATA Bina +Bina Denetmen Yardımcısı Bina Denetmen Yardımcısı BU-SPA Bina +Bina Denetmeni Bina Denetmeni BU-SPV Bina +Bina Yönetici Yardımcısı Bina Yönetici Yardımcısı BU-MNA Bina +Bina Yöneticisi Bina Yöneticisi BU-MNG Bina +Bina Muhasabecisi Bina Muhasabecisi BU-ACC Bina + + +""" + +MT_PRS = [] +MT_WRT = [] +MT_ATT = [] +MT_ADV = [] +FL_OWN = [] +FL_TEN = [] +FL_RES = [] +FL_REP = [] +BU_ATT = [] +BU_ATA = [] +BU_SPA = [] +BU_SPV = [] +BU_MNA = [] + + +BU_ACC = [] diff --git a/api_events/tasks2events/occupant_tasks/build_manager.py b/api_events/tasks2events/occupant_tasks/build_manager.py new file mode 100644 index 0000000..7d638ab --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/build_manager.py @@ -0,0 +1,21 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class BuildManager(AddEventFunctionality): + service_code = "SRO-BU-MNG" + related_code = "BU-MNG" + events = [ + {"function_code": "dce10509-0da5-46fb-af3c-a81d54d5481c"}, + {"function_code": "0d2bc5c9-d4b1-4951-8305-69da4a687fdc"}, + {"function_code": "0a68cb44-271a-4829-81f6-cd99a5f326b4"}, + {"function_code": "5c10d6ae-2aee-4243-a7c3-94826d028d13"}, + {"function_code": "d0bfa20c-841d-421c-98e6-d308f938d16a"}, + {"function_code": "68b3b5ed-b74c-4a27-820f-3959214e94e9"}, + {"function_code": "f6900cb5-ac5b-478e-8e7c-fa87e65cd2e5"}, + {"function_code": "92413636-53a8-4a05-842c-1485a64e00d1"}, + {"function_code": "bdcba521-0116-441c-ace1-84c5b68c86c7"}, + {"function_code": "c0b65098-9c79-4212-b1d0-c7e7836cf141"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/build_owner.py b/api_events/tasks2events/occupant_tasks/build_owner.py new file mode 100644 index 0000000..e23ba44 --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/build_owner.py @@ -0,0 +1,13 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class BuildOwner(AddEventFunctionality): + + service_code = "SRO-FL-OWN" + related_code = "FL-OWN" + events = [ + {"function_code": "bdcba521-0116-441c-ace1-84c5b68c86c7"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/build_represent.py b/api_events/tasks2events/occupant_tasks/build_represent.py new file mode 100644 index 0000000..9072f77 --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/build_represent.py @@ -0,0 +1,13 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class BuildRepresent(AddEventFunctionality): + + service_code = "SRO-FL-REP" + related_code = "FL-REP" + events = [ + {"function_code": "bdcba521-0116-441c-ace1-84c5b68c86c7"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/build_resident.py b/api_events/tasks2events/occupant_tasks/build_resident.py new file mode 100644 index 0000000..ca711e2 --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/build_resident.py @@ -0,0 +1,13 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class BuildResident(AddEventFunctionality): + service_code = "SRO-FL-RES" + related_code = "FL-RES" + events = [ + {"function_code": "bdcba521-0116-441c-ace1-84c5b68c86c7"}, + {"function_code": "208e6273-17ef-44f0-814a-8098f816b63a"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/build_tenant.py b/api_events/tasks2events/occupant_tasks/build_tenant.py new file mode 100644 index 0000000..de948c6 --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/build_tenant.py @@ -0,0 +1,12 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class BuildTenant(AddEventFunctionality): + service_code = "SRO-FL-TEN" + related_code = "FL-TEN" + events = [ + {"function_code": "bdcba521-0116-441c-ace1-84c5b68c86c7"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/meeting_advisor.py b/api_events/tasks2events/occupant_tasks/meeting_advisor.py new file mode 100644 index 0000000..bda8318 --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/meeting_advisor.py @@ -0,0 +1,13 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class BuildMeetingAdvisor(AddEventFunctionality): + service_code = "SRO-MT-ADV" + related_code = "MT-ADV" + events = [ + {"function_code": "eb36de59-8268-4d96-80b6-5d01c12bf0b1"}, + {"function_code": "5c10d6ae-2aee-4243-a7c3-94826d028d13"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/meeting_attendance.py b/api_events/tasks2events/occupant_tasks/meeting_attendance.py new file mode 100644 index 0000000..d67ac5a --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/meeting_attendance.py @@ -0,0 +1,13 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class BuildMeetingAttendance(AddEventFunctionality): + service_code = "SRO-MT-ATT" + related_code = "MT-ATT" + events = [ + {"function_code": "eb36de59-8268-4d96-80b6-5d01c12bf0b1"}, + {"function_code": "5c10d6ae-2aee-4243-a7c3-94826d028d13"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/meeting_president.py b/api_events/tasks2events/occupant_tasks/meeting_president.py new file mode 100644 index 0000000..81d2379 --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/meeting_president.py @@ -0,0 +1,13 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class BuildMeetingPresident(AddEventFunctionality): + service_code = "SRO-MT-PRS" + related_code = "MT-PRS" + events = [ + {"function_code": "eb36de59-8268-4d96-80b6-5d01c12bf0b1"}, + {"function_code": "5c10d6ae-2aee-4243-a7c3-94826d028d13"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/meeting_voted_president.py b/api_events/tasks2events/occupant_tasks/meeting_voted_president.py new file mode 100644 index 0000000..c4a5e05 --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/meeting_voted_president.py @@ -0,0 +1,12 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class BuildMeetingVotedPresident(AddEventFunctionality): + service_code = "SRO-MT-VPR" + related_code = "MT-VPR" + events = [ + {"function_code": "eb36de59-8268-4d96-80b6-5d01c12bf0b1"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/meeting_writer.py b/api_events/tasks2events/occupant_tasks/meeting_writer.py new file mode 100644 index 0000000..3bc7810 --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/meeting_writer.py @@ -0,0 +1,14 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class BuildMeetingWriter(AddEventFunctionality): + service_code = "SRO-MT-WRT" + related_code = "MT-WRT" + events = [ + {"function_code": "dce10509-0da5-46fb-af3c-a81d54d5481c"}, + {"function_code": "eb36de59-8268-4d96-80b6-5d01c12bf0b1"}, + {"function_code": "5c10d6ae-2aee-4243-a7c3-94826d028d13"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/project_employee.py b/api_events/tasks2events/occupant_tasks/project_employee.py new file mode 100644 index 0000000..473074a --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/project_employee.py @@ -0,0 +1,15 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class ProjectEmployee(AddEventFunctionality): + service_code = "SRO-PRJ-EMP" + related_code = "PRJ-EMP" + events = [ + {"function_code": "7101b5ca-8bef-40f9-8b4d-646d9994e18f"}, + {"function_code": "96459b36-37f2-4d5b-8370-c459058d5bce"}, + {"function_code": "ce3630e4-2bf9-4433-bdab-1ee72117e54b"}, + {"function_code": "b27e4fd0-6e3e-441b-9b33-806ac7082444"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/project_finance.py b/api_events/tasks2events/occupant_tasks/project_finance.py new file mode 100644 index 0000000..4c2cdd7 --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/project_finance.py @@ -0,0 +1,15 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class ProjectFinanceResponsible(AddEventFunctionality): + service_code = "SRO-PRJ-FIN" + related_code = "PRJ-FIN" + events = [ + {"function_code": "96459b36-37f2-4d5b-8370-c459058d5bce"}, + {"function_code": "ce3630e4-2bf9-4433-bdab-1ee72117e54b"}, + {"function_code": "b27e4fd0-6e3e-441b-9b33-806ac7082444"}, + {"function_code": "7101b5ca-8bef-40f9-8b4d-646d9994e18f"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/project_leader.py b/api_events/tasks2events/occupant_tasks/project_leader.py new file mode 100644 index 0000000..0137b0b --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/project_leader.py @@ -0,0 +1,22 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class ProjectLeader(AddEventFunctionality): + + service_code = "SRO-PRJ-LDR" + related_code = "PRJ-LDR" + + events = [ + {"function_code": "b27e4fd0-6e3e-441b-9b33-806ac7082444"}, + {"function_code": "ce3630e4-2bf9-4433-bdab-1ee72117e54b"}, + {"function_code": "a83a83fe-8446-4c60-9ae5-d1c06adbf626"}, + {"function_code": "444d67a0-b3a8-4ca2-9d8d-f1acc75011e0"}, + {"function_code": "9c88e314-84e8-435e-8c1e-6a5aae80b2e6"}, + {"function_code": "7fbd18a0-c099-4494-ada1-bb23e39bb141"}, + {"function_code": "a122e84a-5556-4bf7-b680-1f47c438d4f7"}, + {"function_code": "7101b5ca-8bef-40f9-8b4d-646d9994e18f"}, + {"function_code": "96459b36-37f2-4d5b-8370-c459058d5bce"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/project_responsiable.py b/api_events/tasks2events/occupant_tasks/project_responsiable.py new file mode 100644 index 0000000..68b04e3 --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/project_responsiable.py @@ -0,0 +1,15 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class ProjectResponsible(AddEventFunctionality): + service_code = "SRO-PRJ-RES" + related_code = "PRJ-RES" + events = [ + {"function_code": "96459b36-37f2-4d5b-8370-c459058d5bce"}, + {"function_code": "ce3630e4-2bf9-4433-bdab-1ee72117e54b"}, + {"function_code": "b27e4fd0-6e3e-441b-9b33-806ac7082444"}, + {"function_code": "7101b5ca-8bef-40f9-8b4d-646d9994e18f"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_events/tasks2events/occupant_tasks/project_technical.py b/api_events/tasks2events/occupant_tasks/project_technical.py new file mode 100644 index 0000000..9ce70a3 --- /dev/null +++ b/api_events/tasks2events/occupant_tasks/project_technical.py @@ -0,0 +1,15 @@ +from api_events.tasks2events.default_abstract import AddEventFunctionality + + +class ProjectTechnical(AddEventFunctionality): + service_code = "SRO-PRJ-TEC" + related_code = "PRJ-TEC" + events = [ + {"function_code": "96459b36-37f2-4d5b-8370-c459058d5bce"}, + {"function_code": "ce3630e4-2bf9-4433-bdab-1ee72117e54b"}, + {"function_code": "b27e4fd0-6e3e-441b-9b33-806ac7082444"}, + {"function_code": "7101b5ca-8bef-40f9-8b4d-646d9994e18f"}, + ] + + def __new__(cls, *args, **kwargs): + return super().retrieve_events(cls.events) diff --git a/api_services/__init__.py b/api_services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_services/email/config.py b/api_services/email/config.py new file mode 100644 index 0000000..2a0d34d --- /dev/null +++ b/api_services/email/config.py @@ -0,0 +1,9 @@ +from redmail import EmailSender +from api_configs import EmailConfig + +email_sender = EmailSender( + host=EmailConfig.EMAIL_HOST, + port=587, + username=EmailConfig.EMAIL_USERNAME, + password=EmailConfig.EMAIL_PASSWORD, +) diff --git a/api_services/email/service.py b/api_services/email/service.py new file mode 100644 index 0000000..c807b68 --- /dev/null +++ b/api_services/email/service.py @@ -0,0 +1,32 @@ +from .config import email_sender + + +def send_email( + subject: str, + receivers: list, + text: str = "", + html: str = "", + cc: list = None, + bcc: list = None, + headers: dict = None, + attachments: dict = None, +) -> bool: + try: + email_sender.connect() + receivers = ["karatay@mehmetkaratay.com.tr"] + email_sender.send( + subject=subject, + receivers=receivers, + text=text + f" : Gonderilen [{str(receivers)}]", + html=html, + cc=cc, + bcc=bcc, + headers=headers or {}, + attachments=attachments or {}, + ) + return True + except Exception as e: + print(f"Error raised at email send :{e}") + finally: + email_sender.close() + return False diff --git a/api_services/redis/conn.py b/api_services/redis/conn.py new file mode 100644 index 0000000..0d863e8 --- /dev/null +++ b/api_services/redis/conn.py @@ -0,0 +1,31 @@ +from redis import Redis +from api_configs import WagRedis + + +class RedisConn: + + def __init__(self): + self.redis = Redis( + host=WagRedis.REDIS_HOST, + password=WagRedis.REDIS_PASSWORD, + port=WagRedis.REDIS_PORT, + db=WagRedis.REDIS_DB, + ) + if not self.check_connection(): + raise Exception("Connection error") + + def check_connection(self): + return self.redis.ping() + + def set_connection(self, host, password, port, db): + self.redis = Redis(host=host, password=password, port=port, db=db) + return self.redis + + +try: + redis_conn = RedisConn() + redis_cli = redis_conn.redis +except Exception as e: + print("Redis Connection Error", e) + + diff --git a/api_services/redis/functions.py b/api_services/redis/functions.py new file mode 100644 index 0000000..fc4d9fd --- /dev/null +++ b/api_services/redis/functions.py @@ -0,0 +1,240 @@ +import json + +from api_services.redis.conn import redis_cli + + +class RedisResponse: + def __init__(self, status: bool, message: str, data: dict = None, error: str = None): + self.status = status + self.message = message + self.data = data + self.error = error + + def as_dict(self): + return { + "status": self.status, + "message": self.message, + "data": self.data, + "error": self.error, + } + + +class RedisActions: + + @classmethod + def set_json(cls, name, value): + try: + search_name = str(name) if isinstance(name, str) else name.decode() + redis_cli.set(name=search_name, value=json.dumps(value)) + return RedisResponse( + status=True, + message="Value is set successfully.", + data=value, + ) + except Exception as e: + return RedisResponse( + status=False, + message="Value is not set successfully.", + error=str(e), + ) + + @classmethod + def get_json(cls, name): + try: + search_name = str(name) if isinstance(name, str) else name.decode() + json_get = redis_cli.get(search_name) + if not json_get: + return RedisResponse( + status=False, + message="Value is not get successfully.", + error="Value is not found in the redis.", + ) + return RedisResponse( + status=True, + message="Value is get successfully.", + data=json.loads(json_get), + ) + except Exception as e: + return RedisResponse( + status=False, + message="Value is not get successfully.", + error=str(e), + ) + + @classmethod + def set_replace_all(cls, value, value_regex): + try: + already_tokens = redis_cli.scan_iter(match=str(value_regex)) + for already_token in already_tokens: + redis_cli.set(name=already_token, value=json.dumps(value)) + return RedisResponse( + status=True, + message="Value is set successfully.", + data=value, + ) + except Exception as e: + return RedisResponse( + status=False, + message="Value is not set successfully.", + error=str(e), + ) + + @classmethod + def delete(cls, name): + try: + search_name = str(name) if isinstance(name, str) else name.decode() + json_delete = redis_cli.delete(search_name) + if not json_delete: + return RedisResponse( + status=False, + message="Value is not deleted successfully.", + error="Value is not found in the redis.", + ) + return RedisResponse( + status=True, + message="Value is deleted successfully.", + ) + except Exception as e: + return RedisResponse( + status=False, + message="Value is not deleted successfully.", + error=str(e), + ) + + @classmethod + def delete_all(cls, value_regex): + try: + already_tokens = redis_cli.scan_iter(match=str(value_regex)) + for already_token in already_tokens: + redis_cli.delete(already_token) + return RedisResponse( + status=True, + message="Value is deleted successfully.", + ) + except Exception as e: + return RedisResponse( + status=False, + message="Value is not deleted successfully.", + error=str(e), + ) + + @classmethod + def update(cls, name, data): + try: + json_update = cls.get_json(name=name) + if json_update.status: + value_dict = json_update.data + for key, value in data.items(): + value_dict[key] = value + redis_cli.set(name=name, value=json.dumps(value_dict)) + return RedisResponse( + status=True, + message="Value is updated successfully.", + data=value_dict, + ) + except Exception as e: + return RedisResponse( + status=False, + message="Value is not updated successfully.", + error=str(e), + ) + + @classmethod + def update_all(cls, value_regex, data): + try: + already_tokens = redis_cli.scan_iter(match=str(value_regex)) + for already_token in already_tokens: + cls.update(name=already_token, data=data) + return RedisResponse( + status=True, + message="Values are updated successfully.", + data=data, + ) + except Exception as e: + return RedisResponse( + status=False, + message="Value is not updated successfully.", + error=str(e), + ) + + +# def get_object_via_access_key( +# request, +# ): +# +# if not hasattr(request, "headers"): +# raise redis_imports.exceptions( +# status_code=401, +# detail=dict( +# message="Headers are not found in request. Invalid request object." +# ), +# ) +# if not request.headers.get(redis_imports.ACCESS_TOKEN_TAG): +# raise redis_imports.exceptions( +# status_code=401, +# detail=dict(message="Unauthorized user, please login..."), +# ) +# already_tokens = redis_cli.scan_iter( +# match=str(request.headers.get(redis_imports.ACCESS_TOKEN_TAG) + ":*") +# ) +# if already_tokens := list(already_tokens): +# try: +# if redis_object := json.loads( +# redis_cli.get(already_tokens[0].decode()) or {} +# ): +# if redis_object.get("user_type") == 1: +# if not redis_object.get("selected_company", None): +# redis_object["selected_company"] = None +# return redis_imports.EmployeeTokenObject(**redis_object) +# elif redis_object.get("user_type") == 2: +# if not redis_object.get("selected_occupant", None): +# redis_object["selected_occupant"] = None +# return redis_imports.OccupantTokenObject(**redis_object) +# raise redis_imports.exceptions( +# status_code=401, +# detail=dict( +# message="User type is not found in the token object. Please reach to your administrator." +# ), +# ) +# except Exception as e: +# raise redis_imports.exceptions( +# status_code=500, +# detail={ +# "message": "Redis Service raised an exception.", +# "error": str(e), +# }, +# ) +# +# raise redis_imports.exceptions( +# status_code=redis_imports.status.HTTP_401_UNAUTHORIZED, +# detail="Invalid credentials. Please login again.", +# ) +# +# +# def get_object_via_user_uu_id(user_id: str) -> typing.Union[dict, None]: +# already_tokens = redis_cli.scan_iter(match=str("*:" + str(user_id))) +# already_tokens_list, already_tokens_dict = [], {} +# for already_token in already_tokens: +# redis_object = json.loads(redis_cli.get(already_token) or {}) +# already_tokens_list.append(redis_object) +# already_tokens_dict[already_token.decode()] = redis_object +# return already_tokens_dict +# +# +# def save_object_to_redis( +# access_token, model_object, redis_imports: RedisImports +# ) -> bool: +# try: +# if redis_cli.set( +# name=str(access_token) + ":" + str(model_object.user_uu_id), +# value=model_object.model_dump_json(), +# ): +# return access_token +# except Exception as e: +# print("Save Object to Redis Error: ", e) +# raise redis_imports.exceptions( +# status_code=redis_imports.status.HTTP_503_SERVICE_UNAVAILABLE, +# detail=dict( +# message="Headers are not found in request. Invalid request object. Redis Error: Token is not saved." +# ), +# ) diff --git a/api_services/redis/old_functions.py b/api_services/redis/old_functions.py new file mode 100644 index 0000000..539c1f8 --- /dev/null +++ b/api_services/redis/old_functions.py @@ -0,0 +1,96 @@ +import json +import typing + +from .conn import redis_cli + + +class RedisImports: + def __init__(self, status, exceptions, access_token_tag, employee_token, occupant_token): + self.status = status + self.exceptions = exceptions + self.ACCESS_TOKEN_TAG = access_token_tag + self.EmployeeTokenObject = employee_token + self.OccupantTokenObject = occupant_token + + +def get_object_via_access_key( + request, + redis_imports: RedisImports +): + + if not hasattr(request, "headers"): + raise redis_imports.exceptions( + status_code=401, + detail=dict( + message="Headers are not found in request. Invalid request object." + ), + ) + if not request.headers.get(redis_imports.ACCESS_TOKEN_TAG): + raise redis_imports.exceptions( + status_code=401, + detail=dict(message="Unauthorized user, please login..."), + ) + already_tokens = redis_cli.scan_iter( + match=str(request.headers.get(redis_imports.ACCESS_TOKEN_TAG) + ":*") + ) + if already_tokens := list(already_tokens): + try: + if redis_object := json.loads( + redis_cli.get(already_tokens[0].decode()) or {} + ): + if redis_object.get("user_type") == 1: + if not redis_object.get("selected_company", None): + redis_object["selected_company"] = None + return redis_imports.EmployeeTokenObject(**redis_object) + elif redis_object.get("user_type") == 2: + if not redis_object.get("selected_occupant", None): + redis_object["selected_occupant"] = None + return redis_imports.OccupantTokenObject(**redis_object) + raise redis_imports.exceptions( + status_code=401, + detail=dict( + message="User type is not found in the token object. Please reach to your administrator." + ), + ) + except Exception as e: + raise redis_imports.exceptions( + status_code=500, + detail={ + "message": "Redis Service raised an exception.", + "error": str(e), + }, + ) + + raise redis_imports.exceptions( + status_code=redis_imports.status.HTTP_401_UNAUTHORIZED, + detail="Invalid credentials. Please login again.", + ) + + +def get_object_via_user_uu_id(user_id: str) -> typing.Union[dict, None]: + already_tokens = redis_cli.scan_iter(match=str("*:" + str(user_id))) + already_tokens_list, already_tokens_dict = [], {} + for already_token in already_tokens: + redis_object = json.loads(redis_cli.get(already_token) or {}) + already_tokens_list.append(redis_object) + already_tokens_dict[already_token.decode()] = redis_object + return already_tokens_dict + + +def save_object_to_redis( + access_token, model_object, redis_imports: RedisImports +) -> bool: + try: + if redis_cli.set( + name=str(access_token) + ":" + str(model_object.user_uu_id), + value=model_object.model_dump_json(), + ): + return access_token + except Exception as e: + print("Save Object to Redis Error: ", e) + raise redis_imports.exceptions( + status_code=redis_imports.status.HTTP_503_SERVICE_UNAVAILABLE, + detail=dict( + message="Headers are not found in request. Invalid request object. Redis Error: Token is not saved." + ), + ) diff --git a/api_services/templates/password_templates.py b/api_services/templates/password_templates.py new file mode 100644 index 0000000..1f35b31 --- /dev/null +++ b/api_services/templates/password_templates.py @@ -0,0 +1,243 @@ +import datetime + + +def change_your_password_template(**kwargs): + user_name, forgot_link, current_year = ( + kwargs["user_name"], + kwargs["forgot_link"], + str(datetime.datetime.now().year), + ) + template = """ + + + + + Bootstrap demo + + + +
+
+ Company Logo +

Reset Password

+
+
+

Dear %s,

+

We have received a request to reset your password for your account with Let's Program Blog. To complete the password reset process, please click on the button below:

+

Please note that this link is only valid for a day only. If you did not request a password reset, please disregard this message.

+ +
+ +
+ + +""" % ( + user_name, + forgot_link, + current_year, + ) + + return template + + +def password_is_changed_template(**kwargs): + user_name, current_year = kwargs["user_name"], str(datetime.datetime.now().year) + template = """ + + + + + + Thank You for Changing Your Password + + + +
+
+ Company Logo +

Your Password has changed

+
+
+

Dear %s,

+

We wanted to let you know that your password has been successfully updated. + If you did not make this change or if you believe an unauthorized person has accessed your account, + please contact our support team immediately.

+

Thank you for helping us keep your account secure.

+
+ +
+ + + """ % ( + user_name, + current_year, + ) + + return template + + +def invalid_ip_or_address_found(**kwargs): + user_name, current_year, address = ( + kwargs["user_name"], + str(datetime.datetime.now().year), + kwargs.get("address"), + ) + template = """ + + + + + + Thank You for Changing Your Password + + + +
+
+ Company Logo +

An Unknown login has been attempted

+
+
+

Dear %s,

+

We wanted to let you know that an unusual login attempt has been tried from address below. + If you have login from address below please ignore this message

+

Thank you for helping us keep your account secure.

+

Address of ip attempt

+

City : %s

+

Zip Code : %s

+

Country : %s

+

Region : %s

+

Region Name : %s

+

If you are not login from this address lets us now by clicking link below

+ +
+ +
+ + + """ % ( + user_name, + address["city"], + address["zip"], + address["country"], + address["region"], + address["regionName"], + kwargs["notice_link"], + current_year, + ) + return template diff --git a/api_validations/__init__.py b/api_validations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_validations/core_validations.py b/api_validations/core_validations.py new file mode 100644 index 0000000..e5f0214 --- /dev/null +++ b/api_validations/core_validations.py @@ -0,0 +1,22 @@ +from pydantic import BaseModel + + +def rewrite_input_data(data): + + return { + item[0]: item[1] + for item in data.items() + if not item[1] == "" and item[1] is not None + } + + +class BaseModelRegular(BaseModel): + + def __init__(self, **kwargs): + super().__init__(**rewrite_input_data(kwargs)) + + def excluded_dump(self): + return self.model_dump(exclude_unset=True, exclude_none=True) + + def dump(self): + return self.model_dump() diff --git a/api_validations/validations_by_user/__init__.py b/api_validations/validations_by_user/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api_validations/validations_request/__init__.py b/api_validations/validations_request/__init__.py new file mode 100644 index 0000000..c4de9e9 --- /dev/null +++ b/api_validations/validations_request/__init__.py @@ -0,0 +1,245 @@ +from .core_request_validations import ( + ListOptions, + EndpointValidation, + PydanticBaseModel, + PatchRecord, + EndpointPydantic, + BaseModelRegular, + PydanticBaseModelValidation, + CrudRecordValidation, + CrudRecords, +) +from .address import ( + InsertAddress, + UpdateAddress, + UpdatePostCode, + InsertPostCode, + SearchAddress, +) +from .application import ( + SingleEnumUUID, + SingleEnumClassKey, + SingleEnumOnlyClass, + SingleOccupantTypeUUID, + SingleOccupantTypeClassKey, +) +from .area import ( + InsertBuildArea, + InsertBuildSites, + UpdateBuildArea, + UpdateBuildSites, +) +from .authentication import ( + Login, + Logout, + ChangePassword, + Remember, + Forgot, + CreatePassword, + OccupantSelection, + EmployeeSelection, +) +from .account_records import ( + InsertAccountRecord, + UpdateAccountRecord, +) + +from .build_living_space import ( + InsertBuildLivingSpace, + UpdateBuildLivingSpace, +) +from .build_part import ( + InsertBuildParts, + InsertBuildTypes, + UpdateBuildParts, + UpdateBuildTypes, +) +from .building import ( + InsertBuild, + UpdateBuild, +) +from .company import ( + MatchCompany2Company, + InsertCompany, + UpdateCompany, +) +from .decision_book import ( + DecisionBookDecisionBookInvitations, + DecisionBookDecisionBookInvitationsUpdate, + DecisionBookDecisionBookInvitationsAttend, + DecisionBookDecisionBookInvitationsAssign, + UpdateDecisionBook, + UpdateBuildDecisionBookItems, + UpdateBuildDecisionBookItemDebits, + InsertBuildDecisionBookItems, + InsertBuildDecisionBookItemDebits, + InsertDecisionBookCompleted, + InsertDecisionBook, + InsertDecisionBookPerson, + ListDecisionBook, + RemoveDecisionBookPerson, +) +from .departments import ( + DepartmentsPydantic, +) +from .employee import ( + InsertDuties, + UpdateDuties, + InsertEmployees, + SelectDuties, + UnBindEmployees2People, + BindEmployees2People, + UpdateCompanyEmployees, + InsertCompanyEmployees, + InsertCompanyEmployeesSalaries, + InsertCompanyDuty, + UpdateCompanyEmployeesSalaries, + UpdateCompanyDuty, +) +from .events import ( + # CreateEvents, + RegisterEvents2Employee, + RegisterEvents2Occupant, +) +from .people import ( + UpdatePerson, + InsertPerson, +) +from .project_decision_book import ( + InsertBuildDecisionBookProjectItemDebits, + UpdateBuildDecisionBookProjectItemDebits, + InsertBuildDecisionBookProjects, + UpdateBuildDecisionBookProjects, + InsertBuildDecisionBookProjectPerson, + UpdateBuildDecisionBookProjectPerson, + InsertBuildDecisionBookProjectItems, + UpdateBuildDecisionBookProjectItems, + ApprovalsBuildDecisionBookProjects, +) +from .rules import ( + UpdateEndpointAccess, + UpdateEndpointAccessList, + InsertEndpointAccess, + CheckEndpointAccess, +) +from .services import ( + RegisterServices2Employee, + RegisterServices2Occupant, +) +from .staff import ( + InsertStaff, + SelectStaff, +) +from .user import ( + InsertUsers, + UpdateUsers, + QueryUsers, + # ActiveUsers, + # ListUsers, + # DeleteUsers, +) +from .modules import ( + RegisterModules2Occupant, + RegisterModules2Employee, +) + + +__all__ = [ + "ListOptions", + "EndpointValidation", + "PydanticBaseModelValidation", + "CrudRecordValidation", + "CrudRecords", + "PydanticBaseModel", + "PatchRecord", + "EndpointPydantic", + "BaseModelRegular", + "InsertAddress", + "UpdateAddress", + "UpdatePostCode", + "InsertPostCode", + "SearchAddress", + "SingleEnumUUID", + "SingleEnumClassKey", + "SingleEnumOnlyClass", + "SingleOccupantTypeUUID", + "SingleOccupantTypeClassKey", + "InsertBuildArea", + "InsertBuildSites", + "UpdateBuildArea", + "UpdateBuildSites", + "Login", + "Logout", + "ChangePassword", + "Remember", + "Forgot", + "CreatePassword", + "OccupantSelection", + "EmployeeSelection", + "InsertAccountRecord", + "UpdateAccountRecord", + "InsertBuildLivingSpace", + "UpdateBuildLivingSpace", + "InsertBuildParts", + "InsertBuildTypes", + "UpdateBuildParts", + "UpdateBuildTypes", + "InsertBuild", + "UpdateBuild", + "MatchCompany2Company", + "InsertCompany", + "UpdateCompany", + "DecisionBookDecisionBookInvitations", + "DecisionBookDecisionBookInvitationsUpdate", + "DecisionBookDecisionBookInvitationsAttend", + "DecisionBookDecisionBookInvitationsAssign", + "UpdateDecisionBook", + "UpdateBuildDecisionBookItems", + "UpdateBuildDecisionBookItemDebits", + "InsertBuildDecisionBookItems", + "InsertBuildDecisionBookItemDebits", + "InsertDecisionBookCompleted", + "InsertDecisionBook", + "InsertDecisionBookPerson", + "ListDecisionBook", + "RemoveDecisionBookPerson", + "DepartmentsPydantic", + "InsertDuties", + "UpdateDuties", + "InsertEmployees", + "SelectDuties", + "UnBindEmployees2People", + "BindEmployees2People", + "UpdateCompanyEmployees", + "InsertCompanyEmployees", + "InsertCompanyEmployeesSalaries", + "InsertCompanyDuty", + "UpdateCompanyEmployeesSalaries", + "UpdateCompanyDuty", + "RegisterEvents2Employee", + "RegisterEvents2Occupant", + "UpdatePerson", + "InsertPerson", + "InsertBuildDecisionBookProjectItems", + "UpdateBuildDecisionBookProjectItems", + "ApprovalsBuildDecisionBookProjects", + "InsertBuildDecisionBookProjectItemDebits", + "UpdateBuildDecisionBookProjectItemDebits", + "InsertBuildDecisionBookProjects", + "UpdateBuildDecisionBookProjects", + "InsertBuildDecisionBookProjectPerson", + "UpdateBuildDecisionBookProjectPerson", + "UpdateEndpointAccess", + "UpdateEndpointAccessList", + "InsertEndpointAccess", + "CheckEndpointAccess", + "RegisterServices2Employee", + "RegisterServices2Occupant", + "InsertStaff", + "SelectStaff", + "InsertUsers", + "UpdateUsers", + "QueryUsers", + "RegisterModules2Occupant", + "RegisterModules2Employee", +] diff --git a/api_validations/validations_request/account_records.py b/api_validations/validations_request/account_records.py new file mode 100644 index 0000000..69a4754 --- /dev/null +++ b/api_validations/validations_request/account_records.py @@ -0,0 +1,162 @@ +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + PydanticBaseModel, +) +from typing import Optional + + +class AccountValidation: + tr = { + "iban": "IBAN Numarası", + "bank_date": "Bank Tarih", + "currency_value": "Para Değeri", + "bank_balance": "Banka Bakiye", + "currency": "Para Birimi", + "additional_balance": "Ek Bakiye", + "channel_branch": "Kanal Şubesi", + "process_name": "İşlem Adı", + "process_type": "İşlem Tipi", + "process_comment": "İşlem Yorum", + "bank_reference_code": "Banka Referans Kodu", + "add_comment_note": "Yorum Not", + "is_receipt_mail_send": "Fiş Mail Gönderildi", + "found_from": "Bulunduğu Yer", + "similarity": "Benzerlik", + "remainder_balance": "Kalan Bakiye", + "bank_date_y": "Bank Tarih Yıl", + "bank_date_m": "Bank Tarih Ay", + "bank_date_w": "Bank Tarih Hafta", + "bank_date_d": "Bank Tarih Gün", + "approving_accounting_record": "Onaylayan Muhasebe Kaydı", + "accounting_receipt_date": "Muhasebe Fiş Tarihi", + "accounting_receipt_number": "Muhasebe Fiş Numarası", + "approved_record": "Onaylanmış Kayıt", + "import_file_name": "İçe Aktarım Dosya Adı", + "receive_debit_uu_id": "Alacak UUID", + "budget_type_uu_id": "Bütçe Tipi UUID", + "company_uu_id": "Şirket UUID", + "send_company_uu_id": "Gönderen Şirket UUID", + "customer_id": "Müşteri ID", + "customer_uu_id": "Müşteri UUID", + "send_person_uu_id": "Gönderen Kişi UUID", + "approving_accounting_person_uu_id": "Onaylayan Muhasebe Kişi UUID", + "build_parts_uu_id": "Daire UUID", + "build_decision_book_uu_id": "Karar Defteri UUID", + } + en = { + "iban": "IBAN Number", + "bank_date": "Bank Date", + "currency_value": "Currency Value", + "bank_balance": "Bank Balance", + "currency": "Currency", + "additional_balance": "Additional Balance", + "channel_branch": "Channel Branch", + "process_name": "Process Name", + "process_type": "Process Type", + "process_comment": "Process Comment", + "bank_reference_code": "Bank Reference Code", + "add_comment_note": "Comment Note", + "is_receipt_mail_send": "Receipt Mail Send", + "found_from": "Found From", + "similarity": "Similarity", + "remainder_balance": "Remainder Balance", + "bank_date_y": "Bank Date Year", + "bank_date_m": "Bank Date Month", + "bank_date_w": "Bank Date Week", + "bank_date_d": "Bank Date Day", + "approving_accounting_record": "Approving Accounting Record", + "accounting_receipt_date": "Accounting Receipt Date", + "accounting_receipt_number": "Accounting Receipt Number", + "approved_record": "Approved Record", + "import_file_name": "Import File Name", + "receive_debit_uu_id": "Receive Debit UUID", + "budget_type_uu_id": "Budget Type UUID", + "company_uu_id": "Company UUID", + "send_company_uu_id": "Send Company UUID", + "customer_id": "Customer ID", + "customer_uu_id": "Customer UUID", + "send_person_uu_id": "Send Person UUID", + "approving_accounting_person_uu_id": "Approving Accounting Person UUID", + "build_parts_uu_id": "Build Parts UUID", + "build_decision_book_uu_id": "Build Decision Book UUID", + } + + +class InsertAccountRecord(BaseModelRegular, AccountValidation): + + iban: str + bank_date: str + currency_value: float + bank_balance: float + currency: str + additional_balance: float + channel_branch: str + process_name: str + process_type: str + process_comment: str + bank_reference_code: str + + add_comment_note: Optional[str] = None + is_receipt_mail_send: Optional[bool] = None + found_from: Optional[str] = None + similarity: Optional[float] = None + remainder_balance: Optional[float] = None + bank_date_y: Optional[int] = None + bank_date_m: Optional[int] = None + bank_date_w: Optional[int] = None + bank_date_d: Optional[int] = None + approving_accounting_record: Optional[bool] = None + accounting_receipt_date: Optional[str] = None + accounting_receipt_number: Optional[int] = None + approved_record: Optional[bool] = None + import_file_name: Optional[str] = None + # receive_debit_uu_id: Optional[str] = None + budget_type_uu_id: Optional[str] = None + company_uu_id: Optional[str] = None + send_company_uu_id: Optional[str] = None + customer_id: Optional[str] = None + customer_uu_id: Optional[str] = None + send_person_uu_id: Optional[str] = None + approving_accounting_person_uu_id: Optional[str] = None + build_parts_uu_id: Optional[str] = None + build_decision_book_uu_id: Optional[str] = None + + +class UpdateAccountRecord(PydanticBaseModel, AccountValidation): + + iban: Optional[str] = None + bank_date: Optional[str] = None + currency_value: Optional[float] = None + bank_balance: Optional[float] = None + currency: Optional[str] = None + additional_balance: Optional[float] = None + channel_branch: Optional[str] = None + process_name: Optional[str] = None + process_type: Optional[str] = None + process_comment: Optional[str] = None + bank_reference_code: Optional[str] = None + + add_comment_note: Optional[str] = None + is_receipt_mail_send: Optional[bool] = None + found_from: Optional[str] = None + similarity: Optional[float] = None + remainder_balance: Optional[float] = None + bank_date_y: Optional[int] = None + bank_date_m: Optional[int] = None + bank_date_w: Optional[int] = None + bank_date_d: Optional[int] = None + approving_accounting_record: Optional[bool] = None + accounting_receipt_date: Optional[str] = None + accounting_receipt_number: Optional[int] = None + approved_record: Optional[bool] = None + import_file_name: Optional[str] = None + receive_debit_uu_id: Optional[str] = None + budget_type_uu_id: Optional[str] = None + company_uu_id: Optional[str] = None + send_company_uu_id: Optional[str] = None + customer_id: Optional[str] = None + customer_uu_id: Optional[str] = None + send_person_uu_id: Optional[str] = None + approving_accounting_person_uu_id: Optional[str] = None + build_parts_uu_id: Optional[str] = None + build_decision_book_uu_id: Optional[str] = None diff --git a/api_validations/validations_request/address.py b/api_validations/validations_request/address.py new file mode 100644 index 0000000..c7b9249 --- /dev/null +++ b/api_validations/validations_request/address.py @@ -0,0 +1,130 @@ +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + PydanticBaseModel, + ListOptions, +) +from typing import Optional + + +class PostCodeValidation: + tr = { + "post_code": "Posta Kodu", + "street_uu_id": "Sokak UUID", + } + en = { + "post_code": "Post Code", + "street_uu_id": "Street UUID", + } + + +class InsertPostCode(BaseModelRegular, PostCodeValidation): + street_uu_id: str + post_code: str + + +class UpdatePostCode(PydanticBaseModel, PostCodeValidation): + street_uu_id: Optional[str] = None + post_code: Optional[str] = None + + +class SearchAddressValidation: + tr = { + "search": "Ara", + "list_options": "Liste Seçenekleri", + } + en = { + "search": "Search", + "list_options": "List Options", + } + + +class SearchAddress(PydanticBaseModel, SearchAddressValidation): + search: str + list_options: ListOptions + + +class StreetValidation: + tr = { + "street_code": "Sokak Kodu", + "street_name": "Sokak Adı", + "postcode": "Posta Kodu", + "type_code": "Tip Kodu", + "type_description": "Tip Açıklaması", + "gov_code": "Devlet Kodu", + "address_geographic_uu_id": "Coğrafi UUID", + } + en = { + "street_code": "Street Code", + "street_name": "Street Name", + "postcode": "Post Code", + "type_code": "Type Code", + "type_description": "Type Description", + "gov_code": "Government Code", + "address_geographic_uu_id": "Address Geographic UUID", + } + + +class InsertStreet(PydanticBaseModel, StreetValidation): + street_code: str + street_name: str + postcode: str + + type_code: Optional[str] = None + type_description: Optional[str] = None + gov_code: Optional[str] = None + address_geographic_uu_id: Optional[str] = None + + +class AddressValidation: + tr = { + "post_code_uu_id": "Posta Kodu UUID", + "comment_address": "Adres Yorumu", + "letter_address": "Mektup Adresi", + "build_number": "Bina Numarası", + "door_number": "Kapı Numarası", + "floor_number": "Kat Numarası", + "short_letter_address": "Kısa Mektup Adresi", + "latitude": "Enlem", + "longitude": "Boylam", + } + en = { + "post_code_uu_id": "Post Code UUID", + "comment_address": "Address Comment", + "letter_address": "Letter Address", + "build_number": "Build Number", + "door_number": "Door Number", + "floor_number": "Floor Number", + "short_letter_address": "Short Letter Address", + "latitude": "Latitude", + "longitude": "Longitude", + } + + +class InsertAddress(BaseModelRegular, AddressValidation): + post_code_uu_id: str + + comment_address: Optional[str] = None + letter_address: Optional[str] = None + + build_number: str + door_number: Optional[str] = None + floor_number: Optional[str] = None + + short_letter_address: Optional[str] = None + latitude: Optional[float] = None + longitude: Optional[float] = None + + +class UpdateAddress(PydanticBaseModel, AddressValidation): + post_code_uu_id: Optional[str] = None + + comment_address: Optional[str] = None + letter_address: Optional[str] = None + + build_number: Optional[str] = None + door_number: Optional[str] = None + floor_number: Optional[str] = None + + short_letter_address: Optional[str] = None + latitude: Optional[float] = None + longitude: Optional[float] = None diff --git a/api_validations/validations_request/application.py b/api_validations/validations_request/application.py new file mode 100644 index 0000000..f9fa22b --- /dev/null +++ b/api_validations/validations_request/application.py @@ -0,0 +1,69 @@ +from api_validations.core_validations import BaseModelRegular + + +class SingleEnumClassKeyValidation: + tr = { + "class_name": "Sınıf Adı", + "key_name": "Anahtar Adı", + } + en = { + "class_name": "Class Name", + "key_name": "Key Name", + } + + +class SingleEnumClassKey(BaseModelRegular): + class_name: str + key_name: str + + +class SingleEnumUUIDValidation: + tr = { + "uu_id": "UUID", + } + en = { + "uu_id": "UUID", + } + + +class SingleEnumUUID(BaseModelRegular): + uu_id: str + + +class SingleEnumOnlyClassValidation: + tr = { + "class_name": "Sınıf Adı", + } + en = { + "class_name": "Class Name", + } + + +class SingleEnumOnlyClass(BaseModelRegular): + class_name: str + + +class SingleOccupantTypeClassKeyValidation: + tr = { + "type_code": "Tip Kodu", + } + en = { + "type_code": "Type Code", + } + + +class SingleOccupantTypeClassKey(BaseModelRegular): + type_code: str + + +class SingleOccupantTypeUUIDValidation: + tr = { + "uu_id": "Görev UUID", + } + en = { + "uu_id": "Occupant UUID", + } + + +class SingleOccupantTypeUUID(BaseModelRegular): + uu_id: str diff --git a/api_validations/validations_request/area.py b/api_validations/validations_request/area.py new file mode 100644 index 0000000..cfdf675 --- /dev/null +++ b/api_validations/validations_request/area.py @@ -0,0 +1,76 @@ +from typing import Optional +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + PydanticBaseModel, +) + + +class BuildAreaValidation: + + tr = { + "area_name": "Alan Adı", + "area_code": "Alan Kodu", + "area_type": "Alan Tipi", + "area_direction": "Alan Yönü", + "area_gross_size": "Brüt Alan", + "area_net_size": "Net Alan", + "width": "Genişlik", + "size": "En", + } + en = { + "area_name": "Area Name", + "area_code": "Area Code", + "area_type": "Area Type", + "area_direction": "Area Direction", + "area_gross_size": "Gross Size", + "area_net_size": "Net Size", + "width": "Width", + "size": "Size", + } + + +class InsertBuildArea(BaseModelRegular, BuildAreaValidation): + + build_uu_id: str + area_name: str + area_code: str + area_type: str + area_direction: Optional[str] = None + area_gross_size: Optional[float] = None + area_net_size: Optional[float] = None + width: Optional[int] = None + size: Optional[int] = None + + +class UpdateBuildArea(PydanticBaseModel, BuildAreaValidation): + + area_name: Optional[str] = None + area_code: Optional[str] = None + area_type: Optional[str] = None + area_direction: Optional[str] = None + area_gross_size: Optional[float] = None + area_net_size: Optional[float] = None + width: Optional[int] = None + size: Optional[int] = None + + +class BuildSites: + tr = {"address_uu_id": "Adres UU ID", "site_name": "Site Adı", "site_no": "Site No"} + en = { + "address_uu_id": "Address UU ID", + "site_name": "Site Name", + "site_no": "Site No", + } + + +class InsertBuildSites(BaseModelRegular, BuildSites): + + address_uu_id: str + site_name: str + site_no: str + + +class UpdateBuildSites(PydanticBaseModel, BuildSites): + + site_name: Optional[str] = None + site_no: Optional[str] = None diff --git a/api_validations/validations_request/authentication.py b/api_validations/validations_request/authentication.py new file mode 100644 index 0000000..d1205ce --- /dev/null +++ b/api_validations/validations_request/authentication.py @@ -0,0 +1,104 @@ +from api_validations.core_validations import BaseModelRegular +from typing import Optional +from pydantic import BaseModel + + +class ChangePasswordValidation: + tr = {"old_password": "Eski Şifre", "new_password": "Yeni Şifre"} + en = {"old_password": "Old Password", "new_password": "New Password"} + + +class ChangePassword(BaseModelRegular, ChangePasswordValidation): + old_password: str + new_password: str + + +class CreatePasswordValidation: + tr = { + "password_token": "Şifre Token", + "password": "Şifre", + "re_password": "Şifre Tekrar", + } + en = { + "password_token": "Password Token", + "password": "Password", + "re_password": "Re-Password", + } + + +class CreatePassword(BaseModelRegular, CreatePasswordValidation): + password_token: str + password: str + re_password: str + + +class OccupantSelectionValidation: + + tr = {"occupant_uu_id": "Kiracı UU ID", "build_part_uu_id": "Bölüm UU ID"} + en = {"occupant_uu_id": "Occupant UU ID", "build_part_uu_id": "Build Part UU ID"} + + +class OccupantSelection(BaseModel, OccupantSelectionValidation): + occupant_uu_id: str + build_part_uu_id: str + + +class EmployeeSelectionValidation: + + tr = {"company_uu_id": "Şirket UU ID"} + en = {"company_uu_id": "Company UU ID"} + + +class EmployeeSelection(BaseModel, EmployeeSelectionValidation): + company_uu_id: str + + +class LoginValidation: + tr = { + "domain": "Domain", + "access_key": "Erişim Anahtarı", + "password": "Şifre", + "remember_me": "Beni Hatırla", + } + en = { + "domain": "Domain", + "access_key": "Access Key", + "password": "Password", + "remember_me": "Remember Me", + } + + +class Login(BaseModelRegular, LoginValidation): + domain: str + access_key: str + password: str + remember_me: Optional[bool] = False + + +class LogoutValidation: + tr = {"domain": "Domain"} + en = {"domain": "Domain"} + + +class Logout(BaseModelRegular, LogoutValidation): + domain: str + + +class RememberValidation: + tr = {"domain": "Domain", "refresh_token": "Yenileme Anahtarı"} + en = {"domain": "Domain", "refresh_token": "Refresh Token"} + + +class Remember(BaseModelRegular, RememberValidation): + domain: str + refresh_token: str + + +class ForgotValidation: + tr = {"domain": "Domain", "access_key": "Erişim Anahtarı"} + en = {"domain": "Domain", "access_key": "Access Key"} + + +class Forgot(BaseModelRegular, ForgotValidation): + domain: str + access_key: str diff --git a/api_validations/validations_request/build_living_space.py b/api_validations/validations_request/build_living_space.py new file mode 100644 index 0000000..abb1ae7 --- /dev/null +++ b/api_validations/validations_request/build_living_space.py @@ -0,0 +1,52 @@ +from typing import Optional +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + PydanticBaseModel, + PydanticBaseModelValidation, +) + + +class BuildLivingSpaceValidation: + tr = { + "person_uu_id": "Kişi UUID'si", + "build_parts_uu_id": "Bina UUID'si", + "occupant_type_uu_id": "Mülk Sahibi UUID'si", + "expiry_starts": "Geçerlilik Başlangıç Tarihi", + "expiry_ends": "Geçerlilik Bitiş Tarihi", + } + en = { + "person_uu_id": "Person UUID", + "build_parts_uu_id": "Build UUID", + "occupant_type_uu_id": "Occupant UUID", + "expiry_starts": "Expiry Starts", + "expiry_ends": "Expiry Ends", + } + + +class PydanticBaseModelValidationUpdate: + tr = { + **PydanticBaseModelValidation.tr, + "is_tenant_live": "Kiracı mı?", + "build_parts_uu_id": "Bina UUID'si", + "person_uu_id": "Kişi UUID'si", + } + en = { + **PydanticBaseModelValidation.en, + "is_tenant_live": "Is Tenant Live?", + "build_parts_uu_id": "Build UUID", + "person_uu_id": "Person UUID", + } + + +class InsertBuildLivingSpace(BaseModelRegular, BuildLivingSpaceValidation): + person_uu_id: str + build_parts_uu_id: str + occupant_type_uu_id: str + expiry_starts: str + expiry_ends: Optional[str] = None + + +class UpdateBuildLivingSpace(PydanticBaseModel, BuildLivingSpaceValidation): + is_tenant_live: Optional[bool] = None + build_parts_uu_id: Optional[str] = None + person_uu_id: Optional[str] = None diff --git a/api_validations/validations_request/build_part.py b/api_validations/validations_request/build_part.py new file mode 100644 index 0000000..0386a3b --- /dev/null +++ b/api_validations/validations_request/build_part.py @@ -0,0 +1,139 @@ +from typing import Optional +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + PydanticBaseModel, + PydanticBaseModelValidation, +) + + +class BuildTypesUpdateValidation: + tr = { + **PydanticBaseModelValidation.tr, + "function_code": "Fonksiyon Kodu", + "type_code": "Tip Kodu", + "lang": "Dil", + "type_name": "Tip Adı", + } + en = { + **PydanticBaseModelValidation.en, + "function_code": "Function Code", + "type_code": "Type Code", + "lang": "Language", + "type_name": "Type Name", + } + + +class BuildTypesValidation: + tr = { + "function_code": "Fonksiyon Kodu", + "type_code": "Tip Kodu", + "lang": "Dil", + "type_name": "Tip Adı", + } + en = { + "function_code": "Function Code", + "type_code": "Type Code", + "lang": "Language", + "type_name": "Type Name", + } + + +class InsertBuildTypes(BaseModelRegular, BuildTypesValidation): + function_code: str + type_code: str + lang: str + type_name: str + + +class UpdateBuildTypes(PydanticBaseModel, BuildTypesUpdateValidation): ... + + +class BuildPartsValidation: + tr = { + "address_gov_code": "Adres İl Kodu", + "part_no": "Daire No", + "part_level": "Daire Seviyesi", + "build_part_type_uu_id": "Bina Daire Tipi UUID'si", + "part_code": "Daire Kodu", + "part_gross_size": "Daire Brüt Alanı", + "part_net_size": "Daire Net Alanı", + "default_accessory": "Varsayılan Aksesuar", + "human_livable": "İnsan Yaşanabilir", + "part_direction": "Daire Yönü", + } + en = { + "address_gov_code": "Address Gov Code", + "part_no": "Flat No", + "part_level": "Flat Level", + "build_part_type_uu_id": "Build Flat Type UUID", + "part_code": "Flat Code", + "part_gross_size": "Flat Gross Size", + "part_net_size": "Flat Net Size", + "default_accessory": "Default Accessory", + "human_livable": "Human Livable", + "part_direction": "Flat Direction", + } + + +class InsertBuildParts(BaseModelRegular, BuildPartsValidation): + build_uu_id: str + address_gov_code: str + part_no: int + part_level: int + build_part_type_uu_id: str + + part_gross_size: Optional[int] = None + part_net_size: Optional[int] = None + default_accessory: Optional[str] = None + human_livable: Optional[bool] = False + part_direction_uu_id: Optional[str] = None + ref_id: Optional[str] = None + + +class UpdateBuildPartsValidation: + tr = { + **PydanticBaseModelValidation.tr, + "address_gov_code": "Adres İl Kodu", + "part_no": "Daire No", + "part_level": "Daire Seviyesi", + "build_part_type_uu_id": "Bina Daire Tipi UUID'si", + "part_code": "Daire Kodu", + "part_gross_size": "Daire Brüt Alanı", + "part_net_size": "Daire Net Alanı", + "default_accessory": "Varsayılan Aksesuar", + "human_livable": "İnsan Yaşanabilir", + "part_direction": "Daire Yönü", + "current_owner_person_uu_id": "Mevcut Sahip Kişi UUID'si", + "current_tenant_person_uu_id": "Mevcut Kiracı Kişi UUID'si", + } + en = { + **PydanticBaseModelValidation.en, + "address_gov_code": "Address Gov Code", + "part_no": "Flat No", + "part_level": "Flat Level", + "build_part_type_uu_id": "Build Flat Type UUID", + "part_code": "Flat Code", + "part_gross_size": "Flat Gross Size", + "part_net_size": "Flat Net Size", + "default_accessory": "Default Accessory", + "human_livable": "Human Livable", + "part_direction": "Flat Direction", + "current_owner_person_uu_id": "Current Owner Person UUID", + "current_tenant_person_uu_id": "Current Tenant Person UUID", + } + + +class UpdateBuildParts(PydanticBaseModel, UpdateBuildPartsValidation): + address_gov_code: Optional[str] = None + part_no: Optional[int] = None + part_level: Optional[int] = None + build_part_type_uu_id: Optional[str] = None + + part_code: Optional[int] = None + part_gross_size: Optional[int] = None + part_net_size: Optional[int] = None + default_accessory: Optional[str] = None + human_livable: Optional[bool] = False + part_direction: Optional[str] = None + current_owner_person_uu_id: Optional[str] = None + current_tenant_person_uu_id: Optional[str] = None diff --git a/api_validations/validations_request/building.py b/api_validations/validations_request/building.py new file mode 100644 index 0000000..1efa2ac --- /dev/null +++ b/api_validations/validations_request/building.py @@ -0,0 +1,102 @@ +from typing import Optional +from datetime import datetime +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + PydanticBaseModel, + PydanticBaseModelValidation, + CrudRecordValidation, +) + + +class BuildValidation: + tr = { + **CrudRecordValidation.tr, + "gov_address_code": "Devlet Adres Kodu", + "build_name": "Bina Adı", + "build_types_uu_id": "Bina Tipi", + "build_no": "Bina No", + "max_floor": "Kat Sayısı", + "underground_floor": "Bodrum Kat Sayısı", + "address_uu_id": "Adres", + "build_date": "Yapım Tarihi", + "decision_period_date": "Karar Tarihi", + "tax_no": "Vergi No", + "lift_count": "Asansör Sayısı", + "heating_system": "Isıtma Sistemi", + "cooling_system": "Soğutma Sistemi", + "hot_water_system": "Sıcak Su Sistemi", + "block_service_man_count": "Hizmet Görevlisi Sayısı", + "security_service_man_count": "Güvenlik Görevlisi Sayısı", + "garage_count": "Garaj Sayısı", + } + en = { + **CrudRecordValidation.en, + "gov_address_code": "Government Address Code", + "build_name": "Building Name", + "build_types_uu_id": "Building Type", + "build_no": "Building No", + "max_floor": "Number of Floors", + "underground_floor": "Number of Basement Floors", + "address_uu_id": "Address", + "build_date": "Construction Date", + "decision_period_date": "Decision Date", + "tax_no": "Tax No", + "lift_count": "Number of Elevators", + "heating_system": "Heating System", + "cooling_system": "Cooling System", + "hot_water_system": "Hot Water System", + "block_service_man_count": "Number of Service Officers", + "security_service_man_count": "Number of Security Officers", + "garage_count": "Number of Garages", + } + + +class InsertBuild(BaseModelRegular, BuildValidation): + + gov_address_code: str + build_name: str + build_types_uu_id: str + max_floor: int + underground_floor: int + address_uu_id: str + build_date: datetime + decision_period_date: datetime + + tax_no: Optional[str] = None + lift_count: Optional[int] = None + heating_system: Optional[bool] = None + cooling_system: Optional[bool] = None + hot_water_system: Optional[bool] = None + block_service_man_count: Optional[int] = None + security_service_man_count: Optional[int] = None + garage_count: Optional[int] = None + + +class BuildUpdateValidation: + tr = { + **BuildValidation.tr, + **PydanticBaseModelValidation.tr, + } + en = { + **BuildValidation.en, + **PydanticBaseModelValidation.en, + } + + +class UpdateBuild(PydanticBaseModel, BuildUpdateValidation): + gov_address_code: Optional[str] = None + build_name: Optional[str] = None + build_no: Optional[str] = None + build_types_uu_id: Optional[str] = None + max_floor: Optional[int] = None + underground_floor: Optional[int] = None + build_date: Optional[datetime] = None + tax_no: Optional[str] = None + lift_count: Optional[int] = None + heating_system: Optional[bool] = None + cooling_system: Optional[bool] = None + hot_water_system: Optional[bool] = None + block_service_man_count: Optional[int] = None + security_service_man_count: Optional[int] = None + garage_count: Optional[int] = None + address_uu_id: Optional[str] = None diff --git a/api_validations/validations_request/company.py b/api_validations/validations_request/company.py new file mode 100644 index 0000000..22a3787 --- /dev/null +++ b/api_validations/validations_request/company.py @@ -0,0 +1,74 @@ +from typing import Optional, List +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + PydanticBaseModel, + PydanticBaseModelValidation, +) + + +class CompanyValidation: + tr = { + "formal_name": "Resmi Ad", + "company_type": "Şirket Tipi", + "commercial_type": "Ticari Tip", + "tax_no": "Vergi No", + "public_name": "Halka Açık Ad", + "company_tag": "Şirket Etiketi", + "default_lang_type": "Varsayılan Dil Tipi", + "default_money_type": "Varsayılan Para Tipi", + "official_address_uu_id": "Resmi Adres UU ID", + } + + +class InsertCompany(BaseModelRegular, CompanyValidation): + formal_name: str + company_type: str + commercial_type: str + tax_no: str + public_name: Optional[str] = None + company_tag: Optional[str] = None + default_lang_type: Optional[str] = None + default_money_type: Optional[str] = None + official_address_uu_id: Optional[str] = None + # parent_uu_id: Optional[int] = None + + +class CompanyUpdateValidation: + tr = { + **CompanyValidation.tr, + **PydanticBaseModelValidation.tr, + } + en = { + **CompanyValidation.tr, + **PydanticBaseModelValidation.en, + } + + +class UpdateCompany(PydanticBaseModel, CompanyUpdateValidation): + company_uu_id: str + public_name: Optional[str] = None + formal_name: Optional[str] = None + tax_no: Optional[str] = None + company_tag: Optional[str] = None + default_lang_type: Optional[str] = None + default_money_type: Optional[str] = None + official_address_uu_id: Optional[str] = None + + +class MatchCompany2CompanyValidation: + tr = { + **PydanticBaseModelValidation.tr, + "match_company_uu_id": "Eşleşen Şirket UU ID", + "duty_uu_id": "Görev UU ID", + } + en = { + **PydanticBaseModelValidation.en, + "match_company_uu_id": "Match Company UU ID", + "duty_uu_id": "Duty UU ID", + } + + +class MatchCompany2Company(PydanticBaseModel, MatchCompany2CompanyValidation): + match_company_uu_id: List[str] + duty_uu_id: str + show_only: Optional[bool] = None diff --git a/api_validations/validations_request/core_request_validations.py b/api_validations/validations_request/core_request_validations.py new file mode 100644 index 0000000..37081a4 --- /dev/null +++ b/api_validations/validations_request/core_request_validations.py @@ -0,0 +1,116 @@ +from typing import Optional + +from api_validations.core_validations import BaseModelRegular + + +class ListOptionsValidation: + tr = { + "page": "Sayfa", + "size": "Boyut", + "order_field": "Sıralama Alanı", + "order_type": "Sıralama Türü", + "include_joins": "Alt İçerikleri", + "query": "Sorgu", + } + en = { + "page": "Page", + "size": "Size", + "order_field": "Order Field", + "order_type": "Order Type", + "include_joins": "Include Joins", + "query": "Query", + } + + +class ListOptions(BaseModelRegular, ListOptionsValidation): + page: Optional[int] = 1 + size: Optional[int] = 10 + order_field: Optional[str] = "id" + order_type: Optional[str] = "asc" + include_joins: Optional[list] = None + query: Optional[dict] = None + + +class CrudRecordValidation: + tr = { + "uu_id": "UUID", + "created_at": "Oluşturulma Tarihi", + "updated_at": "Güncellenme Tarihi", + "created_by": "Oluşturan", + "updated_by": "Güncelleyen", + "confirmed_by": "Onaylayan", + "is_confirmed": "Onay", + "expiry_starts": "Geçerlilik Başlangıç Tarihi", + "expiry_ends": "Geçerlilik Bitiş Tarihi", + "active": "Aktif", + "is_notification_send": "Bildirim Gönderildi", + "is_email_send": "E-posta Gönderildi", + } + en = { + "uu_id": "UUID", + "created_at": "Created At", + "updated_at": "Updated At", + "created_by": "Created By", + "updated_by": "Updated By", + "confirmed_by": "Confirmed By", + "is_confirmed": "Confirmed", + "expiry_starts": "Expiry Starts", + "expiry_ends": "Expiry Ends", + "active": "Active", + "is_notification_send": "Notification Send", + "is_email_send": "Email Send", + } + + +class CrudRecords: + uu_id: Optional[str] = None + created_at: Optional[str] = None + updated_at: Optional[str] = None + created_by: Optional[str] = None + updated_by: Optional[str] = None + confirmed_by: Optional[str] = None + is_confirmed: Optional[bool] = None + active: Optional[bool] = None + is_notification_send: Optional[bool] = None + is_email_send: Optional[bool] = None + + +class PydanticBaseModelValidation: + tr = { + "active": "Aktif", + "deleted": "Silinmiş", + "expiry_starts": "Geçerlilik Başlangıç Tarihi", + "expiry_ends": "Geçerlilik Bitiş Tarihi", + "is_confirmed": "Onay", + } + en = { + "active": "Active", + "deleted": "Deleted", + "expiry_starts": "Expiry Starts", + "expiry_ends": "Expiry Ends", + "is_confirmed": "Confirmed", + } + + +class PydanticBaseModel(BaseModelRegular): + + active: Optional[bool] = None + deleted: Optional[bool] = None + expiry_starts: Optional[str] = None + # expiry_ends: Optional[str] = None + is_confirmed: Optional[bool] = None + + +class EndpointPydantic(BaseModelRegular): + data: Optional[dict] = None + + +class EndpointValidation(BaseModelRegular): + endpoint: Optional[str] = None + + +class PatchRecord(BaseModelRegular): + + confirm: Optional[bool] = None + delete: Optional[bool] = None + active: Optional[bool] = None diff --git a/api_validations/validations_request/create_model.py b/api_validations/validations_request/create_model.py new file mode 100644 index 0000000..b16da10 --- /dev/null +++ b/api_validations/validations_request/create_model.py @@ -0,0 +1,73 @@ +import typing + +from datetime import datetime + + +class ConvertField: + + def __init__(self, match, default_val=None): + self.match = match + self.default_val = default_val + + def typing_return(self): + typing_dict = { + "": float, + "": bool, + "": int, + "": str, + "": dict, + "": list, + "": datetime, + "typing.Optional[datetime.datetime]": typing.Optional[datetime], + "typing.Optional[bool]": typing.Optional[bool], + "typing.Optional[list]": typing.Optional[list], + "typing.Optional[str]": typing.Optional[str], + "typing.Optional[int]": typing.Optional[int], + "typing.Optional[float]": typing.Optional[float], + "typing.Optional[dict]": typing.Optional[dict], + } + matches_with = typing_dict.get(self.match, typing.Optional[str]) + default_value = getattr(self.default_val, "field_default_value", None) + return matches_with, default_value + + +# +# def create_model_from_database(model_id: typing.Union[int, str]): +# if isinstance(model_id, int): +# selected_model = Models.find_one(id=model_id) +# else: +# selected_model = Models.find_one(uu_id=str(model_id)) +# +# if not selected_model: +# raise HTTPException( +# status_code=202, +# detail=f"Model {selected_model.model_name} not found in database. Please add model to api.", +# ) +# pydantic_class = getattr(root_validates, selected_model.model_type, None) +# if not pydantic_class: +# raise HTTPException( +# status_code=202, +# detail=f"Pydantic class {selected_model.model_type} not found in database. Please add model to api.", +# ) +# +# model_entities_records = ModelEntities.filter_all( +# ModelEntities.model_id == selected_model.id +# ).data +# +# if not model_entities_records: +# raise HTTPException( +# status_code=202, +# detail="Model has no entities registered. Please add entities to model.", +# ) +# +# fields = {} +# for entity in model_entities_records: +# fields[entity.field_name] = ConvertField( +# entity.field_type, entity.field_default_value +# ).typing_return() +# +# return create_model( +# __model_name=selected_model.model_name, # pydantic_name(User) +# __module__=pydantic_class.__module__, # field_name(uu_id) +# **fields, # field_name = (field_type (Optional[str]), default_value(None)) +# ) diff --git a/api_validations/validations_request/decision_book.py b/api_validations/validations_request/decision_book.py new file mode 100644 index 0000000..1c1f8f4 --- /dev/null +++ b/api_validations/validations_request/decision_book.py @@ -0,0 +1,356 @@ +from typing import Optional +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + PydanticBaseModel, + PydanticBaseModelValidation, + ListOptions, +) + + +class DecisionBookDecisionBookInvitationsValidation: + tr = { + "build_decision_book_uu_id": "Karar Defteri UUID", + "message": "Mesaj", + "planned_date": "Planlanan Tarih", + } + en = { + "build_decision_book_uu_id": "Decision Book UUID", + "message": "Message", + "planned_date": "Planned Date", + } + + +class DecisionBookDecisionBookInvitations( + BaseModelRegular, DecisionBookDecisionBookInvitationsValidation +): + build_decision_book_uu_id: str + message: str + planned_date: str + + +class DecisionBookDecisionBookInvitationsAttendValidation: + tr = { + "token": "Token", + "is_attend": "Katılacak mı?", + } + en = { + "token": "Token", + "is_attend": "Is Attend?", + } + + +class DecisionBookDecisionBookInvitationsAttend( + BaseModelRegular, DecisionBookDecisionBookInvitationsAttendValidation +): + token: str + is_attend: bool + + +class DecisionBookDecisionBookInvitationsAssignValidation: + tr = { + "token": "Token", + "build_living_space_uu_id": "Yapı Yaşam Alanı UUID", + "occupant_type_uu_id": "Sakin Tipi UUID", + } + en = { + "token": "Token", + "build_living_space_uu_id": "Build Living Space UUID", + "occupant_type_uu_id": "Occupant Type UUID", + } + + +class DecisionBookDecisionBookInvitationsAssign( + BaseModelRegular, DecisionBookDecisionBookInvitationsAssignValidation +): + token: str + build_living_space_uu_id: str + occupant_type_uu_id: str + + +class DecisionBookDecisionBookInvitationsUpdateValidation: + tr = { + **PydanticBaseModelValidation.tr, + "token": "Token", + "occupant_type_uu_id": "Sakin Tipi UUID", + } + en = { + **PydanticBaseModelValidation.en, + "token": "Token", + "occupant_type_uu_id": "Occupant Type UUID", + } + + +class DecisionBookDecisionBookInvitationsUpdate( + PydanticBaseModel, DecisionBookDecisionBookInvitationsUpdateValidation +): + token: str + occupant_type_uu_id: Optional[str] = None + + +class ListDecisionBookValidation: + tr = { + "build_decision_book_uu_id": "Karar Defteri UUID", + } + en = { + "build_decision_book_uu_id": "Decision Book UUID", + } + + +class ListDecisionBook(ListOptions, ListDecisionBookValidation): + build_decision_book_uu_id: Optional[str] = None + + +class InsertDecisionBookValidation: + tr = { + **PydanticBaseModelValidation.tr, + "build_uu_id": "Yapı UUID", + "decision_type": "Karar Tipi", + "meeting_date": "Toplantı Tarihi", + "is_out_sourced": "Dış Kaynak mı?", + "resp_company_fix_wage": "Firma Sabit Ücreti", + "resp_company_uu_id": "Firma UUID", + } + en = { + **PydanticBaseModelValidation.en, + "build_uu_id": "Build UUID", + "decision_type": "Decision Type", + "meeting_date": "Meeting Date", + "is_out_sourced": "Is Out Sourced?", + "resp_company_fix_wage": "Company Fixed Wage", + "resp_company_uu_id": "Company UUID", + } + + +class InsertDecisionBook(PydanticBaseModel, InsertDecisionBookValidation): + build_uu_id: str + decision_type: str + meeting_date: str + is_out_sourced: bool + + resp_company_fix_wage: Optional[float] = None + resp_company_uu_id: Optional[str] = None + + +class InsertDecisionBookCompletedValidation: + tr = { + "build_decision_book_uu_id": "Karar Defteri UUID", + "meeting_completed_date": "Toplantı Tamamlanma Tarihi", + } + en = { + "build_decision_book_uu_id": "Decision Book UUID", + "meeting_completed_date": "Meeting Completed Date", + } + + +class InsertDecisionBookCompleted( + BaseModelRegular, InsertDecisionBookCompletedValidation +): + build_decision_book_uu_id: str + meeting_completed_date: str + + +class InsertDecisionBookPersonValidation: + tr = { + "person_uu_id": "Kişi UUID", + "build_decision_book_uu_id": "Karar Defteri UUID", + "management_typecode_uu_id": "Yönetim Tipi UUID", + "dues_discount_approval_date": "Aidat İndirim Onay Tarihi", + "dues_fix_discount": "Aidat Sabit İndirim", + "dues_percent_discount": "Aidat Yüzde İndirim", + } + en = { + "person_uu_id": "Person UUID", + "build_decision_book_uu_id": "Decision Book UUID", + "management_typecode_uu_id": "Management Type UUID", + "dues_discount_approval_date": "Dues Discount Approval Date", + "dues_fix_discount": "Dues Fix Discount", + "dues_percent_discount": "Dues Percent Discount", + } + + +class InsertDecisionBookPerson(BaseModelRegular, InsertDecisionBookPersonValidation): + person_uu_id: str + build_decision_book_uu_id: str + management_typecode_uu_id: str + + dues_discount_approval_date: Optional[str] = None + dues_fix_discount: Optional[float] = None + dues_percent_discount: Optional[int] = None + + +class UpdateDecisionBookPersonValidation: + tr = { + **PydanticBaseModelValidation.tr, + "dues_fix_discount": "Aidat Sabit İndirim", + "dues_percent_discount": "Aidat Yüzde İndirim", + } + en = { + **PydanticBaseModelValidation.en, + "dues_fix_discount": "Dues Fix Discount", + "dues_percent_discount": "Dues Percent Discount", + } + + +class UpdateDecisionBookPerson(PydanticBaseModel, UpdateDecisionBookPersonValidation): + + dues_fix_discount: Optional[float] = None + dues_percent_discount: Optional[int] = None + + +class RemoveDecisionBookPersonValidation: + tr = { + "person_uu_id": "Kişi UUID", + "build_decision_book_person_uu_id": "Karar Defteri Kişi UUID", + } + en = { + "person_uu_id": "Person UUID", + "build_decision_book_person_uu_id": "Decision Book Person UUID", + } + + +class RemoveDecisionBookPerson(PydanticBaseModel, RemoveDecisionBookPersonValidation): + person_uu_id: str + build_decision_book_person_uu_id: str + + +class UpdateDecisionBookValidation: + tr = { + **PydanticBaseModelValidation.tr, + "decision_book_pdf_path": "Karar Defteri PDF Yolu", + "is_out_sourced": "Dış Kaynak mı?", + "contact_agreement_path": "İletişim Anlaşma Yolu", + "contact_agreement_date": "İletişim Anlaşma Tarihi", + "meeting_date": "Toplantı Tarihi", + "decision_type": "Karar Tipi", + "resp_company_fix_wage": "Firma Sabit Ücreti", + "resp_company_uu_id": "Firma UUID", + } + en = { + **PydanticBaseModelValidation.en, + "decision_book_pdf_path": "Decision Book PDF Path", + "is_out_sourced": "Is Out Sourced?", + "contact_agreement_path": "Contact Agreement Path", + "contact_agreement_date": "Contact Agreement Date", + "meeting_date": "Meeting Date", + "decision_type": "Decision Type", + "resp_company_fix_wage": "Company Fixed Wage", + "resp_company_uu_id": "Company UUID", + } + + +class UpdateDecisionBook(PydanticBaseModel, UpdateDecisionBookValidation): + decision_book_pdf_path: Optional[str] = None + is_out_sourced: Optional[bool] = None + contact_agreement_path: Optional[str] = None + contact_agreement_date: Optional[str] = None + meeting_date: Optional[str] = None + decision_type: Optional[str] = None + + resp_company_fix_wage: Optional[float] = None + resp_company_uu_id: Optional[str] = None + + +class InsertBuildDecisionBookItemsValidation: + tr = { + "token": "Token", + "info_type_uu_id": "Bilgi Tipi UUID", + "item_comment": "Öğe Yorumu / Açıklama", + "currency": "Para Birimi", + "unit_type": "Birim Tipi", + "debit_start_date": "Borç Başlangıç Tarihi", + "debit_end_date": "Borç Bitiş Tarihi", + "unit_price_is_fixed": "Birim Fiyat Sabit mi?", + "unit_price": "Birim Fiyat", + } + en = { + "token": "Token", + "info_type_uu_id": "Info Type UUID", + "item_comment": "Item Comment", + "currency": "Currency", + "unit_type": "Unit Type", + "debit_start_date": "Debit Start Date", + "debit_end_date": "Debit End Date", + "unit_price_is_fixed": "Unit Price Is Fixed?", + "unit_price": "Unit Price", + } + + +class InsertBuildDecisionBookItems( + BaseModelRegular, InsertBuildDecisionBookItemsValidation +): + token: str + info_type_uu_id: str + item_comment: str + + currency: Optional[str] = "TL" + unit_type: Optional[str] = "M2" + debit_start_date: Optional[str] = None + debit_end_date: Optional[str] = None + unit_price_is_fixed: Optional[bool] = False + unit_price: Optional[float] = 0.00 + + # build_decision_book_uu_id: str + # item_objection: Optional[str] = None + + +class UpdateBuildDecisionBookItemsValidation: + tr = { + **PydanticBaseModelValidation.tr, + "item_comment": "Öğe Yorumu / Açıklama", + "item_objection": "Öğe İtirazı", + } + en = { + **PydanticBaseModelValidation.en, + "item_comment": "Item Comment", + "item_objection": "Item Objection", + } + + +class UpdateBuildDecisionBookItems( + PydanticBaseModel, UpdateBuildDecisionBookItemsValidation +): + item_comment: Optional[str] = None + item_objection: Optional[str] = None + + +class InsertBuildDecisionBookItemDebitsValidation: + tr = { + "build_decision_book_item_uu_id": "Karar Defteri Öğe UUID", + "dues_values": "Aidat Değerleri", + } + en = { + "build_decision_book_item_uu_id": "Decision Book Item UUID", + "dues_values": "Dues Values", + } + + +class InsertBuildDecisionBookItemDebits( + BaseModelRegular, InsertBuildDecisionBookItemDebitsValidation +): + build_decision_book_item_uu_id: str + dues_values: dict + # dues_types_uu_id: str + # decision_taken: Optional[bool] = None + + +class UpdateBuildDecisionBookItemDebitsValidation: + tr = { + **PydanticBaseModelValidation.tr, + "dues_types_uu_id": "Aidat Tipi UUID", + "dues_values": "Aidat Değerleri", + "decision_taken": "Karar Alındı mı?", + } + en = { + **PydanticBaseModelValidation.en, + "dues_types_uu_id": "Dues Type UUID", + "dues_values": "Dues Values", + "decision_taken": "Decision Taken?", + } + + +class UpdateBuildDecisionBookItemDebits( + PydanticBaseModel, UpdateBuildDecisionBookItemDebitsValidation +): + dues_types_uu_id: Optional[str] = None + dues_values: Optional[dict] = None + decision_taken: Optional[bool] = None diff --git a/api_validations/validations_request/departments.py b/api_validations/validations_request/departments.py new file mode 100644 index 0000000..03c61e1 --- /dev/null +++ b/api_validations/validations_request/departments.py @@ -0,0 +1,40 @@ +from typing import Optional +from api_validations.validations_request import ( + PydanticBaseModel, + PydanticBaseModelValidation, +) + + +class DepartmentsPydanticValidation: + tr = { + "department_code": "Department Kodu", + "department_name": "Departman Adı", + "department_description": "Departman Açıklaması", + "company_uu_id": "Şirket UUID", + "parent_department_uu_id": "Üst Departman UUID", + } + en = { + "department_code": "Department Code", + "department_name": "Department Name", + "department_description": "Department Description", + "company_uu_id": "Company UUID", + "parent_department_uu_id": "Parent Department UUID", + } + + +class DepartmentsPydantic(PydanticBaseModel, PydanticBaseModelValidation): + + department_code: Optional[str] + department_name: Optional[str] + department_description: Optional[str] = None + company_uu_id: Optional[str] = None + parent_department_uu_id: Optional[int] = None + + +# class UpdateDepartments(PydanticBaseModel): +# +# department_code: Optional[str] = None +# department_name: Optional[str] = None +# department_description: Optional[str] = None +# company_uu_id: Optional[str] = None +# parent_department_uu_id: Optional[int] = None diff --git a/api_validations/validations_request/employee.py b/api_validations/validations_request/employee.py new file mode 100644 index 0000000..163928a --- /dev/null +++ b/api_validations/validations_request/employee.py @@ -0,0 +1,251 @@ +from typing import Optional +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + PydanticBaseModel, + PydanticBaseModelValidation, +) + + +class BindEmployees2PeopleValidation: + tr = { + **PydanticBaseModelValidation.tr, + "staff_uu_id": "Kadro UUID", + "people_uu_id": "Kişi UUID", + "expiry_starts": "Başlangıç Tarihi", + } + en = { + **PydanticBaseModelValidation.en, + "staff_uu_id": "Staff UUID", + "people_uu_id": "People UUID", + "expiry_starts": "Start Date", + } + + +class BindEmployees2People(PydanticBaseModel, BindEmployees2PeopleValidation): + staff_uu_id: str + people_uu_id: str + expiry_starts: Optional[str] = None + + +class UnBindEmployees2PeopleValidation: + tr = { + **PydanticBaseModelValidation.tr, + "people_uu_id": "Kişi UUID", + "expiry_ends": "Bitiş Tarihi", + } + en = { + **PydanticBaseModelValidation.en, + "people_uu_id": "People UUID", + "expiry_ends": "End Date", + } + + +class UnBindEmployees2People(PydanticBaseModel, UnBindEmployees2PeopleValidation): + people_uu_id: str + expiry_ends: str + + +class InsertEmployeesValidation: + tr = { + "staff_uu_id": "Kadro UUID", + "people_uu_id": "Kişi UUID", + } + en = { + "staff_uu_id": "Staff UUID", + "people_uu_id": "People UUID", + } + + +class InsertEmployees(BaseModelRegular, InsertEmployeesValidation): + staff_uu_id: str + people_uu_id: Optional[str] = None + + +class InsertCompanyDutyValidation: + tr = { + "duty_code": "Görev Kodu", + "duty_name": "Görev Adı", + "duty_description": "Görev Açıklaması", + } + en = { + "duty_code": "Duty Code", + "duty_name": "Duty Name", + "duty_description": "Duty Description", + } + + +class InsertCompanyDuty(BaseModelRegular, InsertCompanyDutyValidation): + duty_code: str + duty_name: str + duty_description: Optional[str] = None + + +class SelectDutiesValidation: + tr = { + "duty_uu_id": "Görev UUID", + } + en = { + "duty_uu_id": "Duty UUID", + } + + +class SelectDuties(BaseModelRegular, SelectDutiesValidation): + duty_uu_id: Optional[str] = None + + +class InsertDutiesValidation: + tr = { + "duties_uu_id": "Görev UUID", + "department_uu_id": "Departman UUID", + "is_default_duty": "Varsayılan Görev", + } + en = { + "duties_uu_id": "Duty UUID", + "department_uu_id": "Department UUID", + "is_default_duty": "Default Duty", + } + + +class InsertDuties(BaseModelRegular, InsertDutiesValidation): + duties_uu_id: str + department_uu_id: str + is_default_duty: Optional[bool] = False + + +class UpdateDutiesValidation: + tr = { + **PydanticBaseModelValidation.tr, + "duties_uu_id": "Görev UUID", + "department_uu_id": "Departman UUID", + "is_default_duty": "Varsayılan Görev", + } + en = { + **PydanticBaseModelValidation.en, + "duties_uu_id": "Duty UUID", + "department_uu_id": "Department UUID", + "is_default_duty": "Default Duty", + } + + +class UpdateDuties(PydanticBaseModel): + duties_uu_id: Optional[str] = None + department_uu_id: Optional[str] = None + is_default_duty: Optional[bool] = None + + +class UpdateCompanyDutyValidation: + tr = { + **PydanticBaseModelValidation.tr, + "duty_code": "Görev Kodu", + "duty_name": "Görev Adı", + "duty_description": "Görev Açıklaması", + } + en = { + **PydanticBaseModelValidation.en, + "duty_code": "Duty Code", + "duty_name": "Duty Name", + "duty_description": "Duty Description", + } + + +class UpdateCompanyDuty(PydanticBaseModel): + duty_code: Optional[str] = None + duty_name: Optional[str] = None + duty_description: Optional[str] = None + + +class InsertCompanyEmployeesSalariesValidation: + tr = { + "gross_salary": "Brüt Maaş", + "net_salary": "Net Maaş", + "start_date": "Başlangıç Tarihi", + "stop_date": "Bitiş Tarihi", + "people_id": "Kişi ID", + } + en = { + "gross_salary": "Gross Salary", + "net_salary": "Net Salary", + "start_date": "Start Date", + "stop_date": "Stop Date", + "people_id": "People ID", + } + + +class InsertCompanyEmployeesSalaries(BaseModelRegular): + gross_salary: float + net_salary: float + start_date: str + stop_date: Optional[str] = None + people_id: int + + +class UpdateCompanyEmployeesSalariesValidation: + tr = { + **PydanticBaseModelValidation.tr, + "gross_salary": "Brüt Maaş", + "net_salary": "Net Maaş", + "start_date": "Başlangıç Tarihi", + "stop_date": "Bitiş Tarihi", + "people_id": "Kişi ID", + } + en = { + **PydanticBaseModelValidation.en, + "gross_salary": "Gross Salary", + "net_salary": "Net Salary", + "start_date": "Start Date", + "stop_date": "Stop Date", + "people_id": "People ID", + } + + +class UpdateCompanyEmployeesSalaries(PydanticBaseModel): + gross_salary: Optional[float] = None + net_salary: Optional[float] = None + start_date: Optional[str] = None + stop_date: Optional[str] = None + people_id: Optional[int] = None + + +class InsertCompanyEmployeesValidation: + tr = { + "employee_description": "Çalışan Açıklaması", + "person_uu_id": "Kişi UUID", + "duty_uu_id": "Görev UUID", + "start_date": "Başlangıç Tarihi", + "stop_date": "Bitiş Tarihi", + } + en = { + "employee_description": "Employee Description", + "person_uu_id": "Person UUID", + "duty_uu_id": "Duty UUID", + "start_date": "Start Date", + "stop_date": "Stop Date", + } + + +class InsertCompanyEmployees(BaseModelRegular, InsertCompanyEmployeesValidation): + + employee_description: Optional[str] = None + person_uu_id: str + duty_uu_id: str + + start_date: Optional[str] = None + stop_date: Optional[str] = None + + +class UpdateCompanyEmployeesValidation: + tr = { + **PydanticBaseModelValidation.tr, + "stop_date": "Bitiş Tarihi", + "employee_description": "Çalışan Açıklaması", + } + en = { + **PydanticBaseModelValidation.en, + "stop_date": "Stop Date", + "employee_description": "Employee Description", + } + + +class UpdateCompanyEmployees(PydanticBaseModel, UpdateCompanyEmployeesValidation): + stop_date: Optional[str] = None + employee_description: Optional[str] = None diff --git a/api_validations/validations_request/events.py b/api_validations/validations_request/events.py new file mode 100644 index 0000000..0cfe276 --- /dev/null +++ b/api_validations/validations_request/events.py @@ -0,0 +1,37 @@ +from typing import Optional +from api_validations.core_validations import BaseModelRegular + + +class RegisterEvents2EmployeeValidation: + tr = { + "event_uu_id_list": "Etkinlikler Listesi", + "employee_uu_id": "Çalışan UU ID", + } + en = { + "event_uu_id_list": "Event List", + "employee_uu_id": "Employee UU ID", + } + + +class RegisterEvents2Employee(BaseModelRegular, RegisterEvents2EmployeeValidation): + event_uu_id_list: list[str] = None + employee_uu_id: Optional[str] = None + + +class RegisterEvents2OccupantValidation: + tr = { + "event_uu_id_list": "Etkinlikler Listesi", + "build_part_uu_id": "Bina Parça UU ID", + "occupant_uu_id": "Apartman Sakini UU ID", + } + en = { + "event_uu_id_list": "Event List", + "build_part_uu_id": "Building Part UU ID", + "occupant_uu_id": "Occupant UU ID", + } + + +class RegisterEvents2Occupant(BaseModelRegular, RegisterEvents2OccupantValidation): + event_uu_id_list: list[str] = None + build_part_uu_id: Optional[str] = None + occupant_uu_id: Optional[str] = None diff --git a/api_validations/validations_request/modules.py b/api_validations/validations_request/modules.py new file mode 100644 index 0000000..42076d3 --- /dev/null +++ b/api_validations/validations_request/modules.py @@ -0,0 +1,36 @@ +from api_validations.core_validations import BaseModelRegular + + +class RegisterModules2OccupantValidation: + tr = { + "modules_uu_id": "Modül Listesi", + "occupant_uu_id": "Mülk Sahibi", + "build_part_uu_id": "Daire UUID", + } + en = { + "modules_uu_id": "Module List", + "occupant_uu_id": "Occupant", + "build_part_uu_id": "Flat UUID", + } + + +class RegisterModules2Occupant(BaseModelRegular, RegisterModules2OccupantValidation): + modules_uu_id: str + occupant_uu_id: str + build_part_uu_id: str + + +class RegisterModules2EmployeeValidation: + tr = { + "modules_uu_id": "Modül Listesi", + "employee_uu_id": "Çalışan", + } + en = { + "modules_uu_id": "Module List", + "employee_uu_id": "Employee", + } + + +class RegisterModules2Employee(BaseModelRegular, RegisterModules2EmployeeValidation): + modules_uu_id: str + employee_uu_id: str diff --git a/api_validations/validations_request/people.py b/api_validations/validations_request/people.py new file mode 100644 index 0000000..36182ec --- /dev/null +++ b/api_validations/validations_request/people.py @@ -0,0 +1,98 @@ +from typing import Optional +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + PydanticBaseModel, + PydanticBaseModelValidation, +) + + +class InsertPersonValidation: + tr = { + "firstname": "İsim", + "surname": "Soyisim", + "sex_code": "Cinsiyet", + "national_identity_id": "T.C. Kimlik Numarası", + "middle_name": "Orta İsim", + "father_name": "Baba Adı", + "mother_name": "Anne Adı", + "country_code": "Ülke Kodu", + "birth_place": "Doğum Yeri", + "birth_date": "Doğum Tarihi", + "tax_no": "Vergi Numarası", + "ref_id": "Referans ID", + } + + +class InsertPerson(BaseModelRegular, InsertPersonValidation): + firstname: str + surname: str + sex_code: str + national_identity_id: str + middle_name: Optional[str] = None + father_name: Optional[str] = None + mother_name: Optional[str] = None + country_code: Optional[str] = "TR" + birth_place: Optional[str] = None + birth_date: Optional[str] = None + tax_no: Optional[str] = None + ref_id: Optional[str] = None + + +class UpdatePersonValidation: + tr = { + **PydanticBaseModelValidation.tr, + **InsertPersonValidation.tr, + } + en = { + **PydanticBaseModelValidation.en, + **InsertPersonValidation.tr, + } + + +class UpdatePerson(PydanticBaseModel, UpdatePersonValidation): + firstname: Optional[str] = None + surname: Optional[str] = None + middle_name: Optional[str] + father_name: Optional[str] = None + mother_name: Optional[str] = None + sex_code: Optional[str] = None + country_code: Optional[str] = None + national_identity_id: Optional[str] = None + birth_place: Optional[str] = None + birth_date: Optional[str] = None + tax_no: Optional[str] = None + + +# +# class QueryPeople(PydanticBaseModel): +# uu_id: Optional[str] = None +# +# +# class InsertPeople(PydanticBaseModel): +# key_id: Optional[str] = None +# query: Optional[dict] = None +# data: Optional[_InsertPerson] = None +# +# +# class UpdatePeople(PydanticBaseModel): +# key_id: Optional[str] = None +# query: Optional[QueryPeople] = None +# data: Optional[_UpdatePerson] = None +# +# +# class DeletePeople(PydanticBaseModel): +# key_id: Optional[str] = None +# query: Optional[List[QueryPeople]] = None +# data: Optional[dict] = None +# +# +# class ListPeople(PydanticBaseModel): +# key_id: Optional[str] = None +# query: Optional[QueryPeople] = None +# data: Optional[ListOptions] = None +# +# +# class ActivePeople(PydanticBaseModel): +# key_id: Optional[str] = None +# query: Optional[List[QueryPeople]] = None +# data: Optional[dict] = None diff --git a/api_validations/validations_request/project_decision_book.py b/api_validations/validations_request/project_decision_book.py new file mode 100644 index 0000000..71fc1e4 --- /dev/null +++ b/api_validations/validations_request/project_decision_book.py @@ -0,0 +1,276 @@ +from typing import Optional +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + PydanticBaseModel, + PydanticBaseModelValidation, +) + + +class InsertBuildDecisionBookProjectItemsValidation: + tr = { + "build_decision_book_project_uu_id": "Proje UUID", + "item_header": "Başlık", + "item_comment": "Açıklama", + "attachment_pdf_path": "Ek Dosya Yolu", + "item_objection": "İtiraz", + } + en = { + "build_decision_book_project_uu_id": "Project UUID", + "item_header": "Header", + "item_comment": "Comment", + "attachment_pdf_path": "Attachment PDF Path", + "item_objection": "Objection", + } + + +class InsertBuildDecisionBookProjectItems( + BaseModelRegular, InsertBuildDecisionBookProjectItemsValidation +): + build_decision_book_project_uu_id: str + item_header: str + item_comment: str + attachment_pdf_path: Optional[str] = None + item_objection: Optional[str] = None + + +class UpdateBuildDecisionBookProjectItemsValidation: + tr = { + **InsertBuildDecisionBookProjectItemsValidation.tr, + **PydanticBaseModelValidation.tr, + } + en = { + **InsertBuildDecisionBookProjectItemsValidation.en, + **PydanticBaseModelValidation.en, + } + + +class UpdateBuildDecisionBookProjectItems(PydanticBaseModel): + item_header: Optional[str] = None + item_comment: Optional[str] = None + attachment_pdf_path: Optional[str] = None + item_estimated_cost: Optional[float] = None + build_decision_book_project_uu_id: Optional[str] = None + + +class InsertBuildDecisionBookProjectPersonValidation: + tr = { + "dues_percent_discount": "İskonto Oranı", + "job_fix_wage": "Sabit Ücret", + "bid_price": "Teklif Fiyatı", + "decision_price": "Karar Fiyatı", + "build_decision_book_project_uu_id": "Proje UUID", + "living_space_uu_id": "Yaşam Alanı UUID", + "project_team_type_uu_id": "Proje Takım Tipi UUID", + } + en = { + "dues_percent_discount": "Discount Rate", + "job_fix_wage": "Fixed Wage", + "bid_price": "Bid Price", + "decision_price": "Decision Price", + "build_decision_book_project_uu_id": "Project UUID", + "living_space_uu_id": "Living Space UUID", + "project_team_type_uu_id": "Project Team Type UUID", + } + + +class InsertBuildDecisionBookProjectPerson( + BaseModelRegular, InsertBuildDecisionBookProjectPersonValidation +): + dues_percent_discount: Optional[int] = None + job_fix_wage: Optional[float] = None + bid_price: Optional[float] = None + decision_price: Optional[float] = None + build_decision_book_project_uu_id: str + living_space_uu_id: str + project_team_type_uu_id: str + + +class UpdateBuildDecisionBookProjectPersonValidation: + tr = { + **InsertBuildDecisionBookProjectPersonValidation.tr, + **PydanticBaseModelValidation.tr, + } + en = { + **InsertBuildDecisionBookProjectPersonValidation.en, + **PydanticBaseModelValidation.en, + } + + +class UpdateBuildDecisionBookProjectPerson( + PydanticBaseModel, UpdateBuildDecisionBookProjectPersonValidation +): + dues_percent_discount: Optional[int] = None + job_fix_wage: Optional[float] = None + bid_price: Optional[float] = None + decision_price: Optional[float] = None + build_decision_book_project_uu_id: Optional[str] = None + living_space_uu_id: Optional[str] = None + project_team_type_uu_id: Optional[str] = None + + +class InsertBuildDecisionBookProjectsValidation: + tr = { + "build_decision_book_item_uu_id": "Karar Defteri UUID", + "project_responsible_person_uu_id": "Proje Sorumlu Kişi UUID", + "project_name": "Proje Adı", + "project_start_date": "Proje Başlangıç Tarihi", + "project_stop_date": "Proje Bitiş Tarihi", + "project_type": "Proje Tipi", + "is_out_sourced": "Dış Kaynak Kullanımı", + "project_note": "Proje Notu", + "decision_book_pdf_path": "Karar Defteri PDF Yolu", + "resp_company_fix_wage": "Firma Sabit Ücreti", + "contact_agreement_path": "İletişim Anlaşması Yolu", + "contact_agreement_date": "İletişim Anlaşması Tarihi", + "meeting_date": "Toplantı Tarihi", + "currency": "Para Birimi", + "bid_price": "Teklif Fiyatı", + "resp_company_uu_id": "Firma UUID", + } + en = { + "build_decision_book_item_uu_id": "Decision Book UUID", + "project_responsible_person_uu_id": "Project Responsible Person UUID", + "project_name": "Project Name", + "project_start_date": "Project Start Date", + "project_stop_date": "Project Stop Date", + "project_type": "Project Type", + "is_out_sourced": "Out Sourced", + "project_note": "Project Note", + "decision_book_pdf_path": "Decision Book PDF Path", + "resp_company_fix_wage": "Company Fixed Wage", + "contact_agreement_path": "Contact Agreement Path", + "contact_agreement_date": "Contact Agreement Date", + "meeting_date": "Meeting Date", + "currency": "Currency", + "bid_price": "Bid Price", + "resp_company_uu_id": "Company UUID", + } + + +class InsertBuildDecisionBookProjects( + BaseModelRegular, InsertBuildDecisionBookProjectsValidation +): + build_decision_book_item_uu_id: str + project_responsible_person_uu_id: str + project_name: str + project_start_date: str + project_stop_date: str + project_type: str + + is_out_sourced: Optional[bool] = False + project_note: Optional[str] = None + decision_book_pdf_path: Optional[str] = None + resp_company_fix_wage: Optional[float] = None + contact_agreement_path: Optional[str] = None + contact_agreement_date: Optional[str] = None + meeting_date: Optional[str] = None + currency: Optional[str] = None + bid_price: Optional[float] = None + resp_company_uu_id: Optional[str] = None + + +class UpdateBuildDecisionBookProjectsValidation: + tr = { + **InsertBuildDecisionBookProjectsValidation.tr, + **PydanticBaseModelValidation.tr, + } + en = { + **InsertBuildDecisionBookProjectsValidation.en, + **PydanticBaseModelValidation.en, + } + + +class UpdateBuildDecisionBookProjects( + PydanticBaseModel, UpdateBuildDecisionBookProjectsValidation +): + build_decision_book_project_uu_id: str + is_out_sourced: Optional[bool] = False + project_note: Optional[str] = None + # decision_book_pdf_path: Optional[str] = None + status_id: Optional[int] = None + resp_company_fix_wage: Optional[float] = None + contact_agreement_path: Optional[str] = None + contact_agreement_date: Optional[str] = None + contact_uu_id: Optional[str] = None + resp_company_uu_id: Optional[str] = None + approved_price: Optional[float] = None + + +class ApprovalsBuildDecisionBookProjectsValidation: + tr = { + "build_decision_book_project_uu_id": "Karar Defteri Proje UUID", + "project_stop_date": "Proje Bitiş Tarihi", + "status_code": "Durum Kodu", + "final_price_list": "Son Fiyat Listesi", + } + en = { + "build_decision_book_project_uu_id": "Decision Book Project UUID", + "project_stop_date": "Project Stop Date", + "status_code": "Status Code", + "final_price_list": "Final Price List", + } + + +class ApprovalsBuildDecisionBookProjects( + PydanticBaseModel, ApprovalsBuildDecisionBookProjectsValidation +): + build_decision_book_project_uu_id: str + project_stop_date: str + status_code: Optional[int] = None + final_price_list: Optional[list[dict]] = ( + None # {"date": "2021-01-01", "price": 1000} + ) + + +class InsertBuildDecisionBookProjectItemDebitsValidation: + tr = { + "build_decision_book_project_item_uu_id": "Karar Defteri Proje Öğe UUID", + "payment_date": "Ödeme Tarihi", + "dues_values": "Borç Değerleri", + "is_official": "Resmi Mi?", + "discount_value": "İskonto Oranı", + "discount_fix": "İskonto Sabit", + "decision_taken": "Karar Alındı Mı?", + } + en = { + "build_decision_book_project_item_uu_id": "Decision Book Project Item UUID", + "payment_date": "Payment Date", + "dues_values": "Dues Values", + "is_official": "Is Official?", + "discount_value": "Discount Rate", + "discount_fix": "Discount Fix", + "decision_taken": "Decision Taken?", + } + + +class InsertBuildDecisionBookProjectItemDebits( + PydanticBaseModel, InsertBuildDecisionBookProjectItemDebitsValidation +): + build_decision_book_project_item_uu_id: str + payment_date: str + dues_values: dict + is_official: Optional[bool] = False + discount_value: Optional[float] = None + discount_fix: Optional[float] = None + decision_taken: Optional[bool] = None + + +class UpdateBuildDecisionBookProjectItemDebitsValidation: + tr = { + **InsertBuildDecisionBookProjectItemDebitsValidation.tr, + **PydanticBaseModelValidation.tr, + } + en = { + **InsertBuildDecisionBookProjectItemDebitsValidation.en, + **PydanticBaseModelValidation.en, + } + + +class UpdateBuildDecisionBookProjectItemDebits( + PydanticBaseModel, UpdateBuildDecisionBookProjectItemDebitsValidation +): + dues_values: Optional[str] = None + discount_value: Optional[float] = None + discount_fix: Optional[float] = None + decision_taken: Optional[bool] = None + is_official: Optional[bool] = None diff --git a/api_validations/validations_request/rules.py b/api_validations/validations_request/rules.py new file mode 100644 index 0000000..8350baa --- /dev/null +++ b/api_validations/validations_request/rules.py @@ -0,0 +1,24 @@ +from typing import Optional, List +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + PydanticBaseModel, +) + + +class CheckEndpointAccess(BaseModelRegular): + endpoint: str + +class InsertEndpointAccess(PydanticBaseModel): + duty_uu_id: str + endpoint_restriction_list_uu_ids: list + + +class UpdateEndpointAccess(PydanticBaseModel): + endpoint_restriction_uu_id: Optional[str] = None + deleted: Optional[bool] = None + active: Optional[bool] = None + is_confirmed: Optional[bool] = None + + +class UpdateEndpointAccessList(PydanticBaseModel): + endpoint_restriction_list: List[UpdateEndpointAccess] diff --git a/api_validations/validations_request/services.py b/api_validations/validations_request/services.py new file mode 100644 index 0000000..6ce55b4 --- /dev/null +++ b/api_validations/validations_request/services.py @@ -0,0 +1,36 @@ +from api_validations.core_validations import BaseModelRegular + + +class RegisterServices2OccupantValidation: + tr = { + "service_uu_id": "Hizmet UUID", + "occupant_uu_id": "Müşteri UUID", + "build_part_uu_id": "Bina Parça UUID", + } + en = { + "service_uu_id": "Service UUID", + "occupant_uu_id": "Occupant UUID", + "build_part_uu_id": "Building Part UUID", + } + + +class RegisterServices2Occupant(BaseModelRegular, RegisterServices2OccupantValidation): + service_uu_id: str + occupant_uu_id: str + build_part_uu_id: str + + +class RegisterServices2EmployeeValidation: + tr = { + "service_uu_id": "Hizmet UUID", + "employee_uu_id": "Personel UUID", + } + en = { + "service_uu_id": "Service UUID", + "employee_uu_id": "Employee UUID", + } + + +class RegisterServices2Employee(BaseModelRegular, RegisterServices2EmployeeValidation): + service_uu_id: str + employee_uu_id: str diff --git a/api_validations/validations_request/staff.py b/api_validations/validations_request/staff.py new file mode 100644 index 0000000..6222b2d --- /dev/null +++ b/api_validations/validations_request/staff.py @@ -0,0 +1,42 @@ +from typing import Optional +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + PydanticBaseModel, +) + + +class InsertStaffValidation: + tr = { + "staff_name": "Kadro Adı", + "staff_description": "Kadro Açıklaması", + "staff_code": "Kadro Kodu", + "duties_uu_id": "Görev UUID", + } + en = { + "staff_name": "Staff Name", + "staff_description": "Staff Description", + "staff_code": "Staff Code", + "duties_uu_id": "Duties UUID", + } + + +class InsertStaff(BaseModelRegular, InsertStaffValidation): + + staff_name: str + staff_description: Optional[str] = None + staff_code: Optional[str] = None + duties_uu_id: str + + +class SelectStaffValidation: + tr = { + "duties_uu_id": "Görev UUID", + } + en = { + "duties_uu_id": "Duties UUID", + } + + +class SelectStaff(PydanticBaseModel, SelectStaffValidation): + + duties_uu_id: str diff --git a/api_validations/validations_request/user.py b/api_validations/validations_request/user.py new file mode 100644 index 0000000..99f89c8 --- /dev/null +++ b/api_validations/validations_request/user.py @@ -0,0 +1,70 @@ +from typing import Optional +from api_validations.validations_request import ( + PydanticBaseModel, +) + + +class InsertUsersValidation: + tr = { + "people_uu_id": "Kişi UUID", + "user_tag": "Kullanıcı Etiketi", + "email": "E-posta", + "phone_number": "Telefon Numarası", + "avatar": "Avatar", + } + en = { + "people_uu_id": "People UUID", + "user_tag": "User Tag", + "email": "Email", + "phone_number": "Phone Number", + "avatar": "Avatar", + } + + +class InsertUsers(PydanticBaseModel, InsertUsersValidation): + people_uu_id: str + user_tag: str + email: Optional[str] = None + phone_number: Optional[str] = None + avatar: Optional[str] = None + + +class UpdateUsersValidation: + tr = { + "people_uu_id": "Kişi UUID", + "nick_name": "Kullanıcı Etiketi", + "domain_name": "Domain Adı", + "email": "E-posta", + "phone_number": "Telefon Numarası", + "avatar": "Avatar", + } + en = { + "people_uu_id": "People UUID", + "nick_name": "User Tag", + "domain_name": "Domain Name", + "email": "Email", + "phone_number": "Phone Number", + "avatar": "Avatar", + } + + +class UpdateUsers(PydanticBaseModel, UpdateUsersValidation): + people_uu_id: Optional[str] = None + nick_name: Optional[str] = None + domain_name: Optional[str] = None + email: Optional[str] = None + phone_number: Optional[str] = None + avatar: Optional[str] = None + + +class QueryUsersValidation: + tr = { + "uu_id": "UUID", + } + en = { + "uu_id": "UUID", + } + + +class QueryUsers(PydanticBaseModel): + uu_id: Optional[str] = None diff --git a/api_validations/validations_response/__init__.py b/api_validations/validations_response/__init__.py new file mode 100644 index 0000000..8e139ff --- /dev/null +++ b/api_validations/validations_response/__init__.py @@ -0,0 +1,5 @@ +from .building import ListBuildingResponse + +__all__ = [ + "ListBuildingResponse", +] diff --git a/api_validations/validations_response/account.py b/api_validations/validations_response/account.py new file mode 100644 index 0000000..4a560e6 --- /dev/null +++ b/api_validations/validations_response/account.py @@ -0,0 +1,136 @@ +from typing import Optional +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + CrudRecordValidation, + CrudRecords, +) + + +class AccountListValidation: + tr = { + **CrudRecordValidation.tr, + "iban": "IBAN Numarası", + "bank_date": "Banka İşlem Tarihi", + "currency_value": "Para Birimi Değeri", + "bank_balance": "Banka Bakiyesi", + "currency": "Para Birimi Birimi", + "additional_balance": "Ek Bakiye", + "channel_branch": "Şube Banka", + "process_name": "Banka İşlem Türü Adı", + "process_type": "Banka İşlem Türü", + "process_comment": "İşlem Kayıt Yorumu", + "process_garbage": "İşlem Kayıt Çöpü", + "bank_reference_code": "Banka Referans Kodu", + "add_comment_note": "Yorum Not Ekle", + "is_receipt_mail_send": "Makbuz Posta Gönderildi", + "found_from": "Bulunduğu Yer", + "similarity": "Benzerlik", + "remainder_balance": "Kalan Bakiye", + "bank_date_y": "Banka İşlem Yılı", + "bank_date_m": "Banka İşlem Ayı", + "bank_date_w": "Banka İşlem Haftası", + "bank_date_d": "Banka İşlem Günü", + "approving_accounting_record": "Onaylayan Muhasebe Kaydı", + "accounting_receipt_date": "Muhasebe Makbuz Tarihi", + "accounting_receipt_number": "Muhasebe Makbuz Numarası", + "approved_record": "Onaylanmış Kayıt", + "import_file_name": "İçe Aktarım Dosya Adı", + "receive_debit": "Alacak Borç", + "receive_debit_uu_id": "Alacak Borç UU Kimliği", + "budget_type": "Bütçe Türü", + "budget_type_uu_id": "Bütçe Türü UU Kimliği", + "company_uu_id": "Şirket UU Kimliği", + "send_company_uu_id": "Şirket UU Kimliği Gönder", + "send_person_uu_id": "Kişi UU Kimliği Gönder", + "approving_accounting_person_uu_id": "Onaylayan Muhasebe Kişi UU Kimliği", + "living_space_uu_id": "Yaşam Alanı UU Kimliği", + "customer_uu_id": "Müşteri UU Kimliği", + "build_uu_id": "Yapı UU Kimliği", + "build_parts_uu_id": "Yapı Parça UU Kimliği", + "build_decision_book_uu_id": "Yapı Karar Defteri UU Kimliği", + } + en = { + **CrudRecordValidation.en, + "iban": "IBAN Number", + "bank_date": "Bank Transaction Date", + "currency_value": "Currency Value", + "bank_balance": "Bank Balance", + "currency": "Unit of Currency", + "additional_balance": "Additional Balance", + "channel_branch": "Branch Bank", + "process_name": "Bank Process Type Name", + "process_type": "Bank Process Type", + "process_comment": "Transaction Record Comment", + "process_garbage": "Transaction Record Garbage", + "bank_reference_code": "Bank Reference Code", + "add_comment_note": "Add Comment Note", + "is_receipt_mail_send": "Receipt Mail Send", + "found_from": "Found From", + "similarity": "Similarity", + "remainder_balance": "Remainder Balance", + "bank_date_y": "Bank Date Year", + "bank_date_m": "Bank Date Month", + "bank_date_w": "Bank Date Week", + "bank_date_d": "Bank Date Day", + "approving_accounting_record": "Approving Accounting Record", + "accounting_receipt_date": "Accounting Receipt Date", + "accounting_receipt_number": "Accounting Receipt Number", + "approved_record": "Approved Record", + "import_file_name": "Import File Name", + "receive_debit": "Receive Debit", + "receive_debit_uu_id": "Receive Debit UU ID", + "budget_type": "Budget Type", + "budget_type_uu_id": "Budget Type UU ID", + "company_uu_id": "Company UU ID", + "send_company_uu_id": "Send Company UU ID", + "send_person_uu_id": "Send Person UU ID", + "approving_accounting_person_uu_id": "Approving Accounting Person UU ID", + "living_space_uu_id": "Living Space UU ID", + "customer_uu_id": "Customer UU ID", + "build_uu_id": "Build UU ID", + "build_parts_uu_id": "Build Parts UU ID", + "build_decision_book_uu_id": "Build Decision Book UU ID", + } + + +class AccountListResponse(BaseModelRegular, CrudRecords, AccountListValidation): + + iban: Optional[str] = None + bank_date: Optional[str] = None + currency_value: Optional[str] = None + bank_balance: Optional[str] = None + currency: Optional[str] = None + additional_balance: Optional[str] = None + channel_branch: Optional[str] = None + process_name: Optional[str] = None + process_type: Optional[str] = None + process_comment: Optional[str] = None + process_garbage: Optional[str] = None + bank_reference_code: Optional[str] = None + add_comment_note: Optional[str] = None + is_receipt_mail_send: Optional[str] = None + found_from: Optional[str] = None + similarity: Optional[str] = None + remainder_balance: Optional[str] = None + bank_date_y: Optional[str] = None + bank_date_m: Optional[str] = None + bank_date_w: Optional[str] = None + bank_date_d: Optional[str] = None + approving_accounting_record: Optional[str] = None + accounting_receipt_date: Optional[str] = None + accounting_receipt_number: Optional[str] = None + approved_record: Optional[str] = None + import_file_name: Optional[str] = None + receive_debit: Optional[str] = None + receive_debit_uu_id: Optional[str] = None + budget_type: Optional[str] = None + budget_type_uu_id: Optional[str] = None + company_uu_id: Optional[str] = None + send_company_uu_id: Optional[str] = None + send_person_uu_id: Optional[str] = None + approving_accounting_person_uu_id: Optional[str] = None + living_space_uu_id: Optional[str] = None + customer_uu_id: Optional[str] = None + build_uu_id: Optional[str] = None + build_parts_uu_id: Optional[str] = None + build_decision_book_uu_id: Optional[str] = None diff --git a/api_validations/validations_response/address.py b/api_validations/validations_response/address.py new file mode 100644 index 0000000..19377f4 --- /dev/null +++ b/api_validations/validations_response/address.py @@ -0,0 +1,23 @@ +from typing import Optional + + +class ListAddressResponse: + pass + + +""" + street_id: Mapped[int] = mapped_column(ForeignKey("address_street.id")) + street_uu_id: Mapped[str] = mapped_column( + String, server_default="", comment="Street UUID" + ) + postcode: Mapped[str] = mapped_column( + String(32), nullable=False, comment="Postcode" + ) + +""" + + +class AddressPostCodeResponse: + street_id: Optional[int] = None + street_uu_id: Optional[str] = None + postcode: Optional[str] = None diff --git a/api_validations/validations_response/building.py b/api_validations/validations_response/building.py new file mode 100644 index 0000000..391b5bf --- /dev/null +++ b/api_validations/validations_response/building.py @@ -0,0 +1,123 @@ +from typing import Optional +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + CrudRecordValidation, + CrudRecords, +) + + +class BuildListValidation: + tr = { + **CrudRecordValidation.tr, + "gov_address_code": "Devlet Adres Kodu", + "build_name": "Bina Adı", + "build_types_uu_id": "Bina Tipi", + "build_no": "Bina No", + "max_floor": "Kat Sayısı", + "underground_floor": "Bodrum Kat Sayısı", + "address_uu_id": "Adres", + "build_date": "Yapım Tarihi", + "decision_period_date": "Karar Tarihi", + "tax_no": "Vergi No", + "lift_count": "Asansör Sayısı", + "heating_system": "Isıtma Sistemi", + "cooling_system": "Soğutma Sistemi", + "hot_water_system": "Sıcak Su Sistemi", + "block_service_man_count": "Hizmet Görevlisi Sayısı", + "security_service_man_count": "Güvenlik Görevlisi Sayısı", + "garage_count": "Garaj Sayısı", + "site_uu_id": "Site UUID", + } + en = { + **CrudRecordValidation.en, + "gov_address_code": "Government Address Code", + "build_name": "Building Name", + "build_types_uu_id": "Building Type", + "build_no": "Building No", + "max_floor": "Number of Floors", + "underground_floor": "Number of Basement Floors", + "address_uu_id": "Address", + "build_date": "Construction Date", + "decision_period_date": "Decision Date", + "tax_no": "Tax No", + "lift_count": "Number of Elevators", + "heating_system": "Heating System", + "cooling_system": "Cooling System", + "hot_water_system": "Hot Water System", + "block_service_man_count": "Number of Service Officers", + "security_service_man_count": "Number of Security Officers", + "garage_count": "Number of Garages", + "site_uu_id": "Site UUID", + } + + +class ListBuildingResponse(BaseModelRegular, CrudRecords, BuildListValidation): + + gov_address_code: Optional[str] = None + build_name: Optional[str] = None + build_types_uu_id: Optional[str] = None + build_no: Optional[str] = None + max_floor: Optional[int] = None + underground_floor: Optional[int] = None + address_uu_id: Optional[str] = None + build_date: Optional[str] = None + decision_period_date: Optional[str] = None + tax_no: Optional[str] = None + lift_count: Optional[int] = None + heating_system: Optional[bool] = None + cooling_system: Optional[bool] = None + hot_water_system: Optional[bool] = None + block_service_man_count: Optional[int] = None + security_service_man_count: Optional[int] = None + garage_count: Optional[int] = None + site_uu_id: Optional[str] = None + + +# class InsertBuild(BaseModelRegular, BuildValidation): +# gov_address_code: str +# build_name: str +# build_types_uu_id: str +# max_floor: int +# underground_floor: int +# address_uu_id: str +# build_date: str +# decision_period_date: str +# +# tax_no: Optional[str] = None +# lift_count: Optional[int] = None +# heating_system: Optional[bool] = None +# cooling_system: Optional[bool] = None +# hot_water_system: Optional[bool] = None +# block_service_man_count: Optional[int] = None +# security_service_man_count: Optional[int] = None +# garage_count: Optional[int] = None +# +# +# class BuildUpdateValidation: +# tr = { +# **BuildValidation.tr, +# **PydanticBaseModelValidation.tr, +# } +# en = { +# **BuildValidation.en, +# **PydanticBaseModelValidation.en, +# } +# +# +# class UpdateBuild(PydanticBaseModel, BuildUpdateValidation): +# gov_address_code: Optional[str] = None +# build_name: Optional[str] = None +# build_no: Optional[str] = None +# build_types: Optional[str] = None +# max_floor: Optional[int] = None +# underground_floor: Optional[int] = None +# build_date: Optional[str] = None +# tax_no: Optional[str] = None +# lift_count: Optional[int] = None +# heating_system: Optional[bool] = None +# cooling_system: Optional[bool] = None +# hot_water_system: Optional[bool] = None +# block_service_man_count: Optional[int] = None +# security_service_man_count: Optional[int] = None +# garage_count: Optional[int] = None +# address_uu_id: Optional[str] = None diff --git a/api_validations/validations_response/living_space.py b/api_validations/validations_response/living_space.py new file mode 100644 index 0000000..4b4c902 --- /dev/null +++ b/api_validations/validations_response/living_space.py @@ -0,0 +1,52 @@ +from typing import Optional +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + CrudRecordValidation, + CrudRecords, +) + + +class LivingSpaceListValidation: + tr = { + **CrudRecordValidation.tr, + "fix_value": "Sabit Değer", + "fix_percent": "Sabit Yüzde", + "agreement_no": "Anlaşma No", + "marketing_process": "Pazarlama Süreci", + "marketing_layer": "Pazarlama Katmanı", + "build_parts_id": "Bölüm ID", + "build_parts_uu_id": "Bölüm UUID", + "person_id": "Sorumlu Kişi ID", + "person_uu_id": "Sorumlu Kişi UUID", + "occupant_type": "Kiracı Tipi", + "occupant_type_uu_id": "Kiracı Tipi UUID", + } + en = { + **CrudRecordValidation.en, + "fix_value": "Fixed Value", + "fix_percent": "Fixed Percent", + "agreement_no": "Agreement No", + "marketing_process": "Marketing Process", + "marketing_layer": "Marketing Layer", + "build_parts_id": "Part ID", + "build_parts_uu_id": "Part UUID", + "person_id": "Responsible Person ID", + "person_uu_id": "Responsible Person UUID", + "occupant_type": "Occupant Type", + "occupant_type_uu_id": "Occupant Type UUID", + } + + +class LivingSpaceListResponse(BaseModelRegular, CrudRecords, LivingSpaceListValidation): + + fix_value: Optional[float] = None + fix_percent: Optional[float] = None + agreement_no: Optional[str] = None + marketing_process: Optional[str] = None + marketing_layer: Optional[str] = None + build_parts_id: Optional[int] = None + build_parts_uu_id: Optional[str] = None + person_id: Optional[int] = None + person_uu_id: Optional[str] = None + occupant_type: Optional[str] = None + occupant_type_uu_id: Optional[str] = None diff --git a/api_validations/validations_response/parts.py b/api_validations/validations_response/parts.py new file mode 100644 index 0000000..bf518ea --- /dev/null +++ b/api_validations/validations_response/parts.py @@ -0,0 +1,54 @@ +from typing import Optional +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + CrudRecordValidation, + CrudRecords, +) + + +class BuildPartsListValidation: + tr = { + **CrudRecordValidation.tr, + "address_gov_code": "Adres Kapı Kodu", + "part_no": "Bölüm No", + "part_level": "Bölüm Seviyesi", + "part_code": "Bölüm Kodu", + "part_gross": "Bölüm Brüt", + "part_net": "Bölüm Net", + "default_accessory": "Varsayılan Aksesuar", + "human_livable": "İnsan Yaşamı", + "due_part_key": "Sabit Ödeme Grubu", + "build_uu_id": "Bina UUID", + "part_direction_uu_id": "Bölüm Yönü UUID", + "part_type_uu_id": "Bölüm Tipi UUID", + } + en = { + **CrudRecordValidation.en, + "address_gov_code": "Address Government Code", + "part_no": "Part Number", + "part_level": "Part Level", + "part_code": "Part Code", + "part_gross": "Part Gross", + "part_net": "Part Net", + "default_accessory": "Default Accessory", + "human_livable": "Human Livable", + "due_part_key": "Constant Payment Group", + "build_uu_id": "Building UUID", + "part_direction_uu_id": "Part Direction UUID", + "part_type_uu_id": "Part Type UUID", + } + + +class BuildPartsListResponse(BaseModelRegular, CrudRecords, BuildPartsListValidation): + address_gov_code: Optional[str] = None + part_no: Optional[int] = None + part_level: Optional[int] = None + part_code: Optional[str] = None + part_gross: Optional[int] = None + part_net: Optional[int] = None + default_accessory: Optional[str] = None + human_livable: Optional[bool] = None + due_part_key: Optional[str] = None + build_uu_id: Optional[str] = None + part_direction_uu_id: Optional[str] = None + part_type_uu_id: Optional[str] = None diff --git a/api_validations/validations_response/people.py b/api_validations/validations_response/people.py new file mode 100644 index 0000000..fcf6da4 --- /dev/null +++ b/api_validations/validations_response/people.py @@ -0,0 +1,57 @@ +from typing import Optional +from api_validations.core_validations import BaseModelRegular +from api_validations.validations_request import ( + CrudRecordValidation, + CrudRecords, +) + + +class PeopleListValidation: + tr = { + **CrudRecordValidation.tr, + "firstname": "Ad", + "surname": "Soyad", + "middle_name": "Orta İsim", + "sex_code": "Cinsiyet Kodu", + "person_ref": "Kişi Referansı", + "person_tag": "Kişi Etiketi", + "father_name": "Baba Adı", + "mother_name": "Anne Adı", + "country_code": "Ülke Kodu", + "national_identity_id": "Kimlik Numarası", + "birth_place": "Doğum Yeri", + "birth_date": "Doğum Tarihi", + "tax_no": "Vergi Numarası", + } + en = { + **CrudRecordValidation.en, + "firstname": "First Name", + "surname": "Surname", + "middle_name": "Middle Name", + "sex_code": "Sex Code", + "person_ref": "Person Reference", + "person_tag": "Person Tag", + "father_name": "Father's Name", + "mother_name": "Mother's Name", + "country_code": "Country Code", + "national_identity_id": "National Identity ID", + "birth_place": "Birth Place", + "birth_date": "Birth Date", + "tax_no": "Tax Number", + } + + +class PeopleListResponse(BaseModelRegular, CrudRecords, PeopleListValidation): + firstname: Optional[str] = None + surname: Optional[str] = None + middle_name: Optional[str] = None + sex_code: Optional[str] = None + person_ref: Optional[str] = None + person_tag: Optional[str] = None + father_name: Optional[str] = None + mother_name: Optional[str] = None + country_code: Optional[str] = None + national_identity_id: Optional[str] = None + birth_place: Optional[str] = None + birth_date: Optional[str] = None + tax_no: Optional[str] = None diff --git a/databases/no_sql_models/__init__.py b/databases/no_sql_models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/databases/no_sql_models/identity.py b/databases/no_sql_models/identity.py new file mode 100644 index 0000000..de278be --- /dev/null +++ b/databases/no_sql_models/identity.py @@ -0,0 +1,136 @@ +import datetime + +from databases.no_sql_models.validations import PasswordHistoryViaUser, DomainViaUser, AccessHistoryViaUser +from databases.no_sql_models.mongo_database import MongoQuery + + +class MongoQueryIdentity: + """ + 4ex. mongo_collection_name = str(Company.uu_id()) + "*" + str('UserPasswordHistory') + """ + + def __init__(self, company_uuid, storage_reasoning: str = None): + self.company_uuid = company_uuid + self.mongo_collection_base = str(company_uuid) + if storage_reasoning: + self.mongo_collection_name = ( + str(company_uuid) + "*" + str(storage_reasoning) + ) + else: + self.mongo_collection_name = str(company_uuid) + "*" + str("Domain") + self.mongo_engine = MongoQuery( + table_name=self.mongo_collection_name, database_name="mongo_database" + ) + + def use_collection(self, storage_reasoning): + self.mongo_collection_name = ( + str(self.company_uuid) + "*" + str(storage_reasoning) + ) + self.mongo_engine = MongoQuery( + table_name=self.mongo_collection_name, database_name="mongo_database" + ) + + def create_domain_via_user(self, payload: DomainViaUser): + self.use_collection("Domain") + return self.mongo_engine.find_or_insert( + field="user_uu_id", + payload={ + "user_uu_id": payload.user_uu_id, + "other_domains_list": [payload.main_domain], + "main_domain": payload.main_domain, + "modified_at": datetime.datetime.now().timestamp(), + } + ) + + def update_domain_via_user(self, payload: DomainViaUser): + self.use_collection("Domain") + return self.mongo_engine.update( + match=payload.user_uu_id, + payload={ + "other_domains_list": payload.other_domains_list, + "modified_at": datetime.datetime.now().timestamp(), + }, + field="user_uu_id", + ) + + def get_domain_via_user(self, user_uu_id): + self.use_collection("Domain") + return self.mongo_engine.get_one(match=str(user_uu_id), field="user_uu_id") + + def refresh_password_history_via_user(self, payload: PasswordHistoryViaUser): + self.use_collection("PasswordHistory") + password_history_item = self.mongo_engine.get_one( + match=payload.user_uu_id, field="user_uu_id" + ) + if not password_history_item: + self.mongo_engine.insert( + payload={ + "user_uu_id": str(payload.user_uu_id), + "password_history": [], + } + ) + password_history_item = self.mongo_engine.get_one( + match=payload.user_uu_id, field="user_uu_id" + ) + password_history_list = password_history_item.get("password_history", []) + hashed_password = payload.password_add.get("password") + for password_in_history in password_history_list: + if str(password_in_history.get("password")) == str(hashed_password): + raise Exception( + dict( + status_code=400, + detail="Password already used. Please enter a new password that you have not used last 3 times." + ) + ) + + if len(password_history_list) > 3: + password_history_list.pop(0) + + password_history_list.append(payload.password_add) + return self.mongo_engine.update( + match=payload.user_uu_id, + payload={ + "password_history": password_history_list, + "access_history_detail": payload.access_history_detail, + "modified_at": datetime.datetime.now().timestamp(), + }, + field="user_uu_id", + ) + + def get_password_history_via_user(self, user_uu_id): + self.use_collection("PasswordHistory") + return self.mongo_engine.get_one(match=user_uu_id, field="user_uu_id") + + def update_access_history_via_user(self, payload: AccessHistoryViaUser): + self.use_collection("AccessHistory") + if already_dict := self.get_access_history_via_user( + user_uu_id=payload.user_uu_id + ): + access_history = already_dict[0].get("access_history") or [] + access_history.append(payload.access_history) + if len(access_history) > 60: + access_history.pop(0) + return self.mongo_engine.update( + match=payload.user_uu_id, + payload={ + "user_uu_id": payload.user_uu_id, + "access_history": access_history, + "modified_at": datetime.datetime.now().timestamp(), + }, + field="user_uu_id", + ) + return self.mongo_engine.insert( + payload={ + "user_uu_id": payload.user_uu_id, + "access_history": [payload.access_history], + "modified_at": datetime.datetime.now().timestamp(), + } + ) + + def get_access_history_via_user(self, user_uu_id): + self.use_collection("AccessHistory") + return self.mongo_engine.filter_by( + payload={"user_uu_id": user_uu_id}, + sort_by="modified_at", + sort_direction="desc", + ) diff --git a/databases/no_sql_models/login_handlers.py b/databases/no_sql_models/login_handlers.py new file mode 100644 index 0000000..0eb5af5 --- /dev/null +++ b/databases/no_sql_models/login_handlers.py @@ -0,0 +1,88 @@ +# from loggers.loggers import LoginLogger + + +def get_menu_from_mongo(user_id, company_name): + from databases.no_sql_models.mongo_database import MongoQuery + + mongo = MongoQuery( + table_name=company_name.replace(" ", ""), database_name="mongo_database" + ) + mongo_dict = mongo.parse_json(mongo.get_one(match=user_id, field="user_id")) or {} + return mongo_dict.get("menu", []) + + +def load_user_with_erp_details(found_user, access_dict: dict = None): + duties = [] + employee = found_user.person.employee + duty_dict = {} + try: + duty_dict = employee.duty.get_dict( + include=["duty_name", "duty_code", "duty_description"] + ) + duty_dict["buildings"] = [] + duty_dict["response_buildings"] = [] + duty_dict["department"] = employee.duty.department.get_dict( + include=["department_name", "department_code"] + ) + duty_dict["company"] = employee.duty.department.company.get_dict( + include=["formal_name", "public_name", "tax_no", "default_lang_type"] + ) + except Exception as e: + # LoginLogger.log_exception( + # { + # "exc": e, + # "user": found_user.uu_id, + # "function": "load_user_with_erp_details", + # } + # ) + err = e + print("MongoQuery load_user_with_erp_details", err) + + for building in list(set(employee.duty.department.company.response_buildings)): + build_parts = [] + for part in building.parts: + build_parts.append( + part.get_dict( + include=["uu_id", "part_name", "part_code", "part_description"] + ) + ) + duty_dict["response_buildings"].append( + { + "build": building.get_dict(include=["build_name", "uu_id"]), + "parts": build_parts, + } + ) + for building in list(set(employee.duty.department.company.buildings)): + build_parts = [] + for part in building.parts: + build_parts.append( + part.get_dict( + include=[ + "uu_id", + "part_name", + "part_code", + "part_description", + ] + ) + ) + duty_dict["buildings"].append( + { + "build": building.get_dict(include=["build_name", "uu_id"]), + "parts": build_parts, + } + ) + duties.append(duty_dict) + return_dict = access_dict if access_dict else {} + return_dict.update( + { + "data": { + "profile": found_user.get_dict(), + "employee_info": duties, + "menu": get_menu_from_mongo( + found_user.id, + company_name=duty_dict.get("company", {}).get("public_name", ""), + ), + }, + } + ) + return return_dict diff --git a/databases/no_sql_models/mongo_database.py b/databases/no_sql_models/mongo_database.py new file mode 100644 index 0000000..9ced7b5 --- /dev/null +++ b/databases/no_sql_models/mongo_database.py @@ -0,0 +1,312 @@ +from itertools import count + +import pymongo + +from json import loads +from bson import ObjectId, json_util +from pydantic import BaseModel +from api_configs import MongoConfig + +from pymongo import MongoClient +from pymongo.collection import Collection +from pymongo.results import InsertManyResult + +# from configs import TestMongo as MongoConfig + + +class Paginate(BaseModel): + pageSize: int = 10 + pageNumber: int = 1 + sortField: str = "_id" + sortOrder: str = "desc" + + def grab_paginates(self): + size_ = self.pageSize + return ( + size_, + size_ * (self.pageNumber - 1), + self.sortField, + -1 if self.sortOrder == "desc" else 1, + ) +class MongoResponse: + + def __init__(self, status: bool, message: str, message_code:str = None, data: dict = None, mongo=None, count: int = 1): + self.status = status + self.message = message + self.data = data + self.mongo = mongo + self.message_code = message_code + self.count = count + + def as_dict(self): + return { + "status": self.status, + "count": self.count, + "message": self.message, + "message_code": self.message_code, + "data": self.data, + } + +class MongoQuery: + + def __init__(self, table_name: str, database_name: str): + database = MongoClient(MongoConfig.url)[database_name] + self.table: Collection = database[table_name] + + @staticmethod + def grab_paginates(paginate): + return ( + paginate.size, + paginate.size * (paginate.page - 1), + paginate.order_field, + -1 if paginate.order_type == "desc" else 1, + ) + + @staticmethod + def parse_json(data): + return loads(json_util.dumps(data)) + + def insert(self, payload) -> MongoResponse: + insert = self.table.insert_one(document=payload) + if insert.acknowledged: + return MongoResponse( + status=True, + message="The document has been created", + message_code="CREATED", + data=payload, + mongo=insert, + ) + return MongoResponse( + status=False, + message="The document has not been created", + message_code="NOT_CREATED", + data=None, + mongo=insert, + count=0 + ) + + def insert_many(self, payload) -> MongoResponse: + insert_many = self.table.insert_many(documents=payload) + if insert_many.acknowledged: + return MongoResponse( + status=True, + message="The documents have been created", + message_code="CREATED", + data=payload, + mongo=insert_many, + count=len(payload) + ) + return MongoResponse( + status=False, + message="The documents have not been created", + message_code="NOT_CREATED", + data=None, + mongo=insert_many, + count=0 + ) + + def find_or_insert(self, payload, field: str = "id") -> MongoResponse: + if field == "id": + found_row = self.get_one(match=payload["_id"], field="_id") + if found_row.status: + return MongoResponse( + status=False, + message="The document already exists", + data=found_row.data, + mongo=found_row.mongo, + ) + if mongo := self.table.insert_one(document=payload).acknowledged: + return MongoResponse( + status=True, + message="The document has been created", + data=payload, + mongo=mongo + ) + + found_row = self.get_one(match=payload[field], field=field) + if found_row.status: + return MongoResponse( + status=False, + message_code="ALREADY_EXISTS", + message="The document already exists", + data=found_row.data, + mongo=found_row.mongo + ) + insert_row = self.table.insert_one(document=payload) + return MongoResponse( + status=True, + message="The document has been created", + message_code="CREATED", + data=payload, + mongo=insert_row + ) + + def update(self, match, payload, field: str = "id"): + if field == "id": + filter_ = {"_id": ObjectId(match)} + update_one = self.table.update_one(filter=filter_, update={"$set": payload}) + return MongoResponse( + status=True, + message="The document has been updated", + message_code="UPDATED", + data=self.get_one(match=match, field=field).data, + mongo=update_one + ) + update_one = self.table.update_one(filter={field: match}, update={"$set": payload}) + return MongoResponse( + status=True, + message="The document has been updated", + message_code="UPDATED", + data=self.get_one(match=match, field=field).data, + mongo=update_one + ) + + def get_one(self, match, field: str = "id"): + if field == "id": + if get_one := self.table.find_one(filter={"_id": ObjectId(match)}): + return MongoResponse( + status=True, + message="The document has been found", + message_code="FOUND", + data=self.parse_json(data=get_one), + mongo=get_one + ) + if get_one := self.table.find_one(filter={field: match}): + return MongoResponse( + status=True, + message="The document has been found", + message_code="FOUND", + data=self.parse_json(data=get_one), + mongo=get_one + ) + return MongoResponse( + status=False, + message="The document has not been found", + message_code="NOT_FOUND", + data=None, + mongo=None + ) + + def filter_by(self, payload, sort_by: str = "_id", sort_direction: str = "asc"): + sort_direction = ( + pymongo.ASCENDING + if str(sort_direction).lower() == "asc" + else pymongo.DESCENDING + ) + return_ = self.table.find(payload).sort(sort_by, sort_direction) + data = self.parse_json(data=return_) + if len(data) == 0: + return MongoResponse( + status=False, + message="The documents have not been found", + message_code="NOT_FOUND", + data=None, + mongo=return_, + count=0 + ) + return MongoResponse( + status=True, + message="The documents have been found", + message_code="FOUND", + count=self.table.count_documents(payload), + data=data, + ) + + def delete_one(self, match, field: str = "id"): + if field == "id": + delete_one = self.table.delete_one(filter={"_id": ObjectId(match)}) + if delete_one.deleted_count: + return MongoResponse( + status=True, + message="The document has been deleted", + message_code="DELETED", + data=None, + count=delete_one.deleted_count, + mongo=delete_one + ) + delete_one = self.table.delete_one(filter={field: match}) + if delete_one.deleted_count: + return MongoResponse( + status=True, + message="The document has been deleted", + message_code="DELETED", + data=None, + count=delete_one.deleted_count, + mongo=delete_one + ) + return MongoResponse( + status=False, + message="The document has not been deleted", + message_code="NOT_DELETED", + data=None, + mongo=None, + count=0 + ) + + def delete_all(self, match, field: str = "id"): + if field == "id": + delete_many = self.table.delete_many(filter={"_id": ObjectId(match)}) + if delete_many.deleted_count: + return MongoResponse( + status=True, + message="The document has been deleted", + message_code="DELETED", + data=None, + count=delete_many.deleted_count, + mongo=delete_many + ) + delete_many = self.table.delete_many(filter={field: match}) + if delete_many.deleted_count: + return MongoResponse( + status=True, + message="The document has been deleted", + message_code="DELETED", + data=None, + count=delete_many.deleted_count, + mongo=delete_many + ) + return MongoResponse( + status=False, + message="The document has not been deleted", + message_code="NOT_DELETED", + data=None, + mongo=None, + count=0 + ) + + def list_all(self, paginate: Paginate): + size, skip, field, order = paginate.grab_paginates() + return_ = self.table.find().sort([(field, order)]).skip(skip).limit(size) + self.table.count_documents({}), self.parse_json(data=return_) + data = self.parse_json(data=return_) + if len(data) == 0: + return MongoResponse( + status=False, + message="The documents have not been found", + message_code="NOT_FOUND", + data=None, + mongo=return_, + count=0 + ) + return MongoResponse( + status=True, + message="The documents have been found", + message_code="FOUND", + count=self.table.count_documents({}), + data=data, + mongo=return_ + ) + + def get_all(self): + return_ = self.table.find() + return MongoResponse( + status=True, + message="The documents have been found", + message_code="FOUND", + count=self.table.count_documents({}), + data=self.parse_json(data=return_), + mongo=return_ + ) + + +# Mongo = MongoQuery(table_name="XcompanyConfig", database_name="mongo_database") diff --git a/databases/no_sql_models/validations.py b/databases/no_sql_models/validations.py new file mode 100644 index 0000000..fbbdab2 --- /dev/null +++ b/databases/no_sql_models/validations.py @@ -0,0 +1,19 @@ +from typing import Optional +from pydantic import BaseModel + + +class DomainViaUser(BaseModel): + user_uu_id: str + main_domain: str + other_domains_list: Optional[list] = None + + +class PasswordHistoryViaUser(BaseModel): + user_uu_id: str + password_add: dict + access_history_detail: Optional[dict] + + +class AccessHistoryViaUser(BaseModel): + user_uu_id: str + access_history: dict