Jump to content
Larry Ullman's Book Forums

Coupon Code: Any Suggestions?


Recommended Posts

Hi All,

 

First off, I would like to thank Larry Ullman for publishing such an awesome book!

 

I have been able to successfully deploy an ecommerce store using the book tutorials!

My sites live @:

http://www.shieldformen.com

 

However, recently I am running into the need to offer coupon codes.

 

Does anybody have any suggestions about how to go about implementing this?

 

Thanks,

Andrew

Link to comment
Share on other sites

Thanks for the nice words and congrats on getting the project done. That's very exciting! As for your question, can you provide more information about how you imagine the coupons will work? Fixed discount? Percentage? Specific items? Requires minimum purchase? Shipping discount? Valid dates? How you specifically imagine the coupons working will dictate how you'd implement them.

Link to comment
Share on other sites

Hi Larry,

 

Thanks for getting back to me so quickly!

 

To answer your questions, I imagined it would be a fixed discount of $20 off a specific package product that I'll be offering including both the moisturizer/cleanser as a kit. No minimum purchase and no shipping discount. Valid dates would be 3 months.

 

 

Andrew

Link to comment
Share on other sites

Okay, then I would create a separate table:

 

coupons: coupon_id, product_id, coupon_code, discount, start_date, end_date

 

The coupon_code needs to be unique for every coupon. In the orders table you would want to store the coupon_id, too. This does assume that each order can only have one coupon apply. Also, this is a simple solution to a fixed use of coupons. More flexible, complicated, coupon situations would require alternative designs.

Link to comment
Share on other sites

I am tackling this right now actually. My solution is insanely complicated at the moment, because it is supposed to handle all sorts of different types of coupon codes, but I'll explain the basic discounts here. My solution is designed for an object oriented environment, but it could easily be applied outside of that.

 

So, I have a cart class. The cart can have a coupon code object applied to it. The coupon codes are generated by a static factory function instead of a constructor.

 

You pass it the string from the coupon code, and it looks it up in the database. The database stores the code, it's code type, start and end dates, and an amount value, which is nullable. The code type is an integer, which is aligned with an array in the parent class. Right now, there is: "PERCENT" =1 ,"STATIC" =2 ,"FREE_SHIPPING"=3

 

Percent is of course a percentage off of the total, static is a static dollar amount off, free shipping is free shipping. If it's percent, the amount is interpreted as a percent discount, whereas if it's a static type, the amount is interpreted as a dollar amount.

 

While this is designed around being object oriented, you could easily do it with simple functions, and a switch-case structure, which determines the appropriate discounts based upon the type.

 

I actually have a whole other table, which contains links from the codes to the products, for individual discounts etc, but that is a whole other store for another day!

  • Upvote 1
Link to comment
Share on other sites

My solution is insanely complicated at the moment. (...)

 

So, I have a cart class. The cart can have a coupon code object applied to it.

 

Looks like a pretty perfect setup if you ask me. So far.

 

When it comes to you static factories, would've skipped that. Create one solid discount class and extend that if needed. There's really no difference between a percentage and a dollar discount. It should be able to display both of those without a problem. What If you need a percentage discount, but still want to provide free shipping? Don't make things to hard to work with. With a factory, unless it's an abstract factory, you don't have that possibility. (Easily)

 

Keep it simple. As you won't offer that many types of discounts, a factory seems like over complicating things a lot. Basic polymorphism or an interface would be recommendations here. "Super-special Valentines day 15% women's discount for men's clothes, with free shipping", here I come.

 

Excuse my English, btw.

  • Upvote 2
Link to comment
Share on other sites

That is a good point on the factory pattern. However, the reason that I implemented it is that I have a large variety of different types of discounts, for various different stores. They are capable of handling any type of discount one could imagine, even with incredible conditions, like conditionals, rebates, buy x get x free etc.

I have several different store systems across 3 or 4 different websites at this point, and I needed to be able to drop in the discount code files without having to alter the checkout implementations, and it seemed like the best way to make it that portable.

 

It basically winds up that I have

$cartCode = DiscountCode::factory("THECODE");
$cart->applyDiscountCode($cartCode);

And can add new types of discounts across the board.

Link to comment
Share on other sites

Very good. You have obviously put some thought into this.

 

I'm not buying that you should have different classes for percentage, amounts and free-shipping. You should be able to use both percentage and amount discounts on ANY discount object, and you should be able to display the discount in percent when specifying amounts and vica-verca. Free-shipping should only be a basic boolean member in the super class.

 

