diff --git a/.gitignore b/.gitignore index 6d9207b..08b5331 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ .env .venv .idea -__pycache__ \ No newline at end of file +__pycache__ +/venv \ No newline at end of file diff --git a/main.py b/main.py index 5608dbf..124d4f1 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,21 @@ from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware import routers +origins = [ + 'http://localhost:5173' +] app = FastAPI() + +app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + routers_list = [ routers.auth_router, routers.deal_router, @@ -10,6 +23,3 @@ routers_list = [ ] for router in routers_list: app.include_router(router) - - - diff --git a/models/client.py b/models/client.py index 59872dd..ff9c1e0 100644 --- a/models/client.py +++ b/models/client.py @@ -1,4 +1,5 @@ -from sqlalchemy import Column, Integer, String, DateTime +from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, BigInteger +from sqlalchemy.orm import relationship from models import BaseModel @@ -7,5 +8,23 @@ class Client(BaseModel): __tablename__ = 'clients' id = Column(Integer, autoincrement=True, primary_key=True, index=True) name = Column(String, nullable=False, unique=True, comment='Название клиента') - address = Column(String) created_at = Column(DateTime, nullable=False, comment='Дата создания') + + +class ClientDetails(BaseModel): + __tablename__ = 'client_details' + + id = Column(Integer, autoincrement=True, primary_key=True, index=True) + + client_id = Column(Integer, ForeignKey('clients.id'), unique=True, nullable=False, comment='ID клиента') + client = relationship('Client', backref='details', uselist=False) + + address = Column(String) + phone_number = Column(String) + inn = Column(BigInteger) + email = Column(String) + + last_modified_at = Column(DateTime, nullable=False) + + modified_by_user_id = Column(Integer, ForeignKey('users.id'), nullable=False) + modified_by_user = relationship('User') diff --git a/models/product.py b/models/product.py new file mode 100644 index 0000000..4262b2a --- /dev/null +++ b/models/product.py @@ -0,0 +1,15 @@ +from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy.orm import relationship + +from models import BaseModel + + +class Product(BaseModel): + __tablename__ = 'products' + id = Column(Integer, autoincrement=True, primary_key=True, index=True) + name = Column(String, nullable=False, index=True) + article = Column(String, nullable=False, index=True) + + client_id = Column(Integer, ForeignKey('clients.id'), nullable=False, comment='ID сделки') + client = relationship('Client', back_populates='status_history') + diff --git a/routers/client.py b/routers/client.py index 1c9bba3..8de30c9 100644 --- a/routers/client.py +++ b/routers/client.py @@ -4,7 +4,10 @@ from fastapi import APIRouter, Depends from sqlalchemy.ext.asyncio import AsyncSession from backend.session import get_session -from schemas.client import ClientSearchRequest +from models import User +from schemas.client import ClientSearchRequest, ClientUpdateDetailsRequest, ClientUpdateDetailsResponse, \ + ClientGetAllResponse +from services.auth import get_current_user from services.client import ClientService client_router = APIRouter( @@ -19,3 +22,25 @@ async def search_clients( session: Annotated[AsyncSession, Depends(get_session)] ): return await ClientService(session).search_clients(ClientSearchRequest(name=name)) + + +@client_router.post('/update-details') +async def update_client_details( + session: Annotated[AsyncSession, Depends(get_session)], + user: Annotated[User, Depends(get_current_user)], + request: ClientUpdateDetailsRequest, +): + service = ClientService(session) + client = await service.get_by_id(request.client_id) + if not client: + return ClientUpdateDetailsResponse(ok=False) + await service.update_details(user, client, request.details) + await session.commit() + return ClientUpdateDetailsResponse(ok=True) + + +@client_router.get('/get-all', operation_id='get_all_clients', response_model=ClientGetAllResponse) +async def get_all_clients( + session: Annotated[AsyncSession, Depends(get_session)], +): + return await ClientService(session).get_all() diff --git a/schemas/client.py b/schemas/client.py index 3412f74..6934b58 100644 --- a/schemas/client.py +++ b/schemas/client.py @@ -8,6 +8,15 @@ class ClientSchema(CustomModel): name: str +class ClientDetailsSchema(CustomModel): + address: str | None = None + phone_number: str | None = None + inn: int | None = None + email: str | None = None + + # TODO add email validation + + class ClientSearchRequest(CustomModel): name: str @@ -19,3 +28,16 @@ class ClientCreateRequest(CustomModel): class ClientSearchResponse(CustomModel): clients: List[ClientSchema] + + +class ClientUpdateDetailsRequest(CustomModel): + client_id: int + details: ClientDetailsSchema + + +class ClientUpdateDetailsResponse(CustomModel): + ok: bool + + +class ClientGetAllResponse(CustomModel): + clients: List[ClientSchema] diff --git a/services/client.py b/services/client.py index fc46937..16b1e66 100644 --- a/services/client.py +++ b/services/client.py @@ -1,9 +1,11 @@ import datetime -from typing import Union +from typing import Union, Annotated -from sqlalchemy import select +from fastapi import Depends +from sqlalchemy import select, update -from models import Client +from models import Client, ClientDetails, User +from services.auth import get_current_user from services.base import BaseService from schemas.client import * @@ -14,10 +16,51 @@ class ClientService(BaseService): client = await self.session.scalar(select(Client).where(Client.name == name)) return client - async def create_client_raw(self, name: str, address: str) -> Client: - client = Client(name=name, address=address, created_at=datetime.datetime.now()) + async def get_by_id(self, client_id: int) -> Union[Client, None]: + return await self.session.get(Client, client_id) + + async def get_details_by_client_id(self, client_id: int) -> Union[ClientDetails, None]: + details = await self.session.scalar(select(ClientDetails).where(ClientDetails.client_id == client_id)) + return details + + async def get_all(self) -> ClientGetAllResponse: + clients_query = await self.session.scalars(select(Client)) + clients = clients_query.all() + result = [] + for client in clients: + result.append(ClientSchema.model_validate(client)) + return ClientGetAllResponse(clients=result) + + async def create_details(self, user, client: Client, request: ClientDetailsSchema): + dict_data = request.dict() + dict_data['client_id'] = client.id + dict_data['last_modified_at'] = datetime.datetime.now() + dict_data['modified_by_user_id'] = user.id + details = ClientDetails(**dict_data) + self.session.add(details) + await self.session.flush() + return details + + async def update_details(self, user: User, client: Client, request: ClientDetailsSchema) -> ClientDetails: + details = await self.get_details_by_client_id(client_id=client.id) + if not details: + details = await self.create_details(user, client, request) + dict_data = request.dict() + dict_data['last_modified_at'] = datetime.datetime.now() + dict_data['modified_by_user_id'] = user.id + await self.session.execute(update(ClientDetails).where(ClientDetails.id == details.id).values(**dict_data)) + await self.session.flush() + + async def create_client_raw(self, + user: User, + client_name: str, + details_schema: ClientDetailsSchema) -> Client: + client = Client(name=client_name, created_at=datetime.datetime.now()) self.session.add(client) await self.session.flush() + + await self.update_details(user, client, details_schema) + return client async def search_clients(self, request: ClientSearchRequest) -> ClientSearchResponse: diff --git a/services/deal.py b/services/deal.py index abc9fa5..44e9231 100644 --- a/services/deal.py +++ b/services/deal.py @@ -5,6 +5,7 @@ from sqlalchemy import select from models import User, Deal from models.deal import * +from schemas.client import ClientDetailsSchema from schemas.deal import * from services.base import BaseService from services.client import ClientService @@ -49,7 +50,11 @@ class DealService(BaseService): client_service = ClientService(self.session) client = await client_service.get_by_name(request.client_name) if not client: - client = await client_service.create_client_raw(request.client_name, request.client_address) + client = await client_service.create_client_raw( + user, + request.client_name, + ClientDetailsSchema(address=request.client_address)) + await client_service.update_details(user, client, ClientDetailsSchema(address=request.client_address)) deal = Deal( name=request.name, created_at=datetime.datetime.now(),