Skip to content
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

Edit cart rule CQRS command #32115

Merged
merged 19 commits into from
Apr 20, 2023
Merged

Edit cart rule CQRS command #32115

merged 19 commits into from
Apr 20, 2023

Conversation

zuk3975
Copy link
Contributor

@zuk3975 zuk3975 commented Apr 11, 2023

Questions Answers
Branch? develop
Description? Adds CQRS command for editing cart rule and clean up some behat tests to have tables and cleaner implementation instead of single line stateful code.
Type? refacto
Category? BO
BC breaks? no
Deprecations? no
How to test? No need to test, added behats to support command and UI wasn't yet changed
Fixed ticket? part of #10547
Related PRs If theme, autoupgrade or other module change is needed to make this change work, provide a link to related PRs here.
Sponsor company Your company or customer's name goes here (if applicable).

BC BREAKS
Changed some arguments/types in EditableCartRule and its subclasses (not sure if I must define them exactly? because some of them might still evolve until the page is fully done). These BC breaks should practically have no influence, because cart rule symfony page was not yet released so the commands was not used at least in core. Ofc in theory someone might have used them from modules)

(Edit 06/06/2024: the page is not released so all the related code is still experimental, therefore this is not a breaking change)

@prestonBot prestonBot added develop Branch Refactoring Type: Refactoring BC break Type: Introduces a backwards-incompatible break labels Apr 11, 2023
@@ -59,7 +59,7 @@ public function __construct(
public function handle(AddCartRuleCommand $command): CartRuleId
{
//@todo: restrictions are missing. We should consider dedicated command for restrictions
$cartRule = $this->cartRuleRepository->create($this->buildCartRuleFromCommandData($command));
$cartRule = $this->cartRuleRepository->add($this->buildCartRuleFromCommandData($command));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

optional change. I switched to "add" because I think it makes sense to have add - when providing already filled object model, create -when required properties for creation are passed and the model is built inside

Copy link
Contributor

Choose a reason for hiding this comment

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

Indeed!

@zuk3975 zuk3975 marked this pull request as ready for review April 18, 2023 07:01
@zuk3975 zuk3975 requested a review from a team as a code owner April 18, 2023 07:01
@@ -59,7 +59,7 @@ public function __construct(
public function handle(AddCartRuleCommand $command): CartRuleId
{
//@todo: restrictions are missing. We should consider dedicated command for restrictions
$cartRule = $this->cartRuleRepository->create($this->buildCartRuleFromCommandData($command));
$cartRule = $this->cartRuleRepository->add($this->buildCartRuleFromCommandData($command));
Copy link
Contributor

Choose a reason for hiding this comment

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

Indeed!

@@ -28,9 +28,6 @@

namespace PrestaShop\PrestaShop\Core\Domain\CartRule\QueryResult;

use PrestaShop\PrestaShop\Core\Domain\Product\Combination\ValueObject\CombinationId;
use PrestaShop\PrestaShop\Core\Domain\Product\ValueObject\ProductId;

class EditableCartRuleActions
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
class EditableCartRuleActions
class CartRuleAction

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
class EditableCartRuleActions
class CartRuleActionForEditing

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not entirely sure, but at least we should drop the s there's only one action no? (although it contains several options)

@@ -29,7 +29,6 @@
namespace PrestaShop\PrestaShop\Core\Domain\CartRule\QueryResult;

use PrestaShop\Decimal\DecimalNumber;
use PrestaShop\PrestaShop\Core\Domain\Currency\ValueObject\CurrencyId;

class EditableCartRuleMinimum
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
class EditableCartRuleMinimum
class CartRuleMinimumForEditing

SHould we change all the query result naming with that convention? Since the query itself is GetCartRuleForEditing ?

@@ -584,7 +584,7 @@ public function useDiscountVoucherOnCart(string $voucherCode, float $discountAmo
public function useDiscountByCodeOnCart(string $voucherCode, string $cartReference)
{
$cartId = SharedStorage::getStorage()->get($cartReference);
$cartRuleId = SharedStorage::getStorage()->get($voucherCode);
$cartRuleId = (int) CartRule::getIdByCode($voucherCode);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we rely on DB code value now? If it worked fine ith the reference system we should continue to use it no? it's preferable to rely on a reference bound to a test scenario than a code in database that can be modified, the reference would still point to the same object while we'd need to adapt all following steps to match the new code

Copy link
Contributor Author

@zuk3975 zuk3975 Apr 18, 2023

Choose a reason for hiding this comment

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

Because we don't save cart rule reference by code anymore (as that was custom step), so it seemed like a nice way around it, but I can set the reference everytime we create a rule when code is not empty and that will work as before then.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm then I think we can use another reference to save the ID based on the code like after addition and edition:

if (!empty($cartRule->code)) {
   $this->getStorage()->set('cart_rule_code' . $cartRule->code, $cartRule->id);
}

then there would be to ways to get the cart rule ID:

$cartRuleId = $this->getStorage()->get('cart_rule_code' . $cartRuleCode);
$cartRuleId = $this->getStorage()->get($cartRuleReference);

this allows you to keep the previous steps that were based on the code as reference but at least only IDs are stored in every case. And we could even add some helper method getCartRuleIdByReference($reference): int and getCartRuleIdByCode($code): int

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just saved by the code whenever is not empty, that should be enough

$cartRule = $this->getCommandBus()->handle($command);

//@todo: should be refactored to save only id to shared storage instead of whole object model
SharedStorage::getStorage()->set($cartRuleReference, new CartRule($cartRule->getValue()));
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
SharedStorage::getStorage()->set($cartRuleReference, new CartRule($cartRule->getValue()));
$this->getSharedStorage()->set($cartRuleReference, new CartRule($cartRule->getValue()));

(this should be replaced in the whole file)

Copy link
Contributor

Choose a reason for hiding this comment

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

We should stop using the singleton method, maybe it would be simpler to actually remove it completely

Copy link
Contributor

Choose a reason for hiding this comment

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

However I don't think the refacto should be done in another PR, all our references are based on IDs and we should always do it this way. It forces fetching the object instead of relying on an existing object from previous step

Comment on lines 221 to 223
foreach ($cartRuleReferenceArray as $carRuleReference) {
$cartRuleIds[] = SharedStorage::getStorage()->get($carRuleReference)->id;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

If references are correctly storing IDs it allows using the referencesToIds method

private function buildAction(array $data): ?CartRuleActionInterface
{
$actionWasSet = false;
$builder = new CartRuleActionBuilder();
Copy link
Contributor

Choose a reason for hiding this comment

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

Ok for now but the CartRuleActionBuilder will have to be refactored to be come stateless later

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah Im still thinking about that stateless. Its hard to do. I've tried similar stuff, but its messy 😄
Further more if we just provide array of $data to build method, it will be coupled with form, meaning we will have to duplicate everything in behats 😓 So I wonder if its really worth it

Copy link
Contributor

Choose a reason for hiding this comment

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

Well you already have to do the mapping from the behat table format already, when you could also build the CartRuleAction from scratch without using the CartRuleActionBuilder

To make it work you would only need to adapt the behat format to the expected builder format:

$builderData = [
    'gift_product_id' => $tableNodeData['gift product'],
    'gift_product_attribute_id' => $tableNodeData['gift combination'],
];

It would actually simplify the behat test because only this mapping would be enough, you wouldn't need to replicate the behaviour of the form data handler: I check that this field and this field is present, so I can call the builder setter with to attributes. Then I check that this fields and that is present and call another setter, ...

So the whole building process would only be handled in the builder, of course its expected format would be based on the form structure because it's easier this way for us. But it's exactly what we did with the product builders, and even then we were able to adapt them to other use cases by relying on form data adapter classes (for combination bulk edition, or list edition)

@zuk3975 zuk3975 closed this Apr 18, 2023
@zuk3975 zuk3975 reopened this Apr 18, 2023
Copy link
Contributor

@jolelievre jolelievre left a comment

Choose a reason for hiding this comment

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

Thanks @zuk3975

just a few details and it's all good

);

if (!empty($data['minimum_amount'])) {
$currencyId = SharedStorage::getStorage()->get($data['minimum_amount_currency']);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
$currencyId = SharedStorage::getStorage()->get($data['minimum_amount_currency']);
$currencyId = $this->getSharedStorage()->get($data['minimum_amount_currency']);

Copy link
Contributor

Choose a reason for hiding this comment

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

To be replaced in the whole file


if (!empty($data['code'])) {
// set cart rule id by code when it is not empty
SharedStorage::getStorage()->set($data['code'], $cartRuleId->getValue());
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah I had almost the same idea (detailed in another comment), I only thought we could add a prefix cart_rule_code_ for example, it's not mandatory but it could prevent some conflicts maybe

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah I don't think its worth it, I don't think we will have such scenario which will force us to have same name for cart rule and for the code, so as long as we are not doing stupid things in behats we will be fine 😄

Copy link
Contributor

Choose a reason for hiding this comment

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

Well you'll be aware of it, but a future developer probably not But maybe it's overengineering, let's go with this current colution

Copy link
Contributor

@jolelievre jolelievre left a comment

Choose a reason for hiding this comment

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

Thanks @zuk3975

Copy link
Member

@boherm boherm left a comment

Choose a reason for hiding this comment

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

LGTM, thanks @zuk3975!

@zuk3975
Copy link
Contributor Author

zuk3975 commented Apr 20, 2023

Thanks for reviews 🚀
Merging this without QA as it is only partial PR containing behat changes and the code that was not yet exposed anywhere in Back Office (and there are more PR's to come related to cart rules migration 🎉 )

@zuk3975 zuk3975 merged commit 7e71a2d into PrestaShop:develop Apr 20, 2023
@jolelievre jolelievre added this to the 9.0.0 milestone Apr 21, 2023
@jolelievre jolelievre removed the BC break Type: Introduces a backwards-incompatible break label Jun 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
develop Branch Refactoring Type: Refactoring
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants