Changing the Invoice date when creating recurrent invoices.
[fa-stable.git] / sales / customer_invoice.php
1 <?php
2 /**********************************************************************
3     Copyright (C) FrontAccounting, LLC.
4         Released under the terms of the GNU General Public License, GPL, 
5         as published by the Free Software Foundation, either version 3 
6         of the License, or (at your option) any later version.
7     This program is distributed in the hope that it will be useful,
8     but WITHOUT ANY WARRANTY; without even the implied warranty of
9     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
10     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
11 ***********************************************************************/
12 //---------------------------------------------------------------------------
13 //
14 //      Entry/Modify Sales Invoice against single delivery
15 //      Entry/Modify Batch Sales Invoice against batch of deliveries
16 //
17 $page_security = 'SA_SALESINVOICE';
18 $path_to_root = "..";
19 include_once($path_to_root . "/sales/includes/cart_class.inc");
20 include_once($path_to_root . "/includes/session.inc");
21 include_once($path_to_root . "/includes/data_checks.inc");
22 include_once($path_to_root . "/includes/manufacturing.inc");
23 include_once($path_to_root . "/sales/includes/sales_db.inc");
24 include_once($path_to_root . "/sales/includes/sales_ui.inc");
25 include_once($path_to_root . "/reporting/includes/reporting.inc");
26 include_once($path_to_root . "/taxes/tax_calc.inc");
27
28 $js = "";
29 if ($use_popup_windows) {
30         $js .= get_js_open_window(900, 500);
31 }
32 if ($use_date_picker) {
33         $js .= get_js_date_picker();
34 }
35
36 if (isset($_GET['ModifyInvoice'])) {
37         $_SESSION['page_title'] = sprintf(_("Modifying Sales Invoice # %d.") ,$_GET['ModifyInvoice']);
38         $help_context = "Modifying Sales Invoice";
39 } elseif (isset($_GET['DeliveryNumber'])) {
40         $_SESSION['page_title'] = _($help_context = "Issue an Invoice for Delivery Note");
41 } elseif (isset($_GET['BatchInvoice'])) {
42         $_SESSION['page_title'] = _($help_context = "Issue Batch Invoice for Delivery Notes");
43 }
44
45 page($_SESSION['page_title'], false, false, "", $js);
46
47 //-----------------------------------------------------------------------------
48 check_edit_conflicts();
49
50 if (isset($_GET['AddedID'])) {
51
52         $invoice_no = $_GET['AddedID'];
53         $trans_type = ST_SALESINVOICE;
54
55         display_notification(_("Selected deliveries has been processed"), true);
56
57         display_note(get_customer_trans_view_str($trans_type, $invoice_no, _("&View This Invoice")), 0, 1);
58
59         display_note(print_document_link($invoice_no."-".$trans_type, _("&Print This Invoice"), true, ST_SALESINVOICE));
60         display_note(print_document_link($invoice_no."-".$trans_type, _("&Email This Invoice"), true, ST_SALESINVOICE, false, "printlink", "", 1),1);
61
62         display_note(get_gl_view_str($trans_type, $invoice_no, _("View the GL &Journal Entries for this Invoice")),1);
63
64         hyperlink_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Another &Delivery For Invoicing"), "OutstandingOnly=1");
65
66         hyperlink_params("$path_to_root/admin/attachments.php", _("Add an Attachment"), "filterType=$trans_type&trans_no=$invoice_no");
67
68         display_footer_exit();
69
70 } elseif (isset($_GET['UpdatedID']))  {
71
72         $invoice_no = $_GET['UpdatedID'];
73         $trans_type = ST_SALESINVOICE;
74
75         display_notification_centered(sprintf(_('Sales Invoice # %d has been updated.'),$invoice_no));
76
77         display_note(get_trans_view_str(ST_SALESINVOICE, $invoice_no, _("&View This Invoice")));
78         echo '<br>';
79         display_note(print_document_link($invoice_no."-".$trans_type, _("&Print This Invoice"), true, ST_SALESINVOICE));
80         display_note(print_document_link($invoice_no."-".$trans_type, _("&Email This Invoice"), true, ST_SALESINVOICE, false, "printlink", "", 1),1);
81
82         hyperlink_no_params($path_to_root . "/sales/inquiry/customer_inquiry.php", _("Select Another &Invoice to Modify"));
83
84         display_footer_exit();
85
86 } elseif (isset($_GET['RemoveDN'])) {
87
88         for($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
89                 $line = &$_SESSION['Items']->line_items[$line_no];
90                 if ($line->src_no == $_GET['RemoveDN']) {
91                         $line->quantity = $line->qty_done;
92                         $line->qty_dispatched=0;
93                 }
94         }
95         unset($line);
96
97     // Remove also src_doc delivery note
98     $sources = &$_SESSION['Items']->src_docs;
99     unset($sources[$_GET['RemoveDN']]);
100 }
101
102 //-----------------------------------------------------------------------------
103
104 if ( (isset($_GET['DeliveryNumber']) && ($_GET['DeliveryNumber'] > 0) )
105 || isset($_GET['BatchInvoice'])) {
106
107         processing_start();
108
109         if (isset($_GET['BatchInvoice'])) {
110                 $src = $_SESSION['DeliveryBatch'];
111                 unset($_SESSION['DeliveryBatch']);
112         } else {
113                 $src = array($_GET['DeliveryNumber']);
114         }
115
116         /*read in all the selected deliveries into the Items cart  */
117         $dn = new Cart(ST_CUSTDELIVERY, $src, true);
118
119         if ($dn->count_items() == 0) {
120                 hyperlink_params($path_to_root . "/sales/inquiry/sales_deliveries_view.php",
121                         _("Select a different delivery to invoice"), "OutstandingOnly=1");
122                 die ("<br><b>" . _("There are no delivered items with a quantity left to invoice. There is nothing left to invoice.") . "</b>");
123         }
124
125         $_SESSION['Items'] = $dn;
126         copy_from_cart();
127
128 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
129
130         if ( get_sales_parent_numbers(ST_SALESINVOICE, $_GET['ModifyInvoice']) == 0) { // 1.xx compatibility hack
131                 echo"<center><br><b>" . _("There are no delivery notes for this invoice.<br>
132                 Most likely this invoice was created in Front Accounting version prior to 2.0
133                 and therefore can not be modified.") . "</b></center>";
134                 display_footer_exit();
135         }
136         processing_start();
137         $_SESSION['Items'] = new Cart(ST_SALESINVOICE, $_GET['ModifyInvoice']);
138
139         if ($_SESSION['Items']->count_items() == 0) {
140                 echo"<center><br><b>" . _("All quantities on this invoice has been credited. There is nothing to modify on this invoice") . "</b></center>";
141                 display_footer_exit();
142         }
143         copy_from_cart();
144 } elseif (!processing_active()) {
145         /* This page can only be called with a delivery for invoicing or invoice no for edit */
146         display_error(_("This page can only be opened after delivery selection. Please select delivery to invoicing first."));
147
148         hyperlink_no_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Delivery to Invoice"));
149
150         end_page();
151         exit;
152 } elseif (!isset($_POST['process_invoice']) && !check_quantities()) {
153         display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
154 }
155 if (isset($_POST['Update'])) {
156         $Ajax->activate('Items');
157 }
158 if (isset($_POST['_InvoiceDate_changed'])) {
159         $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_POST['InvoiceDate']);
160         $Ajax->activate('due_date');
161 }
162 if (list_updated('payment')) {
163         $_SESSION['Items']->payment = get_post('payment');
164         $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_POST['InvoiceDate']);
165         $Ajax->activate('due_date');
166 }
167
168 //-----------------------------------------------------------------------------
169 function check_quantities()
170 {
171         $ok =1;
172         foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
173                 if (isset($_POST['Line'.$line_no])) {
174                         if($_SESSION['Items']->trans_no) {
175                                 $min = $itm->qty_done;
176                                 $max = $itm->quantity;
177                         } else {
178                                 $min = 0;
179                                 $max = $itm->quantity - $itm->qty_done;
180                         }
181                         if (check_num('Line'.$line_no, $min, $max)) {
182                                 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
183                                     input_num('Line'.$line_no);
184                         }
185                         else {
186                                 $ok = 0;
187                         }
188                                 
189                 }
190
191                 if (isset($_POST['Line'.$line_no.'Desc'])) {
192                         $line_desc = $_POST['Line'.$line_no.'Desc'];
193                         if (strlen($line_desc) > 0) {
194                                 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
195                         }
196                 }
197         }
198  return $ok;
199 }
200
201 function set_delivery_shipping_sum($delivery_notes) 
202 {
203     
204     $shipping = 0;
205     
206     foreach($delivery_notes as $delivery_num) 
207     {
208         $myrow = get_customer_trans($delivery_num, 13);
209         //$branch = get_branch($myrow["branch_code"]);
210         //$sales_order = get_sales_order_header($myrow["order_"]);
211         
212         //$shipping += $sales_order['freight_cost'];
213         $shipping += $myrow['ov_freight'];
214     }
215     $_POST['ChargeFreightCost'] = price_format($shipping);
216 }
217
218
219 function copy_to_cart()
220 {
221         $cart = &$_SESSION['Items'];
222         $cart->ship_via = $_POST['ship_via'];
223         $cart->freight_cost = input_num('ChargeFreightCost');
224         $cart->document_date =  $_POST['InvoiceDate'];
225         $cart->due_date =  $_POST['due_date'];
226         if ($cart->pos['cash_sale'] || $cart->pos['credit_sale']) {
227                 $cart->payment = $_POST['payment'];
228                 $cart->payment_terms = get_payment_terms($_POST['payment']);
229         }
230         $cart->Comments = $_POST['Comments'];
231         if ($_SESSION['Items']->trans_no == 0)
232                 $cart->reference = $_POST['ref'];
233         $cart->dimension_id =  $_POST['dimension_id'];
234         $cart->dimension2_id =  $_POST['dimension2_id'];
235
236 }
237 //-----------------------------------------------------------------------------
238
239 function copy_from_cart()
240 {
241         $cart = &$_SESSION['Items'];
242         $_POST['ship_via'] = $cart->ship_via;
243         $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
244         $_POST['InvoiceDate']= $cart->document_date;
245         $_POST['due_date'] = $cart->due_date;
246         $_POST['Comments']= $cart->Comments;
247         $_POST['cart_id'] = $cart->cart_id;
248         $_POST['ref'] = $cart->reference;
249         $_POST['payment'] = $cart->payment;
250         $_POST['dimension_id'] = $cart->dimension_id;
251         $_POST['dimension2_id'] = $cart->dimension2_id;
252 }
253
254 //-----------------------------------------------------------------------------
255
256 function check_data()
257 {
258         global $Refs;
259
260         if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
261                 display_error(_("The entered invoice date is invalid."));
262                 set_focus('InvoiceDate');
263                 return false;
264         }
265
266         if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
267                 display_error(_("The entered invoice date is not in fiscal year."));
268                 set_focus('InvoiceDate');
269                 return false;
270         }
271
272         if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
273                 display_error(_("The entered invoice due date is invalid."));
274                 set_focus('due_date');
275                 return false;
276         }
277
278         if ($_SESSION['Items']->trans_no == 0) {
279                 if (!$Refs->is_valid($_POST['ref'])) {
280                         display_error(_("You must enter a reference."));
281                         set_focus('ref');
282                         return false;
283                 }
284
285                 if (!is_new_reference($_POST['ref'], 10)) {
286                         display_error(_("The entered reference is already in use."));
287                         set_focus('ref');
288                         return false;
289                 }
290         }
291
292         if ($_POST['ChargeFreightCost'] == "") {
293                 $_POST['ChargeFreightCost'] = price_format(0);
294         }
295
296         if (!check_num('ChargeFreightCost', 0)) {
297                 display_error(_("The entered shipping value is not numeric."));
298                 set_focus('ChargeFreightCost');
299                 return false;
300         }
301
302         if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
303                 display_error(_("There are no item quantities on this invoice."));
304                 return false;
305         }
306
307         if (!check_quantities()) {
308                 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
309                 return false;
310         }
311
312         return true;
313 }
314
315 //-----------------------------------------------------------------------------
316 if (isset($_POST['process_invoice']) && check_data()) {
317
318         $newinvoice=  $_SESSION['Items']->trans_no == 0;
319         copy_to_cart();
320         if ($newinvoice) new_doc_date($_SESSION['Items']->document_date);
321
322         $invoice_no = $_SESSION['Items']->write();
323         processing_end();
324
325         if ($newinvoice) {
326                 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
327         } else {
328                 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
329         }
330 }
331
332 if(list_updated('payment')) {
333         $order = &$_SESSION['Items'];
334         $order->payment = get_post('payment');
335         $order->payment_terms = get_payment_terms($order->payment);
336         $order->due_date = get_invoice_duedate($order->payment, $order->document_date);
337         if ($order->payment_terms['cash_sale']) {
338                 $_POST['Location'] = $order->Location = $order->pos['pos_location'];
339                 $order->location_name = $order->pos['location_name'];
340         }
341 }
342 // find delivery spans for batch invoice display
343 $dspans = array();
344 $lastdn = ''; $spanlen=1;
345
346 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
347         $line = $_SESSION['Items']->line_items[$line_no];
348         if ($line->quantity == $line->qty_done) {
349                 continue;
350         }
351         if ($line->src_no == $lastdn) {
352                 $spanlen++;
353         } else {
354                 if ($lastdn != '') {
355                         $dspans[] = $spanlen;
356                         $spanlen = 1;
357                 }
358         }
359         $lastdn = $line->src_no;
360 }
361 $dspans[] = $spanlen;
362
363 //-----------------------------------------------------------------------------
364
365 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
366
367 $is_edition = $_SESSION['Items']->trans_type == ST_SALESINVOICE && $_SESSION['Items']->trans_no != 0;
368 start_form();
369 hidden('cart_id');
370
371 start_table(TABLESTYLE2, "width=80%", 5);
372
373 start_row();
374 $colspan = 1;
375 $dim = get_company_pref('use_dimension');
376 if ($dim > 0) 
377         $colspan = 3;
378 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
379 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
380 if ($_SESSION['Items']->pos['credit_sale'] || $_SESSION['Items']->pos['cash_sale']) {
381         $paymcat = !$_SESSION['Items']->pos['cash_sale'] ? PM_CREDIT :
382                 (!$_SESSION['Items']->pos['credit_sale'] ? PM_CASH : PM_ANY);
383         label_cells(_("Payment terms:"), sale_payment_list('payment', $paymcat),
384                 "class='tableheader2'", "colspan=$colspan");
385 } else
386         label_cells(_('Payment:'), $_SESSION['Items']->payment_terms['terms'], "class='tableheader2'", "colspan=$colspan");
387
388 end_row();
389 start_row();
390
391 if ($_SESSION['Items']->trans_no == 0) {
392         ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'");
393 } else {
394         label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
395 }
396
397 //label_cells(_("Delivery Notes:"),
398 //get_customer_trans_view_str(ST_CUSTDELIVERY, array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
399
400 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
401
402 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
403 // 2010-09-03 Joe Hunt
404 //if ($dim > 0) 
405 //      label_cells(_("Dimension"), get_dimension_string($_SESSION['Items']->dimension_id), "class='tableheader2'");
406 if ($dim > 0) {
407         label_cell(_("Dimension").":", "class='tableheader2'");
408         $_POST['dimension_id'] = $_SESSION['Items']->dimension_id;
409         dimensions_list_cells(null, 'dimension_id', null, true, ' ', false, 1, false);
410 }               
411 else
412         hidden('dimension_id', 0);
413
414 end_row();
415 start_row();
416
417 if (!isset($_POST['ship_via'])) {
418         $_POST['ship_via'] = $_SESSION['Items']->ship_via;
419 }
420 label_cell(_("Shipping Company"), "class='tableheader2'");
421 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
422
423 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
424         $_POST['InvoiceDate'] = new_doc_date();
425         if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
426                 $_POST['InvoiceDate'] = end_fiscalyear();
427         }
428 }
429
430 date_cells(_("Date"), 'InvoiceDate', '', $_SESSION['Items']->trans_no == 0, 
431         0, 0, 0, "class='tableheader2'", true);
432
433 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
434         $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_POST['InvoiceDate']);
435 }
436
437 date_cells(_("Due Date"), 'due_date', '', null, 0, 0, 0, "class='tableheader2'");
438 /*
439 if ($dim > 1) 
440         label_cells(_("Dimension"). " 2", get_dimension_string($_SESSION['Items']->dimension2_id), "class='tableheader2'");
441 else if ($dim > 0)
442         label_cell("&nbsp;", "colspan=2");
443 */
444 if ($dim > 1) {
445         label_cell(_("Dimension")." 2:", "class='tableheader2'");
446         $_POST['dimension2_id'] = $_SESSION['Items']->dimension2_id;
447         dimensions_list_cells(null, 'dimension2_id', null, true, ' ', false, 2, false);
448 }               
449 else
450         hidden('dimension2_id', 0);
451 end_row();
452 end_table();
453
454 $row = get_customer_to_order($_SESSION['Items']->customer_id);
455 if ($row['dissallow_invoices'] == 1)
456 {
457         display_error(_("The selected customer account is currently on hold. Please contact the credit control personnel to discuss."));
458         end_form();
459         end_page();
460         exit();
461 }       
462
463 display_heading(_("Invoice Items"));
464
465 div_start('Items');
466 start_table(TABLESTYLE, "width=80%");
467 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
468         _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
469
470 if ($is_batch_invoice) {
471     $th[] = _("DN");
472     $th[] = "";
473 }
474
475 if ($is_edition) {
476     $th[4] = _("Credited");
477 }
478
479 table_header($th);
480 $k = 0;
481 $has_marked = false;
482 $show_qoh = true;
483
484 $dn_line_cnt = 0;
485
486 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
487         if ($ln_itm->quantity == $ln_itm->qty_done) {
488                 continue; // this line was fully invoiced
489         }
490         alt_table_row_color($k);
491         view_stock_status_cell($ln_itm->stock_id);
492
493         text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
494         $dec = get_qty_dec($ln_itm->stock_id);
495         qty_cell($ln_itm->quantity, false, $dec);
496         label_cell($ln_itm->units);
497         qty_cell($ln_itm->qty_done, false, $dec);
498
499         if ($is_batch_invoice) {
500                 // for batch invoices we can only remove whole deliveries
501                 echo '<td nowrap align=right>';
502                 hidden('Line' . $line, $ln_itm->qty_dispatched );
503                 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
504         } else {
505                 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
506         }
507         $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
508
509         $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
510
511         amount_cell($ln_itm->price);
512         label_cell($ln_itm->tax_type_name);
513         label_cell($display_discount_percent, "nowrap align=right");
514         amount_cell($line_total);
515
516         if ($is_batch_invoice) {
517                 if ($dn_line_cnt == 0) {
518                         $dn_line_cnt = $dspans[0];
519                         $dspans = array_slice($dspans, 1);
520                         label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
521                         label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
522                                 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
523                 }
524                 $dn_line_cnt--;
525         }
526         end_row();
527 }
528
529 /*Don't re-calculate freight if some of the order has already been delivered -
530 depending on the business logic required this condition may not be required.
531 It seems unfair to charge the customer twice for freight if the order
532 was not fully delivered the first time ?? */
533
534 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
535         if ($_SESSION['Items']->any_already_delivered() == 1) {
536                 $_POST['ChargeFreightCost'] = price_format(0);
537         } else {
538                 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
539         }
540
541         if (!check_num('ChargeFreightCost')) {
542                 $_POST['ChargeFreightCost'] = price_format(0);
543         }
544 }
545
546 $accumulate_shipping = get_company_pref('accumulate_shipping');
547 if ($is_batch_invoice && $accumulate_shipping)
548         set_delivery_shipping_sum(array_keys($_SESSION['Items']->src_docs));
549
550 $colspan = 9;
551 start_row();
552 label_cell(_("Shipping Cost"), "colspan=$colspan align=right");
553 small_amount_cells(null, 'ChargeFreightCost', null);
554 if ($is_batch_invoice) {
555 label_cell('', 'colspan=2');
556 }
557
558 end_row();
559 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
560
561 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
562
563 label_row(_("Sub-total"), $display_sub_total, "colspan=$colspan align=right","align=right", $is_batch_invoice ? 2 : 0);
564
565 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
566 $tax_total = display_edit_tax_items($taxes, $colspan, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
567
568 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
569
570 label_row(_("Invoice Total"), $display_total, "colspan=$colspan align=right","align=right", $is_batch_invoice ? 2 : 0);
571
572 end_table(1);
573 div_end();
574
575 start_table(TABLESTYLE2);
576 textarea_row(_("Memo"), 'Comments', null, 50, 4);
577
578 end_table(1);
579
580 submit_center_first('Update', _("Update"),
581   _('Refresh document page'), true);
582 submit_center_last('process_invoice', _("Process Invoice"),
583   _('Check entered data and save document'), 'default');
584
585 end_form();
586
587 end_page();
588
589 ?>