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