Security update merged from 2.1.
[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 ($use_popup_windows)
22         $js .= get_js_open_window(900, 500);
23 if ($use_date_picker)
24         $js .= get_js_date_picker();
25 page(_("Receive Purchase Order Items"), false, false, "", $js);
26
27 //---------------------------------------------------------------------------------------------------------------
28
29 if (isset($_GET['AddedID']))
30 {
31         $grn = $_GET['AddedID'];
32         $trans_type = ST_SUPPRECEIVE;
33
34         display_notification_centered(_("Purchase Order Delivery has been processed"));
35
36         display_note(get_trans_view_str($trans_type, $grn, _("&View this Delivery")));
37
38         hyperlink_params("$path_to_root/purchasing/supplier_invoice.php", _("Entry purchase &invoice for this receival"), "New=1");
39
40         hyperlink_no_params("$path_to_root/purchasing/inquiry/po_search.php", _("Select a different &purchase order for receiving items against"));
41
42         display_footer_exit();
43 }
44
45 //--------------------------------------------------------------------------------------------------
46
47 if ((!isset($_GET['PONumber']) || $_GET['PONumber'] == 0) && !isset($_SESSION['PO']))
48 {
49         die (_("This page can only be opened if a purchase order has been selected. Please select a purchase order first."));
50 }
51
52 //--------------------------------------------------------------------------------------------------
53
54 function display_po_receive_items()
55 {
56         global $table_style;
57
58         div_start('grn_items');
59     start_table("colspan=7 $table_style width=90%");
60     $th = array(_("Item Code"), _("Description"), _("Ordered"), _("Units"), _("Received"),
61         _("Outstanding"), _("This Delivery"), _("Price"), _("Total"));
62     table_header($th);
63
64     /*show the line items on the order with the quantity being received for modification */
65
66     $total = 0;
67     $k = 0; //row colour counter
68
69     if (count($_SESSION['PO']->line_items)> 0 )
70     {
71         foreach ($_SESSION['PO']->line_items as $ln_itm)
72         {
73
74                         alt_table_row_color($k);
75
76                 $qty_outstanding = $ln_itm->quantity - $ln_itm->qty_received;
77
78                         if (!isset($_POST['Update']) && !isset($_POST['ProcessGoodsReceived']) && $ln_itm->receive_qty == 0)
79                 {   //If no quantites yet input default the balance to be received
80                 $ln_itm->receive_qty = $qty_outstanding;
81                 }
82
83                 $line_total = ($ln_itm->receive_qty * $ln_itm->price);
84                 $total += $line_total;
85
86                         label_cell($ln_itm->stock_id);
87                         if ($qty_outstanding > 0)
88                                 text_cells(null, $ln_itm->stock_id . "Desc", $ln_itm->item_description, 30, 50);
89                         else
90                                 label_cell($ln_itm->item_description);
91                         $dec = get_qty_dec($ln_itm->stock_id);
92                         qty_cell($ln_itm->quantity, false, $dec);
93                         label_cell($ln_itm->units);
94                         qty_cell($ln_itm->qty_received, false, $dec);
95                         qty_cell($qty_outstanding, false, $dec);
96
97                         if ($qty_outstanding > 0)
98                                 qty_cells(null, $ln_itm->line_no, number_format2($ln_itm->receive_qty, $dec), "align=right", null, $dec);
99                         else
100                                 label_cell(number_format2($ln_itm->receive_qty, $dec), "align=right");
101
102                         amount_decimal_cell($ln_itm->price);
103                         amount_cell($line_total);
104                         end_row();
105         }
106     }
107
108     $display_total = number_format2($total,user_price_dec());
109     label_row(_("Total value of items received"), $display_total, "colspan=8 align=right",
110         "nowrap align=right");
111     end_table();
112         div_end();
113 }
114
115 //--------------------------------------------------------------------------------------------------
116
117 function check_po_changed()
118 {
119         /*Now need to check that the order details are the same as they were when they were read into the Items array. If they've changed then someone else must have altered them */
120         // Sherifoz 22.06.03 Compare against COMPLETED items only !!
121         // Otherwise if you try to fullfill item quantities separately will give error.
122         $sql = "SELECT item_code, quantity_ordered, quantity_received, qty_invoiced
123                 FROM ".TB_PREF."purch_order_details
124                 WHERE order_no=".db_escape($_SESSION['PO']->order_no)
125                 ." ORDER BY po_detail_item";
126
127         $result = db_query($sql, "could not query purch order details");
128     check_db_error("Could not check that the details of the purchase order had not been changed by another user ", $sql);
129
130         $line_no = 1;
131         while ($myrow = db_fetch($result))
132         {
133                 $ln_item = $_SESSION['PO']->line_items[$line_no];
134                 // only compare against items that are outstanding
135                 $qty_outstanding = $ln_item->quantity - $ln_item->qty_received;
136                 if ($qty_outstanding > 0)
137                 {
138                 if ($ln_item->qty_inv != $myrow["qty_invoiced"] ||
139                         $ln_item->stock_id != $myrow["item_code"] ||
140                         $ln_item->quantity != $myrow["quantity_ordered"] ||
141                         $ln_item->qty_received != $myrow["quantity_received"])
142                 {
143                         return true;
144                 }
145                 }
146                 $line_no++;
147         } /*loop through all line items of the order to ensure none have been invoiced */
148
149         return false;
150 }
151
152 //--------------------------------------------------------------------------------------------------
153
154 function can_process()
155 {
156         global $SysPrefs, $Refs;
157         
158         if (count($_SESSION['PO']->line_items) <= 0)
159         {
160         display_error(_("There is nothing to process. Please enter valid quantities greater than zero."));
161         return false;
162         }
163
164         if (!is_date($_POST['DefaultReceivedDate']))
165         {
166                 display_error(_("The entered date is invalid."));
167                 set_focus('DefaultReceivedDate');
168                 return false;
169         }
170
171     if (!$Refs->is_valid($_POST['ref']))
172     {
173                 display_error(_("You must enter a reference."));
174                 set_focus('ref');
175                 return false;
176         }
177
178         if (!is_new_reference($_POST['ref'], ST_SUPPRECEIVE))
179         {
180                 display_error(_("The entered reference is already in use."));
181                 set_focus('ref');
182                 return false;
183         }
184
185         $something_received = 0;
186         foreach ($_SESSION['PO']->line_items as $order_line)
187         {
188                 if ($order_line->receive_qty > 0)
189                 {
190                         $something_received = 1;
191                         break;
192                 }
193         }
194
195     // Check whether trying to deliver more items than are recorded on the actual purchase order (+ overreceive allowance)
196     $delivery_qty_too_large = 0;
197         foreach ($_SESSION['PO']->line_items as $order_line)
198         {
199                 if ($order_line->receive_qty+$order_line->qty_received >
200                         $order_line->quantity * (1+ ($SysPrefs->over_receive_allowance() / 100)))
201                 {
202                         $delivery_qty_too_large = 1;
203                         break;
204                 }
205         }
206
207     if ($something_received == 0)
208     {   /*Then dont bother proceeding cos nothing to do ! */
209         display_error(_("There is nothing to process. Please enter valid quantities greater than zero."));
210         return false;
211     }
212     elseif ($delivery_qty_too_large == 1)
213     {
214         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() ."%)."
215                 . "<br>" .
216                 _("Modify the ordered items on the purchase order if you wish to increase the quantities."));
217         return false;
218     }
219
220         return true;
221 }
222
223 //--------------------------------------------------------------------------------------------------
224
225 function process_receive_po()
226 {
227         global $path_to_root, $Ajax;
228
229         if (!can_process())
230                 return;
231
232         if (check_po_changed())
233         {
234                 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."));
235                 hyperlink_no_params("$path_to_root/purchasing/inquiry/po_search.php",
236                  _("Select a different purchase order for receiving goods against"));
237                 hyperlink_params("$path_to_root/purchasing/po_receive_items.php", 
238                          _("Re-Read the updated purchase order for receiving goods against"),
239                          "PONumber=" . $_SESSION['PO']->order_no);
240                 unset($_SESSION['PO']->line_items);
241                 unset($_SESSION['PO']);
242                 unset($_POST['ProcessGoodsReceived']);
243                 $Ajax->activate('_page_body');
244                 display_footer_exit();
245         }
246
247         $grn = add_grn($_SESSION['PO'], $_POST['DefaultReceivedDate'],
248                 $_POST['ref'], $_POST['Location']);
249
250         new_doc_date($_POST['DefaultReceivedDate']);
251         unset($_SESSION['PO']->line_items);
252         unset($_SESSION['PO']);
253
254         meta_forward($_SERVER['PHP_SELF'], "AddedID=$grn");
255 }
256
257 //--------------------------------------------------------------------------------------------------
258
259 if (isset($_GET['PONumber']) && $_GET['PONumber'] > 0 && !isset($_POST['Update']))
260 {
261
262         create_new_po();
263
264         /*read in all the selected order into the Items cart  */
265         read_po($_GET['PONumber'], $_SESSION['PO']);
266 }
267
268 //--------------------------------------------------------------------------------------------------
269
270 if (isset($_POST['Update']) || isset($_POST['ProcessGoodsReceived']))
271 {
272
273         /* if update quantities button is hit page has been called and ${$line->line_no} would have be
274         set from the post to the quantity to be received in this receival*/
275         foreach ($_SESSION['PO']->line_items as $line)
276         {
277          if( ($line->quantity - $line->qty_received)>0) {
278                 $_POST[$line->line_no] = max($_POST[$line->line_no], 0);
279                 if (!check_num($line->line_no))
280                         $_POST[$line->line_no] = number_format2(0, get_qty_dec($line->stock_id));
281
282                 if (!isset($_POST['DefaultReceivedDate']) || $_POST['DefaultReceivedDate'] == "")
283                         $_POST['DefaultReceivedDate'] = new_doc_date();
284
285                 $_SESSION['PO']->line_items[$line->line_no]->receive_qty = input_num($line->line_no);
286
287                 if (isset($_POST[$line->stock_id . "Desc"]) && strlen($_POST[$line->stock_id . "Desc"]) > 0)
288                 {
289                         $_SESSION['PO']->line_items[$line->line_no]->item_description = $_POST[$line->stock_id . "Desc"];
290                 }
291          }
292         }
293         $Ajax->activate('grn_items');
294 }
295
296 //--------------------------------------------------------------------------------------------------
297
298 if (isset($_POST['ProcessGoodsReceived']))
299 {
300         process_receive_po();
301 }
302
303 //--------------------------------------------------------------------------------------------------
304
305 start_form();
306
307 display_grn_summary($_SESSION['PO'], true);
308 display_heading(_("Items to Receive"));
309 display_po_receive_items();
310
311 echo '<br>';
312 submit_center_first('Update', _("Update"), '', true);
313 submit_center_last('ProcessGoodsReceived', _("Process Receive Items"), _("Clear all GL entry fields"), 'default');
314
315 end_form();
316
317 //--------------------------------------------------------------------------------------------------
318
319 end_page();
320 ?>
321