From 61529f7d94100c302f73ac8564b4db91825e47b2 Mon Sep 17 00:00:00 2001 From: Berkay Date: Sun, 17 Aug 2025 21:14:46 +0300 Subject: [PATCH] rabbitmq implemented and tested --- .../app/services/database/=0.20.0 => =9.4.1 | 0 .../Reader/Banks/IsBank/app.py | 18 +- ServicesRunner/Depends/mail_handler.py | 3 +- ServicesRunner/Depends/prisma_client.py | 11 +- .../app/services/common/service_base_async.py | 292 +- ServicesTask/app/services/database/Dockerfile | 14 +- .../app/services/database/entrypoint.sh | 21 + ServicesTask/app/services/database/main.py | 54 +- .../app/services/database/prisma_client.py | 189 + .../app/services/database/pyproject.toml | 10 +- .../app/services/database/requirements.txt | 6 + .../app/services/database/schema.prisma | 3661 +++++++++++++++++ .../app/services/mail/IsBank/params.py | 18 + .../app/services/mail/IsBank/runner.py | 29 + ServicesTask/app/services/mail/config.py | 155 + .../app/services/mail/mail_handler.py | 381 ++ ServicesTask/app/services/mail/main.py | 109 +- ServicesTask/app/services/mail/pyproject.toml | 10 +- .../app/services/{queue => mongo}/Dockerfile | 8 +- .../app/services/{queue => mongo}/README.md | 0 .../app/services/{queue => mongo}/__init__.py | 0 ServicesTask/app/services/mongo/main.py | 40 + .../services/{queue => mongo}/pyproject.toml | 6 +- .../{queue => mongo}/queue_service_async.py | 0 ServicesTask/app/services/parser/a.txt | 0 .../app/services/parser/comment/Dockerfile | 18 + .../app/services/parser/comment/README.md | 0 .../app/services/parser/comment/main.py | 30 + .../services/parser/comment/pyproject.toml | 37 + .../app/services/parser/excel/Dockerfile | 18 + .../app/services/parser/excel/README.md | 0 .../app/services/parser/excel/main.py | 40 + .../app/services/parser/excel/pyproject.toml | 37 + .../app/services/parser/mail/Dockerfile | 18 + .../app/services/parser/mail/README.md | 0 ServicesTask/app/services/parser/mail/main.py | 42 + .../app/services/parser/mail/pyproject.toml | 37 + .../app/services/parser/payment/Dockerfile | 18 + .../app/services/parser/payment/README.md | 0 .../app/services/parser/payment/main.py | 43 + .../services/parser/payment/pyproject.toml | 37 + ServicesTask/app/services/queue/main.py | 17 - ServicesTask/docker-compose.yml | 321 +- 43 files changed, 5433 insertions(+), 315 deletions(-) rename ServicesTask/app/services/database/=0.20.0 => =9.4.1 (100%) create mode 100644 ServicesTask/app/services/database/entrypoint.sh create mode 100644 ServicesTask/app/services/database/prisma_client.py create mode 100644 ServicesTask/app/services/database/requirements.txt create mode 100644 ServicesTask/app/services/database/schema.prisma create mode 100644 ServicesTask/app/services/mail/IsBank/params.py create mode 100644 ServicesTask/app/services/mail/IsBank/runner.py create mode 100644 ServicesTask/app/services/mail/config.py create mode 100644 ServicesTask/app/services/mail/mail_handler.py rename ServicesTask/app/services/{queue => mongo}/Dockerfile (60%) rename ServicesTask/app/services/{queue => mongo}/README.md (100%) rename ServicesTask/app/services/{queue => mongo}/__init__.py (100%) create mode 100644 ServicesTask/app/services/mongo/main.py rename ServicesTask/app/services/{queue => mongo}/pyproject.toml (89%) rename ServicesTask/app/services/{queue => mongo}/queue_service_async.py (100%) create mode 100644 ServicesTask/app/services/parser/a.txt create mode 100644 ServicesTask/app/services/parser/comment/Dockerfile create mode 100644 ServicesTask/app/services/parser/comment/README.md create mode 100644 ServicesTask/app/services/parser/comment/main.py create mode 100644 ServicesTask/app/services/parser/comment/pyproject.toml create mode 100644 ServicesTask/app/services/parser/excel/Dockerfile create mode 100644 ServicesTask/app/services/parser/excel/README.md create mode 100644 ServicesTask/app/services/parser/excel/main.py create mode 100644 ServicesTask/app/services/parser/excel/pyproject.toml create mode 100644 ServicesTask/app/services/parser/mail/Dockerfile create mode 100644 ServicesTask/app/services/parser/mail/README.md create mode 100644 ServicesTask/app/services/parser/mail/main.py create mode 100644 ServicesTask/app/services/parser/mail/pyproject.toml create mode 100644 ServicesTask/app/services/parser/payment/Dockerfile create mode 100644 ServicesTask/app/services/parser/payment/README.md create mode 100644 ServicesTask/app/services/parser/payment/main.py create mode 100644 ServicesTask/app/services/parser/payment/pyproject.toml delete mode 100644 ServicesTask/app/services/queue/main.py diff --git a/ServicesTask/app/services/database/=0.20.0 b/=9.4.1 similarity index 100% rename from ServicesTask/app/services/database/=0.20.0 rename to =9.4.1 diff --git a/ServicesRunner/AccountRecordServices/Reader/Banks/IsBank/app.py b/ServicesRunner/AccountRecordServices/Reader/Banks/IsBank/app.py index ac9762b..c424461 100644 --- a/ServicesRunner/AccountRecordServices/Reader/Banks/IsBank/app.py +++ b/ServicesRunner/AccountRecordServices/Reader/Banks/IsBank/app.py @@ -37,14 +37,14 @@ def initialize_service(): # Create singleton instances directly logger.info("Creating Redis handler singleton") redis_handler = MailReaderService() - + logger.info("Creating EmailReaderService") email_service = EmailReaderService(IsBankConfig()) - + # Initialize email service and connect logger.info("Connecting to email service") email_service.login_and_connect() - + # Create email service runner with the singletons logger.info("Creating EmailServiceRunner") runner = EmailServiceRunner(redis_handler=redis_handler, email_service=email_service) @@ -66,14 +66,12 @@ def initialize_service(): if __name__ == "__main__": + logger.info("Starting IsBank Email Service") print(f"Starting Service Mail Reader.") runner = initialize_service() - normal_sleep_time = 10 - error_sleep_time = 30 - max_consecutive_errors = 5 - extended_error_sleep = 120 - consecutive_errors = 0 + consecutive_errors, normal_sleep_time, error_sleep_time = 0, 10, 30 + max_consecutive_errors, extended_error_sleep = 5, 120 while True: try: @@ -96,6 +94,7 @@ if __name__ == "__main__": sleep(extended_error_sleep) else: sleep(error_sleep_time) + except socket.error as e: consecutive_errors += 1 logger.error(f"Email connection error (attempt {consecutive_errors}): {str(e)}") @@ -108,12 +107,13 @@ if __name__ == "__main__": logger.info("Successfully re-established email connection") except Exception as email_retry_error: logger.error(f"Failed to re-establish email connection: {str(email_retry_error)}") - + if consecutive_errors >= max_consecutive_errors: logger.warning(f"Hit {max_consecutive_errors} consecutive email errors, taking longer pause") sleep(extended_error_sleep) else: sleep(error_sleep_time) + except Exception as e: consecutive_errors += 1 logger.error(f"Unexpected error (attempt {consecutive_errors}): {str(e)}") diff --git a/ServicesRunner/Depends/mail_handler.py b/ServicesRunner/Depends/mail_handler.py index c67f259..ee3efdc 100644 --- a/ServicesRunner/Depends/mail_handler.py +++ b/ServicesRunner/Depends/mail_handler.py @@ -455,7 +455,6 @@ class EmailServiceRunner: redis_handler: Redis handler for Redis operations email_service: Email service for email operations """ - # Use MailReaderService singleton for Redis operations self.redis_handler = redis_handler self.email_service = email_service self.mails = None @@ -543,7 +542,7 @@ class EmailServiceRunner: except Exception as e: logger.error(f"Error processing email {mail_id}: {str(e)}") continue - + try: self.email_service.commit() except Exception as e: diff --git a/ServicesRunner/Depends/prisma_client.py b/ServicesRunner/Depends/prisma_client.py index 98aed20..e2511d1 100644 --- a/ServicesRunner/Depends/prisma_client.py +++ b/ServicesRunner/Depends/prisma_client.py @@ -84,6 +84,11 @@ class PrismaService: while self._loop is None: time.sleep(0.005) + async def _lock(self): + lock = asyncio.Lock() + async with lock: + return + async def _connect(self) -> Prisma: if self._client is not None: return self._client @@ -167,7 +172,7 @@ class PrismaService: result = await table_selected.create(data=data, include=include) # print(f"[{datetime.now()}] Create operation completed in {time.time() - start:.2f}s") return result - + async def _a_update(self, table: str, where: dict, data: dict, include: Optional[dict] = None) -> Any: start = time.time() async with self._asession() as db: @@ -207,7 +212,7 @@ class PrismaService: result = await table_selected.find_unique(where=query, include=include) # print(f"[{datetime.now()}] Find unique query completed in {time.time() - start:.2f}s") return result - + async def _a_find_unique_or_throw(self, table: str, query: dict, include: Optional[dict] = None) -> Any: start = time.time() async with self._asession() as db: @@ -229,7 +234,7 @@ class PrismaService: if select and result: result = {k: v for k, v in result if k in select} return result - + def find_many( self, table: str, query: Optional[dict] = None, take: int = None, skip: int = None, order: Optional[list[dict]] = None, select: Optional[dict] = None, include: Optional[dict] = None diff --git a/ServicesTask/app/services/common/service_base_async.py b/ServicesTask/app/services/common/service_base_async.py index efc1c34..d5cbf38 100644 --- a/ServicesTask/app/services/common/service_base_async.py +++ b/ServicesTask/app/services/common/service_base_async.py @@ -1,79 +1,147 @@ import os +import json import uuid import asyncio -import json +import fnmatch +import aio_pika -from typing import Any, Dict, Awaitable, Callable, Optional +from core.utils import now_ms +from contextvars import ContextVar +from aio_pika.abc import AbstractIncomingMessage +from typing import Any, Dict, Awaitable, Callable, Optional, List, NamedTuple -from app.core.utils import now_ms -from app.core import metrics -from nats.aio.client import Client as NATS -from nats.js.api import StreamConfig, ConsumerConfig, AckPolicy -from nats.errors import NoRespondersError +class _MsgCtx(NamedTuple): + msg: AbstractIncomingMessage + rk: str + attempts: int + + +_MSG_CTX: ContextVar[_MsgCtx | None] = ContextVar("_MSG_CTX", default=None) class ServiceBaseAsync: """ - JetStream tabanlı base: - - TASKS subject: publish + consume - - PUBLISH subject: event yayını (enqueued / duplicate_skipped / done / retry / failed) - - Dedup: Nats-Msg-Id = task_id (JetStream duplicate window içinde yazmaz) - - Retry: msg.nak(); MAX_DELIVER aşılınca msg.term() (DLQ yoksa “failed”) + RabbitMQ tabanlı async servis iskeleti. + - Topic exchange: EXCHANGE_EVENTS (default: app.events) + - Çoklu consume binding: CONSUME_BINDINGS="parser.publish,mail.publish" + - Kendi ürettiğini tüketmez: payload.source == SERVICE_NAME -> ACK & skip + - Retry: TTL'li retry kuyruğu (RETRY_DELAY_MS), sonra main'e geri DLX + - Max deneme üstünde DLQ: q..events.dlq + - Handler map: routing key -> özel callback (pattern destekli) + - Geriye uyumluluk: enqueue(payload, type_, routing_key=None, message_id=None) """ def __init__( self, produce_fn: Callable[["ServiceBaseAsync"], Awaitable[None]], consume_fn: Callable[["ServiceBaseAsync", Dict[str, Any]], Awaitable[None]], + handlers: Optional[Dict[str, Callable[["ServiceBaseAsync", Dict[str, Any]], Awaitable[None]]]] = None, ): - self.nats_url = os.getenv("NATS_URL", "nats://nats:4222") + self.service_name = os.getenv("SERVICE_NAME", "db-service") + self.amqp_url = os.getenv("RABBITMQ_URL", "amqp://guest:guest@localhost/") + self.exchange_name = os.getenv("EXCHANGE_EVENTS", "app.events") + self.produce_key: str = os.getenv("PRODUCE_KEY", f"{self.service_name}.publish") - self.stream_name = os.getenv("JS_STREAM", "ACCOUNT_SERVICES_DATABASE") - self.tasks_subject = os.getenv("JS_TASKS_SUBJECT", "ACCOUNT.SERVICES.DATABASE.TASKS") - self.publish_subject = os.getenv("JS_PUBLISH_SUBJECT", "ACCOUNT.SERVICES.DATABASE.PUBLISH") + raw = os.getenv("CONSUME_BINDINGS", "") + self.consume_bindings: List[str] = [s.strip() for s in raw.split(",") if s.strip()] + base = self.service_name.replace("/", "_") - self.durable = os.getenv("JS_DURABLE", "DB_WORKERS") - self.batch_size = int(os.getenv("BATCH_SIZE", "5")) - self.ack_wait_sec = int(os.getenv("ACK_WAIT_SEC", "30")) - self.max_deliver = int(os.getenv("MAX_DELIVER", "3")) - - self.retry_enabled = os.getenv("RETRY_ENABLED", "true").lower() == "true" - self.dedup_header = os.getenv("DEDUP_HEADER", "Nats-Msg-Id") + self.queue_main = f"q.{base}.events" + self.queue_retry = f"{self.queue_main}.retry" + self.queue_dlq = f"{self.queue_main}.dlq" + self.retry_delay_ms = int(os.getenv("RETRY_DELAY_MS", "5000")) + self.max_retries = int(os.getenv("MAX_RETRIES", "3")) + self.prefetch = int(os.getenv("PREFETCH", "16")) + self.ignore_self = os.getenv("IGNORE_SELF_PRODUCED", "true").lower() == "true" self.produce_fn = produce_fn self.consume_fn = consume_fn - self.nc: Optional[NATS] = None - self.js = None + self.handlers = handlers or {} + self.conn: Optional[aio_pika.RobustConnection] = None + self.chan: Optional[aio_pika.RobustChannel] = None + self.ex: Optional[aio_pika.Exchange] = None - async def run(self) -> None: - metrics.start_server() - self.nc = NATS() - await self.nc.connect(self.nats_url) - self.js = self.nc.jetstream() + async def _connect_with_retry(self, max_wait: int = 300): + delay = 1 + deadline = asyncio.get_event_loop().time() + (max_wait or 10**9) + last_err = None + while True: + try: + conn = await aio_pika.connect_robust(self.amqp_url, client_properties={"connection_name": self.service_name}, timeout=10) + print(f"[amqp] connected: {self.amqp_url} : {self.service_name} : {self.exchange_name} : {str(self.consume_bindings)}") + return conn + except Exception as e: + last_err = e + now = asyncio.get_event_loop().time() + if now + delay > deadline: + raise last_err + await asyncio.sleep(delay) + delay = min(delay * 2, 10) - await self._ensure_stream_and_consumer() - await asyncio.gather(self._produce_loop(), self._consume_loop()) + async def run(self): + self.conn = await self._connect_with_retry() + self.chan = await self.conn.channel() + await self.chan.set_qos(prefetch_count=self.prefetch) + self.ex = await self.chan.declare_exchange(self.exchange_name, aio_pika.ExchangeType.TOPIC, durable=True) + self.ex_retry = await self.chan.declare_exchange(f"{self.exchange_name}.retry", aio_pika.ExchangeType.TOPIC, durable=True) + self.ex_dlx = await self.chan.declare_exchange(f"{self.exchange_name}.dlx", aio_pika.ExchangeType.TOPIC, durable=True) + args_main = {"x-dead-letter-exchange": f"{self.exchange_name}.retry", "x-queue-mode": "lazy"} + q_main = await self.chan.declare_queue(self.queue_main, durable=True, arguments=args_main) + args_retry = {"x-message-ttl": self.retry_delay_ms, "x-dead-letter-exchange": self.exchange_name} + q_retry = await self.chan.declare_queue(self.queue_retry, durable=True, arguments=args_retry) + q_dlq = await self.chan.declare_queue(self.queue_dlq, durable=True) + await q_dlq.bind(self.ex_dlx, routing_key="#") + if not self.consume_bindings: + print("[warn] No CONSUME_BINDINGS configured; only producing.") + for rk in (self.consume_bindings or []): + await q_main.bind(self.ex, routing_key=rk) + await q_retry.bind(self.ex_retry, routing_key=rk) + await q_main.consume(self._on_message, no_ack=False) + await asyncio.gather(self._produce_loop()) - async def _ensure_stream_and_consumer(self) -> None: - try: - await self.js.add_stream(StreamConfig(name=self.stream_name, subjects=[self.tasks_subject, self.publish_subject])) - print(f"[js] stream created: {self.stream_name}") - except Exception: - pass - try: - await self.js.add_consumer( - self.stream_name, - ConsumerConfig( - durable_name=self.durable, ack_policy=AckPolicy.EXPLICIT, - ack_wait=self.ack_wait_sec, max_deliver=self.max_deliver, filter_subject=self.tasks_subject), - ) - print(f"[js] consumer created: durable={self.durable}") - except Exception: - pass + async def enqueue(self, task_id: str, payload: Dict[str, Any], type_: Optional[str] = None, routing_key: Optional[str] = None, message_id: Optional[str] = None) -> str: + assert self.ex is not None + payload.setdefault("task_id", task_id) + payload.setdefault("source", self.service_name) + body = json.dumps({"task_id": task_id, "type": type_, "payload": payload, "created_at": now_ms()}).encode() + msg = aio_pika.Message(body, delivery_mode=aio_pika.DeliveryMode.PERSISTENT, message_id=message_id or task_id, headers={"x-attempts": 0}) + rk = routing_key or self.produce_key + await self.ex.publish(msg, routing_key=rk) + return task_id - async def _produce_loop(self) -> None: + async def ack_current(self) -> None: + ctx = _MSG_CTX.get() + if ctx and ctx.msg: + await ctx.msg.ack() + + async def nack_current(self, requeue: bool = False) -> None: + ctx = _MSG_CTX.get() + if ctx and ctx.msg: + await ctx.msg.nack(requeue=requeue) + + async def retry_current(self, job: dict, attempts: int | None = None) -> None: + """Retry kuyruğuna kopyala ve orijinali ACK'le.""" + ctx = _MSG_CTX.get() + if not (ctx and ctx.msg): + return + att = attempts if attempts is not None else (ctx.attempts + 1) + await self._publish_retry(ctx.msg, job, att) + await ctx.msg.ack() + + async def dlq_current(self, job: dict, error: str | None = None) -> None: + """DLQ'ya gönder ve orijinali ACK'le.""" + ctx = _MSG_CTX.get() + if not (ctx and ctx.msg): + return + await self._publish_dlq(ctx.msg, job, error=error) + await ctx.msg.ack() + + def register_handler(self, pattern: str, fn: Callable[["ServiceBaseAsync", Dict[str, Any]], Awaitable[None]]): + self.handlers[pattern] = fn + + async def _produce_loop(self): while True: try: await self.produce_fn(self) @@ -81,85 +149,61 @@ class ServiceBaseAsync: print(f"[produce] ERROR: {e}") await asyncio.sleep(2) - async def _consume_loop(self) -> None: - sub = await self.js.pull_subscribe(self.tasks_subject, durable=self.durable) - while True: + async def _on_message(self, msg: AbstractIncomingMessage): + async with msg.process(ignore_processed=True, requeue=False): try: - msgs = await sub.fetch(self.batch_size, timeout=2) + job = json.loads(msg.body.decode()) except Exception: - msgs = [] + job = {"payload": {}, "task_id": None} + src = (job.get("payload") or {}).get("source") + if self.ignore_self and src == self.service_name: + return + attempts = 0 + try: + attempts = int(msg.headers.get("x-attempts", 0)) + except Exception: + pass - if not msgs: - await asyncio.sleep(0.2) - continue - - for msg in msgs: - job = self._decode_msg(msg) - attempts = self._delivery_attempts(msg) - try: - await self.consume_fn(self, job) + handler = self._resolve_handler(msg.routing_key) or self.consume_fn + meta = job.setdefault("_meta", {}) + meta["routing_key"] = msg.routing_key + meta["attempts"] = attempts + meta["exchange"] = self.exchange_name + ctx_token = _MSG_CTX.set(_MsgCtx(msg=msg, rk=msg.routing_key, attempts=attempts)) + try: + await handler(self, job) + except Exception as e: + if attempts + 1 >= self.max_retries: + await self._publish_dlq(msg, job, error=str(e)) await msg.ack() - await self._publish({"task_id": job.get("task_id"), "status": "done"}) - except Exception as e: - err = str(e) - if (not self.retry_enabled) or (attempts >= self.max_deliver): - await msg.term() - await self._publish({"task_id": job.get("task_id"), "status": "failed", "error": err}) - else: - await msg.nak() - await self._publish({"task_id": job.get("task_id"), "status": "retry", "attempts": attempts, "error": err}) + else: + await self._publish_retry(msg, job, attempts + 1) + await msg.ack() + finally: + _MSG_CTX.reset(ctx_token) - async def enqueue(self, payload: Dict[str, Any], type_: str, task_id: Optional[str] = None) -> str: - """ - Dedup: Nats-Msg-Id = task_id - duplicate ise publish.duplicate True döner ve JS yazmaz. - """ - _task_id = task_id or payload.get("task_id") or str(uuid.uuid4()) - payload.setdefault("task_id", _task_id) + def _resolve_handler(self, routing_key: str): + if routing_key in self.handlers: + return self.handlers[routing_key] + for pat, fn in self.handlers.items(): + if fnmatch.fnmatch(routing_key, pat): + return fn + return None - task = {"task_id": _task_id, "type": type_, "payload": payload, "created_at": now_ms(), "_attempts": 0} - data = json.dumps(task).encode() - try: - ack = await self.js.publish(self.tasks_subject, data, headers={self.dedup_header: _task_id}) - except NoRespondersError: - raise RuntimeError("NATS/JetStream not available") + async def _publish_retry(self, msg: AbstractIncomingMessage, job: Dict[str, Any], attempts: int): + chan = self.chan; assert chan is not None + retry_ex = await chan.get_exchange(f"{self.exchange_name}.retry") + rk = msg.routing_key + body = json.dumps(job).encode() + m = aio_pika.Message(body, delivery_mode=aio_pika.DeliveryMode.PERSISTENT, message_id=msg.message_id, headers={"x-attempts": attempts}) + await retry_ex.publish(m, routing_key=rk) - if getattr(ack, "duplicate", False): - # await self._publish({"task_id": _task_id, "status": "duplicate_skipped"}) - return _task_id - - await self._publish({"task_id": _task_id, "status": "enqueued"}) - return _task_id - - async def _publish(self, event: Dict[str, Any]) -> None: - evt = dict(event) - evt.setdefault("ts", now_ms()) - evt.setdefault("queue", self.tasks_subject) - try: - metrics.observe(evt.get("status","unknown"), evt["queue"], evt.get("type")) - except Exception: - pass - try: - await self.js.publish(self.publish_subject, json.dumps(evt).encode()) - except Exception: - pass - - @staticmethod - def _decode_msg(msg) -> Dict[str, Any]: - try: - obj = json.loads(msg.data.decode()) - if "payload" in obj and isinstance(obj["payload"], str): - try: - obj["payload"] = json.loads(obj["payload"]) - except Exception: - pass - return obj - except Exception: - return {"payload": {}, "task_id": None} - - @staticmethod - def _delivery_attempts(msg) -> int: - try: - return msg.metadata.num_delivered - except Exception: - return 1 + async def _publish_dlq(self, msg: AbstractIncomingMessage, job: Dict[str, Any], error: Optional[str] = None): + chan = self.chan; assert chan is not None + dlx_ex = await chan.get_exchange(f"{self.exchange_name}.dlx") + body_obj = dict(job) + if error: + body_obj.setdefault("_error", str(error)) + body = json.dumps(body_obj).encode() + m = aio_pika.Message(body, delivery_mode=aio_pika.DeliveryMode.PERSISTENT, message_id=msg.message_id, headers={"x-attempts": msg.headers.get("x-attempts", 0)}) + await dlx_ex.publish(m, routing_key=msg.routing_key) diff --git a/ServicesTask/app/services/database/Dockerfile b/ServicesTask/app/services/database/Dockerfile index 198e8de..33d96bf 100644 --- a/ServicesTask/app/services/database/Dockerfile +++ b/ServicesTask/app/services/database/Dockerfile @@ -1,18 +1,22 @@ -FROM python:3.12-slim +FROM python:3.11-slim -ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 +ENV PYTHONUNBUFFERED=1 +ENV PYTHONDONTWRITEBYTECODE=1 +ENV VIRTUAL_ENV=/opt/venv +ENV PRISMA_SCHEMA_PATH=/app/services/database/schema.prisma +ENV PATH="$VIRTUAL_ENV/bin:$PATH" ENV PYTHONPATH=/app WORKDIR / -COPY app/services/database/pyproject.toml ./ COPY app/services/database/README.md ./ COPY app/core ./app/core COPY app/services/common/ ./app/services/common/ COPY app/services/database/ ./app/services/database/ -RUN pip install --upgrade pip && pip install --no-cache-dir . +RUN apt-get update && apt-get install -y bash RUN mkdir -p /app/data +RUN chmod +x /app/services/database/entrypoint.sh -CMD ["python", "-m", "app.services.database.main"] +CMD ["bash", "/app/services/database/entrypoint.sh"] diff --git a/ServicesTask/app/services/database/entrypoint.sh b/ServicesTask/app/services/database/entrypoint.sh new file mode 100644 index 0000000..564698b --- /dev/null +++ b/ServicesTask/app/services/database/entrypoint.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +VENV_PATH="/opt/venv" +REQUIREMENTS_PATH="/app/services/database/requirements.txt" +SCHEMA_PATH="/app/services/database/schema.prisma" +PRISMA_BINARY_PATH="/root/.cache/prisma-python/binaries" + +if [ ! -x "$VENV_PATH/bin/python" ]; then + python -m venv "$VENV_PATH" + . "$VENV_PATH/bin/activate" + "$VENV_PATH/bin/pip" install pip --upgrade + "$VENV_PATH/bin/pip" install -r "$REQUIREMENTS_PATH" + "$VENV_PATH/bin/prisma" generate --schema "$SCHEMA_PATH" +fi + +if ! find "$PRISMA_BINARY_PATH" -type f -name "prisma-query-engine-debian-openssl-3.0.x" 2>/dev/null | grep -q .; then + "$VENV_PATH/bin/pip" install prisma + "$VENV_PATH/bin/prisma" py fetch +fi + +exec "$VENV_PATH/bin/python" -u /app/services/database/main.py diff --git a/ServicesTask/app/services/database/main.py b/ServicesTask/app/services/database/main.py index 3f9f6dd..2522731 100644 --- a/ServicesTask/app/services/database/main.py +++ b/ServicesTask/app/services/database/main.py @@ -1,28 +1,48 @@ import os -import uuid import asyncio -from app.services.common.service_base_async import ServiceBaseAsync +from prisma_client import PrismaService +from services.common.service_base_async import ServiceBaseAsync -PRODUCE_ENABLED = os.getenv("PRODUCE_ENABLED", "true").lower() == "true" -PRODUCE_BATCH = int(os.getenv("PRODUCE_BATCH", "3")) # her produce tick'inde kaç iş -TASK_TYPE = os.getenv("TASK_TYPE", "db-task") # iş tipi (task_id'de de kullanılır) -CONSUME_SLEEP_SEC = float(os.getenv("CONSUME_SLEEP_SEC", "0.5")) # işleme süresi simülasyonu (sn) -STATIC_IDS = ["2c47f1073a9d4f05aad6c15484894a72", "65827e3452b545d6845e050a503401f3", "5c663088f09d4062b4e567f47335fb1a"] +PRODUCE_BURST = int(os.getenv("PRODUCE_BURST", "10")) +PRODUCE_ONCE = os.getenv("PRODUCE_ONCE", "true").lower() == "true" +EVENT_TYPE = os.getenv("EVENT_TYPE", "db-event") +PROCESS_SEC = 10 -async def produce(service: ServiceBaseAsync): - for biz_id in STATIC_IDS: - deterministic_task_id = f"{TASK_TYPE}:{biz_id}" - payload = {"id": biz_id, "op": "sync", "source": "db-service"} - await service.enqueue(payload, TASK_TYPE, task_id=deterministic_task_id) - print(f"[DB] produce tick attempted ids={','.join(STATIC_IDS)}") +async def produce(svc: ServiceBaseAsync): + prisma_service = PrismaService() + async with prisma_service._asession() as db: + result = await db.account_records.find_many(take=10, skip=0) + result: list = prisma_service.to_dict(result, select={"id": True, "uu_id": True, "iban": True, "bank_reference_code": True, "bank_date": True, "bank_balance": True}) + for row in result: + await svc.enqueue(task_id=row["uu_id"], payload=row, type_="database.account.records") + await asyncio.sleep(PROCESS_SEC) + print(f"Produced From Database Producer: {len(result)} events to '{svc.produce_key}") -async def consume(service: ServiceBaseAsync, job: dict): - await asyncio.sleep(CONSUME_SLEEP_SEC) - print(f"[DB] consumed task={job['task_id']}") +async def handle_mail_publish(svc: ServiceBaseAsync, job): + await asyncio.sleep(PROCESS_SEC) + await svc.ack_current() + print("Database Consumer from mail:", job) + + +async def handle_mongo_publish(svc: ServiceBaseAsync, job): + prisma_service = PrismaService() + await asyncio.sleep(PROCESS_SEC) + await svc.ack_current() + print("Database Consumer from mongo:", job) + + +async def consume_default(svc: ServiceBaseAsync, job): + prisma_service = PrismaService() + await asyncio.sleep(PROCESS_SEC) + print("Database Consumer default (DLQ):", job.get("task_id")) + await svc.dlq_current(job, error="unsupported_routing_key") + if __name__ == "__main__": - asyncio.run(ServiceBaseAsync(produce, consume).run()) + + svc = ServiceBaseAsync(produce_fn=produce, consume_fn=consume_default, handlers={"mail.service.publish": handle_mail_publish, "mongo.service.publish": handle_mongo_publish}) + asyncio.run(svc.run()) diff --git a/ServicesTask/app/services/database/prisma_client.py b/ServicesTask/app/services/database/prisma_client.py new file mode 100644 index 0000000..93eedbb --- /dev/null +++ b/ServicesTask/app/services/database/prisma_client.py @@ -0,0 +1,189 @@ +import asyncio +import time +import logging +import uvloop +import threading +import datetime +import uuid + +from typing import Optional, AsyncGenerator, Any, TypeVar, Union +from contextlib import asynccontextmanager +from prisma import Prisma +from prisma.client import _PrismaModel + + +_PrismaModelT = TypeVar('_PrismaModelT', bound='_PrismaModel') + + +logger = logging.getLogger("prisma-service") + + +logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") +logging.getLogger("httpx").setLevel(logging.WARNING) +logging.getLogger("httpcore").setLevel(logging.WARNING) + + +class PrismaService: + + def __init__(self) -> None: + + self._lock = asyncio.Lock() + self._loop: Optional[asyncio.AbstractEventLoop] = None + self._thread: Optional[threading.Thread] = None + self._client: Optional[Prisma] = None + self.result: Optional[Any] = None + self.select: Optional[dict] = None + self._start_loop_thread() + + def _loop_runner(self) -> None: + + asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) + self._loop = asyncio.new_event_loop() + asyncio.set_event_loop(self._loop) + try: + self._loop.run_forever() + finally: + self._loop.close() + + def _submit(self, coro): + + if self._loop is None or not self._loop.is_running(): + raise RuntimeError("PrismaService event loop is not running.") + fut = asyncio.run_coroutine_threadsafe(coro, self._loop) + return fut.result() + + async def _lock(self): + + lock = asyncio.Lock() + async with lock: + return + + async def _aconnect(self) -> Prisma: + + if self._client is not None: + return self._client + logger.info("Connecting Prisma client...") + client = Prisma() + await client.connect() + self._client = client + logger.info("Prisma client connected.") + return self._client + + async def _adisconnect(self) -> None: + + if self._client is not None: + logger.info("Disconnecting Prisma client...") + try: + await self._client.disconnect() + finally: + self._client = None + logger.info("Prisma client disconnected.") + + @asynccontextmanager + async def _asession(self) -> AsyncGenerator[Prisma, None]: + yield await self._aconnect() + + def _start_loop_thread(self) -> None: + t = threading.Thread(target=self._loop_runner, name="PrismaLoop", daemon=True) + t.start() + self._thread = t + while self._loop is None: + time.sleep(0.005) + + async def _connect(self) -> Prisma: + + if self._client is not None: + return self._client + async with self._lock: + if self._client is None: + logger.info("Connecting Prisma client...") + client = Prisma() + await client.connect() + self._client = client + logger.info("Prisma client connected.") + return self._client + + async def _disconnect(self) -> None: + + async with self._lock: + if self._client is not None: + try: + logger.info("Disconnecting Prisma client...") + await self._client.disconnect() + logger.info("Prisma client disconnected.") + finally: + self._client = None + + @staticmethod + def to_dict(result: Union[list, Any], select: dict = None): + if isinstance(result, list): + list_result = [] + for item_iter in result: + item = {} + for k, v in item_iter: + if k not in select: + continue + if isinstance(v, datetime.datetime): + item[k] = str(v) + if isinstance(v, uuid.UUID): + item[k] = str(v) + if isinstance(v, int): + item[k] = int(v) + if isinstance(v, float): + item[k] = float(v) + if isinstance(v, bool): + item[k] = bool(v) + else: + item[k] = str(v) + list_result.append(item) + return list_result + else: + dict_result = {} + for k,v in result: + if k not in select: + continue + if isinstance(v, datetime.datetime): + dict_result[k] = str(v) + if isinstance(v, uuid.UUID): + dict_result[k] = str(v) + if isinstance(v, int): + dict_result[k] = int(v) + if isinstance(v, float): + dict_result[k] = float(v) + if isinstance(v, bool): + dict_result[k] = bool(v) + else: + dict_result[k] = str(v) + return dict_result + + @asynccontextmanager + async def _session(self) -> AsyncGenerator[Prisma, None]: + + client = await self._connect() + try: + yield client + except Exception: + logger.exception("Database operation error") + raise + + def _run(self, coro): + + try: + asyncio.get_running_loop() + raise RuntimeError("Async run is not allowed. Use sync methods instead.") + except RuntimeError as e: + asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) + with asyncio.Runner() as runner: + return runner.run(coro) + + def disconnect(self) -> None: + + try: + self._submit(self._adisconnect()) + finally: + if self._loop and self._loop.is_running(): + self._loop.call_soon_threadsafe(self._loop.stop) + if self._thread and self._thread.is_alive(): + self._thread.join(timeout=2.0) + self._loop = None + self._thread = None diff --git a/ServicesTask/app/services/database/pyproject.toml b/ServicesTask/app/services/database/pyproject.toml index be9f659..945330f 100644 --- a/ServicesTask/app/services/database/pyproject.toml +++ b/ServicesTask/app/services/database/pyproject.toml @@ -7,14 +7,17 @@ name = "dual-queue-services" version = "0.1.0" description = "Async dual queue system with Redis Streams and SQLite persistence" readme = "README.md" -requires-python = ">=3.11" +requires-python = ">=3.11,<4.0" authors = [ { name = "Berkay Karatay", email = "karatay.berkay@gmail.com" } ] dependencies = [ - "nats-py>=2.6.0", + "aio-pika>=9.4.1", "prometheus-client>=0.20.0", - "uvloop>=0.19.0" + "uvloop>=0.19.0", + "prisma==0.9.1", + "asyncio==3.4.3", + "arrow>=1.3.0" ] [project.optional-dependencies] @@ -34,3 +37,4 @@ profile = "black" [tool.setuptools.packages.find] where = ["app"] include = ["app*"] + diff --git a/ServicesTask/app/services/database/requirements.txt b/ServicesTask/app/services/database/requirements.txt new file mode 100644 index 0000000..4ef13f8 --- /dev/null +++ b/ServicesTask/app/services/database/requirements.txt @@ -0,0 +1,6 @@ +aio-pika>=9.4.1 +prometheus-client>=0.20.0 +uvloop>=0.19.0 +prisma==0.9.1 +asyncio==3.4.3 +arrow>=1.3.0 \ No newline at end of file diff --git a/ServicesTask/app/services/database/schema.prisma b/ServicesTask/app/services/database/schema.prisma new file mode 100644 index 0000000..be4a5aa --- /dev/null +++ b/ServicesTask/app/services/database/schema.prisma @@ -0,0 +1,3661 @@ +generator client { + provider = "prisma-client-py" + interface = "asyncio" + recursive_type_depth = -1 + enable_experimental_decimal = true +} + +datasource db { + provider = "postgresql" + url = "postgresql://postgres:password@10.10.2.14:5432/postgres?schema=public" +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model account_books { + country String @db.VarChar + branch_type Int @default(0) @db.SmallInt + company_id Int + company_uu_id String @db.VarChar + branch_id Int + branch_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_account_books_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + companies_account_books_branch_idTocompanies companies @relation("account_books_branch_idTocompanies", fields: [branch_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies_account_books_company_idTocompanies companies @relation("account_books_company_idTocompanies", fields: [company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + account_detail account_detail[] + account_master account_master[] + + @@index([company_id, expiry_starts], map: "account_companies_book_ndx_00") + @@index([created_at], map: "ix_account_books_created_at") + @@index([cryp_uu_id], map: "ix_account_books_cryp_uu_id") + @@index([ref_id], map: "ix_account_books_ref_id") + @@index([ref_int], map: "ix_account_books_ref_int") + @@index([updated_at], map: "ix_account_books_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model account_code_parser { + account_code_1 String @db.VarChar + account_code_2 String @db.VarChar + account_code_3 String @db.VarChar + account_code_4 String @default("") @db.VarChar + account_code_5 String @default("") @db.VarChar + account_code_6 String @default("") @db.VarChar + account_code_id Int + account_code_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_account_code_parser_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + account_codes account_codes @relation(fields: [account_code_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([account_code_id], map: "_account_code_parser_ndx_00") + @@index([created_at], map: "ix_account_code_parser_created_at") + @@index([cryp_uu_id], map: "ix_account_code_parser_cryp_uu_id") + @@index([ref_id], map: "ix_account_code_parser_ref_id") + @@index([ref_int], map: "ix_account_code_parser_ref_int") + @@index([updated_at], map: "ix_account_code_parser_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model account_codes { + account_code String @db.VarChar(48) + comment_line String @db.VarChar(128) + is_receive_or_debit Boolean + product_id Int @default(0) + nvi_id String @default("") @db.VarChar(48) + status_id Int @default(0) @db.SmallInt + account_code_seperator String @default(".") @db.VarChar(1) + system_id Int @default(0) @db.SmallInt + locked Int @default(0) @db.SmallInt + company_id Int + company_uu_id String @db.VarChar + customer_id Int + customer_uu_id String @db.VarChar + person_id Int + person_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_account_codes_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + account_code_parser account_code_parser[] + companies_account_codes_company_idTocompanies companies @relation("account_codes_company_idTocompanies", fields: [company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies_account_codes_customer_idTocompanies companies @relation("account_codes_customer_idTocompanies", fields: [customer_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + people people @relation(fields: [person_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + account_detail account_detail[] + + @@index([created_at], map: "ix_account_codes_created_at") + @@index([cryp_uu_id], map: "ix_account_codes_cryp_uu_id") + @@index([ref_id], map: "ix_account_codes_ref_id") + @@index([ref_int], map: "ix_account_codes_ref_int") + @@index([updated_at], map: "ix_account_codes_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model account_delay_interest { + interest_turn String @default("akdi") @db.VarChar(10) + interest_rate Decimal @default(0) @db.Decimal(10, 2) + delay_day Int @default(0) + daily_rate Decimal @default(0) @db.Decimal(20, 6) + interest Decimal @default(0) @db.Decimal(20, 6) + bsmv Decimal @default(0) @db.Decimal(20, 6) + kkdf Decimal @default(0) @db.Decimal(20, 6) + total Decimal @default(0) @db.Decimal(20, 6) + account_record_bank_date DateTime? @db.Timestamptz(6) + book_payment_process_date DateTime? @db.Timestamptz(6) + debt Decimal @db.Decimal(20, 6) + approving_at DateTime? @db.Timestamptz(6) + approved_record Boolean @default(false) + approving_person_id Int? + approving_person_uu_id String? @db.VarChar + account_records_id Int + account_records_uu_id String @db.VarChar(100) + build_decision_book_payment_id Int + build_decision_book_payment_uu_id String? @db.VarChar(100) + new_build_decision_book_payment_id Int? + new_build_decision_book_payment_uu_id String? @db.VarChar + ref_int Int? + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_account_delay_interest_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + bank_resp_company_id Int? + bank_resp_company_uu_id String? @db.VarChar + account_records account_records @relation(fields: [account_records_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_decision_book_payments build_decision_book_payments @relation(fields: [build_decision_book_payment_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([account_records_id, build_decision_book_payment_id], map: "_account_delay_interest_ndx_00") + @@index([created_at], map: "ix_account_delay_interest_created_at") + @@index([cryp_uu_id], map: "ix_account_delay_interest_cryp_uu_id") + @@index([ref_id], map: "ix_account_delay_interest_ref_id") + @@index([ref_int], map: "ix_account_delay_interest_ref_int") + @@index([updated_at], map: "ix_account_delay_interest_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model account_detail { + doc_date DateTime @db.Timestamptz(6) + line_no Int @db.SmallInt + receive_debit String @db.VarChar(1) + debit Decimal @db.Decimal(20, 6) + department String @default("") @db.VarChar(24) + special_code String @default("") @db.VarChar(12) + account_ref Int @default(0) + account_fiche_ref Int @default(0) + center_ref Int @default(0) + general_code String @default("") @db.VarChar(32) + credit Decimal @default(0) @db.Decimal(20, 6) + currency_type String @default("TL") @db.VarChar(4) + exchange_rate Decimal @default(0) @db.Decimal(20, 6) + debit_cur Decimal @default(0) @db.Decimal(20, 6) + credit_cur Decimal @default(0) @db.Decimal(20, 6) + discount_cur Decimal @default(0) @db.Decimal(20, 6) + amount Decimal @default(0) @db.Decimal(20, 6) + cross_account_code String @default("") @db.VarChar(32) + inf_index Decimal @default(0) @db.Decimal(20, 6) + not_inflated Int @default(0) @db.SmallInt + not_calculated Int @default(0) @db.SmallInt + comment_line1 String @default("") @db.VarChar(64) + comment_line2 String @default("") @db.VarChar(64) + comment_line3 String @default("") @db.VarChar(64) + comment_line4 String @default("") @db.VarChar(64) + comment_line5 String @default("") @db.VarChar(64) + comment_line6 String @default("") @db.VarChar(64) + owner_acc_ref Int @default(0) + from_where Int @default(0) + orj_eid Int @default(0) + canceled Int @default(0) @db.SmallInt + cross_ref Int @default(0) + data_center_id String @default("") @db.VarChar + data_center_rec_num Int @default(0) + status_id Int @default(0) @db.SmallInt + plug_type_id Int? + plug_type_uu_id String @db.VarChar + account_header_id Int + account_header_uu_id String @db.VarChar + account_code_id Int + account_code_uu_id String @db.VarChar + account_master_id Int + account_master_uu_id String @db.VarChar + project_id Int + project_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_account_detail_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + account_codes account_codes @relation(fields: [account_code_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + account_books account_books @relation(fields: [account_header_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + account_master account_master @relation(fields: [account_master_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + api_enum_dropdown api_enum_dropdown? @relation(fields: [plug_type_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_decision_book_projects build_decision_book_projects @relation(fields: [project_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([account_master_id, doc_date, line_no, account_header_id], map: "_account_detail_ndx_00") + @@index([created_at], map: "ix_account_detail_created_at") + @@index([cryp_uu_id], map: "ix_account_detail_cryp_uu_id") + @@index([ref_id], map: "ix_account_detail_ref_id") + @@index([ref_int], map: "ix_account_detail_ref_int") + @@index([updated_at], map: "ix_account_detail_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model account_master { + doc_date DateTime @db.Timestamptz(6) + plug_type String @db.VarChar + plug_number Int + special_code String @default("") @db.VarChar(12) + authorization_code String @default("") @db.VarChar(12) + doc_code String @default("") @db.VarChar(12) + doc_type Int @default(0) @db.SmallInt + comment_line1 String @default("") @db.VarChar + comment_line2 String @default("") @db.VarChar + comment_line3 String @default("") @db.VarChar + comment_line4 String @default("") @db.VarChar + comment_line5 String @default("") @db.VarChar + comment_line6 String @default("") @db.VarChar + project_code String @default("") @db.VarChar(12) + module_no String @default("") @db.VarChar + journal_no Int @default(0) + status_id Int @default(0) @db.SmallInt + canceled Boolean @default(false) + print_count Int @default(0) @db.SmallInt + total_active Decimal @default(0) @db.Decimal(20, 6) + total_passive Decimal @default(0) @db.Decimal(20, 6) + total_active_1 Decimal @default(0) @db.Decimal(20, 6) + total_passive_1 Decimal @default(0) @db.Decimal(20, 6) + total_active_2 Decimal @default(0) @db.Decimal(20, 6) + total_passive_2 Decimal @default(0) @db.Decimal(20, 6) + total_active_3 Decimal @default(0) @db.Decimal(20, 6) + total_passive_3 Decimal @default(0) @db.Decimal(20, 6) + total_active_4 Decimal @default(0) @db.Decimal(20, 6) + total_passive_4 Decimal @default(0) @db.Decimal(20, 6) + cross_ref Int @default(0) + data_center_id String @default("") @db.VarChar + data_center_rec_num Int @default(0) + account_header_id Int + account_header_uu_id String @db.VarChar + project_item_id Int + project_item_uu_id String @db.VarChar + department_id Int + department_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_account_master_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + account_detail account_detail[] + account_books account_books @relation(fields: [account_header_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + departments departments @relation(fields: [department_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_decision_book_projects build_decision_book_projects @relation(fields: [project_item_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([doc_date, account_header_id], map: "_account_master_ndx_00") + @@index([created_at], map: "ix_account_master_created_at") + @@index([cryp_uu_id], map: "ix_account_master_cryp_uu_id") + @@index([ref_id], map: "ix_account_master_ref_id") + @@index([ref_int], map: "ix_account_master_ref_int") + @@index([updated_at], map: "ix_account_master_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model account_record_exchanges { + are_currency String @db.VarChar(5) + are_exchange_rate Decimal @default(1) @db.Decimal(18, 6) + usd_exchange_rate_value Decimal? @default(0) @db.Decimal(18, 6) + eur_exchange_rate_value Decimal? @default(0) @db.Decimal(18, 6) + gbp_exchange_rate_value Decimal? @default(0) @db.Decimal(18, 6) + cny_exchange_rate_value Decimal? @default(0) @db.Decimal(18, 6) + account_records_id Int + account_records_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_account_record_exchanges_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + account_records account_records @relation(fields: [account_records_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([account_records_id], map: "_account_record_exchanges_ndx_00") + @@index([created_at], map: "ix_account_record_exchanges_created_at") + @@index([cryp_uu_id], map: "ix_account_record_exchanges_cryp_uu_id") + @@index([ref_id], map: "ix_account_record_exchanges_ref_id") + @@index([ref_int], map: "ix_account_record_exchanges_ref_int") + @@index([updated_at], map: "ix_account_record_exchanges_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model account_records { + iban String @db.VarChar(64) + bank_date DateTime @db.Timestamptz(6) + currency_value Decimal @db.Decimal(20, 6) + bank_balance Decimal @db.Decimal(20, 6) + currency String @db.VarChar(5) + additional_balance Decimal @db.Decimal(20, 6) + channel_branch String @db.VarChar(120) + process_name String @db.VarChar + process_type String @db.VarChar + process_comment String @db.VarChar + process_garbage String? @db.VarChar + bank_reference_code String @db.VarChar + add_comment_note String @default("") @db.VarChar + is_receipt_mail_send Boolean @default(false) + found_from String? @default("") @db.VarChar + similarity Decimal @default(0) @db.Decimal(20, 6) + remainder_balance Decimal @default(0) @db.Decimal(20, 6) + bank_date_y Int + bank_date_m Int @db.SmallInt + bank_date_w Int @db.SmallInt + bank_date_d Int @db.SmallInt + approving_accounting_record Boolean @default(false) + accounting_receipt_date DateTime @default(dbgenerated("'1900-01-01 00:00:00+00'::timestamp with time zone")) @db.Timestamptz(6) + accounting_receipt_number Int @default(0) + status_id Int @default(0) @db.SmallInt + approved_record Boolean @default(false) + is_predicted Boolean @default(false) + import_file_name String? @db.VarChar + receive_debit Int? + receive_debit_uu_id String? @db.VarChar + budget_type Int? + budget_type_uu_id String? @db.VarChar + company_id Int? + company_uu_id String? @db.VarChar + send_company_id Int? + send_company_uu_id String? @db.VarChar + send_person_id Int? + send_person_uu_id String? @db.VarChar + approving_accounting_person Int? + approving_accounting_person_uu_id String? @db.VarChar + living_space_id Int? + living_space_uu_id String? @db.VarChar + customer_id Int? + customer_uu_id String? @db.VarChar + build_id Int? + build_uu_id String? @db.VarChar + build_parts_id Int? + build_parts_uu_id String? @db.VarChar + build_decision_book_id Int? + build_decision_book_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_account_records_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + payment_result_type Int? + payment_result_type_uu_id String? @db.VarChar + is_commission_applied Boolean @default(false) + account_delay_interest account_delay_interest[] + account_record_exchanges account_record_exchanges[] + people_account_records_approving_accounting_personTopeople people? @relation("account_records_approving_accounting_personTopeople", fields: [approving_accounting_person], references: [id], onDelete: NoAction, onUpdate: NoAction) + api_enum_dropdown_account_records_budget_typeToapi_enum_dropdown api_enum_dropdown? @relation("account_records_budget_typeToapi_enum_dropdown", fields: [budget_type], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_decision_book build_decision_book? @relation(fields: [build_decision_book_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build build? @relation(fields: [build_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_parts build_parts? @relation(fields: [build_parts_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies_account_records_company_idTocompanies companies? @relation("account_records_company_idTocompanies", fields: [company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + people_account_records_customer_idTopeople people? @relation("account_records_customer_idTopeople", fields: [customer_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_living_space build_living_space? @relation(fields: [living_space_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + api_enum_dropdown_account_records_payment_result_typeToapi_enum_dropdown api_enum_dropdown? @relation("account_records_payment_result_typeToapi_enum_dropdown", fields: [payment_result_type], references: [id], onDelete: NoAction, onUpdate: NoAction) + api_enum_dropdown_account_records_receive_debitToapi_enum_dropdown api_enum_dropdown? @relation("account_records_receive_debitToapi_enum_dropdown", fields: [receive_debit], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies_account_records_send_company_idTocompanies companies? @relation("account_records_send_company_idTocompanies", fields: [send_company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + people_account_records_send_person_idTopeople people? @relation("account_records_send_person_idTopeople", fields: [send_person_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + account_records_model_train account_records_model_train[] + account_records_predict account_records_predict[] + build_decision_book_payments build_decision_book_payments[] + + @@unique([iban, bank_date, bank_reference_code, bank_balance], map: "_budget_records_ndx_01") + @@index([is_receipt_mail_send, bank_date], map: "_budget_records_ndx_00") + @@index([status_id, bank_date], map: "_budget_records_ndx_02") + @@index([created_at], map: "ix_account_records_created_at") + @@index([cryp_uu_id], map: "ix_account_records_cryp_uu_id") + @@index([ref_id], map: "ix_account_records_ref_id") + @@index([ref_int], map: "ix_account_records_ref_int") + @@index([updated_at], map: "ix_account_records_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model account_records_model_train { + start_index Int + end_index Int + search_text String @db.VarChar + category_id Int + category_uu_id String @db.VarChar(100) + account_records_id Int + account_records_uu_id String @db.VarChar(100) + ref_int Int? + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_account_records_model_train_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + is_model_trained Boolean @default(false) + trained_at DateTime? @db.Timestamptz(6) + account_records account_records @relation(fields: [account_records_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + api_enum_dropdown api_enum_dropdown @relation(fields: [category_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([created_at], map: "ix_account_records_model_train_created_at") + @@index([cryp_uu_id], map: "ix_account_records_model_train_cryp_uu_id") + @@index([ref_id], map: "ix_account_records_model_train_ref_id") + @@index([ref_int], map: "ix_account_records_model_train_ref_int") + @@index([updated_at], map: "ix_account_records_model_train_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model account_records_predict { + account_records_id Int + account_records_uu_id String @db.VarChar(100) + prediction_result String + treshold Decimal? @db.Decimal(18, 6) + is_first_prediction Boolean @default(false) + is_approved Boolean @default(false) + approved_at DateTime? @db.Timestamptz(6) + ref_int Int? + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_account_records_predict_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + prediction_model String @db.VarChar + prediction_field String @default("") @db.VarChar + account_records account_records @relation(fields: [account_records_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([created_at], map: "ix_account_records_predict_created_at") + @@index([cryp_uu_id], map: "ix_account_records_predict_cryp_uu_id") + @@index([ref_id], map: "ix_account_records_predict_ref_id") + @@index([ref_int], map: "ix_account_records_predict_ref_int") + @@index([updated_at], map: "ix_account_records_predict_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model address_city { + city_code String @db.VarChar(24) + city_name String @db.VarChar + licence_plate String? @db.VarChar(24) + phone_code String? @db.VarChar(36) + gov_code String? @db.VarChar(128) + address_geographic_id BigInt? + state_id Int + state_uu_id String @default("") @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_address_city_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + address_state address_state @relation(fields: [state_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + address_district address_district[] + + @@unique([state_id, city_code], map: "_address_city_ndx_01") + @@index([created_at], map: "ix_address_city_created_at") + @@index([cryp_uu_id], map: "ix_address_city_cryp_uu_id") + @@index([ref_id], map: "ix_address_city_ref_id") + @@index([ref_int], map: "ix_address_city_ref_int") + @@index([updated_at], map: "ix_address_city_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model address_country { + country_code String @unique(map: "_address_country_ndx_01") @db.VarChar(16) + country_name String @db.VarChar + money_code String? @db.VarChar(12) + language String? @db.VarChar + address_geographic_id BigInt? + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_address_country_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + address_state address_state[] + + @@index([money_code], map: "_address_country_ndx_00") + @@index([created_at], map: "ix_address_country_created_at") + @@index([cryp_uu_id], map: "ix_address_country_cryp_uu_id") + @@index([ref_id], map: "ix_address_country_ref_id") + @@index([ref_int], map: "ix_address_country_ref_int") + @@index([updated_at], map: "ix_address_country_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model address_district { + district_code String @db.VarChar(16) + district_name String @db.VarChar + phone_code String? @db.VarChar(36) + gov_code String? @db.VarChar(128) + address_geographic_id BigInt? + city_id Int + city_uu_id String @default("") @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_address_district_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + address_city address_city @relation(fields: [city_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + address_locality address_locality[] + address_neighborhood address_neighborhood[] + + @@unique([city_id, district_code], map: "_address_district_ndx_01") + @@index([created_at], map: "ix_address_district_created_at") + @@index([cryp_uu_id], map: "ix_address_district_cryp_uu_id") + @@index([ref_id], map: "ix_address_district_ref_id") + @@index([ref_int], map: "ix_address_district_ref_int") + @@index([updated_at], map: "ix_address_district_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model address_geographic_locations { + geo_table String @db.VarChar + geo_id Int + geo_name String @db.VarChar + geo_latitude Decimal @default(0) @db.Decimal(20, 6) + geo_longitude Decimal @default(0) @db.Decimal(20, 6) + geo_altitude Decimal @default(0) @db.Decimal(20, 6) + geo_description String + geo_area_size Decimal? @default(0) @db.Decimal(20, 2) + geo_population BigInt? + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_address_geographic_locations_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + + @@index([geo_table, geo_id], map: "_address_geographic_locations_ndx_00") + @@index([geo_latitude, geo_longitude], map: "_address_geographic_locations_ndx_01") + @@index([created_at], map: "ix_address_geographic_locations_created_at") + @@index([cryp_uu_id], map: "ix_address_geographic_locations_cryp_uu_id") + @@index([ref_id], map: "ix_address_geographic_locations_ref_id") + @@index([ref_int], map: "ix_address_geographic_locations_ref_int") + @@index([updated_at], map: "ix_address_geographic_locations_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model address_locality { + locality_code String @db.VarChar(16) + locality_name String @db.VarChar + type_code String? @db.VarChar + type_description String? @db.VarChar + gov_code String? @db.VarChar(128) + address_show Boolean @default(true) + address_geographic_id BigInt? + district_id Int + district_uu_id String @default("") @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_address_locality_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + address_district address_district @relation(fields: [district_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + address_neighborhood address_neighborhood[] + + @@unique([district_id, locality_code], map: "_address_locality_ndx_01") + @@index([created_at], map: "ix_address_locality_created_at") + @@index([cryp_uu_id], map: "ix_address_locality_cryp_uu_id") + @@index([ref_id], map: "ix_address_locality_ref_id") + @@index([ref_int], map: "ix_address_locality_ref_int") + @@index([updated_at], map: "ix_address_locality_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model address_neighborhood { + neighborhood_code String @db.VarChar(16) + neighborhood_name String @db.VarChar + type_code String? @db.VarChar + type_description String? @db.VarChar + gov_code String? @db.VarChar(128) + address_show Boolean @default(true) + address_geographic_id BigInt? + district_id Int? + district_uu_id String @default("") @db.VarChar + locality_id Int? + locality_uu_id String @default("") @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_address_neighborhood_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + address_district address_district? @relation(fields: [district_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + address_locality address_locality? @relation(fields: [locality_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + address_street address_street[] + + @@unique([locality_id, neighborhood_code], map: "_address_neighborhood_ndx_01") + @@index([created_at], map: "ix_address_neighborhood_created_at") + @@index([cryp_uu_id], map: "ix_address_neighborhood_cryp_uu_id") + @@index([ref_id], map: "ix_address_neighborhood_ref_id") + @@index([ref_int], map: "ix_address_neighborhood_ref_int") + @@index([updated_at], map: "ix_address_neighborhood_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model address_postcode { + street_id Int + street_uu_id String @default("") @db.VarChar + postcode String @db.VarChar(32) + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_address_postcode_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + address_street address_street @relation(fields: [street_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + relationship_employee2postcode relationship_employee2postcode[] + + @@index([created_at], map: "ix_address_postcode_created_at") + @@index([cryp_uu_id], map: "ix_address_postcode_cryp_uu_id") + @@index([ref_id], map: "ix_address_postcode_ref_id") + @@index([ref_int], map: "ix_address_postcode_ref_int") + @@index([updated_at], map: "ix_address_postcode_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model address_state { + state_code String @db.VarChar(16) + state_name String @db.VarChar + licence_plate String? @db.VarChar(24) + phone_code String? @db.VarChar(36) + gov_code String? @db.VarChar(128) + address_geographic_id BigInt? + country_id Int + country_uu_id String @default("") @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_address_state_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + address_city address_city[] + address_country address_country @relation(fields: [country_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([country_id, state_code], map: "_address_state_ndx_01") + @@index([created_at], map: "ix_address_state_created_at") + @@index([cryp_uu_id], map: "ix_address_state_cryp_uu_id") + @@index([ref_id], map: "ix_address_state_ref_id") + @@index([ref_int], map: "ix_address_state_ref_int") + @@index([updated_at], map: "ix_address_state_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model address_street { + street_code String @db.VarChar(16) + street_name String @db.VarChar + type_code String? @db.VarChar + type_description String? @db.VarChar + gov_code String? @db.VarChar(128) + address_geographic_id BigInt? + neighborhood_id Int + neighborhood_uu_id String @default("") @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_address_street_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + address_postcode address_postcode[] + address_neighborhood address_neighborhood @relation(fields: [neighborhood_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + addresses addresses[] + + @@unique([neighborhood_id, street_code], map: "_address_street_ndx_01") + @@index([created_at], map: "ix_address_street_created_at") + @@index([cryp_uu_id], map: "ix_address_street_cryp_uu_id") + @@index([ref_id], map: "ix_address_street_ref_id") + @@index([ref_int], map: "ix_address_street_ref_int") + @@index([updated_at], map: "ix_address_street_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model addresses { + build_number String @db.VarChar(24) + door_number String? @db.VarChar(24) + floor_number String? @db.VarChar(24) + comment_address String @db.VarChar + letter_address String @db.VarChar + short_letter_address String @db.VarChar + latitude Decimal @default(0) @db.Decimal(20, 12) + longitude Decimal @default(0) @db.Decimal(20, 12) + street_id Int + street_uu_id String @default("") @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_addresses_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + address_street address_street @relation(fields: [street_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build build[] + build_sites build_sites[] + companies companies[] + + @@index([created_at], map: "ix_addresses_created_at") + @@index([cryp_uu_id], map: "ix_addresses_cryp_uu_id") + @@index([ref_id], map: "ix_addresses_ref_id") + @@index([ref_int], map: "ix_addresses_ref_int") + @@index([updated_at], map: "ix_addresses_updated_at") +} + +model alembic_version { + version_num String @id(map: "alembic_version_pkc") @db.VarChar(32) +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model api_enum_dropdown { + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_api_enum_dropdown_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + enum_class String @db.VarChar + key String @db.VarChar + value String @db.VarChar + description String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + lang String @default("tr") @db.VarChar + account_detail account_detail[] + account_records_account_records_budget_typeToapi_enum_dropdown account_records[] @relation("account_records_budget_typeToapi_enum_dropdown") + account_records_account_records_payment_result_typeToapi_enum_dropdown account_records[] @relation("account_records_payment_result_typeToapi_enum_dropdown") + account_records_account_records_receive_debitToapi_enum_dropdown account_records[] @relation("account_records_receive_debitToapi_enum_dropdown") + account_records_model_train account_records_model_train[] + build build[] + build_area build_area[] + build_companies_providing build_companies_providing[] + build_decision_book_items build_decision_book_items[] + build_decision_book_payments build_decision_book_payments[] + build_parts_build_parts_part_direction_idToapi_enum_dropdown build_parts[] @relation("build_parts_part_direction_idToapi_enum_dropdown") + build_parts_build_parts_part_type_idToapi_enum_dropdown build_parts[] @relation("build_parts_part_type_idToapi_enum_dropdown") + build_person_providing build_person_providing[] + decision_book_budget_master decision_book_budget_master[] + + @@index([created_at], map: "ix_api_enum_dropdown_created_at") + @@index([cryp_uu_id], map: "ix_api_enum_dropdown_cryp_uu_id") + @@index([ref_id], map: "ix_api_enum_dropdown_ref_id") + @@index([ref_int], map: "ix_api_enum_dropdown_ref_int") + @@index([updated_at], map: "ix_api_enum_dropdown_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model application2employee { + employee_id Int + employee_uu_id String @db.VarChar + service_id Int + service_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_application2employee_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + employees employees @relation(fields: [employee_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + services services @relation(fields: [service_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([employee_uu_id, service_uu_id], map: "application2employee_employee_to_service") + @@index([created_at], map: "ix_application2employee_created_at") + @@index([cryp_uu_id], map: "ix_application2employee_cryp_uu_id") + @@index([ref_id], map: "ix_application2employee_ref_id") + @@index([ref_int], map: "ix_application2employee_ref_int") + @@index([updated_at], map: "ix_application2employee_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model application2employee_extra { + employee_id Int + employee_uu_id String @db.VarChar + application_id Int + application_uu_id String @db.VarChar + site_url String @db.VarChar + application_code String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_application2employee_extra_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + applications applications @relation(fields: [application_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + employees employees @relation(fields: [employee_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([employee_id, site_url, application_id], map: "application_to_employee") + @@index([created_at], map: "ix_application2employee_extra_created_at") + @@index([cryp_uu_id], map: "ix_application2employee_extra_cryp_uu_id") + @@index([ref_id], map: "ix_application2employee_extra_ref_id") + @@index([ref_int], map: "ix_application2employee_extra_ref_int") + @@index([updated_at], map: "ix_application2employee_extra_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model application2occupant { + build_living_space_id Int + build_living_space_uu_id String @db.VarChar + service_id Int + service_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_application2occupant_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_living_space build_living_space @relation(fields: [build_living_space_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + services services @relation(fields: [service_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([build_living_space_uu_id, service_uu_id], map: "application2occupant_occupant_to_service") + @@index([created_at], map: "ix_application2occupant_created_at") + @@index([cryp_uu_id], map: "ix_application2occupant_cryp_uu_id") + @@index([ref_id], map: "ix_application2occupant_ref_id") + @@index([ref_int], map: "ix_application2occupant_ref_int") + @@index([updated_at], map: "ix_application2occupant_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model application2occupant_extra { + build_living_space_id Int + build_living_space_uu_id String @db.VarChar + application_id Int + application_uu_id String @db.VarChar + site_url String @db.VarChar + application_code String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_application2occupant_extra_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + applications applications @relation(fields: [application_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_living_space build_living_space @relation(fields: [build_living_space_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([build_living_space_id, site_url, application_id], map: "application_to_occupant") + @@index([created_at], map: "ix_application2occupant_extra_created_at") + @@index([cryp_uu_id], map: "ix_application2occupant_extra_cryp_uu_id") + @@index([ref_id], map: "ix_application2occupant_extra_ref_id") + @@index([ref_int], map: "ix_application2occupant_extra_ref_int") + @@index([updated_at], map: "ix_application2occupant_extra_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model applications { + name String @db.VarChar + site_url String @db.VarChar + application_code String @db.VarChar + application_type String @db.VarChar + application_for String @default("EMP") @db.VarChar + description String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_applications_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + application2employee_extra application2employee_extra[] + application2occupant_extra application2occupant_extra[] + services2applications services2applications[] + + @@index([created_at], map: "ix_applications_created_at") + @@index([cryp_uu_id], map: "ix_applications_cryp_uu_id") + @@index([ref_id], map: "ix_applications_ref_id") + @@index([ref_int], map: "ix_applications_ref_int") + @@index([updated_at], map: "ix_applications_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build { + gov_address_code String @unique @default("") @db.VarChar + build_name String @db.VarChar + build_no String @db.VarChar(8) + max_floor Int @default(1) + underground_floor Int @default(0) + build_date DateTime @default(dbgenerated("'1900-01-01 00:00:00+00'::timestamp with time zone")) @db.Timestamptz(6) + decision_period_date DateTime @default(dbgenerated("'1900-01-01 00:00:00+00'::timestamp with time zone")) @db.Timestamptz(6) + tax_no String @default("") @db.VarChar(24) + lift_count Int @default(0) + heating_system Boolean @default(true) + cooling_system Boolean @default(false) + hot_water_system Boolean @default(false) + block_service_man_count Int @default(0) + security_service_man_count Int @default(0) + garage_count Int @default(0) + management_room_id Int? + site_id Int? + site_uu_id String? @db.VarChar + address_id Int + address_uu_id String @db.VarChar + build_types_id Int + build_types_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + account_records account_records[] + addresses addresses @relation(fields: [address_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + api_enum_dropdown api_enum_dropdown @relation(fields: [build_types_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_sites build_sites? @relation(fields: [site_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_area build_area[] + build_companies_providing build_companies_providing[] + build_decision_book build_decision_book[] + build_ibans build_ibans[] + build_management build_management[] + build_parts build_parts[] + build_person_providing build_person_providing[] + company_delay_interest company_delay_interest[] + relationship_employee2build relationship_employee2build[] + + @@index([gov_address_code], map: "_builds_ndx_00") + @@index([build_name, build_no], map: "_builds_ndx_01") + @@index([created_at], map: "ix_build_created_at") + @@index([cryp_uu_id], map: "ix_build_cryp_uu_id") + @@index([ref_id], map: "ix_build_ref_id") + @@index([ref_int], map: "ix_build_ref_int") + @@index([updated_at], map: "ix_build_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_area { + area_name String @default("") @db.VarChar + area_code String @default("") @db.VarChar + area_type String @default("GREEN") @db.VarChar + area_direction String @default("NN") @db.VarChar(2) + area_gross_size Decimal @default(0) @db.Decimal(20, 6) + area_net_size Decimal @default(0) @db.Decimal(20, 6) + width Int? @default(0) + size Int? @default(0) + build_id Int + build_uu_id String @db.VarChar + part_type_id Int? + part_type_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_area_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build build @relation(fields: [build_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + api_enum_dropdown api_enum_dropdown? @relation(fields: [part_type_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([build_id, area_code], map: "_edm_build_parts_area_ndx_00") + @@index([created_at], map: "ix_build_area_created_at") + @@index([cryp_uu_id], map: "ix_build_area_cryp_uu_id") + @@index([ref_id], map: "ix_build_area_ref_id") + @@index([ref_int], map: "ix_build_area_ref_int") + @@index([updated_at], map: "ix_build_area_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_companies_providing { + build_id Int + build_uu_id String? @db.VarChar + company_id Int + company_uu_id String? @db.VarChar + provide_id Int? + provide_uu_id String? @db.VarChar + contract_id Int? + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_companies_providing_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build build @relation(fields: [build_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies_build_companies_providing_company_idTocompanies companies @relation("build_companies_providing_company_idTocompanies", fields: [company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies_build_companies_providing_contract_idTocompanies companies? @relation("build_companies_providing_contract_idTocompanies", fields: [contract_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + api_enum_dropdown api_enum_dropdown? @relation(fields: [provide_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([build_id, company_id, provide_id], map: "_build_companies_providing_ndx_00") + @@index([created_at], map: "ix_build_companies_providing_created_at") + @@index([cryp_uu_id], map: "ix_build_companies_providing_cryp_uu_id") + @@index([ref_id], map: "ix_build_companies_providing_ref_id") + @@index([ref_int], map: "ix_build_companies_providing_ref_int") + @@index([updated_at], map: "ix_build_companies_providing_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_decision_book { + decision_book_pdf_path String? @default("") @db.VarChar + resp_company_fix_wage Decimal @default(0) @db.Decimal(10, 2) + is_out_sourced Boolean @default(false) + meeting_date DateTime @default(dbgenerated("'1900-01-01 00:00:00+00'::timestamp with time zone")) @db.Timestamptz(6) + decision_type String @default("RBM") @db.VarChar(3) + meeting_is_completed Boolean @default(false) + meeting_completed_date DateTime? @db.Timestamptz(6) + build_id Int + build_uu_id String? @db.VarChar + resp_company_id Int + resp_company_uu_id String? @db.VarChar + contact_id Int? + contact_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_decision_book_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + account_records account_records[] + build build @relation(fields: [build_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + contracts contracts? @relation(fields: [contact_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies companies @relation(fields: [resp_company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_decision_book_invitations build_decision_book_invitations[] + build_decision_book_items build_decision_book_items[] + build_decision_book_payments build_decision_book_payments[] + build_decision_book_person build_decision_book_person[] + build_decision_book_projects build_decision_book_projects[] + decision_book_budget_books decision_book_budget_books[] + decision_book_budget_codes decision_book_budget_codes[] + + @@index([meeting_date, build_id], map: "build_decision_book_ndx_011") + @@index([created_at], map: "ix_build_decision_book_created_at") + @@index([cryp_uu_id], map: "ix_build_decision_book_cryp_uu_id") + @@index([ref_id], map: "ix_build_decision_book_ref_id") + @@index([ref_int], map: "ix_build_decision_book_ref_int") + @@index([updated_at], map: "ix_build_decision_book_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_decision_book_invitations { + build_id Int + build_uu_id String? @db.VarChar + decision_book_id Int + decision_book_uu_id String? @db.VarChar + invitation_type String @db.VarChar + invitation_attempt Int @default(1) @db.SmallInt + living_part_count Int @default(1) @db.SmallInt + living_part_percentage Decimal @default(0.51) @db.Decimal(10, 2) + message String? + planned_date DateTime @db.Timestamptz(6) + planned_date_expires DateTime @db.Timestamptz(6) + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_decision_book_invitations_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_decision_book build_decision_book @relation(fields: [decision_book_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_decision_book_person build_decision_book_person[] + build_decision_book_person_occupants build_decision_book_person_occupants[] + + @@unique([invitation_type, planned_date, invitation_attempt], map: "_build_decision_book_invitations_ndx_01") + @@index([created_at], map: "ix_build_decision_book_invitations_created_at") + @@index([cryp_uu_id], map: "ix_build_decision_book_invitations_cryp_uu_id") + @@index([ref_id], map: "ix_build_decision_book_invitations_ref_id") + @@index([ref_int], map: "ix_build_decision_book_invitations_ref_int") + @@index([updated_at], map: "ix_build_decision_book_invitations_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_decision_book_items { + item_order Int @db.SmallInt + item_comment String + item_objection String? + info_is_completed Boolean @default(false) + is_payment_created Boolean @default(false) + info_type_id Int? + info_type_uu_id String? @db.VarChar + build_decision_book_id Int + build_decision_book_uu_id String? @db.VarChar + item_short_comment String? @db.VarChar(24) + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_decision_book_items_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_decision_book build_decision_book @relation(fields: [build_decision_book_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + api_enum_dropdown api_enum_dropdown? @relation(fields: [info_type_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_decision_book_items_unapproved_build_decision_book_items_unapproved_build_decision_book_itemTobuild_decision_book_items build_decision_book_items_unapproved[] @relation("build_decision_book_items_unapproved_build_decision_book_itemTobuild_decision_book_items") + build_decision_book_items_unapproved_build_decision_book_items_unapproved_decision_book_item_idTobuild_decision_book_items build_decision_book_items_unapproved[] @relation("build_decision_book_items_unapproved_decision_book_item_idTobuild_decision_book_items") + build_decision_book_legal build_decision_book_legal[] + build_decision_book_payments build_decision_book_payments[] + build_decision_book_projects build_decision_book_projects[] + + @@unique([build_decision_book_id, item_order], map: "_build_decision_book_item_ndx_02") + @@index([build_decision_book_id], map: "_build_decision_book_item_ndx_01") + @@index([created_at], map: "ix_build_decision_book_items_created_at") + @@index([cryp_uu_id], map: "ix_build_decision_book_items_cryp_uu_id") + @@index([ref_id], map: "ix_build_decision_book_items_ref_id") + @@index([ref_int], map: "ix_build_decision_book_items_ref_int") + @@index([updated_at], map: "ix_build_decision_book_items_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_decision_book_items_unapproved { + item_objection String + item_order Int @db.SmallInt + decision_book_item_id Int + decision_book_item_uu_id String? @db.VarChar + person_id Int + person_uu_id String? @db.VarChar + build_decision_book_item Int + build_decision_book_item_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_decision_book_items_unapproved_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_decision_book_items_build_decision_book_items_unapproved_build_decision_book_itemTobuild_decision_book_items build_decision_book_items @relation("build_decision_book_items_unapproved_build_decision_book_itemTobuild_decision_book_items", fields: [build_decision_book_item], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "build_decision_book_items_unappro_build_decision_book_item_fkey") + build_decision_book_items_build_decision_book_items_unapproved_decision_book_item_idTobuild_decision_book_items build_decision_book_items @relation("build_decision_book_items_unapproved_decision_book_item_idTobuild_decision_book_items", fields: [decision_book_item_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + people people @relation(fields: [person_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([build_decision_book_item], map: "_build_decision_book_item_unapproved_ndx_01") + @@index([created_at], map: "ix_build_decision_book_items_unapproved_created_at") + @@index([cryp_uu_id], map: "ix_build_decision_book_items_unapproved_cryp_uu_id") + @@index([ref_id], map: "ix_build_decision_book_items_unapproved_ref_id") + @@index([ref_int], map: "ix_build_decision_book_items_unapproved_ref_int") + @@index([updated_at], map: "ix_build_decision_book_items_unapproved_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_decision_book_legal { + period_start_date DateTime @db.Timestamptz(6) + lawsuits_decision_number String @db.VarChar + lawsuits_decision_date DateTime @db.Timestamptz(6) + period_stop_date DateTime @default(dbgenerated("'2099-12-31 23:59:59+00'::timestamp with time zone")) @db.Timestamptz(6) + decision_book_pdf_path String? @default("") @db.VarChar + resp_company_total_wage Decimal? @default(0) @db.Decimal(10, 2) + contact_agreement_path String? @default("") @db.VarChar + contact_agreement_date DateTime? @default(dbgenerated("'1900-01-01 00:00:00+00'::timestamp with time zone")) @db.Timestamptz(6) + meeting_date DateTime @default(dbgenerated("'1900-01-01 00:00:00+00'::timestamp with time zone")) @db.Timestamptz(6) + lawsuits_type String @default("C") @db.VarChar(1) + lawsuits_name String @db.VarChar(128) + lawsuits_note String @db.VarChar(512) + lawyer_cost Decimal @db.Decimal(20, 2) + mediator_lawyer_cost Decimal @db.Decimal(20, 2) + other_cost Decimal @db.Decimal(20, 2) + legal_cost Decimal @db.Decimal(20, 2) + approved_cost Decimal @db.Decimal(20, 2) + total_price Decimal @db.Decimal(20, 2) + build_db_item_id Int + build_db_item_uu_id String? @db.VarChar + resp_attorney_id Int + resp_attorney_uu_id String? @db.VarChar + resp_attorney_company_id Int + resp_attorney_company_uu_id String? @db.VarChar + mediator_lawyer_person_id Int + mediator_lawyer_person_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_decision_book_legal_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_decision_book_items build_decision_book_items @relation(fields: [build_db_item_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + people_build_decision_book_legal_mediator_lawyer_person_idTopeople people @relation("build_decision_book_legal_mediator_lawyer_person_idTopeople", fields: [mediator_lawyer_person_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies companies @relation(fields: [resp_attorney_company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + people_build_decision_book_legal_resp_attorney_idTopeople people @relation("build_decision_book_legal_resp_attorney_idTopeople", fields: [resp_attorney_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([meeting_date], map: "_build_decision_book_legal_ndx_00") + @@index([created_at], map: "ix_build_decision_book_legal_created_at") + @@index([cryp_uu_id], map: "ix_build_decision_book_legal_cryp_uu_id") + @@index([ref_id], map: "ix_build_decision_book_legal_ref_id") + @@index([ref_int], map: "ix_build_decision_book_legal_ref_int") + @@index([updated_at], map: "ix_build_decision_book_legal_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_decision_book_payments { + payment_plan_time_periods String @db.VarChar(10) + process_date DateTime @db.Timestamptz(6) + payment_amount Decimal @db.Decimal(16, 2) + currency String @default("TRY") @db.VarChar(8) + payment_types_id Int? + payment_types_uu_id String? @db.VarChar + period_time String @db.VarChar(12) + process_date_y Int @db.SmallInt + process_date_m Int @db.SmallInt + build_decision_book_item_id Int + build_decision_book_item_uu_id String @db.VarChar + build_parts_id Int + build_parts_uu_id String @db.VarChar + decision_book_project_id Int? + decision_book_project_uu_id String? @db.VarChar + account_records_id Int? + account_records_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_decision_book_payments_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + account_is_debit Boolean? @default(true) + build_decision_book_id Int? + build_decision_book_uu_id String? @db.VarChar + ref_int Int? + is_closed Boolean @default(false) + debt_to_pay Decimal @default(0) @db.Decimal(16, 2) + debt_paid Decimal @default(0) @db.Decimal(16, 2) + account_delay_interest account_delay_interest[] + account_records account_records? @relation(fields: [account_records_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_decision_book build_decision_book? @relation(fields: [build_decision_book_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_decision_book_items build_decision_book_items @relation(fields: [build_decision_book_item_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_parts build_parts @relation(fields: [build_parts_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_decision_book_projects build_decision_book_projects? @relation(fields: [decision_book_project_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + api_enum_dropdown api_enum_dropdown? @relation(fields: [payment_types_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([uu_id, ref_id, build_decision_book_item_id, build_parts_id, payment_plan_time_periods, process_date, payment_types_id, account_records_id, account_is_debit], map: "build_decision_book_payments_detail_ndx_00") + @@index([account_records_id], map: "build_decision_book_payments_detail_ndx_01") + @@index([created_at], map: "ix_build_decision_book_payments_created_at") + @@index([cryp_uu_id], map: "ix_build_decision_book_payments_cryp_uu_id") + @@index([ref_id], map: "ix_build_decision_book_payments_ref_id") + @@index([ref_int], map: "ix_build_decision_book_payments_ref_int") + @@index([updated_at], map: "ix_build_decision_book_payments_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_decision_book_person { + dues_percent_discount Int @default(0) @db.SmallInt + dues_fix_discount Decimal @default(0) @db.Decimal(10, 2) + dues_discount_approval_date DateTime @default(dbgenerated("'1900-01-01 00:00:00+00'::timestamp with time zone")) @db.Timestamptz(6) + send_date DateTime @db.Timestamptz(6) + is_attending Boolean @default(false) + confirmed_date DateTime? @db.Timestamptz(6) + token String @default("") @db.VarChar + vicarious_person_id Int? + vicarious_person_uu_id String? @db.VarChar + invite_id Int + invite_uu_id String @db.VarChar + build_decision_book_id Int + build_decision_book_uu_id String @db.VarChar + build_living_space_id Int + build_living_space_uu_id String? @db.VarChar + person_id Int + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_decision_book_person_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_decision_book build_decision_book @relation(fields: [build_decision_book_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_living_space build_living_space @relation(fields: [build_living_space_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_decision_book_invitations build_decision_book_invitations @relation(fields: [invite_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + people_build_decision_book_person_person_idTopeople people @relation("build_decision_book_person_person_idTopeople", fields: [person_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + people_build_decision_book_person_vicarious_person_idTopeople people? @relation("build_decision_book_person_vicarious_person_idTopeople", fields: [vicarious_person_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_decision_book_person_occupants build_decision_book_person_occupants[] + + @@unique([build_decision_book_id, invite_id, build_living_space_id], map: "_build_decision_book_person_ndx_01") + @@index([created_at], map: "ix_build_decision_book_person_created_at") + @@index([cryp_uu_id], map: "ix_build_decision_book_person_cryp_uu_id") + @@index([ref_id], map: "ix_build_decision_book_person_ref_id") + @@index([ref_int], map: "ix_build_decision_book_person_ref_int") + @@index([updated_at], map: "ix_build_decision_book_person_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_decision_book_person_occupants { + build_decision_book_person_id Int + build_decision_book_person_uu_id String? @db.VarChar + invite_id Int? + invite_uu_id String? @db.VarChar + occupant_type_id Int + occupant_type_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_decision_book_person_occupants_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_decision_book_person build_decision_book_person @relation(fields: [build_decision_book_person_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "build_decision_book_person_oc_build_decision_book_person_i_fkey") + build_decision_book_invitations build_decision_book_invitations? @relation(fields: [invite_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + occupant_types occupant_types @relation(fields: [occupant_type_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([build_decision_book_person_id, occupant_type_id], map: "_build_decision_book_person_occupants_ndx_01") + @@index([created_at], map: "ix_build_decision_book_person_occupants_created_at") + @@index([cryp_uu_id], map: "ix_build_decision_book_person_occupants_cryp_uu_id") + @@index([ref_id], map: "ix_build_decision_book_person_occupants_ref_id") + @@index([ref_int], map: "ix_build_decision_book_person_occupants_ref_int") + @@index([updated_at], map: "ix_build_decision_book_person_occupants_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_decision_book_project_items { + item_header String @db.VarChar + item_comment String + attachment_pdf_path String? @default("") @db.VarChar + item_estimated_cost Decimal @default(0) @db.Decimal(16, 2) + item_short_comment String? @db.VarChar(24) + build_decision_book_project_id Int + build_decision_book_project_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_decision_book_project_items_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_decision_book_projects build_decision_book_projects @relation(fields: [build_decision_book_project_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "build_decision_book_project_i_build_decision_book_project__fkey") + + @@index([created_at], map: "ix_build_decision_book_project_items_created_at") + @@index([cryp_uu_id], map: "ix_build_decision_book_project_items_cryp_uu_id") + @@index([ref_id], map: "ix_build_decision_book_project_items_ref_id") + @@index([ref_int], map: "ix_build_decision_book_project_items_ref_int") + @@index([updated_at], map: "ix_build_decision_book_project_items_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_decision_book_project_person { + dues_percent_discount Int @default(0) @db.SmallInt + job_fix_wage Decimal @default(0) @db.Decimal(10, 2) + bid_price Decimal @default(0) @db.Decimal(10, 2) + decision_price Decimal @default(0) @db.Decimal(10, 2) + build_decision_book_project_id Int + build_decision_book_project_uu_id String? @db.VarChar + living_space_id Int + living_space_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_decision_book_project_person_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_decision_book_projects build_decision_book_projects @relation(fields: [build_decision_book_project_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "build_decision_book_project_p_build_decision_book_project__fkey") + build_living_space build_living_space @relation(fields: [living_space_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([created_at], map: "ix_build_decision_book_project_person_created_at") + @@index([cryp_uu_id], map: "ix_build_decision_book_project_person_cryp_uu_id") + @@index([ref_id], map: "ix_build_decision_book_project_person_ref_id") + @@index([ref_int], map: "ix_build_decision_book_project_person_ref_int") + @@index([updated_at], map: "ix_build_decision_book_project_person_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_decision_book_projects { + project_no String? @db.VarChar(12) + project_name String @db.VarChar + project_start_date DateTime @db.Timestamptz(6) + project_stop_date DateTime @default(dbgenerated("'2099-12-31 23:59:59+00'::timestamp with time zone")) @db.Timestamptz(6) + project_type String @default("C") @db.VarChar + project_note String + decision_book_pdf_path String? @default("") @db.VarChar + is_completed Boolean @default(false) + status_code Int? @db.SmallInt + resp_company_fix_wage Decimal @default(0) @db.Decimal(10, 2) + is_out_sourced Boolean @default(false) + meeting_date DateTime @default(dbgenerated("'1900-01-01 00:00:00+00'::timestamp with time zone")) @db.Timestamptz(6) + currency String @default("TRY") @db.VarChar(8) + bid_price Decimal @default(0) @db.Decimal(16, 4) + approved_price Decimal @default(0) @db.Decimal(16, 4) + final_price Decimal @default(0) @db.Decimal(16, 4) + contact_id Int? + contact_uu_id String? @db.VarChar + build_decision_book_id Int + build_decision_book_uu_id String? @db.VarChar + build_decision_book_item_id Int + build_decision_book_item_uu_id String? @db.VarChar + project_response_living_space_id Int? + project_response_living_space_uu_id String? @db.VarChar + resp_company_id Int? + resp_company_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_decision_book_projects_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + account_detail account_detail[] + account_master account_master[] + build_decision_book_payments build_decision_book_payments[] + build_decision_book_project_items build_decision_book_project_items[] + build_decision_book_project_person build_decision_book_project_person[] + build_decision_book build_decision_book @relation(fields: [build_decision_book_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_decision_book_items build_decision_book_items @relation(fields: [build_decision_book_item_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + contracts contracts? @relation(fields: [contact_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_living_space build_living_space? @relation(fields: [project_response_living_space_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies companies? @relation(fields: [resp_company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([project_no, project_start_date], map: "_build_decision_book_project_ndx_00") + @@index([created_at], map: "ix_build_decision_book_projects_created_at") + @@index([cryp_uu_id], map: "ix_build_decision_book_projects_cryp_uu_id") + @@index([meeting_date], map: "ix_build_decision_book_projects_meeting_date") + @@index([ref_id], map: "ix_build_decision_book_projects_ref_id") + @@index([ref_int], map: "ix_build_decision_book_projects_ref_int") + @@index([updated_at], map: "ix_build_decision_book_projects_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_iban_description { + iban String @db.VarChar + group_id Int @db.SmallInt + search_word String @db.VarChar + customer_id Int? + customer_uu_id String? @db.VarChar + company_id Int? + company_uu_id String? @db.VarChar + build_parts_id Int? + build_parts_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_iban_description_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_parts build_parts? @relation(fields: [build_parts_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies companies? @relation(fields: [company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + people people? @relation(fields: [customer_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([iban, search_word, group_id], map: "_search_iban_description_ndx_00") + @@index([created_at], map: "ix_build_iban_description_created_at") + @@index([cryp_uu_id], map: "ix_build_iban_description_cryp_uu_id") + @@index([ref_id], map: "ix_build_iban_description_ref_id") + @@index([ref_int], map: "ix_build_iban_description_ref_int") + @@index([search_word], map: "ix_build_iban_description_search_word") + @@index([updated_at], map: "ix_build_iban_description_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_ibans { + iban String @default("") @db.VarChar(40) + start_date DateTime @db.Timestamptz(6) + stop_date DateTime @default(dbgenerated("'2900-01-01 00:00:00+00'::timestamp with time zone")) @db.Timestamptz(6) + bank_code String @default("TR0000000000000") @db.VarChar(24) + xcomment String @default("????") @db.VarChar(64) + build_id Int? + build_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_ibans_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build build? @relation(fields: [build_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([iban, start_date], map: "_build_ibans_ndx_01") + @@index([build_uu_id], map: "ix_build_ibans_build_uu_id") + @@index([created_at], map: "ix_build_ibans_created_at") + @@index([cryp_uu_id], map: "ix_build_ibans_cryp_uu_id") + @@index([ref_id], map: "ix_build_ibans_ref_id") + @@index([ref_int], map: "ix_build_ibans_ref_int") + @@index([updated_at], map: "ix_build_ibans_updated_at") +} + +model user_types { + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_user_types_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + type String @db.VarChar + description String @default("") @db.VarChar + type_token String @default("") @db.VarChar + token String @default("") @db.VarChar + occupant_types occupant_types[] + staff staff[] + + @@index([type], map: "ix_user_types_type") + @@index([token], map: "ix_user_types_token") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_living_space { + fix_value Decimal @default(0) @db.Decimal(20, 6) + fix_percent Decimal @default(0) @db.Decimal(6, 2) + agreement_no String @default("") @db.VarChar + marketing_process Boolean @default(false) + marketing_layer Int @default(0) + build_parts_id Int + build_parts_uu_id String @db.VarChar + person_id Int + person_uu_id String @db.VarChar + occupant_type_id Int + occupant_type_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_living_space_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + account_records account_records[] + application2occupant application2occupant[] + application2occupant_extra application2occupant_extra[] + build_decision_book_person build_decision_book_person[] + build_decision_book_project_person build_decision_book_project_person[] + build_decision_book_projects build_decision_book_projects[] + build_parts build_parts @relation(fields: [build_parts_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + occupant_types occupant_types @relation(fields: [occupant_type_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + people people @relation(fields: [person_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + event2occupant event2occupant[] + event2occupant_extra event2occupant_extra[] + + @@index([build_parts_id], map: "ix_build_living_space_build_parts_id") + @@index([created_at], map: "ix_build_living_space_created_at") + @@index([cryp_uu_id], map: "ix_build_living_space_cryp_uu_id") + @@index([person_id], map: "ix_build_living_space_person_id") + @@index([ref_id], map: "ix_build_living_space_ref_id") + @@index([ref_int], map: "ix_build_living_space_ref_int") + @@index([updated_at], map: "ix_build_living_space_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_management { + discounted_percentage Decimal @default(0.00) @db.Decimal(6, 2) + discounted_price Decimal @default(0.00) @db.Decimal(20, 2) + calculated_price Decimal @default(0.00) @db.Decimal(20, 2) + occupant_type Int + occupant_type_uu_id String @db.VarChar + build_id Int + build_uu_id String @db.VarChar + build_parts_id Int + build_parts_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_management_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build build @relation(fields: [build_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_parts build_parts @relation(fields: [build_parts_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + occupant_types occupant_types @relation(fields: [occupant_type], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([build_parts_id, occupant_type, expiry_starts], map: "build_management_ndx_00") + @@index([build_parts_id], map: "ix_build_management_build_parts_id") + @@index([created_at], map: "ix_build_management_created_at") + @@index([cryp_uu_id], map: "ix_build_management_cryp_uu_id") + @@index([ref_id], map: "ix_build_management_ref_id") + @@index([ref_int], map: "ix_build_management_ref_int") + @@index([updated_at], map: "ix_build_management_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_parts { + address_gov_code String @db.VarChar + part_no Int @default(0) + part_level Int @default(0) + part_code String @default("") @db.VarChar + part_gross_size Int @default(0) + part_net_size Int @default(0) + default_accessory String @default("0") + human_livable Boolean @default(true) + due_part_key String @default("") @db.VarChar + build_id Int + build_uu_id String @db.VarChar + part_direction_id Int? + part_direction_uu_id String? @db.VarChar + part_type_id Int + part_type_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_parts_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + account_records account_records[] + build_decision_book_payments build_decision_book_payments[] + build_iban_description build_iban_description[] + build_living_space build_living_space[] + build_management build_management[] + build build @relation(fields: [build_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + api_enum_dropdown_build_parts_part_direction_idToapi_enum_dropdown api_enum_dropdown? @relation("build_parts_part_direction_idToapi_enum_dropdown", fields: [part_direction_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + api_enum_dropdown_build_parts_part_type_idToapi_enum_dropdown api_enum_dropdown @relation("build_parts_part_type_idToapi_enum_dropdown", fields: [part_type_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + decision_book_budget_codes decision_book_budget_codes[] + part2employee part2employee[] + + @@unique([build_id, part_no], map: "build_parts_ndx_1") + @@index([created_at], map: "ix_build_parts_created_at") + @@index([cryp_uu_id], map: "ix_build_parts_cryp_uu_id") + @@index([ref_id], map: "ix_build_parts_ref_id") + @@index([ref_int], map: "ix_build_parts_ref_int") + @@index([updated_at], map: "ix_build_parts_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_person_providing { + build_id Int + build_uu_id String? @db.VarChar + people_id Int + people_uu_id String? @db.VarChar + provide_id Int? + provide_uu_id String? @db.VarChar + contract_id Int? + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_person_providing_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build build @relation(fields: [build_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies companies? @relation(fields: [contract_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + people people @relation(fields: [people_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + api_enum_dropdown api_enum_dropdown? @relation(fields: [provide_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([build_id, people_id, provide_id], map: "_build_person_providing_ndx_00") + @@index([created_at], map: "ix_build_person_providing_created_at") + @@index([cryp_uu_id], map: "ix_build_person_providing_cryp_uu_id") + @@index([ref_id], map: "ix_build_person_providing_ref_id") + @@index([ref_int], map: "ix_build_person_providing_ref_int") + @@index([updated_at], map: "ix_build_person_providing_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_sites { + site_name String @db.VarChar(24) + site_no String @db.VarChar(8) + address_id Int + address_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_sites_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build build[] + addresses addresses @relation(fields: [address_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([site_no, site_name], map: "_sites_ndx_01") + @@index([created_at], map: "ix_build_sites_created_at") + @@index([cryp_uu_id], map: "ix_build_sites_cryp_uu_id") + @@index([ref_id], map: "ix_build_sites_ref_id") + @@index([ref_int], map: "ix_build_sites_ref_int") + @@index([updated_at], map: "ix_build_sites_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model build_types { + function_code String @default("") @db.VarChar(12) + type_code String @default("") @db.VarChar(12) + lang String @default("TR") @db.VarChar(4) + type_name String @default("") @db.VarChar(48) + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_build_types_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + + @@unique([type_code, function_code, lang], map: "_build_types_ndx_00") + @@index([created_at], map: "ix_build_types_created_at") + @@index([cryp_uu_id], map: "ix_build_types_cryp_uu_id") + @@index([ref_id], map: "ix_build_types_ref_id") + @@index([ref_int], map: "ix_build_types_ref_int") + @@index([updated_at], map: "ix_build_types_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model companies { + formal_name String @db.VarChar + company_type String @db.VarChar + commercial_type String @db.VarChar + tax_no String @unique(map: "_company_ndx_01") @db.VarChar + public_name String @db.VarChar + company_tag String @db.VarChar + default_lang_type String @default("TR") @db.VarChar + default_money_type String @default("TL") @db.VarChar + is_commercial Boolean @default(false) + is_blacklist Boolean @default(false) + parent_id Int? + workplace_no String? @db.VarChar + official_address_id Int? + official_address_uu_id String? @db.VarChar + top_responsible_company_id Int? + top_responsible_company_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_companies_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + account_books_account_books_branch_idTocompanies account_books[] @relation("account_books_branch_idTocompanies") + account_books_account_books_company_idTocompanies account_books[] @relation("account_books_company_idTocompanies") + account_codes_account_codes_company_idTocompanies account_codes[] @relation("account_codes_company_idTocompanies") + account_codes_account_codes_customer_idTocompanies account_codes[] @relation("account_codes_customer_idTocompanies") + account_records_account_records_company_idTocompanies account_records[] @relation("account_records_company_idTocompanies") + account_records_account_records_send_company_idTocompanies account_records[] @relation("account_records_send_company_idTocompanies") + build_companies_providing_build_companies_providing_company_idTocompanies build_companies_providing[] @relation("build_companies_providing_company_idTocompanies") + build_companies_providing_build_companies_providing_contract_idTocompanies build_companies_providing[] @relation("build_companies_providing_contract_idTocompanies") + build_decision_book build_decision_book[] + build_decision_book_legal build_decision_book_legal[] + build_decision_book_projects build_decision_book_projects[] + build_iban_description build_iban_description[] + build_person_providing build_person_providing[] + addresses addresses? @relation(fields: [official_address_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies companies? @relation("companiesTocompanies", fields: [top_responsible_company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + other_companies companies[] @relation("companiesTocompanies") + company_delay_interest company_delay_interest[] + contracts contracts[] + decision_book_budget_books_decision_book_budget_books_branch_idTocompanies decision_book_budget_books[] @relation("decision_book_budget_books_branch_idTocompanies") + decision_book_budget_books_decision_book_budget_books_company_idTocompanies decision_book_budget_books[] @relation("decision_book_budget_books_company_idTocompanies") + decision_book_budget_codes decision_book_budget_codes[] + departments departments[] + relationship_duty_company_relationship_duty_company_member_idTocompanies relationship_duty_company[] @relation("relationship_duty_company_member_idTocompanies") + relationship_duty_company_relationship_duty_company_owner_idTocompanies relationship_duty_company[] @relation("relationship_duty_company_owner_idTocompanies") + relationship_duty_company_relationship_duty_company_parent_idTocompanies relationship_duty_company[] @relation("relationship_duty_company_parent_idTocompanies") + relationship_duty_people relationship_duty_people[] + relationship_employee2build relationship_employee2build[] + relationship_employee2postcode relationship_employee2postcode[] + + @@index([formal_name, public_name], map: "_company_ndx_02") + @@index([created_at], map: "ix_companies_created_at") + @@index([cryp_uu_id], map: "ix_companies_cryp_uu_id") + @@index([ref_id], map: "ix_companies_ref_id") + @@index([ref_int], map: "ix_companies_ref_int") + @@index([updated_at], map: "ix_companies_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model company_delay_interest { + company_id Int? + company_uu_id String? @db.VarChar + build_id Int? + build_uu_id String? @db.VarChar + daily_interest_type String? @db.VarChar(24) + daily_interest_rate Decimal @default(0) @db.Decimal(20, 6) + bsmv_rate Decimal @default(0) @db.Decimal(20, 6) + kkdf_rate Decimal @default(0) @db.Decimal(20, 6) + start_date DateTime @db.Timestamptz(6) + stop_date DateTime @default(dbgenerated("'2900-01-01 00:00:00+00'::timestamp with time zone")) @db.Timestamptz(6) + ref_int Int? + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_company_delay_interest_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + build build? @relation(fields: [build_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies companies? @relation(fields: [company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([company_id, build_id, start_date], map: "_company_delay_interest_ndx_01") + @@index([company_id, build_id], map: "ix_company_delay_interest_build_uu_id") + @@index([created_at], map: "ix_company_delay_interest_created_at") + @@index([cryp_uu_id], map: "ix_company_delay_interest_cryp_uu_id") + @@index([ref_id], map: "ix_company_delay_interest_ref_id") + @@index([ref_int], map: "ix_company_delay_interest_ref_int") + @@index([updated_at], map: "ix_company_delay_interest_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model contracts { + contract_type String @db.VarChar(5) + contract_title String @db.VarChar(255) + contract_details String + contract_terms String + contract_code String @unique(map: "_contract_ndx_01") @db.VarChar(100) + contract_date DateTime @default(dbgenerated("'2099-12-31 23:59:59+00'::timestamp with time zone")) @db.Timestamptz(6) + company_id Int? + company_uu_id String @default("") @db.VarChar + person_id Int? + person_uu_id String @default("") @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_contracts_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_decision_book build_decision_book[] + build_decision_book_projects build_decision_book_projects[] + companies companies? @relation(fields: [company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + people people? @relation(fields: [person_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([created_at], map: "ix_contracts_created_at") + @@index([cryp_uu_id], map: "ix_contracts_cryp_uu_id") + @@index([ref_id], map: "ix_contracts_ref_id") + @@index([ref_int], map: "ix_contracts_ref_int") + @@index([updated_at], map: "ix_contracts_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model credentials { + credential_token String @default("") @db.VarChar + user_id Int + user_uu_id String @default("") @db.VarChar + person_id Int + person_uu_id String @default("") @db.VarChar + name String @default("") @db.VarChar + surname String @default("") @db.VarChar + email String @default("") @db.VarChar + phone String @default("") @db.VarChar + is_verified Boolean @default(false) + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_credentials_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + people people @relation(fields: [person_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + users users @relation(fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([created_at], map: "ix_credentials_created_at") + @@index([cryp_uu_id], map: "ix_credentials_cryp_uu_id") + @@index([email], map: "ix_credentials_email") + @@index([name], map: "ix_credentials_name") + @@index([person_uu_id], map: "ix_credentials_person_uu_id") + @@index([phone], map: "ix_credentials_phone") + @@index([ref_id], map: "ix_credentials_ref_id") + @@index([ref_int], map: "ix_credentials_ref_int") + @@index([surname], map: "ix_credentials_surname") + @@index([updated_at], map: "ix_credentials_updated_at") + @@index([user_uu_id], map: "ix_credentials_user_uu_id") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model decision_book_budget_books { + country String @db.VarChar + branch_type Int @default(0) @db.SmallInt + company_id Int + company_uu_id String @db.VarChar + branch_id Int? + branch_uu_id String? @db.VarChar + build_decision_book_id Int + build_decision_book_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_decision_book_budget_books_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + companies_decision_book_budget_books_branch_idTocompanies companies? @relation("decision_book_budget_books_branch_idTocompanies", fields: [branch_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_decision_book build_decision_book @relation(fields: [build_decision_book_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies_decision_book_budget_books_company_idTocompanies companies @relation("decision_book_budget_books_company_idTocompanies", fields: [company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + decision_book_budget_master decision_book_budget_master[] + + @@index([company_id, created_at], map: "_decision_book_budget_companies_book_ndx_00") + @@index([created_at], map: "ix_decision_book_budget_books_created_at") + @@index([cryp_uu_id], map: "ix_decision_book_budget_books_cryp_uu_id") + @@index([ref_id], map: "ix_decision_book_budget_books_ref_id") + @@index([ref_int], map: "ix_decision_book_budget_books_ref_int") + @@index([updated_at], map: "ix_decision_book_budget_books_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model decision_book_budget_codes { + budget_code String @db.VarChar(48) + comment_line String + build_decision_book_id Int? + build_decision_book_uu_id String? @db.VarChar + build_parts_id Int? + build_parts_uu_id String? @db.VarChar + company_id Int? + company_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_decision_book_budget_codes_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_decision_book build_decision_book? @relation(fields: [build_decision_book_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_parts build_parts? @relation(fields: [build_parts_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies companies? @relation(fields: [company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + decision_book_budgets decision_book_budgets[] + + @@index([budget_code, created_at], map: "_decision_book_budget_codes_ndx_00") + @@index([company_id, created_at], map: "_decision_book_budget_codes_ndx_01") + @@index([created_at], map: "ix_decision_book_budget_codes_created_at") + @@index([cryp_uu_id], map: "ix_decision_book_budget_codes_cryp_uu_id") + @@index([ref_id], map: "ix_decision_book_budget_codes_ref_id") + @@index([ref_int], map: "ix_decision_book_budget_codes_ref_int") + @@index([updated_at], map: "ix_decision_book_budget_codes_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model decision_book_budget_master { + budget_type String @db.VarChar(50) + currency String @default("TRY") @db.VarChar(8) + total_budget Decimal @db.Decimal(10, 2) + tracking_period_id Int? + tracking_period_uu_id String? @db.VarChar + budget_books_id Int + budget_books_uu_id String? @db.VarChar + department_id Int + department_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_decision_book_budget_master_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + decision_book_budget_books decision_book_budget_books @relation(fields: [budget_books_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + departments departments @relation(fields: [department_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + api_enum_dropdown api_enum_dropdown? @relation(fields: [tracking_period_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + decision_book_budgets decision_book_budgets[] + + @@index([created_at], map: "ix_decision_book_budget_master_created_at") + @@index([cryp_uu_id], map: "ix_decision_book_budget_master_cryp_uu_id") + @@index([ref_id], map: "ix_decision_book_budget_master_ref_id") + @@index([ref_int], map: "ix_decision_book_budget_master_ref_int") + @@index([updated_at], map: "ix_decision_book_budget_master_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model decision_book_budgets { + process_date DateTime @db.Timestamptz(6) + budget_codes_id Int + total_budget Decimal @db.Decimal(10, 2) + used_budget Decimal @db.Decimal(10, 2) + remaining_budget Decimal @db.Decimal(10, 2) + decision_book_budget_master_id Int + decision_book_budget_master_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_decision_book_budgets_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + decision_book_budget_codes decision_book_budget_codes @relation(fields: [budget_codes_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + decision_book_budget_master decision_book_budget_master @relation(fields: [decision_book_budget_master_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([decision_book_budget_master_uu_id, process_date], map: "_decision_book_budgets_ndx_00") + @@index([created_at], map: "ix_decision_book_budgets_created_at") + @@index([cryp_uu_id], map: "ix_decision_book_budgets_cryp_uu_id") + @@index([ref_id], map: "ix_decision_book_budgets_ref_id") + @@index([ref_int], map: "ix_decision_book_budgets_ref_int") + @@index([updated_at], map: "ix_decision_book_budgets_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model departments { + parent_department_id Int? @default(0) + department_code String @db.VarChar(16) + department_name String @db.VarChar(128) + department_description String @default("") @db.VarChar + company_id Int + company_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_departments_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + account_master account_master[] + decision_book_budget_master decision_book_budget_master[] + companies companies @relation(fields: [company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + duties duties[] + + @@index([created_at], map: "ix_departments_created_at") + @@index([cryp_uu_id], map: "ix_departments_cryp_uu_id") + @@index([department_code], map: "ix_departments_department_code") + @@index([ref_id], map: "ix_departments_ref_id") + @@index([ref_int], map: "ix_departments_ref_int") + @@index([updated_at], map: "ix_departments_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model duties { + users_default_duty Int? + company_id Int + company_uu_id String @db.VarChar + duties_id Int + duties_uu_id String @db.VarChar + department_id Int + department_uu_id String @db.VarChar + management_duty Boolean? @default(false) + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_duties_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + departments departments @relation(fields: [department_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + duty_duties_duties_idToduty duty @relation("duties_duties_idToduty", fields: [duties_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + duty_duties_users_default_dutyToduty duty? @relation("duties_users_default_dutyToduty", fields: [users_default_duty], references: [id], onDelete: NoAction, onUpdate: NoAction) + relationship_duty_company relationship_duty_company[] + relationship_duty_people relationship_duty_people[] + staff staff[] + + @@unique([company_id, duties_id, department_id], map: "duty_ndx_00") + @@index([created_at], map: "ix_duties_created_at") + @@index([cryp_uu_id], map: "ix_duties_cryp_uu_id") + @@index([ref_id], map: "ix_duties_ref_id") + @@index([ref_int], map: "ix_duties_ref_int") + @@index([updated_at], map: "ix_duties_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model duty { + duty_name String @unique @db.VarChar + duty_code String @db.VarChar + duty_description String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_duty_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + duties_duties_duties_idToduty duties[] @relation("duties_duties_idToduty") + duties_duties_users_default_dutyToduty duties[] @relation("duties_users_default_dutyToduty") + + @@index([created_at], map: "ix_duty_created_at") + @@index([cryp_uu_id], map: "ix_duty_cryp_uu_id") + @@index([ref_id], map: "ix_duty_ref_id") + @@index([ref_int], map: "ix_duty_ref_int") + @@index([updated_at], map: "ix_duty_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model employee_history { + staff_id Int + staff_uu_id String @db.VarChar + people_id Int + people_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_employee_history_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + people people @relation(fields: [people_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + staff staff @relation(fields: [staff_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([people_id, staff_id], map: "_employee_history_ndx_00") + @@index([created_at], map: "ix_employee_history_created_at") + @@index([cryp_uu_id], map: "ix_employee_history_cryp_uu_id") + @@index([ref_id], map: "ix_employee_history_ref_id") + @@index([ref_int], map: "ix_employee_history_ref_int") + @@index([updated_at], map: "ix_employee_history_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model employee_salaries { + gross_salary Decimal @db.Decimal(20, 6) + net_salary Decimal @db.Decimal(20, 6) + people_id Int + people_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_employee_salaries_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + people people @relation(fields: [people_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([people_id, expiry_starts], map: "_employee_salaries_ndx_00") + @@index([created_at], map: "ix_employee_salaries_created_at") + @@index([cryp_uu_id], map: "ix_employee_salaries_cryp_uu_id") + @@index([ref_id], map: "ix_employee_salaries_ref_id") + @@index([ref_int], map: "ix_employee_salaries_ref_int") + @@index([updated_at], map: "ix_employee_salaries_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model employees { + staff_id Int + staff_uu_id String @db.VarChar + people_id Int? + people_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_employees_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + application2employee application2employee[] + application2employee_extra application2employee_extra[] + people people? @relation(fields: [people_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + staff staff @relation(fields: [staff_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + event2employee event2employee[] + event2employee_extra event2employee_extra[] + part2employee part2employee[] + relationship_employee2build relationship_employee2build[] + relationship_employee2postcode relationship_employee2postcode[] + + @@unique([people_id, staff_id], map: "employees_ndx_00") + @@index([created_at], map: "ix_employees_created_at") + @@index([cryp_uu_id], map: "ix_employees_cryp_uu_id") + @@index([ref_id], map: "ix_employees_ref_id") + @@index([ref_int], map: "ix_employees_ref_int") + @@index([updated_at], map: "ix_employees_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model endpoint_restriction { + operation_uu_id String @unique @db.VarChar + endpoint_function String @default("") @db.VarChar + endpoint_name String @default("") @db.VarChar + endpoint_method String @default("") @db.VarChar + endpoint_desc String @default("") @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_endpoint_restriction_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + events events[] + + @@unique([operation_uu_id, endpoint_method, endpoint_name], map: "idx_endpoint_restriction_operation_uu_id") + @@index([created_at], map: "ix_endpoint_restriction_created_at") + @@index([cryp_uu_id], map: "ix_endpoint_restriction_cryp_uu_id") + @@index([ref_id], map: "ix_endpoint_restriction_ref_id") + @@index([ref_int], map: "ix_endpoint_restriction_ref_int") + @@index([updated_at], map: "ix_endpoint_restriction_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model event2employee { + employee_id Int + employee_uu_id String @db.VarChar + event_service_id Int + event_service_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_event2employee_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + employees employees @relation(fields: [employee_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + services services @relation(fields: [event_service_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([employee_id, event_service_id], map: "event2employee_employee_to_event") + @@index([created_at], map: "ix_event2employee_created_at") + @@index([cryp_uu_id], map: "ix_event2employee_cryp_uu_id") + @@index([ref_id], map: "ix_event2employee_ref_id") + @@index([ref_int], map: "ix_event2employee_ref_int") + @@index([updated_at], map: "ix_event2employee_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model event2employee_extra { + employee_id Int + employee_uu_id String @db.VarChar + event_id Int + event_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_event2employee_extra_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + employees employees @relation(fields: [employee_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + events events @relation(fields: [event_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([employee_id, event_id], map: "event2employee_extra_employee_to_event") + @@index([created_at], map: "ix_event2employee_extra_created_at") + @@index([cryp_uu_id], map: "ix_event2employee_extra_cryp_uu_id") + @@index([ref_id], map: "ix_event2employee_extra_ref_id") + @@index([ref_int], map: "ix_event2employee_extra_ref_int") + @@index([updated_at], map: "ix_event2employee_extra_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model event2occupant { + build_living_space_id Int + build_living_space_uu_id String @db.VarChar + event_service_id Int + event_service_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_event2occupant_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_living_space build_living_space @relation(fields: [build_living_space_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + services services @relation(fields: [event_service_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([build_living_space_id, event_service_id], map: "event2occupant_bind_event_to_occupant") + @@index([created_at], map: "ix_event2occupant_created_at") + @@index([cryp_uu_id], map: "ix_event2occupant_cryp_uu_id") + @@index([ref_id], map: "ix_event2occupant_ref_id") + @@index([ref_int], map: "ix_event2occupant_ref_int") + @@index([updated_at], map: "ix_event2occupant_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model event2occupant_extra { + build_living_space_id Int + build_living_space_uu_id String @db.VarChar + event_id Int + event_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_event2occupant_extra_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_living_space build_living_space @relation(fields: [build_living_space_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + events events @relation(fields: [event_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([build_living_space_id, event_id], map: "event2occupant_extra_bind_event_to_occupant") + @@index([created_at], map: "ix_event2occupant_extra_created_at") + @@index([cryp_uu_id], map: "ix_event2occupant_extra_cryp_uu_id") + @@index([ref_id], map: "ix_event2occupant_extra_ref_id") + @@index([ref_int], map: "ix_event2occupant_extra_ref_int") + @@index([updated_at], map: "ix_event2occupant_extra_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model events { + function_code String @unique @db.VarChar + function_class String @db.VarChar + description String @default("") @db.VarChar + property_description String @default("") @db.VarChar + marketing_layer Int? @default(3) @db.SmallInt + cost Decimal @default(0.00) @db.Decimal(20, 2) + unit_price Decimal @default(0.00) @db.Decimal(20, 2) + endpoint_code String @db.VarChar + endpoint_id Int? + endpoint_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_events_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + event2employee_extra event2employee_extra[] + event2occupant_extra event2occupant_extra[] + endpoint_restriction endpoint_restriction? @relation(fields: [endpoint_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + module_price module_price[] + services2events services2events[] + + @@index([created_at], map: "ix_events_created_at") + @@index([cryp_uu_id], map: "ix_events_cryp_uu_id") + @@index([ref_id], map: "ix_events_ref_id") + @@index([ref_int], map: "ix_events_ref_int") + @@index([updated_at], map: "ix_events_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model module_price { + campaign_code String @db.VarChar + module_id Int + module_uu_id String @db.VarChar + service_id Int + service_uu_id String @db.VarChar + event_id Int + event_uu_id String @db.VarChar + is_counted_percentage Decimal @default(0.00) @db.Decimal(6, 2) + discounted_price Decimal @default(0.00) @db.Decimal(20, 2) + calculated_price Decimal @default(0.00) @db.Decimal(20, 2) + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_module_price_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + events events @relation(fields: [event_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + modules modules @relation(fields: [module_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + services services @relation(fields: [service_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([created_at], map: "ix_module_price_created_at") + @@index([cryp_uu_id], map: "ix_module_price_cryp_uu_id") + @@index([ref_id], map: "ix_module_price_ref_id") + @@index([ref_int], map: "ix_module_price_ref_int") + @@index([updated_at], map: "ix_module_price_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model modules { + module_name String @db.VarChar + module_description String @default("") @db.VarChar + module_code String @db.VarChar + module_layer Int + is_default_module Boolean? @default(false) + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_modules_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + module_price module_price[] + services services[] + + @@index([created_at], map: "ix_modules_created_at") + @@index([cryp_uu_id], map: "ix_modules_cryp_uu_id") + @@index([ref_id], map: "ix_modules_ref_id") + @@index([ref_int], map: "ix_modules_ref_int") + @@index([updated_at], map: "ix_modules_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model occupant_types { + occupant_type String @db.VarChar + occupant_description String @default("") @db.VarChar + occupant_code String @default("") @db.VarChar + occupant_category String @default("") @db.VarChar + occupant_category_type String @default("") @db.VarChar + // function_retriever String @default("") @db.VarChar + user_type_id Int? + user_type_uu_id String? @db.VarChar + occupant_is_unique Boolean @default(false) + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_occupant_types_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + build_decision_book_person_occupants build_decision_book_person_occupants[] + build_living_space build_living_space[] + build_management build_management[] + user_types user_types? @relation(fields: [user_type_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([created_at], map: "ix_occupant_types_created_at") + @@index([cryp_uu_id], map: "ix_occupant_types_cryp_uu_id") + @@index([ref_id], map: "ix_occupant_types_ref_id") + @@index([ref_int], map: "ix_occupant_types_ref_int") + @@index([updated_at], map: "ix_occupant_types_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model part2employee { + build_id Int + part_id Int + employee_id Int + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_part2employee_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + employees employees @relation(fields: [employee_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build_parts build_parts @relation(fields: [part_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([employee_id, part_id], map: "_part2employee_ndx_00") + @@index([created_at], map: "ix_part2employee_created_at") + @@index([cryp_uu_id], map: "ix_part2employee_cryp_uu_id") + @@index([ref_id], map: "ix_part2employee_ref_id") + @@index([ref_int], map: "ix_part2employee_ref_int") + @@index([updated_at], map: "ix_part2employee_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model people { + firstname String @db.VarChar + surname String @db.VarChar(24) + middle_name String @default("") @db.VarChar + sex_code String @db.VarChar(1) + person_ref String @default("") @db.VarChar + person_tag String @default("") @db.VarChar + father_name String @default("") @db.VarChar + mother_name String @default("") @db.VarChar + country_code String @default("TR") @db.VarChar(4) + national_identity_id String @unique(map: "person_ndx_001") @default("") @db.VarChar + birth_place String @default("") @db.VarChar + birth_date DateTime @default(dbgenerated("'1900-01-01 00:00:00+00'::timestamp with time zone")) @db.Timestamptz(6) + tax_no String @default("") @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_people_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + birthname String? @db.VarChar + account_codes account_codes[] + account_records_account_records_approving_accounting_personTopeople account_records[] @relation("account_records_approving_accounting_personTopeople") + account_records_account_records_customer_idTopeople account_records[] @relation("account_records_customer_idTopeople") + account_records_account_records_send_person_idTopeople account_records[] @relation("account_records_send_person_idTopeople") + build_decision_book_items_unapproved build_decision_book_items_unapproved[] + build_decision_book_legal_build_decision_book_legal_mediator_lawyer_person_idTopeople build_decision_book_legal[] @relation("build_decision_book_legal_mediator_lawyer_person_idTopeople") + build_decision_book_legal_build_decision_book_legal_resp_attorney_idTopeople build_decision_book_legal[] @relation("build_decision_book_legal_resp_attorney_idTopeople") + build_decision_book_person_build_decision_book_person_person_idTopeople build_decision_book_person[] @relation("build_decision_book_person_person_idTopeople") + build_decision_book_person_build_decision_book_person_vicarious_person_idTopeople build_decision_book_person[] @relation("build_decision_book_person_vicarious_person_idTopeople") + build_iban_description build_iban_description[] + build_living_space build_living_space[] + build_person_providing build_person_providing[] + contracts contracts[] + credentials credentials[] + employee_history employee_history[] + employee_salaries employee_salaries[] + employees employees[] + relationship_duty_people relationship_duty_people[] + users users[] + + @@index([created_at], map: "ix_people_created_at") + @@index([cryp_uu_id], map: "ix_people_cryp_uu_id") + @@index([ref_id], map: "ix_people_ref_id") + @@index([ref_int], map: "ix_people_ref_int") + @@index([updated_at], map: "ix_people_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model relationship_duty_company { + owner_id Int + duties_id Int + member_id Int + parent_id Int? + relationship_type String? @default("Commercial") @db.VarChar + child_count Int + show_only Boolean @default(false) + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_relationship_duty_company_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + duties duties @relation(fields: [duties_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies_relationship_duty_company_member_idTocompanies companies @relation("relationship_duty_company_member_idTocompanies", fields: [member_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies_relationship_duty_company_owner_idTocompanies companies @relation("relationship_duty_company_owner_idTocompanies", fields: [owner_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + companies_relationship_duty_company_parent_idTocompanies companies? @relation("relationship_duty_company_parent_idTocompanies", fields: [parent_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([duties_id, owner_id, member_id, relationship_type], map: "_company_relationship_ndx_01") + @@index([created_at], map: "ix_relationship_duty_company_created_at") + @@index([cryp_uu_id], map: "ix_relationship_duty_company_cryp_uu_id") + @@index([ref_id], map: "ix_relationship_duty_company_ref_id") + @@index([ref_int], map: "ix_relationship_duty_company_ref_int") + @@index([updated_at], map: "ix_relationship_duty_company_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model relationship_duty_people { + company_id Int + duties_id Int + member_id Int + relationship_type String? @default("Employee") @db.VarChar + show_only Boolean @default(false) + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_relationship_duty_people_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + companies companies @relation(fields: [company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + duties duties @relation(fields: [duties_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + people people @relation(fields: [member_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([company_id, duties_id, member_id, relationship_type], map: "person_relationship_ndx_01") + @@index([created_at], map: "ix_relationship_duty_people_created_at") + @@index([cryp_uu_id], map: "ix_relationship_duty_people_cryp_uu_id") + @@index([ref_id], map: "ix_relationship_duty_people_ref_id") + @@index([ref_int], map: "ix_relationship_duty_people_ref_int") + @@index([updated_at], map: "ix_relationship_duty_people_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model relationship_employee2build { + company_id Int + employee_id Int + member_id Int + relationship_type String? @default("Employee") @db.VarChar + show_only Boolean @default(false) + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_relationship_employee2build_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + companies companies @relation(fields: [company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + employees employees @relation(fields: [employee_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + build build @relation(fields: [member_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@unique([company_id, employee_id, member_id, relationship_type], map: "relationship_build_employee_ndx_00") + @@index([created_at], map: "ix_relationship_employee2build_created_at") + @@index([cryp_uu_id], map: "ix_relationship_employee2build_cryp_uu_id") + @@index([ref_id], map: "ix_relationship_employee2build_ref_id") + @@index([ref_int], map: "ix_relationship_employee2build_ref_int") + @@index([updated_at], map: "ix_relationship_employee2build_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model relationship_employee2postcode { + company_id Int? + employee_id Int + member_id Int + relationship_type String? @default("Employee") @db.VarChar + show_only Boolean @default(false) + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_relationship_employee2postcode_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + companies companies? @relation(fields: [company_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + employees employees @relation(fields: [employee_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + address_postcode address_postcode @relation(fields: [member_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([created_at], map: "ix_relationship_employee2postcode_created_at") + @@index([cryp_uu_id], map: "ix_relationship_employee2postcode_cryp_uu_id") + @@index([ref_id], map: "ix_relationship_employee2postcode_ref_id") + @@index([ref_int], map: "ix_relationship_employee2postcode_ref_int") + @@index([updated_at], map: "ix_relationship_employee2postcode_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model services { + module_id Int + module_uu_id String @db.VarChar + service_name String @db.VarChar + service_description String @default("") @db.VarChar + service_code String? @db.VarChar + related_responsibility String @default("") @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_services_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + application2employee application2employee[] + application2occupant application2occupant[] + event2employee event2employee[] + event2occupant event2occupant[] + module_price module_price[] + modules modules @relation(fields: [module_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + services2applications services2applications[] + services2events services2events[] + + @@index([created_at], map: "ix_services_created_at") + @@index([cryp_uu_id], map: "ix_services_cryp_uu_id") + @@index([ref_id], map: "ix_services_ref_id") + @@index([ref_int], map: "ix_services_ref_int") + @@index([updated_at], map: "ix_services_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model services2applications { + application_id Int + application_uu_id String @db.VarChar + service_id Int + service_uu_id String @db.VarChar + application_code String @db.VarChar + site_url String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_services2applications_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + applications applications @relation(fields: [application_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + services services @relation(fields: [service_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([created_at], map: "ix_services2applications_created_at") + @@index([cryp_uu_id], map: "ix_services2applications_cryp_uu_id") + @@index([ref_id], map: "ix_services2applications_ref_id") + @@index([ref_int], map: "ix_services2applications_ref_int") + @@index([updated_at], map: "ix_services2applications_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model services2events { + service_id Int + service_uu_id String @db.VarChar + event_id Int + event_uu_id String @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_services2events_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + events events @relation(fields: [event_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + services services @relation(fields: [service_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([created_at], map: "ix_services2events_created_at") + @@index([cryp_uu_id], map: "ix_services2events_cryp_uu_id") + @@index([ref_id], map: "ix_services2events_ref_id") + @@index([ref_int], map: "ix_services2events_ref_int") + @@index([updated_at], map: "ix_services2events_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model staff { + staff_description String @default("") @db.VarChar + staff_name String @db.VarChar + staff_code String @db.VarChar + duties_id Int + duties_uu_id String @db.VarChar + // function_retriever String @default("") @db.VarChar + user_type_id Int? + user_type_uu_id String? @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_staff_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + employee_history employee_history[] + employees employees[] + duties duties @relation(fields: [duties_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + user_types user_types? @relation(fields: [user_type_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([created_at], map: "ix_staff_created_at") + @@index([cryp_uu_id], map: "ix_staff_cryp_uu_id") + @@index([ref_id], map: "ix_staff_ref_id") + @@index([ref_int], map: "ix_staff_ref_int") + @@index([updated_at], map: "ix_staff_updated_at") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model users { + user_tag String @default("") @db.VarChar(64) + user_type String @default("employee") @db.VarChar(32) + email String @default("") @db.VarChar(128) + phone_number String @default("") @db.VarChar + via String @default("111") @db.VarChar + avatar String @default("") @db.VarChar + hash_password String @default("") @db.VarChar(256) + password_token String @default("") @db.VarChar(256) + remember_me Boolean @default(false) + password_expires_day Int @default(30) + password_expiry_begins DateTime @default(now()) @db.Timestamptz(6) + related_company String @db.VarChar + person_id Int + person_uu_id String @default("") @db.VarChar + local_timezone String? @default("GMT+3") @db.VarChar + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_users_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + default_language String @default("tr") @db.VarChar + ref_int Int? + credentials credentials[] + people people @relation(fields: [person_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + users_tokens users_tokens[] + domain_data domain_data[] @relation("UserDomainData") + + @@index([created_at], map: "ix_users_created_at") + @@index([cryp_uu_id], map: "ix_users_cryp_uu_id") + @@index([email], map: "ix_users_email") + @@index([person_uu_id], map: "ix_users_person_uu_id") + @@index([phone_number], map: "ix_users_phone_number") + @@index([ref_id], map: "ix_users_ref_id") + @@index([ref_int], map: "ix_users_ref_int") + @@index([updated_at], map: "ix_users_updated_at") + @@index([user_tag], map: "ix_users_user_tag") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model users_tokens { + user_id Int + token_type String @default("RememberMe") @db.VarChar(16) + token String @default("") @db.VarChar + domain String @default("") @db.VarChar + expires_at DateTime @db.Timestamptz(6) + ref_id String? @db.VarChar(100) + replication_id Int @default(0) @db.SmallInt + cryp_uu_id String? @db.VarChar + created_credentials_token String? @db.VarChar + updated_credentials_token String? @db.VarChar + confirmed_credentials_token String? @db.VarChar + is_confirmed Boolean @default(false) + deleted Boolean @default(false) + active Boolean @default(true) + is_notification_send Boolean @default(false) + is_email_send Boolean @default(false) + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_users_tokens_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + expiry_starts DateTime @default(now()) @db.Timestamptz(6) + expiry_ends DateTime @default(now()) @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + ref_int Int? + users users @relation(fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@index([created_at], map: "ix_users_tokens_created_at") + @@index([cryp_uu_id], map: "ix_users_tokens_cryp_uu_id") + @@index([ref_id], map: "ix_users_tokens_ref_id") + @@index([ref_int], map: "ix_users_tokens_ref_int") + @@index([updated_at], map: "ix_users_tokens_updated_at") +} + +model password_history { + id Int @id @default(autoincrement()) + uu_id String @unique(map: "password_history_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + userUUID String @map("user_uuid") @db.Uuid + password String @db.VarChar + old_password_first String @db.VarChar + old_password_first_modified_at DateTime @db.Timestamptz(6) + old_password_second String @db.VarChar + old_password_second_modified_at DateTime @db.Timestamptz(6) + old_password_third String @db.VarChar + old_password_third_modified_at DateTime @db.Timestamptz(6) + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + + @@index([created_at], map: "ix_password_history_created_at") + @@index([uu_id], map: "idx_password_history_uu_id") + @@index([updated_at], map: "ix_password_history_updated_at") +} + +model domain_data { + id Int @id @default(autoincrement()) + uu_id String @unique(map: "domain_data_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + userUUID String @map("user_uuid") @db.Uuid + otherDomainsList String[] @map("other_domains_list") + mainDomain String? @map("main_domain") + modifiedAt Float @map("modified_at") + created_at DateTime @default(now()) @db.Timestamptz(6) + updated_at DateTime @updatedAt @db.Timestamptz(6) + users users @relation("UserDomainData", fields: [userUUID], references: [uu_id], onDelete: NoAction, onUpdate: NoAction, map: "domain_data_users_fkey") + + @@index([created_at], map: "ix_domain_data_created_at") + @@index([uu_id], map: "idx_domain_data_uu_id") + @@index([updated_at], map: "ix_domain_data_updated_at") +} + +enum tabledefs { + PKEY_INTERNAL + PKEY_EXTERNAL + FKEYS_INTERNAL + FKEYS_EXTERNAL + COMMENTS + FKEYS_NONE + INCLUDE_TRIGGERS + NO_TRIGGERS +} diff --git a/ServicesTask/app/services/mail/IsBank/params.py b/ServicesTask/app/services/mail/IsBank/params.py new file mode 100644 index 0000000..c823de1 --- /dev/null +++ b/ServicesTask/app/services/mail/IsBank/params.py @@ -0,0 +1,18 @@ +import os + +from ..config import ConfigServices + +class IsBankConfig: + + MAILBOX: str = os.getenv("MAILBOX", "bilgilendirme@ileti.isbank.com.tr") + AUTHORIZE_IBAN: str = os.getenv("AUTHORIZE_IBAN", "4245-0093333") + NO_ATTACHMENT_FOLDER: str = "NoAttachment" + COMPLETED_FOLDER: str = "Completed" + SERVICE_NAME: str = "IsBankEmailService" + TASK_DATA_PREFIX: str = ConfigServices.MAIN_TASK_PREFIX + TASK_MAILID_INDEX_PREFIX: str = ConfigServices.TASK_MAILID_INDEX_PREFIX + TASK_UUID_INDEX_PREFIX: str = ConfigServices.TASK_UUID_INDEX_PREFIX + TASK_SEEN_PREFIX: str = ConfigServices.TASK_SEEN_PREFIX + SERVICE_PREFIX: str = ConfigServices.SERVICE_PREFIX_MAIL_READER + NEXT_SERVICE_PREFIX: str = ConfigServices.SERVICE_PREFIX_MAIL_PARSER + diff --git a/ServicesTask/app/services/mail/IsBank/runner.py b/ServicesTask/app/services/mail/IsBank/runner.py new file mode 100644 index 0000000..70cd87e --- /dev/null +++ b/ServicesTask/app/services/mail/IsBank/runner.py @@ -0,0 +1,29 @@ +import sys + +from time import sleep +from logging import getLogger, basicConfig, INFO, StreamHandler, FileHandler + +from ..mail_handler import EmailReaderService +from .params import IsBankConfig + + +format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' +handlers = [StreamHandler(sys.stdout), FileHandler('isbank_email_service.log')] +basicConfig(level=INFO, format=format, handlers=handlers) +logger = getLogger(IsBankConfig.SERVICE_NAME) + + +def initialize_service(): + """Initialize the service with proper error handling""" + try: + logger.info("Creating EmailReaderService") + email_service = EmailReaderService(IsBankConfig()) + + logger.info("Connecting to email service") + email_service.login_and_connect() + return email_service + except Exception as e: + logger.error(f"Service initialization failed: {str(e)}") + sleep(5) + return initialize_service() + \ No newline at end of file diff --git a/ServicesTask/app/services/mail/config.py b/ServicesTask/app/services/mail/config.py new file mode 100644 index 0000000..a420277 --- /dev/null +++ b/ServicesTask/app/services/mail/config.py @@ -0,0 +1,155 @@ +import os +from re import TEMPLATE +from pydantic import BaseModel +from typing import Any, List, Optional, Union + + +class FromToHeader(BaseModel): + + display_name: Optional[str] + username: Optional[str] + domain: Optional[str] + mail: Optional[str] + + +class MailReader(BaseModel): + + id: str + subject: str + from_: FromToHeader + to: List[FromToHeader] + date: str + body_text: str + + +class MailParser(BaseModel): + + filename: str + content_type: str + charset: str + data: str + +class FinderIban(BaseModel): + + filename: str + iban: str + bank_date: str + channel_branch: str + currency_value: float + balance: float + additional_balance: float + process_name: str + process_type: str + process_comment: str + bank_reference_code: str + + +class FinderComment(FinderIban): + + build_id: Optional[int] = None + build_uu_id: Optional[str] = None + decision_book_id: Optional[int] = None + decision_book_uu_id: Optional[str] = None + + +class RedisData(BaseModel): + MailReader: MailReader + MailParser: List[MailParser] + FinderIban: List[FinderIban] + FinderComment: List[FinderComment] + + +class Status: + PENDING: str = "PENDING" + IN_PROGRESS: str = "IN_PROGRESS" + COMPLETED: str = "COMPLETED" + FAILED: str = "FAILED" + + +class RedisTaskObject(BaseModel): + task: str + data: RedisData + completed: bool + service: str + status: str + created_at: str + is_completed: bool + + +class MailSendModel(BaseModel): + receivers: List[str] + subject: str + template_name: str + data: dict + + +class RedisMailSender(BaseModel): + task: RedisTaskObject + data: MailSendModel + completed: bool + service: str + status: str + created_at: str + completed: bool + + +class EmailConfig: + + HOST: str = os.getenv("EMAIL_HOST", "10.10.2.34") + USERNAME: str = os.getenv("EMAIL_USERNAME", "isbank@mehmetkaratay.com.tr") + PASSWORD: str = os.getenv("EMAIL_PASSWORD", "system") + PORT: int = int(os.getenv("EMAIL_PORT", 993)) + + @classmethod + def as_dict(cls): + return dict(host=EmailConfig.HOST, port=EmailConfig.PORT, username=EmailConfig.USERNAME, password=EmailConfig.PASSWORD) + + +class RedisConfig: + + HOST: str = os.getenv("REDIS_HOST", "10.10.2.15") + PASSWORD: str = os.getenv("REDIS_PASSWORD", "your_strong_password_here") + PORT: int = int(os.getenv("REDIS_PORT", 6379)) + DB: int = int(os.getenv("REDIS_DB", 0)) + + @classmethod + def as_dict(cls): + return dict(host=RedisConfig.HOST, port=int(RedisConfig.PORT), password=RedisConfig.PASSWORD, db=int(RedisConfig.DB)) + + +class MailReaderMainConfig: + + MAILBOX: str + AUTHORIZE_IBAN: str + NO_ATTACHMENT_FOLDER: str + COMPLETED_FOLDER: str + TASK_DATA_PREFIX: str + TASK_MAILID_INDEX_PREFIX: str + TASK_UUID_INDEX_PREFIX: str + TASK_SEEN_PREFIX: str + SERVICE_PREFIX: str + NEXT_SERVICE_PREFIX: str + + +class ConfigServices: + + MAIN_TASK_PREFIX: str = "BANK:SERVICES:TASK:DATA" + + TASK_MAILID_INDEX_PREFIX: str = "BANK:SERVICES:TASK:MAILID" + TASK_UUID_INDEX_PREFIX: str = "BANK:SERVICES:TASK:UUID" + TASK_SEEN_PREFIX: str = "BANK:SERVICES:TASK:SEEN" + TASK_DELETED_PREFIX: str = "BANK:SERVICES:TASK:DELETED" + TASK_COMMENT_PARSER: str = "BANK:SERVICES:TASK:COMMENT:PARSER" + TASK_PREDICT_RESULT: str = "BANK:SERVICES:TASK:COMMENT:RESULT" + + SERVICE_PREFIX_MAIL_READER: str = "MailReader" + SERVICE_PREFIX_MAIL_PARSER: str = "MailParser" + SERVICE_PREFIX_FINDER_IBAN: str = "FinderIban" + SERVICE_PREFIX_FINDER_COMMENT: str = "FinderComment" + SERVICE_PREFIX_MAIL_SENDER: str = "MailSender" + + TEMPLATE_ACCOUNT_RECORDS: str = "template_accounts.html" + + +paramsRedisData = Union[MailReader, MailParser, FinderIban, FinderComment] + diff --git a/ServicesTask/app/services/mail/mail_handler.py b/ServicesTask/app/services/mail/mail_handler.py new file mode 100644 index 0000000..0e24f80 --- /dev/null +++ b/ServicesTask/app/services/mail/mail_handler.py @@ -0,0 +1,381 @@ +import os +import socket +import logging + +from functools import wraps +from base64 import b64encode +from time import sleep +from datetime import datetime +from typing import List, Dict, Any, Union, TypeVar, Tuple + +from email.message import EmailMessage +from email.policy import default as policy +from email.headerregistry import UniqueDateHeader, UniqueAddressHeader, UniqueUnstructuredHeader +from email.parser import BytesParser +from imaplib import IMAP4_SSL, IMAP4 + +from .config import EmailConfig, MailReaderMainConfig + + +logger = logging.getLogger('Email Reader Service') + +T = TypeVar('T') + + +def retry_on_connection_error(max_retries: int = 3, delay: int = 5, backoff: int = 2, exceptions=(Exception,)): + """ + Retry decorator with exponential backoff for handling connection errors + + Args: + max_retries: Maximum number of retries + delay: Initial delay between retries in seconds + backoff: Backoff multiplier + exceptions: Tuple of exceptions to catch + Returns: Decorated function + """ + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + mtries, mdelay = max_retries, delay + while mtries > 0: + try: + return func(*args, **kwargs) + except exceptions as e: + logger.warning(f"Connection error in {func.__name__}: {str(e)}, retrying in {mdelay}s...") + sleep(mdelay) + mtries -= 1 + mdelay *= backoff + return func(*args, **kwargs) + return wrapper + return decorator + + +class Mails: + """Class representing an email with attachments and metadata""" + + def __init__(self, mail_id: bytes, mail_data: bytes): + """ + Initialize a mail object + Args: mail_id: Unique identifier for the email, mail_data: Raw email data + """ + self.id: bytes = mail_id + self.raw_data: bytes = mail_data + self.attachments: List[Dict[str, Union[str, bytes]]] = [] + self.message: EmailMessage = BytesParser(policy=policy).parsebytes(mail_data) + self.subject: UniqueUnstructuredHeader = self.message.get('Subject', '') or '' + self.from_: UniqueAddressHeader = self.message.get('From', '') or '' + self.to: UniqueAddressHeader = self.message.get('To', '') or '' + self.date: UniqueDateHeader = self.message.get('Date', '') or '' + self.body_text: str = self._get_body_text() + self._extract_attachments() + + def to_dict(self) -> Dict[str, Any]: + """ + Convert mail object to dictionary representation + Returns: Dictionary representation of mail + """ + return { + 'id': self.id.decode('utf-8'), + 'attachments': [{ + 'filename': attachment['filename'], 'content_type': attachment['content_type'], 'charset': attachment['charset'], + 'data': b64encode(attachment['data']).decode(attachment['charset'], errors='replace') + } for attachment in self.attachments], + 'subject': str(self.subject), + 'from_': { + "display_name": self.from_.addresses[0].display_name, "username": self.from_.addresses[0].username, + "domain": self.from_.addresses[0].domain, "mail": f"{self.from_.addresses[0].username}@{self.from_.addresses[0].domain}" + }, + 'to': [ + { + "display_name": address.display_name, "username": address.username, "domain": address.domain, + "mail": f"{address.username}@{address.domain}" } for address in self.to.addresses + ], 'date': str(self.date.datetime), 'body_text': str(self.body_text) + } + + def _get_body_text(self) -> str: + """ + Extract plain text body from email + Returns: Plain text body of email + """ + body = self.message.get_body(preferencelist=('plain',)) + if body is not None: + return body.get_content() or '' + if self.message.is_multipart(): + for part in self.message.walk(): + if part.get_content_type() == 'text/plain' and (part.get_content_disposition() or '') != 'attachment': + try: + return part.get_content() or '' + except Exception: + payload = part.get_payload(decode=True) or b'' + return payload.decode(part.get_content_charset() or 'utf-8', errors='replace') + else: + if self.message.get_content_type() == 'text/plain': + try: + return self.message.get_content() or '' + except Exception: + payload = self.message.get_payload(decode=True) or b'' + return payload.decode(self.message.get_content_charset() or 'utf-8', errors='replace') + return '' + + def _extract_attachments(self) -> None: + """Extract attachments from email""" + for part in self.message.walk(): + if part.get_content_disposition() == 'attachment': + filename = part.get_filename() + if not filename: + continue + data = part.get_payload(decode=True) or b'' + charset = part.get_charset() or 'utf-8' + self.attachments.append({'filename': filename, 'content_type': part.get_content_type(), 'data': data, 'charset': charset}) + + def save_attachments(self, folder: str) -> None: + """ + Save attachments to folder + Args: folder: Folder to save attachments to + """ + os.makedirs(folder, exist_ok=True) + for att in self.attachments: + with open(os.path.join(folder, att['filename']), 'wb') as f: + f.write(att['data']) + + +class EmailReaderService: + + """Service for reading emails from mailbox with improved connection resilience""" + + def __init__(self, config: MailReaderMainConfig): + """ + Initialize email reader service + Args: config: Application configuration + """ + self.email_config = EmailConfig() + self.config = config + self.mail = None + self.data: List[Mails] = [] + self.mail_count = 0 + self.is_connected = False + self.connect_imap() + + def connect_imap(self) -> bool: + """ + Establish IMAP connection with retry mechanism + Returns: True if connection successful, False otherwise + """ + try: + if self.mail: + try: + self.mail.close() + self.mail.logout() + except Exception: + pass + logger.info(f"Connecting to IMAP server {self.email_config.HOST}:{self.email_config.PORT}") + self.mail = IMAP4_SSL(self.email_config.HOST, self.email_config.PORT) + self.is_connected = True + return True + except (socket.error, IMAP4.error) as e: + logger.error(f"Failed to connect to IMAP server: {str(e)}") + self.is_connected = False + return False + + @retry_on_connection_error(max_retries=3, delay=5, exceptions=(socket.error, IMAP4.error, OSError)) + def login_and_connect(self) -> bool: + """ + Login to IMAP server and connect to inbox with retry mechanism + Returns: True if login successful, False otherwise + Raises: ConnectionError: If connection cannot be established + """ + if not self.is_connected: + if not self.connect_imap(): + raise ConnectionError("Cannot establish connection to IMAP server") + + try: + logger.info(f"Logging in as {self.email_config.USERNAME}") + self.mail.login(self.email_config.USERNAME, self.email_config.PASSWORD) + self._connect_inbox() + logger.info("Successfully logged in and connected to inbox") + return True + except (socket.error, IMAP4.error) as e: + logger.error(f"Login failed: {str(e)}") + self.is_connected = False + raise + + @retry_on_connection_error(max_retries=2, delay=3, exceptions=(socket.error, IMAP4.error, OSError)) + def refresh(self) -> Tuple[List[Mails], int, int]: + """ + Refresh mail data with connection retry + Returns: Tuple of (mail data, mail count, data length) + """ + try: + self.mail_count = self._fetch_count() + self.data = self._fetch_all() + return self.data, self.mail_count, len(self.data) + except (socket.error, IMAP4.error) as e: + logger.error(f"Refresh failed, attempting to reconnect: {str(e)}") + self.connect_imap() + self.login_and_connect() + self.mail_count = self._fetch_count() + self.data = self._fetch_all() + return self.data, self.mail_count, len(self.data) + + @retry_on_connection_error(max_retries=2, delay=2, exceptions=(socket.error, IMAP4.error)) + def _connect_inbox(self) -> None: + """ + Connect to INBOX with retry mechanism + Raises: IMAP4.error: If connection to INBOX fails + """ + logger.info("Selecting INBOX folder") + status, _ = self.mail.select("INBOX") + if status != 'OK': + error_msg = "Failed to connect to INBOX" + logger.error(error_msg) + raise IMAP4.error(error_msg) + + @retry_on_connection_error(max_retries=2, delay=2, exceptions=(socket.error, IMAP4.error)) + def _fetch_count(self) -> int: + """ + Fetch mail count with retry mechanism + Returns: Number of emails + Raises: IMAP4.error: If fetching mail count fails + """ + try: + status, uids = self.mail.uid('SORT', '(REVERSE DATE)', 'UTF-8', 'ALL', 'FROM', f'"{self.config.MAILBOX}"') + if status != 'OK': + raise IMAP4.error("Failed to get mail count") + count = len(uids[0].split()) if uids[0] else 0 + logger.info(f"Found {count} emails from {self.config.MAILBOX}") + return count + except (socket.error, IMAP4.error) as e: + logger.error(f"Error fetching mail count: {str(e)}") + raise + + @retry_on_connection_error(max_retries=2, delay=2, exceptions=(socket.error, IMAP4.error)) + def _fetch_all(self) -> List[Mails]: + """ + Fetch all mails with retry mechanism + Returns: List of mail objects + Raises: IMAP4.error: If fetching mails fails + """ + self.data = [] + try: + status, uids = self.mail.uid('SORT', '(REVERSE DATE)', 'UTF-8', 'ALL', 'FROM', f'"{self.config.MAILBOX}"') + if status != 'OK': + raise IMAP4.error("Mail search failed") + if not uids[0]: + logger.info("No emails found matching criteria") + return self.data + uid_list = uids[0].split() + logger.info(f"Processing {len(uid_list)} emails") + for uid in uid_list: + try: + status, msg_data = self.mail.uid('fetch', uid, '(RFC822)') + if status == 'OK' and msg_data[0] is not None: + self.data.append(Mails(uid, msg_data[0][1])) + except Exception as e: + logger.warning(f"Failed to fetch email with UID {uid}: {str(e)}") + continue + logger.info(f"Successfully fetched {len(self.data)} emails") + return self.data + except (socket.error, IMAP4.error) as e: + logger.error(f"Error fetching emails: {str(e)}") + raise + + @retry_on_connection_error(max_retries=2, delay=1, exceptions=(socket.error, IMAP4.error)) + def move_to_folder(self, uid: Union[str, bytes], folder: str): + """ + Move message to folder with retry mechanism + Args: uid: Email UID, folder: Destination folder + """ + try: + log_uid = uid + if isinstance(uid, bytes): + log_uid = uid.decode('utf-8', errors='replace') + elif isinstance(uid, str): + uid = uid.encode('utf-8') + logger.info(f"Moving email {log_uid} to {folder} folder") + self.mail.uid('MOVE', uid, folder) + self.commit() + return True + except Exception as e: + logger.error(f"Failed to move email to folder: {str(e)}") + return False + + @retry_on_connection_error(max_retries=2, delay=1, exceptions=(socket.error, IMAP4.error)) + def copy_to_folder(self, uid: Union[str, bytes], folder: str): + """ + Copy message to folder with retry mechanism + Args: uid: Email UID, folder: Destination folder + """ + try: + log_uid = uid + if isinstance(uid, bytes): + log_uid = uid.decode('utf-8', errors='replace') + elif isinstance(uid, str): + uid = uid.encode('utf-8') + logger.info(f"Copying email {log_uid} to {folder} folder") + self.mail.uid('COPY', uid, folder) + self.commit() + return True + except Exception as e: + logger.error(f"Failed to copy email to folder: {str(e)}") + return False + + @retry_on_connection_error(max_retries=2, delay=1, exceptions=(socket.error, IMAP4.error)) + def mark_no_attachment(self, uid: Union[str, bytes]): + """ + Move message to no attachment folder with retry mechanism + Args: uid: Email UID + """ + self.move_to_folder(uid, self.config.NO_ATTACHMENT_FOLDER) + + @retry_on_connection_error(max_retries=2, delay=1, exceptions=(socket.error, IMAP4.error)) + def mark_completed(self, uid: Union[str, bytes]): + """ + Move message to completed folder with retry mechanism + Args: uid: Email UID + """ + self.move_to_folder(uid, self.config.COMPLETED_FOLDER) + + @retry_on_connection_error(max_retries=2, delay=1, exceptions=(socket.error, IMAP4.error)) + def delete(self, uid): + """ + Delete message with retry mechanism + Args: uid: Email UID + """ + try: + log_uid = uid + if isinstance(uid, bytes): + log_uid = uid.decode('utf-8', errors='replace') + logger.info(f"Marking email {log_uid} for deletion") + self.mail.uid('STORE', uid, '+FLAGS', r'(\Deleted)') + except Exception as e: + logger.error(f"Failed to delete email: {str(e)}") + raise + + @retry_on_connection_error(max_retries=2, delay=1, exceptions=(socket.error, IMAP4.error)) + def commit(self): + """ + Commit pending operations with retry mechanism + Raises: Exception: If commit fails + """ + try: + logger.info("Committing changes (expunge)") + self.mail.expunge() + except Exception as e: + logger.error(f"Failed to commit changes: {str(e)}") + raise + + def logout(self): + """Logout from IMAP server""" + if self.mail and self.is_connected: + try: + logger.info("Logging out from IMAP server") + self.mail.close() + self.mail.logout() + self.is_connected = False + except Exception as e: + logger.warning(f"Logout failed: {str(e)}") + + @property + def count(self): + """Get count of emails""" + return len(self.data) diff --git a/ServicesTask/app/services/mail/main.py b/ServicesTask/app/services/mail/main.py index 31b252b..093b970 100644 --- a/ServicesTask/app/services/mail/main.py +++ b/ServicesTask/app/services/mail/main.py @@ -1,29 +1,104 @@ import os -import uuid import asyncio +from typing import List +from app.services.mail.IsBank.runner import initialize_service from app.services.common.service_base_async import ServiceBaseAsync - -PRODUCE_ENABLED = os.getenv("PRODUCE_ENABLED", "true").lower() == "true" -PRODUCE_BATCH = int(os.getenv("PRODUCE_BATCH", "3")) # her produce tick'inde kaç iş -TASK_TYPE = os.getenv("TASK_TYPE", "db-task") # iş tipi (task_id'de de kullanılır) -CONSUME_SLEEP_SEC = float(os.getenv("CONSUME_SLEEP_SEC", "0.5")) # işleme süresi simülasyonu (sn) -STATIC_IDS = ["2c47f1073a9d4f05aad6c15484894a74", "65827e3452b545d6845e050a503401f4", "5c663088f09d4062b4e567f47335fb1e"] +from .mail_handler import Mails +from .IsBank.params import IsBankConfig -async def produce(service: ServiceBaseAsync): - for biz_id in STATIC_IDS: - deterministic_task_id = f"{TASK_TYPE}:{biz_id}" - payload = {"id": biz_id, "op": "sync", "source": "db-service"} - await service.enqueue(payload, TASK_TYPE, task_id=deterministic_task_id) - print(f"[DB] produce tick attempted ids={','.join(STATIC_IDS)}") +PRODUCE_BURST = int(os.getenv("PRODUCE_BURST", "10")) +PRODUCE_ONCE = os.getenv("PRODUCE_ONCE", "true").lower() == "true" +EVENT_TYPE = os.getenv("EVENT_TYPE", "db-event") + +_produced = False +PROCESS_SEC = 10 +email_service = initialize_service() -async def consume(service: ServiceBaseAsync, job: dict): - await asyncio.sleep(CONSUME_SLEEP_SEC) - print(f"[DB] consumed task={job['task_id']} attempts={job.get('_attempts', 0)}") +def generate_unique_with_mail_id(mail_id: str, service_prefix: str): + return f"{service_prefix}_{mail_id}" + + +def process_mail_with_attachments(mail: Mails, mail_id: str): + """ + Process an email with attachments using MailReaderService + Args: mail: Mail object, mail_id: Mail ID + Raises: Exception: If processing mail fails + """ + try: + mail_to_dict = mail.to_dict() + task_uuid = generate_unique_with_mail_id(mail_id, IsBankConfig.SERVICE_NAME) + process_mail_dict = dict(mail_id=mail_id, mail_data=mail_to_dict, service_prefix=email_service.config.SERVICE_PREFIX) + return task_uuid, process_mail_dict + except Exception as e: + print(f"Email Service Runner Error processing mail {mail_id}: {str(e)}") + raise + + +def drop(): + """Clean up resources""" + try: + email_service.commit() + except Exception as e: + print(f"Error during commit on drop: {str(e)}") + try: + email_service.logout() + except Exception as e: + print(f"Error during logout on drop: {str(e)}") + + +async def produce(svc: ServiceBaseAsync): + mails, count, length = email_service.refresh() + for mail in mails: + if not getattr(mail, 'id', None): + print("Skipping email with no ID") + continue + mail_id, mail_dict = mail.id.decode('utf-8'), mail.to_dict() + try: + if mail.attachments: + if any([str(attachment['filename']).lower().endswith('.pdf') for attachment in mail_dict['attachments']]): + email_service.mark_no_attachment(mail_id) + else: + task_uuid, process_mail_dict = process_mail_with_attachments(mail, mail_id) + await svc.enqueue(task_id=task_uuid, payload=process_mail_dict, type_="mail.service.isbank") + else: + email_service.mark_no_attachment(mail_id) + except Exception as e: + print(f"Error processing email {mail_id}: {str(e)}") + continue + await asyncio.sleep(PROCESS_SEC) + + +async def handle_from_parser(svc: ServiceBaseAsync, job): + print("Mail Consumer from parser:", job) + await asyncio.sleep(PROCESS_SEC) + return + + +async def handle_database_publish(svc: ServiceBaseAsync, job): + await asyncio.sleep(PROCESS_SEC) + print("Mail Consumer from database:", job) + return + + +async def handle_from_mail(svc: ServiceBaseAsync, job): + await asyncio.sleep(PROCESS_SEC) + print("Mail Consumer from mail:", job) + return + + +async def consume_default(svc, job): + await asyncio.sleep(PROCESS_SEC) + print("Mail Consumer default:", job) + return if __name__ == "__main__": - asyncio.run(ServiceBaseAsync(produce, consume).run()) + + svc = ServiceBaseAsync(produce, consume_default, + handlers={"parser.publish": handle_from_parser, "mail.publish": handle_from_mail, "database.publish": handle_database_publish} + ) + asyncio.run(svc.run()) diff --git a/ServicesTask/app/services/mail/pyproject.toml b/ServicesTask/app/services/mail/pyproject.toml index cfa5c84..a4550e9 100644 --- a/ServicesTask/app/services/mail/pyproject.toml +++ b/ServicesTask/app/services/mail/pyproject.toml @@ -11,9 +11,15 @@ requires-python = ">=3.11" authors = [ { name = "Berkay Karatay", email = "karatay.berkay@gmail.com" } ] + dependencies = [ - "redis>=5.0.0", - "aiosqlite>=0.19.0", + "aio-pika>=9.4.1", + "prometheus-client>=0.20.0", + "uvloop>=0.19.0", + "arrow>=1.3.0", + "pydantic>=2.0.0", + "pydantic-settings>=2.0.0", + "email-validator>=2.0.0", ] [project.optional-dependencies] diff --git a/ServicesTask/app/services/queue/Dockerfile b/ServicesTask/app/services/mongo/Dockerfile similarity index 60% rename from ServicesTask/app/services/queue/Dockerfile rename to ServicesTask/app/services/mongo/Dockerfile index b7fe2e4..2240f58 100644 --- a/ServicesTask/app/services/queue/Dockerfile +++ b/ServicesTask/app/services/mongo/Dockerfile @@ -5,14 +5,14 @@ ENV PYTHONPATH=/app WORKDIR / -COPY app/services/queue/pyproject.toml ./ -COPY app/services/queue/README.md ./ +COPY app/services/mongo/pyproject.toml ./ +COPY app/services/mongo/README.md ./ COPY app/core ./app/core COPY app/services/common/ ./app/services/common/ -COPY app/services/queue/ ./app/services/queue/ +COPY app/services/mongo/ ./app/services/mongo/ RUN pip install --upgrade pip && pip install --no-cache-dir . RUN mkdir -p /app/data -CMD ["python", "-m", "app.services.queue.main"] +CMD ["python", "-m", "app.services.mongo.main"] diff --git a/ServicesTask/app/services/queue/README.md b/ServicesTask/app/services/mongo/README.md similarity index 100% rename from ServicesTask/app/services/queue/README.md rename to ServicesTask/app/services/mongo/README.md diff --git a/ServicesTask/app/services/queue/__init__.py b/ServicesTask/app/services/mongo/__init__.py similarity index 100% rename from ServicesTask/app/services/queue/__init__.py rename to ServicesTask/app/services/mongo/__init__.py diff --git a/ServicesTask/app/services/mongo/main.py b/ServicesTask/app/services/mongo/main.py new file mode 100644 index 0000000..96be00e --- /dev/null +++ b/ServicesTask/app/services/mongo/main.py @@ -0,0 +1,40 @@ +import os +import uuid +import asyncio + +from app.services.common.service_base_async import ServiceBaseAsync + + +PRODUCE_BURST = int(os.getenv("PRODUCE_BURST", "10")) +PRODUCE_ONCE = os.getenv("PRODUCE_ONCE", "true").lower() == "true" +EVENT_TYPE = os.getenv("EVENT_TYPE", "db-mongo") +PROCESS_SEC = 10 + + +async def produce(svc: ServiceBaseAsync): + await asyncio.sleep(PROCESS_SEC) + print(f"Produced From Mongo Producer: {len([1,2])} events to '{svc.produce_key}'") + + +async def handle_db_publish(svc: ServiceBaseAsync, job): + await asyncio.sleep(PROCESS_SEC) + await svc.ack_current() + print("Mongo Consumer from db:", job["task_id"]) + + +async def handle_mail_publish(svc: ServiceBaseAsync, job): + await asyncio.sleep(PROCESS_SEC) + await svc.ack_current() + print("Mongo Consumer from mail:", job["task_id"]) + + +async def consume_default(svc, job): + await asyncio.sleep(PROCESS_SEC) + print("Mongo Consumer default:", job["task_id"]) + return + + +if __name__ == "__main__": + + svc = ServiceBaseAsync(produce_fn=produce, consume_fn=consume_default, handlers={"database.service.publish": handle_db_publish, "mail.service.publish": handle_mail_publish}) + asyncio.run(svc.run()) diff --git a/ServicesTask/app/services/queue/pyproject.toml b/ServicesTask/app/services/mongo/pyproject.toml similarity index 89% rename from ServicesTask/app/services/queue/pyproject.toml rename to ServicesTask/app/services/mongo/pyproject.toml index cfa5c84..82dd953 100644 --- a/ServicesTask/app/services/queue/pyproject.toml +++ b/ServicesTask/app/services/mongo/pyproject.toml @@ -11,9 +11,11 @@ requires-python = ">=3.11" authors = [ { name = "Berkay Karatay", email = "karatay.berkay@gmail.com" } ] + dependencies = [ - "redis>=5.0.0", - "aiosqlite>=0.19.0", + "aio-pika>=9.4.1", + "prometheus-client>=0.20.0", + "uvloop>=0.19.0" ] [project.optional-dependencies] diff --git a/ServicesTask/app/services/queue/queue_service_async.py b/ServicesTask/app/services/mongo/queue_service_async.py similarity index 100% rename from ServicesTask/app/services/queue/queue_service_async.py rename to ServicesTask/app/services/mongo/queue_service_async.py diff --git a/ServicesTask/app/services/parser/a.txt b/ServicesTask/app/services/parser/a.txt new file mode 100644 index 0000000..e69de29 diff --git a/ServicesTask/app/services/parser/comment/Dockerfile b/ServicesTask/app/services/parser/comment/Dockerfile new file mode 100644 index 0000000..6e96476 --- /dev/null +++ b/ServicesTask/app/services/parser/comment/Dockerfile @@ -0,0 +1,18 @@ +FROM python:3.12-slim + +ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 +ENV PYTHONPATH=/app + +WORKDIR / + +COPY app/services/parser/comment/pyproject.toml ./ +COPY app/services/parser/comment/README.md ./ + +COPY app/core ./app/core +COPY app/services/common/ ./app/services/common/ +COPY app/services/parser/comment/ ./app/services/parser/comment/ + +RUN pip install --upgrade pip && pip install --no-cache-dir . +RUN mkdir -p /app/data + +CMD ["python", "-m", "app.services.parser.comment.main"] diff --git a/ServicesTask/app/services/parser/comment/README.md b/ServicesTask/app/services/parser/comment/README.md new file mode 100644 index 0000000..e69de29 diff --git a/ServicesTask/app/services/parser/comment/main.py b/ServicesTask/app/services/parser/comment/main.py new file mode 100644 index 0000000..7ec8834 --- /dev/null +++ b/ServicesTask/app/services/parser/comment/main.py @@ -0,0 +1,30 @@ +import asyncio + +from app.services.common.service_base_async import ServiceBaseAsync + + +PROCESS_SEC = 10 + + +async def handle_mail_publish(svc: ServiceBaseAsync, job: dict): + await asyncio.sleep(PROCESS_SEC) + print("Parser Mail Consumer parsed:", job) + # await svc.ack_current() + # await svc.enqueue({"source": "parser-mail", "from_task": job}, "parser-mail-done", routing_key="parser.comment.publish") + + +async def consume_default(svc: ServiceBaseAsync, job): + print("Parser Mail Consumer default:", job) + await asyncio.sleep(PROCESS_SEC) + await svc.ack_current() + + +async def produce(_svc: ServiceBaseAsync): + print("Parser Mail Producer produce") + await asyncio.sleep(PROCESS_SEC) + + +if __name__ == "__main__": + + svc = ServiceBaseAsync(produce_fn=produce, consume_fn=consume_default, handlers={"mail.service.publish": handle_mail_publish}) + asyncio.run(svc.run()) diff --git a/ServicesTask/app/services/parser/comment/pyproject.toml b/ServicesTask/app/services/parser/comment/pyproject.toml new file mode 100644 index 0000000..82dd953 --- /dev/null +++ b/ServicesTask/app/services/parser/comment/pyproject.toml @@ -0,0 +1,37 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "dual-queue-services" +version = "0.1.0" +description = "Async dual queue system with Redis Streams and SQLite persistence" +readme = "README.md" +requires-python = ">=3.11" +authors = [ + { name = "Berkay Karatay", email = "karatay.berkay@gmail.com" } +] + +dependencies = [ + "aio-pika>=9.4.1", + "prometheus-client>=0.20.0", + "uvloop>=0.19.0" +] + +[project.optional-dependencies] +dev = [ + "pytest>=7.4", + "black>=23.0", + "isort>=5.12" +] + +[tool.black] +line-length = 88 +target-version = ["py311"] + +[tool.isort] +profile = "black" + +[tool.setuptools.packages.find] +where = ["app"] +include = ["app*"] diff --git a/ServicesTask/app/services/parser/excel/Dockerfile b/ServicesTask/app/services/parser/excel/Dockerfile new file mode 100644 index 0000000..71725b2 --- /dev/null +++ b/ServicesTask/app/services/parser/excel/Dockerfile @@ -0,0 +1,18 @@ +FROM python:3.12-slim + +ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 +ENV PYTHONPATH=/app + +WORKDIR / + +COPY app/services/parser/excel/pyproject.toml ./ +COPY app/services/parser/excel/README.md ./ + +COPY app/core ./app/core +COPY app/services/common/ ./app/services/common/ +COPY app/services/parser/excel/ ./app/services/parser/excel/ + +RUN pip install --upgrade pip && pip install --no-cache-dir . +RUN mkdir -p /app/data + +CMD ["python", "-m", "app.services.parser.excel.main"] diff --git a/ServicesTask/app/services/parser/excel/README.md b/ServicesTask/app/services/parser/excel/README.md new file mode 100644 index 0000000..e69de29 diff --git a/ServicesTask/app/services/parser/excel/main.py b/ServicesTask/app/services/parser/excel/main.py new file mode 100644 index 0000000..31fa326 --- /dev/null +++ b/ServicesTask/app/services/parser/excel/main.py @@ -0,0 +1,40 @@ +import os +import uuid +import asyncio + +from app.services.common.service_base_async import ServiceBaseAsync + + +PRODUCE_BURST = int(os.getenv("PRODUCE_BURST", "10")) +PRODUCE_ONCE = os.getenv("PRODUCE_ONCE", "true").lower() == "true" +EVENT_TYPE = os.getenv("EVENT_TYPE", "db-mongo") +PROCESS_SEC = 10 + + +async def produce(svc: ServiceBaseAsync): + await asyncio.sleep(PROCESS_SEC) + print(f"Parser Excel Producer produced {len([1,2])} events to '{svc.produce_key}'") + + +async def handle_from_parser(svc: ServiceBaseAsync, job): + print("Parser Excel Consumer from parser:", job) + await svc.ack_current() + return + + +async def handle_from_mail(svc: ServiceBaseAsync, job): + print("Parser Excel Consumer from mail:", job) + await svc.ack_current() + return + + +async def consume_default(svc, job): + print("Parser Excel Consumer default:", job) + await svc.ack_current() + return + + +if __name__ == "__main__": + + svc = ServiceBaseAsync(produce_fn=produce, consume_fn=consume_default, handlers={"parser.publish": handle_from_parser, "mail.publish": handle_from_mail}) + asyncio.run(svc.run()) diff --git a/ServicesTask/app/services/parser/excel/pyproject.toml b/ServicesTask/app/services/parser/excel/pyproject.toml new file mode 100644 index 0000000..82dd953 --- /dev/null +++ b/ServicesTask/app/services/parser/excel/pyproject.toml @@ -0,0 +1,37 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "dual-queue-services" +version = "0.1.0" +description = "Async dual queue system with Redis Streams and SQLite persistence" +readme = "README.md" +requires-python = ">=3.11" +authors = [ + { name = "Berkay Karatay", email = "karatay.berkay@gmail.com" } +] + +dependencies = [ + "aio-pika>=9.4.1", + "prometheus-client>=0.20.0", + "uvloop>=0.19.0" +] + +[project.optional-dependencies] +dev = [ + "pytest>=7.4", + "black>=23.0", + "isort>=5.12" +] + +[tool.black] +line-length = 88 +target-version = ["py311"] + +[tool.isort] +profile = "black" + +[tool.setuptools.packages.find] +where = ["app"] +include = ["app*"] diff --git a/ServicesTask/app/services/parser/mail/Dockerfile b/ServicesTask/app/services/parser/mail/Dockerfile new file mode 100644 index 0000000..8a72a91 --- /dev/null +++ b/ServicesTask/app/services/parser/mail/Dockerfile @@ -0,0 +1,18 @@ +FROM python:3.12-slim + +ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 +ENV PYTHONPATH=/app + +WORKDIR / + +COPY app/services/parser/mail/pyproject.toml ./ +COPY app/services/parser/mail/README.md ./ + +COPY app/core ./app/core +COPY app/services/common/ ./app/services/common/ +COPY app/services/parser/mail/ ./app/services/parser/mail/ + +RUN pip install --upgrade pip && pip install --no-cache-dir . +RUN mkdir -p /app/data + +CMD ["python", "-m", "app.services.parser.mail.main"] diff --git a/ServicesTask/app/services/parser/mail/README.md b/ServicesTask/app/services/parser/mail/README.md new file mode 100644 index 0000000..e69de29 diff --git a/ServicesTask/app/services/parser/mail/main.py b/ServicesTask/app/services/parser/mail/main.py new file mode 100644 index 0000000..74dc40f --- /dev/null +++ b/ServicesTask/app/services/parser/mail/main.py @@ -0,0 +1,42 @@ +import os +import asyncio + +from app.services.common.service_base_async import ServiceBaseAsync + + +PRODUCE_BURST = int(os.getenv("PRODUCE_BURST", "10")) +PRODUCE_ONCE = os.getenv("PRODUCE_ONCE", "true").lower() == "true" +EVENT_TYPE = os.getenv("EVENT_TYPE", "db-mongo") +PROCESS_SEC = 10 + + +async def produce(svc: ServiceBaseAsync): + await asyncio.sleep(PROCESS_SEC) + print(f"Parser Mail Producer produced {len([1,2])} events to '{svc.produce_key}'") + + +async def handle_db_publish(svc: ServiceBaseAsync, job): + await asyncio.sleep(PROCESS_SEC) + await svc.ack_current() + print("Parser Mail Consumer from db:", job) + + +async def handle_mongo_publish(svc: ServiceBaseAsync, job): + await asyncio.sleep(PROCESS_SEC) + await svc.ack_current() + print("Parser Mail Consumer from mongo:", job) + + +async def consume_default(svc: ServiceBaseAsync, job): + await asyncio.sleep(PROCESS_SEC) + print("Parser Mail Consumer default:", job) + return + + +if __name__ == "__main__": + + svc = ServiceBaseAsync( + produce_fn=produce, consume_fn=consume_default, + handlers={"database.service.publish": handle_db_publish, "mongo.service.publish": handle_mongo_publish}, + ) + asyncio.run(svc.run()) diff --git a/ServicesTask/app/services/parser/mail/pyproject.toml b/ServicesTask/app/services/parser/mail/pyproject.toml new file mode 100644 index 0000000..82dd953 --- /dev/null +++ b/ServicesTask/app/services/parser/mail/pyproject.toml @@ -0,0 +1,37 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "dual-queue-services" +version = "0.1.0" +description = "Async dual queue system with Redis Streams and SQLite persistence" +readme = "README.md" +requires-python = ">=3.11" +authors = [ + { name = "Berkay Karatay", email = "karatay.berkay@gmail.com" } +] + +dependencies = [ + "aio-pika>=9.4.1", + "prometheus-client>=0.20.0", + "uvloop>=0.19.0" +] + +[project.optional-dependencies] +dev = [ + "pytest>=7.4", + "black>=23.0", + "isort>=5.12" +] + +[tool.black] +line-length = 88 +target-version = ["py311"] + +[tool.isort] +profile = "black" + +[tool.setuptools.packages.find] +where = ["app"] +include = ["app*"] diff --git a/ServicesTask/app/services/parser/payment/Dockerfile b/ServicesTask/app/services/parser/payment/Dockerfile new file mode 100644 index 0000000..fe10af4 --- /dev/null +++ b/ServicesTask/app/services/parser/payment/Dockerfile @@ -0,0 +1,18 @@ +FROM python:3.12-slim + +ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 +ENV PYTHONPATH=/app + +WORKDIR / + +COPY app/services/parser/payment/pyproject.toml ./ +COPY app/services/parser/payment/README.md ./ + +COPY app/core ./app/core +COPY app/services/common/ ./app/services/common/ +COPY app/services/parser/payment/ ./app/services/parser/payment/ + +RUN pip install --upgrade pip && pip install --no-cache-dir . +RUN mkdir -p /app/data + +CMD ["python", "-m", "app.services.parser.payment.main"] diff --git a/ServicesTask/app/services/parser/payment/README.md b/ServicesTask/app/services/parser/payment/README.md new file mode 100644 index 0000000..e69de29 diff --git a/ServicesTask/app/services/parser/payment/main.py b/ServicesTask/app/services/parser/payment/main.py new file mode 100644 index 0000000..e9e01f0 --- /dev/null +++ b/ServicesTask/app/services/parser/payment/main.py @@ -0,0 +1,43 @@ +import os +import asyncio + +from app.services.common.service_base_async import ServiceBaseAsync + + +PRODUCE_BURST = int(os.getenv("PRODUCE_BURST", "10")) +PRODUCE_ONCE = os.getenv("PRODUCE_ONCE", "true").lower() == "true" +EVENT_TYPE = os.getenv("EVENT_TYPE", "db-mongo") + +PROCESS_SEC = 10 + + +async def produce(svc: ServiceBaseAsync): + await asyncio.sleep(PROCESS_SEC) + print(f"Parser Payment Producer produced {len([1,2])} events to '{svc.produce_key}'") + + +async def handle_from_parser(svc: ServiceBaseAsync, job): + await asyncio.sleep(PROCESS_SEC) + print("Parser Payment Consumer from parser:", job) + await svc.ack_current() + return + + +async def handle_from_mail(svc: ServiceBaseAsync, job): + await asyncio.sleep(PROCESS_SEC) + print("Parser Payment Consumer from mail:", job) + await svc.ack_current() + return + + +async def consume_default(svc: ServiceBaseAsync, job): + await asyncio.sleep(PROCESS_SEC) + print("Parser Payment Consumer default:", job) + await svc.ack_current() + return + + +if __name__ == "__main__": + + svc = ServiceBaseAsync(produce_fn=produce, consume_fn=consume_default, handlers={"parser.publish": handle_from_parser, "mail.publish": handle_from_mail}) + asyncio.run(svc.run()) diff --git a/ServicesTask/app/services/parser/payment/pyproject.toml b/ServicesTask/app/services/parser/payment/pyproject.toml new file mode 100644 index 0000000..82dd953 --- /dev/null +++ b/ServicesTask/app/services/parser/payment/pyproject.toml @@ -0,0 +1,37 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "dual-queue-services" +version = "0.1.0" +description = "Async dual queue system with Redis Streams and SQLite persistence" +readme = "README.md" +requires-python = ">=3.11" +authors = [ + { name = "Berkay Karatay", email = "karatay.berkay@gmail.com" } +] + +dependencies = [ + "aio-pika>=9.4.1", + "prometheus-client>=0.20.0", + "uvloop>=0.19.0" +] + +[project.optional-dependencies] +dev = [ + "pytest>=7.4", + "black>=23.0", + "isort>=5.12" +] + +[tool.black] +line-length = 88 +target-version = ["py311"] + +[tool.isort] +profile = "black" + +[tool.setuptools.packages.find] +where = ["app"] +include = ["app*"] diff --git a/ServicesTask/app/services/queue/main.py b/ServicesTask/app/services/queue/main.py deleted file mode 100644 index 2b83cf8..0000000 --- a/ServicesTask/app/services/queue/main.py +++ /dev/null @@ -1,17 +0,0 @@ -import uuid -import asyncio - -from app.services.common.service_base_async import ServiceBaseAsync - -async def produce(service: ServiceBaseAsync): - print(f"Queue Reader Service up and running.") - while True: - await asyncio.sleep(1) - -async def consume(service: ServiceBaseAsync, job: dict): - await asyncio.sleep(0.1) - print(f"Queue Sender Service up and running. Job: {job}") - - -if __name__ == "__main__": - asyncio.run(ServiceBaseAsync(produce, consume).run()) diff --git a/ServicesTask/docker-compose.yml b/ServicesTask/docker-compose.yml index 2e0019b..9216d0d 100644 --- a/ServicesTask/docker-compose.yml +++ b/ServicesTask/docker-compose.yml @@ -7,40 +7,41 @@ volumes: sqlite_data: prom_data: grafana_data: - nats_data: - nui_data: + rabbitmq_data: services: - nats: - image: nats:latest - command: ["-js", "-m", "8222"] - ports: - - "4222:4222" - - "8222:8222" - volumes: - - ./app/core/nats/nats.conf:/etc/nats/nats.conf:ro - - nats_data:/data/jetstream - networks: [servicesNetwork] - restart: unless-stopped - nats-exporter: - image: natsio/prometheus-nats-exporter:latest - command: - - "-varz" - - "-connz" - - "-subz" - - "-routez" - - "-jsz=all" - - "http://nats:8222" - depends_on: [nats] - expose: - - "7777" + rabbitmq: + image: rabbitmq:3.13-management + container_name: rabbitmq + ports: + - "127.0.0.1:5672:5672" + - "127.0.0.1:15672:15672" + - "127.0.0.1:15692:15692" + environment: + RABBITMQ_DEFAULT_USER: admin + RABBITMQ_DEFAULT_PASS: admin + command: > + sh -lc "rabbitmq-plugins enable --offline rabbitmq_prometheus && exec docker-entrypoint.sh rabbitmq-server" + healthcheck: + test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"] + interval: 5s + timeout: 3s + retries: 20 + start_period: 10s + volumes: + - rabbitmq_data:/var/lib/rabbitmq networks: [servicesNetwork] restart: unless-stopped + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" prometheus: image: prom/prometheus:latest - depends_on: [nats-exporter] + depends_on: [rabbitmq] networks: [servicesNetwork] volumes: - ./monitor/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro @@ -52,6 +53,11 @@ services: ports: - "9090:9090" restart: unless-stopped + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" grafana: image: grafana/grafana:latest @@ -67,104 +73,199 @@ services: ports: - "3000:3000" restart: unless-stopped + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" - nats-ui: - image: ghcr.io/nats-nui/nui:latest - ports: - - "127.0.0.1:31311:31311" + mongo-service: + build: + context: . + dockerfile: app/services/mongo/Dockerfile + depends_on: + rabbitmq: + condition: service_healthy + env_file: [.env] + environment: + SERVICE_NAME: "mongo-service" + PRODUCE_KEY: "mongo.service.publish" + CONSUME_BINDINGS: "database.service.publish,mail.service.publish" + RABBITMQ_URL: "amqp://admin:admin@rabbitmq:5672/" + EXCHANGE_EVENTS: "app.events" + PRODUCE_BURST: "10" + PRODUCE_ONCE: "true" + EVENT_TYPE: "mongo-event" + RETRY_DELAY_MS: "5000" + MAX_RETRIES: "3" + PREFETCH: "16" + IGNORE_SELF_PRODUCED: "true" networks: [servicesNetwork] - volumes: - - nui_data:/db restart: unless-stopped + logging: + driver: "json-file" + options: { max-size: "10m", max-file: "3" } db-service: build: context: . dockerfile: app/services/database/Dockerfile - depends_on: [nats] + depends_on: + rabbitmq: + condition: service_healthy networks: [servicesNetwork] env_file: [.env] environment: - NATS_URL: "nats://nats:4222" - JS_STREAM: "ACCOUNT_SERVICES_DATABASE" - JS_TASKS_SUBJECT: "ACCOUNT.SERVICES.DATABASE.TASKS" - JS_PUBLISH_SUBJECT: "ACCOUNT.SERVICES.DATABASE.PUBLISH" - JS_DURABLE: "DB_WORKERS" - BATCH_SIZE: "5" - ACK_WAIT_SEC: "30" - MAX_DELIVER: "3" - SQLITE_PATH: "/app/data/queue.db" - TASK_TYPE: "db-task" - CONSUME_SLEEP_SEC: "0.5" - SERVICE_NAME: "db-service" - METRICS_PORT: "8000" + SERVICE_NAME: "database-service" + PRODUCE_KEY: "database.service.publish" + CONSUME_BINDINGS: "mail.service.publish,mongo.service.publish" + RABBITMQ_URL: amqp://admin:admin@rabbitmq:5672/ + EXCHANGE_EVENTS: "app.events" + PRODUCE_ONCE: "true" + RETRY_DELAY_MS: "5000" + MAX_RETRIES: "3" + PREFETCH: "16" + IGNORE_SELF_PRODUCED: "true" volumes: - - sqlite_data:/app/data + - ./app/services/database/venv:/opt/venv + - ./app/services/database/.prisma-cache:/root/.cache/prisma-python restart: unless-stopped + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" - # mail-service: - # build: - # context: . - # dockerfile: app/services/mail/Dockerfile - # volumes: - # - sqlite_data:/app/data - # env_file: [.env] - # environment: - # REDIS_STREAM_PUBLISH: ACCOUNT:SERVICES:MAIL:PUBLISH - # REDIS_STREAM_TASKS: ACCOUNT:SERVICES:MAIL:TASKS - # CONSUME_BACKLOG: true - # depends_on: [redis] - # networks: [servicesNetwork] - # restart: unless-stopped - # logging: - # driver: "json-file" - # options: - # max-size: "10m" - # max-file: "3" + mail-service: + build: + context: . + dockerfile: app/services/mail/Dockerfile + env_file: [.env] + depends_on: + rabbitmq: + condition: service_healthy + environment: + SERVICE_NAME: "mail-service" + PRODUCE_KEY: "mail.service.publish" + CONSUME_BINDINGS: "database.service.publish,mongo.service.publish" + RABBITMQ_URL: amqp://admin:admin@rabbitmq:5672/ + EXCHANGE_EVENTS: "app.events" + PRODUCE_ONCE: "true" + RETRY_DELAY_MS: "5000" + MAX_RETRIES: "3" + PREFETCH: "16" + IGNORE_SELF_PRODUCED: "true" + networks: [servicesNetwork] + restart: unless-stopped + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" - # queue-service: - # build: - # context: . - # dockerfile: app/services/queue/Dockerfile - # volumes: - # - sqlite_data:/app/data - # env_file: [.env] - # environment: - # REDIS_STREAM_PUBLISH: ACCOUNT:SERVICES:QUEUE:PUBLISH - # REDIS_STREAM_TASKS: ACCOUNT:SERVICES:QUEUE:TASKS - # depends_on: [redis] - # networks: [servicesNetwork] - # restart: unless-stopped - # logging: - # driver: "json-file" - # options: - # max-size: "10m" - # max-file: "3" + parser-mail-service: + build: + context: . + dockerfile: app/services/parser/mail/Dockerfile + env_file: [.env] + depends_on: + rabbitmq: + condition: service_healthy + environment: + SERVICE_NAME: "parser-mail-service" + RABBITMQ_URL: amqp://admin:admin@rabbitmq:5672/ + EXCHANGE_EVENTS: "app.events" + CONSUME_BINDINGS: "mail.service.publish" + PRODUCE_KEY: "parser.mail.publish" + RETRY_DELAY_MS: "5000" + MAX_RETRIES: "3" + PREFETCH: "16" + IGNORE_SELF_PRODUCED: "true" + networks: [servicesNetwork] + restart: unless-stopped + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" - # tester: - # build: - # context: . - # dockerfile: app/services/test/Dockerfile - # volumes: - # - sqlite_data:/app/data - # env_file: [.env] - # environment: - # REDIS_STREAM_DATABASE_PUBLISH: ACCOUNT:SERVICES:DATABASE:PUBLISH - # REDIS_STREAM_DATABASE_TASKS: ACCOUNT:SERVICES:DATABASE:TASKS - # REDIS_STREAM_MAIL_PUBLISH: ACCOUNT:SERVICES:MAIL:PUBLISH - # REDIS_STREAM_MAIL_TASKS: ACCOUNT:SERVICES:MAIL:TASKS - # REDIS_STREAM_QUEUE_PUBLISH: ACCOUNT:SERVICES:QUEUE:PUBLISH - # REDIS_STREAM_QUEUE_TASKS: ACCOUNT:SERVICES:QUEUE:TASKS - # depends_on: - # - redis - # # - db-service - # # - mail-service - # # - queue-service - # networks: [servicesNetwork] - # restart: "no" - # logging: - # driver: "json-file" - # options: - # max-size: "10m" - # max-file: "3" + parser-excel-service: + build: + context: . + dockerfile: app/services/parser/excel/Dockerfile + env_file: [.env] + depends_on: + rabbitmq: + condition: service_healthy + environment: + SERVICE_NAME: "parser-excel-service" + RABBITMQ_URL: amqp://admin:admin@rabbitmq:5672/ + EXCHANGE_EVENTS: "app.events" + CONSUME_BINDINGS: "parser.mail.publish" + PRODUCE_KEY: "parser.excel.publish" + PRODUCE_ONCE: "true" + RETRY_DELAY_MS: "5000" + MAX_RETRIES: "3" + PREFETCH: "16" + IGNORE_SELF_PRODUCED: "true" + networks: [servicesNetwork] + restart: unless-stopped + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + parser-comment-service: + build: + context: . + dockerfile: app/services/parser/comment/Dockerfile + env_file: [.env] + depends_on: + rabbitmq: + condition: service_healthy + environment: + SERVICE_NAME: "parser-comment-service" + RABBITMQ_URL: amqp://admin:admin@rabbitmq:5672/ + EXCHANGE_EVENTS: "app.events" + CONSUME_BINDINGS: "parser.excel.publish" + PRODUCE_KEY: "parser.comment.publish" + PRODUCE_ONCE: "true" + RETRY_DELAY_MS: "5000" + MAX_RETRIES: "3" + PREFETCH: "16" + IGNORE_SELF_PRODUCED: "true" + networks: [servicesNetwork] + restart: unless-stopped + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + parser-payment-service: + build: + context: . + dockerfile: app/services/parser/payment/Dockerfile + env_file: [.env] + depends_on: + rabbitmq: + condition: service_healthy + environment: + SERVICE_NAME: "parser-payment-service" + RABBITMQ_URL: amqp://admin:admin@rabbitmq:5672/ + EXCHANGE_EVENTS: "app.events" + CONSUME_BINDINGS: "parser.comment.publish" + PRODUCE_KEY: "parser.payment.publish" + PRODUCE_ONCE: "true" + RETRY_DELAY_MS: "5000" + MAX_RETRIES: "3" + PREFETCH: "16" + IGNORE_SELF_PRODUCED: "true" + networks: [servicesNetwork] + restart: unless-stopped + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3"