Bug 30003: Prevent double up of point-of-sale items
[koha.git] / koha-tmpl / intranet-tmpl / prog / en / modules / pos / pay.tt
1 [% USE raw %]
2 [% USE Asset %]
3 [% USE Branches %]
4 [% USE Koha %]
5 [% USE Price %]
6 [% USE TablesSettings %]
7 [% USE Registers %]
8 [% SET footerjs = 1 %]
9 [% INCLUDE 'doc-head-open.inc' %]
10 [% SET registers = Registers.all( filters => { current_branch => 1 } ) %]
11 <title>Payments &rsaquo; Koha</title>
12 [% INCLUDE 'doc-head-close.inc' %]
13 </head>
14
15 <body id="payments" class="pos">
16 [% INCLUDE 'header.inc' %]
17 [% INCLUDE 'circ-search.inc' %]
18
19 <nav id="breadcrumbs" aria-label="Breadcrumb" class="breadcrumb">
20     <ol>
21         <li>
22             <a href="/cgi-bin/koha/mainpage.pl">Home</a>
23         </li>
24         <li>
25             <a href="#" aria-current="page">
26                 Point of sale
27             </a>
28         </li>
29     </ol>
30 </nav>
31
32 <div class="main container-fluid">
33     <div class="row">
34         <div class="col-md-10 col-md-push-2">
35
36         [% IF ( registers.size == 0 ) %]
37             <div id="error_message" class="dialog message">
38                 <p>
39                     You must have at least one cash register associated with the library before you can record payments.
40                 </p>
41                 [% IF ( CAN_user_parameters_manage_cash_registers ) %]
42                     <form action="/cgi-bin/koha/admin/cash_registers.pl" method="get">
43                         <input type="hidden" name="op" value="add_form" />
44                         <button class="new" type="submit"><i class="fa fa-plus"></i> Create a new cash register</button>
45                     </form>
46                 [% END %]
47             </div>
48         [% ELSE %]
49
50         [% IF payment_id && !Koha.Preference('FinePaymentAutoPopup') %]
51         <div class="dialog alert audio-alert-action">
52             Payment received: <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 btn-xs"><i class="fa fa-print"></i> Print receipt</a>
53         </div>
54         [% END %]
55
56         <form name="payForm" id="payForm" method="post" action="/cgi-bin/koha/pos/pay.pl">
57             <div class="row">
58
59                 <div class="col-md-6">
60                     <fieldset class="rows">
61                         <legend>Items for purchase</legend>
62                             Please select items from below to add to this transaction:
63                             [% IF invoice_types %]
64                             <table id="invoices">
65                             <thead>
66                                 <tr>
67                                     <th>Code</th>
68                                     <th>Description</th>
69                                     <th class="NoSort">Cost</th>
70                                     <th class="NoSort">Action</th>
71                                 </tr>
72                             </thead>
73                             <tbody>
74                             [% FOREACH invoice IN invoice_types %]
75                                 <tr>
76                                     <td>[% invoice.code | html %]</td>
77                                     <td>[% invoice.description | html %]</td>
78                                     <td>[% invoice.default_amount | $Price %]</td>
79                                     <td>
80                                         <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>
81                                     </td>
82                                 </tr>
83                             [% END %]
84                             </table>
85                             [% ELSE %]
86                             You have no manual invoice types defined
87                             [% END %]
88                     </fieldset>
89                 </div>
90
91                 <div class="col-md-6">
92
93                     <fieldset class="rows">
94                         <legend>This sale</legend>
95                         <p>Click to edit item cost or quantities</p>
96                         <table id="sale" class="table_sale">
97                             <thead>
98                                 <tr>
99                                     <th>Item</th>
100                                     <th>Cost</th>
101                                     <th>Quantity</th>
102                                     <th>Total</th>
103                                     <th>Action</th>
104                                     <th>CODE</th>
105                                 </tr>
106                             </thead>
107                             <tbody>
108                             </tbody>
109                             <tfoot>
110                                 <tr>
111                                     <td colspan="3">Total payable:</td>
112                                     <td></td>
113                                     <td></td>
114                                     <td></td>
115                                 </tr>
116                             </tfoot>
117                         </table>
118                     </fieldset>
119
120                     <fieldset class="rows">
121                         <legend>Collect payment</legend>
122                         <ol>
123                             <li>
124                                 <label for="paid">Amount being paid: </label>
125                                 <input type="text" inputmode="none" pattern="[0-9]*" name="paid" id="paid" value="" readonly/>
126                             </li>
127                             <li>
128                                 <label for="collected" class="required">Amount tendered: </label>
129                                 <input type="text" inputmode="numeric" pattern="[0-9]*" name="collected" id="collected" value="" class="required" required="required" />
130                                 <span class="required">Required</span>
131                             </li>
132                             <li>
133                                 <label>Change to give: </label>
134                                 <span id="change">[% 0 | $Price %]</span>
135                                 <input type="hidden" name="change" value="[% 0 | $Price %]"/>
136                             </li>
137
138                             [% INCLUDE 'transaction_types.inc' type="payment" %]
139
140                             <li>
141                                 <label for="registerid" class="required">Cash register: </label>
142                                 <select name="registerid" id="registerid" class="required" required="required">
143                                     <option id="noregister" disabled selected="selected" value="">-- Select an option--</option>
144                                     [% PROCESS options_for_registers %]
145                                 </select>
146                                 <span class="required">Required</span>
147                             </li>
148                         </ol>
149
150                     </fieldset>
151
152                     <div class="action">
153                         <input type="submit" id="submitbutton" name="submitbutton" value="Confirm" />
154                         <a class="cancel" href="/cgi-bin/koha/pos/pay.pl">Cancel</a>
155                     </div>
156                 </div>
157             </div>
158         </form>
159         [% END %]
160     </div>
161
162     <div class="col-md-2 col-md-pull-10">
163         <aside>
164             [% INCLUDE 'pos-menu.inc' %]
165         </aside>
166     </div>
167 </div> <!-- /.row -->
168
169 <!-- Modal -->
170 <div id="confirm_change_form" class="modal" tabindex="-1" role="dialog" aria-hidden="true">
171     <div class="modal-dialog">
172         <div class="modal-content">
173             <div class="modal-header">
174                 <h3>The amount collected is more than the outstanding charge</h3>
175             </div>
176             <div class="modal-body">
177                 <p>The amount collected from the patron is higher than the amount to be paid.</p>
178                 <p>The change to give is <strong><span id="modal_change">[% 0 | $Price %]</span></strong>.</p>
179                 <p>Confirm this payment?</p>
180             </div>
181             <div class="modal-footer">
182                 <button class="btn btn-default approve" id="modal_submit" type="button"><i class="fa fa-check"></i> Yes</button>
183                 <button class="btn btn-default deny cancel" href="#" data-dismiss="modal" aria-hidden="true" type="button"><i class="fa fa-times"></i> No</button>
184             </div>
185         </div>
186     </div>
187 </div>
188
189 [% IF payment_id && Koha.Preference('FinePaymentAutoPopup') %]
190 <!-- Automatic Print Receipt -->
191       <a id="printReceipt" style="display: none" href="#"></a>
192 [% END %]
193
194 [% MACRO jsinclude BLOCK %]
195     [% INCLUDE 'format_price.inc' %]
196     [% INCLUDE 'datatables.inc' %]
197     [% INCLUDE 'columns_settings.inc' %]
198     [% Asset.js("lib/jquery/plugins/jquery.jeditable.mini.js") | $raw %]
199     <script>
200     function moneyFormat(textObj) {
201         var newValue = textObj.value;
202         var decAmount = "";
203         var dolAmount = "";
204         var decFlag   = false;
205         var aChar     = "";
206
207         for(var i=0; i < newValue.length; i++) {
208             aChar = newValue.substring(i, i+1);
209             if (aChar >= "0" && aChar <= "9") {
210                 if(decFlag) {
211                     decAmount = "" + decAmount + aChar;
212                 }
213                 else {
214                     dolAmount = "" + dolAmount + aChar;
215                 }
216             }
217             if (aChar == ".") {
218                 if (decFlag) {
219                     dolAmount = "";
220                     break;
221                 }
222                 decFlag = true;
223             }
224         }
225
226         if (dolAmount == "") {
227             dolAmount = "0";
228         }
229     // Strip leading 0s
230         if (dolAmount.length > 1) {
231             while(dolAmount.length > 1 && dolAmount.substring(0,1) == "0") {
232                 dolAmount = dolAmount.substring(1,dolAmount.length);
233             }
234         }
235         if (decAmount.length > 2) {
236             decAmount = decAmount.substring(0,2);
237         }
238     // Pad right side
239         if (decAmount.length == 1) {
240            decAmount = decAmount + "0";
241         }
242         if (decAmount.length == 0) {
243            decAmount = decAmount + "00";
244         }
245
246         textObj.value = dolAmount + "." + decAmount;
247     }
248
249     function fnClickAddRow( table, invoiceCode, invoiceTitle, invoicePrice ) {
250       var defaultPrice = { value: invoicePrice };
251       moneyFormat(defaultPrice);
252       table.fnAddData( [
253         invoiceTitle,
254         defaultPrice.value,
255         1,
256         null,
257         '<button class="btn btn-default btn-xs drop" type="button"><i class="fa fa-trash"></i> ' + _("Remove") + '</button>',
258         invoiceCode
259         ]
260       );
261     }
262
263     function updateChangeValues() {
264         var change = $('#change')[0];
265         var zero_formatted = "[% 0 | $Price %]";
266         change.innerHTML = Math.round(($('#collected')[0].value - $('#paid')[0].value) * 100) / 100;
267         if (change.innerHTML <= 0) {
268             var paid = $('#paid')[0];
269             moneyFormat(paid);
270             $('#collected').rules( "add", { min: Number(paid.value) });
271             change.innerHTML = zero_formatted;
272             $(':input[name="change"]').val(zero_formatted);
273         } else {
274             change.value = change.innerHTML;
275             moneyFormat(change);
276             change.innerHTML = change.value;
277             $(':input[name="change"]').val(change.value);
278         }
279
280         $('#modal_change').html(change.innerHTML);
281     }
282
283     $(document).ready(function() {
284         var sale_table = $("#sale").dataTable($.extend(true, {}, dataTablesDefaults, {
285             "bPaginate": false,
286             "bFilter": false,
287             "bInfo": false,
288             "aoColumnDefs": [{
289                 "aTargets": [-2],
290                 "bSortable": false,
291                 "bSearchable": false,
292             }, {
293                 "aTargets": [-3],
294                 "mRender": function ( data, type, full ) {
295                     var price = Number.parseFloat(data);
296                     return price.format_price();
297                 }
298             }, {
299                 "aTargets": [-5],
300                 "sClass" : "editable",
301             }, {
302                 "aTargets": [-4],
303                 "sClass" : "editable_int",
304             }, {
305                 "targets": [-1],
306                 "visible": false,
307                 "searchable": false
308             }],
309             "aaSorting": [],
310             "fnDrawCallback": function (oSettings) {
311                 var local = this;
312                 local.$('.editable').editable( function(value, settings) {
313                     var aPos = local.fnGetPosition( this );
314                     local.fnUpdate( value, aPos[0], aPos[1], true, false );
315                     return value;
316                 },{
317                     type    : 'text',
318                     pattern : "^\\d+(\.\\d{2})?$",
319                     onblur  : 'submit',
320                     width   : "8em",
321                     tooltip : _("Click to edit")
322                 });
323                 local.$('.editable_int').editable( function(value, settings) {
324                     var aPos = local.fnGetPosition( this );
325                     local.fnUpdate( value, aPos[0], aPos[1], true, false );
326                     return value;
327                 },{
328                     type    : 'text',
329                     pattern : "[0-9]*",
330                     onblur  : 'submit',
331                     width   : "4em",
332                     tooltip : _("Click to edit")
333                 });
334             },
335             "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
336                 var iTotal = aData[1] * aData[2];
337                 this.fnUpdate( iTotal, nRow, 3, false, false );
338             },
339             "fnFooterCallback": function(nFoot, aData, iStart, iEnd, aiDisplay) {
340                 var iTotalPrice = 0;
341                 for ( var i=0 ; i<aData.length ; i++ )
342                 {
343                     iTotalPrice += aData[i][3]*1;
344                 }
345                 iTotalPrice = iTotalPrice.format_price();
346                 nFoot.getElementsByTagName('td')[1].innerHTML = iTotalPrice;
347                 $('#paid').val(iTotalPrice);
348                 $('#paid').trigger('change');
349             },
350             "autoWidth": false
351         }));
352
353         $("#sale").on("click", "button.drop", function(){
354                 sale_table.DataTable().row($(this).parents('tr')).remove().draw(false);
355         });
356
357         var items_columns_settings = [% TablesSettings.GetColumns('pos', 'pay', 'invoices', 'json') | $raw %];
358         var items_table = KohaTable("invoices", {
359                "sPaginationType": "full",
360                "aaSorting": [[ 0, "asc" ]],
361                "autoWidth": false
362         }, items_columns_settings, false);
363
364         $("#invoices").on("click", ".add_button", function(e) {
365             e.preventDefault();
366             fnClickAddRow(sale_table, $( this ).data('invoiceCode'), $( this ).data('invoiceTitle'), $( this ).data('invoicePrice') );
367             if($('#invoices_filter').find('input[type=search]').val() !== ''){
368                 items_table.fnFilter( '' );
369             }
370         });
371
372         // Change calculation and modal
373         var change = $('#change')[0];
374         $("#paid, #collected").on("change",function() {
375             moneyFormat( this );
376             if (change != undefined) {
377                 updateChangeValues();
378             }
379         });
380
381         var checked = false;
382         $('#modal_submit').click(function() {
383             checked = true;
384             $('#payForm').submit();
385         });
386
387         $('#payForm').validate({
388             rules: {
389                 paid: {
390                     required: true
391                 },
392                 collected: {
393                     required: true
394                 },
395                 payment_type: {
396                     required: true
397                 },
398                 registerid: {
399                     required: true
400                 }
401             }
402         });
403
404         $('#payForm').submit(function(e){
405             // first, clear stale sales 'rows' from the payForm
406             if($('input[name="sales"]').length > 0) {
407                 $('input[name="sales"]').each(function() {
408                     $(this).remove();
409                 });
410             }
411
412             // now, process the current & fresh contents of the sale_table
413             if (change != undefined && change.innerHTML > 0.00 && !checked) {
414                 e.preventDefault();
415                 $("#confirm_change_form").modal("show");
416             } else {
417                 var rows = sale_table.fnGetData();
418                 rows.forEach(function (row, index) {
419                     var sale = {
420                         code: row[5],
421                         price: row[1],
422                         quantity: row[2]
423                     };
424                     $('<input>').attr({
425                         type: 'hidden',
426                         name: 'sales',
427                         value: JSON.stringify(sale)
428                     }).appendTo('#payForm');
429                 });
430                 return true;
431             }
432         });
433
434         [% IF payment_id && Koha.Preference('FinePaymentAutoPopup') %]
435             $("#printReceipt").click(function() {
436                 var win = window.open('/cgi-bin/koha/pos/printreceipt.pl?action=print&accountlines_id=[% payment_id | uri %]&collected=[% collected | uri %]&change=[% change | uri %]', '_blank');
437                 win.focus();
438             });
439             $("#printReceipt").click();
440         [% END %]
441     });
442     </script>
443 [% END %]
444
445 [% INCLUDE 'intranet-bottom.inc' %]