diff --git a/src/Model/Resolver/ApplyCoupon.php b/src/Model/Resolver/ApplyCoupon.php
deleted file mode 100644
index 3ad086e..0000000
--- a/src/Model/Resolver/ApplyCoupon.php
+++ /dev/null
@@ -1,113 +0,0 @@
-couponManagement = $couponManagement;
- }
-
- /**
- * Fetches the data from persistence models and format it according to the GraphQL schema.
- *
- * @param \Magento\Framework\GraphQl\Config\Element\Field $field
- * @param ContextInterface $context
- * @param ResolveInfo $info
- * @param array|null $value
- * @param array|null $args
- * @return mixed|Value
- * @throws \Exception
- */
- public function resolve(
- Field $field,
- $context,
- ResolveInfo $info,
- array $value = null,
- array $args = null
- )
- {
- $couponCode = $args['coupon_code'];
-
- if (empty($couponCode)) {
- throw new GraphQlInputException(__('Coupon Code can not be empty'));
- }
-
- $cart = $this->getCart($args);
-
- if ($cart->getItemsCount() < 1) {
- throw new CartCouponException(__("Cart does not contain products"));
- }
-
- $cartId = $cart->getId();
- $appliedCouponCode = $this->couponManagement->get($cartId);
-
- if ($appliedCouponCode !== null) {
- throw new CartCouponException(
- __('A coupon is already applied to the cart. Please remove it to apply another.')
- );
- }
-
- try {
- $this->couponManagement->set($cartId, $couponCode);
- } catch (NoSuchEntityException | CouldNotSaveException $e) {
- throw new CartCouponException(__('Coupon Code is invalid'), $e);
- }
-
- return [];
- }
-}
diff --git a/src/Model/Resolver/CartIsInStorePickupAvailable.php b/src/Model/Resolver/CartIsInStorePickupAvailable.php
new file mode 100644
index 0000000..adf8e35
--- /dev/null
+++ b/src/Model/Resolver/CartIsInStorePickupAvailable.php
@@ -0,0 +1,62 @@
+inStorePickupDeliveryAvailableForCart = $inStorePickupDeliveryAvailableForCart;
+ }
+
+ /**
+ * @param Field $field
+ * @param ContextInterface $context
+ * @param ResolveInfo $info
+ * @param array|null $value
+ * @param array|null $args
+ * @return array
+ */
+ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
+ {
+ if (!isset($value['model'])) {
+ throw new LocalizedException(__('"model" value should be specified'));
+ }
+
+ $cart = $value['model'];
+
+ return $this->inStorePickupDeliveryAvailableForCart->execute((int) $cart->getId());
+ }
+}
diff --git a/src/Model/Resolver/CartItems.php b/src/Model/Resolver/CartItems.php
new file mode 100644
index 0000000..d5c77d4
--- /dev/null
+++ b/src/Model/Resolver/CartItems.php
@@ -0,0 +1,156 @@
+emulation = $emulation;
+ $this->helperImage = $helperImage;
+ $this->storeManager = $storeManager;
+ }
+
+ /**
+ * @param Field $field
+ * @param ContextInterface $context
+ * @param ResolveInfo $info
+ * @param array|null $value
+ * @param array|null $args
+ * @return array
+ */
+ public function resolve(
+ Field $field,
+ $context,
+ ResolveInfo $info,
+ array $value = null,
+ array $args = null
+ ) {
+ $result = parent::resolve($field, $context, $info, $value, $args);
+
+ $cartItems = [];
+
+ $storeId = $this->storeManager->getStore()->getId();
+ $this->emulation->startEnvironmentEmulation($storeId, Area::AREA_FRONTEND, true);
+
+ foreach ($result as $itemData) {
+ $cartItem = $itemData['model'];
+ $product = $cartItem->getProduct();
+
+ $cartItems[] = array_merge($itemData, [
+ 'sku' => $cartItem->getSku(),
+ 'product' => array_merge($itemData['product'],
+ [
+ 'thumbnail' =>
+ [
+ 'path' => $product->getThumbnail(),
+ 'url' => $this->getImageUrl('thumbnail', $product->getThumbnail(), $product)
+ ]
+ ])
+ ]);
+ }
+
+ $this->emulation->stopEnvironmentEmulation();
+
+ return $cartItems;
+ }
+
+ /**
+ * @param string $imageType
+ * @param string|null $imagePath
+ * @param Product $product
+ * @return string
+ */
+ protected function getImageUrl(
+ string $imageType,
+ ?string $imagePath,
+ $product
+ ): string {
+ if (!isset($imagePath)) {
+ return $this->helperImage->getDefaultPlaceholderUrl($imageType);
+ }
+
+ $imageId = sprintf('scandipwa_%s', $imageType);
+
+ $image = $this->helperImage
+ ->init(
+ $product,
+ $imageId,
+ ['type' => $imageType]
+ )
+ ->constrainOnly(true)
+ ->keepAspectRatio(true)
+ ->keepTransparency(true)
+ ->keepFrame(false);
+
+ return $image->getUrl();
+ }
+}
diff --git a/src/Model/Resolver/CartMinimumOrderAmount.php b/src/Model/Resolver/CartMinimumOrderAmount.php
new file mode 100644
index 0000000..36476f2
--- /dev/null
+++ b/src/Model/Resolver/CartMinimumOrderAmount.php
@@ -0,0 +1,73 @@
+amountValidationMessage = $amountValidationMessage;
+ }
+
+ /**
+ * @param Field $field
+ * @param ContextInterface $context
+ * @param ResolveInfo $info
+ * @param array|null $value
+ * @param array|null $args
+ * @return array
+ * @throws NotFoundException
+ */
+ public function resolve(
+ Field $field,
+ $context,
+ ResolveInfo $info,
+ array $value = null,
+ array $args = null
+ ) {
+ if (!isset($value['model'])) {
+ throw new LocalizedException(__('"model" value should be specified'));
+ }
+
+ $quote = $value['model'];
+
+ $minimumOrderAmountReached = $quote->validateMinimumAmount();
+ $minimumOrderDescription = $this->amountValidationMessage->getMessage();
+
+ return [
+ 'minimum_order_amount_reached' => $minimumOrderAmountReached,
+ 'minimum_order_description' => $minimumOrderDescription
+ ];
+ }
+}
diff --git a/src/Model/Resolver/CartPrices.php b/src/Model/Resolver/CartPrices.php
new file mode 100644
index 0000000..41c0bdc
--- /dev/null
+++ b/src/Model/Resolver/CartPrices.php
@@ -0,0 +1,107 @@
+totalsCollector = $totalsCollector;
+ }
+
+ /**
+ * @param Field $field
+ * @param ContextInterface $context
+ * @param ResolveInfo $info
+ * @param array|null $value
+ * @param array|null $args
+ * @return array
+ */
+ public function resolve(
+ Field $field,
+ $context,
+ ResolveInfo $info,
+ array $value = null,
+ array $args = null
+ ) {
+ $result = parent::resolve($field, $context, $info, $value, $args);
+
+ $quote = $result['model'];
+
+ $applied_rule_ids = $quote->getAppliedRuleIds();
+ $coupon_code = $quote->getCouponCode();
+ $quote_currency_code = $quote->getQuoteCurrencyCode();
+
+ $cartTotals = $this->totalsCollector->collectQuoteTotals($quote);
+
+ return array_merge($result, [
+ 'applied_rule_ids' => $applied_rule_ids,
+ 'applied_taxes' => $this->getAppliedTaxes($cartTotals, $quote_currency_code),
+ 'coupon_code' => $coupon_code,
+ 'quote_currency_code' => $quote_currency_code
+ ]);
+ }
+
+ /**
+ * Returns taxes applied to the current quote
+ *
+ * @param Total $total
+ * @param string $currency
+ * @return array
+ */
+ protected function getAppliedTaxes(Total $total, string $currency): array
+ {
+ $appliedTaxesData = [];
+ $appliedTaxes = $total->getAppliedTaxes();
+
+ if (empty($appliedTaxes)) {
+ return $appliedTaxesData;
+ }
+
+ foreach ($appliedTaxes as $appliedTax) {
+ $appliedTaxesData[] = [
+ 'label' => $appliedTax['id'],
+ 'amount' => ['value' => $appliedTax['amount'], 'currency' => $currency],
+ 'percent' => $appliedTax['percent']
+ ];
+ }
+
+ return $appliedTaxesData;
+ }
+}
diff --git a/src/Model/Resolver/GetCartForCustomer.php b/src/Model/Resolver/GetCartForCustomer.php
deleted file mode 100644
index 6e7b63d..0000000
--- a/src/Model/Resolver/GetCartForCustomer.php
+++ /dev/null
@@ -1,304 +0,0 @@
-configurable = $configurable;
- $this->productFactory = $productFactory;
- $this->productPostProcessor = $productPostProcessor;
- $this->customizableOption = $customizableOption;
- $this->bundleOptions = $bundleOptions;
- $this->serializer = $serializer;
- $this->linkRepository = $linkRepository;
- $this->quoteIdToMaskedQuoteId = $quoteIdToMaskedQuoteId;
- $this->inStorePickupDeliveryAvailableForCart = $inStorePickupDeliveryAvailableForCart;
- $this->amountValidationMessage = $amountValidationMessage;
- }
-
- /**
- * @param QuoteItem $item
- * @param Product $product
- * @return array
- * @throws LocalizedException
- */
- protected function mergeQuoteItemData(
- QuoteItem $item,
- Product $product
- ) {
- return [
- 'product' => $this->productsData[$product->getId()],
- 'customizable_options' => $this->getCustomizableOptions($item),
- 'bundle_options' => $this->bundleOptions->getData($item),
- 'downloadable_links' => $this->getDownloadableLinks($item, $product)
- ] + $item->getData();
- }
-
- /**
- * @param $item
- * @param $product
- * @return array
- */
- private function getDownloadableLinks($item, $product): array
- {
- $quoteItemLinks= $item->getOptionByCode('downloadable_link_ids');
-
- if (null === $quoteItemLinks) {
- return [];
- }
-
- $downloadableLinks = [];
- $downloadableLinkIds = explode(',', $quoteItemLinks->getValue());
- $productLinks = $this->linkRepository->getLinksByProduct($product);
-
- /** @var Link $productLink */
- foreach ($productLinks as $productLink) {
- if (in_array($productLink->getId(), $downloadableLinkIds)){
- $downloadableLinks[] = [
- 'label' => $productLink->getTitle(),
- 'id' => $productLink->getId()
- ];
- }
- }
-
- return $downloadableLinks;
- }
-
-
- /**
- * @param $item
- * @return array
- * @throws LocalizedException
- */
- private function getCustomizableOptions($item): array
- {
- $quoteItemOption = $item->getOptionByCode('option_ids');
-
- if (null === $quoteItemOption) {
- return [];
- }
-
- $customizableOptionsData = [];
- $customizableOptionIds = explode(',', $quoteItemOption->getValue());
-
- foreach ($customizableOptionIds as $customizableOptionId) {
- $customizableOption = $this->customizableOption->getData(
- $item,
- (int)$customizableOptionId
- );
- $customizableOptionsData[] = $customizableOption;
- }
-
- return $customizableOptionsData;
- }
-
- /**
- * @param AddressInterface $address
- * @return array
- */
- private function getAppliedTaxes(AddressInterface $address): array
- {
- $taxes = $address->getData('applied_taxes');
-
- if (is_string($taxes)) {
- $taxes = $this->serializer->unserialize($taxes);
- }
-
- return is_array($taxes) ? array_values($taxes) : [];
- }
-
- /**
- * Fetches the data from persistence models and format it according to the GraphQL schema.
- *
- * @param Field $field
- * @param ContextInterface $context
- * @param ResolveInfo $info
- * @param array|null $value
- * @param array|null $args
- * @return Value|CartInterface|mixed
- * @throws NotFoundException
- */
- public function resolve(
- Field $field,
- $context,
- ResolveInfo $info,
- array $value = null,
- array $args = null
- ) {
- $cart = $this->getCart($args);
- $items = $cart->getItems();
- $itemsData = [];
-
- if ($items) {
- // Prepare product data in advance
- $products = array_map(function ($item) {
- return $item->getProduct();
- }, $items);
-
- $adjustedInfo = $info->fieldNodes[0];
- $this->productsData = $this->productPostProcessor->process(
- $products,
- 'items/product',
- $adjustedInfo,
- ['isCartProduct'=> true]
- );
-
- foreach ($items as $item) {
- /** @var QuoteItem $item */
- $product = $item->getProduct();
- $itemsData[] = $this->mergeQuoteItemData($item, $product);
- }
- }
-
- $cartData = $cart->getData();
- // In interface it is PHPDocumented that it returns bool,
- // while in implementation it returns int.
- $is_virtual = (bool)$cart->isVirtual();
- $address = $is_virtual ? $cart->getBillingAddress() : $cart->getShippingAddress();
- $tax_amount = $address->getTaxAmount();
- $discount_amount = $address->getDiscountAmount();
- $applied_taxes = $this->getAppliedTaxes($address);
- $grand_total = $address->getGrandTotal();
- $subtotal_incl_tax = $address->getSubtotalInclTax();
- $shipping_tax_amount = $address->getShippingTaxAmount();
- $shipping_amount = $address->getShippingAmount();
- $shipping_incl_tax = $address->getShippingInclTax();
- $shipping_method = $address->getShippingMethod();
- $masked_id = $this->quoteIdToMaskedQuoteId->execute(intval($cart->getId()));
- $isInStorePickupAvailable = $this->inStorePickupDeliveryAvailableForCart->execute((int) $cart->getId());
- $minimumOrderAmountReached = $cart->validateMinimumAmount();
- $minimumOrderDescription = $this->amountValidationMessage->getMessage();
-
- return array_merge(
- $cartData,
- [
- 'id' => $masked_id,
- 'items' => $itemsData,
- 'tax_amount' => $tax_amount,
- 'subtotal_incl_tax' => $subtotal_incl_tax,
- 'discount_amount' => $discount_amount,
- 'is_virtual' => $is_virtual,
- 'applied_taxes' => $applied_taxes,
- 'grand_total' => $grand_total,
- 'shipping_tax_amount' => $shipping_tax_amount,
- 'shipping_amount' => $shipping_amount,
- 'shipping_incl_tax' => $shipping_incl_tax,
- 'shipping_method' => $shipping_method,
- 'shipping_address' => $cart->getShippingAddress(),
- 'is_in_store_pickup_available' => $isInStorePickupAvailable,
- 'minimum_order_amount' => [
- 'minimum_order_amount_reached' => $minimumOrderAmountReached,
- 'minimum_order_description' => $minimumOrderDescription
- ]
- ]
- );
- }
-}
diff --git a/src/Model/Resolver/PlaceOrder.php b/src/Model/Resolver/PlaceOrder.php
deleted file mode 100644
index ee99b71..0000000
--- a/src/Model/Resolver/PlaceOrder.php
+++ /dev/null
@@ -1,134 +0,0 @@
-getCartForUser = $getCartForUser;
- $this->cartManagement = $cartManagement;
- $this->orderRepository = $orderRepository;
- $this->checkCartCheckoutAllowance = $checkCartCheckoutAllowance;
- $this->storeManager = $storeManager;
- $this->cartRepository = $cartRepository;
- }
-
- /**
- * @inheritdoc
- */
- public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
- {
- $guestCartId = $args['guestCartId'] ?? '';
-
- $customerId = $context->getUserId();
- $storeId = (int)$context->getExtensionAttributes()->getStore()->getId();
-
- if ($guestCartId !== '') {
- $cart = $this->getCartForUser->execute($guestCartId, $customerId, $storeId);
- } else {
- $cart = $this->cartManagement->getCartForCustomer($customerId);
- }
-
- $this->checkCartCheckoutAllowance->execute($cart);
-
- if ((int)$context->getUserId() === 0) {
- if (!$cart->getCustomerEmail()) {
- throw new GraphQlInputException(__("Guest email for cart is missing."));
- }
- $cart->setCheckoutMethod(CartManagementInterface::METHOD_GUEST);
- }
-
- try {
- $currStoreId = $this->storeManager->getStore()->getId();
- $cart->setStoreId($currStoreId);
- $this->cartRepository->save($cart);
-
- $orderId = $this->cartManagement->placeOrder($cart->getId());
- $order = $this->orderRepository->get($orderId);
-
- return [
- 'order' => [
- 'order_id' => $order->getIncrementId(),
- ],
- ];
- } catch (NoSuchEntityException $e) {
- throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e);
- } catch (LocalizedException $e) {
- throw new GraphQlInputException(__('Unable to place order: %message', ['message' => $e->getMessage()]), $e);
- }
- }
-}
diff --git a/src/Model/Resolver/RemoveCartItem.php b/src/Model/Resolver/RemoveCartItem.php
deleted file mode 100644
index d27320a..0000000
--- a/src/Model/Resolver/RemoveCartItem.php
+++ /dev/null
@@ -1,94 +0,0 @@
-overriderCartId = $overriderCartId;
- $this->cartItemRepository = $cartItemRepository;
- $this->guestCartItemRepository = $guestCartItemRepository;
- }
-
- /**
- * Fetches the data from persistence models and format it according to the GraphQL schema.
- *
- * @param \Magento\Framework\GraphQl\Config\Element\Field $field
- * @param ContextInterface $context
- * @param ResolveInfo $info
- * @param array|null $value
- * @param array|null $args
- * @return mixed|Value
- * @throws \Exception
- */
- public function resolve(
- Field $field,
- $context,
- ResolveInfo $info,
- array $value = null,
- array $args = null
- )
- {
- ['item_id' => $itemId] = $args;
-
- if (isset($args['guestCartId'])) {
- $this->guestCartItemRepository->deleteById($args['guestCartId'], $itemId);
- } else {
- $this->cartItemRepository->deleteById($this->overriderCartId->getOverriddenValue(), $itemId);
- }
-
- return [];
- }
-}
\ No newline at end of file
diff --git a/src/Model/Resolver/RemoveCoupon.php b/src/Model/Resolver/RemoveCoupon.php
deleted file mode 100644
index e5fbba6..0000000
--- a/src/Model/Resolver/RemoveCoupon.php
+++ /dev/null
@@ -1,93 +0,0 @@
-couponManagement = $couponManagement;
- }
-
- /**
- * Fetches the data from persistence models and format it according to the GraphQL schema.
- *
- * @param \Magento\Framework\GraphQl\Config\Element\Field $field
- * @param ContextInterface $context
- * @param ResolveInfo $info
- * @param array|null $value
- * @param array|null $args
- * @return mixed|Value
- * @throws \Exception
- */
- public function resolve(
- Field $field,
- $context,
- ResolveInfo $info,
- array $value = null,
- array $args = null
- )
- {
- $cart = $this->getCart($args);
-
- if ($cart->getItemsCount() < 1) {
- throw new CartCouponException(__("Cart does not contain products"));
- }
-
- $this->couponManagement->remove($cart->getId());
-
- return [];
- }
-}
diff --git a/src/Model/Resolver/SaveCartItem.php b/src/Model/Resolver/SaveCartItem.php
deleted file mode 100755
index eefc90f..0000000
--- a/src/Model/Resolver/SaveCartItem.php
+++ /dev/null
@@ -1,586 +0,0 @@
-quoteIdMaskFactory = $quoteIdMaskFactory;
- $this->quoteRepository = $quoteRepository;
- $this->overriderCartId = $overriderCartId;
- $this->productRepository = $productRepository;
- $this->attributeRepository = $attributeRepository;
- $this->quoteIdMaskResource = $quoteIdMaskResource;
- $this->configurableType = $configurableType;
- $this->stockStatusRepository = $stockStatusRepository;
- $this->getStockItemData = $getStockItemData;
- $this->getReservationsQuantity = $getReservationsQuantity;
- $this->getStockItemConfiguration = $getStockItemConfiguration;
- $this->imageUpload = $imageUpload;
- $this->updateCartItem = $updateCartItem;
- }
-
- /**
- * @param array $options
- * @return array
- */
- private function prepareOptions(array $options): array
- {
- if (isset ($options['product_option']['extension_attributes']['configurable_item_options'])) {
- $configurableOptions = &$options['product_option']['extension_attributes']['configurable_item_options'];
- $stringifiedOptionValues = array_map(function ($item) {
- $item['option_value'] = (string)$item['option_value'];
- return $item;
- }, $configurableOptions);
- $configurableOptions = $stringifiedOptionValues;
- }
-
- return $options;
- }
-
- /**
- * @param string $request
- * @param Product $product
- * @param array $options
- * @return array
- */
- private function getOptionsFromBuyRequest(Product $product, array $options) : array {
- $request = $options['product_option']['buy_request'];
- $data = json_decode($request, true);
- $data['product'] = $product->getEntityId();
- $data['qty'] = $options['quantity'];
-
- return $data;
- }
-
- /**
- * @param Product $product
- * @param array $options
- * @return array
- */
- private function getOptionsFromExtensions(Product $product, array $options) : array {
- $options = $this->prepareOptions($options);
- $data = [
- 'product' => $product->getEntityId(),
- 'qty' => $options['quantity']
- ];
-
- switch ($product->getTypeId()) {
- case ProductType::TYPE_SIMPLE:
- case ProductType::TYPE_VIRTUAL:
- case Configurable::TYPE_CODE:
- $this->setCustomizableOptions($options, $data);
- $data = $this->setConfigurableRequestOptions($options, $data);
- break;
- case Type::TYPE_CODE:
- $data = $this->setBundleRequestOptions($options, $data);
- break;
- case DownloadableType::TYPE_DOWNLOADABLE:
- $this->setCustomizableOptions($options, $data);
- $data = $this->setDownloadableRequestLinks($options, $data);
- break;
- }
-
- return $data;
- }
-
- /**
- * @param Product $product
- * @param array $options
- * @return DataObject
- */
- private function prepareAddItem(Product $product, array $options): DataObject
- {
- if (isset($options['product_option']['buy_request'])) {
- $data = $this->getOptionsFromBuyRequest($product, $options);
- } else {
- $data = $this->getOptionsFromExtensions($product, $options);
- }
-
- $request = new DataObject();
- $request->setData($data);
-
- return $request;
- }
-
- /**
- * @param array $options
- * @param array $data
- * @return array
- */
- private function setConfigurableRequestOptions(array $options, array $data): array
- {
- $configurableOptions = $options['product_option']['extension_attributes']['configurable_item_options'] ?? [];
- $superAttributes = [];
-
- foreach ($configurableOptions as $option) {
- $superAttributes[$option['option_id']] = $option['option_value'];
- }
-
- $data['super_attribute'] = $superAttributes;
- return $data;
- }
-
- /**
- * @param array $options
- * @param array $data
- */
- private function setCustomizableOptions(array $options, array &$data): void
- {
- $customizableOptionsData = $options['product_option']['extension_attributes']['customizable_options'] ?? [];
- $customizableOptions = $this->getCustomizableOptions($customizableOptionsData);
- // Necessary for multi selections, i.e., checkboxes which have same parent option_id
- $customizableOptionsArrayData = $options['product_option']['extension_attributes']['customizable_options_multi'] ?? [];
- $customizableOptionsMulti = $this->getCustomizableOptions($customizableOptionsArrayData, true);
-
- if (count($customizableOptions)) {
- foreach ($customizableOptions as $key => $value) {
- $data['options'][$key] = $value;
- }
- }
-
- if (count($customizableOptionsMulti)) {
- foreach ($customizableOptionsMulti as $key => $value) {
- $data['options'][$key] = $value;
- }
- }
- }
-
- /**
- * @param $customizableOptions
- * @param bool $isMulti
- * @return array
- */
- private function getCustomizableOptions($customizableOptions, $isMulti = false): array
- {
- $data = [];
-
- if (count($customizableOptions)) {
- foreach ($customizableOptions as $customizableOption) {
- if ($isMulti) {
- $data[$customizableOption['option_id']][] = $customizableOption['option_value'];
- } else {
- $data[$customizableOption['option_id']] = $customizableOption['option_value'];
- }
- }
- }
-
- return $data;
- }
-
- /**
- * @param array $options
- * @param array $data
- * @return array
- */
- private function setBundleRequestOptions(array $options, array $data): array
- {
- $data['bundle_option'] = [];
- $data['bundle_option_qty'] = [];
- $bundleOptions = $options['product_option']['extension_attributes']['bundle_options'] ?? [];
-
- foreach ($bundleOptions as $bundleOption) {
- $optionId = $bundleOption['id'];
- $data['bundle_option'][$optionId][] = $bundleOption['value'];
- $data['bundle_option_qty'][$optionId] = $bundleOption['quantity'];
- }
-
- return $data;
- }
-
- /**
- * @param array $options
- * @param array $data
- * @return array
- */
- private function setDownloadableRequestLinks(array $options, array $data): array
- {
- $data['links'] = [];
- $linkOptions = $options['product_option']['extension_attributes']['downloadable_product_links'] ?? [];
- foreach ($linkOptions as $link) {
- $data['links'][] = $link['link_id'];
- }
- return $data;
- }
-
- /**
- * @param string $guestCardId
- * @return string
- */
- protected function getGuestQuoteId(string $guestCardId): string
- {
- $quoteIdMask = $this->quoteIdMaskFactory->create();
- $this->quoteIdMaskResource->load($quoteIdMask, $guestCardId, 'masked_id');
-
- return $quoteIdMask->getQuoteId() ?? '';
- }
-
- /**
- * Fetches the data from persistence models and format it according to the GraphQL schema.
- *
- * @param Field $field
- * @param ContextInterface $context
- * @param ResolveInfo $info
- * @param array|null $value
- * @param array|null $args
- * @return mixed|Value
- * @throws Exception
- */
- public function resolve(
- Field $field,
- $context,
- ResolveInfo $info,
- array $value = null,
- array $args = null
- )
- {
- $requestCartItem = $args['cartItem'];
- if (!$this->validateCartItem($requestCartItem)) {
- throw new GraphQlInputException(new Phrase('Cart item ID or product SKU must be passed'));
- }
- $quoteId = isset($args['guestCartId'])
- ? $this->getGuestQuoteId($args['guestCartId'])
- : $this->overriderCartId->getOverriddenValue();
- $quote = $this->quoteRepository->getActive($quoteId);
- ['quantity' => $qty] = $requestCartItem;
-
- $itemId = $this->getItemId($requestCartItem);
-
- if ($itemId) {
- $cartItem = $quote->getItemById($itemId);
- $product = $cartItem->getProduct();
- $options = $product->getTypeInstance(true)->getOrderOptions($product) ?? [];
-
- if ($product->getData('has_options') && isset($options['options'])) {
- $this->updateCartItem->execute($quote, $itemId, $qty, []);
- } else if ($product->getTypeId() === Bundle::TYPE_CODE) {
- $this->updateCartItem->execute($quote, $itemId, $qty, []);
- } else {
- $this->checkItemQty($cartItem, $qty);
- $cartItem->setQty($qty);
- }
-
- $this->quoteRepository->save($quote);
- } else {
- $sku = $this->getSku($requestCartItem);
- $product = $this->productRepository->get($sku);
-
- if (!$product) {
- throw new GraphQlNoSuchEntityException(new Phrase('Product could not be loaded'));
- }
-
- $newQuoteItem = $this->buildQuoteItem(
- $sku,
- $qty,
- (int) $quoteId,
- $requestCartItem['product_option'] ?? []
- );
-
- try {
- $result = $quote->addProduct($product, $this->prepareAddItem(
- $product,
- $newQuoteItem
- ));
- if (is_string($result)){
- throw new GraphQlInputException(new Phrase($result));
- }
-
- $this->quoteRepository->save($quote);
- } catch (\Exception $e) {
- throw new GraphQlInputException(new Phrase($e->getMessage()));
- }
-
- // Related to bug: https://github.com/magento/magento2/issues/2991
- $quote = $this->quoteRepository->getActive($quoteId);
- $quote->setTotalsCollectedFlag(false)->collectTotals();
- $this->quoteRepository->save($quote);
-
- // We need file upload logic exactly after new quote has arrived
- // Otherwise magento gives us quote with empty prices
- $this->imageUpload->processFileUpload($quote, $requestCartItem);
- }
-
- return [];
- }
-
- /**
- * @param CartItemInterface $cartItem
- * @param $qty
- * @throws GraphQlInputException
- * @throws LocalizedException
- * @throws SkuIsNotAssignedToStockException
- */
- protected function checkItemQty(CartItemInterface $cartItem, $qty): void
- {
- $product = $cartItem->getProduct();
-
- if ($cartItem->getProductType() === Configurable::TYPE_CODE) {
- $attributesInfo = $cartItem->getBuyRequest()->getDataByKey('super_attribute');
- $product = $this->configurableType->getProductByAttributes($attributesInfo, $product);
- }
-
- $stockStatus = $this->stockStatusRepository->get($product->getId());
- $stockItem = $stockStatus->getStockItem();
-
- if (!$stockItem->getManageStock()) { // just skip all checks, if stock is not managed
- return;
- }
-
- $allowedBackorder = $stockItem->getBackorders();
- $fitsInStock = $qty <= $stockItem->getQty();
-
- if (!$fitsInStock && !$allowedBackorder) {
- throw new GraphQlInputException(new Phrase('Provided quantity exceeds stock limits'));
- }
-
- $isMinSaleQuantityCheckFailed = $qty < $stockItem->getMinSaleQty();
-
- if ($isMinSaleQuantityCheckFailed) {
- throw new GraphQlInputException(
- new Phrase('The fewest you may purchase is %1', [$stockItem->getMinSaleQty()])
- );
- }
-
- $isMaxSaleQuantityCheckFailed = $qty > $stockItem->getMaxSaleQty();
-
- if ($isMaxSaleQuantityCheckFailed) {
- throw new GraphQlInputException(
- new Phrase('The requested qty exceeds the maximum qty allowed in shopping cart')
- );
- }
-
- $stockId = $stockItem->getStockId();
- $sku = $product->getSku();
-
- $stockItemData = $this->getStockItemData->execute($sku, $stockId);
-
- /** @var StockItemConfigurationInterface $stockItemConfiguration */
- $stockItemConfiguration = $this->getStockItemConfiguration->execute($sku, $stockId);
-
- $qtyWithReservation = $stockItemData[GetStockItemDataInterface::QUANTITY] +
- $this->getReservationsQuantity->execute($sku, $stockId);
-
- $qtyLeftInStock = $qtyWithReservation - $stockItemConfiguration->getMinQty();
-
- $isInStock = bccomp((string) $qtyLeftInStock, (string) $qty, 4) >= 0 || $allowedBackorder;
- $isEnoughQty = (bool)$stockItemData[GetStockItemDataInterface::IS_SALABLE] && $isInStock;
-
- if (!$isEnoughQty) {
- throw new GraphQlInputException(new Phrase('The requested quantity is not available'));
- }
- }
-
- /**
- * @param string $sku
- * @param float $qty
- * @param int $quoteId
- * @param array $options
- * @return array
- */
- protected function buildQuoteItem(string $sku, float $qty, int $quoteId, array $options = []): array
- {
- return [
- 'quantity' => $qty,
- 'sku' => $sku,
- 'quote_id' => $quoteId,
- 'product_option' => $options
- ];
- }
-
- /**
- * @param array $cartItem
- * @return bool
- */
- private function isIdStructUsed(array $cartItem): bool
- {
- return array_key_exists('id', $cartItem) && is_array($cartItem['id']);
- }
-
- /**
- * @param array $cartItem
- * @return int|null
- */
- protected function getItemId(array $cartItem): ?int
- {
- if (isset($cartItem['item_id'])) {
- return $cartItem['item_id'];
- }
-
- if ($this->isIdStructUsed($cartItem)) {
- return $this->getItemId($cartItem['id']);
- }
-
- return null;
- }
-
- /**
- * @param array $cartItem
- * @return string|null
- */
- protected function getSku(array $cartItem): ?string
- {
- if (isset($cartItem['sku'])) {
- return $cartItem['sku'];
- }
-
- if ($this->isIdStructUsed($cartItem)) {
- return $this->getSku($cartItem['id']);
- }
-
- return null;
- }
-
- /**
- * @param array $cartItem
- * @return bool
- */
- protected function validateCartItem(array $cartItem): bool
- {
- return isset($cartItem['item_id']) || isset($cartItem['sku']) || isset($cartItem['id']);
- }
-}
diff --git a/src/Model/Resolver/SetBillingAddressOnCart.php b/src/Model/Resolver/SetBillingAddressOnCart.php
deleted file mode 100644
index 80e4f9b..0000000
--- a/src/Model/Resolver/SetBillingAddressOnCart.php
+++ /dev/null
@@ -1,123 +0,0 @@
-getCartForUser = $getCartForUser;
- $this->cartManagement = $cartManagement;
- $this->setBillingAddressOnCart = $setBillingAddressOnCart;
- $this->checkCartCheckoutAllowance = $checkCartCheckoutAllowance;
- $this->customerRepository = $customerRepository;
- }
-
- /**
- * @inheritdoc
- */
- public function resolve(
- Field $field,
- $context,
- ResolveInfo $info,
- array $value = null,
- array $args = null
- ) {
- $guestCartId = $args['input']['guest_cart_id'] ?? '';
-
- if (empty($args['input']['billing_address'])) {
- throw new GraphQlInputException(__('Required parameter "billing_address" is missing'));
- }
- $billingAddress = $args['input']['billing_address'];
- $customerAddressId = isset($billingAddress['customer_address_id'])
- ? $billingAddress['customer_address_id']
- : null;
- $sameAsShipping = !!(isset($args['input']['same_as_shipping']) && $args['input']['same_as_shipping']);
-
- $storeId = (int)$context->getExtensionAttributes()->getStore()->getId();
-
- $customerId = $context->getUserId();
- if ($guestCartId !== '') {
- $cart = $this->getCartForUser->execute($guestCartId, $customerId, $storeId);
- } else {
- $cart = $this->cartManagement->getCartForCustomer($customerId);
- }
-
- $this->checkCartCheckoutAllowance->execute($cart);
- $billingAddressIsSaved = false;
-
- if ($sameAsShipping && $customerAddressId) {
- $customer = $cart->getCustomer();
- $billingAddressId = $customer->getDefaultBilling();
-
- if (!$billingAddressId) {
- $customer->setDefaultBilling((string)$customerAddressId);
- $this->customerRepository->save($customer);
- $billingAddressIsSaved = true;
- } else {
- unset($billingAddress['customer_address_id']);
- }
- }
-
- if (!$billingAddressIsSaved) {
- $this->setBillingAddressOnCart->execute($context, $cart, $billingAddress);
- }
-
- return [
- 'cart' => [
- 'model' => $cart,
- ],
- ];
- }
-}
diff --git a/src/Model/Resolver/SetPaymentMethodOnCart.php b/src/Model/Resolver/SetPaymentMethodOnCart.php
deleted file mode 100644
index bb6639b..0000000
--- a/src/Model/Resolver/SetPaymentMethodOnCart.php
+++ /dev/null
@@ -1,96 +0,0 @@
-getCartForUser = $getCartForUser;
- $this->cartManagement = $cartManagement;
- $this->setPaymentMethodOnCart = $setPaymentMethodOnCart;
- $this->checkCartCheckoutAllowance = $checkCartCheckoutAllowance;
- }
-
- /**
- * @inheritdoc
- */
- public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
- {
- $guestCartId = $args['input']['guest_cart_id'] ?? '';
-
- if (empty($args['input']['payment_method']['code'])) {
- throw new GraphQlInputException(__('Required parameter "code" for "payment_method" is missing.'));
- }
- $paymentData = $args['input']['payment_method'];
-
- $storeId = (int)$context->getExtensionAttributes()->getStore()->getId();
-
- $customerId = $context->getUserId();
- if ($guestCartId !== '') {
- $cart = $this->getCartForUser->execute($guestCartId, $customerId, $storeId);
- } else {
- $cart = $this->cartManagement->getCartForCustomer($customerId);
- }
-
- $this->checkCartCheckoutAllowance->execute($cart);
- $this->setPaymentMethodOnCart->execute($cart, $paymentData);
-
- return [
- 'cart' => [
- 'model' => $cart,
- ],
- ];
- }
-}
diff --git a/src/Model/Resolver/ShippingAddress/SelectedShippingMethod.php b/src/Model/Resolver/ShippingAddress/SelectedShippingMethod.php
new file mode 100644
index 0000000..c695ec5
--- /dev/null
+++ b/src/Model/Resolver/ShippingAddress/SelectedShippingMethod.php
@@ -0,0 +1,71 @@
+ [
+ 'city' => $address->getCity(),
+ 'country' => [
+ 'code' => $address->getCountryId()
+ ],
+ 'email' => $address->getEmail(),
+ 'firstname' => $address->getFirstname(),
+ 'lastname' => $address->getLastname(),
+ 'postcode' => $address->getPostcode(),
+ 'region' => [
+ 'label' => $address->getRegion()
+ ],
+ 'street' => $address->getStreet(),
+ 'telephone' => $address->getTelephone(),
+ 'vat_id' => $address->getVatId()
+ ],
+ 'amount_incl_tax' => $address->getShippingInclTax(),
+ 'tax_amount' => $address->getShippingTaxAmount()
+ ]);
+ }
+}
diff --git a/src/etc/di.xml b/src/etc/di.xml
index 5dce1dc..d0ca514 100644
--- a/src/etc/di.xml
+++ b/src/etc/di.xml
@@ -34,10 +34,21 @@
ScandiPWA\QuoteGraphQl\Model\Product\Option\Type\File\ValidatorFile\Proxy
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/src/etc/schema.graphqls b/src/etc/schema.graphqls
index f0c1767..8dc13a4 100755
--- a/src/etc/schema.graphqls
+++ b/src/etc/schema.graphqls
@@ -13,7 +13,6 @@
type Query {
getPaymentMethods(guestCartId: String): [PaymentMethod] @resolver(class: "\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\GetPaymentMethods")
- getCartForCustomer(guestCartId: String): QuoteData @resolver(class: "\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\GetCartForCustomer")
getOrderList: OrderList @resolver(class: "\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\OrderListResolver") @doc(description: "The Sales Order query returns information about a Sales order")
getOrderById(id: Int!): Order @resolver(class: "\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\ExpandedOrderResolver") @doc(description: "The Sales Order query returns information about a Sales order")
getBraintreeConfig: Braintree @resolver(class: "\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\BraintreeResolver")
@@ -24,42 +23,7 @@ type Query {
type Mutation {
estimateShippingCosts(address: EstimateShippingCostsAddress!, guestCartId: String): [ShippingMethod] @resolver(class: "\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\EstimateShippingCosts")
saveAddressInformation(addressInformation: SaveAddressInformation!, guestCartId: String): PaymentDetails @resolver(class: "\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\SaveAddressInformation")
- saveCartItem(cartItem: CartItemInput!, guestCartId: String): Query @resolver(class:"\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\SaveCartItem")
- removeCartItem(guestCartId: String, item_id: Int!): Query @resolver(class:"\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\RemoveCartItem")
- applyCoupon(guestCartId: String, coupon_code: String!): Query @resolver(class:"\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\ApplyCoupon")
- removeCoupon(guestCartId: String): Query @resolver(class:"\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\RemoveCoupon")
linkOrder(customer_email: String!): Boolean @resolver(class:"\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\LinkOrder")
-
- # Magento 2 overrides to stop sending logged in user cart IDs
- s_setPaymentMethodOnCart(input: S_SetPaymentMethodOnCartInput!): SetPaymentMethodOnCartOutput @resolver(class: "\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\SetPaymentMethodOnCart")
- s_placeOrder(guestCartId: String): PlaceOrderOutput @resolver(class: "\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\PlaceOrder")
- s_setBillingAddressOnCart(input: S_SetBillingAddressOnCartInput): SetBillingAddressOnCartOutput @resolver(class: "\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\SetBillingAddressOnCart")
-}
-
-input S_SetBillingAddressOnCartInput {
- guest_cart_id: String
- billing_address: BillingAddressInput!
- same_as_shipping: Boolean
-}
-
-input S_SetPaymentMethodOnCartInput {
- guest_cart_id: String
- payment_method: PaymentMethodInput!
-}
-
-input CartItemInput {
- id: CartItemId
- sku: String
- quantity: Float!
- quote_id: String
- item_id: Int
- product_type: String
- product_option: ProductOptionInput
-}
-
-input CartItemId {
- sku: String,
- item_id: Int
}
input ProductOptionInput {
@@ -91,22 +55,6 @@ input DownloadableProductLinksInput {
link_id: Int
}
-input PaymentInformation {
- billing_address: AddressInput!
- paymentMethod: PaymentMethodInput!
-}
-
-input PaymentMethodInput {
- method: String
- additional_data: PaymentMethodAdditionalData
-}
-
-input PaymentMethodAdditionalData {
- payment_method_nonce: String
- cc_stripejs_token: String
- cc_save: Boolean
-}
-
input AddressInput {
method: String
region: String
@@ -152,12 +100,6 @@ type Braintree {
is_three_d_secure: Boolean
}
-type QuoteData implements TotalsObject {
- id: String
- is_virtual: Boolean
- applied_taxes: [AppliedTaxItem]
-}
-
type PaymentTotals implements TotalsObject {
}
@@ -247,23 +189,6 @@ type MinimumOrderAmount {
minimum_order_description: String
}
-type TotalsSegment {
- code: String
- title: String
- value: Float
- extension_attributes: ExtensionAttributes
-}
-
-type ExtensionAttributes {
- tax_grandtotal_details: [TaxGrandTotalDetails]
-}
-
-type TaxGrandTotalDetails {
- # rates:
- amount: Float
- group_id: Int
-}
-
type ShippingMethod {
carrier_code: String
method_code: String
@@ -379,17 +304,6 @@ type CartDisplayConfig {
display_zero_tax_subtotal: Boolean
}
-type AppliedTaxItem {
- amount: Float
- percent: Float
- rates: [AppliedTaxItemRate]
-}
-
-type AppliedTaxItemRate {
- percent: Float
- title: String
-}
-
extend input CartAddressInput {
vat_id: String
}
@@ -425,3 +339,35 @@ input AddressExtensionAttributes {
attribute_code: String
value: String
}
+
+#Retrieving a shopping cart via Magento's standard functions extension
+
+type Cart @doc(description: "Contains the contents and other details about a guest or customer cart.") {
+ minimum_order_amount: MinimumOrderAmount @resolver(class: "\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\CartMinimumOrderAmount") @doc(description: "Indicates whether the cart contains only virtual products.")
+ is_in_store_pickup_available: Boolean @resolver(class: "\\ScandiPWA\\QuoteGraphQl\\Model\\Resolver\\CartIsInStorePickupAvailable") @doc(description: "Indicates whether the pickup in store is available.")
+}
+
+type CartPrices @doc(description: "Contains details about the final price of items in the cart, including discount and tax information.") {
+ applied_rule_ids: String @doc(description: "Ids of the rules applied to the cart.")
+ coupon_code: String @doc(description: "Coupon code applied to cart.")
+ quote_currency_code: String @doc(description: "Base quote currency code.")
+}
+
+type CartTaxItem @doc(description: "Contains tax information about an item in the cart.") {
+ percent: Float @doc(description: "The tax percentage applied to the item.")
+}
+
+interface CartItemInterface @typeResolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\CartItemTypeResolver") @doc(description: "An interface for products in a cart.") {
+ sku: String
+}
+
+type SelectedShippingMethod @doc(description: "Contains details about the selected shipping method and carrier.") {
+ amount_incl_tax: Float @doc(description: "The cost of shipping including tax using this shipping method.")
+ tax_amount: Float @doc(description: "A shipping tax amount.")
+ address: CartAddress @doc(description: "An array of shipping addresses.")
+}
+
+type CartAddress implements CartAddressInterface {
+ email: String
+ vat_id: String
+}