Koha-clms/koha-tmpl/intranet-tmpl/prog/js/cashup_modal.js

266 lines
11 KiB
JavaScript

$(document).ready(function () {
$("#cashupSummaryModal").on("show.bs.modal", function (e) {
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,
headers: {
"x-koha-embed": "summary",
},
async: false,
success: function (data) {
let from_date = $datetime(data.summary.from_date);
summary_modal.find("#from_date").text(from_date);
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;
var expectedAmount = data.summary.total;
var actualAmount = data.amount;
var tbody = summary_modal.find("tbody");
tbody.empty();
for (out of data.summary.payout_grouped) {
if (out.credit_type_code == "REFUND") {
tbody.append(
"<tr><td>" +
__x(
"{credit_type_description} against {debit_type_description}",
{
credit_type_description: escape_str(
out.credit_type.description
),
debit_type_description: escape_str(
out.related_debit.debit_type
.description
),
}
) +
"</td><td>- " +
out.total.format_price() +
"</td></tr>"
);
} else {
tbody.append(
"<tr><td>" +
escape_str(out.credit_type.description) +
"</td><td>- " +
out.total.format_price() +
"</td></tr>"
);
}
}
for (income of data.summary.income_grouped) {
tbody.append(
"<tr><td>" +
escape_str(income.debit_type.description) +
"</td><td>" +
income.total.format_price() +
"</td></tr>"
);
}
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>" +
totalLabel +
"</strong></td><td><strong>" +
data.summary.total.format_price() +
"</strong></td></tr>"
);
// Add separator line
tfoot.append(
"<tr class='reconciliation-separator'><td colspan='2'><hr></td></tr>"
);
// 2. Cash removed from register (positive = collected and removed at cashup)
var cashCollected = null;
for (type of data.summary.total_grouped) {
if (
type.payment_type === "Cash" ||
type.payment_type === "CASH"
) {
cashCollected = type.total;
break;
}
}
if (cashCollected !== null) {
var cashLabel =
cashCollected >= 0
? __("Cash removed from register")
: __("Cash added to register");
tfoot.append(
"<tr><td><strong>" +
cashLabel +
"</strong></td><td><strong>" +
cashCollected.format_price() +
"</strong></td></tr>"
);
}
// 3. Other payment types collected (excluding CASH)
for (type of data.summary.total_grouped) {
if (
type.total !== 0 &&
type.payment_type !== "Cash" &&
type.payment_type !== "CASH"
) {
var paymentTypeLabel =
type.total >= 0
? __x("{payment_type} collected", {
payment_type: escape_str(
type.payment_type
),
})
: __x("{payment_type} to add", {
payment_type: escape_str(
type.payment_type
),
});
tfoot.append(
"<tr><td><strong>" +
paymentTypeLabel +
"</strong></td><td><strong>" +
type.total.format_price() +
"</strong></td></tr>"
);
}
}
// 4. Cashup surplus OR deficit (highlighted)
if (surplus || deficit) {
// Add separator before reconciliation
tfoot.append(
"<tr class='reconciliation-separator'><td colspan='2'><hr></td></tr>"
);
var reconciliationClass,
reconciliationLabel,
reconciliationAmount,
reconciliationNote;
if (surplus) {
reconciliationClass =
"reconciliation-result text-warning";
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");
reconciliationAmount =
"-" + Math.abs(deficit).format_price();
reconciliationNote = data.summary.deficit_note;
}
tfoot.append(
"<tr class='" +
reconciliationClass +
"'><td><strong>" +
reconciliationLabel +
"</strong></td><td><strong>" +
reconciliationAmount +
"</strong></td></tr>"
);
// 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(noteDisplay) +
"</em></td></tr>"
);
}
}
},
});
});
});