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