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