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
17 $page_security = 'SA_SALESINVOICE';
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'];
53 $trans_type = ST_SALESINVOICE;
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, ST_SALESINVOICE));
60 display_note(print_document_link($invoice_no, _("&Email This Invoice"), true, ST_SALESINVOICE, false, "", "", 1),1);
62 display_note(get_gl_view_str($trans_type, $invoice_no, _("View the GL &Journal Entries for this Invoice")),1);
64 hyperlink_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Another &Delivery For Invoicing"), "OutstandingOnly=1");
66 display_footer_exit();
68 } elseif (isset($_GET['UpdatedID'])) {
70 $invoice_no = $_GET['UpdatedID'];
72 display_notification_centered(sprintf(_('Sales Invoice # %d has been updated.'),$invoice_no));
74 display_note(get_trans_view_str(ST_SALESINVOICE, $invoice_no, _("&View This Invoice")));
76 display_note(print_document_link($invoice_no, _("&Print This Invoice"), true, ST_SALESINVOICE));
78 hyperlink_no_params($path_to_root . "/sales/inquiry/customer_inquiry.php", _("Select A Different &Invoice to Modify"));
80 display_footer_exit();
82 } elseif (isset($_GET['RemoveDN'])) {
84 for($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
85 $line = &$_SESSION['Items']->line_items[$line_no];
86 if ($line->src_no == $_GET['RemoveDN']) {
87 $line->quantity = $line->qty_done;
88 $line->qty_dispatched=0;
93 // Remove also src_doc delivery note
94 $sources = &$_SESSION['Items']->src_docs;
95 unset($sources[$_GET['RemoveDN']]);
98 //-----------------------------------------------------------------------------
100 if ( (isset($_GET['DeliveryNumber']) && ($_GET['DeliveryNumber'] > 0) )
101 || isset($_GET['BatchInvoice'])) {
105 if (isset($_GET['BatchInvoice'])) {
106 $src = $_SESSION['DeliveryBatch'];
107 unset($_SESSION['DeliveryBatch']);
109 $src = array($_GET['DeliveryNumber']);
111 /*read in all the selected deliveries into the Items cart */
112 $dn = new Cart(ST_CUSTDELIVERY, $src, true);
114 if ($dn->count_items() == 0) {
115 hyperlink_params($path_to_root . "/sales/inquiry/sales_deliveries_view.php",
116 _("Select a different delivery to invoice"), "OutstandingOnly=1");
117 die ("<br><b>" . _("There are no delivered items with a quantity left to invoice. There is nothing left to invoice.") . "</b>");
120 $dn->trans_type = ST_SALESINVOICE;
121 $dn->src_docs = $dn->trans_no;
123 $dn->reference = $Refs->get_next(ST_SALESINVOICE);
124 $dn->due_date = get_invoice_duedate($dn->customer_id, $dn->document_date);
126 $_SESSION['Items'] = $dn;
129 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
131 if ( get_parent_trans(ST_SALESINVOICE, $_GET['ModifyInvoice']) == 0) { // 1.xx compatibility hack
132 echo"<center><br><b>" . _("There are no delivery notes for this invoice.<br>
133 Most likely this invoice was created in Front Accounting version prior to 2.0
134 and therefore can not be modified.") . "</b></center>";
135 display_footer_exit();
138 $_SESSION['Items'] = new Cart(ST_SALESINVOICE, $_GET['ModifyInvoice']);
140 if ($_SESSION['Items']->count_items() == 0) {
141 echo"<center><br><b>" . _("All quantities on this invoice has been credited. There is nothing to modify on this invoice") . "</b></center>";
142 display_footer_exit();
145 } elseif (!processing_active()) {
146 /* This page can only be called with a delivery for invoicing or invoice no for edit */
147 display_error(_("This page can only be opened after delivery selection. Please select delivery to invoicing first."));
149 hyperlink_no_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Delivery to Invoice"));
153 } elseif (!check_quantities()) {
154 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
156 if (isset($_POST['Update'])) {
157 $Ajax->activate('Items');
159 if (isset($_POST['_InvoiceDate_changed'])) {
160 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id,
161 $_POST['InvoiceDate']);
162 $Ajax->activate('due_date');
165 //-----------------------------------------------------------------------------
166 function check_quantities()
169 foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
170 if (isset($_POST['Line'.$line_no])) {
171 if($_SESSION['Items']->trans_no) {
172 $min = $itm->qty_done;
173 $max = $itm->quantity;
176 $max = $itm->quantity - $itm->qty_done;
178 if (check_num('Line'.$line_no, $min, $max)) {
179 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
180 input_num('Line'.$line_no);
188 if (isset($_POST['Line'.$line_no.'Desc'])) {
189 $line_desc = $_POST['Line'.$line_no.'Desc'];
190 if (strlen($line_desc) > 0) {
191 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
198 function set_delivery_shipping_sum($delivery_notes)
203 foreach($delivery_notes as $delivery_num)
205 $myrow = get_customer_trans($delivery_num, 13);
206 //$branch = get_branch($myrow["branch_code"]);
207 //$sales_order = get_sales_order_header($myrow["order_"]);
209 //$shipping += $sales_order['freight_cost'];
210 $shipping += $myrow['ov_freight'];
212 $_POST['ChargeFreightCost'] = price_format($shipping);
216 function copy_to_cart()
218 $cart = &$_SESSION['Items'];
219 $cart->ship_via = $_POST['ship_via'];
220 $cart->freight_cost = input_num('ChargeFreightCost');
221 $cart->document_date = $_POST['InvoiceDate'];
222 $cart->due_date = $_POST['due_date'];
223 $cart->Comments = $_POST['Comments'];
224 if ($_SESSION['Items']->trans_no == 0)
225 $cart->reference = $_POST['ref'];
227 //-----------------------------------------------------------------------------
229 function copy_from_cart()
231 $cart = &$_SESSION['Items'];
232 $_POST['ship_via'] = $cart->ship_via;
233 $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
234 $_POST['InvoiceDate']= $cart->document_date;
235 $_POST['due_date'] = $cart->due_date;
236 $_POST['Comments']= $cart->Comments;
237 $_POST['cart_id'] = $cart->cart_id;
238 $_POST['ref'] = $cart->reference;
241 //-----------------------------------------------------------------------------
243 function check_data()
247 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
248 display_error(_("The entered invoice date is invalid."));
249 set_focus('InvoiceDate');
253 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
254 display_error(_("The entered invoice date is not in fiscal year."));
255 set_focus('InvoiceDate');
259 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
260 display_error(_("The entered invoice due date is invalid."));
261 set_focus('due_date');
265 if ($_SESSION['Items']->trans_no == 0) {
266 if (!$Refs->is_valid($_POST['ref'])) {
267 display_error(_("You must enter a reference."));
272 if (!is_new_reference($_POST['ref'], 10)) {
273 display_error(_("The entered reference is already in use."));
279 if ($_POST['ChargeFreightCost'] == "") {
280 $_POST['ChargeFreightCost'] = price_format(0);
283 if (!check_num('ChargeFreightCost', 0)) {
284 display_error(_("The entered shipping value is not numeric."));
285 set_focus('ChargeFreightCost');
289 if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
290 display_error(_("There are no item quantities on this invoice."));
294 if (!check_quantities()) {
295 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
302 //-----------------------------------------------------------------------------
303 if (isset($_POST['process_invoice']) && check_data()) {
305 $newinvoice= $_SESSION['Items']->trans_no == 0;
307 if ($newinvoice) new_doc_date($_SESSION['Items']->document_date);
308 $invoice_no = $_SESSION['Items']->write();
312 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
314 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
318 // find delivery spans for batch invoice display
320 $lastdn = ''; $spanlen=1;
322 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
323 $line = $_SESSION['Items']->line_items[$line_no];
324 if ($line->quantity == $line->qty_done) {
327 if ($line->src_no == $lastdn) {
331 $dspans[] = $spanlen;
335 $lastdn = $line->src_no;
337 $dspans[] = $spanlen;
339 //-----------------------------------------------------------------------------
341 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
343 $is_edition = $_SESSION['Items']->trans_type == ST_SALESINVOICE && $_SESSION['Items']->trans_no != 0;
347 start_table("$table_style2 width=80%", 5);
350 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
351 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
352 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
356 if ($_SESSION['Items']->trans_no == 0) {
357 ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'");
359 label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
362 label_cells(_("Delivery Notes:"),
363 get_customer_trans_view_str(ST_CUSTDELIVERY, array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
365 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
370 if (!isset($_POST['ship_via'])) {
371 $_POST['ship_via'] = $_SESSION['Items']->ship_via;
373 label_cell(_("Shipping Company"), "class='tableheader2'");
374 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
376 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
377 $_POST['InvoiceDate'] = new_doc_date();
378 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
379 $_POST['InvoiceDate'] = end_fiscalyear();
383 date_cells(_("Date"), 'InvoiceDate', '', $_SESSION['Items']->trans_no == 0,
384 0, 0, 0, "class='tableheader2'", true);
386 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
387 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, $_POST['InvoiceDate']);
390 date_cells(_("Due Date"), 'due_date', '', null, 0, 0, 0, "class='tableheader2'");
395 $row = get_customer_to_order($_SESSION['Items']->customer_id);
396 if ($row['dissallow_invoices'] == 1)
398 display_error(_("The selected customer account is currently on hold. Please contact the credit control personnel to discuss."));
404 display_heading(_("Invoice Items"));
407 start_table("$table_style width=80%");
408 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
409 _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
411 if ($is_batch_invoice) {
417 $th[4] = _("Credited");
427 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
428 if ($ln_itm->quantity == $ln_itm->qty_done) {
429 continue; // this line was fully invoiced
431 alt_table_row_color($k);
432 view_stock_status_cell($ln_itm->stock_id);
434 text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
435 $dec = get_qty_dec($ln_itm->stock_id);
436 qty_cell($ln_itm->quantity, false, $dec);
437 label_cell($ln_itm->units);
438 qty_cell($ln_itm->qty_done, false, $dec);
440 if ($is_batch_invoice) {
441 // for batch invoices we can only remove whole deliveries
442 echo '<td nowrap align=right>';
443 hidden('Line' . $line, $ln_itm->qty_dispatched );
444 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
446 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
448 $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
450 $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
452 amount_cell($ln_itm->price);
453 label_cell($ln_itm->tax_type_name);
454 label_cell($display_discount_percent, "nowrap align=right");
455 amount_cell($line_total);
457 if ($is_batch_invoice) {
458 if ($dn_line_cnt == 0) {
459 $dn_line_cnt = $dspans[0];
460 $dspans = array_slice($dspans, 1);
461 label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
462 label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
463 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
470 /*Don't re-calculate freight if some of the order has already been delivered -
471 depending on the business logic required this condition may not be required.
472 It seems unfair to charge the customer twice for freight if the order
473 was not fully delivered the first time ?? */
475 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
476 if ($_SESSION['Items']->any_already_delivered() == 1) {
477 $_POST['ChargeFreightCost'] = price_format(0);
479 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
482 if (!check_num('ChargeFreightCost')) {
483 $_POST['ChargeFreightCost'] = price_format(0);
487 $accumulate_shipping = get_company_pref('accumulate_shipping');
488 if ($is_batch_invoice && $accumulate_shipping)
489 set_delivery_shipping_sum(array_keys($_SESSION['Items']->src_docs));
493 small_amount_cells(_("Shipping Cost"), 'ChargeFreightCost', null, "colspan=9 align=right");
494 if ($is_batch_invoice) {
495 label_cell('', 'colspan=2');
499 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
501 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
503 label_row(_("Sub-total"), $display_sub_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
505 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
506 $tax_total = display_edit_tax_items($taxes, 9, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
508 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
510 label_row(_("Invoice Total"), $display_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
515 start_table($table_style2);
516 textarea_row(_("Memo"), 'Comments', null, 50, 4);
520 submit_center_first('Update', _("Update"),
521 _('Refresh document page'), true);
522 submit_center_last('process_invoice', _("Process Invoice"),
523 _('Check entered data and save document'), 'default');