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_context = "Modifying Sales Invoice";
39 } elseif (isset($_GET['DeliveryNumber'])) {
40 $_SESSION['page_title'] = _($help_context = "Issue an Invoice for Delivery Note");
41 } elseif (isset($_GET['BatchInvoice'])) {
42 $_SESSION['page_title'] = _($help_context = "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, "printlink", "", 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 Another &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->payment, $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']->payment,
161 $_POST['InvoiceDate']);
162 $Ajax->activate('due_date');
164 if (list_updated('payment')) {
165 $_SESSION['Items']->payment = get_post('payment');
166 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment,
167 $_POST['InvoiceDate']);
168 $Ajax->activate('due_date');
171 //-----------------------------------------------------------------------------
172 function check_quantities()
175 foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
176 if (isset($_POST['Line'.$line_no])) {
177 if($_SESSION['Items']->trans_no) {
178 $min = $itm->qty_done;
179 $max = $itm->quantity;
182 $max = $itm->quantity - $itm->qty_done;
184 if (check_num('Line'.$line_no, $min, $max)) {
185 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
186 input_num('Line'.$line_no);
194 if (isset($_POST['Line'.$line_no.'Desc'])) {
195 $line_desc = $_POST['Line'.$line_no.'Desc'];
196 if (strlen($line_desc) > 0) {
197 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
204 function set_delivery_shipping_sum($delivery_notes)
209 foreach($delivery_notes as $delivery_num)
211 $myrow = get_customer_trans($delivery_num, 13);
212 //$branch = get_branch($myrow["branch_code"]);
213 //$sales_order = get_sales_order_header($myrow["order_"]);
215 //$shipping += $sales_order['freight_cost'];
216 $shipping += $myrow['ov_freight'];
218 $_POST['ChargeFreightCost'] = price_format($shipping);
222 function copy_to_cart()
224 $cart = &$_SESSION['Items'];
225 $cart->ship_via = $_POST['ship_via'];
226 $cart->freight_cost = input_num('ChargeFreightCost');
227 $cart->document_date = $_POST['InvoiceDate'];
228 $cart->due_date = $_POST['due_date'];
229 $cart->payment = $_POST['payment'];
230 $cart->payment_terms = get_payment_terms($_POST['payment']);
231 $cart->Comments = $_POST['Comments'];
232 if ($_SESSION['Items']->trans_no == 0)
233 $cart->reference = $_POST['ref'];
236 //-----------------------------------------------------------------------------
238 function copy_from_cart()
240 $cart = &$_SESSION['Items'];
241 $_POST['ship_via'] = $cart->ship_via;
242 $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
243 $_POST['InvoiceDate']= $cart->document_date;
244 $_POST['due_date'] = $cart->due_date;
245 $_POST['Comments']= $cart->Comments;
246 $_POST['cart_id'] = $cart->cart_id;
247 $_POST['ref'] = $cart->reference;
248 $_POST['payment'] = $cart->payment;
251 //-----------------------------------------------------------------------------
253 function check_data()
257 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
258 display_error(_("The entered invoice date is invalid."));
259 set_focus('InvoiceDate');
263 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
264 display_error(_("The entered invoice date is not in fiscal year."));
265 set_focus('InvoiceDate');
269 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
270 display_error(_("The entered invoice due date is invalid."));
271 set_focus('due_date');
275 if ($_SESSION['Items']->trans_no == 0) {
276 if (!$Refs->is_valid($_POST['ref'])) {
277 display_error(_("You must enter a reference."));
282 if (!is_new_reference($_POST['ref'], 10)) {
283 display_error(_("The entered reference is already in use."));
289 if ($_POST['ChargeFreightCost'] == "") {
290 $_POST['ChargeFreightCost'] = price_format(0);
293 if (!check_num('ChargeFreightCost', 0)) {
294 display_error(_("The entered shipping value is not numeric."));
295 set_focus('ChargeFreightCost');
299 if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
300 display_error(_("There are no item quantities on this invoice."));
304 if (!check_quantities()) {
305 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
312 //-----------------------------------------------------------------------------
313 if (isset($_POST['process_invoice']) && check_data()) {
315 $newinvoice= $_SESSION['Items']->trans_no == 0;
317 if ($newinvoice) new_doc_date($_SESSION['Items']->document_date);
319 $invoice_no = $_SESSION['Items']->write();
323 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
325 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
329 // find delivery spans for batch invoice display
331 $lastdn = ''; $spanlen=1;
333 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
334 $line = $_SESSION['Items']->line_items[$line_no];
335 if ($line->quantity == $line->qty_done) {
338 if ($line->src_no == $lastdn) {
342 $dspans[] = $spanlen;
346 $lastdn = $line->src_no;
348 $dspans[] = $spanlen;
350 //-----------------------------------------------------------------------------
352 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
354 $is_edition = $_SESSION['Items']->trans_type == ST_SALESINVOICE && $_SESSION['Items']->trans_no != 0;
358 start_table(TABLESTYLE2, "width=80%", 5);
361 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
362 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
363 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
367 if ($_SESSION['Items']->trans_no == 0) {
368 ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'");
370 label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
373 //label_cells(_("Delivery Notes:"),
374 //get_customer_trans_view_str(ST_CUSTDELIVERY, array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
376 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
378 if ($_SESSION['Items']->pos != -1) // editable payment type
379 label_cells(_("Payment terms:"), sale_payment_list('payment'), "class='tableheader2'");
381 label_cells(_('Payment:'), $_SESSION['Items']->payment_terms['terms'], "class='tableheader2'");
386 if (!isset($_POST['ship_via'])) {
387 $_POST['ship_via'] = $_SESSION['Items']->ship_via;
389 label_cell(_("Shipping Company"), "class='tableheader2'");
390 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
392 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
393 $_POST['InvoiceDate'] = new_doc_date();
394 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
395 $_POST['InvoiceDate'] = end_fiscalyear();
399 date_cells(_("Date"), 'InvoiceDate', '', $_SESSION['Items']->trans_no == 0,
400 0, 0, 0, "class='tableheader2'", true);
402 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
403 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_POST['InvoiceDate']);
406 date_cells(_("Due Date"), 'due_date', '', null, 0, 0, 0, "class='tableheader2'");
411 $row = get_customer_to_order($_SESSION['Items']->customer_id);
412 if ($row['dissallow_invoices'] == 1)
414 display_error(_("The selected customer account is currently on hold. Please contact the credit control personnel to discuss."));
420 display_heading(_("Invoice Items"));
423 start_table(TABLESTYLE, "width=80%");
424 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
425 _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
427 if ($is_batch_invoice) {
433 $th[4] = _("Credited");
443 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
444 if ($ln_itm->quantity == $ln_itm->qty_done) {
445 continue; // this line was fully invoiced
447 alt_table_row_color($k);
448 view_stock_status_cell($ln_itm->stock_id);
450 text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
451 $dec = get_qty_dec($ln_itm->stock_id);
452 qty_cell($ln_itm->quantity, false, $dec);
453 label_cell($ln_itm->units);
454 qty_cell($ln_itm->qty_done, false, $dec);
456 if ($is_batch_invoice) {
457 // for batch invoices we can only remove whole deliveries
458 echo '<td nowrap align=right>';
459 hidden('Line' . $line, $ln_itm->qty_dispatched );
460 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
462 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
464 $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
466 $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
468 amount_cell($ln_itm->price);
469 label_cell($ln_itm->tax_type_name);
470 label_cell($display_discount_percent, "nowrap align=right");
471 amount_cell($line_total);
473 if ($is_batch_invoice) {
474 if ($dn_line_cnt == 0) {
475 $dn_line_cnt = $dspans[0];
476 $dspans = array_slice($dspans, 1);
477 label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
478 label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
479 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
486 /*Don't re-calculate freight if some of the order has already been delivered -
487 depending on the business logic required this condition may not be required.
488 It seems unfair to charge the customer twice for freight if the order
489 was not fully delivered the first time ?? */
491 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
492 if ($_SESSION['Items']->any_already_delivered() == 1) {
493 $_POST['ChargeFreightCost'] = price_format(0);
495 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
498 if (!check_num('ChargeFreightCost')) {
499 $_POST['ChargeFreightCost'] = price_format(0);
503 $accumulate_shipping = get_company_pref('accumulate_shipping');
504 if ($is_batch_invoice && $accumulate_shipping)
505 set_delivery_shipping_sum(array_keys($_SESSION['Items']->src_docs));
509 label_cell(_("Shipping Cost"), "colspan=$colspan align=right");
510 small_amount_cells(null, 'ChargeFreightCost', null);
511 if ($is_batch_invoice) {
512 label_cell('', 'colspan=2');
516 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
518 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
520 label_row(_("Sub-total"), $display_sub_total, "colspan=$colspan align=right","align=right", $is_batch_invoice ? 2 : 0);
522 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
523 $tax_total = display_edit_tax_items($taxes, $colspan, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
525 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
527 label_row(_("Invoice Total"), $display_total, "colspan=$colspan align=right","align=right", $is_batch_invoice ? 2 : 0);
532 start_table(TABLESTYLE2);
533 textarea_row(_("Memo"), 'Comments', null, 50, 4);
537 submit_center_first('Update', _("Update"),
538 _('Refresh document page'), true);
539 submit_center_last('process_invoice', _("Process Invoice"),
540 _('Check entered data and save document'), 'default');