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 . "/sales/includes/sales_db.inc");
23 include_once($path_to_root . "/sales/includes/sales_ui.inc");
24 include_once($path_to_root . "/reporting/includes/reporting.inc");
25 include_once($path_to_root . "/taxes/tax_calc.inc");
26 include_once($path_to_root . "/admin/db/shipping_db.inc");
29 if ($SysPrefs->use_popup_windows) {
30 $js .= get_js_open_window(900, 500);
32 if (user_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");
43 } elseif (isset($_GET['AllocationNumber']) || isset($_GET['InvoicePrepayments'])) {
44 $_SESSION['page_title'] = _($help_context = "Prepayment or Final Invoice Entry");
46 page($_SESSION['page_title'], false, false, "", $js);
48 //-----------------------------------------------------------------------------
50 check_edit_conflicts(get_post('cart_id'));
52 if (isset($_GET['AddedID'])) {
54 $invoice_no = $_GET['AddedID'];
55 $trans_type = ST_SALESINVOICE;
57 display_notification(_("Selected deliveries has been processed"), true);
59 display_note(get_customer_trans_view_str($trans_type, $invoice_no, _("&View This Invoice")), 0, 1);
61 display_note(print_document_link($invoice_no."-".$trans_type, _("&Print This Invoice"), true, ST_SALESINVOICE));
62 display_note(print_document_link($invoice_no."-".$trans_type, _("&Email This Invoice"), true, ST_SALESINVOICE, false, "printlink", "", 1),1);
64 display_note(get_gl_view_str($trans_type, $invoice_no, _("View the GL &Journal Entries for this Invoice")),1);
66 hyperlink_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Another &Delivery For Invoicing"), "OutstandingOnly=1");
68 if (!db_num_rows(get_allocatable_from_cust_transactions(null, $invoice_no, $trans_type)))
69 hyperlink_params("$path_to_root/sales/customer_payments.php", _("Entry &customer payment for this invoice"),
70 "SInvoice=".$invoice_no);
72 hyperlink_params("$path_to_root/admin/attachments.php", _("Add an Attachment"), "filterType=$trans_type&trans_no=$invoice_no");
74 display_footer_exit();
76 } elseif (isset($_GET['UpdatedID'])) {
78 $invoice_no = $_GET['UpdatedID'];
79 $trans_type = ST_SALESINVOICE;
81 display_notification_centered(sprintf(_('Sales Invoice # %d has been updated.'),$invoice_no));
83 display_note(get_trans_view_str(ST_SALESINVOICE, $invoice_no, _("&View This Invoice")));
85 display_note(print_document_link($invoice_no."-".$trans_type, _("&Print This Invoice"), true, ST_SALESINVOICE));
86 display_note(print_document_link($invoice_no."-".$trans_type, _("&Email This Invoice"), true, ST_SALESINVOICE, false, "printlink", "", 1),1);
88 hyperlink_no_params($path_to_root . "/sales/inquiry/customer_inquiry.php", _("Select Another &Invoice to Modify"));
90 display_footer_exit();
92 } elseif (isset($_GET['RemoveDN'])) {
94 for($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
95 $line = &$_SESSION['Items']->line_items[$line_no];
96 if ($line->src_no == $_GET['RemoveDN']) {
97 $line->quantity = $line->qty_done;
98 $line->qty_dispatched=0;
103 // Remove also src_doc delivery note
104 $sources = &$_SESSION['Items']->src_docs;
105 unset($sources[$_GET['RemoveDN']]);
108 //-----------------------------------------------------------------------------
110 if ( (isset($_GET['DeliveryNumber']) && ($_GET['DeliveryNumber'] > 0) )
111 || isset($_GET['BatchInvoice'])) {
115 if (isset($_GET['BatchInvoice'])) {
116 $src = $_SESSION['DeliveryBatch'];
117 unset($_SESSION['DeliveryBatch']);
119 $src = array($_GET['DeliveryNumber']);
122 /*read in all the selected deliveries into the Items cart */
123 $dn = new Cart(ST_CUSTDELIVERY, $src, true);
125 if ($dn->count_items() == 0) {
126 hyperlink_params($path_to_root . "/sales/inquiry/sales_deliveries_view.php",
127 _("Select a different delivery to invoice"), "OutstandingOnly=1");
128 die ("<br><b>" . _("There are no delivered items with a quantity left to invoice. There is nothing left to invoice.") . "</b>");
131 $_SESSION['Items'] = $dn;
134 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
136 check_is_editable(ST_SALESINVOICE, $_GET['ModifyInvoice']);
139 $_SESSION['Items'] = new Cart(ST_SALESINVOICE, $_GET['ModifyInvoice']);
141 if ($_SESSION['Items']->count_items() == 0) {
142 echo"<center><br><b>" . _("All quantities on this invoice has been credited. There is nothing to modify on this invoice") . "</b></center>";
143 display_footer_exit();
146 } elseif (isset($_GET['AllocationNumber']) || isset($_GET['InvoicePrepayments'])) {
148 check_deferred_income_act(_("You have to set Deferred Income Account in GL Setup to entry prepayment invoices."));
150 if (isset($_GET['AllocationNumber']))
152 $payments = array(get_cust_allocation($_GET['AllocationNumber']));
154 if (!$payments || ($payments[0]['trans_type_to'] != ST_SALESORDER))
156 display_error(_("Please select correct Sales Order Prepayment to be invoiced and try again."));
157 display_footer_exit();
159 $order_no = $payments[0]['trans_no_to'];
162 $order_no = $_GET['InvoicePrepayments'];
166 $_SESSION['Items'] = new cart(ST_SALESORDER, $order_no, ST_SALESINVOICE);
167 $_SESSION['Items']->order_no = $order_no;
168 $_SESSION['Items']->src_docs = array($order_no);
169 $_SESSION['Items']->trans_no = 0;
170 $_SESSION['Items']->trans_type = ST_SALESINVOICE;
172 $_SESSION['Items']->update_payments();
176 elseif (!processing_active()) {
177 /* This page can only be called with a delivery for invoicing or invoice no for edit */
178 display_error(_("This page can only be opened after delivery selection. Please select delivery to invoicing first."));
180 hyperlink_no_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Delivery to Invoice"));
184 } elseif (!isset($_POST['process_invoice']) && (!$_SESSION['Items']->is_prepaid() && !check_quantities())) {
185 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
188 if (isset($_POST['Update'])) {
189 $Ajax->activate('Items');
191 if (isset($_POST['_InvoiceDate_changed'])) {
192 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_POST['InvoiceDate']);
193 $Ajax->activate('due_date');
196 //-----------------------------------------------------------------------------
197 function check_quantities()
200 foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
201 if (isset($_POST['Line'.$line_no])) {
202 if($_SESSION['Items']->trans_no) {
203 $min = $itm->qty_done;
204 $max = $itm->quantity;
207 $max = $itm->quantity - $itm->qty_done;
209 if (check_num('Line'.$line_no, $min, $max)) {
210 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
211 input_num('Line'.$line_no);
219 if (isset($_POST['Line'.$line_no.'Desc'])) {
220 $line_desc = $_POST['Line'.$line_no.'Desc'];
221 if (strlen($line_desc) > 0) {
222 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
229 function set_delivery_shipping_sum($delivery_notes)
234 foreach($delivery_notes as $delivery_num)
236 $myrow = get_customer_trans($delivery_num, ST_CUSTDELIVERY);
238 $shipping += $myrow['ov_freight'];
240 $_POST['ChargeFreightCost'] = price_format($shipping);
244 function copy_to_cart()
246 $cart = &$_SESSION['Items'];
247 $cart->due_date = $cart->document_date = $_POST['InvoiceDate'];
248 $cart->Comments = $_POST['Comments'];
249 $cart->due_date = $_POST['due_date'];
250 if (($cart->pos['cash_sale'] || $cart->pos['credit_sale']) && isset($_POST['payment'])) {
251 $cart->payment = $_POST['payment'];
252 $cart->payment_terms = get_payment_terms($_POST['payment']);
254 if ($_SESSION['Items']->trans_no == 0)
255 $cart->reference = $_POST['ref'];
256 if (!$cart->is_prepaid())
258 $cart->ship_via = $_POST['ship_via'];
259 $cart->freight_cost = input_num('ChargeFreightCost');
262 $cart->update_payments();
264 $cart->dimension_id = $_POST['dimension_id'];
265 $cart->dimension2_id = $_POST['dimension2_id'];
267 //-----------------------------------------------------------------------------
269 function copy_from_cart()
271 $cart = &$_SESSION['Items'];
272 $_POST['Comments']= $cart->Comments;
273 $_POST['InvoiceDate']= $cart->document_date;
274 $_POST['ref'] = $cart->reference;
275 $_POST['cart_id'] = $cart->cart_id;
276 $_POST['due_date'] = $cart->due_date;
277 $_POST['payment'] = $cart->payment;
278 if (!$_SESSION['Items']->is_prepaid())
280 $_POST['ship_via'] = $cart->ship_via;
281 $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
283 $_POST['dimension_id'] = $cart->dimension_id;
284 $_POST['dimension2_id'] = $cart->dimension2_id;
287 //-----------------------------------------------------------------------------
289 function check_data()
293 $prepaid = $_SESSION['Items']->is_prepaid();
295 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
296 display_error(_("The entered invoice date is invalid."));
297 set_focus('InvoiceDate');
301 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
302 display_error(_("The entered date is out of fiscal year or is closed for further data entry."));
303 set_focus('InvoiceDate');
308 if (!$prepaid &&(!isset($_POST['due_date']) || !is_date($_POST['due_date']))) {
309 display_error(_("The entered invoice due date is invalid."));
310 set_focus('due_date');
314 if ($_SESSION['Items']->trans_no == 0) {
315 if (!$Refs->is_valid($_POST['ref'], ST_SALESINVOICE)) {
316 display_error(_("You must enter a reference."));
324 if ($_POST['ChargeFreightCost'] == "") {
325 $_POST['ChargeFreightCost'] = price_format(0);
328 if (!check_num('ChargeFreightCost', 0)) {
329 display_error(_("The entered shipping value is not numeric."));
330 set_focus('ChargeFreightCost');
334 if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
335 display_error(_("There are no item quantities on this invoice."));
339 if (!check_quantities()) {
340 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
344 if (($_SESSION['Items']->payment_terms['days_before_due'] == -1) && !count($_SESSION['Items']->prepayments)) {
345 display_error(_("There is no non-invoiced payments for this order. If you want to issue final invoice, select delayed or cash payment terms."));
353 //-----------------------------------------------------------------------------
354 if (isset($_POST['process_invoice']) && check_data()) {
355 $newinvoice= $_SESSION['Items']->trans_no == 0;
359 new_doc_date($_SESSION['Items']->document_date);
361 $invoice_no = $_SESSION['Items']->write();
362 if ($invoice_no == -1)
364 display_error(_("The entered reference is already in use."));
372 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
374 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
379 if(list_updated('payment')) {
380 $order = &$_SESSION['Items'];
382 $order->payment = get_post('payment');
383 $order->payment_terms = get_payment_terms($order->payment);
384 $_POST['due_date'] = $order->due_date = get_invoice_duedate($order->payment, $order->document_date);
385 $_POST['Comments'] = '';
386 $Ajax->activate('due_date');
387 $Ajax->activate('options');
388 if ($order->payment_terms['cash_sale']) {
389 $_POST['Location'] = $order->Location = $order->pos['pos_location'];
390 $order->location_name = $order->pos['location_name'];
394 // find delivery spans for batch invoice display
396 $lastdn = ''; $spanlen=1;
398 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
399 $line = $_SESSION['Items']->line_items[$line_no];
400 if ($line->quantity == $line->qty_done) {
403 if ($line->src_no == $lastdn) {
407 $dspans[] = $spanlen;
411 $lastdn = $line->src_no;
413 $dspans[] = $spanlen;
415 //-----------------------------------------------------------------------------
417 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
418 $prepaid = $_SESSION['Items']->is_prepaid();
420 $is_edition = $_SESSION['Items']->trans_type == ST_SALESINVOICE && $_SESSION['Items']->trans_no != 0;
424 start_table(TABLESTYLE2, "width='80%'", 5);
428 $dim = get_company_pref('use_dimension');
431 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
432 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
433 if (($_SESSION['Items']->pos['credit_sale'] || $_SESSION['Items']->pos['cash_sale'])) {
434 $paymcat = !$_SESSION['Items']->pos['cash_sale'] ? PM_CREDIT :
435 (!$_SESSION['Items']->pos['credit_sale'] ? PM_CASH : PM_ANY);
436 label_cells(_("Payment terms:"), sale_payment_list('payment', $paymcat),
437 "class='tableheader2'", "colspan=$colspan");
439 label_cells(_('Payment:'), $_SESSION['Items']->payment_terms['terms'], "class='tableheader2'", "colspan=$colspan");
444 if ($_SESSION['Items']->trans_no == 0) {
445 ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'", false, ST_SALESINVOICE,
446 array('customer' => $_SESSION['Items']->customer_id,
447 'branch' => $_SESSION['Items']->Branch,
448 'date' => get_post('InvoiceDate')));
450 label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
453 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
455 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
457 label_cell(_("Dimension").":", "class='tableheader2'");
458 $_POST['dimension_id'] = $_SESSION['Items']->dimension_id;
459 dimensions_list_cells(null, 'dimension_id', null, true, ' ', false, 1, false);
462 hidden('dimension_id', 0);
467 if (!isset($_POST['ship_via'])) {
468 $_POST['ship_via'] = $_SESSION['Items']->ship_via;
470 label_cell(_("Shipping Company"), "class='tableheader2'");
473 $shipper = get_shipper($_SESSION['Items']->ship_via);
474 label_cells(null, $shipper['shipper_name']);
476 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
478 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
479 $_POST['InvoiceDate'] = new_doc_date();
480 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
481 $_POST['InvoiceDate'] = end_fiscalyear();
485 date_cells(_("Date"), 'InvoiceDate', '', $_SESSION['Items']->trans_no == 0,
486 0, 0, 0, "class='tableheader2'", true);
488 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
489 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_POST['InvoiceDate']);
492 date_cells(_("Due Date"), 'due_date', '', null, 0, 0, 0, "class='tableheader2'");
494 label_cell(_("Dimension")." 2:", "class='tableheader2'");
495 $_POST['dimension2_id'] = $_SESSION['Items']->dimension2_id;
496 dimensions_list_cells(null, 'dimension2_id', null, true, ' ', false, 2, false);
499 hidden('dimension2_id', 0);
503 $row = get_customer_to_order($_SESSION['Items']->customer_id);
504 if ($row['dissallow_invoices'] == 1)
506 display_error(_("The selected customer account is currently on hold. Please contact the credit control personnel to discuss."));
512 display_heading($prepaid ? _("Sales Order Items") : _("Invoice Items"));
516 start_table(TABLESTYLE, "width='80%'");
518 $th = array(_("Item Code"), _("Item Description"), _("Units"), _("Quantity"),
519 _("Price"), _("Tax Type"), _("Discount"), _("Total"));
521 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
522 _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
524 if ($is_batch_invoice) {
530 $th[4] = _("Credited");
540 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
541 if (!$prepaid && ($ln_itm->quantity == $ln_itm->qty_done)) {
542 continue; // this line was fully invoiced
544 alt_table_row_color($k);
545 view_stock_status_cell($ln_itm->stock_id);
548 label_cell($ln_itm->item_description);
550 text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
551 $dec = get_qty_dec($ln_itm->stock_id);
553 qty_cell($ln_itm->quantity, false, $dec);
554 label_cell($ln_itm->units);
556 qty_cell($ln_itm->qty_done, false, $dec);
558 if ($is_batch_invoice || $prepaid) {
559 // for batch invoices we can only remove whole deliveries
560 echo '<td nowrap align=right>';
561 hidden('Line' . $line, $ln_itm->qty_dispatched );
562 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
564 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
566 $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
568 $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
570 amount_cell($ln_itm->price);
571 label_cell($ln_itm->tax_type_name);
572 label_cell($display_discount_percent, "nowrap align=right");
573 amount_cell($line_total);
575 if ($is_batch_invoice) {
576 if ($dn_line_cnt == 0) {
577 $dn_line_cnt = $dspans[0];
578 $dspans = array_slice($dspans, 1);
579 label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class='oddrow'");
580 label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
581 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class='oddrow'");
588 /*Don't re-calculate freight if some of the order has already been delivered -
589 depending on the business logic required this condition may not be required.
590 It seems unfair to charge the customer twice for freight if the order
591 was not fully delivered the first time ?? */
593 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
594 if ($_SESSION['Items']->any_already_delivered() == 1) {
595 $_POST['ChargeFreightCost'] = price_format(0);
597 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
600 if (!check_num('ChargeFreightCost')) {
601 $_POST['ChargeFreightCost'] = price_format(0);
605 $accumulate_shipping = get_company_pref('accumulate_shipping');
606 if ($is_batch_invoice && $accumulate_shipping)
607 set_delivery_shipping_sum(array_keys($_SESSION['Items']->src_docs));
609 $colspan = $prepaid ? 7:9;
611 label_cell(_("Shipping Cost"), "colspan=$colspan align=right");
613 label_cell($_POST['ChargeFreightCost'], 'align=right');
615 small_amount_cells(null, 'ChargeFreightCost', null);
616 if ($is_batch_invoice) {
617 label_cell('', 'colspan=2');
621 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
623 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
625 label_row(_("Sub-total"), $display_sub_total, "colspan=$colspan align=right","align=right", $is_batch_invoice ? 2 : 0);
627 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
628 $tax_total = display_edit_tax_items($taxes, $colspan, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2 : 0);
630 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
632 label_row(_("Invoice Total"), $display_total, "colspan=$colspan align=right","align=right", $is_batch_invoice ? 2 : 0);
636 div_start('options');
637 start_table(TABLESTYLE2);
641 label_row(_("Sales order:"), get_trans_view_str(ST_SALESORDER, $_SESSION['Items']->order_no, get_reference(ST_SALESORDER, $_SESSION['Items']->order_no)));
643 $list = array(); $allocs = 0;
644 if (count($_SESSION['Items']->prepayments))
646 foreach($_SESSION['Items']->prepayments as $pmt)
648 $list[] = get_trans_view_str($pmt['trans_type_from'], $pmt['trans_no_from'], get_reference($pmt['trans_type_from'], $pmt['trans_no_from']));
649 $allocs += $pmt['amt'];
653 label_row(_("Payments received:"), implode(',', $list));
654 label_row(_("Invoiced here:"), price_format($_SESSION['Items']->prep_amount), 'class=label');
655 label_row(_("Left to be invoiced:"), price_format($_SESSION['Items']->get_trans_total()-max($_SESSION['Items']->prep_amount, $allocs)), 'class=label');
658 textarea_row(_("Memo:"), 'Comments', null, 50, 4);
662 submit_center_first('Update', _("Update"),
663 _('Refresh document page'), true);
664 submit_center_last('process_invoice', _("Process Invoice"),
665 _('Check entered data and save document'), 'default');