Skip to content

ERPNext Native Coupon Code Integration for Gift Cards#96

Open
bvisible wants to merge 44 commits intoBrainWise-DEV:developfrom
bvisible:feature/erpnext-coupon-sync
Open

ERPNext Native Coupon Code Integration for Gift Cards#96
bvisible wants to merge 44 commits intoBrainWise-DEV:developfrom
bvisible:feature/erpnext-coupon-sync

Conversation

@bvisible
Copy link

@bvisible bvisible commented Jan 14, 2026

Summary

Complete refactoring of the Gift Card system to use ERPNext's native Coupon Code doctype instead of the custom POS Coupon doctype. This provides native Webshop compatibility, standard ERPNext reporting, and better accounting integration.

Key Changes

🎯 Core Architecture

Before: Custom POS Coupon doctype only (isolated from ERPNext, no Webshop compatibility)
After: Native ERPNext Coupon Code + Pricing Rule (single source of truth, full ERPNext integration)

✨ New Features

  1. Gift Card Sales via POS

    • Sell gift card items directly in POS
    • Auto-creates ERPNext Coupon Code with Pricing Rule
    • Dialog displays gift card code after purchase
    • Supports custom amounts (zero-price items with rate editing)
  2. Gift Card Application

    • Apply gift cards to invoices with balance tracking
    • Automatic splitting when gift card value exceeds invoice total
    • Balance updates after each use
    • Support for anonymous and customer-specific gift cards
  3. Promotional Coupons

    • Percentage discounts (e.g., 10% off)
    • Fixed amount discounts (e.g., CHF 20 off)
    • Configurable validity periods and usage limits
  4. ERPNext UI Integration

    • "Create Gift Card" button in Coupon Code list view
    • Quick creation dialog (amount, customer, company, validity)

Bug Fixes

Fix: Gift card split — validation error on invoices smaller than the card value

Root cause: ERPNext's set_pos_fields() (called inside set_missing_values()) was overwriting ignore_pricing_rule = 0 from the POS Profile, causing apply_pricing_rule_on_transaction() to run during save()validate() and reset discount_amount to the full Pricing Rule value (e.g. 500 CHF), which exceeded the invoice total (e.g. 300 CHF) and triggered a ValidationError.

Fix: Re-enforce ignore_pricing_rule = 1 after set_missing_values() in both update_invoice() and submit_invoice() (pos_next/api/invoices.py).

Fix: Gift card balance not updated after partial use

Root cause: Sales Invoice.coupon_code stores the Coupon Code document name (e.g. "Gift Card GC-MV2S-Y1G9"), but process_gift_card_on_submit and related hooks were querying by the coupon_code field 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 the coupon_code field. Applied in process_gift_card_on_submit, _process_gift_card_return, and process_gift_card_on_cancel (pos_next/api/gift_cards.py).

Fix: ERPNext v16 compatibility — coupon_code custom field conflict

Root cause: ERPNext v16 has coupon_code as a native field on Sales Invoice. The custom_field.json fixture was trying to create it as a custom field, causing a ValidationError during bench migrate.

Fix: Removed the entry from custom_field.json and added programmatic creation in install.py for ERPNext v15 only.

Files Changed

Backend (pos_next/)

File Description
api/gift_cards.py NEW - Complete gift card API (create, apply, split, balance)
api/offers.py Refactored to use ERPNext Coupon Code, added discount field mapping
api/promotions.py Updated coupon CRUD to use ERPNext Coupon Code
api/invoices.py Added gift card hooks + fix for ignore_pricing_rule override
fixtures/custom_field.json Custom fields for Coupon Code; removed v16 conflicting field
hooks.py Updated doc_events for Sales Invoice
install.py Programmatic coupon_code field creation for ERPNext v15
patches/v2_0_0/migrate_pos_coupons_to_erpnext.py NEW - Migration patch
public/js/coupon_code_list.js NEW - Create Gift Card button

Frontend (POS/src/)

File Description
composables/useGiftCard.js NEW - Gift card composable
components/sale/GiftCardCreatedDialog.vue NEW - Post-sale gift card display
components/sale/CouponDialog.vue Updated for gift card balance display
components/sale/EditItemDialog.vue Allow rate editing for zero-price items
pages/POSSale.vue Gift card creation flow integration
stores/posCart.js Support zero-price item rate updates

Tests (pos_next/tests/)

File Description
test_gift_cards.py NEW - Gift card creation, application, splitting tests
test_coupon_validation.py NEW - Coupon validation tests
test_promotions_coupon.py NEW - Promotional coupon CRUD tests
test_referral_code.py Updated for ERPNext Coupon Code integration

