Fixed printing api.
[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
44         display_notification(_("Selected deliveries has been processed"), true);
45
46         display_note(get_customer_trans_view_str($trans_type, $invoice_no, _("View This Invoice")), 0, 1);
47
48         display_note(print_document_link($invoice_no, _("Print This Invoice"), true, 10));
49
50         display_note(get_gl_view_str($trans_type, $invoice_no, _("View the GL Journal Entries for this Invoice")),1);
51
52         hyperlink_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Another Delivery For Invoicing"), "OutstandingOnly=1");
53
54         display_footer_exit();
55
56 } elseif (isset($_GET['UpdatedID']))  {
57
58         $invoice_no = $_GET['UpdatedID'];
59
60         display_notification_centered(sprintf(_('Sales Invoice # %d has been updated.'),$invoice_no));
61
62         display_note(get_trans_view_str(10, $invoice_no, _("View This Invoice")));
63         echo '<br>';
64         display_note(print_document_link($invoice_no, _("Print This Invoice"), true, 10));
65
66         hyperlink_no_params($path_to_root . "/sales/inquiry/customer_inquiry.php", _("Select A Different Invoice to Modify"));
67
68         display_footer_exit();
69
70 } elseif (isset($_GET['RemoveDN'])) {
71
72         for($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
73                 $line = &$_SESSION['Items']->line_items[$line_no];
74                 if ($line->src_no == $_GET['RemoveDN']) {
75                         $line->quantity = $line->qty_done;
76                         $line->qty_dispatched=0;
77                 }
78         }
79         unset($line);
80 }
81
82 //-----------------------------------------------------------------------------
83
84 if ( (isset($_GET['DeliveryNumber']) && ($_GET['DeliveryNumber'] > 0) )
85         || isset($_GET['BatchInvoice'])) {
86
87         processing_start();
88
89         if (isset($_GET['BatchInvoice'])) {
90                 $src = $_SESSION['DeliveryBatch'];
91                 unset($_SESSION['DeliveryBatch']);
92         } else {
93                 $src = array($_GET['DeliveryNumber']);
94         }
95         /*read in all the selected deliveries into the Items cart  */
96         $dn = new Cart(13, $src, true);
97
98         if ($dn->count_items() == 0) {
99                 hyperlink_params($path_to_root . "/sales/inquiry/sales_deliveries_view.php",
100                         _("Select a different delivery to invoice"), "OutstandingOnly=1");
101                 die ("<br><b>" . _("There are no delivered items with a quantity left to invoice. There is nothing left to invoice.") . "</b>");
102         }
103
104         $dn->trans_type = 10;
105         $dn->src_docs = $dn->trans_no;
106         $dn->trans_no = 0;
107         $dn->reference = references::get_next(10);
108         $dn->due_date = get_invoice_duedate($dn->customer_id, $dn->document_date);
109
110         $_SESSION['Items'] = $dn;
111         copy_from_cart();
112
113 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
114
115         if ( get_parent_trans(10, $_GET['ModifyInvoice']) == 0) { // 1.xx compatibility hack
116                 echo"<center><br><b>" . _("There in no delivery notes for this invoice.<br>
117                 Most likely this invoice was created in Front Accounting version prior to 2.0
118                 and therefore can not be modified.") . "</b></center>";
119                 display_footer_exit();
120         }
121         processing_start();
122         $_SESSION['Items'] = new Cart(10, $_GET['ModifyInvoice']);
123
124         if ($_SESSION['Items']->count_items() == 0) {
125                 echo"<center><br><b>" . _("All quantities on this invoice has been credited. There is nothing to modify on this invoice") . "</b></center>";
126                 display_footer_exit();
127         }
128         copy_from_cart();
129 } elseif (!processing_active()) {
130         /* This page can only be called with a delivery for invoicing or invoice no for edit */
131         display_error(_("This page can only be opened after delivery selection. Please select delivery to invoicing first."));
132
133         hyperlink_no_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Delivery to Invoice"));
134
135         end_page();
136         exit;
137 } elseif (!check_quantities()) {
138         display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
139 }
140 if (isset($_POST['Update'])) {
141         $Ajax->activate('Items');
142 }
143 if (isset($_POST['_InvoiceDate_changed'])) {
144         $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, 
145                 $_POST['InvoiceDate']);
146         $Ajax->activate('due_date');
147 }
148 //-----------------------------------------------------------------------------
149 function check_quantities()
150 {
151         $ok =1;
152         foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
153                 if (isset($_POST['Line'.$line_no])) {
154                         if($_SESSION['Items']->trans_no) {
155                                 $min = $itm->qty_done;
156                                 $max = $itm->quantity;
157                         } else {
158                                 $min = 0;
159                                 $max = $itm->quantity - $itm->qty_done;
160                         }
161                         if (check_num('Line'.$line_no, $min, $max)) {
162                                 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
163                                     input_num('Line'.$line_no);
164                         }
165                         else {
166                                 $ok = 0;
167                         }
168                                 
169                 }
170
171                 if (isset($_POST['Line'.$line_no.'Desc'])) {
172                         $line_desc = $_POST['Line'.$line_no.'Desc'];
173                         if (strlen($line_desc) > 0) {
174                                 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
175                         }
176                 }
177         }
178  return $ok;
179 }
180
181 function copy_to_cart()
182 {
183         $cart = &$_SESSION['Items'];
184         $cart->ship_via = $_POST['ship_via'];
185         $cart->freight_cost = input_num('ChargeFreightCost');
186         $cart->document_date =  $_POST['InvoiceDate'];
187         $cart->due_date =  $_POST['due_date'];
188         $cart->Comments = $_POST['Comments'];
189 }
190 //-----------------------------------------------------------------------------
191
192 function copy_from_cart()
193 {
194         $cart = &$_SESSION['Items'];
195         $_POST['ship_via'] = $cart->ship_via;
196         $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
197         $_POST['InvoiceDate']= $cart->document_date;
198         $_POST['due_date'] = $cart->due_date;
199         $_POST['Comments']= $cart->Comments;
200 }
201
202 //-----------------------------------------------------------------------------
203
204 function check_data()
205 {
206         if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
207                 display_error(_("The entered invoice date is invalid."));
208                 set_focus('InvoiceDate');
209                 return false;
210         }
211
212         if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
213                 display_error(_("The entered invoice date is not in fiscal year."));
214                 set_focus('InvoiceDate');
215                 return false;
216         }
217
218         if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
219                 display_error(_("The entered invoice due date is invalid."));
220                 set_focus('due_date');
221                 return false;
222         }
223
224         if ($_SESSION['Items']->trans_no == 0) {
225                 if (!references::is_valid($_POST['ref'])) {
226                         display_error(_("You must enter a reference."));
227                         set_focus('ref');
228                         return false;
229                 }
230
231                 if (!is_new_reference($_POST['ref'], 10)) {
232                         display_error(_("The entered reference is already in use."));
233                         set_focus('ref');
234                         return false;
235                 }
236         }
237
238         if ($_POST['ChargeFreightCost'] == "") {
239                 $_POST['ChargeFreightCost'] = price_format(0);
240         }
241
242         if (!check_num('ChargeFreightCost', 0)) {
243                 display_error(_("The entered shipping value is not numeric."));
244                 set_focus('ChargeFreightCost');
245                 return false;
246         }
247
248         if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
249                 display_error(_("There are no item quantities on this invoice."));
250                 return false;
251         }
252
253         if (!check_quantities()) {
254                 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
255                 return false;
256         }
257
258         return true;
259 }
260
261 //-----------------------------------------------------------------------------
262 if (isset($_POST['process_invoice']) && check_data()) {
263
264         $newinvoice=  $_SESSION['Items']->trans_no == 0;
265         copy_to_cart();
266         $invoice_no = $_SESSION['Items']->write();
267
268         processing_end();
269         if ($newinvoice) {
270                 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
271         } else {
272                 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
273         }
274 }
275
276 // find delivery spans for batch invoice display
277 $dspans = array();
278 $lastdn = ''; $spanlen=1;
279
280 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
281         $line = $_SESSION['Items']->line_items[$line_no];
282         if ($line->quantity == $line->qty_done) {
283                 continue;
284         }
285         if ($line->src_no == $lastdn) {
286                 $spanlen++;
287         } else {
288                 if ($lastdn != '') {
289                         $dspans[] = $spanlen;
290                         $spanlen = 1;
291                 }
292         }
293         $lastdn = $line->src_no;
294 }
295 $dspans[] = $spanlen;
296
297 //-----------------------------------------------------------------------------
298
299 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
300 $is_edition = $_SESSION['Items']->trans_type == 10 && $_SESSION['Items']->trans_no != 0;
301 start_form(false, true);
302
303 start_table("$table_style2 width=80%", 5);
304
305 start_row();
306 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
307 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
308 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
309 end_row();
310 start_row();
311
312 if ($_SESSION['Items']->trans_no == 0) {
313         ref_cells(_("Reference"), 'ref', '', $_SESSION['Items']->reference, "class='tableheader2'");
314 } else {
315         label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
316 }
317
318 label_cells(_("Delivery Notes:"),
319 get_customer_trans_view_str(systypes::cust_dispatch(), array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
320
321 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
322
323 end_row();
324 start_row();
325
326 if (!isset($_POST['ship_via'])) {
327         $_POST['ship_via'] = $_SESSION['Items']->ship_via;
328 }
329 label_cell(_("Shipping Company"), "class='tableheader2'");
330 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
331
332 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
333         $_POST['InvoiceDate'] = Today();
334         if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
335                 $_POST['InvoiceDate'] = end_fiscalyear();
336         }
337 }
338
339 date_cells(_("Date"), 'InvoiceDate', '', $_POST['InvoiceDate'], 0, 0, 0, "class='tableheader2'", true);
340
341 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
342         $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, $_POST['InvoiceDate']);
343 }
344
345 date_cells(_("Due Date"), 'due_date', '', $_POST['due_date'], 0, 0, 0, "class='tableheader2'");
346
347 end_row();
348 end_table();
349
350 display_heading(_("Invoice Items"));
351
352 div_start('Items');
353 start_table("$table_style width=80%");
354 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
355         _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
356
357 if ($is_batch_invoice) {
358     $th[] = _("DN");
359     $th[] = "";
360 }
361
362 if ($is_edition) {
363     $th[4] = _("Credited");
364 }
365
366 table_header($th);
367 $k = 0;
368 $has_marked = false;
369 $show_qoh = true;
370
371 $dn_line_cnt = 0;
372
373 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
374         if ($ln_itm->quantity == $ln_itm->qty_done) {
375                 continue; // this line was fully invoiced
376         }
377         alt_table_row_color($k);
378         view_stock_status_cell($ln_itm->stock_id);
379
380         text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
381         $dec = get_qty_dec($ln_itm->stock_id);
382         qty_cell($ln_itm->quantity, false, $dec);
383         label_cell($ln_itm->units);
384         qty_cell($ln_itm->qty_done, false, $dec);
385
386         if ($is_batch_invoice) {
387                 // for batch invoices we can only remove whole deliveries
388                 echo '<td nowrap align=right>';
389                 hidden('Line' . $line, $ln_itm->qty_dispatched );
390                 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
391         } else {
392                 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
393         }
394         $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
395
396         $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
397
398         amount_cell($ln_itm->price);
399         label_cell($ln_itm->tax_type_name);
400         label_cell($display_discount_percent, "nowrap align=right");
401         amount_cell($line_total);
402
403         if ($is_batch_invoice) {
404                 if ($dn_line_cnt == 0) {
405                         $dn_line_cnt = $dspans[0];
406                         $dspans = array_slice($dspans, 1);
407                         label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
408                         label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
409                                 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
410                 }
411                 $dn_line_cnt--;
412         }
413         end_row();
414 }
415
416 /*Don't re-calculate freight if some of the order has already been delivered -
417 depending on the business logic required this condition may not be required.
418 It seems unfair to charge the customer twice for freight if the order
419 was not fully delivered the first time ?? */
420
421 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
422         if ($_SESSION['Items']->any_already_delivered() == 1) {
423                 $_POST['ChargeFreightCost'] = price_format(0);
424         } else {
425                 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
426         }
427
428         if (!check_num('ChargeFreightCost')) {
429                 $_POST['ChargeFreightCost'] = price_format(0);
430         }
431 }
432
433 start_row();
434
435 small_amount_cells(_("Shipping Cost"), 'ChargeFreightCost', null, "colspan=9 align=right");
436 if ($is_batch_invoice) {
437 label_cell('', 'colspan=2');
438 }
439
440 end_row();
441 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
442
443 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
444
445 label_row(_("Sub-total"), $display_sub_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
446
447 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
448 $tax_total = display_edit_tax_items($taxes, 9, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
449
450 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
451
452 label_row(_("Invoice Total"), $display_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
453
454 end_table(1);
455 div_end();
456
457 start_table($table_style2);
458 textarea_row(_("Memo"), 'Comments', null, 50, 4);
459
460 end_table(1);
461
462 submit_center_first('Update', _("Update"),
463   _('Refresh document page'), true);
464 submit_center_last('process_invoice', _("Process Invoice"),
465   _('Check entered data and save document'), true);
466
467 end_form();
468
469 end_page();
470
471 ?>