-
Notifications
You must be signed in to change notification settings - Fork 9.4k
[GraphQl] 29168 TierPrices filtering #29675
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[GraphQl] 29168 TierPrices filtering #29675
Conversation
Hi @Usik2203. Thank you for your contribution
❗ Automated tests can be triggered manually with an appropriate comment:
You can find more information about the builds here ℹ️ Please run only needed test builds instead of all when developing. Please run all test builds before sending your PR for review. For more details, please, review the Magento Contributor Guide documentation. 🕙 You can find the schedule on the Magento Community Calendar page. 📞 The triage of Pull Requests happens in the queue order. If you want to speed up the delivery of your contribution, please join the Community Contributions Triage session to discuss the appropriate ticket. 🎥 You can find the recording of the previous Community Contributions Triage on the Magento Youtube Channel ✏️ Feel free to post questions/proposals/feedback related to the Community Contributions Triage process to the corresponding Slack Channel |
@magento run all tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @Usik2203. Please, check my recommendations below.
Also, do you have covering this case by API-functional test in your plans?
* | ||
* @return bool | ||
*/ | ||
private function isFirstPriceBetter(float $firstPrice, float $secondPrice): bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would not suggest creating a separate method for such a simple comparison. It makes code harder to read and introduces semantical complexity. In the future, if we will need more complex comparison we can always create a separate method. But on this stage, I would keep things simple
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
private function filterTierPrices(array $tierPrices): array | ||
{ | ||
$qtyCache = []; | ||
foreach ($tierPrices as $item => &$price) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are passing the &$price
variable by reference but it does not seem like we modify it somehow in the loop below. But I may miss something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Usik2203
Both methods, filterTierPrices
and formatProductTierPrices
, which are called one after another, are using foreach
to loop through the tier prices.
Given that this code executes when a query searches for products, please consider a situation where we might have large b2b catalog with plenty tiers for different customer groups and a relatively short search phrase, yielding plenty of results.
Having to loop twice through all tier prices in all search results, might lead to performance degradation.
I am wondering, could these two methods be somehow combined, so that we get the same results using foreach
only once?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pmarjan Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Usik2203
From "clarity of intent" perspective, when one reads through the "resolve" function alone, it seems as though formatProductTierPrices function does only what its name says. In fact this function's comment seems to support that.
But, that is misleading.
So, I am wondering can we have a function named like filterAndFormatProductTierPrices, that invokes a foreach loop, and inside this loop, one below the other filterTierPrices and formatProductTierPrices are called?
Check for example, when an unfortunate situation like we have, calls for two different things to be done in the same method:
League\Flysystem\Filesystem::readAndDelete()
internally first calls
$this->read()
and later
$this->delete()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pmarjan Done
@magento run all tests |
Hi @rogyar |
app/code/Magento/CatalogCustomerGraphQl/Model/Resolver/PriceTiers.php
Outdated
Show resolved
Hide resolved
dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogCustomer/PriceTiersTest.php
Outdated
Show resolved
Hide resolved
dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogCustomer/PriceTiersTest.php
Outdated
Show resolved
Hide resolved
@magento run all tests |
@magento run all tests |
@magento run all tests |
Hi @rogyar, thank you for the review. |
@@ -120,42 +120,89 @@ function () use ($productId, $context) { | |||
|
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
* @param ProductTierPriceInterface $tierPrice | ||
* @param array $tiers | ||
*/ | ||
private function formatTierPrices(float $productPrice, StoreInterface $store, &$tierPrice, &$tiers) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we kind of prohibit passing params by reference &$tierPrice, &$tiers
You better want a function that returns something. You rarely want a function that returns 2 things.
formatTierPrices can return $tiers for example.
Objects are passed by reference by default so you don't need &$tierPrice to do $tierPrice->setValue
You can also do that outside formatTierPrices and don't set anything in tierPrice, just get
Plus you only need getValue and getQty and getPercentageValue from it. You can use those params directly not by passing the whole tierPrice.
From store you only need CurrencyCode not store.
Suddenly your method becomes: formatTierPricesValues(productPrice, tierPriceValue, TierPricePercentage, tierPriceQty): array (where array is $tiers)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
array $tierPrices, | ||
int $key, | ||
ProductTierPriceInterface $tierPriceItem, | ||
array &$qtyCache, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$qtyCache doesn't need to be passed by reference
it can be part of your object \Magento\CatalogCustomerGraphQl\Model\Resolver\PriceTiers
by declaring a private $productTiersByQuanity[] //you can dcument that this acts like a cache
it can hold prices like $productTiersByQuanity[customerGroup][productId][qty] so it can be used for multiple products and if called multiple times for the same product, you can just fetch it and not even need to recalculate it.
not sure if customerGroup is required. probably not. you'l only get the relevant tiers for current customerGroup
of course filterTierPrices : array which is the filtered tiers, and you can pass formatted tiers from previous function return
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@magento run all tests |
@magento run Functional Tests CE, Integration Tests |
@magento run Functional Tests EE |
@magento run Functional Tests EE |
Hi @Usik2203, thank you for your contribution! |
Description (*)
This PR fixes issue with TierPrices filtering

Result Before

We see all prices for each quantity
Result After

We see lower price for each quantity
Related Pull Requests
Fixed Issues (if relevant)
Manual testing scenarios (*)
Questions or comments
Contribution checklist (*)