Custom Fields Added to Coupon Code

Field Type Description
gift_card_amount Currency Current balance
original_gift_card_amount Currency Original amount
source_pos_invoice Link Source invoice reference
pos_next_gift_card Check Flag for POS Next managed gift cards

Migration

The patch migrate_pos_coupons_to_erpnext.py handles migration of existing POS Coupons:

  • Creates corresponding ERPNext Coupon Codes
  • Creates Pricing Rules for each coupon
  • Preserves all balances and usage data
  • Keeps POS Coupon in read-only state (not deleted)

Test Results

53 backend tests passing:

  • Gift card code generation (format, uniqueness)
  • Manual gift card creation
  • Gift card application and splitting
  • Balance updates after usage
  • Coupon validation (expiry, customer restriction, dates)
  • Promotional coupon CRUD
  • Referral code integration

Frontend tests (manual):

  • Gift card creation via item sale ✅
  • Gift card application with discount display ✅
  • Gift card split: 500 CHF card on 300 CHF invoice → 200 CHF balance remaining ✅
  • Promotional coupons (percentage & fixed amount) ✅
  • Invoice cancellation restores gift card balance ✅
  • ERPNext v16 compatibility (no custom field conflict) ✅

Breaking Changes

  • POS Coupon doctype is now deprecated (read-only after migration)
  • API endpoints now work directly with ERPNext Coupon Code

Compatibility

  • ✅ ERPNext v15 and v16
  • ✅ ERPNext Webshop (gift cards usable on web)
  • ✅ Standard ERPNext Pricing Rules
  • ✅ ERPNext Coupon Code reports
  • ✅ Multi-company support

@engahmed1190
Copy link
Contributor

PR #96 — Action Items & Pre-Merge Checklist

Thank you, @bvisible. Excellent work — very well done.
The implementation looks solid, and your effort is much appreciated

🔴 Must Fix (Blocking)

The following items must be addressed before merge, as they impact code quality, observability standards, and production readiness.

  1. Remove Debug Logging — useInvoice.js

    • File: POS/src/composables/useInvoice.js

    • Issue: Presence of development-level debug statements.

    • Action Required:

      • Remove all instances of:

        • console.log('[useInvoice] ...')
        • console.trace(...)
      • Replace with the project-approved logger where logging is required.

  2. Remove Debug Logging — posCart.js

    • File: POS/src/stores/posCart.js

    • Issue: Debug console statements left in store logic.

    • Action Required:

      • Remove all instances of:

        • console.log('[posCart] ...')
      • Use the standardized logger instead.


🟡 Should Fix (Recommended Before Merge)

These items are not strictly blocking but are strongly recommended to ensure consistency, maintainability, and correctness.

  1. Remove Explicit Database Commit

    • File: pos_next/api/gift_cards.py

    • Function: _update_gift_card_balance()

    • Issue: Explicit frappe.db.commit() inside a lower-level helper.

    • Recommendation:

      • Remove the explicit commit.
      • Allow the caller to manage the transaction lifecycle.
  2. Clarify CLAUDE.md Handling

    • Issue: Ambiguous inclusion of CLAUDE.md in the repository.

    • Action Required:

      • Either:

        • Add CLAUDE.md to .gitignore, or
        • Confirm and document that it is intentionally tracked.
  3. Translate Documentation to English

    • File: docs/GIFT_CARD_REFACTORING_PLAN.md

    • Issue: Contains French text.

    • Action Required:

      • Translate all French content to English for consistency across documentation.
  4. Fix Hardcoded Locale

    • File: GiftCardCreatedDialog.vue

    • Issue: Hardcoded 'en-US' locale in date/number formatter.

    • Recommendation:

      • Use the active user/session locale instead of a fixed value.
  5. Standardize Translation Pattern

    • Issue: Mixed usage of translation placeholders.

    • Action Required:

      • Replace %s-style formatting with:

        __('Message {0}', [variable])
      • Apply consistently across UI components.


📋 Pre-Merge Testing Checklist

The following validations must be completed and confirmed before merging:

  • ☐ Migration patch runs successfully on existing POS Coupon data
  • ☐ Gift card creation via item sale works as expected
  • ☐ Gift card application and balance updates function correctly
  • Invoice cancellation correctly restores gift card balance
  • ☐ Feature operates correctly in offline mode

@engahmed1190
Copy link
Contributor

🔴 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 Issues

1️⃣ Gift Card Balance Fully Exhausted Incorrectly

  • When a gift card balance exceeds the invoice total, the entire balance is deducted instead of only the amount used.

  • Root cause:

    • Backend logic depends on invoice.discount_amount
    • ERPNext clears discount_amount on saved invoices
    • Falsy check (if invoice.discount_amount) causes fallback to full gift card balance

Impact: Financial data corruption, incorrect gift card exhaustion.


2️⃣ Gift Card Balance Not Restored on Invoice Return

  • Return invoices do not restore gift card balance.

  • Root causes:

    • posa_coupon_code is not present on return invoices
    • Same discount_amount = 0 issue breaks return logic

Impact: Permanent loss of gift card value after returns.


3️⃣ Fragile Multi-Customer / Multi-Invoice Handling

  • When a gift card is used across multiple invoices/customers, return calculations rely on:

    • original_amount - current_balance
  • This works by coincidence, not by design.

  • Fails for:

    • Partial returns
    • Mixed discounts
    • Complex refund scenarios

Impact: Silent financial inaccuracies and future regressions.


4️⃣ Root Cause: discount_amount Is Not Persisted

  • Frontend sends discount_amount, but it is always saved as 0 on Sales Invoice.
  • ERPNext recalculates or clears this field during validation.
  • This is the root cause of all issues above.

📍 Affected Areas

  • pos_next/api/gift_cards.py

    • process_gift_card_on_submit
    • process_gift_card_on_cancel
  • pos_next/api/invoices.py

  • POS/src/composables/useInvoice.js


bvisible added a commit to bvisible/POSNext that referenced this pull request Jan 14, 2026
- 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
bvisible added a commit to bvisible/POSNext that referenced this pull request Jan 14, 2026
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.
@engahmed1190
Copy link
Contributor

engahmed1190 commented Jan 15, 2026

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

@bvisible
Copy link
Author

I found strange issue is that when I return sales invoices with giftcard . I want 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:

  • Original Invoice → Shows "Credit Note Issued" only when outstanding_amount <= 0 AND a return exists. If outstanding_amount > 0, it shows "Unpaid."
  • Return Invoice → Shows "Return" status (this is correct).

Could you share the outstanding_amount values for both invoices? This will help identify if there's a reconciliation issue.
Also, I've identified that gift card balance restoration on returns is not yet implemented (only cancellations restore the balance).

@bvisible
Copy link
Author

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).

@engahmed1190
Copy link
Contributor

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?
Kindly verify both:

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,
Ahmed

@bvisible
Copy link
Author

bvisible commented Jan 15, 2026

Hi @engahmed1190,
I've merged your changes and tested the complete flow. Everything works correctly now:

Test Results:

  • ✅ Gift card balance: 54 → 24 (after invoice) → 54 (restored after return)
  • ✅ Original invoice status: "Credit Note Issued"
  • ✅ Return invoice status: "Return"
  • ✅ Outstanding amount: properly reduced to 0

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,
Jérémy

@engahmed1190
Copy link
Contributor

@bvisible Could you please add a screen-recorded video showing the current status, covering the full flow from creation through submission and return?

@bvisible
Copy link
Author

Hi @engahmed1190,

Here are the screen-recorded videos showing the complete gift card flow:

  1. Create Gift Card

Demonstrates selling a gift card item and automatic creation of the Coupon Code with balance.

Create_giftcard.mp4
  1. Use Gift Card

Shows applying the gift card as a discount on a sale, with balance deduction.

Use_giftcard.mp4
  1. Return (Credit Note) with Gift Card Balance Restoration

Demonstrates creating a return/credit note and the automatic restoration of the gift card balance.

Return_giftcard.mp4

Let me know if you need any additional information!

@engahmed1190
Copy link
Contributor

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

@bvisible
Copy link
Author

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

Why Item Selection instead of Promotions menu?

Creating a gift card is a sale - the customer pays money to receive the gift card. We need:

  • A Sales Invoice to record the payment received
  • Payment collection (cash, card, etc.) through checkout flow
  • Proper accounting entry (liability account for deferred revenue)

The Promotions menu is for applying/using existing coupons, not for selling new ones.

Invoice Status in ERPNext Backend:

Capture d’écran 2026-01-15 à 20 29 31
  • FA-2026-00057 (original): Status = "Credit Note Issued", Outstanding = 0.00
  • FA-2026-00058 (return): Status = "Return", Grand Total = -24.05

The gift card balance was correctly restored when the return was processed.

@engahmed1190
Copy link
Contributor

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 !

@engahmed1190
Copy link
Contributor

Hello @bvisible , I have tested the case but found it show Partly Paid, Kindly let me know If I missed something ..

https://streamable.com/7l9v1g

@bvisible
Copy link
Author

