diff --git a/src/Model/Cart/CartWatcherFacade.php b/src/Model/Cart/CartWatcherFacade.php index 7ea32f86d..cfe74831a 100644 --- a/src/Model/Cart/CartWatcherFacade.php +++ b/src/Model/Cart/CartWatcherFacade.php @@ -4,7 +4,6 @@ namespace Shopsys\FrontendApiBundle\Model\Cart; -use DateTime; use Doctrine\ORM\EntityManagerInterface; use Shopsys\FrameworkBundle\Component\Domain\Domain; use Shopsys\FrameworkBundle\Model\Cart\Cart; @@ -51,7 +50,6 @@ public function getCheckedCartWithModifications(Cart $cart): CartWithModificatio $this->checkRemovedProductsItems($cart); $this->checkNotListableItems($cart); - $this->checkUnavailableStockQuantityItems($cart); $this->checkModifiedPrices($cart); $this->checkPromoCodeValidity($cart); @@ -102,39 +100,6 @@ protected function checkNotListableItems(Cart $cart): void } } - /** - * @param \Shopsys\FrameworkBundle\Model\Cart\Cart $cart - */ - protected function checkUnavailableStockQuantityItems(Cart $cart): void - { - foreach ($cart->getItems() as $cartItem) { - $product = $cartItem->getProduct(); - - if ($product === null) { - continue; - } - - $maximumOrderQuantity = $this->productAvailabilityFacade->getGroupedStockQuantityByProductAndDomainId($product, $this->domain->getId()); - - if ($maximumOrderQuantity === 0) { - $cart->removeItemById($cartItem->getId()); - $this->cartWithModificationsResult->addNoLongerAvailableCartItemDueToQuantity($cartItem); - - continue; - } - - if ($cartItem->getQuantity() <= $maximumOrderQuantity) { - continue; - } - - $cartItem->changeQuantity($maximumOrderQuantity); - $cartItem->changeAddedAt(new DateTime()); - $this->em->persist($cartItem); - - $this->cartWithModificationsResult->addCartItemWithChangedQuantity($cartItem); - } - } - /** * @param \Shopsys\FrameworkBundle\Model\Cart\Cart $cart */ diff --git a/src/Model/Cart/CartWithModificationsResult.php b/src/Model/Cart/CartWithModificationsResult.php index dede9c188..fe5592b68 100644 --- a/src/Model/Cart/CartWithModificationsResult.php +++ b/src/Model/Cart/CartWithModificationsResult.php @@ -31,8 +31,6 @@ class CartWithModificationsResult protected array $itemModifications = [ 'noLongerListableCartItems' => [], 'cartItemsWithModifiedPrice' => [], - 'cartItemsWithChangedQuantity' => [], - 'noLongerAvailableCartItemsDueToQuantity' => [], ]; /** @@ -132,22 +130,6 @@ public function addCartItemWithModifiedPrice(CartItem $cartItem): void $this->itemModifications['cartItemsWithModifiedPrice'][] = $cartItem; } - /** - * @param \Shopsys\FrameworkBundle\Model\Cart\Item\CartItem $cartItem - */ - public function addCartItemWithChangedQuantity(CartItem $cartItem): void - { - $this->itemModifications['cartItemsWithChangedQuantity'][] = $cartItem; - } - - /** - * @param \Shopsys\FrameworkBundle\Model\Cart\Item\CartItem $cartItem - */ - public function addNoLongerAvailableCartItemDueToQuantity(CartItem $cartItem): void - { - $this->itemModifications['noLongerAvailableCartItemsDueToQuantity'][] = $cartItem; - } - public function setCartHasRemovedProducts(): void { $this->cartModifications['someProductWasRemovedFromEshop'] = true; @@ -390,9 +372,7 @@ protected function isPromoCodeInCartValid(): bool protected function isSomeCartItemModified(): bool { return count($this->itemModifications['noLongerListableCartItems']) > 0 - || count($this->itemModifications['cartItemsWithModifiedPrice']) > 0 - || count($this->itemModifications['cartItemsWithChangedQuantity']) > 0 - || count($this->itemModifications['noLongerAvailableCartItemsDueToQuantity']) > 0; + || count($this->itemModifications['cartItemsWithModifiedPrice']) > 0; } /** diff --git a/src/Model/Mutation/Cart/CartMutation.php b/src/Model/Mutation/Cart/CartMutation.php index 96512d295..c7eb9d3c7 100644 --- a/src/Model/Mutation/Cart/CartMutation.php +++ b/src/Model/Mutation/Cart/CartMutation.php @@ -117,7 +117,6 @@ public function addOrderItemsToCartMutation( } $notAddedProducts = []; - $addProductResults = []; foreach ($order->getProductItems() as $orderItem) { if ($orderItem->getProduct() === null) { @@ -125,7 +124,7 @@ public function addOrderItemsToCartMutation( } try { - $addProductResults[] = $this->cartApiFacade->addProductByUuidToCart($orderItem->getProduct()->getUuid(), $orderItem->getQuantity(), false, $cart); + $this->cartApiFacade->addProductByUuidToCart($orderItem->getProduct()->getUuid(), $orderItem->getQuantity(), false, $cart); } catch (InvalidCartItemUserError) { $notAddedProducts[] = $orderItem->getProduct(); } @@ -134,12 +133,6 @@ public function addOrderItemsToCartMutation( $cartWithModificationsResult = $this->cartWatcherFacade->getCheckedCartWithModifications($cart); $cartWithModificationsResult->addProductsNotAddedByMultipleAddition($notAddedProducts); - foreach ($addProductResults as $addProductResult) { - if ($addProductResult->getNotOnStockQuantity() > 0) { - $cartWithModificationsResult->addCartItemWithChangedQuantity($addProductResult->getCartItem()); - } - } - return $cartWithModificationsResult; } } diff --git a/src/Model/Resolver/Products/DataMapper/ProductArrayFieldMapper.php b/src/Model/Resolver/Products/DataMapper/ProductArrayFieldMapper.php index d649c5d3a..6eecce496 100644 --- a/src/Model/Resolver/Products/DataMapper/ProductArrayFieldMapper.php +++ b/src/Model/Resolver/Products/DataMapper/ProductArrayFieldMapper.php @@ -263,4 +263,55 @@ public function getProductType(array $data): string { return $data['product_type']; } + + /** + * @param array $data + * @return string|null + */ + public function getNamePrefix(array $data): ?string + { + return $data['name_prefix']; + } + + /** + * @param array $data + * @return string|null + */ + public function getNameSuffix(array $data): ?string + { + return $data['name_suffix']; + } + + /** + * @param array $data + * @return string + */ + public function getFullname(array $data): string + { + return trim( + $data['name_prefix'] + . ' ' + . $data['name'] + . ' ' + . $data['name_suffix'], + ); + } + + /** + * @param array $data + * @return array + */ + public function getStoreAvailabilities(array $data): array + { + return $data['store_availabilities_information']; + } + + /** + * @param array $data + * @return int|null + */ + public function getAvailableStoresCount(array $data): ?int + { + return $data['available_stores_count']; + } } diff --git a/src/Model/Resolver/Products/DataMapper/ProductEntityFieldMapper.php b/src/Model/Resolver/Products/DataMapper/ProductEntityFieldMapper.php index 130f2ad07..5f42a8122 100644 --- a/src/Model/Resolver/Products/DataMapper/ProductEntityFieldMapper.php +++ b/src/Model/Resolver/Products/DataMapper/ProductEntityFieldMapper.php @@ -241,4 +241,77 @@ public function getProductType(Product $product): string { return $product->getProductType(); } + + /** + * @param \Shopsys\FrameworkBundle\Model\Product\Product $product + * @return string|null + */ + public function getNameSuffix(Product $product): ?string + { + return $product->getNameSuffix($this->domain->getLocale()); + } + + /** + * @param \Shopsys\FrameworkBundle\Model\Product\Product $product + * @return string|null + */ + public function getNamePrefix(Product $product): ?string + { + return $product->getNamePrefix($this->domain->getLocale()); + } + + /** + * @param \Shopsys\FrameworkBundle\Model\Product\Product $product + * @return string + */ + public function getFullName(Product $product): string + { + return $product->getFullName($this->domain->getLocale()); + } + + /** + * @param \Shopsys\FrameworkBundle\Model\Product\Product $product + * @return int|null + */ + public function getStockQuantity(Product $product): ?int + { + return $this->productAvailabilityFacade->getGroupedStockQuantityByProductAndDomainId($product, $this->domain->getId()); + } + + /** + * @param \Shopsys\FrameworkBundle\Model\Product\Product $product + * @return array + */ + public function getStoreAvailabilities(Product $product): array + { + $storeAvailabilitiesInformation = $this->productAvailabilityFacade->getProductStoresAvailabilitiesInformationByDomainIdIndexedByStoreId( + $product, + $this->domain->getId(), + ); + + $result = []; + + foreach ($storeAvailabilitiesInformation as $storeAvailabilityInformation) { + $result[] = [ + 'store_name' => $storeAvailabilityInformation->getStoreName(), + 'store_id' => $storeAvailabilityInformation->getStoreId(), + 'availability_information' => $storeAvailabilityInformation->getAvailabilityInformation(), + 'availability_status' => $storeAvailabilityInformation->getAvailabilityStatus(), + ]; + } + + return $result; + } + + /** + * @param \Shopsys\FrameworkBundle\Model\Product\Product $product + * @return int|null + */ + public function getAvailableStoresCount(Product $product): ?int + { + return $this->productAvailabilityFacade->getAvailableStoresCount( + $product, + $this->domain->getId(), + ); + } } diff --git a/src/Resources/config/graphql-types/EnumType/AvailabilityStatusEnumDecorator.types.yaml b/src/Resources/config/graphql-types/EnumType/AvailabilityStatusEnumDecorator.types.yaml new file mode 100644 index 000000000..8833e12fb --- /dev/null +++ b/src/Resources/config/graphql-types/EnumType/AvailabilityStatusEnumDecorator.types.yaml @@ -0,0 +1,12 @@ +AvailabilityStatusEnumDecorator: + type: enum + decorator: true + config: + description: "Product Availability statuses" + values: + InStock: + value: '@=constant("Shopsys\\FrameworkBundle\\Model\\Product\\Availability\\AvailabilityStatusEnum::IN_STOCK")' + description: "Product availability status in stock" + OutOfStock: + value: '@=constant("Shopsys\\FrameworkBundle\\Model\\Product\\Availability\\AvailabilityStatusEnum::OUT_OF_STOCK")' + description: "Product availability status out of stock" diff --git a/src/Resources/config/graphql-types/ModelType/Cart/CartItemModificationsResultDecorator.types.yaml b/src/Resources/config/graphql-types/ModelType/Cart/CartItemModificationsResultDecorator.types.yaml index ceb64a6b6..b4b297771 100644 --- a/src/Resources/config/graphql-types/ModelType/Cart/CartItemModificationsResultDecorator.types.yaml +++ b/src/Resources/config/graphql-types/ModelType/Cart/CartItemModificationsResultDecorator.types.yaml @@ -7,7 +7,3 @@ CartItemModificationsResultDecorator: type: "[CartItem!]!" cartItemsWithModifiedPrice: type: "[CartItem!]!" - cartItemsWithChangedQuantity: - type: "[CartItem!]!" - noLongerAvailableCartItemsDueToQuantity: - type: "[CartItem!]!" diff --git a/src/Resources/config/graphql-types/ModelType/Product/Availability/AvailabilityDecorator.types.yaml b/src/Resources/config/graphql-types/ModelType/Product/Availability/AvailabilityDecorator.types.yaml index 9da75d176..6fb471443 100644 --- a/src/Resources/config/graphql-types/ModelType/Product/Availability/AvailabilityDecorator.types.yaml +++ b/src/Resources/config/graphql-types/ModelType/Product/Availability/AvailabilityDecorator.types.yaml @@ -5,5 +5,8 @@ AvailabilityDecorator: description: "Represents an availability" fields: name: - type: "String" + type: "String!" description: "Localized availability name (domain dependent)" + status: + type: "AvailabilityStatusEnum!" + description: "Availability status in a format suitable for usage in the code" diff --git a/src/Resources/config/graphql-types/ModelType/Product/ProductDecorator.types.yaml b/src/Resources/config/graphql-types/ModelType/Product/ProductDecorator.types.yaml index 754cb494a..cd4a3b591 100644 --- a/src/Resources/config/graphql-types/ModelType/Product/ProductDecorator.types.yaml +++ b/src/Resources/config/graphql-types/ModelType/Product/ProductDecorator.types.yaml @@ -10,6 +10,15 @@ ProductDecorator: name: type: "String" description: "Localized product name (domain dependent)" + namePrefix: + type: "String" + description: "Name prefix" + nameSuffix: + type: "String" + description: "Name suffix" + fullName: + type: "String!" + description: "The full name of the product, which consists of a prefix, name, and a suffix" shortDescription: type: "String" description: "Localized product short description (domain dependent)" @@ -78,3 +87,9 @@ ProductDecorator: type: "Boolean!" productType: type: "ProductTypeEnum!" + availableStoresCount: + type: "Int" + description: "Number of the stores where the product is available (null for main variants)" + storeAvailabilities: + type: "[StoreAvailability!]!" + description: "List of availabilities in individual stores (empty for main variants)" diff --git a/src/Resources/config/graphql-types/ModelType/Store/StoreAvailabilityDecorator.types.yaml b/src/Resources/config/graphql-types/ModelType/Store/StoreAvailabilityDecorator.types.yaml new file mode 100644 index 000000000..292d3f33c --- /dev/null +++ b/src/Resources/config/graphql-types/ModelType/Store/StoreAvailabilityDecorator.types.yaml @@ -0,0 +1,15 @@ +StoreAvailabilityDecorator: + type: object + decorator: true + config: + description: "Represents an availability in an individual store" + fields: + availabilityInformation: + type: "String!" + description: "Detailed information about availability" + availabilityStatus: + type: "AvailabilityStatusEnum!" + description: "Availability status in a format suitable for usage in the code" + store: + type: "Store" + description: "Store"