This is a follow-up to http://drupal.org/node/734690. The solution there works fine but generates very long codes (min 16 chars) for coupons purchased in bulk. Please consider this patch, which attempts to remedy by dividing the number of characters specified in bulk_length between the newly purchased coupon's base code and its bulk_length. The following logic is adopted:
-for single coupons, the new coupon code length is equal to the specified bulk_length
-for multiple (bulk order) coupons, the new coupon base length is set to the specified bulk_length-8, and the bulk_length is set to 8
eg: Base coupon specified with code of PURCHASE, bulk_length of 12
- singe coupon will be PURCHASE[12-char-code]
- mult coupon will be PURCHASE[4-char-base][8-char-bulk]
The net result is that all purchased coupons will have the same length whether purchased singly or in bulk.
Thanks.
| Comment | File | Size | Author |
|---|---|---|---|
| #29 | shorter-code-length.patch | 1.76 KB | wodenx |
| #13 | uc_coupon-956840-3.patch | 13.46 KB | wodenx |
| #12 | uc_coupon-956840-2.patch | 11.79 KB | wodenx |
| #4 | uc_coupon-956840.patch | 6.03 KB | wodenx |
| #3 | uc_coupon_purchase-956840.patch | 1.76 KB | wodenx |
Comments
Comment #1
longwaveThis seems like a sensible request, but what if you set up a bulk purchase coupon with a bulk length of 8? It seems that the base length will be zero so all the purchased coupons will have the same prefix, which will cause problems. Perhaps bulk purchased coupons need a minimum initial bulk length setting of 12?
Comment #2
wodenx commentedSure, that sounds reasonable. Out of curiosity, though, what are the dire consequences of all the purchased coupons having the same prefix? Is it just a tracking issue (i.e. so you can know from the number which coupons were part of the same order)? Presumably the bulk code generator does a good enough job of assuring unique coupon numbers without the added step of a prefix unique to each order--or am I missing something?
Perhaps this could be left up to the store administrator's look-out - would it suffice to issue a warning if the initial bulk length is less than 12?
Comment #3
wodenx commentedok - attached patch generates an error if the bulk length of the base coupon <12
Comment #4
wodenx commentedActually, upon reflection, I think there's a better way.
The attached patch modifies the uc_coupon_add_form to include a fieldset for purchased coupons where you can specify the prefix length, and there's a checkbox to specify whether or not generated coupons should always have the same code length (regardless of whether they are purchased singly or in bulk). The data are stored in the "data" field of the base coupon table. Then, when a new purchased coupon is generated, if these fields are present they are used to govern the new code creation - if not, the fallback is the old default (to make the prefix length==the bulk length).
It seemed to make sense to make the form modification in the uc_coupon_add_form rather than in the uc_coupon_purchase_feature_form because those settings will affect *all* coupon purchase features based on that coupon.
While i was at it, I added an option to reset the coupon valid dates based on the purchase date. The default behavior is as it was, but in this version there is a check box which will cause the "valid_from" date for purchased coupons to be set to the purchase date. If enabled, the "valid_until" date will be calculated by adding the original term to the new start date -- i.e., if the base coupon were valid from 1/1/08 to 1/1/09 and the new coupon were purchased on 11/11/10, the new coupon would be valid 11/11/10-11/11/11.
Note that the attached patch (unlike the previous ones) is a multiple-file patch that should be applied to the uc_coupon base directory.
Thanks
-wodenx
Comment #5
longwaveThat patch looks good, and the recalculate dates option is useful. However, I would prefer those settings to stay in a hook_form_alter in uc_coupon_purchase, so there's no uc_coupon_purchase code in uc_coupon.module - but there's the problem of adding the new fields to the coupon data array on submit. I think uc_coupon_add_form_submit() needs to be reworked so it saves any extra fields straight into the data array, then uc_coupon_purchase can do everything internally.
Comment #6
wodenx commentedI agree
hook_form_alter()would be better. Are you suggesting that *any* extra fields found in the form be saved to the data array? One would then have to keep a list of uc_coupon-defined field names to know which one's didn't need to be saved. Also, other modules altering the form would have to make sure their new field names didn't conflict. How 'bout one of these three options:'%%field_name'- then we'd only have to search for fields beginning with the prefix and add them.executed from a custom '#validate' handler. The elements of the array would then be added to the coupon's data array.
uc_coupon_save()hook. Probably the most drupalish solution, but it means the external module would have to hold on to its data temporarily after processing the form, waiting for the hook to be invoked.Personally, I like #2 best - but you tell me which you prefer and I'll implement it.
Comment #7
longwaveYeah, I think we could stuff the remainder of $form_state['values'] into the $data array after removing the fields that uc_coupon stores separately, so other modules can use hook_form_alter and expect their data to be automatically saved. I think we can also use array_filter() to remove a number of the current checks.
Maybe something like:
If another module does need to change the data before saving, it could add a submit handler that runs before this one and alter $form_state as needed.
Alternatively, similar to option #3, we could put the new cid into $form_state after saving. Other modules can add submit handlers that run afterwards, and update the saved coupon themselves.
Comment #8
longwaveOr, build a real $coupon object in the submit handler, then add a new hook_uc_coupon_presave() and pass $coupon by reference and $form_state['values'] so modules can do what they like, and then use drupal_write_record() to save the coupon object instead of the SQL queries that are used at present?
Comment #9
wodenx commentedI think passing the $form_state values in a presave hook is a great idea - that way the other module doesn't have to worry about ordering of submit handlers. But it's your call - let me know what you'd like me to do and i'll do it...
Comment #10
longwaveYeah, I think the presave hook is probably the most flexible option while keeping it fairly simple for other developers. If we switch to drupal_write_record() as well, then uc_coupon_purchase (and other modules) can use the same technique when creating their own coupons, avoiding breakage if the database schema ever changes.
Comment #11
wodenx commentedok - sounds good
Comment #12
wodenx commentedOK - here's the solution outlined in #8.
Comment #13
wodenx commentedThis version of the patch is better - abstracts the coupon save operation to uc_coupon_save() - and uc_coupon_purchase_create() calls that rather than writing to the db directly, as per your suggestion in #10.
Comment #14
longwaveI committed a modified version of the first half of the patch in #13, keeping the new uc_coupon_save() and presave hook while cleaning up the form submit handler. Looking at the uc_coupon_purchase part next.
Comment #15
longwaveCommitted the uc_coupon_purchase part, with a few changes. I removed the "same length" option and enabled it by default, because I think this makes the most sense and there's already too many options on the coupon edit page. I also renamed the keys for the other two settings so they are more obvious as to what they do.
Marking this as fixed as we've already deviated from the original issue quite a bit, any further patches should be in new issues. Thanks for your work on these changes!
Comment #16
wodenx commentedThis all looks excellent - many thanks for taking it up.
One small thing: I'm curious as to why you enforce a minimum suffix length of 4+(bulk_length). I'm still not convinced that it would be so terrible for two purchased coupons to have the same suffix (excluding the bulk code), as long as the bulk length were long enough to assure uniqueness - and minimum of code length of 12 characters still seems a little long to me for a small store. Also, consider the use-case where a store sells coupons to resellers, who then sell or give those coupons to their customers. There may be only a handful of resellers, each buying thousands of coupons at a time - so for them it would be better if the bulk code were longer, and the purchase-suffix (for want of a better term) shorter.
Anyway, as I say, it's a small think and I can live with it as it is if you really think it's necessary.
Comment #17
longwaveCurrently, the coupon codes (single or bulk prefix) must be unique, this is enforced in other parts of the code, so we need to add a random suffix of some kind. I intend to revisit this and remove this restriction if possible at a later date, and also possibly reduce the minimum bulk length from 8 (which should be possible if you don't need thousands of codes).
Comment #19
Nutty commentedI'm having trouble reconciling this patch with the latest dev release. Any chance you are ready to revisit these restrictions at this point, longwave?
Comment #20
wodenx commentedThe patches in this thread were committed long ago - so I'm not sure what you mean by reconciling them with the latest DEV. What is your use-case and what change are you proposing?
Comment #21
Nutty commentedYes, ignore the first sentence of my previous comment. I was having trouble because the general purpose of this patch is still intact in the latest release.
The second sentence refers to longwave's quote:
"I intend to revisit this and remove this restriction if possible at a later date, and also possibly reduce the minimum bulk length from 8 (which should be possible if you don't need thousands of codes)."
I'd prefer customers need not enter a (minimum) 13 character code (code name 1 + bulk prefix 4 + code 8), as it is much too long for my use case of few affilliates with relatively few bulk coupon codes required.
On a somewhat related note, an optional limitation to "safe" characters might not be a bad idea, taken to an extreme in the last comment of this node: http://groups.drupal.org/node/25985 (but in any case leaving out 0's and O's in coupon codes).
Comment #22
Nutty commentedI opened a new issue as to my last point: http://drupal.org/node/1164034
Comment #23
wodenx commentedI agree with you about the code length - and when I have time I'll go through the code and try to figure out if the restrictions are really necessary. In the meantime, you could try the following changes:
In uc_coupon.admin.inc at line 398, change
to
Similarly in uc_coupon_purchase.module at line 284, change
to
Or, really, whatever you want the minimum length to be.
Regarding the "safe" characters option - it's a good idea, but a bit complicated since the algorithm that generates bulk coupon codes has to be repeatable. If you or someone else wants to work up a patch for it, I'll be happy to review.
Comment #24
Nutty commentedThe solution in #23 appears to work just fine (although a similar change will need to be done for assigning coupons for the uc_coupon_tracking sandbox submodule)
Comment #25
wodenx commentedactually - uc_coupon_tracking uses the same mechanism as uc_coupon_purchase mechanism for generating new coupons, so these changes should propagate. The only thing to be careful of here is that you make the lengths too short to ensure that every new coupon has a unique code. Two or more coupons sharing the same code would cause problems. I suppose we could add a check to enforce this.
Comment #26
Nutty commentedHm...
With the settings in 23, if I create a coupon with name "T" as a bulk coupon, the codes are "T" + 4 characters. When I assign this coupon, it becomes "T" + 8 character prefix, followed by 4 character codes.
Comment #27
wodenx commentedOh I see - yes there's another check. Change line 579 of uc_coupon_purchase.module to
Then you can set the "Purchased coupon suffix length" to 5 and you should end up with both bulk and single coupons having a code length of 6. But if you assign bulk coupons to more than a very few affiliates you may have problems.
Comment #28
Nutty commentedIt looks like you meant line 379. But that didn't do the trick.
I imagine line 375:
$coupon->data['bulk_length'] = 8;might have something to do with it.
Comment #29
wodenx commentedSorry line 379 yes. To clarify I've attached a patch. With this patch to the latest DEV if I:
1. create a coupon with code T
2. set the "Code Length" under "Bulk Coupon Codes" to 4
3. set the "Purchased coupon code suffix length" under "Coupon purchase/assignment options" to 1.
4. assign this coupon to an affiliate
The assigned coupon has codes that are 6 characters long (T + [one-character-suffix] + [4-character-bulk-code])
But again - this is dangerous. I did a bit of calculation. Unless I've made an egregious statistical error, with the settings above the probability of having two identical codes reaches 50% after creating about 8 100-code bulk coupons.
Comment #30
longwaveYeah, the possibility of code clash was why I was somewhat reluctant to decrease the code length in the first place - I think this needs some proper mathematical investigation to determine the lowest safe number that should be available.