I would've worked out a criteria system instead. This way, the discount class will be simple. You can just add a general discount for everyone, or you can narrow down the eligibility to those weird criterias. I tried to illustrate it in application code, but it's a bit tricky to code for others. If you like the idea, I'll surely help you out.

 

The basic idea is to let the Discount object handle all info regarding the discount itself, including calculating new price after discount and the discount percentage compared to the original price. The object should verify that the coupon is valid regarding time/dates, but THEN ask the criteria object whether or not a specific criteria is met. This way, you delegate the special criterias out of the discount class, and your code is easier to build on and understand.

 

If the system works, please feel free to ignore my post. I only find your problem interesting and challenging. I'm not really sure my solution is better, but I think it would be. Feel free to consider this yourself. :)

  • Upvote 1
Link to comment
Share on other sites

@Larry - thanks larry, that means a lot!

 

@Antonio - This is very interesting, thank you for your thoughts! Regardless of a working system or not, it would be foolish to ignore someone's input - and in this case, it even happens to be good input! :lol:

 

While I still need to maintain the factory pattern for the discount codes (I'll get to that in a moment), I think that your idea of a criteria class is quite excellent, and will implement that. I definitely agree that the checking criteria contains it's own functionality that would be better off self contained.

 

Another thing that you made me realize is that I need to refer to these as "promotions" rather than "discounts."

 

The promotion codes have to be in their own classes because the same software is being used across multiple store sites, with various different requirements and components. While it is certainly true that only one class is needed for percentages and amounts, there are other discounts, or more specifically, promotions, that are more specific to their native systems. For example, I have one store that wanted to be able to offer free gift-wrapping with a certain code. The same store needed to be able to include a downloadable coupon that could be printed out immediately after the order was placed and used in a physical store. Another store needed to be able to include a special product in the order when the code was used (they wanted it to be controlled by the inventory manager without showing up in the store). Yet another needed to award digital currency when a certain code was used (although sadly, it looks as though this project mite not get to see the light of day anyway!)

 

The factory pattern allows me to modularize these different types of promotion codes, and mix and match them for different store implementations, without having to cram huge amounts of code into the "discount" class (which, as I said, I am definitely going to change to the "promotion" class) which isn't needed by all the sites. And of course, all of these include entire systems by which the users of the site are able to create/edit codes themselves.

Link to comment
Share on other sites

The factory pattern allows me to modularize these different types of promotion codes, and mix and match them for different store implementations, without having to cram huge amounts of code into the "discount" class.

 

This is what I'm not buying. Look at the abstract factory or the builder pattern to create the basic functionality. This abstract/builder class should handle promotion names, original price, shipping, handle calculations for percentage/amounts and handle expiration dates etc. With all this functionality in one single class, use polymorphism if things need to change. You should be able to create small classes for those special cases instead.

 

Looking forward to it if you want to show us some code. :)

  • Upvote 1
Link to comment
Share on other sites

I'm going to have to disagree. The builder pattern assumes a similar construction for all the different variants. This is not the case. All of the products use a database table to store their relations to various products and systems. Different types of promotional abstractions use the database to store things differently. At this point, you gain absolutely no advantage by implementing a building pattern, vs completely separating the way that this data is extracted in the various protected constructors.

Likewise, an abstract factory is one level of abstraction too far. There is never any need to have multiple factories going, as all the promotions are only one or two descendants down from the original promotion class. There is simply not enough variation between them to warrant the overhead and additional code of an abstract factory.

 

On the other hand, in this implementation, a simple factory pattern needs only to select which descendant class to instantiate based on the code passed to it, and then let that class handle it's own unique functionality. It's extremely light weight, easy to change, and completely modular - to add a new type of promotion, all I have to do is extend the promotion class in a new file, drop it in the folder, add it to the list, and it just works. What is it exactly that you don't like about the factory pattern in this implementation?

 

I have to say though, after typing all of that out, it occurs to me that we are probably talking past eachother at this point. I will consider posting code, but will most likely wind up posting skeletal/pseudocode instead.

  • Upvote 1
Link to comment
Share on other sites

What is it exactly that you don't like about the factory pattern in this implementation?

 

I have to say though, after typing all of that out, it occurs to me that we are probably talking past eachother at this point. I will consider posting code, but will most likely wind up posting skeletal/pseudocode instead.

 

To be honest, I'm not sure. Just based on experience, I feel there's an easier way. I might be wrong there, though. It's tricky to code a coupon system inside your own head. :P

 

If you don't wanna post any code only for whatever reason, feel free to PM me some.

Link to comment
Share on other sites

 Share

×
×
  • Create New...