fed8094e05337bdd8035ac7f50f1ab9964569b31
[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 check_edit_conflicts();
39
40 if (isset($_GET['AddedID'])) {
41
42         $invoice_no = $_GET['AddedID'];
43         $trans_type = 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
61         display_notification_centered(sprintf(_('Sales Invoice # %d has been updated.'),$invoice_no));
62
63         display_note(get_trans_view_str(10, $invoice_no, _("&View This Invoice")));
64         echo '<br>';
65         display_note(print_document_link($invoice_no, _("&Print This Invoice"), true, 10));
66
67         hyperlink_no_params($path_to_root . "/sales/inquiry/customer_inquiry.php", _("Select A Different &Invoice to Modify"));
68
69         display_footer_exit();
70
71 } elseif (isset($_GET['RemoveDN'])) {
72
73         for($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
74                 $line = &$_SESSION['Items']->line_items[$line_no];
75                 if ($line->src_no == $_GET['RemoveDN']) {
76                         $line->quantity = $line->qty_done;
77                         $line->qty_dispatched=0;
78                 }
79         }
80         unset($line);
81
82     // Remove also src_doc delivery note
83     $sources = &$_SESSION['Items']->src_docs;
84     unset($sources[$_GET['RemoveDN']]);
85 }
86
87 //-----------------------------------------------------------------------------
88
89 if ( (isset($_GET['DeliveryNumber']) && ($_GET['DeliveryNumber'] > 0) )
90 || isset($_GET['BatchInvoice'])) {
91
92         processing_start();
93
94         if (isset($_GET['BatchInvoice'])) {
95                 $src = $_SESSION['DeliveryBatch'];
96                 unset($_SESSION['DeliveryBatch']);
97         } else {
98                 $src = array($_GET['DeliveryNumber']);
99         }
100         /*read in all the selected deliveries into the Items cart  */
101         $dn = new Cart(13, $src, true);
102
103         if ($dn->count_items() == 0) {
104                 hyperlink_params($path_to_root . "/sales/inquiry/sales_deliveries_view.php",
105                         _("Select a different delivery to invoice"), "OutstandingOnly=1");
106                 die ("<br><b>" . _("There are no delivered items with a quantity left to invoice. There is nothing left to invoice.") . "</b>");
107         }
108
109         $dn->trans_type = 10;
110         $dn->src_docs = $dn->trans_no;
111         $dn->trans_no = 0;
112         $dn->reference = references::get_next(10);
113         $dn->due_date = get_invoice_duedate($dn->customer_id, $dn->document_date);
114
115         $_SESSION['Items'] = $dn;
116         copy_from_cart();
117
118 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
119
120         if ( get_parent_trans(10, $_GET['ModifyInvoice']) == 0) { // 1.xx compatibility hack
121                 echo"<center><br><b>" . _("There in no delivery notes for this invoice.<br>
122                 Most likely this invoice was created in Front Accounting version prior to 2.0
123                 and therefore can not be modified.") . "</b></center>";
124                 display_footer_exit();
125         }
126         processing_start();
127         $_SESSION['Items'] = new Cart(10, $_GET['ModifyInvoice']);
128
129         if ($_SESSION['Items']->count_items() == 0) {
130                 echo"<center><br><b>" . _("All quantities on this invoice has been credited. There is nothing to modify on this invoice") . "</b></center>";
131                 display_footer_exit();
132         }
133         copy_from_cart();
134 } elseif (!processing_active()) {
135         /* This page can only be called with a delivery for invoicing or invoice no for edit */
136         display_error(_("This page can only be opened after delivery selection. Please select delivery to invoicing first."));
137
138         hyperlink_no_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Delivery to Invoice"));
139
140         end_page();
141         exit;
142 } elseif (!check_quantities()) {
143         display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
144 }
145 if (isset($_POST['Update'])) {
146         $Ajax->activate('Items');
147 }
148 if (isset($_POST['_InvoiceDate_changed'])) {
149         $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, 
150                 $_POST['InvoiceDate']);
151         $Ajax->activate('due_date');
152 }
153
154 //-----------------------------------------------------------------------------
155 function check_quantities()
156 {
157         $ok =1;
158         foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
159                 if (isset($_POST['Line'.$line_no])) {
160                         if($_SESSION['Items']->trans_no) {
161                                 $min = $itm->qty_done;
162                                 $max = $itm->quantity;
163                         } else {
164                                 $min = 0;
165                                 $max = $itm->quantity - $itm->qty_done;
166                         }
167                         if (check_num('Line'.$line_no, $min, $max)) {
168                                 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
169                                     input_num('Line'.$line_no);
170                         }
171                         else {
172                                 $ok = 0;
173                         }
174                                 
175                 }
176
177                 if (isset($_POST['Line'.$line_no.'Desc'])) {
178                         $line_desc = $_POST['Line'.$line_no.'Desc'];
179                         if (strlen($line_desc) > 0) {
180                                 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
181                         }
182                 }
183         }
184  return $ok;
185 }
186
187 function set_delivery_shipping_sum($delivery_notes) 
188 {
189     
190     $shipping = 0;
191     
192     foreach($delivery_notes as $delivery_num) 
193     {
194         $myrow = get_customer_trans($delivery_num, 13);
195         //$branch = get_branch($myrow["branch_code"]);
196         //$sales_order = get_sales_order_header($myrow["order_"]);
197         
198         //$shipping += $sales_order['freight_cost'];
199         $shipping += $myrow['ov_freight'];
200     }
201     $_POST['ChargeFreightCost'] = price_format($shipping);
202 }
203
204
205 function copy_to_cart()
206 {
207         $cart = &$_SESSION['Items'];
208         $cart->ship_via = $_POST['ship_via'];
209         $cart->freight_cost = input_num('ChargeFreightCost');
210         $cart->document_date =  $_POST['InvoiceDate'];
211         $cart->due_date =  $_POST['due_date'];
212         $cart->Comments = $_POST['Comments'];
213 }
214 //-----------------------------------------------------------------------------
215
216 function copy_from_cart()
217 {
218         $cart = &$_SESSION['Items'];
219         $_POST['ship_via'] = $cart->ship_via;
220         $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
221         $_POST['InvoiceDate']= $cart->document_date;
222         $_POST['due_date'] = $cart->due_date;
223         $_POST['Comments']= $cart->Comments;
224         $_POST['cart_id'] = $cart->cart_id;
225 }
226
227 //-----------------------------------------------------------------------------
228
229 function check_data()
230 {
231         if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
232                 display_error(_("The entered invoice date is invalid."));
233                 set_focus('InvoiceDate');
234                 return false;
235         }
236
237         if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
238                 display_error(_("The entered invoice date is not in fiscal year."));
239                 set_focus('InvoiceDate');
240                 return false;
241         }
242
243         if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
244                 display_error(_("The entered invoice due date is invalid."));
245                 set_focus('due_date');
246                 return false;
247         }
248
249         if ($_SESSION['Items']->trans_no == 0) {
250                 if (!references::is_valid($_POST['ref'])) {
251                         display_error(_("You must enter a reference."));
252                         set_focus('ref');
253                         return false;
254                 }
255
256                 if (!is_new_reference($_POST['ref'], 10)) {
257                         display_error(_("The entered reference is already in use."));
258                         set_focus('ref');
259                         return false;
260                 }
261         }
262
263         if ($_POST['ChargeFreightCost'] == "") {
264                 $_POST['ChargeFreightCost'] = price_format(0);
265         }
266
267         if (!check_num('ChargeFreightCost', 0)) {
268                 display_error(_("The entered shipping value is not numeric."));
269                 set_focus('ChargeFreightCost');
270                 return false;
271         }
272
273         if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
274                 display_error(_("There are no item quantities on this invoice."));
275                 return false;
276         }
277
278         if (!check_quantities()) {
279                 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
280                 return false;
281         }
282
283         return true;
284 }
285
286 //-----------------------------------------------------------------------------
287 if (isset($_POST['process_invoice']) && check_data()) {
288
289         $newinvoice=  $_SESSION['Items']->trans_no == 0;
290         copy_to_cart();
291         $invoice_no = $_SESSION['Items']->write();
292
293         processing_end();
294         if ($newinvoice) {
295                 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
296         } else {
297                 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
298         }
299 }
300
301 // find delivery spans for batch invoice display
302 $dspans = array();
303 $lastdn = ''; $spanlen=1;
304
305 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
306         $line = $_SESSION['Items']->line_items[$line_no];
307         if ($line->quantity == $line->qty_done) {
308                 continue;
309         }
310         if ($line->src_no == $lastdn) {
311                 $spanlen++;
312         } else {
313                 if ($lastdn != '') {
314                         $dspans[] = $spanlen;
315                         $spanlen = 1;
316                 }
317         }
318         $lastdn = $line->src_no;
319 }
320 $dspans[] = $spanlen;
321
322 //-----------------------------------------------------------------------------
323
324 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
325
326 $is_edition = $_SESSION['Items']->trans_type == 10 && $_SESSION['Items']->trans_no != 0;
327 start_form(false, true);
328 hidden('cart_id');
329
330 start_table("$table_style2 width=80%", 5);
331
332 start_row();
333 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
334 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
335 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
336 end_row();
337 start_row();
338
339 if ($_SESSION['Items']->trans_no == 0) {
340         ref_cells(_("Reference"), 'ref', '', $_SESSION['Items']->reference, "class='tableheader2'");
341 } else {
342         label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
343 }
344
345 label_cells(_("Delivery Notes:"),
346 get_customer_trans_view_str(systypes::cust_dispatch(), array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
347
348 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
349
350 end_row();
351 start_row();
352
353 if (!isset($_POST['ship_via'])) {
354         $_POST['ship_via'] = $_SESSION['Items']->ship_via;
355 }
356 label_cell(_("Shipping Company"), "class='tableheader2'");
357 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
358
359 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
360         $_POST['InvoiceDate'] = Today();
361         if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
362                 $_POST['InvoiceDate'] = end_fiscalyear();
363         }
364 }
365
366 date_cells(_("Date"), 'InvoiceDate', '', $_POST['InvoiceDate'], 0, 0, 0, "class='tableheader2'", true);
367
368 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
369         $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, $_POST['InvoiceDate']);
370 }
371
372 date_cells(_("Due Date"), 'due_date', '', $_POST['due_date'], 0, 0, 0, "class='tableheader2'");
373
374 end_row();
375 end_table();
376
377 display_heading(_("Invoice Items"));
378
379 div_start('Items');
380 start_table("$table_style width=80%");
381 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
382         _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
383
384 if ($is_batch_invoice) {
385     $th[] = _("DN");
386     $th[] = "";
387 }
388
389 if ($is_edition) {
390     $th[4] = _("Credited");
391 }
392
393 table_header($th);
394 $k = 0;
395 $has_marked = false;
396 $show_qoh = true;
397
398 $dn_line_cnt = 0;
399
400 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
401         if ($ln_itm->quantity == $ln_itm->qty_done) {
402                 continue; // this line was fully invoiced
403         }
404         alt_table_row_color($k);
405         view_stock_status_cell($ln_itm->stock_id);
406
407         text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
408         $dec = get_qty_dec($ln_itm->stock_id);
409         qty_cell($ln_itm->quantity, false, $dec);
410         label_cell($ln_itm->units);
411         qty_cell($ln_itm->qty_done, false, $dec);
412
413         if ($is_batch_invoice) {
414                 // for batch invoices we can only remove whole deliveries
415                 echo '<td nowrap align=right>';
416                 hidden('Line' . $line, $ln_itm->qty_dispatched );
417                 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
418         } else {
419                 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
420         }
421         $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
422
423         $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
424
425         amount_cell($ln_itm->price);
426         label_cell($ln_itm->tax_type_name);
427         label_cell($display_discount_percent, "nowrap align=right");
428         amount_cell($line_total);
429
430         if ($is_batch_invoice) {
431                 if ($dn_line_cnt == 0) {
432                         $dn_line_cnt = $dspans[0];
433                         $dspans = array_slice($dspans, 1);
434                         label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
435                         label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
436                                 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
437                 }
438                 $dn_line_cnt--;
439         }
440         end_row();
441 }
442
443 /*Don't re-calculate freight if some of the order has already been delivered -
444 depending on the business logic required this condition may not be required.
445 It seems unfair to charge the customer twice for freight if the order
446 was not fully delivered the first time ?? */
447
448 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
449         if ($_SESSION['Items']->any_already_delivered() == 1) {
450                 $_POST['ChargeFreightCost'] = price_format(0);
451         } else {
452                 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
453         }
454
455         if (!check_num('ChargeFreightCost')) {
456                 $_POST['ChargeFreightCost'] = price_format(0);
457         }
458 }
459
460 $accumulate_shipping = get_company_pref('accumulate_shipping');
461 if ($is_batch_invoice && $accumulate_shipping)
462         set_delivery_shipping_sum(array_keys($_SESSION['Items']->src_docs));
463
464 start_row();
465
466 small_amount_cells(_("Shipping Cost"), 'ChargeFreightCost', null, "colspan=9 align=right");
467 if ($is_batch_invoice) {
468 label_cell('', 'colspan=2');
469 }
470
471 end_row();
472 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
473
474 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
475
476 label_row(_("Sub-total"), $display_sub_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
477
478 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
479 $tax_total = display_edit_tax_items($taxes, 9, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
480
481 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
482
483 label_row(_("Invoice Total"), $display_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
484
485 end_table(1);
486 div_end();
487
488 start_table($table_style2);
489 textarea_row(_("Memo"), 'Comments', null, 50, 4);
490
491 end_table(1);
492
493 submit_center_first('Update', _("Update"),
494   _('Refresh document page'), true);
495 submit_center_last('process_invoice', _("Process Invoice"),
496   _('Check entered data and save document'), true);
497
498 end_form();
499
500 end_page();
501
502 ?>