@@ -651,6 +651,13 @@ const offerReapplyTimer = ref(null)
651651// Performance: Cache previous cart state to avoid unnecessary reapplications
652652let previousCartHash = ' '
653653
654+ // Helper function to compute cart hash
655+ function computeCartHash () {
656+ return cartStore .invoiceItems .map (i =>
657+ ` ${ i .item_code } -${ i .quantity } -${ i .rate } -${ i .discount_percentage || 0 } -${ i .discount_amount || 0 } -${ i .uom || ' ' } -${ i .warehouse || ' ' } `
658+ ).join (' |' )
659+ }
660+
654661// Promotion dialog
655662const showPromotionManagement = ref (false )
656663
@@ -749,37 +756,72 @@ watch(() => shiftStore.hasOpenShift, value => {
749756 }
750757})
751758
752- // Watch for cart changes to re-apply offers (optimized - only watch length and defer expensive calculations)
753- // Performance: Only recalculate hash if cart length changed, then check if content actually changed
759+ // Watch for cart changes to re-apply offers
760+ // Comprehensive watcher that detects all cart changes including:
761+ // - Items added/removed (length changes)
762+ // - Quantity changes
763+ // - Rate/price changes
764+ // - Discount changes
765+ // - Item properties that affect offers
754766watch (
755- () => cartStore . invoiceItems . length ,
756- () => {
767+ () => computeCartHash () ,
768+ (newHash ) => {
757769 // Only proceed if there are applied offers
758770 if (cartStore .appliedOffers .length === 0 ) {
759771 return
760772 }
761773
762- // Calculate hash only when length changes
763- const currentHash = cartStore .invoiceItems .map (i =>
764- ` ${ i .item_code } -${ i .quantity } -${ i .rate } -${ i .discount_percentage || 0 } -${ i .discount_amount || 0 } `
765- ).join (' ,' )
766-
767774 // Skip if cart content hasn't actually changed
768- if (currentHash === previousCartHash) {
775+ if (newHash === previousCartHash) {
769776 return
770777 }
771778
772- previousCartHash = currentHash
779+ previousCartHash = newHash
773780
774781 // Clear existing timer to prevent multiple API calls
775782 if (offerReapplyTimer .value ) {
776783 clearTimeout (offerReapplyTimer .value )
777784 }
778785
779- // Set new timer - reapply offers after 800ms of no changes (increased for better performance)
786+ // Set new timer - reapply offers after 500ms of no changes
780787 offerReapplyTimer .value = setTimeout (async () => {
781788 await cartStore .reapplyOffer (shiftStore .currentProfile )
782- }, 800 )
789+ }, 500 )
790+ }
791+ )
792+
793+ // Watch for customer changes - customer affects which offers are applicable
794+ watch (
795+ () => cartStore .customer ,
796+ (newCustomer , oldCustomer ) => {
797+ const newCustomerName = newCustomer? .name || newCustomer
798+ const oldCustomerName = oldCustomer? .name || oldCustomer
799+
800+ // Only reapply if customer actually changed
801+ if (newCustomerName !== oldCustomerName) {
802+ // Clear existing timer
803+ if (offerReapplyTimer .value ) {
804+ clearTimeout (offerReapplyTimer .value )
805+ }
806+
807+ // Reapply offers immediately when customer changes
808+ // This will discover newly eligible offers even if cart has no current offers
809+ offerReapplyTimer .value = setTimeout (async () => {
810+ await cartStore .reapplyOffer (shiftStore .currentProfile )
811+ }, 300 )
812+ }
813+ },
814+ { deep: true }
815+ )
816+
817+ // Watch for applied offers changes - handle when offers are added/removed
818+ watch (
819+ () => cartStore .appliedOffers .length ,
820+ () => {
821+ // When offers are added or removed, update the cart hash to reflect new state
822+ if (cartStore .invoiceItems .length > 0 ) {
823+ previousCartHash = computeCartHash ()
824+ }
783825 }
784826)
785827
@@ -998,6 +1040,8 @@ async function handlePaymentCompleted(paymentData) {
9981040 uiStore .showSuccess (` OFFLINE-${ Date .now ()} ` , cartStore .grandTotal )
9991041 uiStore .showPaymentDialog = false
10001042 cartStore .clearCart ()
1043+ // Reset cart hash after successful payment
1044+ previousCartHash = ' '
10011045
10021046 toast .create ({
10031047 title: " Saved Offline" ,
@@ -1014,6 +1058,8 @@ async function handlePaymentCompleted(paymentData) {
10141058
10151059 uiStore .showPaymentDialog = false
10161060 cartStore .clearCart ()
1061+ // Reset cart hash after successful payment
1062+ previousCartHash = ' '
10171063
10181064 if (itemsSelectorRef .value ) {
10191065 itemsSelectorRef .value .loadItems ()
@@ -1082,6 +1128,8 @@ function handleClearCart() {
10821128
10831129function confirmClearCart () {
10841130 cartStore .clearCart ()
1131+ // Reset cart hash when cart is cleared
1132+ previousCartHash = ' '
10851133 uiStore .showClearCartDialog = false
10861134 toast .create ({
10871135 title: " Cart Cleared" ,
@@ -1214,6 +1262,8 @@ async function handleSaveDraft() {
12141262 )
12151263 if (success) {
12161264 cartStore .clearCart ()
1265+ // Reset cart hash when cart is saved as draft and cleared
1266+ previousCartHash = ' '
12171267 }
12181268}
12191269
@@ -1230,6 +1280,9 @@ async function handleLoadDraft(draft) {
12301280 await cartStore .reapplyOffer (shiftStore .currentProfile )
12311281 }
12321282
1283+ // Initialize cart hash for the loaded cart so watchers work correctly
1284+ previousCartHash = computeCartHash ()
1285+
12331286 uiStore .showDraftDialog = false
12341287 } catch (error) {
12351288 // Error handled in store
@@ -1322,6 +1375,9 @@ async function handleEditOfflineInvoice(invoice) {
13221375 }
13231376 }
13241377
1378+ // Initialize cart hash for the loaded cart so watchers work correctly
1379+ previousCartHash = computeCartHash ()
1380+
13251381 await offlineStore .deleteOfflineInvoice (invoice .id )
13261382
13271383 toast .create ({
0 commit comments