Some smaller and compatibility fixes - see CHANGELOG.txt
[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
111         $_SESSION['Items'] = $dn;
112         copy_from_cart();
113
114 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
115
116         processing_start();
117         $_SESSION['Items'] = new Cart(10, $_GET['ModifyInvoice']);
118
119         if ($_SESSION['Items']->count_items() == 0) {
120                 echo"<center><br><b>" . _("All quantities on this invoice has been credited. There is nothing to modify on this invoice") . "</b></center>";
121                 display_footer_exit();
122         }
123         copy_from_cart();
124 } elseif (!processing_active()) {
125         /* This page can only be called with a delivery for invoicing or invoice no for edit */
126         display_error(_("This page can only be opened after delivery selection. Please select delivery to invoicing first."));
127
128         hyperlink_no_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Delivery to Invoice"));
129
130         end_page();
131         exit;
132 } else {
133         foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
134                 if (isset($_POST['Line'.$line_no])) {
135                         $line_qty = $_POST['Line'.$line_no];
136                         if (is_numeric($line_qty) && $_POST['Line'.$line_no] <= ($itm->quantity - $itm->qty_done)) {
137                                 $_SESSION['Items']->line_items[$line_no]->qty_dispatched = $line_qty;
138                         }
139                 }
140
141                 if (isset($_POST['Line'.$line_no.'Desc'])) {
142                         $line_desc = $_POST['Line'.$line_no.'Desc'];
143                         if (strlen($line_desc) > 0) {
144                                 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
145                         }
146                 }
147         }
148 }
149 //-----------------------------------------------------------------------------
150
151 function copy_to_cart()
152 {
153         $cart = &$_SESSION['Items'];
154         $cart->ship_via = $_POST['ship_via'];
155         $cart->freight_cost = $_POST['ChargeFreightCost'];
156         $cart->document_date =  $_POST['InvoiceDate'];
157         $cart->due_date =  $_POST['due_date'];
158         $cart->Comments = $_POST['Comments'];
159 }
160 //-----------------------------------------------------------------------------
161
162 function copy_from_cart()
163 {
164         $cart = &$_SESSION['Items'];
165         $_POST['ship_via'] = $cart->ship_via;
166         $_POST['ChargeFreightCost'] = $cart->freight_cost;
167         $_POST['InvoiceDate']= $cart->document_date;
168         $_POST['due_date'] = $cart->due_date;
169         $_POST['Comments']= $cart->Comments;
170 }
171
172 //-----------------------------------------------------------------------------
173
174 function check_data()
175 {
176         if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
177                 display_error(_("The entered invoice date is invalid."));
178                 return false;
179         }
180
181         if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
182                 display_error(_("The entered invoice date is not in fiscal year."));
183                 return false;
184         }
185
186         if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
187                 display_error(_("The entered invoice due date is invalid."));
188                 return false;
189         }
190
191         if ($_SESSION['Items']->trans_no == 0) {
192                 if (!references::is_valid($_POST['ref'])) {
193                         display_error(_("You must enter a reference."));
194                         return false;
195                 }
196
197                 if (!is_new_reference($_POST['ref'], 10)) {
198                         display_error(_("The entered reference is already in use."));
199                         return false;
200                 }
201         }
202
203         if ($_POST['ChargeFreightCost'] == "") {
204                 $_POST['ChargeFreightCost'] = 0;
205         }
206
207         if (!is_numeric($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] < 0) {
208                 display_error(_("The entered shipping value is not numeric."));
209                 return false;
210         }
211
212         if ($_SESSION['Items']->has_items_dispatch() == 0 && $_POST['ChargeFreightCost'] == 0) {
213                 display_error(_("There are no item quantities on this invoice."));
214                 return false;
215         }
216
217         return true;
218 }
219
220 //-----------------------------------------------------------------------------
221 if (isset($_POST['process_invoice']) && check_data()) {
222
223         $newinvoice=  $_SESSION['Items']->trans_no == 0;
224         copy_to_cart();
225         $invoice_no = $_SESSION['Items']->write();
226
227         processing_end();
228         if ($newinvoice) {
229                 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
230         } else {
231                 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
232         }
233 }
234
235 // find delivery spans for batch invoice display
236 $dspans = array();
237 $lastdn = ''; $spanlen=1;
238
239 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
240         $line = $_SESSION['Items']->line_items[$line_no];
241         if ($line->quantity == $line->qty_done) {
242                 continue;
243         }
244         if ($line->src_no == $lastdn) {
245                 $spanlen++;
246         } else {
247                 if ($lastdn != '') {
248                         $dspans[] = $spanlen;
249                         $spanlen = 1;
250                 }
251         }
252         $lastdn = $line->src_no;
253 }
254 $dspans[] = $spanlen;
255
256 //-----------------------------------------------------------------------------
257
258 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
259 $is_edition = $_SESSION['Items']->trans_type == 10 && $_SESSION['Items']->trans_no != 0;
260 start_form(false, true);
261
262 start_table("$table_style2 width=80%", 5);
263
264 start_row();
265 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
266 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
267 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
268 end_row();
269 start_row();
270
271 if ($_SESSION['Items']->trans_no == 0) {
272         ref_cells(_("Reference"), 'ref', $_SESSION['Items']->reference, "class='tableheader2'");
273 } else {
274         label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
275 }
276
277 label_cells(_("Delivery Notes:"),
278 get_customer_trans_view_str(systypes::cust_dispatch(), array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
279
280 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
281
282 end_row();
283 start_row();
284
285 if (!isset($_POST['ship_via'])) {
286         $_POST['ship_via'] = $_SESSION['Items']->ship_via;
287 }
288 label_cell(_("Shipping Company"), "class='tableheader2'");
289 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
290
291 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
292         $_POST['InvoiceDate'] = Today();
293         if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
294                 $_POST['InvoiceDate'] = end_fiscalyear();
295         }
296 }
297
298 date_cells(_("Date"), 'InvoiceDate', $_POST['InvoiceDate'], 0, 0, 0, "class='tableheader'");
299
300 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
301         $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, $_POST['InvoiceDate']);
302 }
303
304 date_cells(_("Due Date"), 'due_date', $_POST['due_date'], 0, 0, 0, "class='tableheader'");
305
306 end_row();
307 end_table();
308
309 display_heading(_("Invoice Items"));
310
311 start_table("$table_style width=80%");
312 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
313         _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
314
315 if ($is_batch_invoice) {
316 $th[] = _("DN");
317 $th[] = "";
318 }
319
320 if ($is_edition) {
321 $th[4] = _("Credited");
322 }
323
324 table_header($th);
325 $k = 0;
326 $has_marked = false;
327 $show_qoh = true;
328
329 $dn_line_cnt = 0;
330
331 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
332         if ($ln_itm->quantity == $ln_itm->qty_done) {
333                 continue; // this line was fully invoiced
334         }
335         alt_table_row_color($k);
336         view_stock_status_cell($ln_itm->stock_id);
337
338         text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
339         qty_cell($ln_itm->quantity);
340         label_cell($ln_itm->units);
341         qty_cell($ln_itm->qty_done);
342
343         if ($is_batch_invoice) {
344                 // for batch invoices we can only remove whole deliveries
345                 echo '<td nowrap align=right>';
346                 hidden('Line' . $line, $ln_itm->qty_dispatched );
347                 echo number_format2($ln_itm->qty_dispatched, user_qty_dec()).'</td>';
348         } else {
349                 text_cells(null, 'Line'.$line, $ln_itm->qty_dispatched, 10, 10);
350         }
351         $display_discount_percent = number_format2($ln_itm->discount_percent*100, user_percent_dec()) . "%";
352
353         $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
354
355         amount_cell($ln_itm->price);
356         label_cell($ln_itm->tax_type_name);
357         label_cell($display_discount_percent, "nowrap align=right");
358         amount_cell($line_total);
359
360         if ($is_batch_invoice) {
361                 if ($dn_line_cnt == 0) {
362                         $dn_line_cnt = $dspans[0];
363                         $dspans = array_slice($dspans, 1);
364                         label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
365                         label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
366                                 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
367                 }
368                 $dn_line_cnt--;
369         }
370         end_row();
371 }
372
373 /*Don't re-calculate freight if some of the order has already been delivered -
374 depending on the business logic required this condition may not be required.
375 It seems unfair to charge the customer twice for freight if the order
376 was not fully delivered the first time ?? */
377
378 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
379         if ($_SESSION['Items']->any_already_delivered() == 1) {
380                 $_POST['ChargeFreightCost'] = 0;
381         } else {
382                 $_POST['ChargeFreightCost'] = $_SESSION['Items']->freight_cost;
383         }
384
385         if (!is_numeric($_POST['ChargeFreightCost'])) {
386                 $_POST['ChargeFreightCost'] = 0;
387         }
388 }
389
390 start_row();
391
392 small_amount_cells(_("Shipping Cost"), 'ChargeFreightCost', null, "colspan=9 align=right");
393 if ($is_batch_invoice) {
394 label_cell('', 'colspan=2');
395 }
396
397 end_row();
398 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
399
400 $display_sub_total = number_format2($inv_items_total + $_POST['ChargeFreightCost'],user_price_dec());
401
402 label_row(_("Sub-total"), $display_sub_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
403
404 $taxes = $_SESSION['Items']->get_taxes($_POST['ChargeFreightCost']);
405 $tax_total = display_edit_tax_items($taxes, 9, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
406
407 $display_total = number_format2(($inv_items_total + $_POST['ChargeFreightCost'] + $tax_total), user_price_dec());
408
409 label_row(_("Invoice Total"), $display_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
410
411 end_table(1);
412
413 start_table($table_style2);
414
415 textarea_row(_("Memo"), 'Comments', null, 50, 4);
416
417 end_table(1);
418
419 submit_center_first('Update', _("Update"));
420 submit_center_last('process_invoice', _("Process Invoice"));
421
422 end_form();
423
424 end_page();
425
426 ?>