2 [% USE AdditionalContents %]
7 [% USE TablesSettings %]
9 [% PROCESS 'i18n.inc' %]
10 [% SET footerjs = 1 %]
11 [% INCLUDE 'doc-head-open.inc' %]
12 [% SET registers = Registers.all( filters => { current_branch => 1 } ) %]
13 <title>[% FILTER collapse %]
14 [% t("Point of sale") | html %] ›
15 [% t("Koha") | html %]
17 [% INCLUDE 'doc-head-close.inc' %]
20 <body id="payments" class="pos">
21 [% WRAPPER 'header.inc' %]
22 [% INCLUDE 'circ-search.inc' %]
25 [% WRAPPER 'sub-header.inc' %]
26 [% WRAPPER breadcrumbs %]
27 [% WRAPPER breadcrumb_item bc_active= 1 %]
28 <span>Point of sale</span>
30 [% END #/ WRAPPER breadcrumbs %]
31 [% END #/ WRAPPER sub-header.inc %]
33 <div class="main container-fluid">
35 <div class="col-md-10 col-md-push-2">
36 [% INCLUDE 'messages.inc' %]
38 <h1>Point of sale</h1>
40 [% IF ( registers.size == 0 ) %]
41 <div id="error_message" class="dialog message">
43 You must have at least one cash register associated with the library before you can record payments.
45 [% IF ( CAN_user_parameters_manage_cash_registers ) %]
46 <form action="/cgi-bin/koha/admin/cash_registers.pl" method="post">
47 [% INCLUDE 'csrf-token.inc' %]
48 <input type="hidden" name="op-cud" value="add_form" />
49 <button class="new" type="submit"><i class="fa fa-plus"></i> Create a new cash register</button>
55 [% IF payment_id && !Koha.Preference('FinePaymentAutoPopup') %]
56 <div class="dialog message audio-alert-action">
57 <p>Payment received</p>
59 <a target="_blank" href="/cgi-bin/koha/pos/printreceipt.pl?action=print&accountlines_id=[% payment_id | uri %]&collected=[% collected | uri %]&change=[% change | uri %]" class="btn btn-default"><i class="fa fa-print"></i> Print receipt</a>
60 <a href="#" data-toggle="modal" data-target="#emailReceiptModal" class="btn btn-default"><i class="fa-solid fa-envelope"></i> Email receipt</a>
66 <form name="payForm" id="payForm" method="post" action="/cgi-bin/koha/pos/pay.pl">
67 [% INCLUDE 'csrf-token.inc' %]
70 <div class="col-md-6">
71 <fieldset class="rows">
72 <legend>Items for purchase</legend>
73 Please select items from below to add to this transaction:
74 [% IF invoice_types %]
80 <th class="NoSort">Cost</th>
81 <th class="NoSort">Action</th>
85 [% FOREACH invoice IN invoice_types %]
87 <td>[% invoice.code | html %]</td>
88 <td>[% invoice.description | html %]</td>
89 <td>[% invoice.default_amount | $Price %]</td>
91 <button type="button" class="btn btn-default btn-xs add_button" data-invoice-code="[% invoice.code | html %]" data-invoice-title="[% invoice.description | html %]" data-invoice-price="[% invoice.default_amount | html %]"><i class="fa fa-plus"></i> Add</button>
97 You have no manual invoice types defined
102 <div class="col-md-6">
104 <fieldset class="rows">
105 <legend>This sale</legend>
106 <p>Click to edit item cost or quantities</p>
107 <table id="sale" class="table_sale">
122 <td colspan="3">Total payable:</td>
131 <fieldset class="rows">
132 <legend>Collect payment</legend>
135 <label for="paid">Amount being paid: </label>
136 <input type="text" inputmode="none" pattern="[0-9]*" name="paid" id="paid" value="" readonly/>
139 <label for="collected" class="required">Amount tendered: </label>
140 <input type="text" inputmode="numeric" pattern="[0-9]*" name="collected" id="collected" value="" class="required" required="required" />
141 <span class="required">Required</span>
144 <label>Change to give: </label>
145 <span id="change">[% 0 | $Price %]</span>
146 <input type="hidden" name="change" value="[% 0 | $Price %]"/>
149 [% INCLUDE 'transaction_types.inc' type="payment" %]
152 <label for="registerid" class="required">Cash register: </label>
153 <select name="registerid" id="registerid" class="required" required="required">
154 <option id="noregister" disabled="disabled" value="">-- Select an option--</option>
155 [% PROCESS options_for_registers %]
157 <span class="required">Required</span>
163 <fieldset class="action">
164 <input type="submit" id="submitbutton" name="submitbutton" class="btn btn-primary" value="Confirm" />
165 <a class="cancel" href="/cgi-bin/koha/pos/pay.pl">Cancel</a>
172 [%- SET StaffPOSHome = AdditionalContents.get( location => "StaffPOSHome", lang => lang, library => logged_in_user.branchcode ) -%]
173 [%- FOREACH block IN StaffPOSHome.content -%]
174 <div class="page-section">
175 [%- block.content | $raw -%]
181 <div class="col-md-2 col-md-pull-10">
183 [% INCLUDE 'pos-menu.inc' %]
186 </div> <!-- /.row -->
188 <!-- Email receipt modal -->
189 <div class="modal" id="emailReceiptModal" tabindex="-1" role="dialog" aria-labelledby="emailReceiptLabel">
190 <form id="email_form" action="/cgi-bin/koha/pos/pay.pl" method="get" enctype="multipart/form-data" class="validated">
191 <input type="hidden" name="payment_id" value="[% payment_id | uri %]">
192 <input type="hidden" name="collected" value="[% collected | uri %]">
193 <input type="hidden" name="change" value="[% change | uri %]">"
194 <div class="modal-dialog" role="document">
195 <div class="modal-content">
196 <div class="modal-header">
197 <button type="button" class="closebtn" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
198 <h4 class="modal-title" id="emailReceiptLabel">Email receipt</h4>
200 <div class="modal-body">
201 <fieldset class="rows">
204 <label class="required" for="toaddr">Email address: </label>
205 <input type="email" id="toaddr" name="toaddr" required="required">
206 <span class="required">Required</span>
209 </fieldset> <!-- /.rows -->
210 </div> <!-- /.modal-body -->
211 <div class="modal-footer">
212 <input type="hidden" name="action" value="send">
213 <button type="submit" class="btn btn-default">Confirm</button>
214 <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
215 </div> <!-- /.modal-footer -->
216 </div> <!-- /.modal-content -->
217 </div> <!-- /.modal-dialog -->
218 </form> <!-- /#email_form -->
219 </div> <!-- /#emailReceiptModal -->
221 <!-- Change modal -->
222 <div id="confirm_change_form" class="modal" tabindex="-1" role="dialog" aria-hidden="true">
223 <div class="modal-dialog">
224 <div class="modal-content">
225 <div class="modal-header">
226 <h3>The amount collected is more than the outstanding charge</h3>
228 <div class="modal-body">
229 <p>The amount collected from the patron is higher than the amount to be paid.</p>
230 <p>The change to give is <strong><span id="modal_change">[% 0 | $Price %]</span></strong>.</p>
231 <p>Confirm this payment?</p>
233 <div class="modal-footer">
234 <button class="btn btn-default approve" id="modal_submit" type="button"><i class="fa fa-check"></i> Yes</button>
235 <button class="btn btn-default deny cancel" data-dismiss="modal" aria-hidden="true" type="button"><i class="fa fa-times"></i> No</button>
241 [% IF payment_id && Koha.Preference('FinePaymentAutoPopup') %]
242 <!-- Automatic Print Receipt -->
243 <a id="printReceipt" style="display: none" href="#"></a>
246 [% MACRO jsinclude BLOCK %]
247 [% INCLUDE 'format_price.inc' %]
248 [% INCLUDE 'datatables.inc' %]
249 [% INCLUDE 'columns_settings.inc' %]
250 [% Asset.js("lib/jquery/plugins/jquery.jeditable.mini.js") | $raw %]
252 function moneyFormat(textObj) {
253 var newValue = textObj.value;
259 for(var i = newValue.length; 0 < i; i--) {
260 aChar = newValue.substring(i-1, i);
261 if ("0" <= aChar && aChar <= "9") {
263 dolAmount = "" + aChar + dolAmount;
266 decAmount = "" + aChar + decAmount;
269 if (aChar == "." || aChar == ",") {
275 dolAmount = decAmount;
279 if (dolAmount == "") {
283 if (dolAmount.length > 1) {
284 while(dolAmount.length > 1 && dolAmount.substring(0,1) == "0") {
285 dolAmount = dolAmount.substring(1,dolAmount.length);
288 if (decAmount.length > 2) {
289 decAmount = decAmount.substring(0,2);
292 if (decAmount.length == 1) {
293 decAmount = decAmount + "0";
295 if (decAmount.length == 0) {
296 decAmount = decAmount + "00";
299 textObj.value = dolAmount + "." + decAmount;
302 function fnClickAddRow( table, invoiceCode, invoiceTitle, invoicePrice ) {
303 var defaultPrice = { value: invoicePrice };
304 moneyFormat(defaultPrice);
310 '<button class="btn btn-default btn-xs drop" type="button"><i class="fa fa-trash-can"></i> ' + _("Remove") + '</button>',
316 function updateChangeValues() {
317 var change = $('#change')[0];
318 var zero_formatted = "[% 0 | $Price %]";
319 change.innerHTML = Math.round(($('#collected')[0].value - $('#paid')[0].value) * 100) / 100;
320 if (change.innerHTML <= 0) {
321 var paid = $('#paid')[0];
323 $('#collected').rules( "add", { min: Number(paid.value) });
324 change.innerHTML = zero_formatted;
325 $(':input[name="change"]').val(zero_formatted);
327 change.value = change.innerHTML;
329 change.innerHTML = change.value;
330 $(':input[name="change"]').val(change.value);
333 $('#modal_change').html(change.innerHTML);
336 $(document).ready(function() {
337 var sale_table = $("#sale").dataTable($.extend(true, {}, dataTablesDefaults, {
347 "render": function ( data, type, full ) {
348 var price = Number.parseFloat(data);
349 return price.format_price();
353 "className": "editable",
356 "className": "editable_int",
363 "drawCallback": function (oSettings) {
365 local.$('.editable').editable( function(value, settings) {
366 var aPos = local.fnGetPosition( this );
367 local.fnUpdate( value, aPos[0], aPos[1], true, false );
371 pattern : "^\\d+(\.\\d{2})?$",
374 tooltip : _("Click to edit")
376 local.$('.editable_int').editable( function(value, settings) {
377 var aPos = local.fnGetPosition( this );
378 local.fnUpdate( value, aPos[0], aPos[1], true, false );
385 tooltip : _("Click to edit")
388 "rowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
389 var iTotal = aData[1] * aData[2];
390 this.fnUpdate( iTotal, nRow, 3, false, false );
392 "footerCallback": function(nFoot, aData, iStart, iEnd, aiDisplay) {
394 for ( var i=0 ; i<aData.length ; i++ )
396 iTotalPrice += aData[i][3]*1;
398 iTotalPrice = iTotalPrice.format_price();
399 nFoot.getElementsByTagName('td')[1].innerHTML = iTotalPrice;
400 $('#paid').val(iTotalPrice);
401 $('#paid').trigger('change');
406 $("#sale").on("click", "button.drop", function(){
407 sale_table.DataTable().row($(this).parents('tr')).remove().draw(false);
410 var items_table_settings = [% TablesSettings.GetTableSettings('pos', 'pay', 'invoices', 'json') | $raw %];
411 var items_table = KohaTable("invoices", {
412 "pagingType": "full",
413 "order": [[ 0, "asc" ]],
415 }, items_table_settings, false);
417 $("#invoices").on("click", ".add_button", function(e) {
419 fnClickAddRow(sale_table, $( this ).data('invoiceCode'), $( this ).data('invoiceTitle'), $( this ).data('invoicePrice') );
420 if($('#invoices_filter').find('input[type=search]').val() !== ''){
421 items_table.fnFilter( '' );
425 // Change calculation and modal
426 var change = $('#change')[0];
427 $("#paid, #collected").on("change",function() {
429 if (change != undefined) {
430 updateChangeValues();
435 $('#modal_submit').click(function() {
437 $('#payForm').submit();
440 $('#payForm').validate({
457 $('#payForm').submit(function(e){
458 // first, clear stale sales 'rows' from the payForm
459 if($('input[name="sales"]').length > 0) {
460 $('input[name="sales"]').each(function() {
465 // now, process the current & fresh contents of the sale_table
466 if (change != undefined && change.innerHTML > 0.00 && !checked) {
468 $("#confirm_change_form").modal("show");
470 var rows = sale_table.fnGetData();
471 rows.forEach(function (row, index) {
480 value: JSON.stringify(sale)
481 }).appendTo('#payForm');
487 [% IF payment_id && Koha.Preference('FinePaymentAutoPopup') %]
488 $("#printReceipt").click(function() {
489 var win = window.open('/cgi-bin/koha/pos/printreceipt.pl?action=print&accountlines_id=[% payment_id | uri %]&collected=[% collected | uri %]&change=[% change | uri %]', '_blank');
492 $("#printReceipt").click();
497 [% INCLUDE 'intranet-bottom.inc' %]