5 include_once($path_to_root . "/sales/includes/cart_class.inc");
6 include_once($path_to_root . "/includes/session.inc");
8 include_once($path_to_root . "/includes/data_checks.inc");
10 include_once($path_to_root . "/includes/manufacturing.inc");
11 include_once($path_to_root . "/sales/includes/sales_db.inc");
12 include_once($path_to_root . "/sales/includes/sales_ui.inc");
14 include_once($path_to_root . "/taxes/tax_calc.inc");
17 if ($use_popup_windows)
18 $js .= get_js_open_window(900, 500);
20 $js .= get_js_date_picker();
21 if ($_SESSION['Items']->direct_invoice)
22 page(_("Issue an Invoice"), false, false, "", $js);
24 page(_("Issue an Invoice and Deliver Items for a Sales Order"), false, false, "", $js);
26 //---------------------------------------------------------------------------------------------------------------
28 if (isset($_GET['AddedID']))
30 $invoice_no = $_GET['AddedID'];
33 display_notification(_("Invoice processed"), true);
34 display_note(get_customer_trans_view_str($trans_type, $invoice_no, _("View this invoice")), 0, 1);
36 display_note(get_gl_view_str($trans_type, $invoice_no, _("View the GL Journal Entries for this Invoice")));
38 if ($_SESSION['Items']->direct_invoice)
39 hyperlink_params("$path_to_root/sales/sales_order_entry.php", _("Issue Another Invoice"), "NewInvoice=Yes");
41 hyperlink_params("$path_to_root/sales/inquiry/sales_orders_view.php", _("Select Another Order For Invoicing"), "OutstandingOnly=1");
43 unset($_SESSION['Items']->line_items);
44 unset($_SESSION['Items']);
45 display_footer_exit();
48 //---------------------------------------------------------------------------------------------------------------
50 if (!isset($_GET['OrderNumber']) && !isset($_SESSION['ProcessingOrder']) &&
51 !isset($_GET['process_invoice']))
53 /* This page can only be called with an order number for invoicing*/
54 display_error(_("This page can only be opened if an order has been selected. Please select an order first."));
56 hyperlink_no_params("$path_to_root/sales/inquiry/sales_orders_view.php", _("Select a sales order to invoice"));
62 elseif (isset($_GET['OrderNumber']) && $_GET['OrderNumber'] > 0)
65 if (isset($_SESSION['Items']))
67 unset($_SESSION['Items']->line_items);
68 unset ($_SESSION['Items']);
71 session_register("Items");
72 session_register("ProcessingOrder");
74 $_SESSION['ProcessingOrder'] = $_GET['OrderNumber'];
75 $_SESSION['Items'] = new cart;
77 /*read in all the selected order into the Items cart */
79 if (read_sales_order($_SESSION['ProcessingOrder'], $_SESSION['Items'], true))
82 if ($_SESSION['Items']->count_items() == 0)
84 hyperlink_params($path_to_root . "/sales/inquiry/sales_orders_view.php", _("Select a different sales order to invoice"), "OutstandingOnly=1");
85 die ("<br><b>" . _("There are no ordered items with a quantity left to deliver. There is nothing left to invoice.") . "</b>");
90 hyperlink_no_params("/sales_orders_view.php", _("Select a sales order to invoice"));
91 die ("<br><b>" . _("This order item could not be retrieved. Please select another order.") . "</b>");
97 /* if processing, a dispatch page has been called and ${$StkItm->stock_id} would have been set from the post */
98 foreach ($_SESSION['Items']->line_items as $itm)
101 if (isset($_POST[$itm->stock_id]) && is_numeric($_POST[$itm->stock_id]) &&
102 $_POST[$itm->stock_id] <= ($_SESSION['Items']->line_items[$itm->line_no]->quantity -
103 $_SESSION['Items']->line_items[$itm->line_no]->qty_inv))
105 $_SESSION['Items']->line_items[$itm->line_no]->qty_dispatched = $_POST[$itm->stock_id];
108 if (isset($_POST[$itm->stock_id . "Desc"]) && strlen($_POST[$itm->stock_id . "Desc"]) > 0)
110 $_SESSION['Items']->line_items[$itm->line_no]->item_description = $_POST[$itm->stock_id . "Desc"];
115 //---------------------------------------------------------------------------------------------------------------
117 function order_changed_error()
119 global $path_to_root;
120 display_note(_("This order has been changed or invoiced since this delivery was started to be confirmed. Processing halted."), 1, 0);
121 display_note(_("To enter and confirm this dispatch/invoice the order must be re-selected and re-read again to update the changes made by the other user."), 1, 0);
123 hyperlink_no_params("$path_to_root/sales/inquiry/sales_orders_view.php", _("Select a sales order for confirming deliveries and invoicing"));
125 unset($_SESSION['Items']->line_items);
126 unset($_SESSION['Items']);
127 unset($_SESSION['ProcessingOrder']);
131 //---------------------------------------------------------------------------------------------------------------
133 function check_order_changed()
137 /*Now need to check that the order details are the same as they were when
138 they were read into the Items array.
139 If they've changed then someone else may have invoiced them -
140 as modified for bug pointed out by Sherif 1-7-03*/
142 $sql = "SELECT stk_code, quantity, qty_invoiced FROM ".TB_PREF."sales_order_details WHERE
143 quantity - qty_invoiced > 0
144 AND order_no = " . $_SESSION['ProcessingOrder'];
146 $result = db_query($sql,"retreive sales order details");
148 if (db_num_rows($result) != count($_SESSION['Items']->line_items))
151 /*there should be the same number of items returned from this query as there are lines on the invoice -
152 if not then someone has already invoiced or credited some lines */
155 display_note($sql, 1, 0);
156 display_note("No rows returned by sql:" . db_num_rows($result), 1, 0);
157 display_note("Count of items in the session " . count($_SESSION['Items']->line_items), 1, 0);
163 while ($myrow = db_fetch($result))
165 foreach($_SESSION['Items']->line_items as $line)
167 if ($line->stock_id == $myrow["stk_code"])
169 if ($line->quantity != $myrow["quantity"] ||
170 $line->qty_inv != $myrow["qty_invoiced"])
172 display_note(_("Original order for") . " " . $myrow["stk_code"] . " " .
173 _("has a quantity of") . " " . $myrow["quantity"] . " " .
174 _("and an invoiced quantity of") . " " . $myrow["qty_invoiced"] . " " .
175 _("the session shows quantity of") . " " .
176 $line->quantity . " " .
177 _("and quantity invoice of") . " " .
178 $line->qty_inv, 1, 0);
184 } /*loop through all line items of the order to ensure none have been invoiced */
190 //---------------------------------------------------------------------------------------------------------------
192 function check_data()
194 if (!isset($_POST['DispatchDate']) || !is_date($_POST['DispatchDate']))
196 display_error(_("The entered invoice date is invalid."));
199 if (!is_date_in_fiscalyear($_POST['DispatchDate']))
201 display_error(_("The entered invoice date is not in fiscal year."));
204 if (!isset($_POST['due_date']) || !is_date($_POST['due_date']))
206 display_error(_("The entered invoice due date is invalid."));
210 if (!references::is_valid($_POST['ref']))
212 display_error(_("You must enter a reference."));
216 if (!is_new_reference($_POST['ref'], 10))
218 display_error(_("The entered reference is already in use."));
221 if ($_POST['ChargeFreightCost'] == "")
222 $_POST['ChargeFreightCost'] = 0;
223 if (!is_numeric($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] < 0)
225 display_error(_("The entered shipping value is not numeric."));
229 if ($_SESSION['Items']->has_items_dispatch() == 0 && $_POST['ChargeFreightCost'] == 0)
231 display_error(_("There are no item quantities on this invoice."));
238 //---------------------------------------------------------------------------------------------------------------
242 if (!sys_prefs::allow_negative_stock())
244 foreach ($_SESSION['Items']->line_items as $itm)
247 if ($itm->qty_dispatched && has_stock_holding($itm->mb_flag))
249 $qoh = get_qoh_on_date($itm->stock_id, $_POST['Location'], $_POST['DispatchDate']);
251 if ($itm->qty_dispatched > $qoh)
253 display_error(_("The invoice cannot be processed because there is an insufficient quantity for component:") .
254 " " . $itm->stock_id . " - " . $itm->item_description);
264 //---------------------------------------------------------------------------------------------------------------
266 function process_invoice($invoicing=false)
271 read_sales_order($_SESSION['Items']->order_no, $_SESSION['Items'], true);
272 $duedate = get_invoice_duedate($_SESSION['Items']->customer_id, $_SESSION['Items']->delivery_date);
273 $invoice_no = add_sales_invoice($_SESSION['Items'],
274 $_SESSION['Items']->delivery_date, $duedate, $_SESSION['Items']->order_no,
275 $_SESSION['Items']->tax_group_id, $_SESSION['Items']->freight_cost,
276 $_SESSION['Items']->Location, $_SESSION['Items']->ship_via,
277 $_SESSION['Items']->default_sales_type, references::get_next(10),
278 $_SESSION['Items']->memo_, 0);
286 if (!check_order_changed())
287 order_changed_error();
292 if ($_POST['bo_policy'])
297 $invoice_no = add_sales_invoice($_SESSION['Items'],
298 $_POST['DispatchDate'], $_POST['due_date'], $_SESSION['ProcessingOrder'],
299 $_POST['tax_group_id'], $_POST['ChargeFreightCost'], $_POST['Location'],
300 $_POST['ship_via'], $_POST['sales_type_id'], $_POST['ref'],
301 $_POST['InvoiceText'], $bo_policy);
302 unset($_SESSION['ProcessingOrder']);
305 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
308 //---------------------------------------------------------------------------------------------------------------
309 if (isset($_GET['process_invoice']))
310 process_invoice(true);
311 elseif (isset($_POST['process_invoice']))
314 //-------------------------------------------------------------------------------------------------
316 start_form(false, true);
318 start_table("$table_style2 width=80%", 5);
319 echo "<tr><td>"; // outer table
321 start_table("$table_style width=100%");
323 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
324 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
325 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
329 if (!isset($_POST['ref']))
330 $_POST['ref'] = references::get_next(10);
332 ref_cells(_("Reference"), 'ref', null, "class='tableheader2'");
334 if (!isset($_POST['tax_group_id']))
335 $_POST['tax_group_id'] = $_SESSION['Items']->tax_group_id;
336 label_cell(_("Tax Group"), "class='tableheader2'");
337 tax_groups_list_cells(null, 'tax_group_id', $_POST['tax_group_id'], false, null, true);
339 label_cells(_("For Sales Order"), get_customer_trans_view_str(systypes::sales_order(), $_SESSION['ProcessingOrder']), "class='tableheader2'");
344 if (!isset($_POST['sales_type_id']))
345 $_POST['sales_type_id'] = $_SESSION['Items']->default_sales_type;
346 label_cell(_("Sales Type"), "class='tableheader2'");
347 sales_types_list_cells(null, 'sales_type_id', $_POST['sales_type_id']);
349 if (!isset($_POST['Location']))
350 $_POST['Location'] = $_SESSION['Items']->Location;
351 label_cell(_("Delivery From"), "class='tableheader2'");
352 locations_list_cells(null, 'Location', $_POST['Location'], false, true);
354 if (!isset($_POST['ship_via']))
355 $_POST['ship_via'] = $_SESSION['Items']->ship_via;
356 label_cell(_("Shipping Company"), "class='tableheader2'");
357 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
362 echo "</td><td>";// outer table
364 start_table("$table_style width=90%");
366 // set this up here cuz it's used to calc qoh
367 if (!isset($_POST['DispatchDate']) || !is_date($_POST['DispatchDate']))
369 $_POST['DispatchDate'] = Today();
370 if (!is_date_in_fiscalyear($_POST['DispatchDate']))
371 $_POST['DispatchDate'] = end_fiscalyear();
373 date_row(_("Date"), 'DispatchDate', $_POST['DispatchDate'], 0, 0, 0, "class='tableheader'");
375 if (!isset($_POST['due_date']) || !is_date($_POST['due_date']))
376 //$_POST['due_date'] = $_POST['DispatchDate'];
377 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, $_POST['DispatchDate']);
379 date_row(_("Due Date"), 'due_date', $_POST['due_date'], 0, 0, 0, "class='tableheader'");
383 end_table(1); // outer table
385 display_heading(_("Invoice Items"));
387 start_table("$table_style width=80%");
388 $th = array(_("Item Code"), _("Item Description"), _("Ordered"), _("Units"), _("Delivered"),
389 _("This Delivery"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
395 foreach ($_SESSION['Items']->line_items as $ln_itm)
398 // if it's a non-stock item (eg. service) don't show qoh
399 if (sys_prefs::allow_negative_stock() || !has_stock_holding($ln_itm->mb_flag) ||
400 $ln_itm->qty_dispatched == 0)
404 $qoh = get_qoh_on_date($ln_itm->stock_id, $_POST['Location'], $_POST['DispatchDate']);
406 if ($show_qoh && ($ln_itm->qty_dispatched > $qoh))
408 // oops, we don't have enough of one of the component items
409 start_row("class='stockmankobg'");
413 alt_table_row_color($k);
415 view_stock_status_cell($ln_itm->stock_id);
417 text_cells(null, $ln_itm->stock_id . "Desc", $ln_itm->item_description, 30, 50);
418 qty_cell($ln_itm->quantity);
419 label_cell($ln_itm->units);
420 qty_cell($ln_itm->qty_inv);
422 text_cells(null, $ln_itm->stock_id, $ln_itm->qty_dispatched, 10, 10);
424 $display_discount_percent = number_format2($ln_itm->discount_percent*100,user_percent_dec()) . "%";
426 $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
428 amount_cell($ln_itm->price);
429 label_cell($ln_itm->tax_type_name);
430 label_cell($display_discount_percent, "nowrap align=right");
431 amount_cell($line_total);
433 //label_cell(get_tax_free_price_for_item($ln_itm->stock_id, $line_total, $_POST['tax_group_id']));
438 /*Don't re-calculate freight if some of the order has already been delivered -
439 depending on the business logic required this condition may not be required.
440 It seems unfair to charge the customer twice for freight if the order
441 was not fully delivered the first time ?? */
443 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "")
445 if ($_SESSION['Items']->any_already_delivered() == 1)
447 $_POST['ChargeFreightCost'] = 0;
451 $_POST['ChargeFreightCost'] = $_SESSION['Items']->freight_cost;
453 if (!is_numeric($_POST['ChargeFreightCost']))
455 $_POST['ChargeFreightCost'] = 0;
461 small_amount_cells(_("Shipping Cost"), 'ChargeFreightCost', null, "colspan=9 align=right");
463 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
465 $display_sub_total = number_format2($inv_items_total + $_POST['ChargeFreightCost'],user_price_dec());
467 label_row(_("Sub-total"), $display_sub_total, "colspan=9 align=right","align=right");
469 $taxes = $_SESSION['Items']->get_taxes($_POST['tax_group_id'], $_POST['ChargeFreightCost']);
470 $tax_total = display_edit_tax_items($taxes, 9);
472 $display_total = number_format2(($inv_items_total + $_POST['ChargeFreightCost'] + $tax_total), user_price_dec());
474 label_row(_("Invoice Total"), $display_total, "colspan=9 align=right","align=right");
479 display_note(_("Marked items have insufficient quantities in stock."), 0, 1, "class='red'");
481 start_table($table_style2);
483 policy_list_row(_("Action For Balance"), "bo_policy", null);
485 textarea_row(_("Memo"), 'InvoiceText', null, 50, 4);
489 submit_center_first('Update', _("Update"));
490 submit_center_last('process_invoice', _("Process Invoice"));
494 //---------------------------------------------------------------------------------------------