diff --git a/ApiServices/README.md b/ApiServices/README.md new file mode 100644 index 0000000..f8747e5 --- /dev/null +++ b/ApiServices/README.md @@ -0,0 +1,19 @@ +Account Create + +Endpoint('/account/create') -> ClassVar[AccountCreate] +AccountCreate.related_callable -> Serves Result + +* From Endpoint route to related_callable + +AccountCreate: + EndpointURL('http://accountservice/account/create') + + def related_callable(): + callable1 -> UUID[] -> Result + callable2 -> UUID[] + callable3 -> UUID[] + callable4 -> UUID[] + callable5 -> UUID[] + + +ApplicationService -> Serves only app pages that are reachable for Client Side diff --git a/ApiServices/Dockerfile b/ApiServices/TemplateService/Dockerfile similarity index 82% rename from ApiServices/Dockerfile rename to ApiServices/TemplateService/Dockerfile index e90e78d..9a144d2 100644 --- a/ApiServices/Dockerfile +++ b/ApiServices/TemplateService/Dockerfile @@ -15,11 +15,12 @@ RUN poetry config virtualenvs.create false \ && pip cache purge && rm -rf ~/.cache/pypoetry # Copy application code -COPY /ApiServices . +COPY /ApiServices/TemplateService /ApiServices/TemplateService COPY /Controllers /Controllers +COPY /Schemas /Schemas # Set Python path to include app directory ENV PYTHONPATH=/ PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1 # Run the application using the configured uvicorn server -CMD ["poetry", "run", "python", "app.py"] +CMD ["poetry", "run", "python", "ApiServices/TemplateService/app.py"] diff --git a/ApiServices/TemplateService/README.md b/ApiServices/TemplateService/README.md new file mode 100644 index 0000000..e69de29 diff --git a/ApiServices/TemplateService/app.py b/ApiServices/TemplateService/app.py new file mode 100644 index 0000000..b4dfd9c --- /dev/null +++ b/ApiServices/TemplateService/app.py @@ -0,0 +1,15 @@ +import uvicorn + +from ApiServices.TemplateService.config import template_api_config +from ApiServices.TemplateService.create_app import create_app +# from prometheus_fastapi_instrumentator import Instrumentator + + +app = create_app() # Create FastAPI application +# Instrumentator().instrument(app=app).expose(app=app) # Setup Prometheus metrics + + +if __name__ == "__main__": + # Run the application with Uvicorn Server + uvicorn_config = uvicorn.Config(**template_api_config.app_as_dict) + uvicorn.Server(uvicorn_config).run() diff --git a/ApiServices/TemplateService/config.py b/ApiServices/TemplateService/config.py new file mode 100644 index 0000000..bf4b542 --- /dev/null +++ b/ApiServices/TemplateService/config.py @@ -0,0 +1,64 @@ +from pydantic_settings import BaseSettings, SettingsConfigDict +from fastapi.responses import JSONResponse + + +class Configs(BaseSettings): + """ + ApiTemplate configuration settings. + """ + + PATH: str = "" + HOST: str = "", + PORT: int = 0, + LOG_LEVEL: str = "info", + RELOAD: int = 0 + ACCESS_TOKEN_TAG: str = "" + + ACCESS_EMAIL_EXT: str = "" + TITLE: str = "" + ALGORITHM: str = "" + ACCESS_TOKEN_LENGTH: int = 90 + REFRESHER_TOKEN_LENGTH: int = 144 + EMAIL_HOST: str = "" + DATETIME_FORMAT: str = "" + FORGOT_LINK: str = "" + ALLOW_ORIGINS: list = ["http://localhost:3000"] + VERSION: str = "0.1.001" + DESCRIPTION: str = "" + + @property + def app_as_dict(self) -> dict: + """ + Convert the settings to a dictionary. + """ + return { + "app": self.PATH, + "host": self.HOST, + "port": int(self.PORT), + "log_level": self.LOG_LEVEL, + "reload": bool(self.RELOAD) + } + + @property + def api_info(self): + """ + Returns a dictionary with application information. + """ + return { + "title": self.TITLE, + "description": self.DESCRIPTION, + "default_response_class": JSONResponse, + "version": self.VERSION, + } + + @classmethod + def forgot_link(cls, forgot_key): + """ + Generate a forgot password link. + """ + return cls.FORGOT_LINK + forgot_key + + model_config = SettingsConfigDict(env_prefix="API_") + + +template_api_config = Configs() diff --git a/ApiServices/TemplateService/create_app.py b/ApiServices/TemplateService/create_app.py new file mode 100644 index 0000000..4a1b3e6 --- /dev/null +++ b/ApiServices/TemplateService/create_app.py @@ -0,0 +1,41 @@ +from fastapi import FastAPI, Request +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import RedirectResponse +from fastapi.staticfiles import StaticFiles + +from ApiServices.TemplateService.create_route import RouteRegisterController +from ApiServices.TemplateService.endpoints.routes import get_routes +from ApiServices.TemplateService.open_api_creator import create_openapi_schema +from ApiServices.TemplateService.middlewares.token_middleware import token_middleware +from ApiServices.TemplateService.config import template_api_config + + +def create_app(): + + application = FastAPI(**template_api_config.api_info) + # application.mount( + # "/application/static", + # StaticFiles(directory="application/static"), + # name="static", + # ) + application.add_middleware( + CORSMiddleware, + allow_origins=template_api_config.ALLOW_ORIGINS, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + + @application.middleware("http") + async def add_token_middleware(request: Request, call_next): + return await token_middleware(request, call_next) + + @application.get("/", description="Redirect Route", include_in_schema=False) + async def redirect_to_docs(): + return RedirectResponse(url="/docs") + + route_register = RouteRegisterController(app=application, router_list=get_routes()) + application = route_register.register_routes() + + application.openapi = lambda _=application: create_openapi_schema(_) + return application diff --git a/ApiServices/TemplateService/create_route.py b/ApiServices/TemplateService/create_route.py new file mode 100644 index 0000000..bc8545c --- /dev/null +++ b/ApiServices/TemplateService/create_route.py @@ -0,0 +1,14 @@ +from typing import List +from fastapi import APIRouter, FastAPI + + +class RouteRegisterController: + + def __init__(self, app: FastAPI, router_list: List[APIRouter]): + self.router_list = router_list + self.app = app + + def register_routes(self): + for router in self.router_list: + self.app.include_router(router) + return self.app diff --git a/ApiServices/TemplateService/endpoints/__init__.py b/ApiServices/TemplateService/endpoints/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ApiServices/TemplateService/endpoints/routes.py b/ApiServices/TemplateService/endpoints/routes.py new file mode 100644 index 0000000..46a2bab --- /dev/null +++ b/ApiServices/TemplateService/endpoints/routes.py @@ -0,0 +1,17 @@ +from fastapi import APIRouter + + +def get_routes() -> list[APIRouter]: + return [] + + +def get_safe_endpoint_urls() -> list[tuple[str, str]]: + return [ + ("/", "GET"), + ("/docs", "GET"), + ("/redoc", "GET"), + ("/openapi.json", "GET"), + ("/auth/register", "POST"), + ("/auth/login", "POST"), + ("/metrics", "GET"), + ] \ No newline at end of file diff --git a/ApiServices/TemplateService/events/__init__.py b/ApiServices/TemplateService/events/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ApiServices/TemplateService/exception_handlers/__init__.py b/ApiServices/TemplateService/exception_handlers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ApiServices/TemplateService/middlewares/__init__.py b/ApiServices/TemplateService/middlewares/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ApiServices/TemplateService/middlewares/token_middleware.py b/ApiServices/TemplateService/middlewares/token_middleware.py new file mode 100644 index 0000000..da06ba0 --- /dev/null +++ b/ApiServices/TemplateService/middlewares/token_middleware.py @@ -0,0 +1,21 @@ +from fastapi import Request, Response + + +def get_safe_endpoint_urls() -> list: + return [] + + +async def token_middleware(request: Request, call_next): + # from application.routes.routes import get_safe_endpoint_urls + + base_url = "/".join(request.url.path.split("/")[:3]) + safe_endpoints = [_[0] for _ in get_safe_endpoint_urls()] + if base_url in safe_endpoints: + return await call_next(request) + + token = request.headers.get("Authorization") + if not token: + return Response(content="Missing token", status_code=400) + + response = await call_next(request) + return response diff --git a/ApiServices/TemplateService/open_api_creator.py b/ApiServices/TemplateService/open_api_creator.py new file mode 100644 index 0000000..45b4bed --- /dev/null +++ b/ApiServices/TemplateService/open_api_creator.py @@ -0,0 +1,89 @@ +from typing import Any, Dict +from fastapi import FastAPI +from fastapi.routing import APIRoute +from fastapi.openapi.utils import get_openapi +from ApiServices.TemplateService.config import template_api_config + + +class OpenAPISchemaCreator: + """ + OpenAPI schema creator and customizer for FastAPI applications. + """ + + def __init__(self, app: FastAPI): + """ + Initialize the OpenAPI schema creator. + + Args: + app: FastAPI application instance + """ + self.app = app + + def create_security_schemes(self) -> Dict[str, Any]: + """ + Create security scheme definitions. + + Returns: + Dict[str, Any]: Security scheme configurations + """ + + return { + "BearerAuth": { + "type": "apiKey", + "in": "header", + "name": template_api_config.ACCESS_TOKEN_TAG, + "description": "Enter: **'Bearer <JWT>'**, where JWT is the access token", + } + } + + def create_schema(self) -> Dict[str, Any]: + """ + Create the complete OpenAPI schema. + + Returns: + Dict[str, Any]: Complete OpenAPI schema + """ + openapi_schema = get_openapi( + title=template_api_config.TITLE, + description=template_api_config.DESCRIPTION, + version=template_api_config, + routes=self.app.routes, + ) + + # Add security schemes + if "components" not in openapi_schema: + openapi_schema["components"] = {} + + openapi_schema["components"][ + "securitySchemes" + ] = self._create_security_schemes() + + # Configure route security and responses + for route in self.app.routes: + if isinstance(route, APIRoute) and route.include_in_schema: + path = str(route.path) + methods = [method.lower() for method in route.methods] + for method in methods: + self.configure_route_security(path, method, openapi_schema) + + # Add custom documentation extensions + openapi_schema["x-documentation"] = { + "postman_collection": "/docs/postman", + "swagger_ui": "/docs", + "redoc": "/redoc", + } + return openapi_schema + + +def create_openapi_schema(app: FastAPI) -> Dict[str, Any]: + """ + Create OpenAPI schema for a FastAPI application. + + Args: + app: FastAPI application instance + + Returns: + Dict[str, Any]: Complete OpenAPI schema + """ + creator = OpenAPISchemaCreator(app) + return creator.create_schema() \ No newline at end of file diff --git a/ApiServices/TemplateService/schemas/__init__.py b/ApiServices/TemplateService/schemas/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ApiServices/TemplateService/validations/__init__.py b/ApiServices/TemplateService/validations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ApiServices/app.py b/ApiServices/app.py deleted file mode 100644 index aa7f55a..0000000 --- a/ApiServices/app.py +++ /dev/null @@ -1,9 +0,0 @@ -from Controllers.Postgres.config import postgres_configs -from Controllers.Mongo.config import mongo_configs -from Controllers.Mongo.implementations import run_all_tests - - -if __name__ == "__main__": - print(f"Hello from the Test Service {mongo_configs.url}") - print(f"Hello from the Test Service {postgres_configs.url}") - run_all_tests() diff --git a/README.md b/README.md index 48cb84f..b1dbf41 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # prod-wag-backend-automate-services -Production Build of Wag Backend and Services \ No newline at end of file +Production Build of Wag Backend and Services + +ApiService/Auth Build diff --git a/Schemas/__init__.py b/Schemas/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Schemas/account/account.py b/Schemas/account/account.py new file mode 100644 index 0000000..7c9d9de --- /dev/null +++ b/Schemas/account/account.py @@ -0,0 +1,578 @@ +from sqlalchemy.orm import mapped_column, Mapped +from sqlalchemy import ( + String, + Integer, + Boolean, + ForeignKey, + Index, + TIMESTAMP, + Numeric, + SmallInteger, +) + +from Controllers.Postgres.mixin import CrudCollection + + +class AccountBooks(CrudCollection): + + __tablename__ = "account_books" + __exclude__fields__ = [] + + country: Mapped[str] = mapped_column(String, nullable=False) + branch_type: Mapped[int] = mapped_column(SmallInteger, server_default="0") + + company_id: Mapped[int] = mapped_column(ForeignKey("companies.id"), nullable=False) + company_uu_id: Mapped[str] = mapped_column(String, nullable=False) + branch_id: Mapped[int] = mapped_column(ForeignKey("companies.id")) + branch_uu_id: Mapped[str] = mapped_column(String, comment="Branch UU ID") + + __table_args__ = ( + Index("account_companies_book_ndx_00", company_id, "expiry_starts"), + {"comment": "Account Book Information"}, + ) + + +class AccountCodes(CrudCollection): + + __tablename__ = "account_codes" + __exclude__fields__ = [] + + account_code: Mapped[str] = mapped_column( + String(48), nullable=False, comment="Account Code" + ) + comment_line: Mapped[str] = mapped_column( + String(128), nullable=False, comment="Comment Line" + ) + + is_receive_or_debit: Mapped[bool] = mapped_column(Boolean) + product_id: Mapped[int] = mapped_column(Integer, server_default="0") + nvi_id: Mapped[str] = mapped_column(String(48), server_default="") + status_id: Mapped[int] = mapped_column(SmallInteger, server_default="0") + account_code_seperator: Mapped[str] = mapped_column(String(1), server_default=".") + + system_id: Mapped[int] = mapped_column(SmallInteger, server_default="0") + locked: Mapped[int] = mapped_column(SmallInteger, server_default="0") + + company_id: Mapped[int] = mapped_column(ForeignKey("companies.id")) + company_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Company UU ID" + ) + customer_id: Mapped[int] = mapped_column(ForeignKey("companies.id")) + customer_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Customer UU ID" + ) + person_id: Mapped[int] = mapped_column(ForeignKey("people.id")) + person_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Person UU ID" + ) + + __table_args__ = ({"comment": "Account Code Information"},) + + +class AccountCodeParser(CrudCollection): + + __tablename__ = "account_code_parser" + __exclude__fields__ = [] + + account_code_1: Mapped[str] = mapped_column(String, nullable=False, comment="Order") + account_code_2: Mapped[str] = mapped_column(String, nullable=False, comment="Order") + account_code_3: Mapped[str] = mapped_column(String, nullable=False, comment="Order") + account_code_4: Mapped[str] = mapped_column(String, server_default="") + account_code_5: Mapped[str] = mapped_column(String, server_default="") + account_code_6: Mapped[str] = mapped_column(String, server_default="") + + account_code_id: Mapped[int] = mapped_column( + ForeignKey("account_codes.id"), nullable=False + ) + account_code_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Account Code UU ID" + ) + + __table_args__ = ( + Index("_account_code_parser_ndx_00", account_code_id), + {"comment": "Account Code Parser Information"}, + ) + + @property + def get_account_code(self): + return f"{self.account_codes.account_code_seperator}".join( + [ + getattr(self, f"account_code_{i}") + for i in range(1, 7) + if getattr(self, f"account_code_{i}") + ] + ) + + +class AccountMaster(CrudCollection): + """ + AccountCodes class based on declarative_base and CrudCollection via session + """ + + __tablename__ = "account_master" + __exclude__fields__ = [] + + doc_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), nullable=False, comment="Document Date" + ) + plug_type: Mapped[str] = mapped_column(String, nullable=False, comment="Plug Type") + plug_number: Mapped[int] = mapped_column( + Integer, nullable=False, comment="Plug Number" + ) + + special_code: Mapped[str] = mapped_column(String(12), server_default="") + authorization_code: Mapped[str] = mapped_column(String(12), server_default="") + + doc_code: Mapped[str] = mapped_column(String(12), server_default="") + doc_type: Mapped[int] = mapped_column(SmallInteger, server_default="0") + + comment_line1: Mapped[str] = mapped_column(String, server_default="") + comment_line2: Mapped[str] = mapped_column(String, server_default="") + comment_line3: Mapped[str] = mapped_column(String, server_default="") + comment_line4: Mapped[str] = mapped_column(String, server_default="") + comment_line5: Mapped[str] = mapped_column(String, server_default="") + comment_line6: Mapped[str] = mapped_column(String, server_default="") + project_code: Mapped[str] = mapped_column(String(12), server_default="") + module_no: Mapped[str] = mapped_column(String, server_default="") + journal_no: Mapped[int] = mapped_column(Integer, server_default="0") + + status_id: Mapped[int] = mapped_column(SmallInteger, server_default="0") + canceled: Mapped[bool] = mapped_column(Boolean, server_default="0") + print_count: Mapped[int] = mapped_column(SmallInteger, server_default="0") + total_active: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + total_passive: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + total_active_1: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + total_passive_1: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + total_active_2: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + total_passive_2: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + total_active_3: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + total_passive_3: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + total_active_4: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + total_passive_4: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + cross_ref: Mapped[int] = mapped_column(Integer, server_default="0") + data_center_id: Mapped[str] = mapped_column(String, server_default="") + data_center_rec_num: Mapped[int] = mapped_column(Integer, server_default="0") + + account_header_id: Mapped[int] = mapped_column( + ForeignKey("account_books.id"), nullable=False + ) + account_header_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Account Header UU ID" + ) + project_item_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book_projects.id") + ) + project_item_uu_id: Mapped[str] = mapped_column( + String, comment="Project Item UU ID" + ) + department_id: Mapped[int] = mapped_column(ForeignKey("departments.id")) + department_uu_id: Mapped[str] = mapped_column(String, comment="Department UU ID") + + __table_args__ = ( + Index("_account_master_ndx_00", doc_date, account_header_id), + {"comment": "Account Master Information"}, + ) + + +class AccountDetail(CrudCollection): + """ + AccountCodes class based on declarative_base and CrudCollection via session + """ + + __tablename__ = "account_detail" + __exclude__fields__ = [] + __enum_list__ = [("plug_type", "AccountingReceiptTypes", "M")] + + doc_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), nullable=False, comment="Document Date" + ) + line_no: Mapped[int] = mapped_column( + SmallInteger, nullable=False, comment="Line Number" + ) + receive_debit: Mapped[str] = mapped_column( + String(1), nullable=False, comment="Receive Debit" + ) + debit: Mapped[float] = mapped_column( + Numeric(20, 6), nullable=False, comment="Debit" + ) + + department: Mapped[str] = mapped_column(String(24), server_default="") + special_code: Mapped[str] = mapped_column(String(12), server_default="") + account_ref: Mapped[int] = mapped_column(Integer, server_default="0") + account_fiche_ref: Mapped[int] = mapped_column(Integer, server_default="0") + center_ref: Mapped[int] = mapped_column(Integer, server_default="0") + general_code: Mapped[str] = mapped_column(String(32), server_default="") + credit: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + currency_type: Mapped[str] = mapped_column(String(4), server_default="TL") + exchange_rate: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + debit_cur: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + credit_cur: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + discount_cur: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + amount: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + cross_account_code: Mapped[float] = mapped_column(String(32), server_default="") + inf_index: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + not_inflated: Mapped[int] = mapped_column(SmallInteger, server_default="0") + not_calculated: Mapped[int] = mapped_column(SmallInteger, server_default="0") + comment_line1: Mapped[str] = mapped_column(String(64), server_default="") + comment_line2: Mapped[str] = mapped_column(String(64), server_default="") + comment_line3: Mapped[str] = mapped_column(String(64), server_default="") + comment_line4: Mapped[str] = mapped_column(String(64), server_default="") + comment_line5: Mapped[str] = mapped_column(String(64), server_default="") + comment_line6: Mapped[str] = mapped_column(String(64), server_default="") + owner_acc_ref: Mapped[int] = mapped_column(Integer, server_default="0") + from_where: Mapped[int] = mapped_column(Integer, server_default="0") + orj_eid: Mapped[int] = mapped_column(Integer, server_default="0") + canceled: Mapped[int] = mapped_column(SmallInteger, server_default="0") + cross_ref: Mapped[int] = mapped_column(Integer, server_default="0") + data_center_id: Mapped[str] = mapped_column(String, server_default="") + data_center_rec_num: Mapped[int] = mapped_column(Integer, server_default="0") + status_id: Mapped[int] = mapped_column(SmallInteger, server_default="0") + + plug_type_id: Mapped[int] = mapped_column( + ForeignKey("api_enum_dropdown.id"), nullable=True + ) + plug_type_uu_id = mapped_column(String, nullable=False, comment="Plug Type UU ID") + account_header_id: Mapped[int] = mapped_column( + ForeignKey("account_books.id"), nullable=False + ) + account_header_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Account Header UU ID" + ) + account_code_id: Mapped[int] = mapped_column( + ForeignKey("account_codes.id"), nullable=False + ) + account_code_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Account Code UU ID" + ) + account_master_id: Mapped[int] = mapped_column( + ForeignKey("account_master.id"), nullable=False + ) + account_master_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Account Master UU ID" + ) + project_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book_projects.id") + ) + project_uu_id: Mapped[str] = mapped_column(String, comment="Project UU ID") + + __table_args__ = ( + Index( + "_account_detail_ndx_00", + account_master_id, + doc_date, + line_no, + account_header_id, + unique=True, + ), + {"comment": "Account Detail Information"}, + ) + + +class AccountRecordExchanges(CrudCollection): + + __tablename__ = "account_record_exchanges" + __exclude__fields__ = [] + + are_currency: Mapped[str] = mapped_column( + String(5), nullable=False, comment="Unit of Currency" + ) + are_exchange_rate: Mapped[float] = mapped_column( + Numeric(18, 6), nullable=False, server_default="1" + ) + usd_exchange_rate_value: Mapped[float] = mapped_column( + Numeric(18, 6), + nullable=True, + server_default="0", + comment="It will be written by multiplying the usd exchange rate with the current value result.", + ) + eur_exchange_rate_value: Mapped[float] = mapped_column( + Numeric(18, 6), + nullable=True, + server_default="0", + comment="It will be written by multiplying the eur exchange rate with the current value result.", + ) + gbp_exchange_rate_value: Mapped[float] = mapped_column( + Numeric(18, 6), + nullable=True, + server_default="0", + comment="It will be written by multiplying the gpd exchange rate with the current value result.", + ) + cny_exchange_rate_value: Mapped[float] = mapped_column( + Numeric(18, 6), + nullable=True, + server_default="0", + comment="It will be written by multiplying the cny exchange rate with the current value result.", + ) + + account_records_id: Mapped[int] = mapped_column(ForeignKey("account_records.id")) + account_records_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Account Record UU ID" + ) + + __table_args__ = ( + Index("_account_record_exchanges_ndx_00", account_records_id), + {"comment": "Account Record Exchanges Information"}, + ) + + +class AccountRecords(CrudCollection): + """ + build_decision_book_id = kaydın sorumlu olduğu karar defteri + send_company_id = kaydı gönderen firma, send_person_id = gönderen kişi + customer_id = sorumlu kullanıcı bilgisi, company_id = sorumlu firma + """ + + __tablename__ = "account_records" + __exclude__fields__ = [] + __enum_list__ = [ + ("receive_debit", "DebitTypes", "D"), + ("budget_type", "BudgetType", "B"), + ] + + iban: Mapped[str] = mapped_column( + String(64), nullable=False, comment="IBAN Number of Bank" + ) + bank_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), nullable=False, comment="Bank Transaction Date" + ) + + currency_value: Mapped[float] = mapped_column( + Numeric(20, 6), nullable=False, comment="Currency Value" + ) + bank_balance: Mapped[float] = mapped_column( + Numeric(20, 6), nullable=False, comment="Bank Balance" + ) + currency: Mapped[str] = mapped_column( + String(5), nullable=False, comment="Unit of Currency" + ) + additional_balance: Mapped[float] = mapped_column( + Numeric(20, 6), nullable=False, comment="Additional Balance" + ) + channel_branch: Mapped[str] = mapped_column( + String(120), nullable=False, comment="Branch Bank" + ) + process_name: Mapped[str] = mapped_column( + String, nullable=False, comment="Bank Process Type Name" + ) + process_type: Mapped[str] = mapped_column( + String, nullable=False, comment="Bank Process Type" + ) + process_comment: Mapped[str] = mapped_column( + String, nullable=False, comment="Transaction Record Comment" + ) + process_garbage: Mapped[str] = mapped_column( + String, nullable=True, comment="Transaction Record Garbage" + ) + bank_reference_code: Mapped[str] = mapped_column( + String, nullable=False, comment="Bank Reference Code" + ) + + add_comment_note: Mapped[str] = mapped_column(String, server_default="") + is_receipt_mail_send: Mapped[bool] = mapped_column(Boolean, server_default="0") + found_from = mapped_column(String, server_default="") + similarity: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + remainder_balance: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + + bank_date_y: Mapped[int] = mapped_column(Integer) + bank_date_m: Mapped[int] = mapped_column(SmallInteger) + bank_date_w: Mapped[int] = mapped_column(SmallInteger) + bank_date_d: Mapped[int] = mapped_column(SmallInteger) + + approving_accounting_record: Mapped[bool] = mapped_column( + Boolean, server_default="0" + ) + accounting_receipt_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), server_default="1900-01-01 00:00:00" + ) + accounting_receipt_number: Mapped[int] = mapped_column(Integer, server_default="0") + status_id: Mapped[int] = mapped_column(SmallInteger, server_default="0") + + approved_record: Mapped[bool] = mapped_column(Boolean, server_default="0") + import_file_name: Mapped[str] = mapped_column( + String, nullable=True, comment="XLS Key" + ) + + receive_debit: Mapped[int] = mapped_column( + ForeignKey("api_enum_dropdown.id"), nullable=True + ) + receive_debit_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Debit UU ID" + ) + budget_type: Mapped[int] = mapped_column( + ForeignKey("api_enum_dropdown.id"), nullable=True + ) + budget_type_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Budget Type UU ID" + ) + company_id: Mapped[int] = mapped_column(ForeignKey("companies.id"), nullable=True) + company_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Company UU ID" + ) + send_company_id: Mapped[int] = mapped_column( + ForeignKey("companies.id"), nullable=True + ) + send_company_uu_id = mapped_column( + String, nullable=True, comment="Send Company UU ID" + ) + + send_person_id: Mapped[int] = mapped_column(ForeignKey("people.id"), nullable=True) + send_person_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Send Person UU ID" + ) + approving_accounting_person: Mapped[int] = mapped_column( + ForeignKey("people.id"), nullable=True + ) + approving_accounting_person_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Approving Accounting Person UU ID" + ) + + living_space_id: Mapped[int] = mapped_column( + ForeignKey("build_living_space.id"), nullable=True + ) + living_space_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Living Space UU ID" + ) + customer_id: Mapped[int] = mapped_column(ForeignKey("people.id"), nullable=True) + customer_uu_id = mapped_column(String, nullable=True, comment="Customer UU ID") + + build_id: Mapped[int] = mapped_column(ForeignKey("build.id"), nullable=True) + build_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Build UU ID" + ) + build_parts_id: Mapped[int] = mapped_column( + ForeignKey("build_parts.id"), nullable=True + ) + build_parts_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Build Parts UU ID" + ) + build_decision_book_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book.id"), nullable=True + ) + build_decision_book_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Build Decision Book UU ID" + ) + + __table_args__ = ( + Index("_budget_records_ndx_00", is_receipt_mail_send, bank_date), + Index( + "_budget_records_ndx_01", + iban, + bank_date, + bank_reference_code, + bank_balance, + unique=True, + ), + Index("_budget_records_ndx_02", status_id, bank_date), + { + "comment": "Bank Records that are related to building and financial transactions" + }, + ) + + # def payment_budget_record_close(self): + # from database_sql_models import ( + # DecisionBookProjectPaymentsMaster, + # ApiEnumDropdown, + # BuildDecisionBook, + # BuildDecisionBookPaymentsMaster, + # ) + # + # budget_record = self + # if self.receive_debit == ApiEnumDropdown.uuid_of_enum( + # enum_class="DebitTypes", key="R" + # ): + # print( + # "This record is not debit. Debit:", + # self.receive_debit, + # "DebitTypes.R.name", + # # str(DebitTypes.R.name), + # ) + # return + # if abs(budget_record.currency_value + budget_record.remainder_balance) > 0: + # payment_dict = { + # "budget_records_id": self.id, + # "build_decision_book_id": budget_record.build_decision_book_id, + # "build_parts_id": budget_record.build_parts_id, + # "start_date": budget_record.bank_date, + # "paid_value": budget_record.currency_value + # - budget_record.remainder_balance, + # "is_all": False, + # } + # (paid_value, start_paid_value, balance) = ( + # float(budget_record.currency_value - budget_record.remainder_balance), + # float(budget_record.currency_value - budget_record.remainder_balance), + # float(budget_record.remainder_balance), + # ) + # print( + # "self.id", + # self.id, + # "paid_value", + # paid_value, + # "start_paid_value", + # start_paid_value, + # "balance", + # balance, + # self.receive_debit, + # ) + # + # if not BuildDecisionBook.find_one( + # id=payment_dict["build_decision_book_id"] + # ): + # return paid_value + # + # if budget_record.replication_id == 55: + # if paid_value > 0: + # payment_dict["dues_type"] = ApiEnumDropdown.uuid_of_enum( + # enum_class="BuildDuesTypes", key="L" + # ) + # paid_value = ( + # DecisionBookProjectPaymentsMaster.pay_law_and_ren_of_build_part( + # **payment_dict + # ) + # ) + # print("dues_type", payment_dict["dues_type"], paid_value) + # if paid_value > 0: + # payment_dict.pop("dues_type", None) + # paid_value = BuildDecisionBookPaymentsMaster.pay_dues_of_build_part( + # **payment_dict + # ) + # print("dues_type", None, paid_value) + # if paid_value > 0: + # payment_dict["dues_type"] = ApiEnumDropdown.uuid_of_enum( + # enum_class="BuildDuesTypes", key="R" + # ) + # paid_value = ( + # DecisionBookProjectPaymentsMaster.pay_law_and_ren_of_build_part( + # **payment_dict + # ) + # ) + # print("dues_type", payment_dict["dues_type"], paid_value) + # payment_dict["is_all"] = True + # if paid_value > 0: + # payment_dict["dues_type"] = ApiEnumDropdown.uuid_of_enum( + # enum_class="BuildDuesTypes", key="L" + # ) + # paid_value = ( + # DecisionBookProjectPaymentsMaster.pay_law_and_ren_of_build_part( + # **payment_dict + # ) + # ) + # print("is all dues_type", payment_dict["dues_type"], paid_value) + # if paid_value > 0: + # payment_dict.pop("dues_type", None) + # paid_value = BuildDecisionBookPaymentsMaster.pay_dues_of_build_part( + # **payment_dict + # ) + # print("is all dues_type", None, paid_value) + # if paid_value > 0: + # payment_dict["dues_type"] = ApiEnumDropdown.uuid_of_enum( + # enum_class="BuildDuesTypes", key="R" + # ) + # paid_value = ( + # DecisionBookProjectPaymentsMaster.pay_law_and_ren_of_build_part( + # **payment_dict + # ) + # ) + # print("is all dues_type", payment_dict["dues_type"], paid_value) + + + diff --git a/Schemas/account/iban.py b/Schemas/account/iban.py new file mode 100644 index 0000000..cbb3644 --- /dev/null +++ b/Schemas/account/iban.py @@ -0,0 +1,74 @@ +from sqlalchemy import String, ForeignKey, Index, TIMESTAMP, SmallInteger +from sqlalchemy.orm import mapped_column, Mapped + +from Controllers.Postgres.mixin import CrudCollection + + +class BuildIbans(CrudCollection): + """ + BuildParts class based on declarative_base and BaseMixin via session + """ + + __tablename__ = "build_ibans" + __exclude__fields__ = [] + + iban: Mapped[str] = mapped_column( + String(40), server_default="", nullable=False, comment="IBAN number" + ) + start_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), nullable=False, comment="Bank Transaction Start Date" + ) + stop_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), server_default="2900-01-01 00:00:00" + ) + bank_code: Mapped[str] = mapped_column(String(24), server_default="TR0000000000000") + xcomment: Mapped[str] = mapped_column(String(64), server_default="????") + build_id: Mapped[int] = mapped_column( + ForeignKey("build.id"), nullable=True, comment="Building ID" + ) + build_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Building UUID", index=True + ) + + __table_args__ = ( + Index("_build_ibans_ndx_01", iban, start_date, unique=True), + {"comment": "IBANs related to money transactions due to building objects"}, + ) + + +class BuildIbanDescription(CrudCollection): + """ + SearchComments class based on declarative_base and CrudCollection via session + """ + + __tablename__ = "build_iban_description" + __exclude__fields__ = [] + + iban: Mapped[str] = mapped_column(String, nullable=False, comment="IBAN Number") + group_id: Mapped[int] = mapped_column( + SmallInteger, nullable=False, comment="Group ID" + ) + search_word: Mapped[str] = mapped_column( + String, nullable=False, comment="Search Word", index=True + ) + customer_id: Mapped[int] = mapped_column(ForeignKey("people.id"), nullable=True) + customer_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Customer UUID" + ) + company_id: Mapped[int] = mapped_column(ForeignKey("companies.id"), nullable=True) + company_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Company UUID" + ) + build_parts_id: Mapped[int] = mapped_column( + ForeignKey("build_parts.id"), nullable=True + ) + build_parts_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Build Parts UUID" + ) + + __table_args__ = ( + Index( + "_search_iban_description_ndx_00", iban, search_word, group_id, unique=True + ), + {"comment": "Search Iban Description Information"}, + ) diff --git a/Schemas/building/budget.py b/Schemas/building/budget.py new file mode 100644 index 0000000..0c20744 --- /dev/null +++ b/Schemas/building/budget.py @@ -0,0 +1,156 @@ +from sqlalchemy import ( + String, + ForeignKey, + Index, + SmallInteger, + TIMESTAMP, + Text, + Numeric, + Integer, +) +from sqlalchemy.orm import mapped_column, Mapped +from Controllers.Postgres.mixin import CrudCollection + + +class DecisionBookBudgetBooks(CrudCollection): + + __tablename__ = "decision_book_budget_books" + __exclude__fields__ = [] + + country: Mapped[str] = mapped_column(String, nullable=False) + branch_type: Mapped[int] = mapped_column(SmallInteger, server_default="0") + + company_id: Mapped[int] = mapped_column(ForeignKey("companies.id"), nullable=False) + company_uu_id: Mapped[str] = mapped_column(String, nullable=False) + branch_id: Mapped[int] = mapped_column(ForeignKey("companies.id"), nullable=True) + branch_uu_id: Mapped[str] = mapped_column( + String, comment="Branch UU ID", nullable=True + ) + build_decision_book_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book.id"), nullable=False + ) + build_decision_book_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Build Decision Book UU ID" + ) + + __table_args__ = ( + Index( + "_decision_book_budget_companies_book_ndx_00", + company_id, + "created_at", + ), + {"comment": "budget Book Information"}, + ) + + +class DecisionBookBudgetCodes(CrudCollection): + + __tablename__ = "decision_book_budget_codes" + __exclude__fields__ = [] + + budget_code: Mapped[str] = mapped_column( + String(48), nullable=False, comment="budget Code" + ) + comment_line: Mapped[str] = mapped_column( + Text, nullable=False, comment="Comment Line" + ) + + build_decision_book_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book.id"), nullable=True + ) + build_decision_book_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Build Decision Book UU ID" + ) + + build_parts_id: Mapped[int] = mapped_column( + ForeignKey("build_parts.id"), nullable=True + ) + build_parts_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Build Parts UU ID" + ) + + company_id: Mapped[int] = mapped_column(ForeignKey("companies.id"), nullable=True) + company_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Company UU ID" + ) + + __table_args__ = ( + Index("_decision_book_budget_codes_ndx_00", budget_code, "created_at"), + Index("_decision_book_budget_codes_ndx_01", company_id, "created_at"), + {"comment": "budget Book Information"}, + ) + + +class DecisionBookBudgetMaster(CrudCollection): + + __tablename__ = "decision_book_budget_master" + __exclude__fields__ = [] + + budget_type: Mapped[str] = mapped_column( + String(50), nullable=False + ) # Bütçe tipi (örneğin: Operasyonel, Yatırım) + currency: Mapped[str] = mapped_column( + String(8), server_default="TRY" + ) # Bütçe para birimi + total_budget: Mapped[float] = mapped_column( + Numeric(10, 2), nullable=False + ) # Toplam bütçe + + tracking_period_id: Mapped[int] = mapped_column( + ForeignKey("api_enum_dropdown.id"), nullable=True + ) + tracking_period_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Part Direction UUID" + ) + budget_books_id: Mapped[int] = mapped_column( + Integer, ForeignKey("decision_book_budget_books.id"), nullable=False + ) + budget_books_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Budget Books UU ID" + ) + department_id: Mapped[int] = mapped_column( + Integer, ForeignKey("departments.id"), nullable=False + ) # Departman ile ilişki + department_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Department UU ID" + ) + + __table_args__ = ({"comment": "budget Book Information"},) + + +class DecisionBookBudgets(CrudCollection): + + __tablename__ = "decision_book_budgets" + __exclude__fields__ = [] + + process_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), nullable=False + ) # Başlangıç tarihi + budget_codes_id: Mapped[int] = mapped_column( + Integer, ForeignKey("decision_book_budget_codes.id"), nullable=False + ) + total_budget: Mapped[float] = mapped_column( + Numeric(10, 2), nullable=False + ) # Toplam bütçe + used_budget: Mapped[float] = mapped_column( + Numeric(10, 2), nullable=False, default=0.0 + ) # Kullanılan bütçe + remaining_budget: Mapped[float] = mapped_column( + Numeric(10, 2), nullable=False, default=0.0 + ) # Kullanılan bütçe + + decision_book_budget_master_id: Mapped[int] = mapped_column( + Integer, ForeignKey("decision_book_budget_master.id"), nullable=False + ) + decision_book_budget_master_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Decision Book Budget Master UU ID" + ) + + __table_args__ = ( + Index( + "_decision_book_budgets_ndx_00", + decision_book_budget_master_uu_id, + process_date, + ), + {"comment": "budget Book Information"}, + ) diff --git a/Schemas/building/build.py b/Schemas/building/build.py new file mode 100644 index 0000000..ddb0466 --- /dev/null +++ b/Schemas/building/build.py @@ -0,0 +1,627 @@ +from datetime import timedelta +from typing import List, Union, Any + +import arrow +from sqlalchemy.orm import mapped_column, relationship, Mapped +from sqlalchemy import ( + String, + Integer, + Boolean, + ForeignKey, + Index, + TIMESTAMP, + Text, + Numeric, + or_, +) +from fastapi import HTTPException, status + +from Controllers.Postgres.mixin import CrudCollection + + +class BuildTypes(CrudCollection): + """ + BuildTypes class based on declarative_base and BaseMixin via session + + """ + + __tablename__ = "build_types" + __exclude__fields__ = [] + __include__fields__ = [] + + function_code: Mapped[str] = mapped_column( + String(12), server_default="", nullable=False, comment="Function Code" + ) + type_code: Mapped[str] = mapped_column( + String(12), server_default="", nullable=False, comment="Structure Type Code" + ) + lang: Mapped[str] = mapped_column( + String(4), server_default="TR", nullable=False, comment="Language" + ) + type_name: Mapped[str] = mapped_column( + String(48), server_default="", nullable=False, comment="Type Name" + ) + + __table_args__ = ( + Index("_build_types_ndx_00", type_code, function_code, lang, unique=True), + {"comment": "Function group of building types with their language information"}, + ) + + +class Part2Employee(CrudCollection): + """ + Employee2Parts class based on declarative_base and BaseMixin via session + In between start and end date, a part can be assigned to only one employee + """ + + __tablename__ = "part2employee" + __exclude__fields__ = [] + __include__fields__ = [] + + build_id: Mapped[int] = mapped_column(Integer, comment="Building ID") + part_id: Mapped[int] = mapped_column( + ForeignKey("build_parts.id"), nullable=False, comment="Part ID" + ) + employee_id: Mapped[int] = mapped_column( + ForeignKey("employees.id"), nullable=False, comment="Employee ID" + ) + + __table_args__ = ( + Index("_part2employee_ndx_00", employee_id, part_id, unique=True), + {"comment": "Employee2Parts Information"}, + ) + + +class RelationshipEmployee2Build(CrudCollection): + """ + CompanyRelationship class based on declarative_base and CrudCollection via session + Company -> Sub Company -> Sub-Sub Company + + """ + + __tablename__ = "relationship_employee2build" + __exclude__fields__ = [] + + company_id: Mapped[int] = mapped_column( + ForeignKey("companies.id"), nullable=False + ) # 1, 2, 3 + employee_id: Mapped[int] = mapped_column( + ForeignKey("employees.id"), nullable=False + ) # employee -> (n)person Evyos LTD + member_id: Mapped[int] = mapped_column( + ForeignKey("build.id"), nullable=False + ) # 2, 3, 4 + + relationship_type: Mapped[str] = mapped_column( + String, nullable=True, server_default="Employee" + ) # Commercial + show_only: Mapped[bool] = mapped_column(Boolean, server_default="False") + + __table_args__ = ( + Index( + "relationship_build_employee_ndx_00", + company_id, + employee_id, + member_id, + relationship_type, + unique=True, + ), + {"comment": "Build & Employee Relationship Information"}, + ) + + +class Build(CrudCollection): + """ + Builds class based on declarative_base and BaseMixin via session + """ + + __tablename__ = "build" + __exclude__fields__ = [] + __include__fields__ = [] + __access_by__ = [] + # __many__table__ = RelationshipEmployee2Build + + gov_address_code: Mapped[str] = mapped_column( + String, server_default="", unique=True + ) + build_name: Mapped[str] = mapped_column( + String, nullable=False, comment="Building Name" + ) + build_no: Mapped[str] = mapped_column( + String(8), nullable=False, comment="Building Number" + ) + + max_floor: Mapped[int] = mapped_column( + Integer, server_default="1", nullable=False, comment="Max Floor" + ) + underground_floor: Mapped[int] = mapped_column( + Integer, server_default="0", nullable=False, comment="Underground Floor" + ) + build_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), server_default="1900-01-01" + ) + decision_period_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), + server_default="1900-01-01", + comment="Building annual ordinary meeting period", + ) + tax_no: Mapped[str] = mapped_column(String(24), server_default="") + lift_count: Mapped[int] = mapped_column(Integer, server_default="0") + heating_system: Mapped[bool] = mapped_column(Boolean, server_default="True") + cooling_system: Mapped[bool] = mapped_column(Boolean, server_default="False") + hot_water_system: Mapped[bool] = mapped_column(Boolean, server_default="False") + block_service_man_count: Mapped[int] = mapped_column(Integer, server_default="0") + security_service_man_count: Mapped[int] = mapped_column(Integer, server_default="0") + garage_count: Mapped[int] = mapped_column( + Integer, server_default="0", comment="Garage Count" + ) + management_room_id: Mapped[int] = mapped_column( + Integer, nullable=True, comment="Management Room ID" + ) + + site_id: Mapped[int] = mapped_column(ForeignKey("build_sites.id"), nullable=True) + site_uu_id: Mapped[str] = mapped_column(String, comment="Site UUID", nullable=True) + address_id: Mapped[int] = mapped_column(ForeignKey("addresses.id"), nullable=False) + address_uu_id: Mapped[str] = mapped_column( + String, comment="Address UUID", nullable=False + ) + build_types_id: Mapped[int] = mapped_column( + ForeignKey("build_types.id"), nullable=False, comment="Building Type" + ) + build_types_uu_id: Mapped[str] = mapped_column(String, comment="Building Type UUID") + + parts: Mapped[List["BuildParts"]] = relationship( + "BuildParts", back_populates="buildings", foreign_keys="BuildParts.build_id" + ) + decision_books: Mapped[List["BuildDecisionBook"]] = relationship( + "BuildDecisionBook", + back_populates="buildings", + foreign_keys="BuildDecisionBook.build_id", + ) + + # build_ibans: Mapped["BuildIbans"] = relationship( + # "BuildIbans", back_populates="building", foreign_keys="BuildIbans.build_id" + # ) + # areas: Mapped["BuildArea"] = relationship( + # "BuildArea", back_populates="buildings", foreign_keys="BuildArea.build_id" + # ) + # response_companies: Mapped["Companies"] = relationship( + # "Companies", + # back_populates="response_buildings", + # foreign_keys=[response_company_id], + # ) + # addresses: Mapped[List["Address"]] = relationship( + # "Address", back_populates="buildings", foreign_keys=[address_id] + # ) + # peoples: Mapped["People"] = relationship( + # "People", back_populates="buildings", foreign_keys=[people_id] + # ) + # sites: Mapped["BuildSites"] = relationship( + # "BuildSites", back_populates="buildings", foreign_keys=[site_id] + # ) + + __table_args__ = ( + Index("_builds_ndx_00", gov_address_code), + Index("_builds_ndx_01", build_name, build_no), + { + "comment": "Build objects are building that are created for living and store purposes" + }, + ) + + @property + def management_room(self): + with self.new_session() as db_session: + if management_room := BuildParts.filter_by_one( + system=True, id=self.management_room_id, build_id=self.id, db=db_session + ).data: + return management_room + return None + + @property + def top_flat(self): + max_flat_no = 0 + for part in self.parts: + if part.part_no > self.max_floor: + max_flat_no = part.part_no + return max_flat_no + + @property + def bottom_flat(self): + min_flat_no = 0 + for part in self.parts: + if part.part_no < self.max_floor: + min_flat_no = part.part_no + return min_flat_no + + @property + def human_livable_parts(self) -> tuple: + parts = list(part for part in self.parts if part.human_livable) + return parts, len(parts) + + @property + def livable_part_count(self): + with self.new_session() as db_session: + livable_parts = BuildParts.filter_all( + BuildParts.build_id == self.id, + BuildParts.human_livable == True, + db=db_session + ) + if not livable_parts.data: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="There is no livable part in this building.", + ) + return livable_parts.count + + @property + def part_type_count(self): + with self.new_session() as db_session: + building_types = None + for part in self.parts: + building_types = {} + build_type = BuildTypes.filter_by_one( + system=True, id=part.build_part_type_id, + db=db_session + ).data + if build_type.type_code in building_types: + building_types[build_type.type_code]["list"].append(part.part_no) + else: + building_types[build_type.type_code] = {"list": [part.part_no]} + + # for key, val in building_types.items(): + # list_parts = val["list"] + # building_types[key] = { + # "list": list_parts, + # "min": min(list_parts), + # "max": max(list_parts), + # "count": len(list_parts), + # } + return building_types + + +class BuildParts(CrudCollection): + """ + BuildParts class based on declarative_base and BaseMixin via session + Attentions: Part_no is unique for each building and Every building must have a management section.!!! default no 0 + """ + + __tablename__ = "build_parts" + __exclude__fields__ = [] + __include__fields__ = [] + __enum_list__ = [("part_direction", "Directions", "NN")] + + # https://adres.nvi.gov.tr/VatandasIslemleri/AdresSorgu + address_gov_code: Mapped[str] = mapped_column( + String, nullable=False, comment="Goverment Door Code" + ) + # part_name: Mapped[str] = mapped_column(String(24), server_default="", nullable=False, comment="Part Name") + part_no: Mapped[int] = mapped_column( + Integer, server_default="0", nullable=False, comment="Part Number" + ) + part_level: Mapped[int] = mapped_column( + Integer, server_default="0", comment="Building Part Level" + ) + part_code: Mapped[str] = mapped_column( + String, server_default="", nullable=False, comment="Part Code" + ) + part_gross_size: Mapped[int] = mapped_column( + Integer, server_default="0", comment="Part Gross Size" + ) + part_net_size: Mapped[int] = mapped_column( + Integer, server_default="0", comment="Part Net Size" + ) + default_accessory: Mapped[str] = mapped_column( + Text, server_default="0", comment="Default Accessory" + ) + human_livable: Mapped[bool] = mapped_column( + Boolean, server_default="1", comment="Human Livable" + ) + due_part_key: Mapped[str] = mapped_column( + String, server_default="", nullable=False, comment="Constant Payment Group" + ) + + build_id: Mapped[int] = mapped_column( + ForeignKey("build.id"), nullable=False, comment="Building ID" + ) + build_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Building UUID" + ) + part_direction_id: Mapped[int] = mapped_column( + ForeignKey("api_enum_dropdown.id"), nullable=True + ) + part_direction_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Part Direction UUID" + ) + part_type_id: Mapped[int] = mapped_column( + ForeignKey("build_types.id"), nullable=False, comment="Building Part Type" + ) + part_type_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Building Part Type UUID" + ) + + buildings: Mapped["Build"] = relationship( + "Build", back_populates="parts", foreign_keys=[build_id] + ) + + __table_args__ = ( + Index("build_parts_ndx_01", build_id, part_no, unique=True), + {"comment": "Part objects that are belong to building objects"}, + ) + + @property + def part_name(self): + with self.new_session() as db_session: + if build_type := BuildTypes.filter_by_one( + system=True, id=self.part_type_id, db=db_session + ).data: + return f"{str(build_type.type_name).upper()} : {str(self.part_no).upper()}" + return f"Undefined:{str(build_type.type_name).upper()}" + + +class BuildLivingSpace(CrudCollection): + """ + LivingSpace class based on declarative_base and BaseMixin via session + Owner or live person = Occupant of the build part + + Query OR(owner_person_id == person_id, life_person_id == person_id) AND (now(date)) + """ + + __tablename__ = "build_living_space" + __exclude__fields__ = [] + __include__fields__ = [] + + fix_value: Mapped[float] = mapped_column( + Numeric(20, 6), + server_default="0", + comment="Fixed value is deducted from debit.", + ) + fix_percent: Mapped[float] = mapped_column( + Numeric(6, 2), + server_default="0", + comment="Fixed percent is deducted from debit.", + ) + + agreement_no: Mapped[str] = mapped_column( + String, server_default="", comment="Agreement No" + ) + marketing_process: Mapped[bool] = mapped_column(Boolean, server_default="False") + marketing_layer: Mapped[int] = mapped_column(Integer, server_default="0") + + build_parts_id: Mapped[int] = mapped_column( + ForeignKey("build_parts.id"), + nullable=False, + index=True, + comment="Build Part ID", + ) + build_parts_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Build Part UUID" + ) + person_id: Mapped[int] = mapped_column( + ForeignKey("people.id"), + nullable=False, + index=True, + comment="Responsible People ID", + ) + person_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Responsible People UUID" + ) + occupant_type: Mapped[int] = mapped_column( + ForeignKey("occupant_types.id"), + nullable=False, + comment="Occupant Type", + ) + occupant_type_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Occupant Type UUID" + ) + + __table_args__ = ( + {"comment": "Living Space inside building parts that are related to people"}, + ) + + @classmethod + def find_living_from_customer_id( + cls, customer_id, process_date, add_days: int = 32 + ): + with cls.new_session() as db_session: + formatted_date = arrow.get(str(process_date)) + living_spaces = cls.filter_all( + or_( + cls.owner_person_id == customer_id, + cls.life_person_id == customer_id, + ), + cls.start_date < formatted_date - timedelta(days=add_days), + cls.stop_date > formatted_date + timedelta(days=add_days), + db=db_session + ) + return living_spaces.data, living_spaces.count + + +class BuildManagement(CrudCollection): + + __tablename__ = "build_management" + __exclude__fields__ = [] + + discounted_percentage: Mapped[float] = mapped_column( + Numeric(6, 2), server_default="0.00" + ) # %22 + discounted_price: Mapped[float] = mapped_column( + Numeric(20, 2), server_default="0.00" + ) # Normal: 78.00 TL + calculated_price: Mapped[float] = mapped_column( + Numeric(20, 2), server_default="0.00" + ) # sana düz 75.00 TL yapar + + occupant_type: Mapped[int] = mapped_column( + ForeignKey("occupant_types.id"), + nullable=False, + comment="Occupant Type", + ) + occupant_type_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Occupant Type UUID" + ) + build_id: Mapped[int] = mapped_column( + ForeignKey("build.id"), nullable=False, comment="Building ID" + ) + build_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Building UUID" + ) + build_parts_id: Mapped[int] = mapped_column( + ForeignKey("build_parts.id"), + nullable=False, + index=True, + comment="Build Part ID", + ) + build_parts_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Build Part UUID" + ) + + __table_args__ = ( + Index( + "build_management_ndx_00", + build_parts_id, + occupant_type, + "expiry_starts", + unique=True, + ), + {"comment": "Management of the building parts that are related to people"}, + ) + + +class BuildArea(CrudCollection): + """ + Builds class based on declarative_base and BaseMixin via session + """ + + __tablename__ = "build_area" + __exclude__fields__ = [] + + area_name: Mapped[str] = mapped_column(String, server_default="") + area_code: Mapped[str] = mapped_column(String, server_default="") + area_type: Mapped[str] = mapped_column(String, server_default="GREEN") + area_direction: Mapped[str] = mapped_column(String(2), server_default="NN") + area_gross_size: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + area_net_size: Mapped[float] = mapped_column(Numeric(20, 6), server_default="0") + width = mapped_column(Integer, server_default="0") + size = mapped_column(Integer, server_default="0") + + build_id: Mapped[int] = mapped_column(ForeignKey("build.id")) + build_uu_id: Mapped[str] = mapped_column(String, comment="Building UUID") + part_type_id: Mapped[int] = mapped_column( + ForeignKey("build_types.id"), nullable=True, comment="Building Part Type" + ) + part_type_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Building Part Type UUID" + ) + + # buildings: Mapped["Build"] = relationship( + # "Build", back_populates="areas", foreign_keys=[build_id] + # ) + + _table_args_ = ( + Index("_edm_build_parts_area_ndx_00", build_id, area_code, unique=True), + ) + + +class BuildSites(CrudCollection): + """ + Builds class based on declarative_base and BaseMixin via session + """ + + __tablename__ = "build_sites" + __exclude__fields__ = [] + __include__fields__ = [] + + site_name: Mapped[str] = mapped_column(String(24), nullable=False) + site_no: Mapped[str] = mapped_column(String(8), nullable=False) + + address_id: Mapped[int] = mapped_column(ForeignKey("addresses.id")) + address_uu_id: Mapped[str] = mapped_column(String, comment="Address UUID") + + # addresses: Mapped["Address"] = relationship( + # "Address", back_populates="site", foreign_keys=[address_id] + # ) + # buildings: Mapped["Build"] = relationship( + # "Build", back_populates="sites", foreign_keys="Build.site_id" + # ) + + __table_args__ = ( + Index("_sites_ndx_01", site_no, site_name), + {"comment": "Sites that groups building objets"}, + ) + + +class BuildCompaniesProviding(CrudCollection): + """ """ + + __tablename__ = "build_companies_providing" + __exclude__fields__ = [] + __include__fields__ = [] + + build_id = mapped_column( + ForeignKey("build.id"), nullable=False, comment="Building ID" + ) + build_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Providing UUID" + ) + company_id: Mapped[int] = mapped_column(ForeignKey("companies.id")) + company_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Providing UUID" + ) + provide_id: Mapped[int] = mapped_column( + ForeignKey("api_enum_dropdown.id"), nullable=True + ) + provide_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Providing UUID" + ) + contract_id: Mapped[int] = mapped_column( + Integer, ForeignKey("companies.id"), nullable=True + ) + + __table_args__ = ( + Index( + "_build_companies_providing_ndx_00", + build_id, + company_id, + provide_id, + unique=True, + ), + {"comment": "Companies providing services for building"}, + ) + + +class BuildPersonProviding(CrudCollection): + """ """ + + __tablename__ = "build_person_providing" + __exclude__fields__ = [] + __include__fields__ = [] + + build_id = mapped_column( + ForeignKey("build.id"), nullable=False, comment="Building ID" + ) + build_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Providing UUID" + ) + people_id: Mapped[int] = mapped_column(ForeignKey("people.id")) + people_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="People UUID" + ) + provide_id: Mapped[int] = mapped_column( + ForeignKey("api_enum_dropdown.id"), nullable=True + ) + provide_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Providing UUID" + ) + contract_id: Mapped[int] = mapped_column( + Integer, ForeignKey("companies.id"), nullable=True + ) + + __table_args__ = ( + Index( + "_build_person_providing_ndx_00", + build_id, + people_id, + provide_id, + unique=True, + ), + {"comment": "People providing services for building"}, + ) diff --git a/Schemas/building/decision_book.py b/Schemas/building/decision_book.py new file mode 100644 index 0000000..06998c8 --- /dev/null +++ b/Schemas/building/decision_book.py @@ -0,0 +1,880 @@ +import math +import arrow + +from datetime import datetime, timedelta +from decimal import Decimal +from typing import List, Any +from fastapi import HTTPException, status + +from sqlalchemy import ( + String, + ForeignKey, + Index, + SmallInteger, + Boolean, + TIMESTAMP, + Text, + Numeric, + Integer, +) +from sqlalchemy.orm import Mapped, mapped_column, relationship + +from Controllers.Postgres.mixin import CrudCollection + + +class BuildDecisionBook(CrudCollection): + """ + Builds class based on declarative_base and BaseMixin via session + The start dates of the decision log periods are determined from the 'decision_period_date' field in the decision log table within the building information. + decision_period_date = Her yıl yapılan karar toplantısı + 365 gün her yıl tekrar eden + decision_book_pdf_path: Karar defteri pdf dosyasının yolu + resp_company_fix_wage: Karar defterinin oluşmasını sağlayan dışardaki danışmanlık ücreti + is_out_sourced: Karar defterinin dışardan alınan hizmetle oluşturulup oluşturulmadığı + contact_agreement_path: Karar defterinin oluşmasını sağlayan dışardaki danışmanlık anlaşması dosyasının yolu + contact_agreement_date: Karar defterinin oluşmasını sağlayan dışardaki danışmanlık anlaşma tarihi + meeting_date: Karar defterinin oluşmasını sağlayan toplantı tarihi + decision_type: Karar defterinin tipi (Bina Yönetim Toplantısı (BYT), Yıllık Acil Toplantı (YAT) + """ + + __tablename__ = "build_decision_book" + __exclude__fields__ = [] + + decision_book_pdf_path: Mapped[str] = mapped_column( + String, server_default="", nullable=True + ) + resp_company_fix_wage: Mapped[float] = mapped_column( + Numeric(10, 2), server_default="0" + ) # + is_out_sourced: Mapped[bool] = mapped_column(Boolean, server_default="0") + meeting_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), server_default="1900-01-01" + ) + decision_type: Mapped[str] = mapped_column(String(3), server_default="RBM") + meeting_is_completed: Mapped[bool] = mapped_column(Boolean, server_default="0") + meeting_completed_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), nullable=True, comment="Meeting Completed Date" + ) + + build_id: Mapped[int] = mapped_column(ForeignKey("build.id"), nullable=False) + build_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Build UUID" + ) + resp_company_id: Mapped[int] = mapped_column(ForeignKey("companies.id")) + resp_company_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Company UUID" + ) + contact_id: Mapped[int] = mapped_column( + ForeignKey("contracts.id"), nullable=True, comment="Contract id" + ) + contact_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Contract UUID" + ) + + buildings: Mapped["Build"] = relationship( + "Build", + back_populates="decision_books", + foreign_keys=build_id, + ) + decision_book_items: Mapped[List["BuildDecisionBookItems"]] = relationship( + "BuildDecisionBookItems", + back_populates="decision_books", + foreign_keys="BuildDecisionBookItems.build_decision_book_id", + ) + + __table_args__ = ( + Index("build_decision_book_ndx_011", meeting_date, build_id), + Index("build_decision_book_ndx_011", build_id, "expiry_starts", "expiry_ends"), + { + "comment": "Decision Book objects that are related to decision taken at building meetings" + }, + ) + + @classmethod + def retrieve_active_rbm(cls): + from Schemas.building.build import Build + with cls.new_session() as db_session: + related_build = Build.find_one(id=cls.build_id) + related_date = arrow.get(related_build.build_date) + date_processed = related_date.replace( + year=arrow.now().date().year, month=related_date.month, day=1 + ) + if arrow.now().date() <= date_processed: + book = cls.filter_one( + cls.expiry_ends <= date_processed, + cls.decision_type == "RBM", + cls.build_id == related_build.id, + db=db_session + ).data + if not book: + cls.raise_http_exception( + status_code="HTTP_404_NOT_FOUND", + error_case="NOTFOUND", + message=f"Decision Book is not found for {related_build.build_name}-RBM", + data=dict( + build_id=str(related_build.uu_id), + build_name=related_build.build_name, + decision_type="RBM", + ), + ) + return book + return + + @property + def semester(self): + start_format = "".join( + [str(self.expiry_starts.year), "-", str(self.expiry_starts.month)] + ) + end_format = "".join( + [str(self.expiry_ends.year), "-", str(self.expiry_ends.month)] + ) + return "".join([start_format, " ", end_format]) + + def check_book_is_valid(self, bank_date: str): + if all( + [True if letter in str(bank_date) else False for letter in ["-", " ", ":"]] + ): + bank_date = datetime.strptime(str(bank_date), "%Y-%m-%d %H:%M:%S") + date_valid = ( + arrow.get(self.expiry_starts) + < arrow.get(bank_date) + < arrow.get(self.expiry_ends) + ) + return date_valid and self.active and not self.deleted + + # @classmethod + # def retrieve_valid_book(cls, bank_date, iban): + # from Schemas import ( + # BuildIbans, + # ) + # with cls.new_session() as db_session: + # if all( + # [True if letter in str(bank_date) else False for letter in ["-", " ", ":"]] + # ): + # bank_date = datetime.strptime(str(bank_date), "%Y-%m-%d %H:%M:%S") + # build_iban = BuildIbans.find_one(iban=iban) + # decision_book: cls = cls.filter_one( + # cls.build_id == build_iban.build_id, + # cls.expiry_starts < bank_date, + # cls.expiry_ends > bank_date, + # cls.active == True, + # cls.deleted == False, + # db=db_session + # ).data + # decision_book.check_book_is_valid(bank_date.__str__()) + # return decision_book + # return + + +class BuildDecisionBookInvitations(CrudCollection): + """ + Builds class based on declarative_base and BaseMixin via session + """ + + __tablename__ = "build_decision_book_invitations" + __exclude__fields__ = [] + + build_id: Mapped[int] = mapped_column(Integer, nullable=False) + build_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Build UUID" + ) + decision_book_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book.id"), nullable=False + ) + decision_book_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Decision Book UUID" + ) + + invitation_type: Mapped[str] = mapped_column( + String, nullable=False, comment="Invite Type" + ) + invitation_attempt: Mapped[int] = mapped_column(SmallInteger, server_default="1") + living_part_count: Mapped[int] = mapped_column(SmallInteger, server_default="1") + living_part_percentage: Mapped[float] = mapped_column( + Numeric(10, 2), server_default="0.51" + ) + + message: Mapped[str] = mapped_column( + Text, nullable=True, comment="Invitation Message" + ) + planned_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), nullable=False, comment="Planned Meeting Date" + ) + planned_date_expires: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), nullable=False, comment="Planned Meeting Date Expires" + ) + + __table_args__ = ( + Index( + "_build_decision_book_invitations_ndx_01", + invitation_type, + planned_date, + invitation_attempt, + unique=True, + ), + {"comment": "People that are invited to building meetings."}, + ) + + @classmethod + def check_invites_are_ready_for_meeting(cls, selected_decision_book, token_dict): + with cls.new_session() as db_session: + first_book_invitation = BuildDecisionBookInvitations.filter_one( + BuildDecisionBookInvitations.build_id + == token_dict.selected_occupant.build_id, + BuildDecisionBookInvitations.decision_book_id == selected_decision_book.id, + BuildDecisionBookInvitations.invitation_attempt == 1, + db=db_session, + ).data + if not first_book_invitation: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"First Meeting Invitation is not found for Decision Book UUID : {selected_decision_book.uu_id}", + ) + need_attend_count = int(first_book_invitation.living_part_count) * Decimal( + first_book_invitation.living_part_percentage + ) + valid_invite_count = ( + BuildDecisionBookPerson.filter_all_system( + BuildDecisionBookPerson.invite_id == first_book_invitation.id, + BuildDecisionBookPerson.build_decision_book_id + == selected_decision_book.id, + BuildDecisionBookPerson.is_attending == True, + db=db_session, + ) + .query.distinct(BuildDecisionBookPerson.person_id) + .count() + ) + + second_book_invitation = BuildDecisionBookInvitations.filter_one_system( + BuildDecisionBookInvitations.build_id + == token_dict.selected_occupant.build_id, + BuildDecisionBookInvitations.decision_book_id == selected_decision_book.id, + BuildDecisionBookInvitations.invitation_attempt == 2, + db=db_session, + ).data + if not valid_invite_count >= need_attend_count and not second_book_invitation: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"In order meeting to be held, {math.ceil(need_attend_count)} people must attend " + f"to the meeting. Only {valid_invite_count} people are attending to the meeting.", + ) + return first_book_invitation or second_book_invitation + + +class BuildDecisionBookPerson(CrudCollection): + """ + Builds class based on declarative_base and BaseMixin via session + Karar Defteri toplantılarına katılan kişiler veya yetkililer + dues_percent_discount: Katılımcının aidat indirim oranı Aidatdan yüzde indirim alır + dues_fix_discount: Katılımcının aidat sabit miktarı Aidatdan sabit bir miktar indirim alır + dues_discount_approval_date: Bu kişinin indiriminin onayladığı tarih + management_typecode: Kişinin toplantı görevi + """ + + __tablename__ = "build_decision_book_person" + __exclude__fields__ = [] + __enum_list__ = [("management_typecode", "BuildManagementType", "bm")] + + dues_percent_discount: Mapped[int] = mapped_column(SmallInteger, server_default="0") + dues_fix_discount: Mapped[float] = mapped_column(Numeric(10, 2), server_default="0") + dues_discount_approval_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), server_default="1900-01-01 00:00:00" + ) + send_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), nullable=False, comment="Confirmation Date" + ) + is_attending: Mapped[bool] = mapped_column( + Boolean, server_default="0", comment="Occupant is Attending to invitation" + ) + confirmed_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), nullable=True, comment="Confirmation Date" + ) + token: Mapped[str] = mapped_column( + String, server_default="", comment="Invitation Token" + ) + + vicarious_person_id: Mapped[int] = mapped_column( + ForeignKey("people.id"), nullable=True, comment="Vicarious Person ID" + ) + vicarious_person_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Vicarious Person UUID" + ) + + invite_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book_invitations.id"), nullable=False + ) + invite_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Invite UUID" + ) + + build_decision_book_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book.id"), nullable=False + ) + build_decision_book_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Decision Book UUID" + ) + build_living_space_id: Mapped[int] = mapped_column( + ForeignKey("build_living_space.id"), nullable=False + ) + build_living_space_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Living Space UUID" + ) + person_id: Mapped[int] = mapped_column(ForeignKey("people.id"), nullable=False) + # person_uu_id: Mapped[str] = mapped_column(String, nullable=False, comment="Person UUID") + + __table_args__ = ( + Index( + "_build_decision_book_person_ndx_01", + build_decision_book_id, + invite_id, + build_living_space_id, + unique=True, + ), + {"comment": "People that are attended to building meetings."}, + ) + + def retrieve_all_occupant_types(self): + with self.new_session() as db_session: + all_decision_book_people = self.filter_all_system( + BuildDecisionBookPersonOccupants.invite_id == self.invite_id, + db=db_session + ) + BuildDecisionBookPersonOccupants.pre_query = all_decision_book_people.query + return BuildDecisionBookPersonOccupants.filter_all_system( + db=db_session + ).data + + def get_occupant_types(self): + with self.new_session() as db_session: + if occupants := BuildDecisionBookPersonOccupants.filter_all( + BuildDecisionBookPersonOccupants.build_decision_book_person_id == self.id, + db=db_session + ).data: + return occupants + return + + def check_occupant_type(self, occupant_type): + with self.new_session() as db_session: + book_person_occupant_type = BuildDecisionBookPersonOccupants.filter_one( + BuildDecisionBookPersonOccupants.build_decision_book_person_id == self.id, + BuildDecisionBookPersonOccupants.occupant_type_id == occupant_type.id, + BuildDecisionBookPersonOccupants.active == True, + BuildDecisionBookPersonOccupants.is_confirmed == True, + db=db_session, + ).data + if not book_person_occupant_type: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Occupant Type : {occupant_type.occupant_code} is not found in " + f"Decision Book Person UUID {self.uu_id}", + ) + + +class BuildDecisionBookPersonOccupants(CrudCollection): + """ + Builds class based on declarative_base and BaseMixin via session + """ + + __tablename__ = "build_decision_book_person_occupants" + __exclude__fields__ = [] + + build_decision_book_person_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book_person.id"), nullable=False + ) + build_decision_book_person_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Decision Book Person UUID" + ) + invite_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book_invitations.id"), nullable=True + ) + invite_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Invite UUID" + ) + + occupant_type_id: Mapped[int] = mapped_column( + ForeignKey("occupant_types.id"), nullable=False + ) + occupant_type_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Occupant UUID" + ) + + __table_args__ = ( + Index( + "_build_decision_book_person_occupants_ndx_01", + build_decision_book_person_id, + occupant_type_id, + unique=True, + ), + {"comment": "Occupant Types of People that are attended to building meetings."}, + ) + + +class BuildDecisionBookItems(CrudCollection): + """ + Builds class based on declarative_base and BaseMixin via session + item_commentary = metine itiraz şerh maddesi için + item_order = maddelerin sıralanma numarası + item_objection = maddelerin itiraz şerhi Text şeklinde + """ + + __tablename__ = "build_decision_book_items" + __exclude__fields__ = [] + + item_order: Mapped[int] = mapped_column( + SmallInteger, nullable=False, comment="Order Number of Item" + ) + item_comment: Mapped[str] = mapped_column( + Text, nullable=False, comment="Comment Content" + ) + item_objection: Mapped[str] = mapped_column( + Text, nullable=True, comment="Objection Content" + ) + info_is_completed: Mapped[bool] = mapped_column( + Boolean, server_default="0", comment="Info process is Completed" + ) + is_payment_created: Mapped[bool] = mapped_column( + Boolean, server_default="0", comment="Are payment Records Created" + ) + + info_type_id: Mapped[int] = mapped_column( + ForeignKey("api_enum_dropdown.id"), nullable=True + ) + info_type_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Info Type UUID" + ) + + build_decision_book_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book.id"), nullable=False + ) + build_decision_book_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Decision Book UUID" + ) + item_short_comment: Mapped[str] = mapped_column( + String(24), + nullable=True, + comment="This field is reserved for use in grouping data or in the pivot heading.", + ) + + decision_books: Mapped["BuildDecisionBook"] = relationship( + "BuildDecisionBook", + back_populates="decision_book_items", + foreign_keys=[build_decision_book_id], + ) + decision_book_project: Mapped["BuildDecisionBookProjects"] = relationship( + "BuildDecisionBookProjects", + back_populates="build_decision_book_item", + foreign_keys="BuildDecisionBookProjects.build_decision_book_item_id", + ) + + __table_args__ = ( + Index("_build_decision_book_item_ndx_01", build_decision_book_id), + Index( + "_build_decision_book_item_ndx_02", + build_decision_book_id, + item_order, + unique=True, + ), + { + "comment": "Decision Book Items that are related to decision taken at building meetings" + }, + ) + + +class BuildDecisionBookItemsUnapproved(CrudCollection): + """ + Builds class based on declarative_base and BaseMixin via session unapproved personnel + """ + + __tablename__ = "build_decision_book_items_unapproved" + __exclude__fields__ = [] + + item_objection: Mapped[str] = mapped_column( + Text, nullable=False, comment="Objection Content" + ) + item_order: Mapped[int] = mapped_column( + SmallInteger, nullable=False, comment="Order Number" + ) + + decision_book_item_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book_items.id"), nullable=False + ) + decision_book_item_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Decision Book Item" + ) + person_id: Mapped[int] = mapped_column(ForeignKey("people.id"), nullable=False) + person_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Person UUID" + ) + build_decision_book_item: Mapped[int] = mapped_column( + ForeignKey("build_decision_book_items.id"), nullable=False + ) + build_decision_book_item_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Decision Book Item UUID" + ) + + __table_args__ = ( + Index("_build_decision_book_item_unapproved_ndx_01", build_decision_book_item), + { + "comment": "People that are unapproved partially or completely in decision book items" + }, + ) + + +class BuildDecisionBookPayments(CrudCollection): + """ + Builds class based on declarative_base and BaseMixin via session + period_time = to_char(NEW.process_date, 'YYYY-MM'); + """ + + __tablename__ = "build_decision_book_payments" + __exclude__fields__ = [] + __enum_list__ = [("receive_debit", "DebitTypes", "D")] + + payment_plan_time_periods: Mapped[str] = mapped_column( + String(10), nullable=False, comment="Payment Plan Time Periods" + ) + process_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), nullable=False, comment="Payment Due Date" + ) + payment_amount: Mapped[float] = mapped_column( + Numeric(16, 2), nullable=False, comment="Payment Amount" + ) + currency: Mapped[str] = mapped_column(String(8), server_default="TRY") + + payment_types_id: Mapped[int] = mapped_column( + ForeignKey("api_enum_dropdown.id"), nullable=True + ) + payment_types_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Dues Type UUID" + ) + + period_time: Mapped[str] = mapped_column(String(12)) + process_date_y: Mapped[int] = mapped_column(SmallInteger) + process_date_m: Mapped[int] = mapped_column(SmallInteger) + + build_decision_book_item_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book_items.id"), + nullable=False, + comment="Build Decision Book Item ID", + ) + build_decision_book_item_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Decision Book Item UUID" + ) + # build_decision_book_id: Mapped[int] = mapped_column( + # ForeignKey("build_decision_book.id"), nullable=True + # ) + # build_decision_book_uu_id: Mapped[str] = mapped_column( + # String, nullable=True, comment="Decision Book UUID" + # ) + build_parts_id: Mapped[int] = mapped_column( + ForeignKey("build_parts.id"), nullable=False + ) + build_parts_uu_id: Mapped[str] = mapped_column( + String, nullable=False, comment="Build Part UUID" + ) + decision_book_project_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book_projects.id"), + nullable=True, + comment="Decision Book Project ID", + ) + decision_book_project_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Decision Book Project UUID" + ) + account_records_id: Mapped[int] = mapped_column( + ForeignKey("account_records.id"), nullable=True + ) + account_records_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Account Record UU ID" + ) + + # budget_records_id: Mapped[int] = mapped_column(ForeignKey("account_records.id"), nullable=True) + # budget_records_uu_id: Mapped[str] = mapped_column( + # String, nullable=True, comment="Budget UUID" + # ) + # accounting_id: Mapped[int] = mapped_column(ForeignKey("account_detail.id"), nullable=True) + # accounting_uu_id: Mapped[str] = mapped_column( + # String, nullable=True, comment="Accounting UUID" + # ) + # receive_debit_id: Mapped[int] = mapped_column(ForeignKey("api_enum_dropdown.id"), nullable=True) + # receive_debit_uu_id: Mapped[str] = mapped_column(String, nullable=True, comment="Debit UUID") + + # accounting: Mapped["AccountDetail"] = relationship( + # "AccountDetail", + # back_populates="decision_book_payment_detail", + # foreign_keys=[accounting_id], + # ) + # + # decision_book_master: Mapped["BuildDecisionBookPaymentsMaster"] = relationship( + # "BuildDecisionBookPaymentsMaster", + # back_populates="decision_book_payment_detail", + # foreign_keys=[build_decision_book_payments_master_id], + # ) + # budget_records: Mapped["CompanyBudgetRecords"] = relationship( + # "CompanyBudgetRecords", + # back_populates="decision_book_payment_detail", + # foreign_keys=[budget_records_id], + # ) + + __table_args__ = ( + Index( + "build_decision_book_payments_detail_ndx_00", + build_decision_book_item_id, + build_parts_id, + payment_plan_time_periods, + process_date, + payment_types_id, + account_records_id, + unique=True, + ), + Index("build_decision_book_payments_detail_ndx_01", account_records_id), + {"comment": "Payment Details of Decision Book Payments"}, + ) + + +class BuildDecisionBookLegal(CrudCollection): + """ + Builds class based on declarative_base and BaseMixin via session + lawsuits_type C:Court Mehkeme M: mediator arabulucu + """ + + __tablename__ = "build_decision_book_legal" + __exclude__fields__ = [] + + period_start_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), nullable=False, comment="Start Date of Legal Period" + ) + lawsuits_decision_number: Mapped[str] = mapped_column( + String, nullable=False, comment="Lawsuits Decision Number" + ) + lawsuits_decision_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), nullable=False, comment="Lawsuits Decision Date" + ) + + period_stop_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), server_default="2099-12-31 23:59:59" + ) + decision_book_pdf_path: Mapped[str] = mapped_column( + String, server_default="", nullable=True + ) + resp_company_total_wage: Mapped[float] = mapped_column( + Numeric(10, 2), server_default="0", nullable=True + ) + contact_agreement_path: Mapped[str] = mapped_column( + String, server_default="", nullable=True + ) + contact_agreement_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), server_default="1900-01-01 00:00:00", nullable=True + ) + meeting_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), server_default="1900-01-01 00:00:00" + ) + lawsuits_type: Mapped[str] = mapped_column(String(1), server_default="C") + lawsuits_name: Mapped[str] = mapped_column(String(128)) + lawsuits_note: Mapped[str] = mapped_column(String(512)) + lawyer_cost: Mapped[float] = mapped_column(Numeric(20, 2)) + mediator_lawyer_cost: Mapped[float] = mapped_column(Numeric(20, 2)) + other_cost: Mapped[float] = mapped_column(Numeric(20, 2)) + legal_cost: Mapped[float] = mapped_column(Numeric(20, 2)) + approved_cost: Mapped[float] = mapped_column(Numeric(20, 2)) + total_price: Mapped[float] = mapped_column(Numeric(20, 2)) + + build_db_item_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book_items.id"), nullable=False + ) + build_db_item_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Decision Book Item UUID" + ) + resp_attorney_id: Mapped[int] = mapped_column( + ForeignKey("people.id"), nullable=False + ) + resp_attorney_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Attorney UUID" + ) + resp_attorney_company_id: Mapped[int] = mapped_column(ForeignKey("companies.id")) + resp_attorney_company_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Company UUID" + ) + mediator_lawyer_person_id: Mapped[int] = mapped_column(ForeignKey("people.id")) + mediator_lawyer_person_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Mediator Lawyer UUID" + ) + + __table_args__ = ( + Index("_build_decision_book_legal_ndx_00", meeting_date), + { + "comment": "Legal items related to decision book items recoreded at building meetings" + }, + ) + + +class BuildDecisionBookProjects(CrudCollection): + """ + Builds class based on declarative_base and BaseMixin via session + project_type = C:Court Mehkeme M: mediator arabulucu + """ + + __tablename__ = "build_decision_book_projects" + __exclude__fields__ = [] + + project_no: Mapped[str] = mapped_column( + String(12), nullable=True, comment="Project Number of Decision Book" + ) + project_name: Mapped[str] = mapped_column( + String, nullable=False, comment="Project Name" + ) + project_start_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), nullable=False, comment="Project Start Date" + ) + project_stop_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), server_default="2099-12-31 23:59:59" + ) + project_type: Mapped[str] = mapped_column(String, server_default="C") + project_note: Mapped[str] = mapped_column(Text) + + decision_book_pdf_path: Mapped[str] = mapped_column( + String, server_default="", nullable=True + ) + is_completed: Mapped[bool] = mapped_column( + Boolean, server_default="0", comment="Project is Completed" + ) + status_code: Mapped[int] = mapped_column(SmallInteger, nullable=True) + resp_company_fix_wage: Mapped[float] = mapped_column( + Numeric(10, 2), server_default="0" + ) + is_out_sourced: Mapped[bool] = mapped_column(Boolean, server_default="0") + + meeting_date: Mapped[TIMESTAMP] = mapped_column( + TIMESTAMP(timezone=True), server_default="1900-01-01 00:00:00", index=True + ) + currency: Mapped[str] = mapped_column(String(8), server_default="TRY") + bid_price: Mapped[float] = mapped_column(Numeric(16, 4), server_default="0") + approved_price: Mapped[float] = mapped_column(Numeric(16, 4), server_default="0") + final_price: Mapped[float] = mapped_column(Numeric(16, 4), server_default="0") + + contact_id: Mapped[int] = mapped_column( + ForeignKey("contracts.id"), nullable=True, comment="Contract id" + ) + contact_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Contract UUID" + ) + build_decision_book_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book.id"), nullable=False + ) + build_decision_book_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Decision Book UUID" + ) + build_decision_book_item_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book_items.id"), nullable=False + ) + build_decision_book_item_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Decision Book Item UUID" + ) + project_response_living_space_id: Mapped[int] = mapped_column( + ForeignKey("build_living_space.id"), + nullable=True, + comment="Project Response Person ID", + ) + project_response_living_space_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Project Response Person UUID" + ) + resp_company_id: Mapped[int] = mapped_column( + ForeignKey("companies.id"), nullable=True + ) + resp_company_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Company UUID" + ) + + build_decision_book_item: Mapped["BuildDecisionBookItems"] = relationship( + "BuildDecisionBookItems", + back_populates="decision_book_project", + foreign_keys=[build_decision_book_item_id], + ) + + __table_args__ = ( + Index( + "_build_decision_book_project_ndx_00", + project_no, + project_start_date, + unique=True, + ), + { + "comment": "Project related to decision taken at building meetings on book items" + }, + ) + + @property + def get_project_year(self): + return self.decision_book_items.decision_books.period_start_date.year + + @property + def get_project_no(self): + return f"{self.get_project_year}-{str(self.id)[-4:].zfill(4)}" + + +class BuildDecisionBookProjectPerson(CrudCollection): + """ + Builds class based on declarative_base and BaseMixin via session + """ + + __tablename__ = "build_decision_book_project_person" + __exclude__fields__ = [] + # __enum_list__ = [("management_typecode", "ProjectTeamTypes", "PTT-EMP")] + + dues_percent_discount: Mapped[int] = mapped_column(SmallInteger, server_default="0") + job_fix_wage: Mapped[float] = mapped_column(Numeric(10, 2), server_default="0") + bid_price: Mapped[float] = mapped_column(Numeric(10, 2), server_default="0") + decision_price: Mapped[float] = mapped_column(Numeric(10, 2), server_default="0") + + build_decision_book_project_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book_projects.id"), nullable=False + ) + build_decision_book_project_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Decision Book Project UUID" + ) + living_space_id: Mapped[int] = mapped_column( + ForeignKey("build_living_space.id"), nullable=False + ) + living_space_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Living Space UUID" + ) + + __table_args__ = ( + {"comment": "People that are attended to building project meetings."}, + ) + + +class BuildDecisionBookProjectItems(CrudCollection): + """ + Builds class based on declarative_base and BaseMixin via session + """ + + __tablename__ = "build_decision_book_project_items" + __exclude__fields__ = [] + + item_header: Mapped[str] = mapped_column( + String, nullable=False, comment="Item Header" + ) + item_comment: Mapped[str] = mapped_column( + Text, nullable=False, comment="Item Comment" + ) + attachment_pdf_path: Mapped[str] = mapped_column( + String, server_default="", nullable=True, comment="Attachment PDF Path" + ) + item_estimated_cost: Mapped[float] = mapped_column( + Numeric(16, 2), server_default="0", comment="Estimated Cost" + ) + item_short_comment: Mapped[str] = mapped_column( + String(24), + nullable=True, + comment="This field is reserved for use in grouping data or in the pivot heading.", + ) + + build_decision_book_project_id: Mapped[int] = mapped_column( + ForeignKey("build_decision_book_projects.id"), nullable=False + ) + build_decision_book_project_uu_id: Mapped[str] = mapped_column( + String, nullable=True, comment="Decision Book Project UUID" + ) + + __table_args__ = ( + {"comment": "Project Items related to decision taken at building meetings"}, + ) diff --git a/Trash/tester_app.py b/Trash/tester_app.py new file mode 100644 index 0000000..68ed880 --- /dev/null +++ b/Trash/tester_app.py @@ -0,0 +1,27 @@ +""" +FastAPI Application Entry Point + +This module initializes and configures the FastAPI application with: +- CORS middleware for cross-origin requests +- Request timing middleware for performance monitoring +- Custom exception handlers for consistent error responses +- Prometheus instrumentation for metrics +- API routers for endpoint organization +""" + +import uvicorn + +from prometheus_fastapi_instrumentator import Instrumentator +from app_handler import setup_middleware +from create_file import create_app +from config import ApiConfig + + +app = create_app() # Initialize FastAPI application +Instrumentator().instrument(app=app).expose(app=app) # Setup Prometheus metrics +setup_middleware(app) # Configure middleware and exception handlers + + +if __name__ == "__main__": + # Run the application with Uvicorn + uvicorn.Server(uvicorn.Config(**ApiConfig.as_dict())).run() diff --git a/api_env.env b/api_env.env index f6c8b34..ecf714c 100644 --- a/api_env.env +++ b/api_env.env @@ -19,4 +19,12 @@ POSTGRES_ECHO=True REDIS_HOST=redis_service REDIS_PASSWORD=commercial_redis_password REDIS_PORT=6379 -REDIS_DB=0 \ No newline at end of file +REDIS_DB=0 +API_ACCESS_TOKEN_TAG=evyos-session-key +API_ACCESS_EMAIL_EXT=evyos.com.tr +API_ALGORITHM=HS256 +API_ACCESS_TOKEN_LENGTH=90 +API_REFRESHER_TOKEN_LENGTH=144 +API_EMAIL_HOST=10.10.2.36 +API_DATETIME_FORMAT=YYYY-MM-DD HH:mm:ss Z +API_FORGOT_LINK=https://www.evyos.com.tr/password/create?tokenUrl= diff --git a/docker-compose.yml b/docker-compose.yml index 1fb7175..3714bfc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -49,15 +49,43 @@ services: ports: - "11222:6379" - test_server: - container_name: test_server + template_service: + container_name: template_service build: context: . - dockerfile: ApiServices/Dockerfile - env_file: - - api_env.env + dockerfile: ApiServices/TemplateService/Dockerfile networks: - wag-services + env_file: + - api_env.env + environment: + - API_PATH=app:app + - API_HOST=0.0.0.0 + - API_PORT=8000 + - API_LOG_LEVEL=info + - API_RELOAD=1 + - API_ACCESS_TOKEN_TAG=1 + - API_APP_NAME=evyos-template-api-gateway + - API_TITLE=WAG API Template Api Gateway + - API_FORGOT_LINK=https://template_service/forgot-password + - API_DESCRIPTION=This api is serves as web template api gateway only to evyos web services. + - API_APP_URL=https://template_service + ports: + - "8000:8000" + depends_on: + - postgres-service + - mongo_service + - redis_service + +# test_server: +# container_name: test_server +# build: +# context: . +# dockerfile: ApiServices/Dockerfile +# env_file: +# - api_env.env +# networks: +# - wag-services networks: wag-services: diff --git a/hello.py b/hello.py deleted file mode 100644 index c7e2e67..0000000 --- a/hello.py +++ /dev/null @@ -1,6 +0,0 @@ -def main(): - print("Hello from prod-wag-backend-automate-services!") - - -if __name__ == "__main__": - main() diff --git a/pyproject.toml b/pyproject.toml index d91a9f9..5d4e085 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,6 +11,7 @@ dependencies = [ "faker>=37.1.0", "fastapi>=0.115.12", "pandas>=2.2.3", + "prometheus-fastapi-instrumentator>=7.1.0", "psycopg2-binary>=2.9.10", "pydantic-settings>=2.8.1", "pymongo>=4.11.3", diff --git a/uv.lock b/uv.lock index a85eec9..6fda53e 100644 --- a/uv.lock +++ b/uv.lock @@ -442,6 +442,7 @@ dependencies = [ { name = "faker" }, { name = "fastapi" }, { name = "pandas" }, + { name = "prometheus-fastapi-instrumentator" }, { name = "psycopg2-binary" }, { name = "pydantic-settings" }, { name = "pymongo" }, @@ -464,6 +465,7 @@ requires-dist = [ { name = "faker", specifier = ">=37.1.0" }, { name = "fastapi", specifier = ">=0.115.12" }, { name = "pandas", specifier = ">=2.2.3" }, + { name = "prometheus-fastapi-instrumentator", specifier = ">=7.1.0" }, { name = "psycopg2-binary", specifier = ">=2.9.10" }, { name = "pydantic-settings", specifier = ">=2.8.1" }, { name = "pymongo", specifier = ">=4.11.3" }, @@ -478,6 +480,28 @@ requires-dist = [ { name = "uvicorn", specifier = ">=0.34.0" }, ] +[[package]] +name = "prometheus-client" +version = "0.21.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/62/14/7d0f567991f3a9af8d1cd4f619040c93b68f09a02b6d0b6ab1b2d1ded5fe/prometheus_client-0.21.1.tar.gz", hash = "sha256:252505a722ac04b0456be05c05f75f45d760c2911ffc45f2a06bcaed9f3ae3fb", size = 78551 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/c2/ab7d37426c179ceb9aeb109a85cda8948bb269b7561a0be870cc656eefe4/prometheus_client-0.21.1-py3-none-any.whl", hash = "sha256:594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301", size = 54682 }, +] + +[[package]] +name = "prometheus-fastapi-instrumentator" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "prometheus-client" }, + { name = "starlette" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/6d/24d53033cf93826aa7857699a4450c1c67e5b9c710e925b1ed2b320c04df/prometheus_fastapi_instrumentator-7.1.0.tar.gz", hash = "sha256:be7cd61eeea4e5912aeccb4261c6631b3f227d8924542d79eaf5af3f439cbe5e", size = 20220 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/72/0824c18f3bc75810f55dacc2dd933f6ec829771180245ae3cc976195dec0/prometheus_fastapi_instrumentator-7.1.0-py3-none-any.whl", hash = "sha256:978130f3c0bb7b8ebcc90d35516a6fe13e02d2eb358c8f83887cdef7020c31e9", size = 19296 }, +] + [[package]] name = "psycopg2-binary" version = "2.9.10"