Bugzilla – Attachment 193183 Details for
Bug 40445
Point of Sale reconciliation input during daily summaries
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 40445: Add configuration options and UI enhancements
c8c2d68.patch (text/plain), 16.78 KB, created by
Martin Renvoize (ashimema)
on 2026-02-16 11:08:13 UTC
(
hide
)
Description:
Bug 40445: Add configuration options and UI enhancements
Filename:
MIME Type:
Creator:
Martin Renvoize (ashimema)
Created:
2026-02-16 11:08:13 UTC
Size:
16.78 KB
patch
obsolete
>From c8c2d6861c5b23c0e3ff187516dfaaaa0090980f Mon Sep 17 00:00:00 2001 >From: Martin Renvoize <martin.renvoize@openfifth.co.uk> >Date: Mon, 16 Feb 2026 07:50:41 +0000 >Subject: [PATCH] Bug 40445: Add configuration options and UI enhancements > >This patch adds configuration options for cashup reconciliation and >enhances the user interface with preview functionality and improved >interaction patterns. > >Configuration Options: > >1. CashupReconciliationNoteRequired (System Preference): > - Optional validation requiring reconciliation notes when discrepancies exist > - Ensures documentation of surplus/deficit causes when needed > - Can be disabled for less stringent workflows > - Applied at cashup completion time > >2. CashupReconciliationNoteAuthorisedValue (System Preference): > - Allows use of authorized value dropdown for reconciliation notes > - Provides standardized note options (e.g., "Till count error", "Cash removed") > - Falls back to free text textarea when not configured > - Improves consistency and reporting capabilities > >UI Enhancements: > >1. Cashup Summary Preview: > - Preview cashup summary for in-progress cashups > - Shows current transaction totals before completion > - Clearly indicates preview vs. final summary status > - Helps staff verify amounts before committing > >2. Improved User Experience: > - Conditional note fields based on configuration > - Authorized value dropdowns when configured > - Clear validation messages > - Responsive UI updates > >Backend changes: >- Enhanced Koha::REST::V1::CashRegisters::Cashups with preview support >- Database atomicupdate script for system preferences >- Validation logic for required notes > >Frontend changes: >- Preview modal functionality in cashup_modal.js >- Conditional rendering of note input fields >- Authorized value dropdown integration >- Enhanced summary display logic > >Test plan: >1. Apply patches and run database update >2. Configure CashupReconciliationNoteRequired: > - Enable preference > - Perform cashup with discrepancy without note - should fail > - Add note and retry - should succeed > - Disable preference - verify note optional >3. Configure CashupReconciliationNoteAuthorisedValue: > - Create AV category (e.g., CASHUP_NOTE) with values > - Set preference to category name > - Verify dropdown appears in cashup modal > - Clear preference - verify textarea shown >4. Test cashup preview: > - Start cashup on register > - Click "Preview cashup summary" > - Verify current totals displayed > - Add transaction and re-preview - verify updated > - Complete cashup - verify final summary > >Sponsored-by: OpenFifth <https://openfifth.co.uk/> >Signed-off-by: Jackie Usher <jackie.usher@westsussex.gov.uk> >--- > Koha/REST/V1/CashRegisters/Cashups.pm | 16 +++ > .../data/mysql/atomicupdate/bug_40445.pl | 40 +++++++ > installer/data/mysql/mandatory/sysprefs.sql | 2 + > .../modules/admin/preferences/accounting.pref | 10 ++ > .../intranet-tmpl/prog/js/cashup_modal.js | 104 ++++++++++++++++-- > 5 files changed, 165 insertions(+), 7 deletions(-) > >diff --git a/Koha/REST/V1/CashRegisters/Cashups.pm b/Koha/REST/V1/CashRegisters/Cashups.pm >index 375eab431e0..ffb8e63b9f1 100644 >--- a/Koha/REST/V1/CashRegisters/Cashups.pm >+++ b/Koha/REST/V1/CashRegisters/Cashups.pm >@@ -63,8 +63,24 @@ sub get { > my $c = shift->openapi->valid_input or return; > > return try { >+ >+ # Try to find as a completed cashup first > my $cashup = Koha::Cash::Register::Cashups->find( $c->param('cashup_id') ); > >+ # If not found, try as a CASHUP_START action (for preview) >+ unless ($cashup) { >+ require Koha::Cash::Register::Actions; >+ my $action = Koha::Cash::Register::Actions->find( $c->param('cashup_id') ); >+ >+ # Only allow CASHUP_START actions for preview >+ if ( $action && $action->code eq 'CASHUP_START' ) { >+ >+ # Wrap as Cashup object for summary generation >+ require Koha::Cash::Register::Cashup; >+ $cashup = Koha::Cash::Register::Cashup->_new_from_dbic( $action->_result ); >+ } >+ } >+ > return $c->render_resource_not_found("Cashup") > unless $cashup; > >diff --git a/installer/data/mysql/atomicupdate/bug_40445.pl b/installer/data/mysql/atomicupdate/bug_40445.pl >index f6226eb4512..e73db60c26f 100755 >--- a/installer/data/mysql/atomicupdate/bug_40445.pl >+++ b/installer/data/mysql/atomicupdate/bug_40445.pl >@@ -33,5 +33,45 @@ return { > $out, > "Staff can now record actual cash amounts during cashup with automatic surplus/deficit tracking" > ); >+ >+ # Add CashupReconciliationNoteRequired preference >+ $dbh->do( >+ q{ >+ INSERT IGNORE INTO systempreferences (variable, value, options, explanation, type) >+ VALUES ( >+ 'CashupReconciliationNoteRequired', >+ '0', >+ '', >+ 'Require a reconciliation note when completing cashup with discrepancies between expected and actual amounts', >+ 'YesNo' >+ ) >+ } >+ ); >+ >+ say_success( $out, "Added CashupReconciliationNoteRequired system preference" ); >+ say_info( >+ $out, >+ "CashupReconciliationNoteRequired: Controls whether reconciliation notes are required during cashup with discrepancies" >+ ); >+ >+ # Add CashupReconciliationNoteAuthorisedValue preference >+ $dbh->do( >+ q{ >+ INSERT IGNORE INTO systempreferences (variable, value, options, explanation, type) >+ VALUES ( >+ 'CashupReconciliationNoteAuthorisedValue', >+ '', >+ '', >+ 'Authorized value category to use for cashup reconciliation notes (leave empty for free text)', >+ 'Free' >+ ) >+ } >+ ); >+ >+ say_success( $out, "Added CashupReconciliationNoteAuthorisedValue system preference" ); >+ say_info( >+ $out, >+ "CashupReconciliationNoteAuthorisedValue: Optionally restrict reconciliation notes to authorized values" >+ ); > }, > }; >diff --git a/installer/data/mysql/mandatory/sysprefs.sql b/installer/data/mysql/mandatory/sysprefs.sql >index 585d7a5d8d8..40fd0cddcf5 100644 >--- a/installer/data/mysql/mandatory/sysprefs.sql >+++ b/installer/data/mysql/mandatory/sysprefs.sql >@@ -149,6 +149,8 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` > ('CardnumberLength', '', NULL, 'Set a length for card numbers with a maximum of 32 characters.', 'Free'), > ('CardnumberLog','1',NULL,'If ON, log edit actions on patron cardnumbers','YesNo'), > ('casAuthentication','0',NULL,'Enable or disable CAS authentication','YesNo'), >+('CashupReconciliationNoteAuthorisedValue', '', NULL, 'Authorized value category to use for cashup reconciliation notes (leave empty for free text)', 'Free'), >+('CashupReconciliationNoteRequired', '0', NULL, 'Require a reconciliation note when completing cashup with discrepancies between expected and actual amounts', 'YesNo'), > ('casLogout','0',NULL,'Does a logout from Koha should also log the user out of CAS?','YesNo'), > ('casServerUrl','https://localhost:8443/cas',NULL,'URL of the cas server','Free'), > ('casServerVersion','2', '2|3','Version of the CAS server Koha will connect to.','Choice'), >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/accounting.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/accounting.pref >index 55bcd590cfb..627ca5a800f 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/accounting.pref >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/accounting.pref >@@ -57,3 +57,13 @@ Accounting: > branchyyyymmincr: 'Automatically generate credit numbers in the form <branchcode>yyyymm0001' > incremental: 'Automatically generate credit numbers in the form 1, 2, 3' > - Automatic generation also has to be enabled for each credit type (<a href="/cgi-bin/koha/admin/credit_types.pl">Configure credit types</a>). >+ - >+ - pref: CashupReconciliationNoteRequired >+ choices: >+ 1: "Require" >+ 0: "Don't require" >+ - a reconciliation note when completing cashup with discrepancies between expected and actual amounts. >+ - >+ - "Use authorized value category " >+ - pref: CashupReconciliationNoteAuthorisedValue >+ - " for reconciliation notes during cashup. Leave empty to allow free text entry." >diff --git a/koha-tmpl/intranet-tmpl/prog/js/cashup_modal.js b/koha-tmpl/intranet-tmpl/prog/js/cashup_modal.js >index 306b82cb106..ba236ee67c3 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/cashup_modal.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/cashup_modal.js >@@ -3,7 +3,20 @@ $(document).ready(function () { > var button = $(e.relatedTarget); > var cashup = button.data("cashup"); > var description = button.data("register"); >+ var inProgress = button.data("in-progress") || false; > var summary_modal = $(this); >+ >+ // Update title based on whether this is a preview >+ if (inProgress) { >+ summary_modal >+ .find("#cashupSummaryLabel") >+ .text(__("Cashup summary preview")); >+ } else { >+ summary_modal >+ .find("#cashupSummaryLabel") >+ .text(__("Cashup summary")); >+ } >+ > summary_modal.find("#register_description").text(description); > $.ajax({ > url: "/api/v1/cashups/" + cashup, >@@ -17,6 +30,28 @@ $(document).ready(function () { > let to_date = $datetime(data.summary.to_date); > summary_modal.find("#to_date").text(to_date); > >+ // Add preview notice if this is an in-progress cashup >+ if (inProgress) { >+ var previewNotice = summary_modal.find(".preview-notice"); >+ if (previewNotice.length === 0) { >+ summary_modal >+ .find(".modal-body > ul") >+ .before( >+ '<div class="alert alert-info preview-notice">' + >+ '<i class="fa-solid fa-info-circle"></i> ' + >+ "<strong>" + >+ __("Preview:") + >+ "</strong> " + >+ __( >+ "This summary shows the expected cashup amounts. A reconciliation record may be added when you complete the cashup." >+ ) + >+ "</div>" >+ ); >+ } >+ } else { >+ summary_modal.find(".preview-notice").remove(); >+ } >+ > // Check for reconciliation (surplus or deficit) from dedicated fields > var surplus = data.summary.surplus_total; > var deficit = data.summary.deficit_total; >@@ -69,9 +104,35 @@ $(document).ready(function () { > var tfoot = summary_modal.find("tfoot"); > tfoot.empty(); > >+ // Determine if this is a negative cashup (float deficit scenario) >+ var isNegativeCashup = data.summary.total < 0; >+ >+ // Add informational notice for negative cashups >+ if (isNegativeCashup) { >+ var noticeText = __( >+ "This cashup shows a negative amount because refunds exceeded collections during this session. " + >+ "The register float was topped up to restore the expected balance." >+ ); >+ tbody.prepend( >+ "<tr class='reconciliation-info'><td colspan='2'>" + >+ "<i class='fa-solid fa-info-circle'></i> " + >+ "<strong>" + >+ __("Float deficit:") + >+ "</strong> " + >+ noticeText + >+ "</td></tr>" >+ ); >+ } >+ > // 1. Total (sum of all transactions) >+ var totalLabel = isNegativeCashup >+ ? __("Total float deficit") >+ : __("Total"); >+ > tfoot.append( >- "<tr class='total-row'><td><strong>Total</strong></td><td><strong>" + >+ "<tr class='total-row'><td><strong>" + >+ totalLabel + >+ "</strong></td><td><strong>" + > data.summary.total.format_price() + > "</strong></td></tr>" > ); >@@ -93,8 +154,15 @@ $(document).ready(function () { > } > } > if (cashCollected !== null) { >+ var cashLabel = >+ cashCollected < 0 >+ ? __("Cash added to register") >+ : __("Cash collected"); >+ > tfoot.append( >- "<tr><td><strong>Cash collected</strong></td><td><strong>" + >+ "<tr><td><strong>" + >+ cashLabel + >+ "</strong></td><td><strong>" + > cashCollected.format_price() + > "</strong></td></tr>" > ); >@@ -107,10 +175,22 @@ $(document).ready(function () { > type.payment_type !== "Cash" && > type.payment_type !== "CASH" > ) { >+ var paymentTypeLabel = >+ type.total < 0 >+ ? __x("{payment_type} to add", { >+ payment_type: escape_str( >+ type.payment_type >+ ), >+ }) >+ : __x("{payment_type} collected", { >+ payment_type: escape_str( >+ type.payment_type >+ ), >+ }); >+ > tfoot.append( > "<tr><td><strong>" + >- escape_str(type.payment_type) + >- " collected" + >+ paymentTypeLabel + > "</strong></td><td><strong>" + > type.total.format_price() + > "</strong></td></tr>" >@@ -133,14 +213,14 @@ $(document).ready(function () { > if (surplus) { > reconciliationClass = > "reconciliation-result text-warning"; >- reconciliationLabel = "Cashup surplus"; >+ reconciliationLabel = __("Cashup surplus"); > reconciliationAmount = > "+" + Math.abs(surplus).format_price(); > reconciliationNote = data.summary.surplus_note; > } else if (deficit) { > reconciliationClass = > "reconciliation-result text-danger"; >- reconciliationLabel = "Cashup deficit"; >+ reconciliationLabel = __("Cashup deficit"); > reconciliationAmount = > "-" + Math.abs(deficit).format_price(); > reconciliationNote = data.summary.deficit_note; >@@ -158,13 +238,23 @@ $(document).ready(function () { > > // Add note if present > if (reconciliationNote) { >+ // Check if note is an authorized value code and use description if available >+ var noteDisplay = reconciliationNote; >+ if ( >+ typeof reconciliation_note_avs !== "undefined" && >+ reconciliation_note_avs[reconciliationNote] >+ ) { >+ noteDisplay = >+ reconciliation_note_avs[reconciliationNote]; >+ } >+ > tfoot.append( > "<tr class='" + > reconciliationClass + > "'><td colspan='2'><em>" + > __("Note:") + > " " + >- escape_str(reconciliationNote) + >+ escape_str(noteDisplay) + > "</em></td></tr>" > ); > } >-- >2.53.0 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 40445
:
185289
|
185290
|
185291
|
185292
|
185809
|
186636
|
186637
|
186638
|
186639
|
186640
|
186641
|
186642
|
186643
|
189333
|
189334
|
189335
|
189336
|
189337
|
189338
|
189339
|
189340
|
189341
|
189353
|
189354
|
189355
|
189356
|
189357
|
189358
|
189359
|
189360
|
189361
|
189362
|
189363
|
189364
|
189410
|
189411
|
189412
|
189413
|
189414
|
189415
|
189420
|
189421
|
189422
|
189423
|
189424
|
189425
|
189426
|
189427
|
189428
|
189429
|
189430
|
189476
|
189477
|
189478
|
189479
|
189480
|
189481
|
189482
|
190361
|
190362
|
190363
|
190364
|
190365
|
190366
|
190367
|
190368
|
190369
|
190370
|
190371
|
190372
|
190373
|
190374
|
190375
|
190376
|
190379
|
190380
|
190388
|
190389
|
190404
|
190405
|
190406
|
190407
|
190408
|
190409
|
190410
|
190411
|
190412
|
190413
|
190414
|
190415
|
191273
|
191274
|
191275
|
191276
|
191277
|
191278
|
191279
|
191280
|
191281
|
191282
|
191283
|
191284
|
191285
|
191286
|
191287
|
191288
|
193123
|
193124
|
193125
|
193126
|
193127
|
193128
|
193129
|
193130
|
193131
|
193132
|
193133
|
193134
|
193135
|
193136
|
193137
|
193138
|
193139
|
193140
|
193141
|
193180
|
193181
|
193182
| 193183