-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Coupon Code Case Sensitive #6331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Coupon Code Case Sensitive #6331
Conversation
Add a new configuration option to control the case sensitivity of coupon code and implement across all relevant models and handlers. Changes include: - Create CouponCodeCaseSensitivity concern that provides both class and instance methods to check the case sensitivity preference - Add preferred_coupon_code_case_sensitive preference to Configuration with a default value of false to maintain backward compatibility - Include concern in PromotionCode model and update normalize_code method to conditionally downcase based on configuration - Include concern in Promotion model and update with_coupon_code class method to perform case-sensitive or insensitive lookups - Include concern in PromotionHandler::Coupon and update coupon_code initialization to handle case sensitivity - Include concern in OrderPatch to make the case sensitivity behavior available to Order instances - Update coupon_code= setter in Spree::Order to conditionally normalize the code based on case sensitivity configuration, stripping whitespace and downcasing only when case-insensitive mode is enabled The default behavior remains case-insensitive to preserve existing functionality. To enable case sensitivity via: SolidusPromotions.configure do |config| config.preferred_coupon_code_case_sensitive = true end signed-off-by: Thukten Singye <thuktensingye2163@gmail.com>
Add comprehensive test coverage for the coupon code case sensitivity feature across all affected models and handlers. Changes include: - Create CouponCodeCaseSensitivity concern spec to test both class and instance methods for checking the preference in case-sensitive and case-insensitive modes - Update PromotionCode spec to verify code normalization behavior in both modes, including validation of duplicate codes with different cases when case-sensitive mode is enabled - Update Promotion spec to verify with_coupon_code class method performs correct lookups in both case-sensitive and case-insensitive modes, and preserves original case when appropriate - Update PromotionHandler::Coupon spec to verify coupon application succeeds with exact case match and fails with incorrect case when case-sensitive mode is enabled - Update Spree::Order spec to verify coupon_code setter correctly normalizes codes based on configuration, downcasing only when case-insensitive mode is active Tests cover both default behavior (case-insensitive) and case-sensitive mode to ensure backward compatibility and correct implementation of the new feature. signed-off-by: Thukten Singye <thuktensingye2163@gmail.com>
Add comprehensive documentation describing the coupon code case sensitivity configuration and its impact on promotion behavior. - Added YARD documentation for the configuration preference explaining the difference between case-sensitive and case-insensitive modes. - Added detailed module documentation for `CouponCodeCaseSensitivity`. - Updated the promotions README with a new section describing the feature. signed-off-by: Thukten Singye <thuktensingye2163@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This pull request introduces configurable case sensitivity for coupon codes in Solidus Promotions. By default, coupon codes remain case-insensitive (maintaining backward compatibility), but administrators can now enable strict case-sensitive matching where "SAVE20" and "save20" are treated as distinct codes.
- Added a new configuration preference
preferred_coupon_code_case_sensitive
(defaults to false) - Implemented case sensitivity logic across promotion models, handlers, and order processing
- Added comprehensive test coverage for both case-sensitive and case-insensitive scenarios
Reviewed Changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
File | Description |
---|---|
promotions/lib/solidus_promotions/configuration.rb |
Adds the new boolean configuration preference with detailed documentation |
promotions/app/models/concerns/solidus_promotions/coupon_code_case_sensitivity.rb |
New concern providing shared methods for checking case sensitivity configuration |
promotions/app/models/solidus_promotions/promotion.rb |
Updates coupon code lookup to respect case sensitivity setting |
promotions/app/models/solidus_promotions/promotion_code.rb |
Modifies code normalization to preserve case when sensitivity is enabled |
promotions/app/models/solidus_promotions/promotion_handler/coupon.rb |
Updates coupon handler to conditionally downcase codes based on configuration |
promotions/app/patches/models/solidus_promotions/order_patch.rb |
Includes case sensitivity concern in order model |
core/app/models/spree/order.rb |
Updates coupon code assignment to respect case sensitivity |
promotions/README.md |
Adds comprehensive documentation explaining the feature and its implications |
Multiple test files | Extensive test coverage for case-sensitive and case-insensitive scenarios |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
end | ||
end | ||
|
||
context "when preferred_coupon_case_code_sensitive is true" do |
Copilot
AI
Oct 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'preferred_coupon_case_code_sensitive' to 'preferred_coupon_code_case_sensitive'.
context "when preferred_coupon_case_code_sensitive is true" do | |
context "when preferred_coupon_code_case_sensitive is true" do |
Copilot uses AI. Check for mistakes.
context "with extra spacing" do | ||
let(:code) { " new code " } | ||
|
||
it "remove surrounding whitespace" do |
Copilot
AI
Oct 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected grammar from 'remove' to 'removes'.
it "remove surrounding whitespace" do | |
it "removes surrounding whitespace" do |
Copilot uses AI. Check for mistakes.
@ThuktenSingye Thanks! Copilot has found some small issues that I think we can easily fix. Overall, the change seems very good to me, but I'd like to get @mamhoff opinion as well, in case I'm missing something. |
@kennyadsl Thank you for the feedback. I’ll be glad to incorporate any additional improvements or refactors. |
I'd love to know the business case for this - usually, as a business I want customers to be able to successfully use my promotion codes, even if they e.g. only heard them on the radio or on a podcast. For the English language, this is a feature that's useful for very, very few stores, and setting it to Can we make the coupon code normalization a configurable class instead? I'm thinking of # promotions/configuration.rb
class_name_attribute :coupon_code_normalizer_class, default: "Promotions::CaseInsensitiveCode"
# This is the class and its API
module SolidusPromotions
class CaseInsensitiveCode
def self.call(value)
value.strip.downcase
end
end
end
# This is how it would be used, e.g. in `SolidusPromotions::PromotionCode
def normalize_code
self.value = SolidusPromotions.config.coupon_code_normalizer_class.call(value)
end This way, y'all are free to implement a |
@mamhoff Thank you for the feedback!. I agree that case-insensitive is the better default for customer experience, which is exactly why I implemented it that way. By default, the behavior is unchanged - codes remain case-insensitive just as Solidus has always maintained. The preference is opt-in, so developers have to explicitly enable case-sensitivity. Users won't encounter this unless a developer intentionally changes the configuration. With this boolean preference approach, users who need case-sensitive codes simply add one line to their configuration: config.preferred_coupon_code_case_sensitive = true They don't need to create any custom classes and make changes in multiple file. It just seems more straightforward and easy for developers. As you mention, as a business, it depends. some business prefer this way and some might not though it will made easier for those who want. |
Your reply does not include a business case, and it misses my point. I think it's preferable to not make this too easy, and we have a well-established pattern in the Solidus community to add custom classes to change behavior. I'm not going to die on this hill. Core team: You decide. :) |
The @mamhoff's point is valid. There's no need to add other possible implementations of the interface, as long as it's easily configurable. Martin is suggesting to keep the class configurable, and you swap it with your own in your Solidus app. The point is also that we are a small team, and we are not able to maintain all the possible ramifications of the use cases. Still, Solidus can be flexible enough to let you customize this part. If you can make this change, this would be the preferred way of handling this change for me as well. |
@mamhoff and @kennyadsl Thank you for the feedback! I was elaborating how my current approach wouldn't affect the default Solidus behavior though it was off from the solidus pattern. The custom configurable class approach makes sense for keeping the core maintainable while still providing flexibility. I encountered this need working with a client who runs events and they distribute the promotional code exclusively to their subscriber base or VIP customers. It just prevent from unauthorized redemptions and prevent excessive use of coupon code. There might be other business cases which I have no idea but I am happy to update and contribute if you find this needed down the road. Thank you for you time! :) |
@ThuktenSingye Thanks to you! Looking forward to the updated PR! |
We probably want to move the `coupon_code` accessor into the promotion gems
for this, otherwise `solidus_core` depends on a promotion configuration.
Alberto Vena ***@***.***> schrieb am Mo., 13. Okt. 2025,
16:23:
… *kennyadsl* left a comment (solidusio/solidus#6331)
<#6331 (comment)>
@ThuktenSingye <https://github.com/ThuktenSingye> Thanks to you! Looking
forward to the updated PR!
—
Reply to this email directly, view it on GitHub
<#6331 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAFLXKK3LOAFA2HQOOJGA7T3XOYX3AVCNFSM6AAAAACI5TDLZKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTGOJXG42DSNBUGU>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Summary
This pull request introduces coupon code case sensitivity support to Solidus Promotions.
It allows to configure whether promotion codes should be matched case-sensitively or case-insensitively.
By default, coupon codes remain case-insensitive, so promo code like SAVE20, save20, or Save20 will all apply the promotion successfully. With this update, you can enable a case-sensitive mode where the coupon code must match exactly (e.g., only SAVE20 is valid, while save20 or Save20 are not).
Key changes
CouponCodeCaseSensitivity
and the configuration preference.Checklist
Check out our PR guidelines for more details.
The following are mandatory for all PRs:
The following are not always needed: