fix: applied timezone to default values, removed value nesting
This commit is contained in:
@ -98,19 +98,9 @@ class AttributeValue(BaseModel):
|
|||||||
)
|
)
|
||||||
attribute: Mapped[Attribute] = relationship(
|
attribute: Mapped[Attribute] = relationship(
|
||||||
back_populates="values",
|
back_populates="values",
|
||||||
lazy="joined",
|
lazy="noload",
|
||||||
)
|
)
|
||||||
|
|
||||||
def set_value(self, value: Optional[dict | str | bool | int | float]):
|
|
||||||
if value is None:
|
|
||||||
return
|
|
||||||
self.value = {"value": value}
|
|
||||||
|
|
||||||
def get_value(self) -> Optional[dict | str | bool | int | float]:
|
|
||||||
if self.value is None:
|
|
||||||
return None
|
|
||||||
return self.value["value"]
|
|
||||||
|
|
||||||
|
|
||||||
class AttributeLabel(BaseModel):
|
class AttributeLabel(BaseModel):
|
||||||
__tablename__ = "attribute_labels"
|
__tablename__ = "attribute_labels"
|
||||||
@ -132,5 +122,5 @@ class AttributeLabel(BaseModel):
|
|||||||
)
|
)
|
||||||
attribute: Mapped[Attribute] = relationship(
|
attribute: Mapped[Attribute] = relationship(
|
||||||
backref="attribute_labels",
|
backref="attribute_labels",
|
||||||
lazy="joined",
|
lazy="noload",
|
||||||
)
|
)
|
||||||
|
|||||||
@ -24,8 +24,8 @@ dependencies = [
|
|||||||
"reportlab>=4.4.4",
|
"reportlab>=4.4.4",
|
||||||
"pathlib>=1.0.1",
|
"pathlib>=1.0.1",
|
||||||
"starlette>=0.47.2",
|
"starlette>=0.47.2",
|
||||||
"lexorank>=1.0.1",
|
|
||||||
"python-multipart>=0.0.20",
|
"python-multipart>=0.0.20",
|
||||||
|
"lexorank-py==0.1.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
from sqlalchemy import and_
|
from sqlalchemy import and_
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
|
|
||||||
@ -9,7 +11,11 @@ from models import (
|
|||||||
module_attribute,
|
module_attribute,
|
||||||
)
|
)
|
||||||
from repositories.mixins import *
|
from repositories.mixins import *
|
||||||
from schemas.attribute import CreateAttributeSchema, UpdateAttributeSchema, UpdateDealModuleAttributeSchema
|
from schemas.attribute import (
|
||||||
|
CreateAttributeSchema,
|
||||||
|
UpdateAttributeSchema,
|
||||||
|
UpdateDealModuleAttributeSchema,
|
||||||
|
)
|
||||||
from utils.exceptions import ForbiddenException
|
from utils.exceptions import ForbiddenException
|
||||||
|
|
||||||
|
|
||||||
@ -83,7 +89,18 @@ class AttributeRepository(
|
|||||||
self, deal_id: int, module_id: int
|
self, deal_id: int, module_id: int
|
||||||
) -> list[tuple[Attribute, AttributeValue, AttributeLabel]]:
|
) -> list[tuple[Attribute, AttributeValue, AttributeLabel]]:
|
||||||
stmt = (
|
stmt = (
|
||||||
select(Attribute, AttributeValue, AttributeLabel)
|
select(
|
||||||
|
Attribute,
|
||||||
|
AttributeValue,
|
||||||
|
AttributeLabel,
|
||||||
|
)
|
||||||
|
.join(
|
||||||
|
module_attribute,
|
||||||
|
and_(
|
||||||
|
module_attribute.c.attribute_id == Attribute.id,
|
||||||
|
module_attribute.c.module_id == module_id,
|
||||||
|
),
|
||||||
|
)
|
||||||
.outerjoin(
|
.outerjoin(
|
||||||
AttributeValue,
|
AttributeValue,
|
||||||
and_(
|
and_(
|
||||||
@ -99,25 +116,21 @@ class AttributeRepository(
|
|||||||
AttributeLabel.module_id == module_id,
|
AttributeLabel.module_id == module_id,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.join(
|
.where(
|
||||||
module_attribute,
|
Attribute.is_deleted.is_(False),
|
||||||
and_(
|
|
||||||
module_attribute.c.attribute_id == Attribute.id,
|
|
||||||
module_attribute.c.module_id == module_id,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result = await self.session.execute(stmt)
|
result = await self.session.execute(stmt)
|
||||||
return list(result.all())
|
return list(result.all())
|
||||||
|
|
||||||
async def _get_deal_attribute_values(
|
async def _get_deals_attribute_values(
|
||||||
self, deal_id: int, module_id: int
|
self, deal_ids: list[int], module_id: int
|
||||||
) -> list[AttributeValue]:
|
) -> list[AttributeValue]:
|
||||||
stmt = (
|
stmt = (
|
||||||
select(AttributeValue)
|
select(AttributeValue)
|
||||||
.join(Attribute, AttributeValue.attribute_id == Attribute.id)
|
.join(Attribute, AttributeValue.attribute_id == Attribute.id)
|
||||||
.where(
|
.where(
|
||||||
AttributeValue.deal_id == deal_id,
|
AttributeValue.deal_id.in_(deal_ids),
|
||||||
AttributeValue.module_id == module_id,
|
AttributeValue.module_id == module_id,
|
||||||
Attribute.is_deleted.is_(False),
|
Attribute.is_deleted.is_(False),
|
||||||
)
|
)
|
||||||
@ -125,22 +138,38 @@ class AttributeRepository(
|
|||||||
result = await self.session.execute(stmt)
|
result = await self.session.execute(stmt)
|
||||||
return list(result.scalars().all())
|
return list(result.scalars().all())
|
||||||
|
|
||||||
async def update_or_create_deal_attribute_values(
|
async def update_or_create_deals_attribute_values(
|
||||||
self,
|
self,
|
||||||
deal_id: int,
|
main_deal_id: int,
|
||||||
|
group_deal_ids: list[int],
|
||||||
module_id: int,
|
module_id: int,
|
||||||
attributes: list[UpdateDealModuleAttributeSchema],
|
attributes: list[UpdateDealModuleAttributeSchema],
|
||||||
):
|
):
|
||||||
old_deal_attribute_values: list[AttributeValue] = await self._get_deal_attribute_values(deal_id, module_id)
|
old_deal_attribute_values: list[
|
||||||
dict_old_attrs: dict[int, AttributeValue] = {obj.attribute_id: obj for obj in old_deal_attribute_values}
|
AttributeValue
|
||||||
|
] = await self._get_deals_attribute_values(group_deal_ids, module_id)
|
||||||
|
|
||||||
|
dict_old_attrs: dict[int, dict[int, AttributeValue]] = defaultdict(dict)
|
||||||
|
|
||||||
|
for deal_attribute in old_deal_attribute_values:
|
||||||
|
dict_old_attrs[deal_attribute.deal_id][deal_attribute.attribute_id] = (
|
||||||
|
deal_attribute
|
||||||
|
)
|
||||||
|
|
||||||
for attribute in attributes:
|
for attribute in attributes:
|
||||||
if attribute.attribute_id in dict_old_attrs:
|
if attribute.is_applicable_to_group:
|
||||||
# update
|
deal_ids_to_apply = group_deal_ids
|
||||||
attribute_value = dict_old_attrs[attribute.attribute_id]
|
else:
|
||||||
|
deal_ids_to_apply = [main_deal_id]
|
||||||
|
|
||||||
|
for deal_id in deal_ids_to_apply:
|
||||||
|
if attribute.attribute_id in dict_old_attrs[deal_id]:
|
||||||
|
attribute_value = dict_old_attrs[deal_id][attribute.attribute_id]
|
||||||
attribute_value.value = attribute.value
|
attribute_value.value = attribute.value
|
||||||
else:
|
else:
|
||||||
# create
|
if attribute.value is None:
|
||||||
|
continue
|
||||||
|
|
||||||
attribute_value = AttributeValue(
|
attribute_value = AttributeValue(
|
||||||
attribute_id=attribute.attribute_id,
|
attribute_id=attribute.attribute_id,
|
||||||
deal_id=deal_id,
|
deal_id=deal_id,
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class CreateAttributeSchema(BaseSchema):
|
|||||||
label: str
|
label: str
|
||||||
is_applicable_to_group: bool
|
is_applicable_to_group: bool
|
||||||
is_nullable: bool
|
is_nullable: bool
|
||||||
default_value: Optional[dict[str, Any]]
|
default_value: Optional[Any]
|
||||||
description: str
|
description: str
|
||||||
type_id: int
|
type_id: int
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ class UpdateAttributeSchema(BaseSchema):
|
|||||||
label: Optional[str] = None
|
label: Optional[str] = None
|
||||||
is_applicable_to_group: Optional[bool] = None
|
is_applicable_to_group: Optional[bool] = None
|
||||||
is_nullable: Optional[bool] = None
|
is_nullable: Optional[bool] = None
|
||||||
default_value: Optional[dict[str, Any]] = None
|
default_value: Optional[Any] = None
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
type: Optional[AttributeTypeSchema] = None
|
type: Optional[AttributeTypeSchema] = None
|
||||||
|
|
||||||
@ -44,9 +44,9 @@ class DealModuleAttributeSchema(BaseSchema):
|
|||||||
attribute_id: int
|
attribute_id: int
|
||||||
label: str
|
label: str
|
||||||
original_label: str
|
original_label: str
|
||||||
value: Optional[dict[str, Any]]
|
value: Optional[Any]
|
||||||
type: AttributeTypeSchema
|
type: AttributeTypeSchema
|
||||||
default_value: dict[str, Any]
|
default_value: Any
|
||||||
description: str
|
description: str
|
||||||
is_applicable_to_group: bool
|
is_applicable_to_group: bool
|
||||||
is_nullable: bool
|
is_nullable: bool
|
||||||
@ -54,7 +54,8 @@ class DealModuleAttributeSchema(BaseSchema):
|
|||||||
|
|
||||||
class UpdateDealModuleAttributeSchema(BaseSchema):
|
class UpdateDealModuleAttributeSchema(BaseSchema):
|
||||||
attribute_id: int
|
attribute_id: int
|
||||||
value: Optional[dict[str, Any]]
|
is_applicable_to_group: bool
|
||||||
|
value: Optional[Any] = None
|
||||||
|
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
@ -79,6 +80,7 @@ class UpdateAttributeLabelRequest(BaseSchema):
|
|||||||
class UpdateDealModuleAttributesRequest(BaseSchema):
|
class UpdateDealModuleAttributesRequest(BaseSchema):
|
||||||
attributes: list[UpdateDealModuleAttributeSchema]
|
attributes: list[UpdateDealModuleAttributeSchema]
|
||||||
|
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
# region Response
|
# region Response
|
||||||
@ -115,4 +117,5 @@ class GetDealModuleAttributesResponse(BaseSchema):
|
|||||||
class UpdateDealModuleAttributesResponse(BaseResponse):
|
class UpdateDealModuleAttributesResponse(BaseResponse):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
from models import Attribute, AttributeValue, AttributeLabel
|
from models import Attribute, AttributeValue, AttributeLabel
|
||||||
from repositories import AttributeRepository
|
from repositories import AttributeRepository, DealRepository
|
||||||
from schemas.attribute import *
|
from schemas.attribute import *
|
||||||
from services.mixins import *
|
from services.mixins import *
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ class AttributeService(
|
|||||||
attribute_id=attr.id,
|
attribute_id=attr.id,
|
||||||
label=attr_label.label if attr_label else attr.label,
|
label=attr_label.label if attr_label else attr.label,
|
||||||
original_label=attr.label,
|
original_label=attr.label,
|
||||||
value=attr_value.value if attr_value else attr.default_value,
|
value=attr_value.value if attr_value else None,
|
||||||
type=AttributeTypeSchema.model_validate(attr.type),
|
type=AttributeTypeSchema.model_validate(attr.type),
|
||||||
default_value=attr.default_value,
|
default_value=attr.default_value,
|
||||||
description=attr.description,
|
description=attr.description,
|
||||||
@ -57,7 +57,15 @@ class AttributeService(
|
|||||||
async def update_deal_module_attributes(
|
async def update_deal_module_attributes(
|
||||||
self, deal_id: int, module_id: int, request: UpdateDealModuleAttributesRequest
|
self, deal_id: int, module_id: int, request: UpdateDealModuleAttributesRequest
|
||||||
) -> UpdateDealModuleAttributesResponse:
|
) -> UpdateDealModuleAttributesResponse:
|
||||||
await self.repository.update_or_create_deal_attribute_values(
|
deal_repo = DealRepository(self.repository.session)
|
||||||
deal_id, module_id, request.attributes
|
deal = await deal_repo.get_by_id(deal_id)
|
||||||
|
if deal.group_id:
|
||||||
|
deals = await deal_repo.get_by_group_id(deal.group_id)
|
||||||
|
else:
|
||||||
|
deals = [deal]
|
||||||
|
|
||||||
|
group_deal_ids = [d.id for d in deals]
|
||||||
|
await self.repository.update_or_create_deals_attribute_values(
|
||||||
|
deal_id, group_deal_ids, module_id, request.attributes
|
||||||
)
|
)
|
||||||
return UpdateDealModuleAttributesResponse(message="Успешно сохранено")
|
return UpdateDealModuleAttributesResponse(message="Успешно сохранено")
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
from lexorank import lexorank
|
import lexorank
|
||||||
|
|
||||||
from models import DealGroup, Deal
|
from models import DealGroup, Deal
|
||||||
from repositories import DealGroupRepository, DealRepository, DealTagRepository
|
from repositories import DealGroupRepository, DealRepository, DealTagRepository
|
||||||
from schemas.deal_group import *
|
from schemas.deal_group import *
|
||||||
|
|||||||
11
uv.lock
generated
11
uv.lock
generated
@ -362,7 +362,6 @@ dependencies = [
|
|||||||
{ name = "fastapi-endpoints" },
|
{ name = "fastapi-endpoints" },
|
||||||
{ name = "fpdf" },
|
{ name = "fpdf" },
|
||||||
{ name = "gunicorn" },
|
{ name = "gunicorn" },
|
||||||
{ name = "lexorank" },
|
|
||||||
{ name = "orjson" },
|
{ name = "orjson" },
|
||||||
{ name = "pathlib" },
|
{ name = "pathlib" },
|
||||||
{ name = "pdfrw" },
|
{ name = "pdfrw" },
|
||||||
@ -393,7 +392,6 @@ requires-dist = [
|
|||||||
{ name = "fastapi-endpoints", git = "https://github.com/vladNed/fastapi-endpoints.git?rev=main" },
|
{ name = "fastapi-endpoints", git = "https://github.com/vladNed/fastapi-endpoints.git?rev=main" },
|
||||||
{ name = "fpdf", specifier = ">=1.7.2" },
|
{ name = "fpdf", specifier = ">=1.7.2" },
|
||||||
{ name = "gunicorn", specifier = ">=23.0.0" },
|
{ name = "gunicorn", specifier = ">=23.0.0" },
|
||||||
{ name = "lexorank", specifier = ">=1.0.1" },
|
|
||||||
{ name = "orjson", specifier = ">=3.11.1" },
|
{ name = "orjson", specifier = ">=3.11.1" },
|
||||||
{ name = "pathlib", specifier = ">=1.0.1" },
|
{ name = "pathlib", specifier = ">=1.0.1" },
|
||||||
{ name = "pdfrw", specifier = ">=0.4" },
|
{ name = "pdfrw", specifier = ">=0.4" },
|
||||||
@ -694,15 +692,6 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" },
|
{ url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lexorank"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/11/58/87b3ced0716ea1997315b6f690edbe52d38f8145c12e56c35e1b7cfe306e/lexorank-1.0.1.tar.gz", hash = "sha256:e84869f626ddf4295cc848fd639a76f87bb8a17b2f649aa1d6449a4c53530fd7", size = 1758, upload-time = "2022-05-25T22:07:16.683Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/37/d7/b7bde2527103aeb4ddfd02e13b689a2c2ead51971276b4633e24fbbbdc68/lexorank-1.0.1-py3-none-any.whl", hash = "sha256:3a734155866e7c52b2e0e11f92226d002e79b7442271bf969b513aa5278b65c5", size = 1804, upload-time = "2022-05-25T22:07:15.03Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mako"
|
name = "mako"
|
||||||
version = "1.3.10"
|
version = "1.3.10"
|
||||||
|
|||||||
Reference in New Issue
Block a user