From 89301d6432b0747948a6910281d179ad50375f22 Mon Sep 17 00:00:00 2001 From: Egor fureunoir Gorbunov Date: Tue, 8 Jul 2025 21:02:54 +0300 Subject: [PATCH] Features: 1) Add support for processing `chosen_products` in order creation and update mutations; 2) Introduce new field `chosen_products` to serializers and GraphQL inputs; 3) Enhance order model to allow bulk addition of products with quantity updates; Fixes: 1) Correct avatar resolution in `resolve_avatar` method for cases where `url` or `name` attributes are missing; 2) Refresh user object from the database after avatar update to avoid stale data; Extra: 1) Rename `BulkActionOrderProductInput` to `BulkProductInput` for consistency; 2) Minor code refactorings and adjustments for clarity. --- core/graphene/mutations.py | 9 ++++++--- core/graphene/object_types.py | 2 +- core/models.py | 10 +++++----- core/serializers/utility.py | 1 + core/viewsets.py | 1 + vibes_auth/graphene/mutations.py | 1 + vibes_auth/graphene/object_types.py | 7 ++++++- 7 files changed, 21 insertions(+), 10 deletions(-) diff --git a/core/graphene/mutations.py b/core/graphene/mutations.py index 385dc4d0..1ba0445e 100644 --- a/core/graphene/mutations.py +++ b/core/graphene/mutations.py @@ -13,7 +13,7 @@ from core.elasticsearch import process_query from core.graphene import BaseMutation from core.graphene.object_types import ( AddressType, - BulkActionOrderProductInput, + BulkProductInput, OrderType, ProductType, SearchResultsType, @@ -182,6 +182,7 @@ class BuyOrder(BaseMutation): promocode_uuid = String(required=False) shipping_address = String(required=False) billing_address = String(required=False) + chosen_products = List(BulkProductInput, required=False) order = Field(OrderType, required=False) transaction = Field(TransactionType, required=False) @@ -197,6 +198,7 @@ class BuyOrder(BaseMutation): promocode_uuid=None, shipping_address=None, billing_address=None, + chosen_products=None, ): if not any([order_uuid, order_hr_id]) or all([order_uuid, order_hr_id]): raise BadRequest(_("please provide either order_uuid or order_hr_id - mutually exclusive")) @@ -215,6 +217,7 @@ class BuyOrder(BaseMutation): promocode_uuid=promocode_uuid, shipping_address=shipping_address, billing_address=billing_address, + chosen_products=chosen_products, ) match str(type(instance)): @@ -237,7 +240,7 @@ class BulkOrderAction(BaseMutation): order_uuid = UUID(required=False) order_hr_id = String(required=False) action = String(required=True, description=_("remove/add")) - products = List(BulkActionOrderProductInput, required=True) + products = List(BulkProductInput, required=True) order = Field(OrderType, required=False) @@ -283,7 +286,7 @@ class BulkWishlistAction(BaseMutation): class Arguments: wishlist_uuid = UUID(required=False) action = String(required=True, description="remove/add") - products = List(BulkActionOrderProductInput, required=True) + products = List(BulkProductInput, required=True) wishlist = Field(WishlistType, required=False) diff --git a/core/graphene/object_types.py b/core/graphene/object_types.py index c93c0aef..583c72e1 100644 --- a/core/graphene/object_types.py +++ b/core/graphene/object_types.py @@ -566,6 +566,6 @@ class SearchResultsType(ObjectType): posts = List(description=_("posts search results"), of_type=SearchPostsResultsType) -class BulkActionOrderProductInput(InputObjectType): +class BulkProductInput(InputObjectType): uuid = UUID(required=True) attributes = GenericScalar(required=False) diff --git a/core/models.py b/core/models.py index 6227b25d..00ab49fc 100644 --- a/core/models.py +++ b/core/models.py @@ -1579,7 +1579,7 @@ class Order(ExportModelOperationsMixin("order"), NiceModel): # type: ignore [mi if chosen_products: order = Order.objects.create(status="MOMENTAL", user=self.user) - order.bulk_add_products(chosen_products) + order.bulk_add_products(chosen_products, update_quantity=True) if config.DISABLED_COMMERCE: raise DisabledCommerceError(_("you can not buy at this moment, please try again in a few minutes")) @@ -1713,19 +1713,19 @@ class Order(ExportModelOperationsMixin("order"), NiceModel): # type: ignore [mi def update_order_products_statuses(self, status: str = "PENDING"): self.order_products.update(status=status) - def bulk_add_products(self, products: list[dict[str, Any]]): + def bulk_add_products(self, products: list[dict[str, Any]], update_quantity: bool = False): for product in products: self.add_product( - product.get("uuid"), + product.get("uuid") or product.get("product_uuid"), attributes=product.get("attributes"), - update_quantity=False, + update_quantity=update_quantity, ) return self def bulk_remove_products(self, products: list): for product in products: self.remove_product( - product.get("uuid"), + product.get("uuid") or product.get("product_uuid"), attributes=product.get("attributes"), zero_quantity=True, ) diff --git a/core/serializers/utility.py b/core/serializers/utility.py index ca4e6df1..eae2cf21 100644 --- a/core/serializers/utility.py +++ b/core/serializers/utility.py @@ -160,6 +160,7 @@ class BuyOrderSerializer(Serializer): promocode_uuid = CharField(required=False) shipping_address_uuid = CharField(required=False) billing_address_uuid = CharField(required=False) + chosen_products = ListField(child=AddOrderProductSerializer(), required=False) class BuyUnregisteredOrderSerializer(Serializer): diff --git a/core/viewsets.py b/core/viewsets.py index 31da5b55..53bd1abe 100644 --- a/core/viewsets.py +++ b/core/viewsets.py @@ -585,6 +585,7 @@ class OrderViewSet(EvibesViewSet): promocode_uuid=serializer.validated_data.get("promocode_uuid"), shipping_address=serializer.validated_data.get("shipping_address_uuid"), billing_address=serializer.validated_data.get("billing_address_uuid"), + chosen_products=serializer.validated_data.get("chosen_products"), ) match str(type(instance)): case "": diff --git a/vibes_auth/graphene/mutations.py b/vibes_auth/graphene/mutations.py index 8b5b0fb1..7a1a01ba 100644 --- a/vibes_auth/graphene/mutations.py +++ b/vibes_auth/graphene/mutations.py @@ -338,6 +338,7 @@ class UploadAvatar(BaseMutation): try: info.context.user.avatar = avatar info.context.user.save() + info.context.user.refresh_from_db() except Exception as e: raise BadRequest(str(e)) from e diff --git a/vibes_auth/graphene/object_types.py b/vibes_auth/graphene/object_types.py index 5eeced8f..a91ca2b3 100644 --- a/vibes_auth/graphene/object_types.py +++ b/vibes_auth/graphene/object_types.py @@ -97,7 +97,12 @@ class UserType(DjangoObjectType): def resolve_avatar(self: User, info) -> str: if self.avatar: - return info.context.build_absolute_uri(self.avatar.url) + if hasattr(self.avatar, "url"): + return info.context.build_absolute_uri(self.avatar.url) + elif hasattr(self.avatar, "name"): + return info.context.build_absolute_uri(f"/media/{self.avatar.name}") + else: + return info.context.build_absolute_uri(f"/media/{self.avatar}") else: return ""