Add the ability to search and refund transactions from any register when using anonymous_refund permission, allowing staff to process refunds at a different register than where the original payment was made. Currently, the POS register page (pos/register.pl) only displays transactions for the current register. This creates a workflow problem when a patron: 1. Makes a payment at Register A 2. Returns to Register B with their receipt requesting a refund 3. Staff at Register B cannot find the original transaction on their register page 4. Staff must navigate to patron account page to locate and process the refund This is particularly problematic for anonymous transactions where there may be no patron account to search. PROPOSED SOLUTION ----------------- Add a new "Search transactions" or "Process refund" feature accessible from the POS interface that allows staff with anonymous_refund permission to: 1. Search across all registers (or all registers in current branch) by: - Receipt ID / Credit number - Transaction ID / Accountline ID - Item barcode / Product code - Date range 2. Display transaction details including: - Original payment amount - Original register where payment was made - Payment type (CASH, card, etc.) - Items/services purchased - Whether transaction has already been refunded 3. Process refund at current register: - Clearly indicate: "Original payment at Register A, refund from Register B" - Create REFUND credit on the original transaction - Create PAYOUT debit at the CURRENT register (cash leaving current till) - Maintain proper accounting: Register A shows +£10, Register B shows -£10 BENEFITS -------- - Improved customer service (refund at any register) - Better support for anonymous transactions - Maintains accurate per-register accounting - Reduces staff confusion and navigation complexity
Created attachment 191252 [details] [review] Bug 41592: Add API endpoints for global account line search This patch adds new REST API endpoints to support cross-register refund functionality by allowing global searches of account lines (credits and debits) across all patrons. Changes: - Add /api/v1/account/credits endpoint for searching credits globally - Add /api/v1/account/debits endpoint for searching debits globally - Support embedding of related debits in credits endpoint - Allow searching by credit_number or accountlines_id - Fix Koha::Account::Line credits() and debits() methods to return proper Koha::Account::Credits and Koha::Account::Debits objects - Make patron_id nullable in credit and debit API definitions to support anonymous transactions The new endpoints require the 'anonymous_refund' cash_management permission and enable staff to search for and refund transactions made at any register. Test plan: 1. Apply patch and run: yarn build && ktd --restart_all 2. Test API endpoint: GET /api/v1/account/credits?q={"credit_number":"CR-123"} 3. Test with embed: GET /api/v1/account/credits?q={"credit_number":"CR-123"} with header x-koha-embed: debits 4. Verify results include credit details and embedded debit information 5. Bonus points: Run the new and updated unit tests: prove -v t/db_dependent/api/v1/account.t prove -v t/db_dependent/Koha/Account/Line.t
Created attachment 191253 [details] [review] Bug 41592: Add cross-register refund search to Point of Sale This patch adds a "Process refund" feature to the Point of Sale page, allowing staff to search for and refund transactions made at any register. Changes: - Add toolbar with "Process refund" button to pos/pay.tt - Add transaction search modal that searches by receipt number or transaction ID - Implement AJAX-based search using new /api/v1/account/credits endpoint - Display transaction details including total, date, and associated debits - Show warning when refunding transactions from different registers - Create reusable refund modal component (refund_modal.inc) with: * Transaction details summary (description, original charge, amount paid) * Payment method display (Cash/Card) * Original register information * Refund amount input with validation * Transaction type selector * Cash register selector (when applicable) * Note field for refund reason - Add JavaScript lookups to display human-readable descriptions instead of codes for both debit types and payment types - Auto-focus search input when modal opens - Filter out PAYOUT debits and already REFUNDED items The refund modal is now shared and can be reused by other pages (e.g., patron account page). It intelligently shows/hides fields based on context and available data. Requires the 'anonymous_refund' cash_management permission. Test plan: 1. Apply patch and rebuild: yarn build 2. Enable UseCashRegisters system preference 3. Create at least two cash registers for a branch 4. Make a POS sale at register A 5. Navigate to POS page 6. Click "Process refund" button 7. Search for transaction by receipt number 8. Verify transaction details are displayed correctly with proper descriptions 9. Click "Issue refund" on a debit 10. Verify refund modal shows: - Debit description (not code) - Original charge amount - Amount paid - Payment method (Cash/Card, not CASH/SIP00) - Register warning if different 11. Complete refund and verify success
Created attachment 191254 [details] [review] Bug 41592: Refactor patron account page to use shared refund modal This patch refactors the patron account page (boraccount.tt) to use the new shared refund modal component created in the previous commit, removing duplicate code and providing a consistent refund experience across both the Point of Sale and patron account pages. Changes: - Replace inline refund modal with shared refund_modal.inc component - Update modal population JavaScript to work with new modal structure: * Parse amount and amountoutstanding as floats for proper formatting * Populate transaction details fields (description, original charge, amount paid) * Hide payment method and original register rows (not applicable in this context) * Update form field IDs to match new modal structure - Fix focus to use #refund_amount instead of deprecated #returned field - Update cash register validation to use #refund_registerid_select - Add html_helpers.inc for proper formatting support The shared modal intelligently adapts to different contexts, showing only relevant information based on available data. For patron account refunds, payment method and original register information are hidden since debits can be paid by multiple credits with different payment methods. Test plan: 1. Apply patch and rebuild: yarn build 2. Navigate to a patron's account page with paid charges 3. Click "Issue refund" on a debit that has been partially or fully paid 4. Verify refund modal displays: - Transaction description (properly formatted) - Original charge amount (properly formatted with currency) - Amount paid (properly formatted) - No payment method row (hidden in this context) - No original register row (hidden in this context) 5. Enter a refund amount and complete the refund 6. Verify the refund is processed successfully 7. Verify cash register validation works when UseCashRegisters is enabled
Created attachment 191255 [details] [review] Bug 41592: Refactor register page to use shared refund modal This patch refactors the register report page (register.tt) to use the new shared refund modal component created in previous commits, removing duplicate code and providing a consistent refund experience across both the Point of Sale and register pages. Changes: - Replace inline refund modal with shared refund_modal.inc component - Update modal population JavaScript to work with new modal structure: * Parse amount and amountoutstanding as floats for proper formatting * Populate transaction details fields (description, original charge, amount paid) * Hide payment method and original register rows (not applicable in this context) * Update form field IDs to match new modal structure - Fix focus to use #refund_amount instead of deprecated #returned field - Update cash register validation to use #refund_registerid_select - Add html_helpers.inc for proper formatting support The shared modal intelligently adapts to different contexts, showing only relevant information based on available data. For patron account refunds, payment method and original register information are hidden since debits can be paid by multiple credits with different payment methods. Test plan: 1. Apply patch and rebuild: yarn build 2. Navigate to a register page with some paid charges 3. Click "Issue refund" on a debit that has been paid 4. Verify refund modal displays: - Transaction description (properly formatted) - Original charge amount (properly formatted with currency) - Amount paid (properly formatted) - No original register row (hidden in this context) 5. Enter a refund amount and complete the refund 6. Verify the refund is processed successfully