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, "", "", 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->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->Comments = $_POST['Comments'];
231 if ($_SESSION['Items']->trans_no == 0)
232 $cart->reference = $_POST['ref'];
235 //-----------------------------------------------------------------------------
237 function copy_from_cart()
239 $cart = &$_SESSION['Items'];
240 $_POST['ship_via'] = $cart->ship_via;
241 $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
242 $_POST['InvoiceDate']= $cart->document_date;
243 $_POST['due_date'] = $cart->due_date;
244 $_POST['Comments']= $cart->Comments;
245 $_POST['cart_id'] = $cart->cart_id;
246 $_POST['ref'] = $cart->reference;
249 //-----------------------------------------------------------------------------
251 function check_data()
255 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
256 display_error(_("The entered invoice date is invalid."));
257 set_focus('InvoiceDate');
261 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
262 display_error(_("The entered invoice date is not in fiscal year."));
263 set_focus('InvoiceDate');
267 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
268 display_error(_("The entered invoice due date is invalid."));
269 set_focus('due_date');
273 if ($_SESSION['Items']->trans_no == 0) {
274 if (!$Refs->is_valid($_POST['ref'])) {
275 display_error(_("You must enter a reference."));
280 if (!is_new_reference($_POST['ref'], 10)) {
281 display_error(_("The entered reference is already in use."));
287 if ($_POST['ChargeFreightCost'] == "") {
288 $_POST['ChargeFreightCost'] = price_format(0);
291 if (!check_num('ChargeFreightCost', 0)) {
292 display_error(_("The entered shipping value is not numeric."));
293 set_focus('ChargeFreightCost');
297 if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
298 display_error(_("There are no item quantities on this invoice."));
302 if (!check_quantities()) {
303 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
310 //-----------------------------------------------------------------------------
311 if (isset($_POST['process_invoice']) && check_data()) {
313 $newinvoice= $_SESSION['Items']->trans_no == 0;
315 if ($newinvoice) new_doc_date($_SESSION['Items']->document_date);
317 $invoice_no = $_SESSION['Items']->write();
321 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
323 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
327 // find delivery spans for batch invoice display
329 $lastdn = ''; $spanlen=1;
331 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
332 $line = $_SESSION['Items']->line_items[$line_no];
333 if ($line->quantity == $line->qty_done) {
336 if ($line->src_no == $lastdn) {
340 $dspans[] = $spanlen;
344 $lastdn = $line->src_no;
346 $dspans[] = $spanlen;
348 //-----------------------------------------------------------------------------
350 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
352 $is_edition = $_SESSION['Items']->trans_type == ST_SALESINVOICE && $_SESSION['Items']->trans_no != 0;
356 start_table("$table_style2 width=80%", 5);
359 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
360 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
361 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
365 if ($_SESSION['Items']->trans_no == 0) {
366 ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'");
368 label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
371 //label_cells(_("Delivery Notes:"),
372 //get_customer_trans_view_str(ST_CUSTDELIVERY, array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
374 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
376 if ($_SESSION['Items']->pos != -1) // editable payment type
377 label_cells(_("Payment terms:"), sale_payment_list('payment'), "class='tableheader2'");
379 label_cells(_('Payment:'), $_SESSION['Items']->payment_terms['terms'], "class='tableheader2'");
384 if (!isset($_POST['ship_via'])) {
385 $_POST['ship_via'] = $_SESSION['Items']->ship_via;
387 label_cell(_("Shipping Company"), "class='tableheader2'");
388 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
390 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
391 $_POST['InvoiceDate'] = new_doc_date();
392 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
393 $_POST['InvoiceDate'] = end_fiscalyear();
397 date_cells(_("Date"), 'InvoiceDate', '', $_SESSION['Items']->trans_no == 0,
398 0, 0, 0, "class='tableheader2'", true);
400 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
401 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_POST['InvoiceDate']);
404 date_cells(_("Due Date"), 'due_date', '', null, 0, 0, 0, "class='tableheader2'");
409 $row = get_customer_to_order($_SESSION['Items']->customer_id);
410 if ($row['dissallow_invoices'] == 1)
412 display_error(_("The selected customer account is currently on hold. Please contact the credit control personnel to discuss."));
418 display_heading(_("Invoice Items"));
421 start_table("$table_style width=80%");
422 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
423 _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
425 if ($is_batch_invoice) {
431 $th[4] = _("Credited");
441 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
442 if ($ln_itm->quantity == $ln_itm->qty_done) {
443 continue; // this line was fully invoiced
445 alt_table_row_color($k);
446 view_stock_status_cell($ln_itm->stock_id);
448 text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
449 $dec = get_qty_dec($ln_itm->stock_id);
450 qty_cell($ln_itm->quantity, false, $dec);
451 label_cell($ln_itm->units);
452 qty_cell($ln_itm->qty_done, false, $dec);
454 if ($is_batch_invoice) {
455 // for batch invoices we can only remove whole deliveries
456 echo '<td nowrap align=right>';
457 hidden('Line' . $line, $ln_itm->qty_dispatched );
458 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
460 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
462 $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
464 $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
466 amount_cell($ln_itm->price);
467 label_cell($ln_itm->tax_type_name);
468 label_cell($display_discount_percent, "nowrap align=right");
469 amount_cell($line_total);
471 if ($is_batch_invoice) {
472 if ($dn_line_cnt == 0) {
473 $dn_line_cnt = $dspans[0];
474 $dspans = array_slice($dspans, 1);
475 label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
476 label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
477 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
484 /*Don't re-calculate freight if some of the order has already been delivered -
485 depending on the business logic required this condition may not be required.
486 It seems unfair to charge the customer twice for freight if the order
487 was not fully delivered the first time ?? */
489 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
490 if ($_SESSION['Items']->any_already_delivered() == 1) {
491 $_POST['ChargeFreightCost'] = price_format(0);
493 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
496 if (!check_num('ChargeFreightCost')) {
497 $_POST['ChargeFreightCost'] = price_format(0);
501 $accumulate_shipping = get_company_pref('accumulate_shipping');
502 if ($is_batch_invoice && $accumulate_shipping)
503 set_delivery_shipping_sum(array_keys($_SESSION['Items']->src_docs));
507 label_cell(_("Shipping Cost"), "colspan=$colspan align=right");
508 small_amount_cells(null, 'ChargeFreightCost', null);
509 if ($is_batch_invoice) {
510 label_cell('', 'colspan=2');
514 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
516 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
518 label_row(_("Sub-total"), $display_sub_total, "colspan=$colspan align=right","align=right", $is_batch_invoice ? 2 : 0);
520 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
521 $tax_total = display_edit_tax_items($taxes, $colspan, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
523 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
525 label_row(_("Invoice Total"), $display_total, "colspan=$colspan align=right","align=right", $is_batch_invoice ? 2 : 0);
530 start_table($table_style2);
531 textarea_row(_("Memo"), 'Comments', null, 50, 4);
535 submit_center_first('Update', _("Update"),
536 _('Refresh document page'), true);
537 submit_center_last('process_invoice', _("Process Invoice"),
538 _('Check entered data and save document'), 'default');