Repository navigation
feat(discounts): add Shopify-style discounts and a server-side cart - #254
Draft
NagariaHussain wants to merge 11 commits into
Draft
NagariaHussain wants to merge 11 commits into
NagariaHussain wants to merge 11 commits into
Conversation
The cart lived only in the browser and the Quotation was rebuilt from it, so a cart could not be built on the server and lines could not carry discounts or attributes. ERPNext also allows one coupon per document, and its rule matcher fails when coupon rules overlap. Commera Cart now holds the shopper's lines, line attributes and codes. The browser cart loads it on page load and syncs changes back, guarded by a version. Commera Discount codes stack like Shopify's product and order classes and are applied on top of ERPNext pricing on every save of a Quotation, Sales Order and Sales Invoice, into the standard discount fields.
… rules One code per discount could not give automatic discounts or unique codes, and the rules covered only a percentage or amount on items or the order. A Commera Discount now holds the rules and Commera Discount Code holds the strings shoppers type, including generated single-use codes. Discounts can be automatic, buy X get Y or free shipping, with a percentage cap, spend tiers, skipping items already on sale, a minimum purchase, a payment method, first-order or customer-group eligibility, total and once-per-customer limits, and a budget. Each placed order logs a Commera Discount Use, which drives the counts, the budget and once-per-customer. Shipping discounts change the delivery options after the plugin hooks, and the cash on delivery summary drops prepaid-only discounts.
The dashboard needs to list, edit and test discounts. The new endpoints in commera.api.admin.discounts list discounts by status and code, save one with its typed code, generate and download unique codes, refuse to delete a discount orders used, price a test cart with an unsaved draft, and fill the editor's pickers. The cart and the test cart share one preview Quotation.
Merchants could only manage discounts in Desk. Discounts in the sidebar now lists them by status with uses and discount given. The editor opens on what every discount needs, with conditions, limits and reporting in their own tabs and optional sections collapsed to a one-line summary. Its side panel summarises the rules in words, shows orders, discount given, sales and budget left as number cards, and prices a test cart with the unsaved draft. The list endpoint now returns the fields its summary reads.
Team code and plugins had no supported way to manage discounts or show a discount's amount before checkout. commera.sdk.discounts can create, read, list and update discounts, add or generate codes, preview a cart with codes and automatic discounts, and read the discounts an order used. Writes need the caller's own permission on Commera Discount. The new cart and discount names join the frozen public SDK list; nothing was removed, so API_VERSION stays.
Explains why discounts are not ERPNext coupons, the discount step on each save, the cart sync, the dashboard screens, the SDK and the records, with diagrams and screenshots.
An automatic discount with no qualifying item in the cart was still chosen, and then blocked an order code it does not combine with. A discount now takes part only when it would take something off the cart, and a shopper's code that gives nothing says that nothing in the cart qualifies.
Plugins could build carts and discounts through the SDK but could not give discounts of their own, read the discounts on a cart or order, or tag a guest's cart before checkout. The cart_discounts hook lets an app take an amount off a line or the order; it competes with the merchant's product discounts per line and adds to order discounts, and orders keep what the cart got. cart_created and discount_used join commera_events, and order snapshots carry discounts. The SDK Cart, PricedCart and Order now return discounts and attributes per order and line. set_cart_attributes sets cart-level attributes, and set_cart_fields now works before checkout by waiting on the server cart.
A cart link always replaced the cart and always went to checkout, so it could not add a product to the current cart or land on the cart or a product page. `?mode=add` now keeps the cart and adds the link's lines, and `?return_to=cart` or a path on this site picks the page after; anything else keeps the default. A return_to that would leave the site is ignored.
An app that limits a code could only refuse the whole cart at checkout and ask the shopper to remove the code. The validate_discount_code hook takes the cart and a code and returns a refusal, for discount codes and the store coupon alike. A refused code cannot be added, is skipped while the cart changes, and is removed at checkout with the app's message and the new total. The removal is committed before the message so a retry does not refuse again.
The summer theme has its own cart link page, and it did not pass is_merge. A link with mode=add replaced the cart there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #223
Closes #246
Closes #247
Closes #249
Summary
Merchants can now create Shopify-style discounts in the dashboard: codes or automatic discounts that stack per line and per order on top of ERPNext pricing. The cart also moves to the server, so code and plugins can build a cart and give its lines attributes.
Why
ERPNext allows one coupon per document, and its Pricing Rule matcher fails when coupon rules overlap. A coupon rule can also cancel an automatic rule on the same item. Commera Discount records are outside that matcher, and their result goes into ERPNext's standard discount fields. The Sales Order, Sales Invoice and GL flow does not change.
What changed
commera.api.admin.discounts.commera.sdk.discounts, and new cart functions incommera.sdk.cart. Nothing was removed, soAPI_VERSIONstays.bench migrate.cart_discountshook lets an app take an amount off a cart line or the order. It competes with the merchant's product discounts for a line and adds to order discounts, and orders keep what the cart got.cart_createdanddiscount_usedevents. Order event snapshots now includediscounts.discountsandattributesfor the order and for each line. The newcart.set_cart_attributessets cart-level attributes.cart.set_cart_fieldsnow also works before checkout, for guests too.validate_discount_codehook lets an app refuse a code with a message. This works for discount codes and the store coupon. At checkout a refused code is removed, and the shopper sees the message and the new total. Before this change, the whole cart was refused.?mode=addadds the link's lines to the current cart instead of replacing it.?return_to=cart, or a path on this site, sets the page that opens next. Areturn_tothat would leave the site is ignored.Details, diagrams and the SDK examples are in
docs/implementation/discounts.md.Screenshots
Discounts list
Order code with a cap, its results and a test cart
Conditions tab with collapsed sections
Collection discount with unique codes and a budget
Automatic spend tiers, and buy X get Y
Phone and dark theme
🤖 Generated with Claude Code