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'];
44 display_notification(_("Selected deliveries has been processed"), true);
46 display_note(get_customer_trans_view_str($trans_type, $invoice_no, _("&View This Invoice")), 0, 1);
48 display_note(print_document_link($invoice_no, _("&Print This Invoice"), true, 10));
50 display_note(get_gl_view_str($trans_type, $invoice_no, _("View the GL &Journal Entries for this Invoice")),1);
52 hyperlink_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Another &Delivery For Invoicing"), "OutstandingOnly=1");
54 display_footer_exit();
56 } elseif (isset($_GET['UpdatedID'])) {
58 $invoice_no = $_GET['UpdatedID'];
60 display_notification_centered(sprintf(_('Sales Invoice # %d has been updated.'),$invoice_no));
62 display_note(get_trans_view_str(10, $invoice_no, _("&View This Invoice")));
64 display_note(print_document_link($invoice_no, _("&Print This Invoice"), true, 10));
66 hyperlink_no_params($path_to_root . "/sales/inquiry/customer_inquiry.php", _("Select A Different &Invoice to Modify"));
68 display_footer_exit();
70 } elseif (isset($_GET['RemoveDN'])) {
72 for($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
73 $line = &$_SESSION['Items']->line_items[$line_no];
74 if ($line->src_no == $_GET['RemoveDN']) {
75 $line->quantity = $line->qty_done;
76 $line->qty_dispatched=0;
82 //-----------------------------------------------------------------------------
84 if ( (isset($_GET['DeliveryNumber']) && ($_GET['DeliveryNumber'] > 0) )
85 || isset($_GET['BatchInvoice'])) {
89 if (isset($_GET['BatchInvoice'])) {
90 $src = $_SESSION['DeliveryBatch'];
91 unset($_SESSION['DeliveryBatch']);
93 $src = array($_GET['DeliveryNumber']);
95 /*read in all the selected deliveries into the Items cart */
96 $dn = new Cart(13, $src, true);
98 if ($dn->count_items() == 0) {
99 hyperlink_params($path_to_root . "/sales/inquiry/sales_deliveries_view.php",
100 _("Select a different delivery to invoice"), "OutstandingOnly=1");
101 die ("<br><b>" . _("There are no delivered items with a quantity left to invoice. There is nothing left to invoice.") . "</b>");
104 $dn->trans_type = 10;
105 $dn->src_docs = $dn->trans_no;
107 $dn->reference = references::get_next(10);
108 $dn->due_date = get_invoice_duedate($dn->customer_id, $dn->document_date);
110 $_SESSION['Items'] = $dn;
113 } elseif (isset($_GET['ModifyInvoice']) && $_GET['ModifyInvoice'] > 0) {
115 if ( get_parent_trans(10, $_GET['ModifyInvoice']) == 0) { // 1.xx compatibility hack
116 echo"<center><br><b>" . _("There in no delivery notes for this invoice.<br>
117 Most likely this invoice was created in Front Accounting version prior to 2.0
118 and therefore can not be modified.") . "</b></center>";
119 display_footer_exit();
122 $_SESSION['Items'] = new Cart(10, $_GET['ModifyInvoice']);
124 if ($_SESSION['Items']->count_items() == 0) {
125 echo"<center><br><b>" . _("All quantities on this invoice has been credited. There is nothing to modify on this invoice") . "</b></center>";
126 display_footer_exit();
129 } elseif (!processing_active()) {
130 /* This page can only be called with a delivery for invoicing or invoice no for edit */
131 display_error(_("This page can only be opened after delivery selection. Please select delivery to invoicing first."));
133 hyperlink_no_params("$path_to_root/sales/inquiry/sales_deliveries_view.php", _("Select Delivery to Invoice"));
137 } elseif (!check_quantities()) {
138 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
140 if (isset($_POST['Update'])) {
141 $Ajax->activate('Items');
143 if (isset($_POST['_InvoiceDate_changed'])) {
144 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id,
145 $_POST['InvoiceDate']);
146 $Ajax->activate('due_date');
148 //-----------------------------------------------------------------------------
149 function check_quantities()
152 foreach ($_SESSION['Items']->line_items as $line_no=>$itm) {
153 if (isset($_POST['Line'.$line_no])) {
154 if($_SESSION['Items']->trans_no) {
155 $min = $itm->qty_done;
156 $max = $itm->quantity;
159 $max = $itm->quantity - $itm->qty_done;
161 if (check_num('Line'.$line_no, $min, $max)) {
162 $_SESSION['Items']->line_items[$line_no]->qty_dispatched =
163 input_num('Line'.$line_no);
171 if (isset($_POST['Line'.$line_no.'Desc'])) {
172 $line_desc = $_POST['Line'.$line_no.'Desc'];
173 if (strlen($line_desc) > 0) {
174 $_SESSION['Items']->line_items[$line_no]->item_description = $line_desc;
181 function copy_to_cart()
183 $cart = &$_SESSION['Items'];
184 $cart->ship_via = $_POST['ship_via'];
185 $cart->freight_cost = input_num('ChargeFreightCost');
186 $cart->document_date = $_POST['InvoiceDate'];
187 $cart->due_date = $_POST['due_date'];
188 $cart->Comments = $_POST['Comments'];
190 //-----------------------------------------------------------------------------
192 function copy_from_cart()
194 $cart = &$_SESSION['Items'];
195 $_POST['ship_via'] = $cart->ship_via;
196 $_POST['ChargeFreightCost'] = price_format($cart->freight_cost);
197 $_POST['InvoiceDate']= $cart->document_date;
198 $_POST['due_date'] = $cart->due_date;
199 $_POST['Comments']= $cart->Comments;
202 //-----------------------------------------------------------------------------
204 function check_data()
206 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
207 display_error(_("The entered invoice date is invalid."));
208 set_focus('InvoiceDate');
212 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
213 display_error(_("The entered invoice date is not in fiscal year."));
214 set_focus('InvoiceDate');
218 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
219 display_error(_("The entered invoice due date is invalid."));
220 set_focus('due_date');
224 if ($_SESSION['Items']->trans_no == 0) {
225 if (!references::is_valid($_POST['ref'])) {
226 display_error(_("You must enter a reference."));
231 if (!is_new_reference($_POST['ref'], 10)) {
232 display_error(_("The entered reference is already in use."));
238 if ($_POST['ChargeFreightCost'] == "") {
239 $_POST['ChargeFreightCost'] = price_format(0);
242 if (!check_num('ChargeFreightCost', 0)) {
243 display_error(_("The entered shipping value is not numeric."));
244 set_focus('ChargeFreightCost');
248 if ($_SESSION['Items']->has_items_dispatch() == 0 && input_num('ChargeFreightCost') == 0) {
249 display_error(_("There are no item quantities on this invoice."));
253 if (!check_quantities()) {
254 display_error(_("Selected quantity cannot be less than quantity credited nor more than quantity not invoiced yet."));
261 //-----------------------------------------------------------------------------
262 if (isset($_POST['process_invoice']) && check_data()) {
264 $newinvoice= $_SESSION['Items']->trans_no == 0;
266 $invoice_no = $_SESSION['Items']->write();
270 meta_forward($_SERVER['PHP_SELF'], "AddedID=$invoice_no");
272 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$invoice_no");
276 // find delivery spans for batch invoice display
278 $lastdn = ''; $spanlen=1;
280 for ($line_no = 0; $line_no < count($_SESSION['Items']->line_items); $line_no++) {
281 $line = $_SESSION['Items']->line_items[$line_no];
282 if ($line->quantity == $line->qty_done) {
285 if ($line->src_no == $lastdn) {
289 $dspans[] = $spanlen;
293 $lastdn = $line->src_no;
295 $dspans[] = $spanlen;
297 //-----------------------------------------------------------------------------
299 $is_batch_invoice = count($_SESSION['Items']->src_docs) > 1;
300 $is_edition = $_SESSION['Items']->trans_type == 10 && $_SESSION['Items']->trans_no != 0;
301 start_form(false, true);
303 start_table("$table_style2 width=80%", 5);
306 label_cells(_("Customer"), $_SESSION['Items']->customer_name, "class='tableheader2'");
307 label_cells(_("Branch"), get_branch_name($_SESSION['Items']->Branch), "class='tableheader2'");
308 label_cells(_("Currency"), $_SESSION['Items']->customer_currency, "class='tableheader2'");
312 if ($_SESSION['Items']->trans_no == 0) {
313 ref_cells(_("Reference"), 'ref', '', $_SESSION['Items']->reference, "class='tableheader2'");
315 label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
318 label_cells(_("Delivery Notes:"),
319 get_customer_trans_view_str(systypes::cust_dispatch(), array_keys($_SESSION['Items']->src_docs)), "class='tableheader2'");
321 label_cells(_("Sales Type"), $_SESSION['Items']->sales_type_name, "class='tableheader2'");
326 if (!isset($_POST['ship_via'])) {
327 $_POST['ship_via'] = $_SESSION['Items']->ship_via;
329 label_cell(_("Shipping Company"), "class='tableheader2'");
330 shippers_list_cells(null, 'ship_via', $_POST['ship_via']);
332 if (!isset($_POST['InvoiceDate']) || !is_date($_POST['InvoiceDate'])) {
333 $_POST['InvoiceDate'] = Today();
334 if (!is_date_in_fiscalyear($_POST['InvoiceDate'])) {
335 $_POST['InvoiceDate'] = end_fiscalyear();
339 date_cells(_("Date"), 'InvoiceDate', '', $_POST['InvoiceDate'], 0, 0, 0, "class='tableheader2'", true);
341 if (!isset($_POST['due_date']) || !is_date($_POST['due_date'])) {
342 $_POST['due_date'] = get_invoice_duedate($_SESSION['Items']->customer_id, $_POST['InvoiceDate']);
345 date_cells(_("Due Date"), 'due_date', '', $_POST['due_date'], 0, 0, 0, "class='tableheader2'");
350 display_heading(_("Invoice Items"));
353 start_table("$table_style width=80%");
354 $th = array(_("Item Code"), _("Item Description"), _("Delivered"), _("Units"), _("Invoiced"),
355 _("This Invoice"), _("Price"), _("Tax Type"), _("Discount"), _("Total"));
357 if ($is_batch_invoice) {
363 $th[4] = _("Credited");
373 foreach ($_SESSION['Items']->line_items as $line=>$ln_itm) {
374 if ($ln_itm->quantity == $ln_itm->qty_done) {
375 continue; // this line was fully invoiced
377 alt_table_row_color($k);
378 view_stock_status_cell($ln_itm->stock_id);
380 text_cells(null, 'Line'.$line.'Desc', $ln_itm->item_description, 30, 50);
381 $dec = get_qty_dec($ln_itm->stock_id);
382 qty_cell($ln_itm->quantity, false, $dec);
383 label_cell($ln_itm->units);
384 qty_cell($ln_itm->qty_done, false, $dec);
386 if ($is_batch_invoice) {
387 // for batch invoices we can only remove whole deliveries
388 echo '<td nowrap align=right>';
389 hidden('Line' . $line, $ln_itm->qty_dispatched );
390 echo number_format2($ln_itm->qty_dispatched, $dec).'</td>';
392 small_qty_cells(null, 'Line'.$line, qty_format($ln_itm->qty_dispatched, $ln_itm->stock_id, $dec), null, null, $dec);
394 $display_discount_percent = percent_format($ln_itm->discount_percent*100) . " %";
396 $line_total = ($ln_itm->qty_dispatched * $ln_itm->price * (1 - $ln_itm->discount_percent));
398 amount_cell($ln_itm->price);
399 label_cell($ln_itm->tax_type_name);
400 label_cell($display_discount_percent, "nowrap align=right");
401 amount_cell($line_total);
403 if ($is_batch_invoice) {
404 if ($dn_line_cnt == 0) {
405 $dn_line_cnt = $dspans[0];
406 $dspans = array_slice($dspans, 1);
407 label_cell($ln_itm->src_no, "rowspan=$dn_line_cnt class=oddrow");
408 label_cell("<a href='" . $_SERVER['PHP_SELF'] . "?RemoveDN=".
409 $ln_itm->src_no."'>" . _("Remove") . "</a>", "rowspan=$dn_line_cnt class=oddrow");
416 /*Don't re-calculate freight if some of the order has already been delivered -
417 depending on the business logic required this condition may not be required.
418 It seems unfair to charge the customer twice for freight if the order
419 was not fully delivered the first time ?? */
421 if (!isset($_POST['ChargeFreightCost']) || $_POST['ChargeFreightCost'] == "") {
422 if ($_SESSION['Items']->any_already_delivered() == 1) {
423 $_POST['ChargeFreightCost'] = price_format(0);
425 $_POST['ChargeFreightCost'] = price_format($_SESSION['Items']->freight_cost);
428 if (!check_num('ChargeFreightCost')) {
429 $_POST['ChargeFreightCost'] = price_format(0);
435 small_amount_cells(_("Shipping Cost"), 'ChargeFreightCost', null, "colspan=9 align=right");
436 if ($is_batch_invoice) {
437 label_cell('', 'colspan=2');
441 $inv_items_total = $_SESSION['Items']->get_items_total_dispatch();
443 $display_sub_total = price_format($inv_items_total + input_num('ChargeFreightCost'));
445 label_row(_("Sub-total"), $display_sub_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
447 $taxes = $_SESSION['Items']->get_taxes(input_num('ChargeFreightCost'));
448 $tax_total = display_edit_tax_items($taxes, 9, $_SESSION['Items']->tax_included, $is_batch_invoice ? 2:0);
450 $display_total = price_format(($inv_items_total + input_num('ChargeFreightCost') + $tax_total));
452 label_row(_("Invoice Total"), $display_total, "colspan=9 align=right","align=right", $is_batch_invoice ? 2 : 0);
457 start_table($table_style2);
458 textarea_row(_("Memo"), 'Comments', null, 50, 4);
462 submit_center_first('Update', _("Update"),
463 _('Refresh document page'), true);
464 submit_center_last('process_invoice', _("Process Invoice"),
465 _('Check entered data and save document'), true);