Init project

This commit is contained in:
2025-08-27 12:47:23 +04:00
commit 9ee249de29
24 changed files with 2449 additions and 0 deletions

56
doc-service/app/config.py Normal file
View File

@@ -0,0 +1,56 @@
import os
from typing import List
from pydantic_settings import BaseSettings
from dotenv import load_dotenv
# Загрузка .env файла
load_dotenv()
class Settings(BaseSettings):
"""Настройки приложения"""
# Основные настройки
DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true"
HOST: str = os.getenv("HOST", "0.0.0.0")
PORT: int = int(os.getenv("PORT", "8000"))
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
# CORS
ALLOWED_ORIGINS: List[str] = [
"http://localhost:3000",
"http://localhost:8080",
"https://localhost:3000",
"https://localhost:8080"
]
# Redis
REDIS_HOST: str = os.getenv("REDIS_HOST", "localhost")
REDIS_PORT: int = int(os.getenv("REDIS_PORT", "6379"))
REDIS_PASSWORD: str = os.getenv("REDIS_PASSWORD", "")
REDIS_DB: int = int(os.getenv("REDIS_DB", "0"))
# Core Service
CORE_SERVICE_URL: str = os.getenv("CORE_SERVICE_URL", "http://localhost:8080")
# Документы
DOCUMENTS_CACHE_TTL: int = int(os.getenv("DOCUMENTS_CACHE_TTL", "86400")) # 24 часа
MAX_DOCUMENT_SIZE: int = int(os.getenv("MAX_DOCUMENT_SIZE", "10485760")) # 10MB
# Пути для файлов
TEMPLATES_DIR: str = os.getenv("TEMPLATES_DIR", "app/templates")
OUTPUT_DIR: str = os.getenv("OUTPUT_DIR", "app/output")
# QR коды
QR_CODE_SIZE: int = int(os.getenv("QR_CODE_SIZE", "10"))
QR_CODE_BORDER: int = int(os.getenv("QR_CODE_BORDER", "2"))
class Config:
env_file = ".env"
case_sensitive = False
# Создание экземпляра настроек
settings = Settings()
# Создание директорий если не существуют
os.makedirs(settings.TEMPLATES_DIR, exist_ok=True)
os.makedirs(settings.OUTPUT_DIR, exist_ok=True)

80
doc-service/app/main.py Normal file
View File

