This commit is contained in:
2024-04-24 01:19:46 +03:00
parent be623a3555
commit 4e7626d2e6
12 changed files with 114 additions and 39 deletions

View File

@@ -29,6 +29,10 @@ target_metadata = BaseModel.metadata
# can be acquired: # can be acquired:
# my_important_option = config.get_main_option("my_important_option") # my_important_option = config.get_main_option("my_important_option")
# ... etc. # ... etc.
def include_object(object, name, type_, reflected, compare_to):
print(f"{type_}: {name}")
return True # Temporarily return True to debug all objects
def get_url(): def get_url():
url = config.get_main_option("sqlalchemy.url").format( url = config.get_main_option("sqlalchemy.url").format(
@@ -65,7 +69,11 @@ def run_migrations_offline() -> None:
def do_run_migrations(connection: Connection) -> None: def do_run_migrations(connection: Connection) -> None:
context.configure(connection=connection, target_metadata=target_metadata) context.configure(connection=connection,
target_metadata=target_metadata,
include_schemas=True,
include_object=include_object,
)
with context.begin_transaction(): with context.begin_transaction():
context.run_migrations() context.run_migrations()

View File

@@ -6,5 +6,4 @@ from .client import *
from .service import * from .service import *
from .product import * from .product import *
from .secondary import * from .secondary import *
configure_mappers() configure_mappers()

View File

@@ -1,9 +1,10 @@
from enum import IntEnum, unique from enum import IntEnum, unique
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Boolean from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Boolean, Sequence
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from models.base import BaseModel from models.base import BaseModel, metadata
from models.utils import add_sequence_to_model
@unique @unique
@@ -35,6 +36,10 @@ class Deal(BaseModel):
services = relationship('DealService', back_populates='deal') services = relationship('DealService', back_populates='deal')
products = relationship('DealProduct', back_populates='deal') products = relationship('DealProduct', back_populates='deal')
# TODO remake with sequence
rank = Column(String, nullable=False, comment='Lexorank')
comment = Column(String, nullable=False, server_default='', comment='Коментарий к заданию')
class DealStatusHistory(BaseModel): class DealStatusHistory(BaseModel):
__tablename__ = 'deals_status_history' __tablename__ = 'deals_status_history'
@@ -52,3 +57,4 @@ class DealStatusHistory(BaseModel):
next_status_deadline = Column(DateTime, next_status_deadline = Column(DateTime,
comment='Дедлайн до которого сделку нужно перевести на следующий этап') comment='Дедлайн до которого сделку нужно перевести на следующий этап')
comment = Column(String, nullable=False, comment='Коментарий', server_default='')

View File

@@ -1,7 +1,11 @@
from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy import Column, Integer, String, ForeignKey, Sequence
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from models import BaseModel from models import BaseModel, metadata
deal_rank_seq = Sequence('test_ochko', start=1, increment=1, metadata=metadata)
sequence = Sequence('my_sequence_name')
class Product(BaseModel): class Product(BaseModel):
@@ -13,6 +17,7 @@ class Product(BaseModel):
client_id = Column(Integer, ForeignKey('clients.id'), nullable=False, comment='ID сделки') client_id = Column(Integer, ForeignKey('clients.id'), nullable=False, comment='ID сделки')
client = relationship('Client', back_populates='products') client = relationship('Client', back_populates='products')
barcodes = relationship('ProductBarcode', back_populates='product', cascade="all, delete-orphan") barcodes = relationship('ProductBarcode', back_populates='product', cascade="all, delete-orphan")
my_column = Column(Integer, sequence)
class ProductBarcode(BaseModel): class ProductBarcode(BaseModel):

4
models/sequences.py Normal file
View File

@@ -0,0 +1,4 @@
from sqlalchemy import Sequence
from models import BaseModel

4
models/utils.py Normal file
View File

@@ -0,0 +1,4 @@
def add_sequence_to_model(sequence, metadata):
metadata.info.setdefault("sequences", set()).add(
(sequence.schema, sequence.name)
)

View File

@@ -17,4 +17,5 @@ alembic
python-dotenv python-dotenv
aiohttp aiohttp
aiohttp[speedups] aiohttp[speedups]
openpyxl openpyxl
lexorank-py

View File

@@ -51,6 +51,18 @@ async def get_summary(
): ):
return await DealService(session).get_summary() return await DealService(session).get_summary()
@deal_router.post(
'/summaries/reorder',
response_model=DealSummaryReorderResponse,
operation_id='reorderDealSummaries'
)
async def reorder(
session: Annotated[AsyncSession, Depends(get_session)],
request: DealSummaryReorderRequest,
user: Annotated[User, Depends(get_current_user)]
):
return await DealService(session).reorder(request, user)
@deal_router.get( @deal_router.get(
'/get-all', '/get-all',

View File

@@ -23,6 +23,7 @@ class DealSummary(CustomModelCamel):
changed_at: datetime.datetime changed_at: datetime.datetime
status: int status: int
total_price: int total_price: int
rank: int
class DealServiceSchema(CustomModelCamel): class DealServiceSchema(CustomModelCamel):
@@ -55,12 +56,14 @@ class DealSchema(CustomModelCamel):
is_deleted: bool is_deleted: bool
is_completed: bool is_completed: bool
client: ClientSchema client: ClientSchema
comment: str
class DealGeneralInfoSchema(CustomModelCamel): class DealGeneralInfoSchema(CustomModelCamel):
name: str name: str
is_deleted: bool is_deleted: bool
is_completed: bool is_completed: bool
comment: str
# endregion Entities # endregion Entities
@@ -141,6 +144,14 @@ class DealUpdateGeneralInfoRequest(CustomModelCamel):
data: DealGeneralInfoSchema data: DealGeneralInfoSchema
class DealSummaryReorderRequest(CustomModelCamel):
deal_id: int
new_status: int
rank: int
next_status_deadline: datetime.datetime
comment: str
# endregion Requests # endregion Requests
# region Responses # region Responses
@@ -204,4 +215,8 @@ class DealAddProductResponse(OkMessageSchema):
class DealUpdateGeneralInfoResponse(OkMessageSchema): class DealUpdateGeneralInfoResponse(OkMessageSchema):
pass pass
class DealSummaryReorderResponse(OkMessageSchema):
pass
# endregion Responses # endregion Responses

View File

@@ -1,3 +1,5 @@
import lexorank
import models.secondary import models.secondary
from typing import Union from typing import Union
import models.deal import models.deal
@@ -19,6 +21,14 @@ 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 _get_rank(self):
query = await self.session.execute(select(Deal.rank).order_by(Deal.rank.desc()))
result = query.scalar_one_or_none()
if not result:
return str(lexorank.Bucket.BUCEKT_0.next())
rank = lexorank.parse(result)
return str(rank.next())
async def change_status(self, deal: Deal, async def change_status(self, deal: Deal,
status: DealStatus, status: DealStatus,
user: User, user: User,
@@ -37,10 +47,12 @@ class DealService(BaseService):
return status_change return status_change
async def create(self, request: DealCreateRequest, user: User) -> DealCreateResponse: async def create(self, request: DealCreateRequest, user: User) -> DealCreateResponse:
rank = await self._get_rank()
deal = Deal( deal = Deal(
name=request.name, name=request.name,
created_at=datetime.datetime.now(), created_at=datetime.datetime.now(),
current_status=DealStatus.CREATED current_status=DealStatus.CREATED,
rank=rank
) )
self.session.add(deal) self.session.add(deal)
await self.session.flush() await self.session.flush()
@@ -60,11 +72,13 @@ class DealService(BaseService):
request.client_name, request.client_name,
ClientDetailsSchema(address=request.client_address)) ClientDetailsSchema(address=request.client_address))
await client_service.update_details(user, client, ClientDetailsSchema(address=request.client_address)) await client_service.update_details(user, client, ClientDetailsSchema(address=request.client_address))
rank = await self._get_rank()
deal = Deal( deal = Deal(
name=request.name, name=request.name,
created_at=datetime.datetime.now(), created_at=datetime.datetime.now(),
client_id=client.id, client_id=client.id,
current_status=DealStatus.CREATED current_status=DealStatus.CREATED,
rank=rank
) )
self.session.add(deal) self.session.add(deal)
await self.session.flush() await self.session.flush()
@@ -91,15 +105,25 @@ class DealService(BaseService):
.group_by(models.secondary.DealService.deal_id) .group_by(models.secondary.DealService.deal_id)
.subquery() .subquery()
) )
q = (select( q = (
Deal, select(
func.coalesce(service_subquery.c.total_price, 0) Deal,
func.coalesce(service_subquery.c.total_price, 0)
)
.order_by(
Deal.rank.desc()
)
.options(
selectinload(Deal.status_history),
joinedload(Deal.client)
)
.outerjoin(
service_subquery, Deal.id == service_subquery.c.deal_id)
.where(
Deal.is_deleted == False,
Deal.is_completed == False
)
) )
.options(selectinload(Deal.status_history),
joinedload(Deal.client))
.outerjoin(service_subquery, Deal.id == service_subquery.c.deal_id)
.where(Deal.is_deleted == False,
Deal.is_completed == False))
deals_query = await self.session.execute(q) deals_query = await self.session.execute(q)
summaries = [] summaries = []
for deal, total_price in deals_query.all(): for deal, total_price in deals_query.all():
@@ -112,7 +136,8 @@ class DealService(BaseService):
name=deal.name, name=deal.name,
changed_at=last_status.changed_at, changed_at=last_status.changed_at,
status=last_status.to_status, status=last_status.to_status,
total_price=total_price total_price=total_price,
rank=deal.rank
) )
) )
return DealSummaryResponse(summaries=summaries) return DealSummaryResponse(summaries=summaries)
@@ -156,6 +181,7 @@ class DealService(BaseService):
if not deal: if not deal:
raise HTTPException(status_code=404, detail="Сделка не найдена") raise HTTPException(status_code=404, detail="Сделка не найдена")
deal.name = request.data.name deal.name = request.data.name
deal.comment = request.data.comment
deal.is_deleted = request.data.is_deleted deal.is_deleted = request.data.is_deleted
deal.is_completed = request.data.is_completed deal.is_completed = request.data.is_completed
await self.session.commit() await self.session.commit()
@@ -164,6 +190,9 @@ class DealService(BaseService):
await self.session.rollback() await self.session.rollback()
return DealUpdateGeneralInfoResponse(ok=False, message=str(e)) return DealUpdateGeneralInfoResponse(ok=False, message=str(e))
async def reorder(self, request: DealSummaryReorderRequest, user: User) -> DealSummaryReorderResponse:
pass
# endregion # endregion
# region Deal services # region Deal services

