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 //-----------------------------------------------------------------------------
39 if (isset($_GET['AddedID'])) {
41 $invoice_no = $_GET['AddedID'];
44 display_notification(_("Selected deliveries has been processed"), true);
46 display_note(get_customer_trans_view_str($trans_type, $invoice_no, _("&View This Invoice")), 0, 1);
48 display_note(print_document_link($invoice_no, _("&Print This Invoice"), true, 10));
50 display_note(get_gl_view_str($trans_type, $invoice_no, _("View the GL &Journal Entries for this Invoice")),1);
52 hyperlink_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Another &Delivery For Invoicing"), "OutstandingOnly=1");
54 display_footer_exit();
56 } elseif (isset($_GET['UpdatedID'])) {
58 $invoice_no = $_GET['UpdatedID'];
60 display_notification_centered(sprintf(_('Sales Invoice # %d has been updated.'),$invoice_no));
62 display_note(get_trans_view_str(10, $invoice_no, _("&View This Invoice")));
64 display_note(print_document_link($invoice_no, _("&Print This Invoice"), true, 10));
66 hyperlink_no_params($path_to_root . "/sales/inquiry/customer_inquiry.php", _("Select A Different &Invoice to Modify"));
68 display_footer_exit();
70 } elseif (isset($_GET['RemoveDN'])) {
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;
81 // Remove also src_doc delivery note
82 $sources = &$_SESSION['Items']->src_docs;
83 unset($sources[$_GET['RemoveDN']]);
86 //-----------------------------------------------------------------------------
88 if ( (isset($_GET['DeliveryNumber']) && ($_GET['DeliveryNumber'] > 0) )
89 || isset($_GET['BatchInvoice'])) {
93 if (isset($_GET['BatchInvoice'])) {
94 $src = $_SESSION['DeliveryBatch'];
95 unset($_SESSION['DeliveryBatch']);
97 $src = array($_GET['DeliveryNumber']);
99 /*read in all the selected deliveries into the Items cart */
100 $dn = new Cart(13, $src, true);
102 if ($dn->count_items() == 0) {
103 hyperlink_params($path_to_root . "/sales/inquiry/sales_deliveries_view.php",
104 _("Select a different delivery to invoice"), "OutstandingOnly=1");
105 die ("<br><b>" . _("There are no delivered items with a quantity left to invoice. There is nothing left to invoice.") . "</b>");
108 $dn->trans_type = 10;
109 $dn->src_docs = $dn->trans_no;
111 $dn->reference = references::get_next(10);
112 $dn->due_date = get_invoice_duedate($dn->customer_id, $dn->document_date);
114 $_SESSION['Items'] = $dn;
117 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
119 if ( get_parent_trans(10, $_GET['ModifyInvoice']) == 0) { // 1.xx compatibility hack
120 echo"<center><br><b>" . _("There in no delivery notes for this invoice.<br>
121 Most likely this invoice was created in Front Accounting version prior to 2.0
122 and therefore can not be modified.") . "</b></center>";
123 display_footer_exit();
126 $_SESSION['Items'] = new Cart(10, $_GET['ModifyInvoice']);
128 if ($_SESSION['Items']->count_items() == 0) {
129 echo"<center><br><b>" . _("All quantities on this invoice has been credited. There is nothing to modify on this invoice") . "</b></center>";
130 display_footer_exit();
133 } elseif (!processing_active()) {
134 /* This page can only be called with a delivery for invoicing or invoice no for edit */
135 display_error(_("This page can only be opened after delivery selection. Please select delivery to invoicing first."));
137 hyperlink_no_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Delivery to Invoice"));
141 } elseif (!check_quantities()) {
142 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
144 if (isset($_POST['Update'])) {
145 $Ajax->activate('Items');
147 if (isset($_POST['_InvoiceDate_changed'])) {
148 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id,
149 $_POST['InvoiceDate']);
150 $Ajax->activate('due_date');
152 //-----------------------------------------------------------------------------
153 function check_quantities()
156 foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
157 if (isset($_POST['Line'.$line_no])) {
158 if($_SESSION['Items']->trans_no) {
159 $min = $itm->qty_done;
160 $max = $itm->quantity;
163 $max = $itm->quantity - $itm->qty_done;
165 if (check_num('Line'.$line_no, $min, $max)) {
166 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
167 input_num('Line'.$line_no);
175 if (isset($_POST['Line'.$line_no.'Desc'])) {
176 $line_desc = $_POST['Line'.$line_no.'Desc'];
177 if (strlen($line_desc) > 0) {
178 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
185 function set_delivery_shipping_sum($delivery_notes)
190 foreach($delivery_notes as $delivery_num)
192 $myrow = get_customer_trans($delivery_num, 13);
193 //$branch = get_branch($myrow["branch_code"]);
194 //$sales_order = get_sales_order_header($myrow["order_"]);
196 //$shipping += $sales_order['freight_cost'];
197 $shipping += $myrow['ov_freight'];
199 $_POST['ChargeFreightCost'] = price_format($shipping);
203 function copy_to_cart()
205 $cart = &$_SESSION['Items'];
206 $cart->ship_via = $_POST['ship_via'];
207 $cart->freight_cost = input_num('ChargeFreightCost');
208 $cart->document_date = $_POST['InvoiceDate'];
209 $cart->due_date = $_POST['due_date'];
210 $cart->Comments = $_POST['Comments'];
212 //-----------------------------------------------------------------------------
214 function copy_from_cart()
216 $cart = &$_SESSION['Items'];
217 $_POST['ship_via'] = $cart->ship_via;
218 $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
219 $_POST['InvoiceDate']= $cart->document_date;
220 $_POST['due_date'] = $cart->due_date;
221 $_POST['Comments']= $cart->Comments;
224 //-----------------------------------------------------------------------------
226 function check_data()
228 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
229 display_error(_("The entered invoice date is invalid."));
230 set_focus('InvoiceDate');
234 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
235 display_error(_("The entered invoice date is not in fiscal year."));
236 set_focus('InvoiceDate');
240 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
241 display_error(_("The entered invoice due date is invalid."));
242 set_focus('due_date');
246 if ($_SESSION['Items']->trans_no == 0) {
247 if (!references::is_valid($_POST['ref'])) {
248 display_error(_("You must enter a reference."));
253 if (!is_new_reference($_POST['ref'], 10)) {
254 display_error(_("The entered reference is already in use."));
260 if ($_POST['ChargeFreightCost'] == "") {
261 $_POST['ChargeFreightCost'] = price_format(0);
264 if (!check_num('ChargeFreightCost', 0)) {
265 display_error(_("The entered shipping value is not numeric."));
266 set_focus('ChargeFreightCost');
270 if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
271 display_error(_("There are no item quantities on this invoice."));
275 if (!check_quantities()) {
276 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
283 //-----------------------------------------------------------------------------
284 if (isset($_POST['process_invoice']) && check_data()) {
286 $newinvoice= $_SESSION['Items']->trans_no == 0;
288 $invoice_no = $_SESSION['Items']->write();
292 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
294 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
298 // find delivery spans for batch invoice display
300 $lastdn = ''; $spanlen=1;
302 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
303 $line = $_SESSION['Items']->line_items[$line_no];
304 if ($line->quantity == $line->qty_done) {
307 if ($line->src_no == $lastdn) {
311 $dspans[] = $spanlen;
315 $lastdn = $line->src_no;
317 $dspans[] = $spanlen;
319 //-----------------------------------------------------------------------------
321 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
323 $is_edition = $_SESSION['Items']->trans_type == 10 && $_SESSION['Items']->trans_no != 0;
324 start_form(false, true);
326 start_table("$table_style2 width=80%", 5);
329 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
330 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
331 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
335 if ($_SESSION['Items']->trans_no == 0) {
336 ref_cells(_("Reference"), 'ref', '', $_SESSION['Items']->reference, "class='tableheader2'");
338 label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
341 label_cells(_("Delivery Notes:"),
342 get_customer_trans_view_str(systypes::cust_dispatch(), array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
344 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
349 if (!isset($_POST['ship_via'])) {
350 $_POST['ship_via'] = $_SESSION['Items']->ship_via;
352 label_cell(_("Shipping Company"), "class='tableheader2'");
353 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
355 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
356 $_POST['InvoiceDate'] = Today();
357 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
358 $_POST['InvoiceDate'] = end_fiscalyear();
362 date_cells(_("Date"), 'InvoiceDate', '', $_POST['InvoiceDate'], 0, 0, 0, "class='tableheader2'", true);
364 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
365 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, $_POST['InvoiceDate']);
368 date_cells(_("Due Date"), 'due_date', '', $_POST['due_date'], 0, 0, 0, "class='tableheader2'");
373 display_heading(_("Invoice Items"));
376 start_table("$table_style width=80%");
377 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
378 _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
380 if ($is_batch_invoice) {
386 $th[4] = _("Credited");
396 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
397 if ($ln_itm->quantity == $ln_itm->qty_done) {
398 continue; // this line was fully invoiced
400 alt_table_row_color($k);
401 view_stock_status_cell($ln_itm->stock_id);
403 text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
404 $dec = get_qty_dec($ln_itm->stock_id);
405 qty_cell($ln_itm->quantity, false, $dec);
406 label_cell($ln_itm->units);
407 qty_cell($ln_itm->qty_done, false, $dec);
409 if ($is_batch_invoice) {
410 // for batch invoices we can only remove whole deliveries
411 echo '<td nowrap align=right>';
412 hidden('Line' . $line, $ln_itm->qty_dispatched );
413 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
415 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
417 $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
419 $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
421 amount_cell($ln_itm->price);
422 label_cell($ln_itm->tax_type_name);
423 label_cell($display_discount_percent, "nowrap align=right");
424 amount_cell($line_total);
426 if ($is_batch_invoice) {
427 if ($dn_line_cnt == 0) {
428 $dn_line_cnt = $dspans[0];
429 $dspans = array_slice($dspans, 1);
430 label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
431 label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
432 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
439 /*Don't re-calculate freight if some of the order has already been delivered -
440 depending on the business logic required this condition may not be required.
441 It seems unfair to charge the customer twice for freight if the order
442 was not fully delivered the first time ?? */
444 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
445 if ($_SESSION['Items']->any_already_delivered() == 1) {
446 $_POST['ChargeFreightCost'] = price_format(0);
448 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
451 if (!check_num('ChargeFreightCost')) {
452 $_POST['ChargeFreightCost'] = price_format(0);
456 $accumulate_shipping = get_company_pref('accumulate_shipping');
457 if ($is_batch_invoice && $accumulate_shipping)
458 set_delivery_shipping_sum(array_keys($_SESSION['Items']->src_docs));
462 small_amount_cells(_("Shipping Cost"), 'ChargeFreightCost', null, "colspan=9 align=right");
463 if ($is_batch_invoice) {
464 label_cell('', 'colspan=2');
468 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
470 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
472 label_row(_("Sub-total"), $display_sub_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
474 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
475 $tax_total = display_edit_tax_items($taxes, 9, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
477 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
479 label_row(_("Invoice Total"), $display_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
484 start_table($table_style2);
485 textarea_row(_("Memo"), 'Comments', null, 50, 4);
489 submit_center_first('Update', _("Update"),
490 _('Refresh document page'), true);
491 submit_center_last('process_invoice', _("Process Invoice"),
492 _('Check entered data and save document'), true);