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 display_footer_exit();
68 } elseif (isset($_GET['UpdatedID'])) {
70 $invoice_no = $_GET['UpdatedID'];
71 $trans_type = ST_SALESINVOICE;
73 display_notification_centered(sprintf(_('Sales Invoice # %d has been updated.'),$invoice_no));
75 display_note(get_trans_view_str(ST_SALESINVOICE, $invoice_no, _("&View This Invoice")));
77 display_note(print_document_link($invoice_no."-".$trans_type, _("&Print This Invoice"), true, ST_SALESINVOICE));
78 display_note(print_document_link($invoice_no."-".$trans_type, _("&Email This Invoice"), true, ST_SALESINVOICE, false, "printlink", "", 1),1);
80 hyperlink_no_params($path_to_root . "/sales/inquiry/customer_inquiry.php", _("Select Another &Invoice to Modify"));
82 display_footer_exit();
84 } elseif (isset($_GET['RemoveDN'])) {
86 for($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
87 $line = &$_SESSION['Items']->line_items[$line_no];
88 if ($line->src_no == $_GET['RemoveDN']) {
89 $line->quantity = $line->qty_done;
90 $line->qty_dispatched=0;
95 // Remove also src_doc delivery note
96 $sources = &$_SESSION['Items']->src_docs;
97 unset($sources[$_GET['RemoveDN']]);
100 //-----------------------------------------------------------------------------
102 if ( (isset($_GET['DeliveryNumber']) && ($_GET['DeliveryNumber'] > 0) )
103 || isset($_GET['BatchInvoice'])) {
107 if (isset($_GET['BatchInvoice'])) {
108 $src = $_SESSION['DeliveryBatch'];
109 unset($_SESSION['DeliveryBatch']);
111 $src = array($_GET['DeliveryNumber']);
113 /*read in all the selected deliveries into the Items cart */
114 $dn = new Cart(ST_CUSTDELIVERY, $src, true);
116 if ($dn->count_items() == 0) {
117 hyperlink_params($path_to_root . "/sales/inquiry/sales_deliveries_view.php",
118 _("Select a different delivery to invoice"), "OutstandingOnly=1");
119 die ("<br><b>" . _("There are no delivered items with a quantity left to invoice. There is nothing left to invoice.") . "</b>");
122 $dn->trans_type = ST_SALESINVOICE;
123 $dn->src_docs = $dn->trans_no;
125 $dn->reference = $Refs->get_next(ST_SALESINVOICE);
126 $dn->due_date = get_invoice_duedate($dn->payment, $dn->document_date);
128 $_SESSION['Items'] = $dn;
131 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
133 if ( get_sales_parent_numbers(ST_SALESINVOICE, $_GET['ModifyInvoice']) == 0) { // 1.xx compatibility hack
134 echo"<center><br><b>" . _("There are no delivery notes for this invoice.<br>
135 Most likely this invoice was created in Front Accounting version prior to 2.0
136 and therefore can not be modified.") . "</b></center>";
137 display_footer_exit();
140 $_SESSION['Items'] = new Cart(ST_SALESINVOICE, $_GET['ModifyInvoice']);
142 if ($_SESSION['Items']->count_items() == 0) {
143 echo"<center><br><b>" . _("All quantities on this invoice has been credited. There is nothing to modify on this invoice") . "</b></center>";
144 display_footer_exit();
147 } elseif (!processing_active()) {
148 /* This page can only be called with a delivery for invoicing or invoice no for edit */
149 display_error(_("This page can only be opened after delivery selection. Please select delivery to invoicing first."));
151 hyperlink_no_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Delivery to Invoice"));
155 } elseif (!check_quantities()) {
156 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
158 if (isset($_POST['Update'])) {
159 $Ajax->activate('Items');
161 if (isset($_POST['_InvoiceDate_changed'])) {
162 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_POST['InvoiceDate']);
163 $Ajax->activate('due_date');
165 if (list_updated('payment')) {
166 $_SESSION['Items']->payment = get_post('payment');
167 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_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 if ($cart->pos['cash_sale'] || $cart->pos['credit_sale']) {
230 $cart->payment = $_POST['payment'];
231 $cart->payment_terms = get_payment_terms($_POST['payment']);
233 $cart->Comments = $_POST['Comments'];
234 if ($_SESSION['Items']->trans_no == 0)
235 $cart->reference = $_POST['ref'];
238 //-----------------------------------------------------------------------------
240 function copy_from_cart()
242 $cart = &$_SESSION['Items'];
243 $_POST['ship_via'] = $cart->ship_via;
244 $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
245 $_POST['InvoiceDate']= $cart->document_date;
246 $_POST['due_date'] = $cart->due_date;
247 $_POST['Comments']= $cart->Comments;
248 $_POST['cart_id'] = $cart->cart_id;
249 $_POST['ref'] = $cart->reference;
250 $_POST['payment'] = $cart->payment;
253 //-----------------------------------------------------------------------------
255 function check_data()
259 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
260 display_error(_("The entered invoice date is invalid."));
261 set_focus('InvoiceDate');
265 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
266 display_error(_("The entered invoice date is not in fiscal year."));
267 set_focus('InvoiceDate');
271 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
272 display_error(_("The entered invoice due date is invalid."));
273 set_focus('due_date');
277 if ($_SESSION['Items']->trans_no == 0) {
278 if (!$Refs->is_valid($_POST['ref'])) {
279 display_error(_("You must enter a reference."));
284 if (!is_new_reference($_POST['ref'], 10)) {
285 display_error(_("The entered reference is already in use."));
291 if ($_POST['ChargeFreightCost'] == "") {
292 $_POST['ChargeFreightCost'] = price_format(0);
295 if (!check_num('ChargeFreightCost', 0)) {
296 display_error(_("The entered shipping value is not numeric."));
297 set_focus('ChargeFreightCost');
301 if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
302 display_error(_("There are no item quantities on this invoice."));
306 if (!check_quantities()) {
307 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
314 //-----------------------------------------------------------------------------
315 if (isset($_POST['process_invoice']) && check_data()) {
317 $newinvoice= $_SESSION['Items']->trans_no == 0;
319 if ($newinvoice) new_doc_date($_SESSION['Items']->document_date);
321 $invoice_no = $_SESSION['Items']->write();
325 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
327 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
331 // find delivery spans for batch invoice display
333 $lastdn = ''; $spanlen=1;
335 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
336 $line = $_SESSION['Items']->line_items[$line_no];
337 if ($line->quantity == $line->qty_done) {
340 if ($line->src_no == $lastdn) {
344 $dspans[] = $spanlen;
348 $lastdn = $line->src_no;
350 $dspans[] = $spanlen;
352 //-----------------------------------------------------------------------------
354 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
356 $is_edition = $_SESSION['Items']->trans_type == ST_SALESINVOICE && $_SESSION['Items']->trans_no != 0;
360 start_table(TABLESTYLE2, "width=80%", 5);
364 $dim = get_company_pref('use_dimension');
367 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
368 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
369 if ($_SESSION['Items']->pos['credit_sale'] || $_SESSION['Items']->pos['cash_sale']) {
370 // editable payment type
371 $paymcat = !$_SESSION['Items']->pos['cash_sale'] ? PM_CREDIT :
372 (!$_SESSION['Items']->pos['credit_sale'] ? PM_CASH : PM_ANY);
373 label_cells(_("Payment terms:"), sale_payment_list('payment', $paymcat),
374 "class='tableheader2'", "colspan=$colspan");
376 label_cells(_('Payment:'), $_SESSION['Items']->payment_terms['terms'], "class='tableheader2'", "colspan=$colspan");
381 if ($_SESSION['Items']->trans_no == 0) {
382 ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'");
384 label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
387 //label_cells(_("Delivery Notes:"),
388 //get_customer_trans_view_str(ST_CUSTDELIVERY, array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
390 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
392 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
393 // 2010-09-03 Joe Hunt
395 label_cells(_("Dimension"), get_dimension_string($_SESSION['Items']->dimension_id), "class='tableheader2'");
400 if (!isset($_POST['ship_via'])) {
401 $_POST['ship_via'] = $_SESSION['Items']->ship_via;
403 label_cell(_("Shipping Company"), "class='tableheader2'");
404 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
406 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
407 $_POST['InvoiceDate'] = new_doc_date();
408 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
409 $_POST['InvoiceDate'] = end_fiscalyear();
413 date_cells(_("Date"), 'InvoiceDate', '', $_SESSION['Items']->trans_no == 0,
414 0, 0, 0, "class='tableheader2'", true);
416 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
417 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->payment, $_POST['InvoiceDate']);
420 date_cells(_("Due Date"), 'due_date', '', null, 0, 0, 0, "class='tableheader2'");
422 label_cells(_("Dimension"). " 2", get_dimension_string($_SESSION['Items']->dimension2_id), "class='tableheader2'");
424 label_cell(" ", "colspan=2");
429 $row = get_customer_to_order($_SESSION['Items']->customer_id);
430 if ($row['dissallow_invoices'] == 1)
432 display_error(_("The selected customer account is currently on hold. Please contact the credit control personnel to discuss."));
438 display_heading(_("Invoice Items"));
441 start_table(TABLESTYLE, "width=80%");
442 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
443 _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
445 if ($is_batch_invoice) {
451 $th[4] = _("Credited");
461 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
462 if ($ln_itm->quantity == $ln_itm->qty_done) {
463 continue; // this line was fully invoiced
465 alt_table_row_color($k);
466 view_stock_status_cell($ln_itm->stock_id);
468 text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
469 $dec = get_qty_dec($ln_itm->stock_id);
470 qty_cell($ln_itm->quantity, false, $dec);
471 label_cell($ln_itm->units);
472 qty_cell($ln_itm->qty_done, false, $dec);
474 if ($is_batch_invoice) {
475 // for batch invoices we can only remove whole deliveries
476 echo '<td nowrap align=right>';
477 hidden('Line' . $line, $ln_itm->qty_dispatched );
478 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
480 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
482 $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
484 $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
486 amount_cell($ln_itm->price);
487 label_cell($ln_itm->tax_type_name);
488 label_cell($display_discount_percent, "nowrap align=right");
489 amount_cell($line_total);
491 if ($is_batch_invoice) {
492 if ($dn_line_cnt == 0) {
493 $dn_line_cnt = $dspans[0];
494 $dspans = array_slice($dspans, 1);
495 label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
496 label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
497 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
504 /*Don't re-calculate freight if some of the order has already been delivered -
505 depending on the business logic required this condition may not be required.
506 It seems unfair to charge the customer twice for freight if the order
507 was not fully delivered the first time ?? */
509 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
510 if ($_SESSION['Items']->any_already_delivered() == 1) {
511 $_POST['ChargeFreightCost'] = price_format(0);
513 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
516 if (!check_num('ChargeFreightCost')) {
517 $_POST['ChargeFreightCost'] = price_format(0);
521 $accumulate_shipping = get_company_pref('accumulate_shipping');
522 if ($is_batch_invoice && $accumulate_shipping)
523 set_delivery_shipping_sum(array_keys($_SESSION['Items']->src_docs));
527 label_cell(_("Shipping Cost"), "colspan=$colspan align=right");
528 small_amount_cells(null, 'ChargeFreightCost', null);
529 if ($is_batch_invoice) {
530 label_cell('', 'colspan=2');
534 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
536 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
538 label_row(_("Sub-total"), $display_sub_total, "colspan=$colspan align=right","align=right", $is_batch_invoice ? 2 : 0);
540 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
541 $tax_total = display_edit_tax_items($taxes, $colspan, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
543 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
545 label_row(_("Invoice Total"), $display_total, "colspan=$colspan align=right","align=right", $is_batch_invoice ? 2 : 0);
550 start_table(TABLESTYLE2);
551 textarea_row(_("Memo"), 'Comments', null, 50, 4);
555 submit_center_first('Update', _("Update"),
556 _('Refresh document page'), true);
557 submit_center_last('process_invoice', _("Process Invoice"),
558 _('Check entered data and save document'), 'default');