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."-".$trans_type, _("&Print This Invoice"), true, ST_SALESINVOICE));
60 display_note(print_document_link($invoice_no."-".$trans_type, _("&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 hyperlink_params("$path_to_root/admin/attachments.php", _("Add an Attachment"), "filterType=$trans_type&trans_no=$invoice_no");
68 display_footer_exit();
70 } elseif (isset($_GET['UpdatedID'])) {
72 $invoice_no = $_GET['UpdatedID'];
73 $trans_type = ST_SALESINVOICE;
75 display_notification_centered(sprintf(_('Sales Invoice # %d has been updated.'),$invoice_no));
77 display_note(get_trans_view_str(ST_SALESINVOICE, $invoice_no, _("&View This Invoice")));
79 display_note(print_document_link($invoice_no."-".$trans_type, _("&Print This Invoice"), true, ST_SALESINVOICE));
80 display_note(print_document_link($invoice_no."-".$trans_type, _("&Email This Invoice"), true, ST_SALESINVOICE, false, "printlink", "", 1),1);
82 hyperlink_no_params($path_to_root . "/sales/inquiry/customer_inquiry.php", _("Select Another &Invoice to Modify"));
84 display_footer_exit();
86 } elseif (isset($_GET['RemoveDN'])) {
88 for($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
89 $line = &$_SESSION['Items']->line_items[$line_no];
90 if ($line->src_no == $_GET['RemoveDN']) {
91 $line->quantity = $line->qty_done;
92 $line->qty_dispatched=0;
97 // Remove also src_doc delivery note
98 $sources = &$_SESSION['Items']->src_docs;
99 unset($sources[$_GET['RemoveDN']]);
102 //-----------------------------------------------------------------------------
104 if ( (isset($_GET['DeliveryNumber']) && ($_GET['DeliveryNumber'] > 0) )
105 || isset($_GET['BatchInvoice'])) {
109 if (isset($_GET['BatchInvoice'])) {
110 $src = $_SESSION['DeliveryBatch'];
111 unset($_SESSION['DeliveryBatch']);
113 $src = array($_GET['DeliveryNumber']);
116 /*read in all the selected deliveries into the Items cart */
117 $dn = new Cart(ST_CUSTDELIVERY, $src, true);
119 if ($dn->count_items() == 0) {
120 hyperlink_params($path_to_root . "/sales/inquiry/sales_deliveries_view.php",
121 _("Select a different delivery to invoice"), "OutstandingOnly=1");
122 die ("<br><b>" . _("There are no delivered items with a quantity left to invoice. There is nothing left to invoice.") . "</b>");
125 $_SESSION['Items'] = $dn;
128 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
130 if ( get_sales_parent_numbers(ST_SALESINVOICE, $_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(ST_SALESINVOICE, $_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 (!isset($_POST['process_invoice']) && !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']->payment, $_POST['InvoiceDate']);
160 $Ajax->activate('due_date');
162 if (list_updated('payment')) {
163 $_SESSION['Items']->payment = get_post('payment');
164 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_POST['InvoiceDate']);
165 $Ajax->activate('due_date');
168 //-----------------------------------------------------------------------------
169 function check_quantities()
172 foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
173 if (isset($_POST['Line'.$line_no])) {
174 if($_SESSION['Items']->trans_no) {
175 $min = $itm->qty_done;
176 $max = $itm->quantity;
179 $max = $itm->quantity - $itm->qty_done;
181 if (check_num('Line'.$line_no, $min, $max)) {
182 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
183 input_num('Line'.$line_no);
191 if (isset($_POST['Line'.$line_no.'Desc'])) {
192 $line_desc = $_POST['Line'.$line_no.'Desc'];
193 if (strlen($line_desc) > 0) {
194 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
201 function set_delivery_shipping_sum($delivery_notes)
206 foreach($delivery_notes as $delivery_num)
208 $myrow = get_customer_trans($delivery_num, 13);
209 //$branch = get_branch($myrow["branch_code"]);
210 //$sales_order = get_sales_order_header($myrow["order_"]);
212 //$shipping += $sales_order['freight_cost'];
213 $shipping += $myrow['ov_freight'];
215 $_POST['ChargeFreightCost'] = price_format($shipping);
219 function copy_to_cart()
221 $cart = &$_SESSION['Items'];
222 $cart->ship_via = $_POST['ship_via'];
223 $cart->freight_cost = input_num('ChargeFreightCost');
224 $cart->document_date = $_POST['InvoiceDate'];
225 $cart->due_date = $_POST['due_date'];
226 if ($cart->pos['cash_sale'] || $cart->pos['credit_sale']) {
227 $cart->payment = $_POST['payment'];
228 $cart->payment_terms = get_payment_terms($_POST['payment']);
230 $cart->Comments = $_POST['Comments'];
231 if ($_SESSION['Items']->trans_no == 0)
232 $cart->reference = $_POST['ref'];
233 $cart->dimension_id = $_POST['dimension_id'];
234 $cart->dimension2_id = $_POST['dimension2_id'];
237 //-----------------------------------------------------------------------------
239 function copy_from_cart()
241 $cart = &$_SESSION['Items'];
242 $_POST['ship_via'] = $cart->ship_via;
243 $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
244 $_POST['InvoiceDate']= $cart->document_date;
245 $_POST['due_date'] = $cart->due_date;
246 $_POST['Comments']= $cart->Comments;
247 $_POST['cart_id'] = $cart->cart_id;
248 $_POST['ref'] = $cart->reference;
249 $_POST['payment'] = $cart->payment;
250 $_POST['dimension_id'] = $cart->dimension_id;
251 $_POST['dimension2_id'] = $cart->dimension2_id;
254 //-----------------------------------------------------------------------------
256 function check_data()
260 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
261 display_error(_("The entered invoice date is invalid."));
262 set_focus('InvoiceDate');
266 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
267 display_error(_("The entered invoice date is not in fiscal year."));
268 set_focus('InvoiceDate');
272 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
273 display_error(_("The entered invoice due date is invalid."));
274 set_focus('due_date');
278 if ($_SESSION['Items']->trans_no == 0) {
279 if (!$Refs->is_valid($_POST['ref'])) {
280 display_error(_("You must enter a reference."));
285 if (!is_new_reference($_POST['ref'], 10)) {
286 display_error(_("The entered reference is already in use."));
292 if ($_POST['ChargeFreightCost'] == "") {
293 $_POST['ChargeFreightCost'] = price_format(0);
296 if (!check_num('ChargeFreightCost', 0)) {
297 display_error(_("The entered shipping value is not numeric."));
298 set_focus('ChargeFreightCost');
302 if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
303 display_error(_("There are no item quantities on this invoice."));
307 if (!check_quantities()) {
308 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
315 //-----------------------------------------------------------------------------
316 if (isset($_POST['process_invoice']) && check_data()) {
318 $newinvoice= $_SESSION['Items']->trans_no == 0;
320 if ($newinvoice) new_doc_date($_SESSION['Items']->document_date);
322 $invoice_no = $_SESSION['Items']->write();
326 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
328 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
332 if(list_updated('payment')) {
333 $order = &$_SESSION['Items'];
334 $order->payment = get_post('payment');
335 $order->payment_terms = get_payment_terms($order->payment);
336 $order->due_date = get_invoice_duedate($order->payment, $order->document_date);
337 if ($order->payment_terms['cash_sale']) {
338 $_POST['Location'] = $order->Location = $order->pos['pos_location'];
339 $order->location_name = $order->pos['location_name'];
342 // find delivery spans for batch invoice display
344 $lastdn = ''; $spanlen=1;
346 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
347 $line = $_SESSION['Items']->line_items[$line_no];
348 if ($line->quantity == $line->qty_done) {
351 if ($line->src_no == $lastdn) {
355 $dspans[] = $spanlen;
359 $lastdn = $line->src_no;
361 $dspans[] = $spanlen;
363 //-----------------------------------------------------------------------------
365 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
367 $is_edition = $_SESSION['Items']->trans_type == ST_SALESINVOICE && $_SESSION['Items']->trans_no != 0;
371 start_table(TABLESTYLE2, "width=80%", 5);
375 $dim = get_company_pref('use_dimension');
378 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
379 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
380 if ($_SESSION['Items']->pos['credit_sale'] || $_SESSION['Items']->pos['cash_sale']) {
381 $paymcat = !$_SESSION['Items']->pos['cash_sale'] ? PM_CREDIT :
382 (!$_SESSION['Items']->pos['credit_sale'] ? PM_CASH : PM_ANY);
383 label_cells(_("Payment terms:"), sale_payment_list('payment', $paymcat),
384 "class='tableheader2'", "colspan=$colspan");
386 label_cells(_('Payment:'), $_SESSION['Items']->payment_terms['terms'], "class='tableheader2'", "colspan=$colspan");
391 if ($_SESSION['Items']->trans_no == 0) {
392 ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'");
394 label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
397 //label_cells(_("Delivery Notes:"),
398 //get_customer_trans_view_str(ST_CUSTDELIVERY, array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
400 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
402 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
403 // 2010-09-03 Joe Hunt
405 // label_cells(_("Dimension"), get_dimension_string($_SESSION['Items']->dimension_id), "class='tableheader2'");
407 label_cell(_("Dimension").":", "class='tableheader2'");
408 $_POST['dimension_id'] = $_SESSION['Items']->dimension_id;
409 dimensions_list_cells(null, 'dimension_id', null, true, ' ', false, 1, false);
412 hidden('dimension_id', 0);
417 if (!isset($_POST['ship_via'])) {
418 $_POST['ship_via'] = $_SESSION['Items']->ship_via;
420 label_cell(_("Shipping Company"), "class='tableheader2'");
421 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
423 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
424 $_POST['InvoiceDate'] = new_doc_date();
425 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
426 $_POST['InvoiceDate'] = end_fiscalyear();
430 date_cells(_("Date"), 'InvoiceDate', '', $_SESSION['Items']->trans_no == 0,
431 0, 0, 0, "class='tableheader2'", true);
433 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
434 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_POST['InvoiceDate']);
437 date_cells(_("Due Date"), 'due_date', '', null, 0, 0, 0, "class='tableheader2'");
440 label_cells(_("Dimension"). " 2", get_dimension_string($_SESSION['Items']->dimension2_id), "class='tableheader2'");
442 label_cell(" ", "colspan=2");
445 label_cell(_("Dimension")." 2:", "class='tableheader2'");
446 $_POST['dimension2_id'] = $_SESSION['Items']->dimension2_id;
447 dimensions_list_cells(null, 'dimension2_id', null, true, ' ', false, 2, false);
450 hidden('dimension2_id', 0);
454 $row = get_customer_to_order($_SESSION['Items']->customer_id);
455 if ($row['dissallow_invoices'] == 1)
457 display_error(_("The selected customer account is currently on hold. Please contact the credit control personnel to discuss."));
463 display_heading(_("Invoice Items"));
466 start_table(TABLESTYLE, "width=80%");
467 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
468 _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
470 if ($is_batch_invoice) {
476 $th[4] = _("Credited");
486 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
487 if ($ln_itm->quantity == $ln_itm->qty_done) {
488 continue; // this line was fully invoiced
490 alt_table_row_color($k);
491 view_stock_status_cell($ln_itm->stock_id);
493 text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
494 $dec = get_qty_dec($ln_itm->stock_id);
495 qty_cell($ln_itm->quantity, false, $dec);
496 label_cell($ln_itm->units);
497 qty_cell($ln_itm->qty_done, false, $dec);
499 if ($is_batch_invoice) {
500 // for batch invoices we can only remove whole deliveries
501 echo '<td nowrap align=right>';
502 hidden('Line' . $line, $ln_itm->qty_dispatched );
503 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
505 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
507 $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
509 $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
511 amount_cell($ln_itm->price);
512 label_cell($ln_itm->tax_type_name);
513 label_cell($display_discount_percent, "nowrap align=right");
514 amount_cell($line_total);
516 if ($is_batch_invoice) {
517 if ($dn_line_cnt == 0) {
518 $dn_line_cnt = $dspans[0];
519 $dspans = array_slice($dspans, 1);
520 label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
521 label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
522 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
529 /*Don't re-calculate freight if some of the order has already been delivered -
530 depending on the business logic required this condition may not be required.
531 It seems unfair to charge the customer twice for freight if the order
532 was not fully delivered the first time ?? */
534 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
535 if ($_SESSION['Items']->any_already_delivered() == 1) {
536 $_POST['ChargeFreightCost'] = price_format(0);
538 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
541 if (!check_num('ChargeFreightCost')) {
542 $_POST['ChargeFreightCost'] = price_format(0);
546 $accumulate_shipping = get_company_pref('accumulate_shipping');
547 if ($is_batch_invoice && $accumulate_shipping)
548 set_delivery_shipping_sum(array_keys($_SESSION['Items']->src_docs));
552 label_cell(_("Shipping Cost"), "colspan=$colspan align=right");
553 small_amount_cells(null, 'ChargeFreightCost', null);
554 if ($is_batch_invoice) {
555 label_cell('', 'colspan=2');
559 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
561 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
563 label_row(_("Sub-total"), $display_sub_total, "colspan=$colspan align=right","align=right", $is_batch_invoice ? 2 : 0);
565 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
566 $tax_total = display_edit_tax_items($taxes, $colspan, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
568 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
570 label_row(_("Invoice Total"), $display_total, "colspan=$colspan align=right","align=right", $is_batch_invoice ? 2 : 0);
575 start_table(TABLESTYLE2);
576 textarea_row(_("Memo"), 'Comments', null, 50, 4);
580 submit_center_first('Update', _("Update"),
581 _('Refresh document page'), true);
582 submit_center_last('process_invoice', _("Process Invoice"),
583 _('Check entered data and save document'), 'default');