It would be great to be able to apply a coupon code through a link, in a format something like this:

example.com/product_page?code=XXXX

So that when a user clicks the link, they end up on a product display page with a discounted price, instead of a cart view. That way, they have all available information about the product and the discounted price in one place.

I had to do this recently and took this approach:

1. Custom action triggered on "Calculating the sell price of a product":

  • looks for the query parameter "code" in the url
  • verifies code is valid and active (uses commerce_coupon code)
  • applies it to the line item on product landing page
  • saves code as a session variable

2. Custom action triggered on "After adding a product to the cart"

  • looks for code as a session variable
  • verifies code is valid and active
  • uses 'commerce_coupon_redeem_coupon' to apply to cart order
  • clears the session variable

This works but I'm not sure a session variable is a good way preserve a coupon code that arrived as a query parameter.

It would be nice to have this feature in commerce coupon or commerce discount. In the meantime, I'd be interested in any better ways to achieve this.

Remaining tasks

  1. Create tests
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

caschbre’s picture

My project is also looking to do something similar. The session variable is what we're thinking but haven't implemented it yet. I'm making note of this issue in case we get to a point we can create a patch or offer any other approaches.

GoZ’s picture

Version: 7.x-1.0-beta7 » 7.x-2.x-dev
Status: Active » Needs review
Related issues: +#2263315: Allow discount_coupon on orders without the discount, +#2697593: Add weight to coupon form fields
FileSize
5.32 KB

Instead of using sessions and params, i prefer another way :

  • Apply coupon thanks specific url : /coupon/XXXXX
  • Create new cart if no cart exists and apply coupon to this cart
  • Use https://www.drupal.org/node/2263315 patch to allow coupons to be applied without discount
  • Add destination url param to coupon, stored in $coupon->data.
  • User will be redirected to destination from destination url param (drupal_get_destination()) or from destination url param from coupon or by default to cart.

Both sessions and coupon in url params are not the best option :

  • Using session can be avoid, we just have to create or apply coupon in order, and then use user cart informations to apply coupon discounts in product prices. Coupons should not be in differents place, and order is the best place to store them.
  • Using hook_init will execute this init and conditions in each pages. Less we execute global code, lighter the execution will be.

Patch add a commerce_coupon_url submodule.
Needs https://www.drupal.org/node/2263315 patch to allow coupons to be applied without discount.
We also needs patch from issue https://www.drupal.org/node/2697593 to order coupon form fields.

GoZ’s picture

I add with this patch property metadata wrapper to display coupon path + a views handler.

GoZ’s picture

I miss some files (for views)
Sorry

mdupree’s picture

I was unable to get this module to work without adding the page arguments,
'page arguments' => array(1, 'code')
to the menu hook.

Am I understanding this correctly, but don't you need the page argument in order to pass the coupon code ?

GoZ’s picture

You are right, i miss page arguments, but only array(1) is needed.

I'll add tests to this patch

mdupree’s picture

Looks good +1 here

torgosPizza’s picture

Status: Needs review » Needs work

Some comments:

+/**
+ * Load coupon by code.
+ * @param string $code
+ *   Coupon code to load.
+ *
+ * @return object
+ */
+function commerce_coupon_url_code_load($code) {
+  return commerce_coupon_load_by_code($code);
+}

Is this needed? It seems redundant, and I don't see commerce_coupon_url_code_load() being called anywhere else.

+  /**
+   * Overrides parent::check_access().
+   */
+  function check_access($coupon_id, $op) {
+    $coupon = commerce_coupon_create('discount');
+    $coupon->coupon_id = $coupon_id;

I think 'discount' needs to be 'discount_coupon'.

This is just after a cursory glance. I haven't tested this yet, but can shortly. Until now we've been using code from #2263315: Allow discount_coupon on orders without the discount and some custom code (and I've even managed to utilize Rules Link for some use cases as well), but this solution looks like it could be cleaner.

GoZ’s picture

Status: Needs work » Needs review
FileSize
786 bytes
9.11 KB

@torgosPizza There is no way to load coupon from coupon code as url argument. The only one available on commerce_coupon is coupon id. So commerce_coupon_url_code_load() is used to load coupon from coupon code %commerce_coupon_url_code in /coupon/%commerce_coupon_url_code.

You are right for 'discount_coupon'. This code was based on existing commerce_coupon_handler_field_coupon_link.inc handler which should be wrong to.

GoZ’s picture

Issue summary: View changes
Status: Needs review » Needs work
torgosPizza’s picture

@torgosPizza There is no way to load coupon from coupon code as url argument. The only one available on commerce_coupon is coupon id. So commerce_coupon_url_code_load() is used to load coupon from coupon code %commerce_coupon_url_code in /coupon/%commerce_coupon_url_code.

Oh, I get it now. Right, I was thinking it would just be passed in as an argument, but if we can use an autoloading URL argument that would be ideal.

Thanks for the re-roll, looks good to me otherwise. And you're right about the handler for link having incorrect coupon type in its check_access() call, that might need to be a new issue.