ERPNext Native Coupon Code Integration for Gift Cards#96
ERPNext Native Coupon Code Integration for Gift Cards#96bvisible wants to merge 44 commits intoBrainWise-DEV:developfrom
Conversation
PR #96 — Action Items & Pre-Merge ChecklistThank you, @bvisible. Excellent work — very well done. 🔴 Must Fix (Blocking)The following items must be addressed before merge, as they impact code quality, observability standards, and production readiness.
🟡 Should Fix (Recommended Before Merge)These items are not strictly blocking but are strongly recommended to ensure consistency, maintainability, and correctness.
📋 Pre-Merge Testing ChecklistThe following validations must be completed and confirmed before merging:
|
🔴 PR Review – Blocking Issues (Gift Card Balance Logic)Thanks for the work on PR #96. After detailed testing and code review, there are critical issues in gift card balance tracking that must be addressed before this PR can be safely merged. ❗ Blocking Issues1️⃣ Gift Card Balance Fully Exhausted Incorrectly
Impact: Financial data corruption, incorrect gift card exhaustion. 2️⃣ Gift Card Balance Not Restored on Invoice Return
Impact: Permanent loss of gift card value after returns. 3️⃣ Fragile Multi-Customer / Multi-Invoice Handling
Impact: Silent financial inaccuracies and future regressions. 4️⃣ Root Cause:
|
- Remove debug console.log/trace statements from useInvoice.js
- Remove debug console.log statements from posCart.js
- Remove explicit frappe.db.commit() in gift_cards.py (let caller manage transaction)
- Add CLAUDE.md to .gitignore
- Fix hardcoded 'en-US' locale in GiftCardCreatedDialog.vue (use useLocale)
- Standardize translation pattern: use {0} instead of %s
Problem: ERPNext clears discount_amount on saved invoices, causing: - Gift card balance fully exhausted instead of partial usage - Balance not restored on invoice cancellation Solution: - Add posa_gift_card_amount_used custom field to Sales Invoice - Frontend sends this field with the actual discount amount - Backend uses this persisted field instead of discount_amount - Fallback logic for backward compatibility Fixes balance tracking issues reported in PR BrainWise-DEV#96 review.
|
I found strange issue is that when I return sales invoices with giftcard . I found the status "Un Paid" for Orginal Invoice and Normal "Return" Invoice is per my understanding we should have "Credit Note " and "Return" , Please let me know what do you think here |
The status behavior you're seeing is standard ERPNext logic:
Could you share the outstanding_amount values for both invoices? This will help identify if there's a reconciliation issue. |
|
Update: Gift card balance restoration on returns is now implemented in commit df15edc. When a return (Credit Note) is submitted, the gift card balance is automatically restored (proportionally for partial returns). |
|
Hello @bvisible, While reviewing the return flow in ERPNext, I identified a behavior that requires an update from our side. Specifically, the POS should send update_outstanding_for_self = 0. This adjustment ensures that the return is processed as a standard return, consistent with the expected ERPNext behavior. However, after applying this change, I noticed that the invoice appears as partially paid, as if the coupon amount is not being fully reflected in the return process. Could you please merge the latest changes and re-test the flow? Payment entries Return behavior This will help confirm whether the issue is fully resolved or if additional adjustments are needed. Thank you for your support. Best regards, |
|
Hi @engahmed1190, Test Results:
The combination of update_outstanding_for_self = 0 and the gift card return handling works as expected. Thank you for identifying this fix! Best regards, |
|
@bvisible Could you please add a screen-recorded video showing the current status, covering the full flow from creation through submission and return? |
|
Hi @engahmed1190, Here are the screen-recorded videos showing the complete gift card flow:
Demonstrates selling a gift card item and automatic creation of the Coupon Code with balance. Create_giftcard.mp4
Shows applying the gift card as a discount on a sale, with balance deduction. Use_giftcard.mp4
Demonstrates creating a return/credit note and the automatic restoration of the gift card balance. Return_giftcard.mp4Let me know if you need any additional information! |
|
Regarding the Creation I was having in mind to create it from the Promotions In the Side Menu as You shown in the Use if Gift Card. Any reason why you added it in the item Selection Also Please show the Invoice Status in ERPNext as the Backend as I want to verify the Invoice Creation Status. Please |
|
Nice got your point also may you please record the creation of gift card item from item list as I want to replicate the same on my site. Thanks nice work ! |
|
Hello @bvisible , I have tested the case but found it show Partly Paid, Kindly let me know If I missed something .. |
|
Hi @engahmed1190 ,
That's it! When this item is sold, a Coupon Code is automatically created with the sale price as the gift card value. Settings_giftcard.mp4 |
Thanks for the video! I think I understand the issue. The "Partly Paid" status might be caused by a Pricing Rule or promotional price on the item. When you apply a gift card, if the item has a promotion that reduces the price, there can be a mismatch between the expected amount and the paid amount. I will test this scenario with a product that has a promotional price configured and get back to you with the results... |
|
Can you test this commit? 46f36d4 |
|
I will test and update you. Nice responding time. |
|
Let me know if you need anything else . |
|
Hello @engahmed1190 , Root Cause The frontend was sending additional_discount_amount for the gift card discount, but this field does not exist in the ERPNext Sales Invoice schema. The backend expects Solution Changed additional_discount_amount → discount_amount in:
Validated Test
|
|
Hello @engahmed1190 , We have other improvements to offer, and the next one would be a “second screen” to display the ticket on the customer side and also offer the possibility of creating an account. We have already coded this into another cash register and it is already in production. |
|
Hello @bvisible . I have tested it very quickly still getting partially paid. i.e. the coupon code was not proceed. What I will do is to create new site with this Branch test it better. Sure all your new improvements are mandatory. Nice to see them merged here. |
POSNext.-.demo_1.mp4 |
|
Could you limit this PR to POS Coupons only? |
Hi @engahmed1190 , no problem limiting this PR to POS Coupons. For context, we are currently working across three different branches and sometimes need to merge them temporarily to test integrations, which is why unrelated commits can occasionally appear. What is becoming critical for us is to know whether this PR is expected to be merged into the main project or not. If not, that’s totally fine — we will simply continue development on our side. We just need clarity to plan properly. We also have another development coming (second screen display with customer account creation, address management, and duplicated cart), which makes it harder to keep everything isolated without knowing the merge direction. Since this PR has been pending for quite some time, it would really help us to have visibility on its status. And of course, if there are bugs or improvements needed, feel free to request changes from us or push fixes directly — we are happy to collaborate. |
|
I will get back to you later this week with an update on the status, as I’ll be testing this throughout the week. In the meantime, feel free to create additional PRs for:
|
ERPNext requires customer when coupon_type is Gift Card. Use Promotional type and rely on pos_next_gift_card field for identification.
- Add customer field to create_gift_card_manual coupon creation - Use unique hash instead of timestamp for referral coupon names - Fix create_coupon return value to use 'name' key
- Change update_coupon to accept single data parameter with name inside - Only set is_cumulative when valid_upto is provided (ERPNext requirement)
- Make Rate field editable when item's price_list_rate is 0 - Add isRateEditable computed property to check if rate should be editable - Style changes: white background and focus ring when editable - Enables setting custom value for gift card items in POS
- Expose openEditDialog method in InvoiceCart via defineExpose - Add invoiceCartRef in POSSale to access InvoiceCart methods - Auto-open edit dialog when adding items with rate=0 - Improves UX for gift cards that need custom value entry
- Add rate field handling in updateItemDetails function - Also update price_list_rate when original was 0 for consistency - Fixes gift card rate not persisting after edit dialog update
Add API function to retrieve gift cards created from a specific invoice. This is needed to display the GiftCardCreatedDialog after selling gift card items.
- Remove debug console.log/trace statements from useInvoice.js
- Remove debug console.log statements from posCart.js
- Remove explicit frappe.db.commit() in gift_cards.py (let caller manage transaction)
- Add CLAUDE.md to .gitignore
- Fix hardcoded 'en-US' locale in GiftCardCreatedDialog.vue (use useLocale)
- Standardize translation pattern: use {0} instead of %s
Problem: ERPNext clears discount_amount on saved invoices, causing: - Gift card balance fully exhausted instead of partial usage - Balance not restored on invoice cancellation Solution: - Add posa_gift_card_amount_used custom field to Sales Invoice - Frontend sends this field with the actual discount amount - Backend uses this persisted field instead of discount_amount - Fallback logic for backward compatibility Fixes balance tracking issues reported in PR BrainWise-DEV#96 review.
- Detect return invoices (is_return=1) in process_gift_card_on_submit - Add _process_gift_card_return() to handle balance restoration - Get gift card info from original invoice (return_against) - Support partial returns with proportional balance restoration - Cap restored balance at original gift card amount
Gift cards now always create ERPNext Coupon Code directly, making this option redundant. The sync is always enabled by design.
Gift card discount was incorrectly calculated on the original subtotal instead of the net total after pricing rules. This caused validation errors when the gift card balance exceeded the discounted price. - Add netTotalBeforeAdditionalDiscount computed in useInvoice.js - Pass netTotal prop to CouponDialog for gift card calculations - Use netTotal for gift card discount capping instead of subtotal
…ft card discounts
- Add coupon_code Link field (Custom Field) on Sales Invoice for native ERPNext integration - Add validate/submit/cancel hooks for coupon usage tracking via ERPNext pricing_rule utils - Simplify update_invoice: use coupon_code directly instead of post-save DB patching - Mark posa_coupon_code as legacy, keep for backwards compatibility with gift cards
97dff40 to
4ed37fc
Compare
|
@bvisible , Thanks is it ready now . |
ERPNext v16 has a native coupon_code field on Sales Invoice, causing a ValidationError during migration when the fixture tries to create it as a Custom Field. Dynamically detect the ERPNext version by reading the Sales Invoice DocType JSON and only include the custom field for v15 and below.
The previous relative path calculation was wrong because __file__ resolves to pos_next/pos_next/hooks.py, not pos_next/hooks.py. Use importlib.import_module to reliably find the erpnext package directory regardless of install path.
…for v15 The fixtures JSON is imported directly by Frappe during migrate (import_doc reads the full file, ignoring hooks.py filters). This caused a ValidationError on ERPNext v16+ where coupon_code is a native field on Sales Invoice. - Remove Sales Invoice-coupon_code entry from custom_field.json - Add ensure_coupon_code_field() in install.py that creates the Custom Field only on ERPNext v15 (where it does not exist natively) - Called from both after_install and after_migrate hooks
ERPNext's set_pos_fields() (called inside set_missing_values when for_validate=False) overwrites ignore_pricing_rule with the POS Profile value (default: 0). This caused apply_pricing_rule_on_transaction() to run during save/validate and overwrite the capped discount amount sent by the POS frontend with the full Pricing Rule amount (e.g. 500 CHF gift card on a 300 CHF invoice), triggering a validation error. Fix: re-set ignore_pricing_rule=1 after set_missing_values() in both update_invoice() and submit_invoice() to ensure the POS frontend's already-computed discounts are preserved.
Sales Invoice stores the Coupon Code *document name* (e.g. 'Gift Card GC-MV2S-Y1G9') in coupon_code/posa_coupon_code, but the on_submit/ on_cancel hooks were querying by the coupon_code *field* value (e.g. 'GC-MV2S-Y1G9'), causing a mismatch that silently skipped balance updates after every gift card payment. Add _get_gift_card_coupon() helper that tries by document name first, then falls back to the coupon_code field. Apply it in process_gift_card_on_submit, _process_gift_card_return, and process_gift_card_on_cancel.
|
Hi @engahmed1190, We set up a clean ERPNext v16 instance (without any of our custom instance The following scenarios were tested and are working correctly:
Could you confirm on your end that everything looks good before we merge? Thanks! |



Summary
Complete refactoring of the Gift Card system to use ERPNext's native
Coupon Codedoctype instead of the customPOS Coupondoctype. This provides native Webshop compatibility, standard ERPNext reporting, and better accounting integration.Key Changes
🎯 Core Architecture
Before: Custom
POS Coupondoctype only (isolated from ERPNext, no Webshop compatibility)After: Native
ERPNext Coupon Code+Pricing Rule(single source of truth, full ERPNext integration)✨ New Features
Gift Card Sales via POS
Gift Card Application
Promotional Coupons
ERPNext UI Integration
Bug Fixes
Fix: Gift card split — validation error on invoices smaller than the card value
Root cause: ERPNext's
set_pos_fields()(called insideset_missing_values()) was overwritingignore_pricing_rule = 0from the POS Profile, causingapply_pricing_rule_on_transaction()to run duringsave()→validate()and resetdiscount_amountto the full Pricing Rule value (e.g. 500 CHF), which exceeded the invoice total (e.g. 300 CHF) and triggered aValidationError.Fix: Re-enforce
ignore_pricing_rule = 1afterset_missing_values()in bothupdate_invoice()andsubmit_invoice()(pos_next/api/invoices.py).Fix: Gift card balance not updated after partial use
Root cause:
Sales Invoice.coupon_codestores the Coupon Code document name (e.g."Gift Card GC-MV2S-Y1G9"), butprocess_gift_card_on_submitand related hooks were querying by thecoupon_codefield value (e.g."GC-MV2S-Y1G9"), causing a silent mismatch — the coupon was never found and the balance was never reduced.Fix: Added
_get_gift_card_coupon()helper that tries lookup by document name first, then falls back to filtering by thecoupon_codefield. Applied inprocess_gift_card_on_submit,_process_gift_card_return, andprocess_gift_card_on_cancel(pos_next/api/gift_cards.py).Fix: ERPNext v16 compatibility —
coupon_codecustom field conflictRoot cause: ERPNext v16 has
coupon_codeas a native field onSales Invoice. Thecustom_field.jsonfixture was trying to create it as a custom field, causing aValidationErrorduringbench migrate.Fix: Removed the entry from
custom_field.jsonand added programmatic creation ininstall.pyfor ERPNext v15 only.Files Changed
Backend (
pos_next/)api/gift_cards.pyapi/offers.pyapi/promotions.pyapi/invoices.pyignore_pricing_ruleoverridefixtures/custom_field.jsonhooks.pyinstall.pycoupon_codefield creation for ERPNext v15patches/v2_0_0/migrate_pos_coupons_to_erpnext.pypublic/js/coupon_code_list.jsFrontend (
POS/src/)composables/useGiftCard.jscomponents/sale/GiftCardCreatedDialog.vuecomponents/sale/CouponDialog.vuecomponents/sale/EditItemDialog.vuepages/POSSale.vuestores/posCart.jsTests (
pos_next/tests/)test_gift_cards.pytest_coupon_validation.pytest_promotions_coupon.pytest_referral_code.pyCustom Fields Added to
Coupon Codegift_card_amountoriginal_gift_card_amountsource_pos_invoicepos_next_gift_cardMigration
The patch
migrate_pos_coupons_to_erpnext.pyhandles migration of existing POS Coupons:Test Results
53 backend tests passing:
Frontend tests (manual):
Breaking Changes
POS Coupondoctype is now deprecated (read-only after migration)Compatibility