Skip to content

Commit

Permalink
Merge pull request #5983 from magento-honey-badgers/241-customer-orders
Browse files Browse the repository at this point in the history
[honey] MC-20638: MyAccount :: Order Details :: Shipping Details by Order Number
  • Loading branch information
cpartica authored Aug 11, 2020
2 parents da50b9b + 35145b1 commit 2c90cff
Show file tree
Hide file tree
Showing 127 changed files with 6,920 additions and 674 deletions.
96 changes: 76 additions & 20 deletions app/code/Magento/Bundle/Model/Product/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

namespace Magento\Bundle\Model\Product;

use Magento\Bundle\Model\Option;
use Magento\Bundle\Model\ResourceModel\Option\Collection;
use Magento\Bundle\Model\ResourceModel\Selection\Collection as Selections;
use Magento\Bundle\Model\ResourceModel\Selection\Collection\FilterApplier as SelectionCollectionFilterApplier;
use Magento\Catalog\Api\ProductRepositoryInterface;
Expand Down Expand Up @@ -414,16 +416,13 @@ public function beforeSave($product)
if ($product->getCanSaveBundleSelections()) {
$product->canAffectOptions(true);
$selections = $product->getBundleSelectionsData();
if ($selections && !empty($selections)) {
$options = $product->getBundleOptionsData();
if ($options) {
foreach ($options as $option) {
if (empty($option['delete']) || 1 != (int)$option['delete']) {
$product->setTypeHasOptions(true);
if (1 == (int)$option['required']) {
$product->setTypeHasRequiredOptions(true);
break;
}
if (!empty($selections) && $options = $product->getBundleOptionsData()) {
foreach ($options as $option) {
if (empty($option['delete']) || 1 != (int)$option['delete']) {
$product->setTypeHasOptions(true);
if (1 == (int)$option['required']) {
$product->setTypeHasRequiredOptions(true);
break;
}
}
}
Expand Down Expand Up @@ -464,7 +463,7 @@ public function getOptionsIds($product)
public function getOptionsCollection($product)
{
if (!$product->hasData($this->_keyOptionsCollection)) {
/** @var \Magento\Bundle\Model\ResourceModel\Option\Collection $optionsCollection */
/** @var Collection $optionsCollection */
$optionsCollection = $this->_bundleOption->create()
->getResourceCollection();
$optionsCollection->setProductIdFilter($product->getEntityId());
Expand Down Expand Up @@ -530,10 +529,10 @@ public function getSelectionsCollection($optionIds, $product)
* Example: the catalog inventory validation of decimal qty can change qty to int,
* so need to change quote item qty option value too.
*
* @param array $options
* @param \Magento\Framework\DataObject $option
* @param mixed $value
* @param \Magento\Catalog\Model\Product $product
* @param array $options
* @param \Magento\Framework\DataObject $option
* @param mixed $value
* @param \Magento\Catalog\Model\Product $product
* @return $this
*/
public function updateQtyOption($options, \Magento\Framework\DataObject $option, $value, $product)
Expand Down Expand Up @@ -682,6 +681,11 @@ protected function _prepareProduct(\Magento\Framework\DataObject $buyRequest, $p
$options
);

$this->validateRadioAndSelectOptions(
$optionsCollection,
$options
);

$selectionIds = array_values($this->arrayUtility->flatten($options));
// If product has not been configured yet then $selections array should be empty
if (!empty($selectionIds)) {
Expand Down Expand Up @@ -1184,9 +1188,11 @@ public function canConfigure($product)
* @return void
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
// @codingStandardsIgnoreStart
public function deleteTypeSpecificData(\Magento\Catalog\Model\Product $product)
{
}
// @codingStandardsIgnoreEnd

/**
* Return array of specific to type product entities
Expand All @@ -1196,18 +1202,19 @@ public function deleteTypeSpecificData(\Magento\Catalog\Model\Product $product)
*/
public function getIdentities(\Magento\Catalog\Model\Product $product)
{
$identities = parent::getIdentities($product);
$identities = [];
$identities[] = parent::getIdentities($product);
/** @var \Magento\Bundle\Model\Option $option */
foreach ($this->getOptions($product) as $option) {
if ($option->getSelections()) {
/** @var \Magento\Catalog\Model\Product $selection */
foreach ($option->getSelections() as $selection) {
$identities = array_merge($identities, $selection->getIdentities());
$identities[] = $selection->getIdentities();
}
}
}

return $identities;
return array_merge([], ...$identities);
}

/**
Expand Down Expand Up @@ -1272,6 +1279,53 @@ protected function checkIsAllRequiredOptions($product, $isStrictProcessMode, $op
}
}

/**
* Validate Options for Radio and Select input types
*
* @param Collection $optionsCollection
* @param int[] $options
* @return void
* @throws \Magento\Framework\Exception\LocalizedException
*/
private function validateRadioAndSelectOptions($optionsCollection, $options): void
{
$errorTypes = [];

if (is_array($optionsCollection->getItems())) {
foreach ($optionsCollection->getItems() as $option) {
if ($this->isSelectedOptionValid($option, $options)) {
$errorTypes[] = $option->getType();
}
}
}

if (!empty($errorTypes)) {
throw new \Magento\Framework\Exception\LocalizedException(
__(
'Option type (%types) should have only one element.',
['types' => implode(", ", $errorTypes)]
)
);
}
}

/**
* Check if selected option is valid
*
* @param Option $option
* @param array $options
* @return bool
*/
private function isSelectedOptionValid($option, $options): bool
{
return (
($option->getType() == 'radio' || $option->getType() == 'select') &&
isset($options[$option->getOptionId()]) &&
is_array($options[$option->getOptionId()]) &&
count($options[$option->getOptionId()]) > 1
);
}

/**
* Check if selection is salable
*
Expand Down Expand Up @@ -1333,16 +1387,18 @@ protected function checkIsResult($_result)
*/
protected function mergeSelectionsWithOptions($options, $selections)
{
$selections = [];

foreach ($options as $option) {
$optionSelections = $option->getSelections();
if ($option->getRequired() && is_array($optionSelections) && count($optionSelections) == 1) {
$selections = array_merge($selections, $optionSelections);
$selections[] = $optionSelections;
} else {
$selections = [];
break;
}
}

return $selections;
return array_merge([], ...$selections);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\BundleGraphQl\Model\Order\Shipment;

use Magento\Catalog\Model\Product\Type\AbstractType;
use Magento\Sales\Api\Data\ShipmentInterface;
use Magento\Sales\Api\Data\ShipmentItemInterface;
use Magento\SalesGraphQl\Model\Shipment\Item\ShipmentItemFormatter;
use Magento\SalesGraphQl\Model\Shipment\Item\FormatterInterface;

/**
* Format Bundle shipment items for GraphQl output
*/
class BundleShipmentItemFormatter implements FormatterInterface
{
/**
* @var ShipmentItemFormatter
*/
private $itemFormatter;

/**
* @param ShipmentItemFormatter $itemFormatter
*/
public function __construct(ShipmentItemFormatter $itemFormatter)
{
$this->itemFormatter = $itemFormatter;
}

/**
* Format bundle product shipment item
*
* @param ShipmentInterface $shipment
* @param ShipmentItemInterface $item
* @return array|null
*/
public function formatShipmentItem(ShipmentInterface $shipment, ShipmentItemInterface $item): ?array
{
$orderItem = $item->getOrderItem();
$shippingType = $orderItem->getProductOptions()['shipment_type'] ?? null;
if ($shippingType == AbstractType::SHIPMENT_SEPARATELY && !$orderItem->getParentItemId()) {
//When bundle items are shipped separately the children are treated as their own items
return null;
}
return $this->itemFormatter->formatShipmentItem($shipment, $item);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/
declare(strict_types=1);

namespace Magento\SalesGraphQl\Model\Resolver;
namespace Magento\BundleGraphQl\Model\Resolver\Order\Item;

use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\GraphQl\Config\Element\Field;
Expand All @@ -15,6 +15,8 @@
use Magento\Framework\Serialize\Serializer\Json;
use Magento\Sales\Api\Data\InvoiceItemInterface;
use Magento\Sales\Api\Data\OrderItemInterface;
use Magento\Sales\Api\Data\ShipmentItemInterface;
use Magento\Sales\Api\Data\CreditmemoItemInterface;

/**
* Resolve bundle options items for order item
Expand Down Expand Up @@ -55,12 +57,12 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
throw new LocalizedException(__('"model" value should be specified'));
}
if ($value['model'] instanceof OrderItemInterface) {
/** @var OrderItemInterface $item */
$item = $value['model'];
return $this->getBundleOptions($item, $value);
}
if ($value['model'] instanceof InvoiceItemInterface) {
/** @var InvoiceItemInterface $item */
if ($value['model'] instanceof InvoiceItemInterface
|| $value['model'] instanceof ShipmentItemInterface
|| $value['model'] instanceof CreditmemoItemInterface) {
$item = $value['model'];
// Have to pass down order and item to map to avoid refetching all data
return $this->getBundleOptions($item->getOrderItem(), $value);
Expand Down
2 changes: 2 additions & 0 deletions app/code/Magento/BundleGraphQl/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"magento/module-quote": "*",
"magento/module-quote-graph-ql": "*",
"magento/module-store": "*",
"magento/module-sales": "*",
"magento/module-sales-graph-ql": "*",
"magento/framework": "*"
},
"license": [
Expand Down
35 changes: 35 additions & 0 deletions app/code/Magento/BundleGraphQl/etc/graphql/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,39 @@
</argument>
</arguments>
</type>
<type name="Magento\SalesGraphQl\Model\TypeResolver\OrderItem">
<arguments>
<argument name="productTypeMap" xsi:type="array">
<item name="bundle" xsi:type="string">BundleOrderItem</item>
</argument>
</arguments>
</type>
<type name="Magento\SalesGraphQl\Model\TypeResolver\InvoiceItem">
<arguments>
<argument name="productTypeMap" xsi:type="array">
<item name="bundle" xsi:type="string">BundleInvoiceItem</item>
</argument>
</arguments>
</type>
<type name="Magento\SalesGraphQl\Model\TypeResolver\ShipmentItem">
<arguments>
<argument name="productTypeMap" xsi:type="array">
<item name="bundle" xsi:type="string">BundleShipmentItem</item>
</argument>
</arguments>
</type>
<type name="Magento\SalesGraphQl\Model\TypeResolver\CreditMemoItem">
<arguments>
<argument name="productTypeMap" xsi:type="array">
<item name="bundle" xsi:type="string">BundleCreditMemoItem</item>
</argument>
</arguments>
</type>
<type name="Magento\SalesGraphQl\Model\Shipment\ItemProvider">
<arguments>
<argument name="formatters" xsi:type="array">
<item name="bundle" xsi:type="object">Magento\BundleGraphQl\Model\Order\Shipment\BundleShipmentItemFormatter\Proxy</item>
</argument>
</arguments>
</type>
</config>
30 changes: 30 additions & 0 deletions app/code/Magento/BundleGraphQl/etc/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,33 @@ enum ShipBundleItemsEnum @doc(description: "This enumeration defines whether bun
TOGETHER
SEPARATELY
}

type BundleOrderItem implements OrderItemInterface {
bundle_options: [ItemSelectedBundleOption] @doc(description: "A list of bundle options that are assigned to the bundle product") @resolver(class: "Magento\\BundleGraphQl\\Model\\Resolver\\Order\\Item\\BundleOptions")
}

type BundleInvoiceItem implements InvoiceItemInterface{
bundle_options: [ItemSelectedBundleOption] @doc(description: "A list of bundle options that are assigned to the bundle product") @resolver(class: "Magento\\BundleGraphQl\\Model\\Resolver\\Order\\Item\\BundleOptions")
}

type BundleShipmentItem implements ShipmentItemInterface {
bundle_options: [ItemSelectedBundleOption] @doc(description: "A list of bundle options that are assigned to the bundle product") @resolver(class: "Magento\\BundleGraphQl\\Model\\Resolver\\Order\\Item\\BundleOptions")
}

type BundleCreditMemoItem implements CreditMemoItemInterface {
bundle_options: [ItemSelectedBundleOption] @doc(description: "A list of bundle options that are assigned to the bundle product") @resolver(class: "Magento\\BundleGraphQl\\Model\\Resolver\\Order\\Item\\BundleOptions")
}

type ItemSelectedBundleOption @doc(description: "A list of options of the selected bundle product") {
id: ID! @doc(description: "The unique identifier of the option")
label: String! @doc(description: "The label of the option")
values: [ItemSelectedBundleOptionValue] @doc(description: "A list of products that represent the values of the parent option")
}

type ItemSelectedBundleOptionValue @doc(description: "A list of values for the selected bundle product") {
id: ID! @doc(description: "The unique identifier of the value")
product_name: String! @doc(description: "The name of the child bundle product")
product_sku: String! @doc(description: "The SKU of the child bundle product")
quantity: Float! @doc(description: "Indicates how many of this bundle product were ordered")
price: Money! @doc(description: "The price of the child bundle product")
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public function resolve(
array $value = null,
array $args = null
) {
if (isset($value['uid'])) {
return $value['uid'];
}
if (!isset($value['option_id']) || empty($value['option_id'])) {
throw new GraphQlInputException(__('"option_id" value should be specified.'));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public function resolve(
array $value = null,
array $args = null
) {
if (isset($value['uid'])) {
return $value['uid'];
}
if (!isset($value['option_id']) || empty($value['option_id'])) {
throw new GraphQlInputException(__('"option_id" value should be specified.'));
}
Expand Down
5 changes: 5 additions & 0 deletions app/code/Magento/GraphQl/etc/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -277,3 +277,8 @@ enum CurrencyEnum @doc(description: "The list of available currency codes") {
TRL
XPF
}

input EnteredOptionInput @doc(description: "Defines a customer-entered option") {
uid: ID! @doc(description: "An encoded ID")
value: String! @doc(description: "Text the customer entered")
}
Loading

0 comments on commit 2c90cff

Please sign in to comment.