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

[4.x]: Cannot update address when checking out as guest #3229

Closed
doit-jochem opened this issue Jul 24, 2023 · 2 comments
Closed

[4.x]: Cannot update address when checking out as guest #3229

doit-jochem opened this issue Jul 24, 2023 · 2 comments
Labels
bug commerce4 Issues related to Commerce v4

Comments

@doit-jochem
Copy link

doit-jochem commented Jul 24, 2023

What happened?

Description

If the user is a guest and it has an address with an ID, the next update-cart request tries to load the addresses from the current user. The current user does not exist and this generates an error:

if ($setShippingAddress) {
            // Shipping address
            if ($shippingAddressId && !$shippingIsBilling) {
                /** @var Address|null $userShippingAddress */
                **$userShippingAddress = Collection::make($currentUser->getAddresses())->firstWhere('id', $shippingAddressId);**

So if I submit my addresses as guest, reload the page, the addresses are loaded in and then submit them again, the CartController breaks on line 572.

If I remove the address ID from the request it works again but the ID is also used for the 'billingSameAsShipping' field in the element Order on line 2989:

public function setBillingAddress(AddressElement|array|null $address): void
   
$this->billingAddressId = $address->id;

So then I can't use this feature.

Steps to reproduce

Default flow

  1. Run the checkout proces as guest and save the addresses through the actionUpdateCart in the CartController.
  2. Reload the page and reload the values from the cart in the view
  3. Submit the page again and there is an address ID in the request
  4. Now the CartController tries to get the user addressbook but there is no user.

Flow removing Address Id's from request but then billingSameAsShipping breaks

  1. Remove the Address ID's from the view
  2. Save the cart without the Address ID's
  3. Now you can update the addresses
  4. add the request param billingAddressSameAsShipping so actionUpdateCart knows you want the same billing address as shipping address
  5. Now Craft executes the afterSave and tries to set the billingAddress with the shippingAddress
  6. when executing the setBillingAddress it tries to set the same address ID on the billingAddress as the shippingAddress but there is no address ID.

Expected behavior

An check if there is a current user before trying to get the user addresses. If no user, this does not need to be executed:

if (**$currentUser &&** $shippingAddressId && !$shippingIsBilling ) {

Actual behavior

It breaks because it executes an function on null ($currentUser->getAddresses())

Craft CMS version

4.4.15

Craft Commerce version

4.2.3

PHP version

8.2

Operating system and version

Linux

Database type and version

MySQL 5.7

Image driver and version

Imagick

Installed plugins and versions

  • CraftCMS
  • Craft Commerce
@doit-jochem doit-jochem added commerce4 Issues related to Commerce v4 bug labels Jul 24, 2023
@lukeholder
Copy link
Member

lukeholder commented Jul 25, 2023

@doit-jochem I think this is working as expected.

You should only submit a shippingAddressId or billingAddressId if the current user is logged in. If they arent logged in, you should not submit a shippingAddressId or billingAddressId.

See:
https://craftcms.com/docs/commerce/4.x/addresses.html#updating-cart-addresses

If you submit shippingAddress data (no shippingAddressId), you should still be able to use the billingAddressSameAsShipping param to have the address copied over. If that isn’t working, there is a bug. I just tried to reproduce that and couldn't.

Both addresses on the cart will always have different IDs (so they can be independently updated from then on), but you can determine if they contain the same address with {% if order.hasMatchingAddresses %}.

If you are using headless, it looks like hasMatchingAddresses is not available in the json response so if you need to add it, you can add this code to your project module init:

Event::on(\craft\commerce\controllers\CartController::class, \craft\commerce\controllers\CartController::EVENT_MODIFY_CART_INFO, function(\craft\commerce\events\ModifyCartInfoEvent $event) {
    $event->cartInfo['hasMatchingAddresses'] = $event->cart->hasMatchingAddresses();
});

@doit-jochem
Copy link
Author

@lukeholder

Thanks for the answer. The hasMatchingAddresses function helped me a long way.

I thought because I received an ID from the update-cart endpoint, it was no problem to also send the same object (with ID's) back to update-cart. This means I have to unset the billingAddressId and shippingAddressId from the object when changing the address if i'm a guest.

If i'm unsetting the ID, I noticed that through every update-cart call, there are new Address ID's attached. Doesn't this mean that the Addresses table gets bloated because i'm not updating the current Address but creating a new Address object every time?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug commerce4 Issues related to Commerce v4
Projects
None yet
Development

No branches or pull requests

2 participants