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 $sql = "SELECT trans_type_from, trans_no_from FROM ".TB_PREF."cust_allocations
67 WHERE trans_type_to=".ST_SALESINVOICE." AND trans_no_to=".db_escape($invoice_no);
68 $result = db_query($sql, "could not retrieve customer allocation");
69 $row = db_fetch($result);
72 hyperlink_params("$path_to_root/sales/customer_payments.php", _("Entry &customer payment for this invoice"),
73 "SInvoice=".$invoice_no);
75 hyperlink_params("$path_to_root/admin/attachments.php", _("Add an Attachment"), "filterType=$trans_type&trans_no=$invoice_no");
77 display_footer_exit();
79 } elseif (isset($_GET['UpdatedID'])) {
81 $invoice_no = $_GET['UpdatedID'];
82 $trans_type = ST_SALESINVOICE;
84 display_notification_centered(sprintf(_('Sales Invoice # %d has been updated.'),$invoice_no));
86 display_note(get_trans_view_str(ST_SALESINVOICE, $invoice_no, _("&View This Invoice")));
88 display_note(print_document_link($invoice_no."-".$trans_type, _("&Print This Invoice"), true, ST_SALESINVOICE));
89 display_note(print_document_link($invoice_no."-".$trans_type, _("&Email This Invoice"), true, ST_SALESINVOICE, false, "printlink", "", 1),1);
91 hyperlink_no_params($path_to_root . "/sales/inquiry/customer_inquiry.php", _("Select Another &Invoice to Modify"));
93 display_footer_exit();
95 } elseif (isset($_GET['RemoveDN'])) {
97 for($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
98 $line = &$_SESSION['Items']->line_items[$line_no];
99 if ($line->src_no == $_GET['RemoveDN']) {
100 $line->quantity = $line->qty_done;
101 $line->qty_dispatched=0;
106 // Remove also src_doc delivery note
107 $sources = &$_SESSION['Items']->src_docs;
108 unset($sources[$_GET['RemoveDN']]);
111 //-----------------------------------------------------------------------------
113 if ( (isset($_GET['DeliveryNumber']) && ($_GET['DeliveryNumber'] > 0) )
114 || isset($_GET['BatchInvoice'])) {
118 if (isset($_GET['BatchInvoice'])) {
119 $src = $_SESSION['DeliveryBatch'];
120 unset($_SESSION['DeliveryBatch']);
122 $src = array($_GET['DeliveryNumber']);
125 /*read in all the selected deliveries into the Items cart */
126 $dn = new Cart(ST_CUSTDELIVERY, $src, true);
128 if ($dn->count_items() == 0) {
129 hyperlink_params($path_to_root . "/sales/inquiry/sales_deliveries_view.php",
130 _("Select a different delivery to invoice"), "OutstandingOnly=1");
131 die ("<br><b>" . _("There are no delivered items with a quantity left to invoice. There is nothing left to invoice.") . "</b>");
134 $_SESSION['Items'] = $dn;
137 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
139 if ( get_sales_parent_numbers(ST_SALESINVOICE, $_GET['ModifyInvoice']) == 0) { // 1.xx compatibility hack
140 echo"<center><br><b>" . _("There are no delivery notes for this invoice.<br>
141 Most likely this invoice was created in Front Accounting version prior to 2.0
142 and therefore can not be modified.") . "</b></center>";
143 display_footer_exit();
146 $_SESSION['Items'] = new Cart(ST_SALESINVOICE, $_GET['ModifyInvoice']);
148 if ($_SESSION['Items']->count_items() == 0) {
149 echo"<center><br><b>" . _("All quantities on this invoice has been credited. There is nothing to modify on this invoice") . "</b></center>";
150 display_footer_exit();
153 } elseif (!processing_active()) {
154 /* This page can only be called with a delivery for invoicing or invoice no for edit */
155 display_error(_("This page can only be opened after delivery selection. Please select delivery to invoicing first."));
157 hyperlink_no_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Delivery to Invoice"));
161 } elseif (!isset($_POST['process_invoice']) && !check_quantities()) {
162 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
164 if (isset($_POST['Update'])) {
165 $Ajax->activate('Items');
167 if (isset($_POST['_InvoiceDate_changed'])) {
168 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_POST['InvoiceDate']);
169 $Ajax->activate('due_date');
171 if (list_updated('payment')) {
172 $_SESSION['Items']->payment = get_post('payment');
173 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_POST['InvoiceDate']);
174 $Ajax->activate('due_date');
177 //-----------------------------------------------------------------------------
178 function check_quantities()
181 foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
182 if (isset($_POST['Line'.$line_no])) {
183 if($_SESSION['Items']->trans_no) {
184 $min = $itm->qty_done;
185 $max = $itm->quantity;
188 $max = $itm->quantity - $itm->qty_done;
190 if (check_num('Line'.$line_no, $min, $max)) {
191 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
192 input_num('Line'.$line_no);
200 if (isset($_POST['Line'.$line_no.'Desc'])) {
201 $line_desc = $_POST['Line'.$line_no.'Desc'];
202 if (strlen($line_desc) > 0) {
203 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
210 function set_delivery_shipping_sum($delivery_notes)
215 foreach($delivery_notes as $delivery_num)
217 $myrow = get_customer_trans($delivery_num, 13);
218 //$branch = get_branch($myrow["branch_code"]);
219 //$sales_order = get_sales_order_header($myrow["order_"]);
221 //$shipping += $sales_order['freight_cost'];
222 $shipping += $myrow['ov_freight'];
224 $_POST['ChargeFreightCost'] = price_format($shipping);
228 function copy_to_cart()
230 $cart = &$_SESSION['Items'];
231 $cart->ship_via = $_POST['ship_via'];
232 $cart->freight_cost = input_num('ChargeFreightCost');
233 $cart->document_date = $_POST['InvoiceDate'];
234 $cart->due_date = $_POST['due_date'];
235 if ($cart->pos['cash_sale'] || $cart->pos['credit_sale']) {
236 $cart->payment = $_POST['payment'];
237 $cart->payment_terms = get_payment_terms($_POST['payment']);
239 $cart->Comments = $_POST['Comments'];
240 if ($_SESSION['Items']->trans_no == 0)
241 $cart->reference = $_POST['ref'];
242 $cart->dimension_id = $_POST['dimension_id'];
243 $cart->dimension2_id = $_POST['dimension2_id'];
246 //-----------------------------------------------------------------------------
248 function copy_from_cart()
250 $cart = &$_SESSION['Items'];
251 $_POST['ship_via'] = $cart->ship_via;
252 $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
253 $_POST['InvoiceDate']= $cart->document_date;
254 $_POST['due_date'] = $cart->due_date;
255 $_POST['Comments']= $cart->Comments;
256 $_POST['cart_id'] = $cart->cart_id;
257 $_POST['ref'] = $cart->reference;
258 $_POST['payment'] = $cart->payment;
259 $_POST['dimension_id'] = $cart->dimension_id;
260 $_POST['dimension2_id'] = $cart->dimension2_id;
263 //-----------------------------------------------------------------------------
265 function check_data()
269 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
270 display_error(_("The entered invoice date is invalid."));
271 set_focus('InvoiceDate');
275 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
276 display_error(_("The entered invoice date is not in fiscal year."));
277 set_focus('InvoiceDate');
281 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
282 display_error(_("The entered invoice due date is invalid."));
283 set_focus('due_date');
287 if ($_SESSION['Items']->trans_no == 0) {
288 if (!$Refs->is_valid($_POST['ref'])) {
289 display_error(_("You must enter a reference."));
295 if ($_POST['ChargeFreightCost'] == "") {
296 $_POST['ChargeFreightCost'] = price_format(0);
299 if (!check_num('ChargeFreightCost', 0)) {
300 display_error(_("The entered shipping value is not numeric."));
301 set_focus('ChargeFreightCost');
305 if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
306 display_error(_("There are no item quantities on this invoice."));
310 if (!check_quantities()) {
311 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
318 //-----------------------------------------------------------------------------
319 if (isset($_POST['process_invoice']) && check_data()) {
320 $newinvoice= $_SESSION['Items']->trans_no == 0;
323 new_doc_date($_SESSION['Items']->document_date);
325 $invoice_no = $_SESSION['Items']->write();
326 if ($invoice_no == -1)
328 display_error(_("The entered reference is already in use."));
336 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
338 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
343 if(list_updated('payment')) {
344 $order = &$_SESSION['Items'];
345 $order->payment = get_post('payment');
346 $order->payment_terms = get_payment_terms($order->payment);
347 $order->due_date = get_invoice_duedate($order->payment, $order->document_date);
348 if ($order->payment_terms['cash_sale']) {
349 $_POST['Location'] = $order->Location = $order->pos['pos_location'];
350 $order->location_name = $order->pos['location_name'];
353 // find delivery spans for batch invoice display
355 $lastdn = ''; $spanlen=1;
357 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
358 $line = $_SESSION['Items']->line_items[$line_no];
359 if ($line->quantity == $line->qty_done) {
362 if ($line->src_no == $lastdn) {
366 $dspans[] = $spanlen;
370 $lastdn = $line->src_no;
372 $dspans[] = $spanlen;
374 //-----------------------------------------------------------------------------
376 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
378 $is_edition = $_SESSION['Items']->trans_type == ST_SALESINVOICE && $_SESSION['Items']->trans_no != 0;
382 start_table(TABLESTYLE2, "width='80%'", 5);
386 $dim = get_company_pref('use_dimension');
389 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
390 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
391 if ($_SESSION['Items']->pos['credit_sale'] || $_SESSION['Items']->pos['cash_sale']) {
392 $paymcat = !$_SESSION['Items']->pos['cash_sale'] ? PM_CREDIT :
393 (!$_SESSION['Items']->pos['credit_sale'] ? PM_CASH : PM_ANY);
394 label_cells(_("Payment terms:"), sale_payment_list('payment', $paymcat),
395 "class='tableheader2'", "colspan=$colspan");
397 label_cells(_('Payment:'), $_SESSION['Items']->payment_terms['terms'], "class='tableheader2'", "colspan=$colspan");
402 if ($_SESSION['Items']->trans_no == 0) {
403 ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'");
405 label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
408 //label_cells(_("Delivery Notes:"),
409 //get_customer_trans_view_str(ST_CUSTDELIVERY, array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
411 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
413 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
414 // 2010-09-03 Joe Hunt
416 // label_cells(_("Dimension"), get_dimension_string($_SESSION['Items']->dimension_id), "class='tableheader2'");
418 label_cell(_("Dimension").":", "class='tableheader2'");
419 $_POST['dimension_id'] = $_SESSION['Items']->dimension_id;
420 dimensions_list_cells(null, 'dimension_id', null, true, ' ', false, 1, false);
423 hidden('dimension_id', 0);
428 if (!isset($_POST['ship_via'])) {
429 $_POST['ship_via'] = $_SESSION['Items']->ship_via;
431 label_cell(_("Shipping Company"), "class='tableheader2'");
432 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
434 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
435 $_POST['InvoiceDate'] = new_doc_date();
436 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
437 $_POST['InvoiceDate'] = end_fiscalyear();
441 date_cells(_("Date"), 'InvoiceDate', '', $_SESSION['Items']->trans_no == 0,
442 0, 0, 0, "class='tableheader2'", true);
444 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
445 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_POST['InvoiceDate']);
448 date_cells(_("Due Date"), 'due_date', '', null, 0, 0, 0, "class='tableheader2'");
451 label_cells(_("Dimension"). " 2", get_dimension_string($_SESSION['Items']->dimension2_id), "class='tableheader2'");
453 label_cell(" ", "colspan=2");
456 label_cell(_("Dimension")." 2:", "class='tableheader2'");
457 $_POST['dimension2_id'] = $_SESSION['Items']->dimension2_id;
458 dimensions_list_cells(null, 'dimension2_id', null, true, ' ', false, 2, false);
461 hidden('dimension2_id', 0);
465 $row = get_customer_to_order($_SESSION['Items']->customer_id);
466 if ($row['dissallow_invoices'] == 1)
468 display_error(_("The selected customer account is currently on hold. Please contact the credit control personnel to discuss."));
474 display_heading(_("Invoice Items"));
477 start_table(TABLESTYLE, "width='80%'");
478 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
479 _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
481 if ($is_batch_invoice) {
487 $th[4] = _("Credited");
497 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
498 if ($ln_itm->quantity == $ln_itm->qty_done) {
499 continue; // this line was fully invoiced
501 alt_table_row_color($k);
502 view_stock_status_cell($ln_itm->stock_id);
504 text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
505 $dec = get_qty_dec($ln_itm->stock_id);
506 qty_cell($ln_itm->quantity, false, $dec);
507 label_cell($ln_itm->units);
508 qty_cell($ln_itm->qty_done, false, $dec);
510 if ($is_batch_invoice) {
511 // for batch invoices we can only remove whole deliveries
512 echo '<td nowrap align=right>';
513 hidden('Line' . $line, $ln_itm->qty_dispatched );
514 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
516 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
518 $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
520 $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
522 amount_cell($ln_itm->price);
523 label_cell($ln_itm->tax_type_name);
524 label_cell($display_discount_percent, "nowrap align=right");
525 amount_cell($line_total);
527 if ($is_batch_invoice) {
528 if ($dn_line_cnt == 0) {
529 $dn_line_cnt = $dspans[0];
530 $dspans = array_slice($dspans, 1);
531 label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class='oddrow'");
532 label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
533 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class='oddrow'");
540 /*Don't re-calculate freight if some of the order has already been delivered -
541 depending on the business logic required this condition may not be required.
542 It seems unfair to charge the customer twice for freight if the order
543 was not fully delivered the first time ?? */
545 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
546 if ($_SESSION['Items']->any_already_delivered() == 1) {
547 $_POST['ChargeFreightCost'] = price_format(0);
549 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
552 if (!check_num('ChargeFreightCost')) {
553 $_POST['ChargeFreightCost'] = price_format(0);
557 $accumulate_shipping = get_company_pref('accumulate_shipping');
558 if ($is_batch_invoice && $accumulate_shipping)
559 set_delivery_shipping_sum(array_keys($_SESSION['Items']->src_docs));
563 label_cell(_("Shipping Cost"), "colspan=$colspan align=right");
564 small_amount_cells(null, 'ChargeFreightCost', null);
565 if ($is_batch_invoice) {
566 label_cell('', 'colspan=2');
570 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
572 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
574 label_row(_("Sub-total"), $display_sub_total, "colspan=$colspan align=right","align=right", $is_batch_invoice ? 2 : 0);
576 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
577 $tax_total = display_edit_tax_items($taxes, $colspan, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
579 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
581 label_row(_("Invoice Total"), $display_total, "colspan=$colspan align=right","align=right", $is_batch_invoice ? 2 : 0);
586 start_table(TABLESTYLE2);
587 textarea_row(_("Memo"), 'Comments', null, 50, 4);
591 submit_center_first('Update', _("Update"),
592 _('Refresh document page'), true);
593 submit_center_last('process_invoice', _("Process Invoice"),
594 _('Check entered data and save document'), 'default');