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

[SSP-2065] customer's user cart is now overwritten with the incoming cart if logged in in 3rd order step #2978

Merged
merged 3 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions UPGRADE-14.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -991,3 +991,8 @@ Follow the instructions in relevant sections, e.g. `shopsys/coding-standards` or
- fix Add to cart popup product link type
- fix Bestsellers product link type
- add scroll to cart order personal pick up place select modal ([#2979](https://github.com/shopsys/shopsys/pull/2979))

- customer's user cart is now overwritten with the incoming cart if logged in in 3rd order step ([#2978](https://github.com/shopsys/shopsys/pull/2978))
- new optional parameter `shouldOverwriteCustomerUserCart` was added to `LoginMutation`
- you can use it if in certain scenarios it makes more sense to overwrite customer user's cart instead of merging it
- see #project-base-diff to update your project
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ LoginInputDecorator:
type: "[Uuid!]!"
description: "Uuids of product lists that should be merged to the product lists of the user"
defaultValue: []
shouldOverwriteCustomerUserCart:
type: "Boolean!"
description: "A boolean pointer to indicate if the current customer user cart should be overwritten by the cart with cartUuid"
defaultValue: false
2 changes: 2 additions & 0 deletions project-base/app/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,8 @@ input LoginInput {
password: Password!
"Uuids of product lists that should be merged to the product lists of the user"
productListsUuids: [Uuid!]! = []
"A boolean pointer to indicate if the current customer user cart should be overwritten by the cart with cartUuid"
shouldOverwriteCustomerUserCart: Boolean! = false
}

type LoginResult {
Expand Down
16 changes: 16 additions & 0 deletions project-base/app/src/FrontendApi/Model/Cart/MergeCartFacade.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,22 @@ public function mergeCartByUuidToCustomerCart(string $cartUuid, CustomerUser $cu
$this->mergeCarts($oldCart, $customerCart);
}

/**
* @param string $cartUuid
* @param \App\Model\Customer\User\CustomerUser $customerUser
*/
public function overwriteCustomerCartWithCartByUuid(string $cartUuid, CustomerUser $customerUser): void
sebaholesz marked this conversation as resolved.
Show resolved Hide resolved
{
$oldCart = $this->cartFacade->getCartCreateIfNotExists(null, $cartUuid);
$customerCart = $this->cartFacade->getCartCreateIfNotExists($customerUser, null);

$oldCart->assignCartToCustomerUser($customerUser);

$this->entityManager->flush();

$this->cartFacade->deleteCart($customerCart);
}

/**
* @param \App\Model\Cart\Cart $cart
* @param \App\Model\Cart\Cart $currentCart
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ public function loginWithResultMutation(Argument $argument): array
}

if (array_key_exists('cartUuid', $input) && $input['cartUuid'] !== null) {
$this->mergeCartFacade->mergeCartByUuidToCustomerCart($input['cartUuid'], $user);
if (array_key_exists('shouldOverwriteCustomerUserCart', $input) && $input['shouldOverwriteCustomerUserCart']) {
$this->mergeCartFacade->overwriteCustomerCartWithCartByUuid($input['cartUuid'], $user);
} else {
$this->mergeCartFacade->mergeCartByUuidToCustomerCart($input['cartUuid'], $user);
}
}

if (array_key_exists('productListsUuids', $input)) {
Expand Down
10 changes: 10 additions & 0 deletions project-base/app/src/Model/Cart/Cart.php
Original file line number Diff line number Diff line change
Expand Up @@ -317,4 +317,14 @@ public function setPaymentWatchedPrice(?Money $paymentWatchedPrice): void
{
$this->paymentWatchedPrice = $paymentWatchedPrice;
}

/**
* @param \App\Model\Customer\User\CustomerUser|null $customerUser
*/
public function assignCartToCustomerUser(?CustomerUser $customerUser): void
{
$this->customerUser = $customerUser;
$this->cartIdentifier = '';
$this->setModifiedNow();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,55 @@ public function testCartIsMergedAfterLogin(): void
self::assertNull($oldCart);
}

public function testCartIsOverwrittenAfterLogin(): void
{
/** @var \App\Model\Product\Product $productAddedToCustomerUserCart */
$productAddedToCustomerUserCart = $this->getReference(ProductDataFixture::PRODUCT_PREFIX . '5');
$productAddedToCustomerUserCartQuantity = 6;
$this->addProductToCustomerCart($productAddedToCustomerUserCart, $productAddedToCustomerUserCartQuantity);

/** @var \App\Model\Product\Product $productAddedToCustomerUserCart2 */
$productAddedToCustomerUserCart2 = $this->getReference(ProductDataFixture::PRODUCT_PREFIX . '1');
$productAddedToCustomerUserCart2Quantity = 1;
$this->addProductToCustomerCart($productAddedToCustomerUserCart2, $productAddedToCustomerUserCart2Quantity);

$testCartUuid = CartDataFixture::CART_UUID;

$response = $this->getResponseContentForGql(
__DIR__ . '/graphql/OverwriteCartAfterLogin.graphql',
[
'email' => 'no-reply@shopsys.com',
'password' => 'user123',
'cartUuid' => $testCartUuid,
'shouldOverwriteCustomerUserCart' => true,
],
);

$data = $this->getResponseDataForGraphQlType($response, 'Login');

$cart = $this->findCartOfCurrentCustomer();

self::assertNotNull($cart);

self::assertFalse($data['showCartMergeInfo']);

$cartItems = $cart->getItems();
self::assertCount(2, $cartItems);

/** @var \App\Model\Product\Product $firstProduct */
$firstProduct = $this->getReference(ProductDataFixture::PRODUCT_PREFIX . '72');
self::assertEquals($firstProduct->getFullname(), $cartItems[0]->getName(), 'First product name mismatch');
self::assertEquals(2, $cartItems[0]->getQuantity(), 'First product quantity mismatch');

/** @var \App\Model\Product\Product $secondProduct */
$secondProduct = $this->getReference(ProductDataFixture::PRODUCT_PREFIX . '1');
self::assertEquals($secondProduct->getFullname(), $cartItems[1]->getName(), 'Second product name mismatch');
self::assertEquals(2, $cartItems[1]->getQuantity(), 'Second product quantity mismatch');
sebaholesz marked this conversation as resolved.
Show resolved Hide resolved

$oldCart = $this->cartFacade->findCartByCartIdentifier($testCartUuid);
self::assertNull($oldCart);
}

public function testCartIsMergedAfterRegister(): void
{
$testCartUuid = CartDataFixture::CART_UUID;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
mutation OverwriteCartAfterLogin(
$email: String!
$password: Password!
$cartUuid: Uuid
$shouldOverwriteCustomerUserCart: Boolean!
) {
Login(
input: {
email: $email
password: $password
cartUuid: $cartUuid
shouldOverwriteCustomerUserCart: $shouldOverwriteCustomerUserCart
}
) {
tokens {
accessToken
refreshToken
}
showCartMergeInfo
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ import * as Yup from 'yup';

type LoginProps = {
defaultEmail?: string;
shouldOverwriteCustomerUserCart?: boolean;
};

const TEST_IDENTIFIER = 'blocks-popup-login';

export const Login: FC<LoginProps> = ({ defaultEmail }) => {
export const Login: FC<LoginProps> = ({ defaultEmail, shouldOverwriteCustomerUserCart }) => {
const { t } = useTranslation();
const cartUuid = usePersistStore((store) => store.cartUuid);
const { url } = useDomainConfig();
Expand All @@ -44,6 +45,7 @@ export const Login: FC<LoginProps> = ({ defaultEmail }) => {
email: data.email,
password: data.password,
previousCartUuid: cartUuid,
shouldOverwriteCustomerUserCart,
});

handleFormErrors(
Expand Down
9 changes: 9 additions & 0 deletions project-base/storefront/graphql/docs/schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -8617,6 +8617,15 @@ The user password.

Uuids of product lists that should be merged to the product lists of the user

</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>shouldOverwriteCustomerUserCart</strong></td>
<td valign="top"><a href="#boolean">Boolean</a>!</td>
<td>

A boolean pointer to indicate if the current customer user cart should be overwritten by the cart with cartUuid

</td>
</tr>
</tbody>
Expand Down
7 changes: 5 additions & 2 deletions project-base/storefront/graphql/generated/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,8 @@ export type LoginInputApi = {
password: Scalars['Password']['input'];
/** Uuids of product lists that should be merged to the product lists of the user */
productListsUuids: Array<Scalars['Uuid']['input']>;
/** A boolean pointer to indicate if the current customer user cart should be overwritten by the cart with cartUuid */
shouldOverwriteCustomerUserCart: Scalars['Boolean']['input'];
};

export type LoginResultApi = {
Expand Down Expand Up @@ -2923,6 +2925,7 @@ export type LoginVariablesApi = Exact<{
password: Scalars['Password']['input'];
previousCartUuid: InputMaybe<Scalars['Uuid']['input']>;
productListsUuids: Array<Scalars['Uuid']['input']> | Scalars['Uuid']['input'];
shouldOverwriteCustomerUserCart?: InputMaybe<Scalars['Boolean']['input']>;
}>;


Expand Down Expand Up @@ -5100,9 +5103,9 @@ export function useBlogArticlesQueryApi(options?: Omit<Urql.UseQueryArgs<BlogArt
return Urql.useQuery<BlogArticlesQueryApi, BlogArticlesQueryVariablesApi>({ query: BlogArticlesQueryDocumentApi, ...options });
};
export const LoginDocumentApi = gql`
mutation Login($email: String!, $password: Password!, $previousCartUuid: Uuid, $productListsUuids: [Uuid!]!) {
mutation Login($email: String!, $password: Password!, $previousCartUuid: Uuid, $productListsUuids: [Uuid!]!, $shouldOverwriteCustomerUserCart: Boolean = false) {
Login(
input: {email: $email, password: $password, cartUuid: $previousCartUuid, productListsUuids: $productListsUuids}
input: {email: $email, password: $password, cartUuid: $previousCartUuid, productListsUuids: $productListsUuids, shouldOverwriteCustomerUserCart: $shouldOverwriteCustomerUserCart}
) {
tokens {
...TokenFragments
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
mutation Login($email: String!, $password: Password!, $previousCartUuid: Uuid, $productListsUuids: [Uuid!]!) {
Login(input: { email: $email, password: $password, cartUuid: $previousCartUuid, productListsUuids: $productListsUuids }) {
mutation Login(
$email: String!
$password: Password!
$previousCartUuid: Uuid
$productListsUuids: [Uuid!]!
$shouldOverwriteCustomerUserCart: Boolean = false
) {
Login(
input: {
email: $email
password: $password
cartUuid: $previousCartUuid
productListsUuids: $productListsUuids
shouldOverwriteCustomerUserCart: $shouldOverwriteCustomerUserCart
}
) {
tokens {
...TokenFragments
}
Expand Down
17 changes: 3 additions & 14 deletions project-base/storefront/pages/order/contact-information.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import { useGtmPageViewEvent } from 'gtm/hooks/useGtmPageViewEvent';
import { GtmMessageOriginType, GtmPageType } from 'gtm/types/enums';
import { handleFormErrors } from 'helpers/forms/handleFormErrors';
import { getInternationalizedStaticUrls } from 'helpers/getInternationalizedStaticUrls';
import { isStoreHydrated } from 'helpers/isStoreHydrated';
import { getIsPaymentWithPaymentGate } from 'helpers/mappers/payment';
import { getServerSidePropsWrapper } from 'helpers/serverSide/getServerSidePropsWrapper';
import { initServerSideProps, ServerSidePropsType } from 'helpers/serverSide/initServerSideProps';
Expand Down Expand Up @@ -54,8 +53,8 @@ const ContactInformationPage: FC<ServerSidePropsType> = () => {
const updateCartUuid = usePersistStore((store) => store.updateCartUuid);
const resetContactInformation = usePersistStore((store) => store.resetContactInformation);
const customer = usePersistStore((store) => store.contactInformation.customer);
const [transportAndPaymentUrl, orderConfirmationUrl, cartUrl] = getInternationalizedStaticUrls(
['/order/transport-and-payment', '/order-confirmation', '/cart'],
const [transportAndPaymentUrl, orderConfirmationUrl] = getInternationalizedStaticUrls(
['/order/transport-and-payment', '/order-confirmation'],
domainConfig.url,
);
const [orderCreating, setOrderCreating] = useState(false);
Expand Down Expand Up @@ -88,16 +87,6 @@ const ContactInformationPage: FC<ServerSidePropsType> = () => {
}
}, []);

useEffect(() => {
if (currentCart.cart !== undefined) {
if (!currentCart.cart?.items.length) {
router.replace(cartUrl);
} else if (!(currentCart.transport && currentCart.payment)) {
router.replace(transportAndPaymentUrl);
}
}
}, [currentCart.cart, currentCart.cart?.items, currentCart.transport, currentCart.payment, isStoreHydrated()]);

const onCreateOrderHandler: SubmitHandler<typeof defaultValues> = async (formValues) => {
setOrderCreating(true);

Expand Down Expand Up @@ -267,7 +256,7 @@ const ContactInformationPage: FC<ServerSidePropsType> = () => {
{isLoginPopupOpened && (
<Popup onCloseCallback={() => setIsLoginPopupOpened(false)}>
<div className="h2 mb-3">{t('Login')}</div>
<Login defaultEmail={emailValue} />
<Login shouldOverwriteCustomerUserCart defaultEmail={emailValue} />
</Popup>
)}
</>
Expand Down
2 changes: 1 addition & 1 deletion project-base/storefront/schema.graphql.json

Large diffs are not rendered by default.