Main Koha release repository https://koha-community.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

411 lines
16 KiB

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