Coupon redemption fails for guest checkouts, if order has no email yet

Created on 21 November 2024, 5 months ago

Problem/Motivation

Coupon redemption fails for guest checkouts, if order has no email (stored) yet. This is the case, if the coupon redemption form is placed in the same (or earlier, which is untypical) checkout step as the guest email / address input!

The provided coupon code is not available. It may have expired or already been used.

As the form has not been saved, the email address entered is not yet stored in the order!

    if ($usage_limit_customer) {
      // Promotion cannot apply to orders without email addresses.
      if (!$email = $order->getEmail()) {
        return FALSE;
      }
      if ($usage_limit_customer <= $usage->load($this, $email)) {
        return FALSE;
      }
    }

Steps to reproduce

Proposed resolution

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

๐Ÿ› Bug report
Status

Active

Version

3.0

Component

Promotions

Created by

๐Ÿ‡ฉ๐Ÿ‡ชGermany Anybody Porta Westfalica

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @Anybody
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany Anybody Porta Westfalica

    I know this is by design currently and I have no easy solution yet. We could also set this a feature request, of course.
    The point is, that for one-/single-page-checkout you always want that on the same page. Also in other cases you often want the coupon redemption form placed in an early step.

    So I think Bug is also fine.

  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany Anybody Porta Westfalica
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany Anybody Porta Westfalica
  • ๐Ÿ‡ฎ๐Ÿ‡ฑIsrael jsacksick

    That is because you have a usage limit per customer set... This is a tricky problem, on one hand some merchants would like the coupon code to be allowed even if the order email is not, but at the same time they usually don't want the coupon code to be reused by the same customer... I think the solution to that problem is generating unique coupon codes that can be used only once in total.

    Related issues #3017503: Allow users to explicitly require customer email for coupon usage โ†’ and #3278227: Total per customer at the coupon level is ignored for unknown customers โ†’ .

    This is probably more like a feature request however, fixing this could lead to bug reports... so... not sure what to do here.

  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany Anybody Porta Westfalica

    Okay I have an idea how this might be solvable in a good fashion: For that we'd need to store the email address in the order with priority, at least for anonymous checkouts!

    Then the other validations might happen without having too specific hacks / workarounds. The email address is something special for guest checkouts, so I think it would be fine logically. The question is, is that acceptable and solvable in code?

  • ๐Ÿ‡ฎ๐Ÿ‡ฑIsrael jsacksick

    The email is set when the pane is submitted, so if it's placed in the same step, this isn't going to work unless the pane is ajaxified.

  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany Anybody Porta Westfalica

    @jsacksick yes, maybe we could already set it earlier in ContactInformation::validatePaneForm()?

  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany Anybody Porta Westfalica

    Or maybe the coupon validation could at least get the email value from form state, if not yet saved on the order and set it?

    (Just some brainstorming...)

  • ๐Ÿ‡ฎ๐Ÿ‡ฑIsrael jsacksick

    But then you'd need to ajaxify the pane and save the order from there... We're doing this in shipping and getting bug reports every now and then due to race conditions... So I'd suggest you to create your own pane if you'd like to see this fixed faster.

  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany Anybody Porta Westfalica

    @jsacksick the coupon form is already ajaxified.

    I implemented a working POC, which of course is not "the yellow from the egg" :D - just to document in code, what might be an idea.

    Risks I see here is for example setting an invalid email address on the order!

    It works, if the contact_information is in the same pane as the coupon redemption form - which is the context of this issue. Maybe you'd like to have a look and maybe this is a starting point for improvements or better solutions.

  • Pipeline finished with Canceled
    5 months ago
    Total: 2078s
    #345858
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany Anybody Porta Westfalica

    Static patch attached, if someone needs a quickfix / workaround.

  • Pipeline finished with Success
    5 months ago
    Total: 1104s
    #345910
  • ๐Ÿ‡ฎ๐Ÿ‡ฑIsrael jsacksick

    I'm sorry but a fix like the one in the patch isn't acceptable as is...
    The added logic is making too many assumptions. The contact information pane might not be used or might not be present... This can't go in as is...

  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany Anybody Porta Westfalica

    @jsacksick yeah that's kind of what I wrote in #12 and didn't set it to "Needs review" for that reason.
    It should just write the idea into code and act as basis for feedback to iterate on.

    Thanks!

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium blacksnipe

    I encountered this issue while trying to validate a promotion's per-customer limit. Our setup places the coupon code pane on the same page as the contact information pane, meaning we cannot access the email address from the order at this stage.

    The patch in #13 is a helpful quick fix, but as noted in #14, it doesnโ€™t fully resolve the underlying issue. Iโ€™d like to suggest a couple of additional points:

    • When the customer limit is set to "unlimited," the validation is bypassed entirely. While this workaround was suitable for us, itโ€™s clear that it may not be a universal solution. Still, it might be worth testing in specific cases.
    • As mentioned by @jsacksick, the contact information pane can be altered, removed, or replaced. In our case, the default pane was extended into a custom pane with the ID contact_information_custom. To address this, we need a way to reference contact_information_custom (or any other dynamically defined pane) instead of relying on the hard-coded contact_information pane.

    I've also have feedback for the @todo's in the patch:

    • Is hard-coding 'contact_information' fine here?
    • I donโ€™t think hard-coding the pane ID is the right approach. Since our implementation extends the original pane class, the pane ID should ideally be dynamic and adaptable to custom configurations.
    • Should we set an error otherwise, if a coupon code has been entered but no email address is available?
    • If a coupon code is entered but no email address is available during checkout, it might be better to display an error message. This way, customers understand that the coupon validation requires an email address and can address the issue before proceeding. Without this feedback, they might be confused about why the coupon isnโ€™t being validated.

    Just my two cents โ€” hope this helps move this forward.

Production build 0.71.5 2024