Hi @engahmed1190 ,
Here's how to set up the Gift Card item:

  1. Create the Item:
  • Create a regular Item (e.g., "Gift Card" or "giftcard")
  • Set Standard Selling Rate = 0 (the cashier enters the amount at sale time)
  • No special configuration needed on the Item itself
  1. Configure in POS Settings:
  • Go to POSNext > POS Settings for your POS Profile
  • In the "Gift Cards" section:
    • ✓ Enable Gift Cards
    • Select your item in "Gift Card Item" field
    • ✓ Enable Gift Card Splitting (optional, allows partial usage)
    • Set validity period (e.g., 12 months)

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

@bvisible
Copy link
Author

Hello @bvisible , I have tested the case but found it show Partly Paid, Kindly let me know If I missed something ..

https://streamable.com/7l9v1g

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...

@bvisible
Copy link
Author

Can you test this commit? 46f36d4

@engahmed1190
Copy link
Contributor

I will test and update you. Nice responding time.

@engahmed1190
Copy link
Contributor

image I tested it but found it still Partial Paid and Also Gift Card Discount Empty ,

@bvisible
Copy link
Author

image I tested it but found it still Partial Paid and Also Gift Card Discount Empty ,

That's strange. Could you please check something for me?

When you apply the gift card in the POS, what is the Grand Total shown at that moment? Is it exactly 0.00 or is it a negative amount?

In a previous video, I noticed the total was going negative when the gift card exceeded the invoice amount. The fix should clamp the discount so the total never goes below zero.

If the Grand Total shows a negative value before checkout, that would explain why:

  1. The gift card discount field is empty (validation may have rejected it)
  2. The invoice is "Partly Paid" instead of "Paid"

Could you share a screenshot of the POS cart after applying the gift card but before clicking Checkout?

@engahmed1190
Copy link
Contributor

https://streamable.com/3zfibk

Let me know if you need anything else .

@bvisible
Copy link
Author

Hello @engahmed1190 ,
When using a gift card that doesn't cover the full invoice amount (e.g., CHF 27.09 gift card on CHF 80 invoice), then paying the remainder in cash, the invoice was marked as "Partly Paid" instead of "Paid", and the "Gift Card Discount" field showed 0.00.

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
discount_amount.

Solution

Changed additional_discount_amount → discount_amount in:

  • POS/src/composables/useInvoice.js (saveDraft and submitInvoice)
  • POS/src/pages/POSSale.vue (offline invoices)
  • POS/src/utils/printInvoice.js (receipt display)

Validated Test

  • Item: Cours Yoga 1h Privé (CHF 80.00)
  • Gift card applied: GC-02MB-DJE3 (CHF 27.09)
  • Cash payment: CHF 53.00
  • Result: Invoice FA-2026-00075 with status "Paid", discount_amount = 27.09 ✅

@bvisible
Copy link
Author

bvisible commented Feb 1, 2026

Hello @engahmed1190 ,
have you had time to run another test?

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.

@engahmed1190
Copy link
Contributor

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.

@bvisible
Copy link
Author

bvisible commented Feb 2, 2026

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

@engahmed1190
Copy link
Contributor

@bvisible

Could you limit this PR to POS Coupons only?
I noticed that this PR also includes a translation-related commit, which may be better handled separately.

@bvisible
Copy link
Author

bvisible commented Feb 4, 2026

@bvisible

Could you limit this PR to POS Coupons only? I noticed that this PR also includes a translation-related commit, which may be better handled separately.

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.

@engahmed1190
Copy link
Contributor

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:

  1. Second screen (customer display)
  2. Customer account creation
  3. Address management
  4. Duplicate cart handling

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
- 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
@bvisible bvisible force-pushed the feature/erpnext-coupon-sync branch from 97dff40 to 4ed37fc Compare February 18, 2026 13:49
@engahmed1190
Copy link
Contributor

@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.
@bvisible
Copy link
Author

Hi @engahmed1190,

We set up a clean ERPNext v16 instance (without any of our custom instance
configurations) specifically to test this PR before merging.

The following scenarios were tested and are working correctly:

  • bench migrate runs without errors (no more ValidationError on the
    coupon_code custom field — in ERPNext v16, the coupon_code field was
    added natively to Sales Invoice, so our custom field definition was
    conflicting; we now skip creating it on v16 and only create it
    programmatically on v15)
  • Applying a gift card to an invoice smaller than the card value
    (e.g. CHF 500 card on a CHF 300 invoice) no longer throws a
    "Additional Discount Amount cannot exceed total" error
  • The gift card balance is correctly reduced after a partial use
    (CHF 500 -> CHF 200 after a CHF 300 purchase)
  • Full payment flow (draft + submit) completes successfully

Could you confirm on your end that everything looks good before we merge?

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants