2 /**********************************************************************
3 Copyright (C) FrontAccounting, LLC.
4 Released under the terms of the GNU General Public License, GPL,
5 as published by the Free Software Foundation, either version 3
6 of the License, or (at your option) any later version.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
11 ***********************************************************************/
12 //---------------------------------------------------------------------------
14 // Entry/Modify Sales Invoice against single delivery
15 // Entry/Modify Batch Sales Invoice against batch of deliveries
19 include_once($path_to_root . "/sales/includes/cart_class.inc");
20 include_once($path_to_root . "/includes/session.inc");
21 include_once($path_to_root . "/includes/data_checks.inc");
22 include_once($path_to_root . "/includes/manufacturing.inc");
23 include_once($path_to_root . "/sales/includes/sales_db.inc");
24 include_once($path_to_root . "/sales/includes/sales_ui.inc");
25 include_once($path_to_root . "/reporting/includes/reporting.inc");
26 include_once($path_to_root . "/taxes/tax_calc.inc");
29 if ($use_popup_windows) {
30 $js .= get_js_open_window(900, 500);
32 if ($use_date_picker) {
33 $js .= get_js_date_picker();
36 if (isset($_GET['ModifyInvoice'])) {
37 $_SESSION['page_title'] = sprintf(_("Modifying Sales Invoice # %d.") ,$_GET['ModifyInvoice']);
38 $help_page_title = _("Modifying Sales Invoice");
39 } elseif (isset($_GET['DeliveryNumber'])) {
40 $_SESSION['page_title'] = _("Issue an Invoice for Delivery Note");
41 } elseif (isset($_GET['BatchInvoice'])) {
42 $_SESSION['page_title'] = _("Issue Batch Invoice for Delivery Notes");
45 page($_SESSION['page_title'], false, false, "", $js);
47 //-----------------------------------------------------------------------------
48 check_edit_conflicts();
50 if (isset($_GET['AddedID'])) {
52 $invoice_no = $_GET['AddedID'];
55 display_notification(_("Selected deliveries has been processed"), true);
57 display_note(get_customer_trans_view_str($trans_type, $invoice_no, _("&View This Invoice")), 0, 1);
59 display_note(print_document_link($invoice_no, _("&Print This Invoice"), true, 10));
61 display_note(get_gl_view_str($trans_type, $invoice_no, _("View the GL &Journal Entries for this Invoice")),1);
63 hyperlink_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Another &Delivery For Invoicing"), "OutstandingOnly=1");
65 display_footer_exit();
67 } elseif (isset($_GET['UpdatedID'])) {
69 $invoice_no = $_GET['UpdatedID'];
71 display_notification_centered(sprintf(_('Sales Invoice # %d has been updated.'),$invoice_no));
73 display_note(get_trans_view_str(10, $invoice_no, _("&View This Invoice")));
75 display_note(print_document_link($invoice_no, _("&Print This Invoice"), true, 10));
77 hyperlink_no_params($path_to_root . "/sales/inquiry/customer_inquiry.php", _("Select A Different &Invoice to Modify"));
79 display_footer_exit();
81 } elseif (isset($_GET['RemoveDN'])) {
83 for($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
84 $line = &$_SESSION['Items']->line_items[$line_no];
85 if ($line->src_no == $_GET['RemoveDN']) {
86 $line->quantity = $line->qty_done;
87 $line->qty_dispatched=0;
92 // Remove also src_doc delivery note
93 $sources = &$_SESSION['Items']->src_docs;
94 unset($sources[$_GET['RemoveDN']]);
97 //-----------------------------------------------------------------------------
99 if ( (isset($_GET['DeliveryNumber']) && ($_GET['DeliveryNumber'] > 0) )
100 || isset($_GET['BatchInvoice'])) {
104 if (isset($_GET['BatchInvoice'])) {
105 $src = $_SESSION['DeliveryBatch'];
106 unset($_SESSION['DeliveryBatch']);
108 $src = array($_GET['DeliveryNumber']);
110 /*read in all the selected deliveries into the Items cart */
111 $dn = new Cart(13, $src, true);
113 if ($dn->count_items() == 0) {
114 hyperlink_params($path_to_root . "/sales/inquiry/sales_deliveries_view.php",
115 _("Select a different delivery to invoice"), "OutstandingOnly=1");
116 die ("<br><b>" . _("There are no delivered items with a quantity left to invoice. There is nothing left to invoice.") . "</b>");
119 $dn->trans_type = 10;
120 $dn->src_docs = $dn->trans_no;
122 $dn->reference = references::get_next(10);
123 $dn->due_date = get_invoice_duedate($dn->customer_id, $dn->document_date);
125 $_SESSION['Items'] = $dn;
128 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
130 if ( get_parent_trans(10, $_GET['ModifyInvoice']) == 0) { // 1.xx compatibility hack
131 echo"<center><br><b>" . _("There are no delivery notes for this invoice.<br>
132 Most likely this invoice was created in Front Accounting version prior to 2.0
133 and therefore can not be modified.") . "</b></center>";
134 display_footer_exit();
137 $_SESSION['Items'] = new Cart(10, $_GET['ModifyInvoice']);
139 if ($_SESSION['Items']->count_items() == 0) {
140 echo"<center><br><b>" . _("All quantities on this invoice has been credited. There is nothing to modify on this invoice") . "</b></center>";
141 display_footer_exit();
144 } elseif (!processing_active()) {
145 /* This page can only be called with a delivery for invoicing or invoice no for edit */
146 display_error(_("This page can only be opened after delivery selection. Please select delivery to invoicing first."));
148 hyperlink_no_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Delivery to Invoice"));
152 } elseif (!check_quantities()) {
153 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
155 if (isset($_POST['Update'])) {
156 $Ajax->activate('Items');
158 if (isset($_POST['_InvoiceDate_changed'])) {
159 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id,
160 $_POST['InvoiceDate']);
161 $Ajax->activate('due_date');
164 //-----------------------------------------------------------------------------
165 function check_quantities()
168 foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
169 if (isset($_POST['Line'.$line_no])) {
170 if($_SESSION['Items']->trans_no) {
171 $min = $itm->qty_done;
172 $max = $itm->quantity;
175 $max = $itm->quantity - $itm->qty_done;
177 if (check_num('Line'.$line_no, $min, $max)) {
178 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
179 input_num('Line'.$line_no);
187 if (isset($_POST['Line'.$line_no.'Desc'])) {
188 $line_desc = $_POST['Line'.$line_no.'Desc'];
189 if (strlen($line_desc) > 0) {
190 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
197 function set_delivery_shipping_sum($delivery_notes)
202 foreach($delivery_notes as $delivery_num)
204 $myrow = get_customer_trans($delivery_num, 13);
205 //$branch = get_branch($myrow["branch_code"]);
206 //$sales_order = get_sales_order_header($myrow["order_"]);
208 //$shipping += $sales_order['freight_cost'];
209 $shipping += $myrow['ov_freight'];
211 $_POST['ChargeFreightCost'] = price_format($shipping);
215 function copy_to_cart()
217 $cart = &$_SESSION['Items'];
218 $cart->ship_via = $_POST['ship_via'];
219 $cart->freight_cost = input_num('ChargeFreightCost');
220 $cart->document_date = $_POST['InvoiceDate'];
221 $cart->due_date = $_POST['due_date'];
222 $cart->Comments = $_POST['Comments'];
223 if ($_SESSION['Items']->trans_no == 0)
224 $cart->reference = $_POST['ref'];
226 //-----------------------------------------------------------------------------
228 function copy_from_cart()
230 $cart = &$_SESSION['Items'];
231 $_POST['ship_via'] = $cart->ship_via;
232 $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
233 $_POST['InvoiceDate']= $cart->document_date;
234 $_POST['due_date'] = $cart->due_date;
235 $_POST['Comments']= $cart->Comments;
236 $_POST['cart_id'] = $cart->cart_id;
237 $_POST['ref'] = $cart->reference;
240 //-----------------------------------------------------------------------------
242 function check_data()
244 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
245 display_error(_("The entered invoice date is invalid."));
246 set_focus('InvoiceDate');
250 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
251 display_error(_("The entered invoice date is not in fiscal year."));
252 set_focus('InvoiceDate');
256 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
257 display_error(_("The entered invoice due date is invalid."));
258 set_focus('due_date');
262 if ($_SESSION['Items']->trans_no == 0) {
263 if (!references::is_valid($_POST['ref'])) {
264 display_error(_("You must enter a reference."));
269 if (!is_new_reference($_POST['ref'], 10)) {
270 display_error(_("The entered reference is already in use."));
276 if ($_POST['ChargeFreightCost'] == "") {
277 $_POST['ChargeFreightCost'] = price_format(0);
280 if (!check_num('ChargeFreightCost', 0)) {
281 display_error(_("The entered shipping value is not numeric."));
282 set_focus('ChargeFreightCost');
286 if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
287 display_error(_("There are no item quantities on this invoice."));
291 if (!check_quantities()) {
292 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
299 //-----------------------------------------------------------------------------
300 if (isset($_POST['process_invoice']) && check_data()) {
302 $newinvoice= $_SESSION['Items']->trans_no == 0;
304 $invoice_no = $_SESSION['Items']->write();
308 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
310 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
314 // find delivery spans for batch invoice display
316 $lastdn = ''; $spanlen=1;
318 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
319 $line = $_SESSION['Items']->line_items[$line_no];
320 if ($line->quantity == $line->qty_done) {
323 if ($line->src_no == $lastdn) {
327 $dspans[] = $spanlen;
331 $lastdn = $line->src_no;
333 $dspans[] = $spanlen;
335 //-----------------------------------------------------------------------------
337 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
339 $is_edition = $_SESSION['Items']->trans_type == 10 && $_SESSION['Items']->trans_no != 0;
340 start_form(false, true);
343 start_table("$table_style2 width=80%", 5);
346 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
347 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
348 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
352 if ($_SESSION['Items']->trans_no == 0) {
353 ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'");
355 label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
358 label_cells(_("Delivery Notes:"),
359 get_customer_trans_view_str(systypes::cust_dispatch(), array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
361 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
366 if (!isset($_POST['ship_via'])) {
367 $_POST['ship_via'] = $_SESSION['Items']->ship_via;
369 label_cell(_("Shipping Company"), "class='tableheader2'");
370 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
372 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
373 $_POST['InvoiceDate'] = Today();
374 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
375 $_POST['InvoiceDate'] = end_fiscalyear();
379 date_cells(_("Date"), 'InvoiceDate', '', $_POST['InvoiceDate'], 0, 0, 0, "class='tableheader2'", true);
381 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
382 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, $_POST['InvoiceDate']);
385 date_cells(_("Due Date"), 'due_date', '', $_POST['due_date'], 0, 0, 0, "class='tableheader2'");
390 $row = get_customer_to_order($_SESSION['Items']->customer_id);
391 if ($row['dissallow_invoices'] == 1)
393 display_error(_("The selected customer account is currently on hold. Please contact the credit control personnel to discuss."));
399 display_heading(_("Invoice Items"));
402 start_table("$table_style width=80%");
403 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
404 _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
406 if ($is_batch_invoice) {
412 $th[4] = _("Credited");
422 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
423 if ($ln_itm->quantity == $ln_itm->qty_done) {
424 continue; // this line was fully invoiced
426 alt_table_row_color($k);
427 view_stock_status_cell($ln_itm->stock_id);
429 text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
430 $dec = get_qty_dec($ln_itm->stock_id);
431 qty_cell($ln_itm->quantity, false, $dec);
432 label_cell($ln_itm->units);
433 qty_cell($ln_itm->qty_done, false, $dec);
435 if ($is_batch_invoice) {
436 // for batch invoices we can only remove whole deliveries
437 echo '<td nowrap align=right>';
438 hidden('Line' . $line, $ln_itm->qty_dispatched );
439 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
441 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
443 $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
445 $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
447 amount_cell($ln_itm->price);
448 label_cell($ln_itm->tax_type_name);
449 label_cell($display_discount_percent, "nowrap align=right");
450 amount_cell($line_total);
452 if ($is_batch_invoice) {
453 if ($dn_line_cnt == 0) {
454 $dn_line_cnt = $dspans[0];
455 $dspans = array_slice($dspans, 1);
456 label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
457 label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
458 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
465 /*Don't re-calculate freight if some of the order has already been delivered -
466 depending on the business logic required this condition may not be required.
467 It seems unfair to charge the customer twice for freight if the order
468 was not fully delivered the first time ?? */
470 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
471 if ($_SESSION['Items']->any_already_delivered() == 1) {
472 $_POST['ChargeFreightCost'] = price_format(0);
474 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
477 if (!check_num('ChargeFreightCost')) {
478 $_POST['ChargeFreightCost'] = price_format(0);
482 $accumulate_shipping = get_company_pref('accumulate_shipping');
483 if ($is_batch_invoice && $accumulate_shipping)
484 set_delivery_shipping_sum(array_keys($_SESSION['Items']->src_docs));
488 small_amount_cells(_("Shipping Cost"), 'ChargeFreightCost', null, "colspan=9 align=right");
489 if ($is_batch_invoice) {
490 label_cell('', 'colspan=2');
494 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
496 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
498 label_row(_("Sub-total"), $display_sub_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
500 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
501 $tax_total = display_edit_tax_items($taxes, 9, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
503 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
505 label_row(_("Invoice Total"), $display_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
510 start_table($table_style2);
511 textarea_row(_("Memo"), 'Comments', null, 50, 4);
515 submit_center_first('Update', _("Update"),
516 _('Refresh document page'), true);
517 submit_center_last('process_invoice', _("Process Invoice"),
518 _('Check entered data and save document'), true);