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