Sales/purchase terms update after document date change [0000058].
[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 } elseif (!check_quantities()) {
140         display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
141 }
142 if (isset($_POST['Update'])) {
143         $Ajax->activate('Items');
144 }
145 if (isset($_POST['_InvoiceDate_changed'])) {
146         $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, 
147                 $_POST['InvoiceDate']);
148         $Ajax->activate('due_date');
149 }
150 //-----------------------------------------------------------------------------
151 function check_quantities()
152 {
153         $ok =1;
154         foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
155                 if (isset($_POST['Line'.$line_no])) {
156                         if($_SESSION['Items']->trans_no) {
157                                 $min = $itm->qty_done;
158                                 $max = $itm->quantity;
159                         } else {
160                                 $min = 0;
161                                 $max = $itm->quantity - $itm->qty_done;
162                         }
163                         if (check_num('Line'.$line_no, $min, $max)) {
164                                 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
165                                     input_num('Line'.$line_no);
166                         }
167                         else {
168                                 $ok = 0;
169                         }
170                                 
171                 }
172
173                 if (isset($_POST['Line'.$line_no.'Desc'])) {
174                         $line_desc = $_POST['Line'.$line_no.'Desc'];
175                         if (strlen($line_desc) > 0) {
176                                 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
177                         }
178                 }
179         }
180  return $ok;
181 }
182
183 function copy_to_cart()
184 {
185         $cart = &$_SESSION['Items'];
186         $cart->ship_via = $_POST['ship_via'];
187         $cart->freight_cost = input_num('ChargeFreightCost');
188         $cart->document_date =  $_POST['InvoiceDate'];
189         $cart->due_date =  $_POST['due_date'];
190         $cart->Comments = $_POST['Comments'];
191 }
192 //-----------------------------------------------------------------------------
193
194 function copy_from_cart()
195 {
196         $cart = &$_SESSION['Items'];
197         $_POST['ship_via'] = $cart->ship_via;
198         $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
199         $_POST['InvoiceDate']= $cart->document_date;
200         $_POST['due_date'] = $cart->due_date;
201         $_POST['Comments']= $cart->Comments;
202 }
203
204 //-----------------------------------------------------------------------------
205
206 function check_data()
207 {
208         if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
209                 display_error(_("The entered invoice date is invalid."));
210                 set_focus('InvoiceDate');
211                 return false;
212         }
213
214         if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
215                 display_error(_("The entered invoice date is not in fiscal year."));
216                 set_focus('InvoiceDate');
217                 return false;
218         }
219
220         if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
221                 display_error(_("The entered invoice due date is invalid."));
222                 set_focus('due_date');
223                 return false;
224         }
225
226         if ($_SESSION['Items']->trans_no == 0) {
227                 if (!references::is_valid($_POST['ref'])) {
228                         display_error(_("You must enter a reference."));
229                         set_focus('ref');
230                         return false;
231                 }
232
233                 if (!is_new_reference($_POST['ref'], 10)) {
234                         display_error(_("The entered reference is already in use."));
235                         set_focus('ref');
236                         return false;
237                 }
238         }
239
240         if ($_POST['ChargeFreightCost'] == "") {
241                 $_POST['ChargeFreightCost'] = price_format(0);
242         }
243
244         if (!check_num('ChargeFreightCost', 0)) {
245                 display_error(_("The entered shipping value is not numeric."));
246                 set_focus('ChargeFreightCost');
247                 return false;
248         }
249
250         if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
251                 display_error(_("There are no item quantities on this invoice."));
252                 return false;
253         }
254
255         if (!check_quantities()) {
256                 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
257                 return false;
258         }
259
260         return true;
261 }
262
263 //-----------------------------------------------------------------------------
264 if (isset($_POST['process_invoice']) && check_data()) {
265
266         $newinvoice=  $_SESSION['Items']->trans_no == 0;
267         copy_to_cart();
268         $invoice_no = $_SESSION['Items']->write();
269
270         processing_end();
271         if ($newinvoice) {
272                 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
273         } else {
274                 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
275         }
276 }
277
278 // find delivery spans for batch invoice display
279 $dspans = array();
280 $lastdn = ''; $spanlen=1;
281
282 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
283         $line = $_SESSION['Items']->line_items[$line_no];
284         if ($line->quantity == $line->qty_done) {
285                 continue;
286         }
287         if ($line->src_no == $lastdn) {
288                 $spanlen++;
289         } else {
290                 if ($lastdn != '') {
291                         $dspans[] = $spanlen;
292                         $spanlen = 1;
293                 }
294         }
295         $lastdn = $line->src_no;
296 }
297 $dspans[] = $spanlen;
298
299 //-----------------------------------------------------------------------------
300
301 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
302 $is_edition = $_SESSION['Items']->trans_type == 10 && $_SESSION['Items']->trans_no != 0;
303 start_form(false, true);
304
305 start_table("$table_style2 width=80%", 5);
306
307 start_row();
308 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
309 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
310 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
311 end_row();
312 start_row();
313
314 if ($_SESSION['Items']->trans_no == 0) {
315         ref_cells(_("Reference"), 'ref', '', $_SESSION['Items']->reference, "class='tableheader2'");
316 } else {
317         label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
318 }
319
320 label_cells(_("Delivery Notes:"),
321 get_customer_trans_view_str(systypes::cust_dispatch(), array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
322
323 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
324
325 end_row();
326 start_row();
327
328 if (!isset($_POST['ship_via'])) {
329         $_POST['ship_via'] = $_SESSION['Items']->ship_via;
330 }
331 label_cell(_("Shipping Company"), "class='tableheader2'");
332 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
333
334 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
335         $_POST['InvoiceDate'] = Today();
336         if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
337                 $_POST['InvoiceDate'] = end_fiscalyear();
338         }
339 }
340
341 date_cells(_("Date"), 'InvoiceDate', '', $_POST['InvoiceDate'], 0, 0, 0, "class='tableheader2'", true);
342
343 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
344         $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, $_POST['InvoiceDate']);
345 }
346
347 date_cells(_("Due Date"), 'due_date', '', $_POST['due_date'], 0, 0, 0, "class='tableheader2'");
348
349 end_row();
350 end_table();
351
352 display_heading(_("Invoice Items"));
353
354 div_start('Items');
355 start_table("$table_style width=80%");
356 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
357         _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
358
359 if ($is_batch_invoice) {
360     $th[] = _("DN");
361     $th[] = "";
362 }
363
364 if ($is_edition) {
365     $th[4] = _("Credited");
366 }
367
368 table_header($th);
369 $k = 0;
370 $has_marked = false;
371 $show_qoh = true;
372
373 $dn_line_cnt = 0;
374
375 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
376         if ($ln_itm->quantity == $ln_itm->qty_done) {
377                 continue; // this line was fully invoiced
378         }
379         alt_table_row_color($k);
380         view_stock_status_cell($ln_itm->stock_id);
381
382         text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
383         $dec = get_qty_dec($ln_itm->stock_id);
384         qty_cell($ln_itm->quantity, false, $dec);
385         label_cell($ln_itm->units);
386         qty_cell($ln_itm->qty_done, false, $dec);
387
388         if ($is_batch_invoice) {
389                 // for batch invoices we can only remove whole deliveries
390                 echo '<td nowrap align=right>';
391                 hidden('Line' . $line, $ln_itm->qty_dispatched );
392                 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
393         } else {
394                 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
395         }
396         $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
397
398         $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
399
400         amount_cell($ln_itm->price);
401         label_cell($ln_itm->tax_type_name);
402         label_cell($display_discount_percent, "nowrap align=right");
403         amount_cell($line_total);
404
405         if ($is_batch_invoice) {
406                 if ($dn_line_cnt == 0) {
407                         $dn_line_cnt = $dspans[0];
408                         $dspans = array_slice($dspans, 1);
409                         label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
410                         label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
411                                 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
412                 }
413                 $dn_line_cnt--;
414         }
415         end_row();
416 }
417
418 /*Don't re-calculate freight if some of the order has already been delivered -
419 depending on the business logic required this condition may not be required.
420 It seems unfair to charge the customer twice for freight if the order
421 was not fully delivered the first time ?? */
422
423 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
424         if ($_SESSION['Items']->any_already_delivered() == 1) {
425                 $_POST['ChargeFreightCost'] = price_format(0);
426         } else {
427                 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
428         }
429
430         if (!check_num('ChargeFreightCost')) {
431                 $_POST['ChargeFreightCost'] = price_format(0);
432         }
433 }
434
435 start_row();
436
437 small_amount_cells(_("Shipping Cost"), 'ChargeFreightCost', null, "colspan=9 align=right");
438 if ($is_batch_invoice) {
439 label_cell('', 'colspan=2');
440 }
441
442 end_row();
443 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
444
445 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
446
447 label_row(_("Sub-total"), $display_sub_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
448
449 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
450 $tax_total = display_edit_tax_items($taxes, 9, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
451
452 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
453
454 label_row(_("Invoice Total"), $display_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
455
456 end_table(1);
457 div_end();
458
459 start_table($table_style2);
460 textarea_row(_("Memo"), 'Comments', null, 50, 4);
461
462 end_table(1);
463
464 submit_center_first('Update', _("Update"),
465   _('Refresh document page'), true);
466 submit_center_last('process_invoice', _("Process Invoice"),
467   _('Check entered data and save document'), true);
468
469 end_form();
470
471 end_page();
472
473 ?>