Skip to content
Merged
117 changes: 83 additions & 34 deletions app/code/Magento/CatalogCustomerGraphQl/Model/Resolver/PriceTiers.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@

namespace Magento\CatalogCustomerGraphQl\Model\Resolver;

use Magento\Catalog\Api\Data\ProductTierPriceInterface;
use Magento\CatalogCustomerGraphQl\Model\Resolver\Customer\GetCustomerGroup;
use Magento\CatalogCustomerGraphQl\Model\Resolver\Product\Price\Tiers;
use Magento\CatalogCustomerGraphQl\Model\Resolver\Product\Price\TiersFactory;
use Magento\CatalogGraphQl\Model\Resolver\Product\Price\Discount;
use Magento\CatalogGraphQl\Model\Resolver\Product\Price\ProviderPool as PriceProviderPool;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\Pricing\PriceCurrencyInterface;
use Magento\CatalogCustomerGraphQl\Model\Resolver\Product\Price\Tiers;
use Magento\CatalogCustomerGraphQl\Model\Resolver\Product\Price\TiersFactory;
use Magento\CatalogCustomerGraphQl\Model\Resolver\Customer\GetCustomerGroup;
use Magento\Store\Api\Data\StoreInterface;
use Magento\CatalogGraphQl\Model\Resolver\Product\Price\Discount;
use Magento\CatalogGraphQl\Model\Resolver\Product\Price\ProviderPool as PriceProviderPool;
use Magento\Catalog\Api\Data\ProductTierPriceInterface;

/**
* Resolver for price_tiers
Expand Down Expand Up @@ -66,6 +66,16 @@ class PriceTiers implements ResolverInterface
*/
private $priceCurrency;

/**
* @var array
*/
private $formatAndFilterTierPrices = [];

/**
* @var array
*/
private $tierPricesQty = [];

/**
* @param ValueFactory $valueFactory
* @param TiersFactory $tiersFactory
Expand Down Expand Up @@ -115,52 +125,91 @@ public function resolve(
return [];
}

$productId = $product->getId();
$productId = (int)$product->getId();
$this->tiers->addProductFilter($productId);

return $this->valueFactory->create(
function () use ($productId, $context) {
/** @var StoreInterface $store */
$store = $context->getExtensionAttributes()->getStore();
$currencyCode = $context->getExtensionAttributes()->getStore()->getCurrentCurrencyCode();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you fix types on $this->tiers->addProductFilter($productId) ? \Magento\CatalogCustomerGraphQl\Model\Resolver\Product\Price\Tiers::addProductFilter has no strict types
public function addProductFilter($productId): void
would be
public function addProductFilter(int $productId): void

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

$productPrice = $this->tiers->getProductRegularPrice($productId) ?? 0.0;
$tierPrices = $this->tiers->getProductTierPrices($productId) ?? [];

return $this->formatProductTierPrices($tierPrices, $productPrice, $store);
return $this->formatAndFilterTierPrices($productPrice, $tierPrices, $currencyCode);
}
);
}