View File

@@ -1,8 +1,17 @@
import string import string
import lexorank
def main(): def main():
pass prev = lexorank.middle(lexorank.Bucket.BUCEKT_0)
ranks = [prev]
for _ in range(1_000_000):
ranks.append(prev.next())
prev = ranks[-1]
print('generated')
sorted_ranks = list(sorted(ranks))
for idx in range(len(sorted_ranks)):
print(sorted_ranks[idx], ' ', ranks[idx])
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@@ -3,29 +3,12 @@ import asyncio
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from backend.session import session_maker from backend.session import session_maker
from migrations.env import run_async_migrations
from models import Product, ProductBarcode from models import Product, ProductBarcode
async def main(session: AsyncSession): async def main(session: AsyncSession):
client_ids = [8, 18] await run_async_migrations()
for client_id in client_ids:
for i in range(1, 500 + 1):
product = Product(
name=f"Товар №{i}",
article=f"Ариткул товара №{i}",
client_id=client_id
)
session.add(product)
await session.flush()
for j in range(1, 5 + 1):
barcode = ProductBarcode(
barcode=f"Штрихкод №{j} для товара №{i}",
product_id=product.id
)
session.add(barcode)
await session.flush()
await session.commit()
async def preload(): async def preload():
async with session_maker() as session: async with session_maker() as session: