Changed API for input/lists functions, added empty hints when needed
[fa-stable.git] / sales / customer_invoice.php
1 <?php
2 //---------------------------------------------------------------------------
3 //
4 //      Entry/Modify Sales Invoice against single delivery
5 //      Entry/Modify Batch Sales Invoice against batch of deliveries
6 //
7 $page_security = 2;
8 $path_to_root="..";
9 include_once($path_to_root . "/sales/includes/cart_class.inc");
10 include_once($path_to_root . "/includes/session.inc");
11 include_once($path_to_root . "/includes/data_checks.inc");
12 include_once($path_to_root . "/includes/manufacturing.inc");
13 include_once($path_to_root . "/sales/includes/sales_db.inc");
14 include_once($path_to_root . "/sales/includes/sales_ui.inc");
15 include_once($path_to_root . "/reporting/includes/reporting.inc");
16 include_once($path_to_root . "/taxes/tax_calc.inc");
17
18 $js = "";
19 if ($use_popup_windows) {
20         $js .= get_js_open_window(900, 500);
21 }
22 if ($use_date_picker) {
23         $js .= get_js_date_picker();
24 }
25
26 if (isset($_GET['ModifyInvoice'])) {
27         $_SESSION['page_title'] = sprintf(_("Modifying Sales Invoice # %d.") ,$_GET['ModifyInvoice']);
28         $help_page_title = _("Modifying Sales Invoice");
29 } elseif (isset($_GET['DeliveryNumber'])) {
30         $_SESSION['page_title'] = _("Issue an Invoice for Delivery Note");
31 } elseif (isset($_GET['BatchInvoice'])) {
32         $_SESSION['page_title'] = _("Issue Batch Invoice for Delivery Notes");
33 }
34
35 page($_SESSION['page_title'], false, false, "", $js);
36
37 //-----------------------------------------------------------------------------
38
39 if (isset($_GET['AddedID'])) {
40
41         $invoice_no = $_GET['AddedID'];
42         $trans_type = 10;
43         print_hidden_script(10);
44
45         display_notification(_("Selected deliveries has been processed"), true);
46
47         display_note(get_customer_trans_view_str($trans_type, $invoice_no, _("View This Invoice")), 0, 1);
48
49         display_note(print_document_link($invoice_no, _("Print This Invoice"), true, 10));
50
51         display_note(get_gl_view_str($trans_type, $invoice_no, _("View the GL Journal Entries for this Invoice")),1);
52
53         hyperlink_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Another Delivery For Invoicing"), "OutstandingOnly=1");
54
55         display_footer_exit();
56
57 } elseif (isset($_GET['UpdatedID']))  {
58
59         $invoice_no = $_GET['UpdatedID'];
60         print_hidden_script(10);
61
62         display_notification_centered(sprintf(_('Sales Invoice # %d has been updated.'),$invoice_no));
63
64         display_note(get_trans_view_str(10, $invoice_no, _("View This Invoice")));
65         echo '<br>';
66         display_note(print_document_link($invoice_no, _("Print This Invoice"), true, 10));
67
68         hyperlink_no_params($path_to_root . "/sales/inquiry/customer_inquiry.php", _("Select A Different Invoice to Modify"));
69
70         display_footer_exit();
71
72 } elseif (isset($_GET['RemoveDN'])) {
73
74         for($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
75                 $line = &$_SESSION['Items']->line_items[$line_no];
76                 if ($line->src_no == $_GET['RemoveDN']) {
77                         $line->quantity = $line->qty_done;
78                         $line->qty_dispatched=0;
79                 }
80         }
81         unset($line);
82 }
83
84 //-----------------------------------------------------------------------------
85
86 if ( (isset($_GET['DeliveryNumber']) && ($_GET['DeliveryNumber'] > 0) )
87         || isset($_GET['BatchInvoice'])) {
88
89         processing_start();
90
91         if (isset($_GET['BatchInvoice'])) {
92                 $src = $_SESSION['DeliveryBatch'];
93                 unset($_SESSION['DeliveryBatch']);
94         } else {
95                 $src = array($_GET['DeliveryNumber']);
96         }
97         /*read in all the selected deliveries into the Items cart  */
98         $dn = new Cart(13, $src, true);
99
100         if ($dn->count_items() == 0) {
101                 hyperlink_params($path_to_root . "/sales/inquiry/sales_deliveries_view.php",
102                         _("Select a different delivery to invoice"), "OutstandingOnly=1");
103                 die ("<br><b>" . _("There are no delivered items with a quantity left to invoice. There is nothing left to invoice.") . "</b>");
104         }
105
106         $dn->trans_type = 10;
107         $dn->src_docs = $dn->trans_no;
108         $dn->trans_no = 0;
109         $dn->reference = references::get_next(10);
110         $dn->due_date = get_invoice_duedate($dn->customer_id, $dn->document_date);
111
112         $_SESSION['Items'] = $dn;
113         copy_from_cart();
114
115 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
116
117         if ( get_parent_trans(10, $_GET['ModifyInvoice']) == 0) { // 1.xx compatibility hack
118                 echo"<center><br><b>" . _("There in no delivery notes for this invoice.<br>
119                 Most likely this invoice was created in Front Accounting version prior to 2.0
120                 and therefore can not be modified.") . "</b></center>";
121                 display_footer_exit();
122         }
123         processing_start();
124         $_SESSION['Items'] = new Cart(10, $_GET['ModifyInvoice']);
125
126         if ($_SESSION['Items']->count_items() == 0) {
127                 echo"<center><br><b>" . _("All quantities on this invoice has been credited. There is nothing to modify on this invoice") . "</b></center>";
128                 display_footer_exit();
129         }
130         copy_from_cart();
131 } elseif (!processing_active()) {
132         /* This page can only be called with a delivery for invoicing or invoice no for edit */
133         display_error(_("This page can only be opened after delivery selection. Please select delivery to invoicing first."));
134
135         hyperlink_no_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Delivery to Invoice"));
136
137         end_page();
138         exit;
139 } else {
140         foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
141                 if (isset($_POST['Line'.$line_no])) {
142                         if (!check_num('Line'.$line_no, 0, ($itm->quantity - $itm->qty_done))) {
143                                 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
144                                     input_num('Line'.$line_no);
145                         }
146                 }
147
148                 if (isset($_POST['Line'.$line_no.'Desc'])) {
149                         $line_desc = $_POST['Line'.$line_no.'Desc'];
150                         if (strlen($line_desc) > 0) {
151                                 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
152                         }
153                 }
154         }
155 }
156 //-----------------------------------------------------------------------------
157
158 function copy_to_cart()
159 {
160         $cart = &$_SESSION['Items'];
161         $cart->ship_via = $_POST['ship_via'];
162         $cart->freight_cost = input_num('ChargeFreightCost');
163         $cart->document_date =  $_POST['InvoiceDate'];
164         $cart->due_date =  $_POST['due_date'];
165         $cart->Comments = $_POST['Comments'];
166 }
167 //-----------------------------------------------------------------------------
168
169 function copy_from_cart()
170 {
171         $cart = &$_SESSION['Items'];
172         $_POST['ship_via'] = $cart->ship_via;
173         $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
174         $_POST['InvoiceDate']= $cart->document_date;
175         $_POST['due_date'] = $cart->due_date;
176         $_POST['Comments']= $cart->Comments;
177 }
178
179 //-----------------------------------------------------------------------------
180
181 function check_data()
182 {
183         if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
184                 display_error(_("The entered invoice date is invalid."));
185                 set_focus('InvoiceDate');
186                 return false;
187         }
188
189         if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
190                 display_error(_("The entered invoice date is not in fiscal year."));
191                 set_focus('InvoiceDate');
192                 return false;
193         }
194
195         if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
196                 display_error(_("The entered invoice due date is invalid."));
197                 set_focus('due_date');
198                 return false;
199         }
200
201         if ($_SESSION['Items']->trans_no == 0) {
202                 if (!references::is_valid($_POST['ref'])) {
203                         display_error(_("You must enter a reference."));
204                         set_focus('ref');
205                         return false;
206                 }
207
208                 if (!is_new_reference($_POST['ref'], 10)) {
209                         display_error(_("The entered reference is already in use."));
210                         set_focus('ref');
211                         return false;
212                 }
213         }
214
215         if ($_POST['ChargeFreightCost'] == "") {
216                 $_POST['ChargeFreightCost'] = price_format(0);
217         }
218
219         if (!check_num('ChargeFreightCost', 0)) {
220                 display_error(_("The entered shipping value is not numeric."));
221                 set_focus('ChargeFreightCost');
222                 return false;
223         }
224
225         if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
226                 display_error(_("There are no item quantities on this invoice."));
227                 return false;
228         }
229
230         return true;
231 }
232
233 //-----------------------------------------------------------------------------
234 if (isset($_POST['process_invoice']) && check_data()) {
235
236         $newinvoice=  $_SESSION['Items']->trans_no == 0;
237         copy_to_cart();
238         $invoice_no = $_SESSION['Items']->write();
239
240         processing_end();
241         if ($newinvoice) {
242                 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
243         } else {
244                 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
245         }
246 }
247
248 // find delivery spans for batch invoice display
249 $dspans = array();
250 $lastdn = ''; $spanlen=1;
251
252 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
253         $line = $_SESSION['Items']->line_items[$line_no];
254         if ($line->quantity == $line->qty_done) {
255                 continue;
256         }
257         if ($line->src_no == $lastdn) {
258                 $spanlen++;
259         } else {
260                 if ($lastdn != '') {
261                         $dspans[] = $spanlen;
262                         $spanlen = 1;
263                 }
264         }
265         $lastdn = $line->src_no;
266 }
267 $dspans[] = $spanlen;
268
269 //-----------------------------------------------------------------------------
270
271 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
272 $is_edition = $_SESSION['Items']->trans_type == 10 && $_SESSION['Items']->trans_no != 0;
273 start_form(false, true);
274
275 start_table("$table_style2 width=80%", 5);
276
277 start_row();
278 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
279 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
280 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
281 end_row();
282 start_row();
283
284 if ($_SESSION['Items']->trans_no == 0) {
285         ref_cells(_("Reference"), 'ref', '', $_SESSION['Items']->reference, "class='tableheader2'");
286 } else {
287         label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
288 }
289
290 label_cells(_("Delivery Notes:"),
291 get_customer_trans_view_str(systypes::cust_dispatch(), array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
292
293 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
294
295 end_row();
296 start_row();
297
298 if (!isset($_POST['ship_via'])) {
299         $_POST['ship_via'] = $_SESSION['Items']->ship_via;
300 }
301 label_cell(_("Shipping Company"), "class='tableheader2'");
302 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
303
304 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
305         $_POST['InvoiceDate'] = Today();
306         if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
307                 $_POST['InvoiceDate'] = end_fiscalyear();
308         }
309 }
310
311 date_cells(_("Date"), 'InvoiceDate', '', $_POST['InvoiceDate'], 0, 0, 0, "class='tableheader2'");
312
313 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
314         $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, $_POST['InvoiceDate']);
315 }
316
317 date_cells(_("Due Date"), 'due_date', '', $_POST['due_date'], 0, 0, 0, "class='tableheader2'");
318
319 end_row();
320 end_table();
321
322 display_heading(_("Invoice Items"));
323
324 start_table("$table_style width=80%");
325 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
326         _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
327
328 if ($is_batch_invoice) {
329     $th[] = _("DN");
330     $th[] = "";
331 }
332
333 if ($is_edition) {
334     $th[4] = _("Credited");
335 }
336
337 table_header($th);
338 $k = 0;
339 $has_marked = false;
340 $show_qoh = true;
341
342 $dn_line_cnt = 0;
343
344 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
345         if ($ln_itm->quantity == $ln_itm->qty_done) {
346                 continue; // this line was fully invoiced
347         }
348         alt_table_row_color($k);
349         view_stock_status_cell($ln_itm->stock_id);
350
351         text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
352         qty_cell($ln_itm->quantity);
353         label_cell($ln_itm->units);
354         qty_cell($ln_itm->qty_done);
355
356         if ($is_batch_invoice) {
357                 // for batch invoices we can only remove whole deliveries
358                 echo '<td nowrap align=right>';
359                 hidden('Line' . $line, $ln_itm->qty_dispatched );
360                 echo qty_format($ln_itm->qty_dispatched).'</td>';
361         } else {
362                 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched));
363         }
364         $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
365
366         $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
367
368         amount_cell($ln_itm->price);
369         label_cell($ln_itm->tax_type_name);
370         label_cell($display_discount_percent, "nowrap align=right");
371         amount_cell($line_total);
372
373         if ($is_batch_invoice) {
374                 if ($dn_line_cnt == 0) {
375                         $dn_line_cnt = $dspans[0];
376                         $dspans = array_slice($dspans, 1);
377                         label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
378                         label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
379                                 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
380                 }
381                 $dn_line_cnt--;
382         }
383         end_row();
384 }
385
386 /*Don't re-calculate freight if some of the order has already been delivered -
387 depending on the business logic required this condition may not be required.
388 It seems unfair to charge the customer twice for freight if the order
389 was not fully delivered the first time ?? */
390
391 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
392         if ($_SESSION['Items']->any_already_delivered() == 1) {
393                 $_POST['ChargeFreightCost'] = price_format(0);
394         } else {
395                 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
396         }
397
398         if (!check_num('ChargeFreightCost')) {
399                 $_POST['ChargeFreightCost'] = price_format(0);
400         }
401 }
402
403 start_row();
404
405 small_amount_cells(_("Shipping Cost"), 'ChargeFreightCost', null, "colspan=9 align=right");
406 if ($is_batch_invoice) {
407 label_cell('', 'colspan=2');
408 }
409
410 end_row();
411 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
412
413 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
414
415 label_row(_("Sub-total"), $display_sub_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
416
417 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
418 $tax_total = display_edit_tax_items($taxes, 9, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
419
420 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
421
422 label_row(_("Invoice Total"), $display_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
423
424 end_table(1);
425
426 start_table($table_style2);
427
428 textarea_row(_("Memo"), 'Comments', null, 50, 4);
429
430 end_table(1);
431
432 submit_center_first('Update', _("Update"));
433 submit_center_last('process_invoice', _("Process Invoice"));
434
435 end_form();
436
437 end_page();
438
439 ?>