Right now, discounts for free items are only applied when those items are manually added to the cart. This often works, but in the case of a client they want the product(s) specified in Products to be automatically added when the condition is met.

I'm going to do this by adding a checkbox to the Discount Application form that will enable this functionality. When items are added to the cart, I'll check if any conditions have been met (by implementing a hook or something, or worst-case on the item-loading hook) and add the appropriate number of free items (as specified in Discount Amount) or update the quantity to that amount if the product is already in the cart. If there are already more than (discount amount X number of times condition met), I'll just do nothing.

Patch posted - current limitations

  • Probably doesn't work too well with attributes.
  • Takes maximum allowed uses into account, but not really maximum qualifying amounts. My reasoning was that it'd be nice, but in the end the cart pane will still show which discounts were actually applied. It would be nice to see that added in too, though in an improved patch. Not sure if it'll be by me.
  • Probably other stuff I'm forgetting right now. It works well for simple, and probably common, free item use cases (Discount trigger = Minimum quantity + Required product (not specific SKU), Filter type = Filter by Products, Discount type = Free items).

Comments

wizonesolutions’s picture

Status: Active » Needs review
StatusFileSize
new8.27 KB

Phew! That was a doozy, but I got it working. Discounts are applied to the product being discounted, which is why there's a lot of hocus pocus in this patch. I am aware of its imperfections but figured I'd contribute something back and see if anyone cared. Let's work together to improve it.

Disclosure: I coded this to work for free item discounts that require one product to be added to the cart and that are applied to specific products (filter_type = FILTER_TYPE_PRODUCTS). I am certain there are lots of use cases it doesn't work properly for, but it works pretty well for mine. It even respects max_times_applied! I've figured out some pretty robust math that makes sure the right amount of free items are added, but it could probably be simplified. It probably doesn't work too well with attributes or anything, but it'll work with base models.

Anyway, I hope this feature can make it into this module or at least inspire something. This module needs a good amount of refactoring, really - tons of code repeat could be avoided. I will try to do so next time I work with it, but in a separate issue.

Patch attached.

wizonesolutions’s picture

Issue summary: View changes

Detailed current state of patch.

wizonesolutions’s picture

The previous patch contained an issue with Maximum Applications; it did not respect a setting of 0. Now it should. Patch attached.

jrust’s picture

Definitely a great new feature that I've wanted. Hoping that some others can test to flush out any bugs.

wizonesolutions’s picture

Thanks for "blessing" the patch! I hope it gets reviewed and improved too.

ahimsauzi’s picture

Thanks wizonesolutions! This opens a slew of promotional possibilities in a much more elegant manner. I'd love to see this in the next release.

jrust’s picture

Wondering why you moved the logic to hook_init as opposed to keeping it in the add to cart hook? Is there something I'm missing?

wizonesolutions’s picture

Excellent question. With my session var + hook_init trick I can simulate an *after* add to cart hook, which lets me work with a cart already containing data instead of having to fake said data myself. With the discount-retrieving functions available to me, that was easiest.

jrust’s picture

hmm, still don't quite understand, because isn't all the data about the cart already there in the add to cart hook? Specifically, you just need to know what is being added to the cart, right?

wizonesolutions’s picture

@jrust: Yeah, the data about is being added to the cart is there, but it is not formatted the same way as it is after add_to_cart as run and you subsequently call uc_cart_get_contents(). I would have to massage it to that format if I wanted to call whichever function I'm calling (get_codeless_discounts or something) and not write a new function. Doing it in hook_add_to_cart, if it can be done in a coherent way, is better in my opinion, but I didn't have the time to go down that path, so I went with a reasonably clean solution that I knew wouldn't introduce strange issues (faking a data structure can never be good).
...
OK, I just looked at the patch. I think one big drive was to have all the cart data (especially quantity) in one place. I do some hocus pocus to make sure the right quantity of free items is added, and to do this I need to know both how many of the required_product items are in the cart and how many Free items products are in the cart. This data could be calculated, yeah, but it's easier to work with it when it's already there.

I actually just noticed an issue with my approach. It is possible to stop cart adding in hook_add_to_cart, but my approach always assumes it is successful. A simple before-and-after quantity check could get around that, though. A bit of an edge case, but worth thinking about.

All in all, though, improvements could be made to my patch, and I contributed it knowing that. So if something seems weird, keep asking me as you're doing. It might actually just be kinda weird. The whole thing for me still has a bit of a hackish feel to it, and it's partially because I was working with the module understanding I had and didn't want to write new discount-retrieval functions, but doing so would probably make the code cleaner and more understandable.

Hope this explains.

timmetj’s picture

Thanks man! this is realy nice and what i was looking for a long long time!
I do got one request:
Is it possible to auto add the free item at any time? Now the free product adds only when you buy one specific product (required product) But can somebody add something that the product will also add without a required product.
For example:
- add a free product for every order/product
- add a free product when the other requirement are reached (min order price or min quantity)

Keep up the good work!

wizonesolutions’s picture

Well, as mentioned, this only works with the Free items type of discount, and it was built specifically to depend on a required product being set. It wouldn't be that hard to extend, though I don't foresee myself being the one to enhance the patch. One would basically just check the code and make sure the information that the discount-handling function needs is there (e.g. the current order total) and that it is fed the correct data (e.g. things were a bit backwards with required_product, but for total price that wouldn't be necessary). Then the discount-calculation functions in the module itself should be able to take over from there. The code that adds the free items is pretty simple, and as long as it gets the right data, it would also work.

jrust’s picture

Status: Needs review » Fixed

Implemented the feature. Had to rework it since I also recently added the ability to specify multiple required products, but with the benefit that this feature will work will check all required products and then add all qualifying products to the cart.

wizonesolutions’s picture

Thanks for the attribution!

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

BigMike’s picture

Bringing this topic back to life, is there a way to achieve the functionality explained in reply #2 here: http://drupal.org/node/1416334#comment-5629688 ?

To summarize,

Currently, one has to first add a "free" product manually to her cart, then apply a discount code which can be configured to subtract the same amount as the product from the order (thereby the product becomes "free"). But it would be great if we could just enter a discount code that it itself inserts a product of value "$0" to the order (the best method to offer a free product if some condition is met).

What do you guys think? This could really help us out! I don't have any clue how to achieve this on my own :'(

Thanks
BigMike

hockey2112’s picture

Can you detail the patch process itself... how to add this patch's content to our module file? Thanks!

wizonesolutions’s picture

hockey2112: The maintainer already committed the functionality in this issue. If the official version of the module is dated before when he said he did that, then download the development version. I didn't see any patches in the other issue queue.

Also: http://drupal.org/patch/apply details the process.

wizonesolutions’s picture

Issue summary: View changes

Tweaked text a bit more, removed some extra text.