/**
* Format tier prices for output
* Format and filter tier prices for output
*
* @param ProductTierPriceInterface[] $tierPrices
* @param float $productPrice
* @param StoreInterface $store
* @param ProductTierPriceInterface[] $tierPrices
* @param string $currencyCode
* @return array
*/
private function formatProductTierPrices(array $tierPrices, float $productPrice, StoreInterface $store): array
{
$tiers = [];
private function formatAndFilterTierPrices(
float $productPrice,
array $tierPrices,
string $currencyCode
): array {

foreach ($tierPrices as $tierPrice) {
foreach ($tierPrices as $key => $tierPrice) {
$tierPrice->setValue($this->priceCurrency->convertAndRound($tierPrice->getValue()));
$percentValue = $tierPrice->getExtensionAttributes()->getPercentageValue();
if ($percentValue && is_numeric($percentValue)) {
$discount = $this->discount->getDiscountByPercent($productPrice, (float)$percentValue);
$this->formatTierPrices($productPrice, $currencyCode, $tierPrice);
$this->filterTierPrices($tierPrices, $key, $tierPrice);
}
return $this->formatAndFilterTierPrices;
}

/**
* Format tier prices for output
*
* @param float $productPrice
* @param string $currencyCode
* @param ProductTierPriceInterface $tierPrice
*/
private function formatTierPrices(float $productPrice, string $currencyCode, $tierPrice)
{
$percentValue = $tierPrice->getExtensionAttributes()->getPercentageValue();
if ($percentValue && is_numeric($percentValue)) {
$discount = $this->discount->getDiscountByPercent($productPrice, (float)$percentValue);
} else {
$discount = $this->discount->getDiscountByDifference($productPrice, (float)$tierPrice->getValue());
}

$this->formatAndFilterTierPrices[] = [
"discount" => $discount,
"quantity" => $tierPrice->getQty(),
"final_price" => [
"value" => $tierPrice->getValue(),
"currency" => $currencyCode
]
];
}

/**
* Filter the lowest price for each quantity
*
* @param array $tierPrices
* @param int $key
* @param ProductTierPriceInterface $tierPriceItem
*/
private function filterTierPrices(
array $tierPrices,
int $key,
ProductTierPriceInterface $tierPriceItem
) {
$qty = $tierPriceItem->getQty();
if (isset($this->tierPricesQty[$qty])) {
$priceQty = $this->tierPricesQty[$qty];
if ((float)$tierPriceItem->getValue() < (float)$tierPrices[$priceQty]->getValue()) {
unset($this->formatAndFilterTierPrices[$priceQty]);
$this->tierPricesQty[$priceQty] = $key;
} else {
$discount = $this->discount->getDiscountByDifference($productPrice, (float)$tierPrice->getValue());
unset($this->formatAndFilterTierPrices[$key]);
}

$tiers[] = [
"discount" => $discount,
"quantity" => $tierPrice->getQty(),
"final_price" => [
"value" => $tierPrice->getValue(),
"currency" => $store->getCurrentCurrencyCode()
]
];
} else {
$this->tierPricesQty[$qty] = $key;
}
return $tiers;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public function __construct(
*
* @param int $productId
*/
public function addProductFilter($productId): void
public function addProductFilter(int $productId): void
{
$this->filterProductIds[] = $productId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public function resolve(

/** @var Product $product */
$product = $value['model'];
$productId = $product->getId();
$productId = (int)$product->getId();
$this->tiers->addProductFilter($productId);

return $this->valueFactory->create(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
namespace Magento\GraphQl\CatalogCustomer;

use Magento\GraphQl\GetCustomerAuthenticationHeader;
use Magento\TestFramework\TestCase\GraphQlAbstract;
use Magento\Store\Api\StoreRepositoryInterface;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\ObjectManager;
use Magento\TestFramework\TestCase\GraphQlAbstract;

class PriceTiersTest extends GraphQlAbstract
{
Expand Down Expand Up @@ -64,10 +64,12 @@ public function testLoggedInCustomer()
);

$itemTiers = $response['products']['items'][0]['price_tiers'];
$this->assertCount(3, $itemTiers);
$this->assertCount(5, $itemTiers);
$this->assertEquals(9.25, $this->getValueForQuantity(2, $itemTiers));
$this->assertEquals(8.25, $this->getValueForQuantity(3, $itemTiers));
$this->assertEquals(7.25, $this->getValueForQuantity(5, $itemTiers));
$this->assertEquals(9.00, $this->getValueForQuantity(7, $itemTiers));
$this->assertEquals(7.25, $this->getValueForQuantity(8, $itemTiers));
}

/**
Expand Down Expand Up @@ -95,12 +97,26 @@ public function testSecondStoreViewWithCurrencyRate()
);

$itemTiers = $response['products']['items'][0]['price_tiers'];
$this->assertCount(3, $itemTiers);
$this->assertCount(5, $itemTiers);
$this->assertEquals(round(9.25 * $rate, 2), $this->getValueForQuantity(2, $itemTiers));
$this->assertEquals(round(8.25 * $rate, 2), $this->getValueForQuantity(3, $itemTiers));
$this->assertEquals(round(7.25 * $rate, 2), $this->getValueForQuantity(5, $itemTiers));
}

/**
* @magentoApiDataFixture Magento/Catalog/_files/simple_product_with_tier_prices_for_multiple_groups.php
*/
public function testGetLowestPriceForGuest()
{
$productSku = 'simple';
$query = $this->getProductSearchQuery($productSku);
$response = $this->graphQlQuery($query);
$itemTiers = $response['products']['items'][0]['price_tiers'];
$this->assertCount(2, $itemTiers);
$this->assertEquals(round(8.25, 2), $this->getValueForQuantity(7, $itemTiers));
$this->assertEquals(round(7.25, 2), $this->getValueForQuantity(8, $itemTiers));
}

/**
* Get the tier price value for the given product quantity
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Magento\Store\Api\WebsiteRepositoryInterface;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
use Magento\Customer\Model\Group;

Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple.php');

Expand Down Expand Up @@ -57,6 +58,36 @@
'percentage_value'=> null,
'qty'=> 5,
'value'=> 7
],
[
'customer_group_id' => Group::CUST_GROUP_ALL,
'percentage_value'=> null,
'qty'=> 7,
'value'=> 9.25
],
[
'customer_group_id' => '1',
'percentage_value'=> null,
'qty'=> 7,
'value'=> 9.00
],
[
'customer_group_id' => Group::NOT_LOGGED_IN_ID,
'percentage_value'=> null,
'qty'=> 7,
'value'=> 8.25
],
[
'customer_group_id' => Group::CUST_GROUP_ALL,
'percentage_value'=> null,
'qty'=> 8,
'value'=> 7.25
],
[
'customer_group_id' => Group::NOT_LOGGED_IN_ID,
'percentage_value'=> null,
'qty'=> 8,
'value'=> 9
]
];
$productTierPrices = [];
Expand Down