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