From 35d5fed0fdb2fa05caa7230d2ae1ec4787062e23 Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Fri, 7 Nov 2025 16:48:08 +0000 Subject: [PATCH] Bug 40445: Add cashup summary preview for in-progress cashups In two-phase workflow, staff start cashup then count cash while continuing transactions. This adds preview capability to see what will be included before completion. Features: - "Preview cashup summary" link in cashup progress alert - Modal shows expected amounts with "(preview)" indicator - Alert explains this is preview and reconciliation may be added - API endpoint supports preview by accepting CASHUP_START action IDs - All strings properly wrapped for translation Test plan: 1. Start two-phase cashup on register 2. Verify "Cashup in progress" alert appears 3. Click "Preview cashup summary" link 4. Verify modal shows: - Title: "Cashup summary preview" - Info alert explaining preview status - Correct period dates - Current transaction totals 5. Add new cash transaction 6. Re-open preview - verify totals updated 7. Complete cashup normally 8. View completed cashup summary 9. Verify no preview notice, normal title shown 10. Check translations: Verify all strings wrapped with __() or t()/tx() --- Koha/REST/V1/CashRegisters/Cashups.pm | 16 ++++++ .../prog/en/modules/pos/register.tt | 10 +++- .../intranet-tmpl/prog/js/cashup_modal.js | 52 ++++++++++++++++--- 3 files changed, 71 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/koha-tmpl/intranet-tmpl/prog/en/modules/pos/register.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/pos/register.tt index a23383c01e0..72181d4b931 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/pos/register.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/pos/register.tt @@ -96,7 +96,15 @@ [% IF cashup_in_progress %]
- Cashup in progress - started [% cashup_in_progress.timestamp | $KohaDates with_hours => 1 %]. You can continue to make transactions while counting cash. + [% tx("Cashup in progress - started {timestamp}. You can continue to make transactions while counting cash.", { timestamp = cashup_in_progress.timestamp | $KohaDates(with_hours => 1) }) | html %] ([% t("Preview cashup summary") | html %])
[% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/js/cashup_modal.js b/koha-tmpl/intranet-tmpl/prog/js/cashup_modal.js index 667a8205890..dc743b47825 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( + '
' + + ' ' + + "" + + __("Preview:") + + " " + + __( + "This summary shows the expected cashup amounts. A reconciliation record may be added when you complete the cashup." + ) + + "
" + ); + } + } 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; @@ -71,7 +106,9 @@ $(document).ready(function () { // 1. Total (sum of all transactions) tfoot.append( - "Total" + + "" + + __("Total") + + "" + data.summary.total.format_price() + "" ); @@ -94,7 +131,9 @@ $(document).ready(function () { } if (cashCollected !== null) { tfoot.append( - "Cash collected" + + "" + + __("Cash collected") + + "" + cashCollected.format_price() + "" ); @@ -109,8 +148,9 @@ $(document).ready(function () { ) { tfoot.append( "" + - escape_str(type.payment_type) + - " collected" + + __x("{payment_type} collected", { + payment_type: escape_str(type.payment_type), + }) + "" + type.total.format_price() + "" @@ -132,13 +172,13 @@ $(document).ready(function () { if (surplus) { reconciliationClass = "reconciliation-result text-warning"; - reconciliationLabel = "Cashup surplus"; + reconciliationLabel = __("Cashup surplus"); reconciliationAmount = "+" + Math.abs(surplus).format_price(); } else if (deficit) { reconciliationClass = "reconciliation-result text-danger"; - reconciliationLabel = "Cashup deficit"; + reconciliationLabel = __("Cashup deficit"); reconciliationAmount = "-" + Math.abs(deficit).format_price(); } -- 2.51.1