@@ -0,0 +1,80 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
import structlog
from app.config import settings
from app.api.routes import documents, templates
from app.core.redis_client import redis_client
from app.core.logging import setup_logging
# Настройка логирования
setup_logging()
logger = structlog.get_logger()
# Создание FastAPI приложения
app = FastAPI(
title="ERP Document Service",
description="Сервис для генерации документов (PDF, Excel, Word)",
version="1.0.0",
docs_url="/docs",
redoc_url="/redoc"
)
# Настройка CORS
app.add_middleware(
CORSMiddleware,
allow_origins=settings.ALLOWED_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Подключение роутов
app.include_router(documents.router, prefix="/api/documents", tags=["documents"])
app.include_router(templates.router, prefix="/api/templates", tags=["templates"])
@app.on_event("startup")
async def startup_event():
"""Событие запуска приложения"""
logger.info("Starting Document Service")
# Подключение к Redis
await redis_client.connect()
logger.info("Connected to Redis")
@app.on_event("shutdown")
async def shutdown_event():
"""Событие остановки приложения"""
logger.info("Shutting down Document Service")
# Отключение от Redis
await redis_client.disconnect()
logger.info("Disconnected from Redis")
@app.get("/health")
async def health_check():
"""Проверка здоровья сервиса"""
return {
"status": "healthy",
"service": "document-service",
"version": "1.0.0"
}
@app.get("/")
async def root():
"""Корневой эндпоинт"""
return {
"message": "ERP Document Service",
"docs": "/docs",
"health": "/health"
}
if __name__ == "__main__":
uvicorn.run(
"app.main:app",
host=settings.HOST,
port=settings.PORT,
reload=settings.DEBUG,
log_level=settings.LOG_LEVEL.lower()
)

View File

@@ -0,0 +1,86 @@
from typing import Optional, Dict, Any, List
from pydantic import BaseModel, Field
from datetime import datetime
from enum import Enum
class DocumentType(str, Enum):
"""Типы документов"""
PDF = "pdf"
EXCEL = "excel"
WORD = "word"
QR_CODE = "qr_code"
class DocumentStatus(str, Enum):
"""Статусы документов"""
PENDING = "pending"
PROCESSING = "processing"
COMPLETED = "completed"
FAILED = "failed"
class QRCodeRequest(BaseModel):
"""Запрос на генерацию QR-кода"""
location_id: str = Field(..., description="ID места хранения")
location_address: str = Field(..., description="Адрес места")
organization_id: str = Field(..., description="ID организации")
size: Optional[int] = Field(10, description="Размер QR-кода")
border: Optional[int] = Field(2, description="Размер границы")
class QRCodeResponse(BaseModel):
"""Ответ с QR-кодом"""
document_id: str = Field(..., description="ID документа")
qr_code_url: str = Field(..., description="URL для скачивания QR-кода")
qr_code_data: str = Field(..., description="Данные QR-кода")
expires_at: datetime = Field(..., description="Время истечения")
class ReportRequest(BaseModel):
"""Запрос на генерацию отчета"""
report_type: str = Field(..., description="Тип отчета")
organization_id: str = Field(..., description="ID организации")
filters: Optional[Dict[str, Any]] = Field({}, description="Фильтры для отчета")
format: DocumentType = Field(DocumentType.PDF, description="Формат отчета")
class ReportResponse(BaseModel):
"""Ответ с отчетом"""
document_id: str = Field(..., description="ID документа")
download_url: str = Field(..., description="URL для скачивания")
file_size: int = Field(..., description="Размер файла в байтах")
expires_at: datetime = Field(..., description="Время истечения")
class DocumentStatusResponse(BaseModel):
"""Ответ со статусом документа"""
document_id: str = Field(..., description="ID документа")
status: DocumentStatus = Field(..., description="Статус документа")
progress: Optional[int] = Field(None, description="Прогресс в процентах")
error_message: Optional[str] = Field(None, description="Сообщение об ошибке")
created_at: datetime = Field(..., description="Время создания")
updated_at: datetime = Field(..., description="Время обновления")
class GeneratePDFRequest(BaseModel):
"""Запрос на генерацию PDF"""
template_name: str = Field(..., description="Название шаблона")
data: Dict[str, Any] = Field(..., description="Данные для шаблона")
filename: Optional[str] = Field(None, description="Имя файла")
class GenerateExcelRequest(BaseModel):
"""Запрос на генерацию Excel"""
data: List[Dict[str, Any]] = Field(..., description="Данные для таблицы")
sheet_name: str = Field("Sheet1", description="Название листа")
filename: Optional[str] = Field(None, description="Имя файла")
class TemplateInfo(BaseModel):
"""Информация о шаблоне"""
name: str = Field(..., description="Название шаблона")
description: str = Field(..., description="Описание шаблона")
variables: List[str] = Field(..., description="Переменные шаблона")
created_at: datetime = Field(..., description="Время создания")
updated_at: datetime = Field(..., description="Время обновления")
class DocumentInfo(BaseModel):
"""Информация о документе"""
id: str = Field(..., description="ID документа")
type: DocumentType = Field(..., description="Тип документа")
status: DocumentStatus = Field(..., description="Статус документа")
filename: str = Field(..., description="Имя файла")
file_size: int = Field(..., description="Размер файла")
created_at: datetime = Field(..., description="Время создания")
expires_at: datetime = Field(..., description="Время истечения")