6.7.4. A Controller for Invoices

The invoice controller is more complex and includes an additional function to pay an invoice. Paid invoices are highlighted in a different color. While viewing an invoice, you can also see its items. While editing an invoice, you can edit its items as well. Here is the code for the controller with detailed comments.

  1. <?php
  2. /*
  3. * Invoice controller
  4. */
  5. namespace App\Http\Controllers;
  6. use App\Http\Controllers\Controller;
  7. use App\Invoice;
  8. use App\Customer;
  9. use App\Product;
  10. use App\InvoiceLine;
  11. class InvoiceController extends Controller {
  12. /**
  13. * Show invoice list
  14. *
  15. * @return Response
  16. */
  17. public function showInvoices() {
  18. // The invoice model will also select the related suppliers
  19. $invoices = Invoice::with('customer');
  20. // Add a widget for search.
  21. $filter = \DataFilter::source($invoices);
  22. // Let's filter by date range
  23. $filter->add('INVOICE_DATE', 'Date', 'daterange');
  24. // and filter by customer name
  25. $filter->add('customer.NAME', 'Customer', 'text');
  26. $filter->submit('Search');
  27. $filter->reset('Reset');
  28. // Create a grid to display the filtered data
  29. $grid = \DataGrid::source($filter);
  30. // output grid columns
  31. // Field, caption, sorted
  32. // For the date we set an additional function that converts
  33. // the date into a string
  34. $grid->add('INVOICE_DATE|strtotime|date[Y-m-d H:i:s]', 'Date', true);
  35. // for money we will set a format with two decimal places
  36. $grid->add('TOTAL_SALE|number_format[2,., ]', 'Amount');
  37. $grid->add('customer.NAME', 'Customer');
  38. // Boolean printed as Yes/No
  39. $grid->add('PAID', 'Paid')
  40. ->cell(function( $value, $row) {
  41. return $value ? 'Yes' : 'No';
  42. });
  43. // set the function of processing each row
  44. $grid->row(function($row) {
  45. // The monetary values are pressed to the right
  46. $row->cell('TOTAL_SALE')->style("text-align: right");
  47. // paint the paid waybills in a different color
  48. if ($row->cell('PAID')->value == 'Yes') {
  49. $row->style("background-color: #ddffee;");
  50. }
  51. });
  52. // Add buttons to view, edit and delete records
  53. $grid->edit('/invoice/edit', '??????????????', 'show|modify|delete');
  54. // Add the button for adding invoices
  55. $grid->link('/invoice/edit', "?????????? ?????", "TR");
  56. $grid->orderBy('INVOICE_DATE', 'desc');
  57. // set the number of records per page
  58. $grid->paginate(10);
  59. // display the customer template and pass the filter and grid to it
  60. return view('invoice', compact('filter', 'grid'));
  61. }
  62. /**
  63. * Add, edit and delete invoice
  64. *
  65. * @return Response
  66. */
  67. public function editInvoice() {
  68. // get the text of the saved error, if it was
  69. $error_msg = \Request::old('error_msg');
  70. // create an invoice invoice editor
  71. $edit = \DataEdit::source(new Invoice());
  72. // if the invoice is paid, then we generate an error when trying to edit it
  73. if (($edit->model->PAID) && ($edit->status === 'modify')) {
  74. $edit->status = 'show';
  75. $error_msg = 'Editing is not possible. The account has already been paid.';
  76. }
  77. // if the invoice is paid, then we generate an error when trying to delete it
  78. if (($edit->model->PAID) && ($edit->status === 'delete')) {
  79. $edit->status = 'show';
  80. $error_msg = 'Deleting is not possible. The account has already been paid.';
  81. }
  82. // Set the label of the dialog, depending on the type of operation
  83. switch ($edit->status) {
  84. case 'create':
  85. $edit->label('Add invoice');
  86. break;
  87. case 'modify':
  88. $edit->label('Edit invoice');
  89. break;
  90. case 'do_delete':
  91. $edit->label('Delete invoice');
  92. break;
  93. case 'show':
  94. $edit->label('Invoice');
  95. $edit->link('invoices', 'Back', 'TR');
  96. // If the invoice is not paid, we show the pay button
  97. if (!$edit->model->PAID)
  98. $edit->link('invoice/pay/' . $edit->model->INVOICE_ID,
  99. 'Pay', 'BL');
  100. break;
  101. }
  102. // set that after the operations of adding, editing and deleting,
  103. // we return to the list of invoices
  104. $edit->back('insert|update|do_delete', 'invoices');
  105. // set the "date" field, that it is mandatory
  106. // The default is the current date
  107. $edit->add('INVOICE_DATE', '????', 'datetime')
  108. ->rule('required')
  109. ->insertValue(date('Y-m-d H:i:s'));
  110. // add a field for entering the customer. When typing a customer name,
  111. // a list of prompts will be displayed
  112. $edit->add('customer.NAME', 'Customer', 'autocomplete')
  113. ->rule('required')
  114. ->options(Customer::lists('NAME', 'CUSTOMER_ID')
  115. ->all());
  116. // add a field that will display the invoice amount, read-only
  117. $edit->add('TOTAL_SALE', 'Amount', 'text')
  118. ->mode('readonly')
  119. ->insertValue('0.00');
  120. // add paid checkbox
  121. $paidCheckbox = $edit->add('PAID', 'Paid', 'checkbox')
  122. ->insertValue('0')
  123. ->mode('readonly');
  124. $paidCheckbox->checked_output = 'Yes';
  125. $paidCheckbox->unchecked_output = 'No';
  126. // create a grid to display the invoice line rows
  127. $grid = $this->getInvoiceLineGrid($edit->model, $edit->status);
  128. // we display the invoice_edit template and pass the editor and grid to
  129. // it to display the invoice invoice items
  130. return $edit->view('invoice_edit', compact('edit', 'grid', 'error_msg'));
  131. }
  132. /**
  133. * Payment of invoice
  134. *
  135. * @return Response
  136. */
  137. public function payInvoice($id) {
  138. try {
  139. // find the invoice by ID
  140. $invoice = Invoice::findOrFail($id);
  141. // call the payment procedure
  142. $invoice->pay();
  143. } catch (\Illuminate\Database\QueryException $e) {
  144. // if an error occurs, select the exclusion text
  145. $pos = strpos($e->getMessage(), 'E_INVOICE_ALREADY_PAYED');
  146. if ($pos !== false) {
  147. // redirect to the editor page and display the error there
  148. return redirect('invoice/edit?show=' . $id)
  149. ->withInput(['error_msg' => 'Invoice already paid']);
  150. } else
  151. throw $e;
  152. }
  153. // redirect to the editor page
  154. return redirect('invoice/edit?show=' . $id);
  155. }
  156. /**
  157. * Returns the grid for the invoice item
  158. * @param \App\Invoice $invoice
  159. * @param string $mode
  160. * @return \DataGrid
  161. */
  162. private function getInvoiceLineGrid(Invoice $invoice, $mode) {
  163. // Get invoice items
  164. // For each ivoice item, the associated product will be initialized
  165. $lines = InvoiceLine::with('product')
  166. ->where('INVOICE_ID', $invoice->INVOICE_ID);
  167. // Create a grid for displaying invoice items
  168. $grid = \DataGrid::source($lines);
  169. // output grid columns
  170. // Field, caption, sorted
  171. $grid->add('product.NAME', 'Name');
  172. $grid->add('QUANTITY', 'Quantity');
  173. $grid->add('SALE_PRICE|number_format[2,., ]', 'Price')
  174. ->style('min-width: 8em;');
  175. $grid->add('SUM_PRICE|number_format[2,., ]', 'Amount')
  176. ->style('min-width: 8em;');
  177. // set the function of processing each row
  178. $grid->row(function($row) {
  179. $row->cell('QUANTITY')->style("text-align: right");
  180. // The monetary values are pressed to the right
  181. $row->cell('SALE_PRICE')->style("text-align: right");
  182. $row->cell('SUM_PRICE')->style("text-align: right");
  183. });
  184. if ($mode == 'modify') {
  185. // Add buttons to view, edit and delete records
  186. $grid->edit('/invoice/editline', '??????????????', 'modify|delete');
  187. // Add a button to add an invoice item
  188. $grid->link('/invoice/editline?invoice_id=' . $invoice->INVOICE_ID,
  189. "Add item", "TR");
  190. }
  191. return $grid;
  192. }
  193. /**
  194. * Add, edit and delete invoice items
  195. *
  196. * @return Response
  197. */
  198. public function editInvoiceLine() {
  199. if (\Input::get('do_delete') == 1)
  200. return "not the first";
  201. $invoice_id = null;
  202. // create the editor of the invoice item
  203. $edit = \DataEdit::source(new InvoiceLine());
  204. // Set the label of the dialog, depending on the type of operation
  205. switch ($edit->status) {
  206. case 'create':
  207. $edit->label('Add invoice item');
  208. $invoice_id = \Input::get('invoice_id');
  209. break;
  210. case 'modify':
  211. $edit->label('Edit invoice item');
  212. $invoice_id = $edit->model->INVOICE_ID;
  213. break;
  214. case 'delete':
  215. $invoice_id = $edit->model->INVOICE_ID;
  216. break;
  217. case 'do_delete':
  218. $edit->label('Delete invoice item');
  219. $invoice_id = $edit->model->INVOICE_ID;
  220. break;
  221. }
  222. // make url to go back
  223. $base = str_replace(\Request::path(), '', strtok(\Request::fullUrl(), '?'));
  224. $back_url = $base . 'invoice/edit?modify=' . $invoice_id;
  225. // set the page to go back
  226. $edit->back('insert|update|do_delete', $back_url);
  227. $edit->back_url = $back_url;
  228. // add a hidden field with an invoice code
  229. $edit->add('INVOICE_ID', '', 'hidden')
  230. ->rule('required')
  231. ->insertValue($invoice_id)
  232. ->updateValue($invoice_id);
  233. // Add a field for entering the goods. When you type the product name,
  234. // a list of prompts is displayed.
  235. $edit->add('product.NAME', 'Name', 'autocomplete')
  236. ->rule('required')
  237. ->options(Product::lists('NAME', 'PRODUCT_ID')->all());
  238. // Field for input quantity
  239. $edit->add('QUANTITY', 'Quantity', 'text')
  240. ->rule('required');
  241. // display the template invoice_line_edit and pass it to the editor
  242. return $edit->view('invoice_line_edit', compact('edit'));
  243. }
  244. }

The Invoice Editor

The invoice editor has a view that is not standard for zofe/rapyd because we want to display a grid with invoice items. To do that, we change the invoice_edit template as follows:

  1. @extends('example')
  2. @section('title','Edit invoice')
  3. @section('body')
  4. <div class="container">
  5. {!! $edit->header !!}
  6. @if($error_msg)
  7. <div class="alert alert-danger">
  8. <strong>??????!</strong> {{ $error_msg }}
  9. </div>
  10. @endif
  11. {!! $edit->message !!}
  12. @if(!$edit->message)
  13. <div class="row">
  14. <div class="col-sm-4">
  15. {!! $edit->render('INVOICE_DATE') !!}
  16. {!! $edit->render('customer.NAME') !!}
  17. {!! $edit->render('TOTAL_SALE') !!}
  18. {!! $edit->render('PAID') !!}
  19. </div>
  20. </div>
  21. {!! $grid !!}
  22. @endif
  23. {!! $edit->footer !!}
  24. </div>
  25. @stop