2 //---------------------------------------------------------------------------
4 // Entry/Modify Sales Invoice against single delivery
5 // Entry/Modify Batch Sales Invoice against batch of deliveries
9 include_once($path_to_root . "/sales/includes/cart_class.inc");
10 include_once($path_to_root . "/includes/session.inc");
11 include_once($path_to_root . "/includes/data_checks.inc");
12 include_once($path_to_root . "/includes/manufacturing.inc");
13 include_once($path_to_root . "/sales/includes/sales_db.inc");
14 include_once($path_to_root . "/sales/includes/sales_ui.inc");
15 include_once($path_to_root . "/reporting/includes/reporting.inc");
16 include_once($path_to_root . "/taxes/tax_calc.inc");
19 if ($use_popup_windows) {
20 $js .= get_js_open_window(900, 500);
22 if ($use_date_picker) {
23 $js .= get_js_date_picker();
26 if (isset($_GET['ModifyInvoice'])) {
27 $_SESSION['page_title'] = sprintf(_("Modifying Sales Invoice # %d.") ,$_GET['ModifyInvoice']);
28 $help_page_title = _("Modifying Sales Invoice");
29 } elseif (isset($_GET['DeliveryNumber'])) {
30 $_SESSION['page_title'] = _("Issue an Invoice for Delivery Note");
31 } elseif (isset($_GET['BatchInvoice'])) {
32 $_SESSION['page_title'] = _("Issue Batch Invoice for Delivery Notes");
35 page($_SESSION['page_title'], false, false, "", $js);
37 //-----------------------------------------------------------------------------
39 if (isset($_GET['AddedID'])) {
41 $invoice_no = $_GET['AddedID'];
43 print_hidden_script(10);
45 display_notification(_("Selected deliveries has been processed"), true);
47 display_note(get_customer_trans_view_str($trans_type, $invoice_no, _("View This Invoice")), 0, 1);
49 display_note(print_document_link($invoice_no, _("Print This Invoice"), true, 10));
51 display_note(get_gl_view_str($trans_type, $invoice_no, _("View the GL Journal Entries for this Invoice")),1);
53 hyperlink_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Another Delivery For Invoicing"), "OutstandingOnly=1");
55 display_footer_exit();
57 } elseif (isset($_GET['UpdatedID'])) {
59 $invoice_no = $_GET['UpdatedID'];
60 print_hidden_script(10);
62 display_notification_centered(sprintf(_('Sales Invoice # %d has been updated.'),$invoice_no));
64 display_note(get_trans_view_str(10, $invoice_no, _("View This Invoice")));
66 display_note(print_document_link($invoice_no, _("Print This Invoice"), true, 10));
68 hyperlink_no_params($path_to_root . "/sales/inquiry/customer_inquiry.php", _("Select A Different Invoice to Modify"));
70 display_footer_exit();
72 } elseif (isset($_GET['RemoveDN'])) {
74 for($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
75 $line = &$_SESSION['Items']->line_items[$line_no];
76 if ($line->src_no == $_GET['RemoveDN']) {
77 $line->quantity = $line->qty_done;
78 $line->qty_dispatched=0;
84 //-----------------------------------------------------------------------------
86 if ( (isset($_GET['DeliveryNumber']) && ($_GET['DeliveryNumber'] > 0) )
87 || isset($_GET['BatchInvoice'])) {
91 if (isset($_GET['BatchInvoice'])) {
92 $src = $_SESSION['DeliveryBatch'];
93 unset($_SESSION['DeliveryBatch']);
95 $src = array($_GET['DeliveryNumber']);
97 /*read in all the selected deliveries into the Items cart */
98 $dn = new Cart(13, $src, true);
100 if ($dn->count_items() == 0) {
101 hyperlink_params($path_to_root . "/sales/inquiry/sales_deliveries_view.php",
102 _("Select a different delivery to invoice"), "OutstandingOnly=1");
103 die ("<br><b>" . _("There are no delivered items with a quantity left to invoice. There is nothing left to invoice.") . "</b>");
106 $dn->trans_type = 10;
107 $dn->src_docs = $dn->trans_no;
109 $dn->reference = references::get_next(10);
110 $dn->due_date = get_invoice_duedate($dn->customer_id, $dn->document_date);
112 $_SESSION['Items'] = $dn;
115 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
117 if ( get_parent_trans(10, $_GET['ModifyInvoice']) == 0) { // 1.xx compatibility hack
118 echo"<center><br><b>" . _("There are no delivery notes for this invoice.<br>
119 Most likely this invoice was created in Front Accounting version prior to 2.0
120 and therefore can not be modified.") . "</b></center>";
121 display_footer_exit();
124 $_SESSION['Items'] = new Cart(10, $_GET['ModifyInvoice']);
126 if ($_SESSION['Items']->count_items() == 0) {
127 echo"<center><br><b>" . _("All quantities on this invoice has been credited. There is nothing to modify on this invoice") . "</b></center>";
128 display_footer_exit();
131 } elseif (!processing_active()) {
132 /* This page can only be called with a delivery for invoicing or invoice no for edit */
133 display_error(_("This page can only be opened after delivery selection. Please select delivery to invoicing first."));
135 hyperlink_no_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Delivery to Invoice"));
139 } elseif (!check_quantities()) {
140 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
142 if (isset($_POST['Update'])) {
143 $Ajax->activate('Items');
145 if (isset($_POST['_InvoiceDate_changed'])) {
146 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id,
147 $_POST['InvoiceDate']);
148 $Ajax->activate('due_date');
150 //-----------------------------------------------------------------------------
151 function check_quantities()
154 foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
155 if (isset($_POST['Line'.$line_no])) {
156 if($_SESSION['Items']->trans_no) {
157 $min = $itm->qty_done;
158 $max = $itm->quantity;
161 $max = $itm->quantity - $itm->qty_done;
163 if (check_num('Line'.$line_no, $min, $max)) {
164 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
165 input_num('Line'.$line_no);
173 if (isset($_POST['Line'.$line_no.'Desc'])) {
174 $line_desc = $_POST['Line'.$line_no.'Desc'];
175 if (strlen($line_desc) > 0) {
176 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
183 function copy_to_cart()
185 $cart = &$_SESSION['Items'];
186 $cart->ship_via = $_POST['ship_via'];
187 $cart->freight_cost = input_num('ChargeFreightCost');
188 $cart->document_date = $_POST['InvoiceDate'];
189 $cart->due_date = $_POST['due_date'];
190 $cart->Comments = $_POST['Comments'];
192 //-----------------------------------------------------------------------------
194 function copy_from_cart()
196 $cart = &$_SESSION['Items'];
197 $_POST['ship_via'] = $cart->ship_via;
198 $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
199 $_POST['InvoiceDate']= $cart->document_date;
200 $_POST['due_date'] = $cart->due_date;
201 $_POST['Comments']= $cart->Comments;
204 //-----------------------------------------------------------------------------
206 function check_data()
208 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
209 display_error(_("The entered invoice date is invalid."));
210 set_focus('InvoiceDate');
214 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
215 display_error(_("The entered invoice date is not in fiscal year."));
216 set_focus('InvoiceDate');
220 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
221 display_error(_("The entered invoice due date is invalid."));
222 set_focus('due_date');
226 if ($_SESSION['Items']->trans_no == 0) {
227 if (!references::is_valid($_POST['ref'])) {
228 display_error(_("You must enter a reference."));
233 if (!is_new_reference($_POST['ref'], 10)) {
234 display_error(_("The entered reference is already in use."));
240 if ($_POST['ChargeFreightCost'] == "") {
241 $_POST['ChargeFreightCost'] = price_format(0);
244 if (!check_num('ChargeFreightCost', 0)) {
245 display_error(_("The entered shipping value is not numeric."));
246 set_focus('ChargeFreightCost');
250 if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
251 display_error(_("There are no item quantities on this invoice."));
255 if (!check_quantities()) {
256 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
263 //-----------------------------------------------------------------------------
264 if (isset($_POST['process_invoice']) && check_data()) {
266 $newinvoice= $_SESSION['Items']->trans_no == 0;
268 $invoice_no = $_SESSION['Items']->write();
272 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
274 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
278 // find delivery spans for batch invoice display
280 $lastdn = ''; $spanlen=1;
282 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
283 $line = $_SESSION['Items']->line_items[$line_no];
284 if ($line->quantity == $line->qty_done) {
287 if ($line->src_no == $lastdn) {
291 $dspans[] = $spanlen;
295 $lastdn = $line->src_no;
297 $dspans[] = $spanlen;
299 //-----------------------------------------------------------------------------
301 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
302 $is_edition = $_SESSION['Items']->trans_type == 10 && $_SESSION['Items']->trans_no != 0;
303 start_form(false, true);
305 start_table("$table_style2 width=80%", 5);
308 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
309 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
310 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
314 if ($_SESSION['Items']->trans_no == 0) {
315 ref_cells(_("Reference"), 'ref', '', $_SESSION['Items']->reference, "class='tableheader2'");
317 label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
320 label_cells(_("Delivery Notes:"),
321 get_customer_trans_view_str(systypes::cust_dispatch(), array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
323 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
328 if (!isset($_POST['ship_via'])) {
329 $_POST['ship_via'] = $_SESSION['Items']->ship_via;
331 label_cell(_("Shipping Company"), "class='tableheader2'");
332 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
334 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
335 $_POST['InvoiceDate'] = Today();
336 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
337 $_POST['InvoiceDate'] = end_fiscalyear();
341 date_cells(_("Date"), 'InvoiceDate', '', $_POST['InvoiceDate'], 0, 0, 0, "class='tableheader2'", true);
343 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
344 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, $_POST['InvoiceDate']);
347 date_cells(_("Due Date"), 'due_date', '', $_POST['due_date'], 0, 0, 0, "class='tableheader2'");
352 $row = get_customer_to_order($_SESSION['Items']->customer_id);
353 if ($row['dissallow_invoices'] == 1)
355 display_error(_("The selected customer account is currently on hold. Please contact the credit control personnel to discuss."));
361 display_heading(_("Invoice Items"));
364 start_table("$table_style width=80%");
365 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
366 _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
368 if ($is_batch_invoice) {
374 $th[4] = _("Credited");
384 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
385 if ($ln_itm->quantity == $ln_itm->qty_done) {
386 continue; // this line was fully invoiced
388 alt_table_row_color($k);
389 view_stock_status_cell($ln_itm->stock_id);
391 text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
392 $dec = get_qty_dec($ln_itm->stock_id);
393 qty_cell($ln_itm->quantity, false, $dec);
394 label_cell($ln_itm->units);
395 qty_cell($ln_itm->qty_done, false, $dec);
397 if ($is_batch_invoice) {
398 // for batch invoices we can only remove whole deliveries
399 echo '<td nowrap align=right>';
400 hidden('Line' . $line, $ln_itm->qty_dispatched );
401 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
403 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
405 $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
407 $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
409 amount_cell($ln_itm->price);
410 label_cell($ln_itm->tax_type_name);
411 label_cell($display_discount_percent, "nowrap align=right");
412 amount_cell($line_total);
414 if ($is_batch_invoice) {
415 if ($dn_line_cnt == 0) {
416 $dn_line_cnt = $dspans[0];
417 $dspans = array_slice($dspans, 1);
418 label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
419 label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
420 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
427 /*Don't re-calculate freight if some of the order has already been delivered -
428 depending on the business logic required this condition may not be required.
429 It seems unfair to charge the customer twice for freight if the order
430 was not fully delivered the first time ?? */
432 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
433 if ($_SESSION['Items']->any_already_delivered() == 1) {
434 $_POST['ChargeFreightCost'] = price_format(0);
436 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
439 if (!check_num('ChargeFreightCost')) {
440 $_POST['ChargeFreightCost'] = price_format(0);
446 small_amount_cells(_("Shipping Cost"), 'ChargeFreightCost', null, "colspan=9 align=right");
447 if ($is_batch_invoice) {
448 label_cell('', 'colspan=2');
452 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
454 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
456 label_row(_("Sub-total"), $display_sub_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
458 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
459 $tax_total = display_edit_tax_items($taxes, 9, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
461 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
463 label_row(_("Invoice Total"), $display_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
468 start_table($table_style2);
469 textarea_row(_("Memo"), 'Comments', null, 50, 4);
473 submit_center_first('Update', _("Update"),
474 _('Refresh document page'), true);
475 submit_center_last('process_invoice', _("Process Invoice"),
476 _('Check entered data and save document'), true);