2 //---------------------------------------------------------------------------
4 // Entry/Modify Sales Invoice against single delivery
5 // Entry/Modify Batch Sales Invoice against batch of deliveries
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");
19 if ($use_popup_windows) {
20 $js .= get_js_open_window(900, 500);
22 if ($use_date_picker) {
23 $js .= get_js_date_picker();
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");
35 page($_SESSION['page_title'], false, false, "", $js);
37 //-----------------------------------------------------------------------------
38 check_edit_conflicts();
40 if (isset($_GET['AddedID'])) {
42 $invoice_no = $_GET['AddedID'];
45 display_notification(_("Selected deliveries has been processed"), true);
47 display_note(get_customer_trans_view_str($trans_type, $invoice_no, _("&View This Invoice")), 0, 1);
49 display_note(print_document_link($invoice_no, _("&Print This Invoice"), true, 10));
51 display_note(get_gl_view_str($trans_type, $invoice_no, _("View the GL &Journal Entries for this Invoice")),1);
53 hyperlink_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Another &Delivery For Invoicing"), "OutstandingOnly=1");
55 display_footer_exit();
57 } elseif (isset($_GET['UpdatedID'])) {
59 $invoice_no = $_GET['UpdatedID'];
61 display_notification_centered(sprintf(_('Sales Invoice # %d has been updated.'),$invoice_no));
63 display_note(get_trans_view_str(10, $invoice_no, _("&View This Invoice")));
65 display_note(print_document_link($invoice_no, _("&Print This Invoice"), true, 10));
67 hyperlink_no_params($path_to_root . "/sales/inquiry/customer_inquiry.php", _("Select A Different &Invoice to Modify"));
69 display_footer_exit();
71 } elseif (isset($_GET['RemoveDN'])) {
73 for($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
74 $line = &$_SESSION['Items']->line_items[$line_no];
75 if ($line->src_no == $_GET['RemoveDN']) {
76 $line->quantity = $line->qty_done;
77 $line->qty_dispatched=0;
82 // Remove also src_doc delivery note
83 $sources = &$_SESSION['Items']->src_docs;
84 unset($sources[$_GET['RemoveDN']]);
87 //-----------------------------------------------------------------------------
89 if ( (isset($_GET['DeliveryNumber']) && ($_GET['DeliveryNumber'] > 0) )
90 || isset($_GET['BatchInvoice'])) {
94 if (isset($_GET['BatchInvoice'])) {
95 $src = $_SESSION['DeliveryBatch'];
96 unset($_SESSION['DeliveryBatch']);
98 $src = array($_GET['DeliveryNumber']);
100 /*read in all the selected deliveries into the Items cart */
101 $dn = new Cart(13, $src, true);
103 if ($dn->count_items() == 0) {
104 hyperlink_params($path_to_root . "/sales/inquiry/sales_deliveries_view.php",
105 _("Select a different delivery to invoice"), "OutstandingOnly=1");
106 die ("<br><b>" . _("There are no delivered items with a quantity left to invoice. There is nothing left to invoice.") . "</b>");
109 $dn->trans_type = 10;
110 $dn->src_docs = $dn->trans_no;
112 $dn->reference = references::get_next(10);
113 $dn->due_date = get_invoice_duedate($dn->customer_id, $dn->document_date);
115 $_SESSION['Items'] = $dn;
118 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
120 if ( get_parent_trans(10, $_GET['ModifyInvoice']) == 0) { // 1.xx compatibility hack
121 echo"<center><br><b>" . _("There in no delivery notes for this invoice.<br>
122 Most likely this invoice was created in Front Accounting version prior to 2.0
123 and therefore can not be modified.") . "</b></center>";
124 display_footer_exit();
127 $_SESSION['Items'] = new Cart(10, $_GET['ModifyInvoice']);
129 if ($_SESSION['Items']->count_items() == 0) {
130 echo"<center><br><b>" . _("All quantities on this invoice has been credited. There is nothing to modify on this invoice") . "</b></center>";
131 display_footer_exit();
134 } elseif (!processing_active()) {
135 /* This page can only be called with a delivery for invoicing or invoice no for edit */
136 display_error(_("This page can only be opened after delivery selection. Please select delivery to invoicing first."));
138 hyperlink_no_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Delivery to Invoice"));
142 } elseif (!check_quantities()) {
143 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
145 if (isset($_POST['Update'])) {
146 $Ajax->activate('Items');
148 if (isset($_POST['_InvoiceDate_changed'])) {
149 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id,
150 $_POST['InvoiceDate']);
151 $Ajax->activate('due_date');
154 //-----------------------------------------------------------------------------
155 function check_quantities()
158 foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
159 if (isset($_POST['Line'.$line_no])) {
160 if($_SESSION['Items']->trans_no) {
161 $min = $itm->qty_done;
162 $max = $itm->quantity;
165 $max = $itm->quantity - $itm->qty_done;
167 if (check_num('Line'.$line_no, $min, $max)) {
168 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
169 input_num('Line'.$line_no);
177 if (isset($_POST['Line'.$line_no.'Desc'])) {
178 $line_desc = $_POST['Line'.$line_no.'Desc'];
179 if (strlen($line_desc) > 0) {
180 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
187 function set_delivery_shipping_sum($delivery_notes)
192 foreach($delivery_notes as $delivery_num)
194 $myrow = get_customer_trans($delivery_num, 13);
195 //$branch = get_branch($myrow["branch_code"]);
196 //$sales_order = get_sales_order_header($myrow["order_"]);
198 //$shipping += $sales_order['freight_cost'];
199 $shipping += $myrow['ov_freight'];
201 $_POST['ChargeFreightCost'] = price_format($shipping);
205 function copy_to_cart()
207 $cart = &$_SESSION['Items'];
208 $cart->ship_via = $_POST['ship_via'];
209 $cart->freight_cost = input_num('ChargeFreightCost');
210 $cart->document_date = $_POST['InvoiceDate'];
211 $cart->due_date = $_POST['due_date'];
212 $cart->Comments = $_POST['Comments'];
214 //-----------------------------------------------------------------------------
216 function copy_from_cart()
218 $cart = &$_SESSION['Items'];
219 $_POST['ship_via'] = $cart->ship_via;
220 $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
221 $_POST['InvoiceDate']= $cart->document_date;
222 $_POST['due_date'] = $cart->due_date;
223 $_POST['Comments']= $cart->Comments;
224 $_POST['cart_id'] = $cart->cart_id;
227 //-----------------------------------------------------------------------------
229 function check_data()
231 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
232 display_error(_("The entered invoice date is invalid."));
233 set_focus('InvoiceDate');
237 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
238 display_error(_("The entered invoice date is not in fiscal year."));
239 set_focus('InvoiceDate');
243 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
244 display_error(_("The entered invoice due date is invalid."));
245 set_focus('due_date');
249 if ($_SESSION['Items']->trans_no == 0) {
250 if (!references::is_valid($_POST['ref'])) {
251 display_error(_("You must enter a reference."));
256 if (!is_new_reference($_POST['ref'], 10)) {
257 display_error(_("The entered reference is already in use."));
263 if ($_POST['ChargeFreightCost'] == "") {
264 $_POST['ChargeFreightCost'] = price_format(0);
267 if (!check_num('ChargeFreightCost', 0)) {
268 display_error(_("The entered shipping value is not numeric."));
269 set_focus('ChargeFreightCost');
273 if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
274 display_error(_("There are no item quantities on this invoice."));
278 if (!check_quantities()) {
279 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
286 //-----------------------------------------------------------------------------
287 if (isset($_POST['process_invoice']) && check_data()) {
289 $newinvoice= $_SESSION['Items']->trans_no == 0;
291 $invoice_no = $_SESSION['Items']->write();
295 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
297 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
301 // find delivery spans for batch invoice display
303 $lastdn = ''; $spanlen=1;
305 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
306 $line = $_SESSION['Items']->line_items[$line_no];
307 if ($line->quantity == $line->qty_done) {
310 if ($line->src_no == $lastdn) {
314 $dspans[] = $spanlen;
318 $lastdn = $line->src_no;
320 $dspans[] = $spanlen;
322 //-----------------------------------------------------------------------------
324 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
326 $is_edition = $_SESSION['Items']->trans_type == 10 && $_SESSION['Items']->trans_no != 0;
327 start_form(false, true);
330 start_table("$table_style2 width=80%", 5);
333 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
334 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
335 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
339 if ($_SESSION['Items']->trans_no == 0) {
340 ref_cells(_("Reference"), 'ref', '', $_SESSION['Items']->reference, "class='tableheader2'");
342 label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
345 label_cells(_("Delivery Notes:"),
346 get_customer_trans_view_str(systypes::cust_dispatch(), array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
348 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
353 if (!isset($_POST['ship_via'])) {
354 $_POST['ship_via'] = $_SESSION['Items']->ship_via;
356 label_cell(_("Shipping Company"), "class='tableheader2'");
357 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
359 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
360 $_POST['InvoiceDate'] = Today();
361 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
362 $_POST['InvoiceDate'] = end_fiscalyear();
366 date_cells(_("Date"), 'InvoiceDate', '', $_POST['InvoiceDate'], 0, 0, 0, "class='tableheader2'", true);
368 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
369 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, $_POST['InvoiceDate']);
372 date_cells(_("Due Date"), 'due_date', '', $_POST['due_date'], 0, 0, 0, "class='tableheader2'");
377 display_heading(_("Invoice Items"));
380 start_table("$table_style width=80%");
381 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
382 _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
384 if ($is_batch_invoice) {
390 $th[4] = _("Credited");
400 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
401 if ($ln_itm->quantity == $ln_itm->qty_done) {
402 continue; // this line was fully invoiced
404 alt_table_row_color($k);
405 view_stock_status_cell($ln_itm->stock_id);
407 text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
408 $dec = get_qty_dec($ln_itm->stock_id);
409 qty_cell($ln_itm->quantity, false, $dec);
410 label_cell($ln_itm->units);
411 qty_cell($ln_itm->qty_done, false, $dec);
413 if ($is_batch_invoice) {
414 // for batch invoices we can only remove whole deliveries
415 echo '<td nowrap align=right>';
416 hidden('Line' . $line, $ln_itm->qty_dispatched );
417 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
419 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
421 $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
423 $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
425 amount_cell($ln_itm->price);
426 label_cell($ln_itm->tax_type_name);
427 label_cell($display_discount_percent, "nowrap align=right");
428 amount_cell($line_total);
430 if ($is_batch_invoice) {
431 if ($dn_line_cnt == 0) {
432 $dn_line_cnt = $dspans[0];
433 $dspans = array_slice($dspans, 1);
434 label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
435 label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
436 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
443 /*Don't re-calculate freight if some of the order has already been delivered -
444 depending on the business logic required this condition may not be required.
445 It seems unfair to charge the customer twice for freight if the order
446 was not fully delivered the first time ?? */
448 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
449 if ($_SESSION['Items']->any_already_delivered() == 1) {
450 $_POST['ChargeFreightCost'] = price_format(0);
452 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
455 if (!check_num('ChargeFreightCost')) {
456 $_POST['ChargeFreightCost'] = price_format(0);
460 $accumulate_shipping = get_company_pref('accumulate_shipping');
461 if ($is_batch_invoice && $accumulate_shipping)
462 set_delivery_shipping_sum(array_keys($_SESSION['Items']->src_docs));
466 small_amount_cells(_("Shipping Cost"), 'ChargeFreightCost', null, "colspan=9 align=right");
467 if ($is_batch_invoice) {
468 label_cell('', 'colspan=2');
472 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
474 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
476 label_row(_("Sub-total"), $display_sub_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
478 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
479 $tax_total = display_edit_tax_items($taxes, 9, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
481 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
483 label_row(_("Invoice Total"), $display_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
488 start_table($table_style2);
489 textarea_row(_("Memo"), 'Comments', null, 50, 4);
493 submit_center_first('Update', _("Update"),
494 _('Refresh document page'), true);
495 submit_center_last('process_invoice', _("Process Invoice"),
496 _('Check entered data and save document'), true);