This commit is contained in:
2024-05-09 01:32:37 +03:00
parent 3e83cf6f92
commit 61d27d2389
16 changed files with 179 additions and 115 deletions

View File

@@ -1,21 +1,21 @@
from abc import abstractmethod, ABC
from .article_attribute_writer import ArticleAttributeWriter
from .name_attribute_writer import NameAttributeWriter
from ..barcode import Barcode
class BaseAttributeWriter(ABC):
@abstractmethod
def write(self, barcode: Barcode):
pass
class AttributeWriterFactory:
@staticmethod
def get_writer(key: str):
match key:
case 'name':
return NameAttributeWriter()
case 'article':
return ArticleAttributeWriter()
# from abc import abstractmethod, ABC
#
# from .article_attribute_writer import ArticleAttributeWriter
# from .name_attribute_writer import NameAttributeWriter
# from ..barcode import Barcode
#
#
# class BaseAttributeWriter(ABC):
# @abstractmethod
# def write(self, barcode: Barcode):
# pass
#
#
# class AttributeWriterFactory:
# @staticmethod
# def get_writer(key: str):
# match key:
# case 'name':
# return NameAttributeWriter()
# case 'article':
# return ArticleAttributeWriter()

View File

@@ -1,7 +1,7 @@
from barcodes.attributes import BaseAttributeWriter
from barcodes.barcode import Barcode
class ArticleAttributeWriter(BaseAttributeWriter):
def write(self, barcode: Barcode):
pass
# from barcodes.attributes import BaseAttributeWriter
# from barcodes.barcode import Barcode
#
#
# class ArticleAttributeWriter(BaseAttributeWriter):
# def write(self, barcode: Barcode):
# pass

View File

@@ -1,7 +1,7 @@
from barcodes.attributes import BaseAttributeWriter
from barcodes.barcode import Barcode
class NameAttributeWriter(BaseAttributeWriter):
def write(self, barcode: Barcode):
pass
# from barcodes.attributes import BaseAttributeWriter
# from barcodes.barcode import Barcode
#
#
# class NameAttributeWriter(BaseAttributeWriter):
# def write(self, barcode: Barcode):
# pass

View File

@@ -1,15 +1,15 @@
from .attributes import AttributeWriterFactory
from models import ProductBarcode, BarcodeTemplate, BarcodeTemplateAttribute
class Barcode:
def __init__(self, session, barcode: ProductBarcode):
self.session = session
self.barcode = barcode
def render(self, template: BarcodeTemplate):
for attribute in template.attributes:
attribute: BarcodeTemplateAttribute
writer = AttributeWriterFactory.get_writer(attribute.key)
writer.write(self)
# from .attributes import AttributeWriterFactory
# from models import ProductBarcode, BarcodeTemplate, BarcodeTemplateAttribute
#
#
# class Barcode:
# def __init__(self, session, barcode: ProductBarcode):
# self.session = session
# self.barcode = barcode
#
# def render(self, template: BarcodeTemplate):
# for attribute in template.attributes:
# attribute: BarcodeTemplateAttribute
# writer = AttributeWriterFactory.get_writer(attribute.key)
# writer.write(self)
#

View File

@@ -1,6 +1,6 @@
from models import ProductBarcode
class BarcodeGenerator:
def __init__(self, barcode: ProductBarcode):
self.barcode = barcode
# from models import ProductBarcode
#
#
# class BarcodeGenerator:
# def __init__(self, barcode: ProductBarcode):
# self.barcode = barcode

View File

