Recurrent Invoices: fixed buggy call to non existing function and payment terms type...
[fa-stable.git] / purchasing / po_receive_items.php
1 <?php
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 $page_security = 'SA_GRN';
13 $path_to_root = "..";
14 include_once($path_to_root . "/purchasing/includes/po_class.inc");
15
16 include_once($path_to_root . "/includes/session.inc");
17 include_once($path_to_root . "/purchasing/includes/purchasing_db.inc");
18 include_once($path_to_root . "/purchasing/includes/purchasing_ui.inc");
19
20 $js = "";
21 if ($SysPrefs->use_popup_windows)
22         $js .= get_js_open_window(900, 500);
23 if (user_use_date_picker())
24         $js .= get_js_date_picker();
25
26 //--------------------------------------------------------------------------------------------------
27
28 if (isset($_GET['PONumber']) && $_GET['PONumber'] > 0 && !isset($_POST['Update']))
29 {
30         $_SESSION['page_title'] = _($help_context = "Receive Purchase Order Items");
31         create_cart(ST_PURCHORDER, $_GET['PONumber']);
32         $_SESSION['PO']->trans_type = ST_SUPPRECEIVE;
33         $_SESSION['PO']->reference = $Refs->get_next(ST_SUPPRECEIVE, 
34                 array('date' => Today(), 'supplier' => $_SESSION['PO']->supplier_id));
35         foreach ($_SESSION['PO']->line_items as $line)
36                 $line->quantity = $line->qty_ordered - $line->qty_received;
37         copy_from_cart();
38 }
39 elseif (isset($_GET['ModifyGRN']) && $_GET['ModifyGRN'] > 0 && !isset($_POST['Update']))
40 {
41         $_SESSION['page_title'] = _($help_context = "Modify GRN #") . $_GET['ModifyGRN'];
42         create_cart(ST_SUPPRECEIVE, $_GET['ModifyGRN']);
43         copy_from_cart();
44 }
45
46 page($_SESSION['page_title'], false, false, "", $js);
47
48 //---------------------------------------------------------------------------------------------------------------
49
50 if (isset($_GET['AddedID']) || isset($_GET['UpdatedID']))
51 {
52         $new = isset($_GET['AddedID']);
53         $grn = $_GET[$new ? 'AddedID' : 'UpdatedID'];
54         $trans_type = ST_SUPPRECEIVE;
55
56         display_notification_centered(_("Purchase Order Delivery has been processed"));
57
58         display_note(get_trans_view_str($trans_type, $grn, _("&View this Delivery")));
59         
60     $clearing_act = get_company_pref('grn_clearing_act');
61         if ($clearing_act)      
62                 display_note(get_gl_view_str($trans_type, $grn, _("View the GL Journal Entries for this Delivery")), 1);
63
64         hyperlink_params("$path_to_root/purchasing/supplier_invoice.php", _("Entry purchase &invoice for this receival"), "New=1");
65
66         if ($new)
67                 hyperlink_no_params("$path_to_root/purchasing/inquiry/po_search.php", _("Select another &purchase order for receiving items against"));
68         else
69                 hyperlink_no_params("$path_to_root/purchasing/inquiry/supplier_inquiry.php", _("Select another &document for edition"));
70
71         display_footer_exit();
72 }
73
74 //--------------------------------------------------------------------------------------------------
75
76 if ((!isset($_GET['PONumber']) || $_GET['PONumber'] == 0) && (!isset($_GET['ModifyGRN']) || $_GET['ModifyGRN'] == 0) && !isset($_SESSION['PO']))
77 {
78         die (_("This page can only be opened with valid Purchase Order or GRN number."));
79 }
80
81 //--------------------------------------------------------------------------------------------------
82
83 function display_po_receive_items()
84 {
85         div_start('grn_items');
86     start_table(TABLESTYLE, "colspan=7 width='90%'");
87     $mod_grn = $_SESSION['PO']->grn_id;
88
89         if ($mod_grn) // modify GRN
90             $th = array(_("Item Code"), _("Description"), _("Ordered"), _("Units"), _("Received"), _("Invoiced"), _("This Delivery"), _("Price"), _("Total"));
91     else
92             $th = array(_("Item Code"), _("Description"), _("Ordered"), _("Units"), _("Received"), _("Outstanding"), _("This Delivery"), _("Price"), _("Total"));
93     table_header($th);
94
95     /* show the line items on the order with the quantity being received for modification */
96
97     $total = 0;
98     $k = 0; //row colour counter
99
100     if (count($_SESSION['PO']->line_items) > 0 )
101     {
102         foreach ($_SESSION['PO']->line_items as $line_no => $ln_itm)
103         {
104
105                         alt_table_row_color($k);
106
107                 $qty_outstanding = $ln_itm->qty_ordered - $ln_itm->qty_received;
108
109                         if (!isset($_POST['Update']) && !isset($_POST['ProcessGoodsReceived']) && $ln_itm->quantity == 0)
110                 {   //If no quantites yet input default the balance to be received
111                 $ln_itm->quantity = $qty_outstanding;
112                 }
113
114                 $line_total = ($ln_itm->quantity * $ln_itm->price);
115                 $total += $line_total;
116
117                         label_cell($ln_itm->stock_id);
118                         if ($mod_grn || $qty_outstanding > 0)
119                                 text_cells(null, $ln_itm->stock_id . "Desc", $ln_itm->item_description, 30, 50);
120                         else
121                                 label_cell($ln_itm->item_description);
122
123                         $dec = get_qty_dec($ln_itm->stock_id);
124                         qty_cell($ln_itm->qty_ordered, false, $dec);
125                         label_cell($ln_itm->units);
126                         qty_cell($ln_itm->qty_received, false, $dec);
127                         if ($mod_grn)
128                                 qty_cell($ln_itm->qty_inv, false, $dec);
129                         else
130                                 qty_cell($qty_outstanding, false, $dec);
131
132                         if ($mod_grn || $qty_outstanding > 0)
133                                 qty_cells(null, $line_no, number_format2($ln_itm->quantity, $dec), "align=right", null, $dec);
134                         else
135                                 label_cell(number_format2($ln_itm->quantity, $dec), "align=right");
136
137                         amount_decimal_cell($ln_itm->price);
138                         amount_cell($line_total);
139                         end_row();
140         }
141     }
142
143         $colspan = count($th)-1;
144
145         $display_sub_total = price_format($total);
146
147         label_row(_("Sub-total"), $display_sub_total, "colspan=$colspan align=right","align=right");
148         $taxes = $_SESSION['PO']->get_taxes();
149         
150         $tax_total = display_edit_tax_items($taxes, $colspan, $_SESSION['PO']->tax_included);
151
152         $display_total = price_format(($total + $tax_total));
153
154         start_row();
155         label_cells(_("Amount Total"), $display_total, "colspan=$colspan align='right'","align='right'");
156         end_row();
157     end_table();
158         div_end();
159 }
160
161 //--------------------------------------------------------------------------------------------------
162
163 function check_po_changed()
164 {
165         /*Now need to check that the order details are the same as they were when they were read
166         into the Items array. If they've changed then someone else must have altered them */
167         // Compare against COMPLETED items only !!
168         // Otherwise if you try to fullfill item quantities separately will give error.
169         $result = get_po_items($_SESSION['PO']->order_no);
170
171         $line_no = 0;
172         while ($myrow = db_fetch($result))
173         {
174                 $ln_item = $_SESSION['PO']->line_items[$line_no];
175                 // only compare against items that are outstanding
176                 $qty_outstanding = $ln_item->qty_ordered - $ln_item->qty_received;
177                 if ($qty_outstanding > 0)
178                 {
179                 if ($ln_item->qty_inv != $myrow["qty_invoiced"] ||
180                         $ln_item->stock_id != $myrow["item_code"] ||
181                         $ln_item->qty_ordered != $myrow["quantity_ordered"] ||
182                         $ln_item->qty_received + @$ln_item->qty_old != $myrow["quantity_received"])
183                 {
184                         return true;
185                 }
186                 }
187                 $line_no++;
188         } /*loop through all line items of the order to ensure none have been invoiced */
189
190         return false;
191 }
192
193 //--------------------------------------------------------------------------------------------------
194
195 function can_process()
196 {
197         global $SysPrefs;
198
199         if (count($_SESSION['PO']->line_items) <= 0)
200         {
201         display_error(_("There is nothing to process. Please enter valid quantities greater than zero."));
202         return false;
203         }
204
205         if (!is_date($_POST['tran_date']))
206         {
207                 display_error(_("The entered date is invalid."));
208                 set_focus('tran_date');
209                 return false;
210         }
211         if (!is_date_in_fiscalyear($_POST['tran_date'])) {
212                 display_error(_("The entered date is out of fiscal year or is closed for further data entry."));
213                 set_focus('tran_date');
214                 return false;
215         }
216
217         if (!check_reference($_POST['ref'], ST_SUPPRECEIVE, $_SESSION['PO']->grn_id))
218         {
219                 set_focus('ref');
220                 return false;
221         }
222
223         $something_received = 0;
224         foreach ($_SESSION['PO']->line_items as $order_line)
225         {
226                 if ($order_line->quantity > 0)
227                 {
228                         $something_received = 1;
229                         break;
230                 }
231         }
232
233     // Check whether trying to deliver more items than are recorded on the actual purchase order (+ overreceive allowance)
234     $delivery_qty_too_large = 0;
235         foreach ($_SESSION['PO']->line_items as $order_line)
236         {
237                 if ($order_line->quantity+$order_line->qty_received >
238                         $order_line->qty_ordered * (1+ ($SysPrefs->over_receive_allowance() / 100)))
239                 {
240                         $delivery_qty_too_large = 1;
241                         break;
242                 }
243         }
244
245     if ($something_received == 0)
246     {   /*Then dont bother proceeding cos nothing to do ! */
247         display_error(_("There is nothing to process. Please enter valid quantities greater than zero."));
248         return false;
249     }
250     elseif ($delivery_qty_too_large == 1)
251     {
252         display_error(_("Entered quantities cannot be greater than the quantity entered on the purchase order including the allowed over-receive percentage") . " (" . $SysPrefs->over_receive_allowance() ."%)."
253                 . "<br>" .
254                 _("Modify the ordered items on the purchase order if you wish to increase the quantities."));
255         return false;
256     }
257
258         return true;
259 }
260
261 //--------------------------------------------------------------------------------------------------
262
263 function process_receive_po()
264 {
265         global $path_to_root, $Ajax;
266
267         if (!can_process())
268                 return;
269
270         if (check_po_changed())
271         {
272                 display_error(_("This order has been changed or invoiced since this delivery was started to be actioned. Processing halted. To enter a delivery against this purchase order, it must be re-selected and re-read again to update the changes made by the other user."));
273
274                 hyperlink_no_params("$path_to_root/purchasing/inquiry/po_search.php",
275                  _("Select a different purchase order for receiving goods against"));
276
277                 if (!$_SESSION['PO']->grn_id)
278                         hyperlink_params("$path_to_root/purchasing/po_receive_items.php", 
279                                  _("Re-Read the updated purchase order for receiving goods against"),
280                                  "PONumber=" . $_SESSION['PO']->order_no);
281                 else
282                         hyperlink_params("$path_to_root/purchasing/po_receive_items.php", 
283                                  _("Re-Read the GRN for reedition"),
284                                  "ModifyGRN=" . $_SESSION['PO']->grn_id);
285
286                 unset($_SESSION['PO']->line_items);
287                 unset($_SESSION['PO']);
288                 unset($_POST['ProcessGoodsReceived']);
289                 $Ajax->activate('_page_body');
290                 display_footer_exit();
291         }
292         
293         $grn = &$_SESSION['PO'];
294         $grn->tran_date = $_POST['tran_date'];
295         $grn->reference = $_POST['ref'];
296         $grn->Location = $_POST['Location'];
297         $grn->ex_rate = input_num('_ex_rate', null);
298
299         $trans_no = write_grn($grn);
300         $new = $grn->grn_id == 0;
301
302         new_doc_date($_POST['tran_date']);
303         unset($_SESSION['PO']->line_items);
304         unset($_SESSION['PO']);
305
306         if ($new)
307                 meta_forward($_SERVER['PHP_SELF'], "AddedID=$trans_no");
308         else
309                 meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$trans_no");
310 }
311
312 //--------------------------------------------------------------------------------------------------
313
314 if (isset($_POST['Update']) || isset($_POST['ProcessGoodsReceived']))
315 {
316         /* if update quantities button is hit page has been called and ${$line_no} would have be
317         set from the post to the quantity to be received in this receival*/
318         foreach ($_SESSION['PO']->line_items as $line_no => $line)
319         {
320          if( ($line->qty_ordered - $line->qty_received) > 0) {
321                 $_POST[$line_no] = max($_POST[$line_no], 0);
322                 if (!check_num($line_no))
323                         $_POST[$line_no] = number_format2(0, get_qty_dec($line->stock_id));
324
325                 if (!isset($_POST['tran_date']) || $_POST['tran_date'] == "")
326                         $_POST['tran_date'] = new_doc_date();
327
328                 $_SESSION['PO']->line_items[$line_no]->quantity = input_num($line_no);
329
330                 if (isset($_POST[$line->stock_id . "Desc"]) && strlen($_POST[$line->stock_id . "Desc"]) > 0)
331                 {
332                         $_SESSION['PO']->line_items[$line_no]->item_description = $_POST[$line->stock_id . "Desc"];
333                 }
334          }
335         }
336         $Ajax->activate('grn_items');
337 }
338
339 //--------------------------------------------------------------------------------------------------
340
341 if (isset($_POST['ProcessGoodsReceived']))
342 {
343         process_receive_po();
344 }
345
346 //--------------------------------------------------------------------------------------------------
347
348 start_form();
349
350 edit_grn_summary($_SESSION['PO'], true);
351 display_heading(_("Items to Receive"));
352 display_po_receive_items();
353
354 echo '<br>';
355 submit_center_first('Update', _("Update"), '', true);
356 submit_center_last('ProcessGoodsReceived', _("Process Receive Items"), _("Clear all GL entry fields"), 'default');
357
358 end_form();
359
360 //--------------------------------------------------------------------------------------------------
361 end_page();