crappy
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
from typing import AsyncGenerator
|
||||||
|
|
||||||
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
|
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
|
||||||
@@ -10,10 +12,10 @@ session_maker = sessionmaker(
|
|||||||
class_=AsyncSession,
|
class_=AsyncSession,
|
||||||
expire_on_commit=False,
|
expire_on_commit=False,
|
||||||
autocommit=False,
|
autocommit=False,
|
||||||
autoflush=False
|
autoflush=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def get_session() -> AsyncSession:
|
async def get_session() -> AsyncGenerator[AsyncSession, None]:
|
||||||
async with session_maker() as session:
|
async with session_maker() as session:
|
||||||
yield session
|
yield session
|
||||||
|
|||||||
3
main.py
3
main.py
@@ -19,7 +19,8 @@ app.add_middleware(
|
|||||||
routers_list = [
|
routers_list = [
|
||||||
routers.auth_router,
|
routers.auth_router,
|
||||||
routers.deal_router,
|
routers.deal_router,
|
||||||
routers.client_router
|
routers.client_router,
|
||||||
|
routers.service_router
|
||||||
]
|
]
|
||||||
for router in routers_list:
|
for router in routers_list:
|
||||||
app.include_router(router)
|
app.include_router(router)
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
from sqlalchemy.orm import configure_mappers
|
||||||
|
|
||||||
from .auth import *
|
from .auth import *
|
||||||
from .deal import *
|
from .deal import *
|
||||||
from .client import *
|
from .client import *
|
||||||
|
from .service import *
|
||||||
|
from .secondary import *
|
||||||
|
|
||||||
|
configure_mappers()
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
from sqlalchemy.orm import declarative_base
|
from sqlalchemy.orm import declarative_base
|
||||||
|
|
||||||
BaseModel = declarative_base()
|
BaseModel = declarative_base()
|
||||||
|
metadata = BaseModel.metadata
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, BigInteger
|
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, BigInteger
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship, backref
|
||||||
|
|
||||||
from models import BaseModel
|
from models import BaseModel
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ class ClientDetails(BaseModel):
|
|||||||
id = Column(Integer, autoincrement=True, primary_key=True, index=True)
|
id = Column(Integer, autoincrement=True, primary_key=True, index=True)
|
||||||
|
|
||||||
client_id = Column(Integer, ForeignKey('clients.id'), unique=True, nullable=False, comment='ID клиента')
|
client_id = Column(Integer, ForeignKey('clients.id'), unique=True, nullable=False, comment='ID клиента')
|
||||||
client = relationship('Client', backref='details', uselist=False)
|
client = relationship('Client', backref=backref('details', uselist=False))
|
||||||
|
|
||||||
address = Column(String)
|
address = Column(String)
|
||||||
phone_number = Column(String)
|
phone_number = Column(String)
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
from enum import IntEnum, unique
|
from enum import IntEnum, unique
|
||||||
|
|
||||||
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey
|
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Boolean
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
from models.base import BaseModel
|
from models.base import BaseModel
|
||||||
|
from models.secondary import deal_services
|
||||||
|
|
||||||
|
|
||||||
@unique
|
@unique
|
||||||
@@ -29,6 +30,11 @@ class Deal(BaseModel):
|
|||||||
|
|
||||||
status_history = relationship('DealStatusHistory', back_populates='deal', cascade="all, delete-orphan")
|
status_history = relationship('DealStatusHistory', back_populates='deal', cascade="all, delete-orphan")
|
||||||
|
|
||||||
|
is_deleted = Column(Boolean, nullable=False, server_default='0', default=False, comment='Удалена')
|
||||||
|
is_completed = Column(Boolean, nullable=False, server_default='0', default=False, comment='Завершена')
|
||||||
|
|
||||||
|
services = relationship('Service', secondary=deal_services)
|
||||||
|
|
||||||
|
|
||||||
class DealStatusHistory(BaseModel):
|
class DealStatusHistory(BaseModel):
|
||||||
__tablename__ = 'deals_status_history'
|
__tablename__ = 'deals_status_history'
|
||||||
|
|||||||
10
models/secondary.py
Normal file
10
models/secondary.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from sqlalchemy import Table, Column, Integer, ForeignKey
|
||||||
|
|
||||||
|
from models.base import metadata
|
||||||
|
|
||||||
|
deal_services = Table(
|
||||||
|
'deal_services', metadata,
|
||||||
|
Column('deal_id', Integer, ForeignKey('deals.id')),
|
||||||
|
Column('service_id', Integer, ForeignKey('services.id')),
|
||||||
|
Column('quantity', Integer)
|
||||||
|
)
|
||||||
21
models/service.py
Normal file
21
models/service.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
from sqlalchemy import Column, Integer, String, ForeignKey, Double
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
|
from models import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Service(BaseModel):
|
||||||
|
__tablename__ = 'services'
|
||||||
|
id = Column(Integer, autoincrement=True, primary_key=True, index=True)
|
||||||
|
name = Column(String, nullable=False, comment='Название услуги')
|
||||||
|
|
||||||
|
category_id = Column(Integer, ForeignKey('service_categories.id'), nullable=False, comment='ID категории услуги')
|
||||||
|
category = relationship('ServiceCategory')
|
||||||
|
|
||||||
|
price = Column(Double, nullable=False, comment='Стоимость услуги')
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceCategory(BaseModel):
|
||||||
|
__tablename__ = 'service_categories'
|
||||||
|
id = Column(Integer, autoincrement=True, primary_key=True, index=True)
|
||||||
|
name = Column(String, nullable=False)
|
||||||
@@ -16,4 +16,5 @@ alembic
|
|||||||
# Other
|
# Other
|
||||||
python-dotenv
|
python-dotenv
|
||||||
aiohttp
|
aiohttp
|
||||||
aiohttp[speedups]
|
aiohttp[speedups]
|
||||||
|
openpyxl
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
from .auth import auth_router
|
from .auth import auth_router
|
||||||
from .deal import deal_router
|
from .deal import deal_router
|
||||||
from .client import client_router
|
from .client import client_router
|
||||||
|
from .service import service_router
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,11 @@ async def update_client_details(
|
|||||||
return ClientUpdateDetailsResponse(ok=True)
|
return ClientUpdateDetailsResponse(ok=True)
|
||||||
|
|
||||||
|
|
||||||
@client_router.get('/get-all', operation_id='get_all_clients', response_model=ClientGetAllResponse)
|
@client_router.get(
|
||||||
|
'/get-all',
|
||||||
|
operation_id='get_all_clients',
|
||||||
|
response_model=ClientGetAllResponse
|
||||||
|
)
|
||||||
async def get_all_clients(
|
async def get_all_clients(
|
||||||
session: Annotated[AsyncSession, Depends(get_session)],
|
session: Annotated[AsyncSession, Depends(get_session)],
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -40,3 +40,13 @@ async def change_status(
|
|||||||
user: Annotated[User, Depends(get_current_user)]
|
user: Annotated[User, Depends(get_current_user)]
|
||||||
):
|
):
|
||||||
return await DealService(session).change_status(request, user)
|
return await DealService(session).change_status(request, user)
|
||||||
|
|
||||||
|
|
||||||
|
@deal_router.get('/summaries',
|
||||||
|
response_model=DealSummaryResponse,
|
||||||
|
operation_id='getDealSummaries'
|
||||||
|
)
|
||||||
|
async def get_summary(
|
||||||
|
session: Annotated[AsyncSession, Depends(get_session)]
|
||||||
|
):
|
||||||
|
return await DealService(session).get_summary()
|
||||||
|
|||||||
59
routers/service.py
Normal file
59
routers/service.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from backend.session import get_session
|
||||||
|
from schemas.services import *
|
||||||
|
from services.service import ServiceService
|
||||||
|
|
||||||
|
service_router = APIRouter(
|
||||||
|
prefix="/service",
|
||||||
|
tags=['service']
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@service_router.get(
|
||||||
|
'/get-all',
|
||||||
|
response_model=ServiceGetAllResponse,
|
||||||
|
operation_id="get_all_services"
|
||||||
|
)
|
||||||
|
async def get_all(
|
||||||
|
session: Annotated[AsyncSession, Depends(get_session)]
|
||||||
|
):
|
||||||
|
return await ServiceService(session).get_all()
|
||||||
|
|
||||||
|
|
||||||
|
@service_router.post(
|
||||||
|
'/create',
|
||||||
|
response_model=ServiceCreateResponse,
|
||||||
|
operation_id="create_service"
|
||||||
|
)
|
||||||
|
async def create(
|
||||||
|
session: Annotated[AsyncSession, Depends(get_session)],
|
||||||
|
request: ServiceCreateRequest
|
||||||
|
):
|
||||||
|
return await ServiceService(session).create(request)
|
||||||
|
|
||||||
|
|
||||||
|
@service_router.get(
|
||||||
|
'/categories/get-all',
|
||||||
|
response_model=ServiceGetAllCategoriesResponse,
|
||||||
|
operation_id="get_all_service_categories"
|
||||||
|
)
|
||||||
|
async def get_all_categories(
|
||||||
|
session: Annotated[AsyncSession, Depends(get_session)]
|
||||||
|
):
|
||||||
|
return await ServiceService(session).get_all_categories()
|
||||||
|
|
||||||
|
|
||||||
|
@service_router.post(
|
||||||
|
'/categories/create',
|
||||||
|
response_model=ServiceCreateCategoryResponse,
|
||||||
|
operation_id="create_service_category"
|
||||||
|
)
|
||||||
|
async def create_category(
|
||||||
|
session: Annotated[AsyncSession, Depends(get_session)],
|
||||||
|
request: ServiceCreateCategoryRequest
|
||||||
|
):
|
||||||
|
return await ServiceService(session).create_category(request)
|
||||||
@@ -10,3 +10,7 @@ class CustomModel(BaseModel):
|
|||||||
class Config:
|
class Config:
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
|
|
||||||
|
|
||||||
|
class OkMessageSchema(BaseModel):
|
||||||
|
ok: bool
|
||||||
|
message: str
|
||||||
|
|||||||
@@ -3,18 +3,17 @@ from typing import List
|
|||||||
from schemas.base import CustomModel
|
from schemas.base import CustomModel
|
||||||
|
|
||||||
|
|
||||||
class ClientSchema(CustomModel):
|
|
||||||
id: int
|
|
||||||
name: str
|
|
||||||
|
|
||||||
|
|
||||||
class ClientDetailsSchema(CustomModel):
|
class ClientDetailsSchema(CustomModel):
|
||||||
address: str | None = None
|
address: str | None = None
|
||||||
phone_number: str | None = None
|
phone_number: str | None = None
|
||||||
inn: int | None = None
|
inn: int | None = None
|
||||||
email: str | None = None
|
email: str | None = None
|
||||||
|
|
||||||
# TODO add email validation
|
|
||||||
|
class ClientSchema(CustomModel):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
details: ClientDetailsSchema | None = None
|
||||||
|
|
||||||
|
|
||||||
class ClientSearchRequest(CustomModel):
|
class ClientSearchRequest(CustomModel):
|
||||||
|
|||||||
@@ -1,18 +1,34 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from schemas.base import CustomModel
|
from schemas.base import CustomModel
|
||||||
from schemas.client import ClientSchema
|
from schemas.client import ClientSchema
|
||||||
|
|
||||||
|
|
||||||
|
# region Entities
|
||||||
|
class FastDeal(CustomModel):
|
||||||
|
name: str
|
||||||
|
client: ClientSchema
|
||||||
|
comment: str
|
||||||
|
acceptance_date: datetime.datetime
|
||||||
|
|
||||||
|
|
||||||
|
class DealSummary(CustomModel):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
client_name: str
|
||||||
|
changed_at: datetime.datetime
|
||||||
|
status: int
|
||||||
|
|
||||||
|
|
||||||
|
# endregion Entities
|
||||||
|
|
||||||
|
# region Requests
|
||||||
class DealChangeStatusRequest(CustomModel):
|
class DealChangeStatusRequest(CustomModel):
|
||||||
deal_id: int
|
deal_id: int
|
||||||
new_status: int
|
new_status: int
|
||||||
|
|
||||||
|
|
||||||
class DealChangeStatusResponse(CustomModel):
|
|
||||||
ok: bool
|
|
||||||
|
|
||||||
|
|
||||||
class DealCreateRequest(CustomModel):
|
class DealCreateRequest(CustomModel):
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
@@ -25,16 +41,27 @@ class DealQuickCreateRequest(CustomModel):
|
|||||||
acceptance_date: datetime.datetime
|
acceptance_date: datetime.datetime
|
||||||
|
|
||||||
|
|
||||||
class DealQuickCreateResponse(CustomModel):
|
class DealSummaryRequest(CustomModel):
|
||||||
deal_id: int
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# endregion Requests
|
||||||
|
|
||||||
|
# region Responses
|
||||||
|
|
||||||
|
class DealChangeStatusResponse(CustomModel):
|
||||||
|
ok: bool
|
||||||
|
|
||||||
|
|
||||||
class DealCreateResponse(CustomModel):
|
class DealCreateResponse(CustomModel):
|
||||||
ok: bool
|
ok: bool
|
||||||
|
|
||||||
|
|
||||||
class FastDeal(CustomModel):
|
class DealQuickCreateResponse(CustomModel):
|
||||||
name: str
|
deal_id: int
|
||||||
client: ClientSchema
|
|
||||||
comment: str
|
|
||||||
acceptance_date: datetime.datetime
|
class DealSummaryResponse(CustomModel):
|
||||||
|
summaries: List[DealSummary]
|
||||||
|
|
||||||
|
# endregion Responses
|
||||||
|
|||||||
49
schemas/services.py
Normal file
49
schemas/services.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
from typing import List
|
||||||
|
|
||||||
|
from schemas.base import CustomModel, OkMessageSchema
|
||||||
|
|
||||||
|
|
||||||
|
# region Entities
|
||||||
|
class ServiceCategorySchema(CustomModel):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceSchema(CustomModel):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
category: ServiceCategorySchema
|
||||||
|
price: float
|
||||||
|
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
|
||||||
|
# region Requests
|
||||||
|
class ServiceCreateRequest(CustomModel):
|
||||||
|
service: ServiceSchema
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceCreateCategoryRequest(CustomModel):
|
||||||
|
category: ServiceCategorySchema
|
||||||
|
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
|
||||||
|
# region Responses
|
||||||
|
class ServiceGetAllResponse(CustomModel):
|
||||||
|
services: List[ServiceSchema]
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceGetAllCategoriesResponse(CustomModel):
|
||||||
|
categories: List[ServiceCategorySchema]
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceCreateResponse(OkMessageSchema):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceCreateCategoryResponse(OkMessageSchema):
|
||||||
|
pass
|
||||||
|
# endregion
|
||||||
@@ -3,6 +3,7 @@ from typing import Union, Annotated
|
|||||||
|
|
||||||
from fastapi import Depends
|
from fastapi import Depends
|
||||||
from sqlalchemy import select, update
|
from sqlalchemy import select, update
|
||||||
|
from sqlalchemy.orm import joinedload
|
||||||
|
|
||||||
from models import Client, ClientDetails, User
|
from models import Client, ClientDetails, User
|
||||||
from services.auth import get_current_user
|
from services.auth import get_current_user
|
||||||
@@ -24,7 +25,7 @@ class ClientService(BaseService):
|
|||||||
return details
|
return details
|
||||||
|
|
||||||
async def get_all(self) -> ClientGetAllResponse:
|
async def get_all(self) -> ClientGetAllResponse:
|
||||||
clients_query = await self.session.scalars(select(Client))
|
clients_query = await self.session.scalars(select(Client).options(joinedload(Client.details)))
|
||||||
clients = clients_query.all()
|
clients = clients_query.all()
|
||||||
result = []
|
result = []
|
||||||
for client in clients:
|
for client in clients:
|
||||||
@@ -65,7 +66,8 @@ class ClientService(BaseService):
|
|||||||
|
|
||||||
async def search_clients(self, request: ClientSearchRequest) -> ClientSearchResponse:
|
async def search_clients(self, request: ClientSearchRequest) -> ClientSearchResponse:
|
||||||
query = await self.session.scalars(select(Client)
|
query = await self.session.scalars(select(Client)
|
||||||
.where(Client.name.ilike(f'%{request.name}%')))
|
.where(Client.name.ilike(f'%{request.name}%'))
|
||||||
|
.options(joinedload(Client.details)))
|
||||||
clients = []
|
clients = []
|
||||||
for client in query.all():
|
for client in query.all():
|
||||||
clients.append(ClientSchema.model_validate(client))
|
clients.append(ClientSchema.model_validate(client))
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import datetime
|
|||||||
from typing import Type, Union
|
from typing import Type, Union
|
||||||
|
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
|
from sqlalchemy.orm import joinedload, selectinload
|
||||||
|
|
||||||
from models import User, Deal
|
from models import User, Deal
|
||||||
from models.deal import *
|
from models.deal import *
|
||||||
@@ -16,7 +17,9 @@ class DealService(BaseService):
|
|||||||
async def _get_deal_by_id(self, deal_id) -> Union[Deal, None]:
|
async def _get_deal_by_id(self, deal_id) -> Union[Deal, None]:
|
||||||
return await self.session.get(Deal, deal_id)
|
return await self.session.get(Deal, deal_id)
|
||||||
|
|
||||||
async def change_status(self, deal: Deal, status: DealStatus, user: User,
|
async def change_status(self, deal: Deal,
|
||||||
|
status: DealStatus,
|
||||||
|
user: User,
|
||||||
deadline: datetime.datetime = None) -> DealStatusHistory:
|
deadline: datetime.datetime = None) -> DealStatusHistory:
|
||||||
deadline = deadline
|
deadline = deadline
|
||||||
status_change = DealStatusHistory(
|
status_change = DealStatusHistory(
|
||||||
@@ -75,3 +78,24 @@ class DealService(BaseService):
|
|||||||
await self.change_status(deal, DealStatus(request.new_status), user)
|
await self.change_status(deal, DealStatus(request.new_status), user)
|
||||||
await self.session.commit()
|
await self.session.commit()
|
||||||
return DealChangeStatusResponse(ok=True)
|
return DealChangeStatusResponse(ok=True)
|
||||||
|
|
||||||
|
async def get_summary(self) -> DealSummaryResponse:
|
||||||
|
deals_query = await self.session.scalars(select(Deal)
|
||||||
|
.options(selectinload(Deal.status_history),
|
||||||
|
joinedload(Deal.client))
|
||||||
|
.where(Deal.is_deleted == False,
|
||||||
|
Deal.is_completed == False))
|
||||||
|
summaries = []
|
||||||
|
for deal in deals_query.all():
|
||||||
|
deal: Deal
|
||||||
|
last_status: DealStatusHistory = max(deal.status_history, key=lambda status: status.changed_at)
|
||||||
|
summaries.append(
|
||||||
|
DealSummary(
|
||||||
|
id=deal.id,
|
||||||
|
client_name=deal.client.name,
|
||||||
|
name=deal.name,
|
||||||
|
changed_at=last_status.changed_at,
|
||||||
|
status=last_status.to_status
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return DealSummaryResponse(summaries=summaries)
|
||||||
56
services/service.py
Normal file
56
services/service.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
from sqlalchemy import select
|
||||||
|
from sqlalchemy.orm import joinedload
|
||||||
|
|
||||||
|
from models import Service, ServiceCategory
|
||||||
|
from services.base import BaseService
|
||||||
|
from schemas.services import ServiceGetAllResponse, ServiceSchema, ServiceGetAllCategoriesResponse, \
|
||||||
|
ServiceCategorySchema, ServiceCreateRequest, ServiceCreateResponse, ServiceCreateCategoryRequest, \
|
||||||
|
ServiceCreateCategoryResponse
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceService(BaseService):
|
||||||
|
async def get_all(self) -> ServiceGetAllResponse:
|
||||||
|
query = await (self.session
|
||||||
|
.scalars(select(Service)
|
||||||
|
.options(joinedload(Service.category))
|
||||||
|
.order_by(Service.category_id, Service.id)))
|
||||||
|
services = []
|
||||||
|
for service in query.all():
|
||||||
|
services.append(ServiceSchema.model_validate(service))
|
||||||
|
return ServiceGetAllResponse(services=services)
|
||||||
|
|
||||||
|
async def create(self, request: ServiceCreateRequest) -> ServiceCreateResponse:
|
||||||
|
try:
|
||||||
|
raw_service = request.service
|
||||||
|
service_dict = raw_service.model_dump()
|
||||||
|
service_dict['category_id'] = raw_service.category.id
|
||||||
|
del service_dict['id']
|
||||||
|
del service_dict['category']
|
||||||
|
service = Service(**service_dict)
|
||||||
|
self.session.add(service)
|
||||||
|
await self.session.commit()
|
||||||
|
return ServiceCreateResponse(ok=True, message="Услуга успешно создана")
|
||||||
|
except Exception as e:
|
||||||
|
return ServiceCreateResponse(ok=False, message=f"Неудалось создать услугу, ошибка: {e}")
|
||||||
|
|
||||||
|
async def create_category(self, request: ServiceCreateCategoryRequest) -> ServiceCreateCategoryResponse:
|
||||||
|
try:
|
||||||
|
raw_category = request.category
|
||||||
|
category_dict = raw_category.model_dump()
|
||||||
|
del category_dict['id']
|
||||||
|
category = ServiceCategory(**category_dict)
|
||||||
|
self.session.add(category)
|
||||||
|
await self.session.commit()
|
||||||
|
return ServiceCreateCategoryResponse(ok=True, message="Категория успешно создана")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return ServiceCreateCategoryResponse(ok=False, message=f"Неудалось создать категорию, ошибка: {e}")
|
||||||
|
|
||||||
|
async def get_all_categories(self) -> ServiceGetAllCategoriesResponse:
|
||||||
|
query = await (self.session
|
||||||
|
.scalars(select(ServiceCategory)
|
||||||
|
.order_by(ServiceCategory.id)))
|
||||||
|
categories = []
|
||||||
|
for category in query.all():
|
||||||
|
categories.append(ServiceCategorySchema.model_validate(category))
|
||||||
|
return ServiceGetAllCategoriesResponse(categories=categories)
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
# Test your FastAPI endpoints
|
|
||||||
|
|
||||||
GET http://127.0.0.1:8000/
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET http://127.0.0.1:8000/hello/User
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
###
|
|
||||||
58
utils/import_services.py
Normal file
58
utils/import_services.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import asyncio
|
||||||
|
|
||||||
|
import openpyxl
|
||||||
|
from openpyxl.worksheet.worksheet import Worksheet
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from backend.session import session_maker
|
||||||
|
from models import ServiceCategory, Service
|
||||||
|
|
||||||
|
|
||||||
|
async def write_services(services: dict):
|
||||||
|
async with session_maker() as session:
|
||||||
|
session: AsyncSession
|
||||||
|
|
||||||
|
for raw_category in services.keys():
|
||||||
|
category = ServiceCategory(name=raw_category)
|
||||||
|
session.add(category)
|
||||||
|
await session.flush()
|
||||||
|
print(category.id)
|
||||||
|
for raw_service in services[raw_category]:
|
||||||
|
service = Service(name=raw_service['name'],
|
||||||
|
price=raw_service['price'],
|
||||||
|
category_id=category.id)
|
||||||
|
session.add(service)
|
||||||
|
await session.flush()
|
||||||
|
await session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
workbook = openpyxl.load_workbook('services.xlsx')
|
||||||
|
sheet: Worksheet = workbook.active
|
||||||
|
START_ROW = 12
|
||||||
|
current_category = None
|
||||||
|
services = {}
|
||||||
|
merged_cells = sheet.merged_cells.ranges
|
||||||
|
for row in range(START_ROW, sheet.max_row):
|
||||||
|
first_column = sheet.cell(row, 1)
|
||||||
|
first_column_value = first_column.value.strip()
|
||||||
|
|
||||||
|
second_column = sheet.cell(row, 2)
|
||||||
|
second_column_value = second_column.value
|
||||||
|
|
||||||
|
is_category = any([second_column.coordinate in merged_cell for merged_cell in merged_cells])
|
||||||
|
if is_category:
|
||||||
|
current_category = first_column_value
|
||||||
|
services[current_category] = []
|
||||||
|
continue
|
||||||
|
price = second_column_value
|
||||||
|
name = first_column_value
|
||||||
|
services[current_category].append({
|
||||||
|
'name': name,
|
||||||
|
'price': price
|
||||||
|
})
|
||||||
|
await write_services(services)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
||||||
BIN
utils/services.xlsx
Normal file
BIN
utils/services.xlsx
Normal file
Binary file not shown.
Reference in New Issue
Block a user