@@ -1,7 +1,7 @@
from sqlalchemy import Integer, Column, String, Boolean
from sqlalchemy import Integer, Column, String, Boolean, ForeignKey
from sqlalchemy.orm import relationship
from models import BaseModel
from models import BaseModel, barcode_template_attribute_link
class BarcodeTemplateAttribute(BaseModel):
@@ -11,14 +11,31 @@ class BarcodeTemplateAttribute(BaseModel):
name = Column(String, nullable=False, index=True, comment='Метка атрибута')
class BarcodeTemplateAdditionalField(BaseModel):
__tablename__ = 'barcode_template_additional_fields'
id = Column(Integer, autoincrement=True, primary_key=True, index=True)
name = Column(String, nullable=False)
value = Column(String, nullable=False)
barcode_template_id = Column(Integer, ForeignKey('barcode_templates.id'), nullable=False)
barcode_template = relationship('BarcodeTemplate', back_populates='additional_fields')
class BarcodeTemplate(BaseModel):
__tablename__ = 'barcode_templates'
id = Column(Integer, autoincrement=True, primary_key=True, index=True)
name = Column(String, nullable=False, index=True, comment='Название шаблона')
attributes = relationship('BarcodeTemplateAttributeLink',
attributes = relationship('BarcodeTemplateAttribute',
secondary=barcode_template_attribute_link,
# back_populates='barcode_template',
# cascade="all, delete-orphan",
lazy='selectin'
)
additional_fields = relationship('BarcodeTemplateAdditionalField',
back_populates='barcode_template',
cascade="all, delete-orphan",
lazy='joined')
lazy='selectin'
)
is_default = Column(Boolean, nullable=False, default=False, comment='По умолчанию')
# size

View File

@@ -14,7 +14,7 @@ class Client(BaseModel):
details = relationship('ClientDetails', uselist=False, back_populates='client', cascade='all, delete')
barcode_template_id = Column(Integer, ForeignKey('barcode_templates.id'), nullable=True)
barcode_template = relationship('BarcodeTemplate')
barcode_template = relationship('BarcodeTemplate', lazy='selectin')
class ClientDetails(BaseModel):

View File

@@ -1,10 +1,9 @@
from enum import IntEnum, unique
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Boolean, Sequence
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Boolean
from sqlalchemy.orm import relationship, backref
from models.base import BaseModel, metadata
from models.utils import add_sequence_to_model
from models.base import BaseModel
@unique

View File

@@ -1,11 +1,7 @@
from sqlalchemy import Column, Integer, String, ForeignKey, Sequence
from sqlalchemy.orm import relationship
from models import BaseModel, metadata
deal_rank_seq = Sequence('test_ochko', start=1, increment=1, metadata=metadata)
sequence = Sequence('my_sequence_name')
from models import BaseModel
class Product(BaseModel):

View File

@@ -33,18 +33,26 @@ class DealProduct(BaseModel):
quantity = Column(Integer, nullable=False, comment='Кол-во продукта')
class BarcodeTemplateAttributeLink(BaseModel):
__tablename__ = 'barcode_template_attributes_links'
barcode_template_id = Column(Integer,
ForeignKey('barcode_templates.id'),
nullable=False,
comment='ID Шаблона ШК',
primary_key=True)
barcode_template = relationship('BarcodeTemplate', back_populates='attributes')
attribute_id = Column(Integer,
ForeignKey('barcode_template_attributes.id'),
nullable=False,
comment='ID Атрибута',
primary_key=True)
attribute = relationship('BarcodeTemplateAttribute')
# class BarcodeTemplateAttributeLink(BaseModel):
# __tablename__ = 'barcode_template_attributes_links'
# barcode_template_id = Column(Integer,
# ForeignKey('barcode_templates.id'),
# nullable=False,
# comment='ID Шаблона ШК',
# primary_key=True)
# barcode_template = relationship('BarcodeTemplate',
# # back_populates='attributes'
# )
#
# attribute_id = Column(Integer,
# ForeignKey('barcode_template_attributes.id'),
# nullable=False,
# comment='ID Атрибута',
# primary_key=True)
# attribute = relationship('BarcodeTemplateAttribute')
barcode_template_attribute_link = Table(
'barcode_template_attribute_links',
BaseModel.metadata,
Column('barcode_template_id', ForeignKey('barcode_templates.id')),
Column('attribute_id', ForeignKey('barcode_template_attributes.id'))
)

View File

@@ -10,7 +10,8 @@ from schemas.barcode import (GetBarcodeTemplateByIdResponse,
BarcodeTemplateCreateRequest, GetAllBarcodeTemplateAttributesResponse,
CreateBarcodeTemplateAttributeResponse, CreateBarcodeTemplateAttributeRequest,
BarcodeTemplateUpdateResponse, BarcodeTemplateUpdateRequest,
GetAllBarcodeTemplatesResponse)
GetAllBarcodeTemplatesResponse, BarcodeTemplateDeleteRequest,
BarcodeTemplateDeleteResponse)
from services.barcode import BarcodeService
barcode_router = APIRouter(
@@ -67,6 +68,18 @@ async def update_barcode_template(
return await BarcodeService(session).update_barcode_template(request)
@barcode_router.post(
'/template/delete',
response_model=BarcodeTemplateDeleteResponse,
operation_id='delete_barcode_template'
)
async def delete_barcode_template(
request: BarcodeTemplateDeleteRequest,
session: Annotated[AsyncSession, Depends(get_session)]
):
return await BarcodeService(session).delete_template(request)
# endregion
# region Template attributes

View File

@@ -40,6 +40,10 @@ class CreateBarcodeTemplateAttributeRequest(CustomModelCamel):
label: str
class BarcodeTemplateDeleteRequest(CustomModelCamel):
id: int
# endregion
# region Responses
@@ -66,4 +70,8 @@ class GetAllBarcodeTemplatesResponse(CustomModelCamel):
class GetAllBarcodeTemplateAttributesResponse(CustomModelCamel):
attributes: list[BarcodeTemplateAttributeSchema]
class BarcodeTemplateDeleteResponse(OkMessageSchema):
pass
# endregion

View File

@@ -2,6 +2,7 @@ from typing import List
from pydantic import validator, field_validator
from schemas.barcode import BarcodeTemplateSchema
from schemas.base import CustomModelCamel, OkMessageSchema
@@ -20,6 +21,7 @@ class ClientDetailsSchema(CustomModelCamel):
class ClientSchema(CustomModelCamel):
id: int
name: str
barcode_template: BarcodeTemplateSchema | None = None
details: ClientDetailsSchema | None = None

View File

@@ -1,13 +1,15 @@
from sqlalchemy import select, update
from sqlalchemy import select, update, insert
from sqlalchemy.orm import selectinload
from models import BarcodeTemplate, BarcodeTemplateAttribute, BarcodeTemplateAttributeLink
from models import BarcodeTemplate, BarcodeTemplateAttribute, barcode_template_attribute_link
from schemas.barcode import (GetBarcodeTemplateByIdRequest,
GetBarcodeTemplateByIdResponse,
BarcodeTemplateCreateResponse,
BarcodeTemplateCreateRequest, CreateBarcodeTemplateAttributeRequest,
BarcodeTemplateUpdateResponse, BarcodeTemplateUpdateRequest,
BarcodeTemplateAttributeSchema, GetAllBarcodeTemplateAttributesResponse,
GetAllBarcodeTemplatesResponse)
GetAllBarcodeTemplatesResponse, BarcodeTemplateDeleteRequest,
BarcodeTemplateDeleteResponse)
from services.base import BaseService
@@ -23,7 +25,12 @@ class BarcodeService(BaseService):
return query.scalar()
async def get_all_barcode_templates(self) -> GetAllBarcodeTemplatesResponse:
stmt = select(BarcodeTemplate).order_by(BarcodeTemplate.id)
stmt = (
select(BarcodeTemplate)
.options(
selectinload(BarcodeTemplate.attributes)
)
.order_by(BarcodeTemplate.id))
query = await self.session.execute(stmt)
templates = query.scalars().all()
return GetAllBarcodeTemplatesResponse(templates=templates)
@@ -43,10 +50,12 @@ class BarcodeService(BaseService):
raise ValueError('Шаблон с таким именем уже существует')
# create template then add attributes
template = BarcodeTemplate(name=request.name, is_default=request.is_default)
request_dict = request.dict()
del request_dict['attribute_ids']
template = BarcodeTemplate(**request_dict)
self.session.add(template)
await self.session.flush()
await self.session.refresh(template)
# get all attributes from database
stmt = select(BarcodeTemplateAttribute).filter(
BarcodeTemplateAttribute.id.in_(request.attribute_ids))
@@ -55,12 +64,7 @@ class BarcodeService(BaseService):
# add attributes to template
for attribute in attributes:
template_attribute_link = BarcodeTemplateAttributeLink(
barcode_template_id=template.id,
attribute_id=attribute.id
)
self.session.add(template_attribute_link)
await self.session.flush()
template.attributes.append(attribute)
await self.session.commit()
return BarcodeTemplateCreateResponse(message='Шаблон успешно создан',
ok=True,
@@ -97,24 +101,22 @@ class BarcodeService(BaseService):
)
# difference deleted and new
template_attributes = set([attribute.attribute_id for attribute in template.attributes])
template_attributes = set([attribute.id for attribute in template.attributes])
request_attributes = set(request.attribute_ids)
new_attributes = request_attributes.difference(template_attributes)
deleted_attributes = template_attributes.difference(request_attributes)
new_attribute_ids = request_attributes.difference(template_attributes)
deleted_attribute_ids = template_attributes.difference(request_attributes)
# delete attributes
for attribute in template.attributes:
if attribute.attribute_id not in deleted_attributes:
if attribute.id not in deleted_attribute_ids:
continue
await self.session.delete(attribute)
# add new attributes
for new_attribute in new_attributes:
template_attribute_link = BarcodeTemplateAttributeLink(
barcode_template_id=template.id,
attribute_id=new_attribute
)
self.session.add(template_attribute_link)
template.attributes.remove(attribute)
for new_attribute_id in new_attribute_ids:
stmt = insert(barcode_template_attribute_link).values({
'barcode_template_id': template.id,
'attribute_id': new_attribute_id
})
await self.session.execute(stmt)
await self.session.flush()
await self.session.commit()
@@ -125,6 +127,15 @@ class BarcodeService(BaseService):
return BarcodeTemplateUpdateResponse(message=str(e),
ok=False)
async def delete_template(self, request: BarcodeTemplateDeleteRequest) -> BarcodeTemplateDeleteResponse:
try:
template = await self.session.get(BarcodeTemplate, request.id)
await self.session.delete(template)
await self.session.commit()
return BarcodeTemplateDeleteResponse(ok=True, message='Шаблон успешно удален')
except Exception as e:
return BarcodeTemplateDeleteResponse(ok=False, message=str(e))
# endregion
# region Template attributes

View File

@@ -91,7 +91,17 @@ class ClientService(BaseService):
client = await self.get_by_id(request.data.id)
if not client:
return ClientUpdateResponse(ok=False, message='Клиент не найден')
await self.session.execute(update(Client).where(Client.id == client.id).values(name=request.data.name))
request_dict = request.data.dict()
del request_dict['id']
del request_dict['details']
del request_dict['barcode_template']
request_dict['barcode_template_id'] = request.data.barcode_template.id
stmt = (
update(Client)
.where(Client.id == client.id)
.values(**request_dict)
)
await self.session.execute(stmt)
await self.update_details(user, client, request.data.details)
await self.session.commit()
return ClientUpdateResponse(ok=True, message='Клиент обновлен')

View File

@@ -21,7 +21,7 @@ class DealService(BaseService):
async def _get_deal_by_id(self, deal_id) -> Union[Deal, None]:
return await self.session.get(Deal, deal_id)
async def _get_rank_for_deal(self, deal_status: DealStatus) -> int:
async def _get_rank_for_deal(self, deal_status: DealStatus) -> str:
deal_query = await self.session.execute(
select(Deal).where(Deal.current_status == deal_status).order_by(Deal.lexorank.desc()).limit(1))
deal = deal_query.scalar_one_or_none()
@@ -35,7 +35,7 @@ class DealService(BaseService):
user: User,
deadline: datetime.datetime = None,
rank=None,
comment: str = '') -> DealStatusHistory:
comment: str = ''):
if not deal.current_status == status:
deadline = deadline
status_change = DealStatusHistory(