Cost handling in purchasing module fixed.
[fa-stable.git] / purchasing / po_entry_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 $path_to_root = "..";
13 $page_security = 'SA_PURCHASEORDER';
14 include_once($path_to_root . "/purchasing/includes/po_class.inc");
15 include_once($path_to_root . "/includes/session.inc");
16 include_once($path_to_root . "/purchasing/includes/purchasing_ui.inc");
17 include_once($path_to_root . "/purchasing/includes/db/suppliers_db.inc");
18 include_once($path_to_root . "/reporting/includes/reporting.inc");
19
20 set_page_security( @$_SESSION['PO']->trans_type,
21         array(  ST_PURCHORDER => 'SA_PURCHASEORDER',
22                         ST_SUPPRECEIVE => 'SA_GRN',
23                         ST_SUPPINVOICE => 'SA_SUPPLIERINVOICE'),
24         array(  'NewOrder' => 'SA_PURCHASEORDER',
25                         'ModifyOrderNumber' => 'SA_PURCHASEORDER',
26                         'AddedID' => 'SA_PURCHASEORDER',
27                         'NewGRN' => 'SA_GRN',
28                         'AddedGRN' => 'SA_GRN',
29                         'NewInvoice' => 'SA_SUPPLIERINVOICE',
30                         'AddedPI' => 'SA_SUPPLIERINVOICE')
31 );
32
33 $js = '';
34 if ($SysPrefs->use_popup_windows)
35         $js .= get_js_open_window(900, 500);
36 if (user_use_date_picker())
37         $js .= get_js_date_picker();
38
39 if (isset($_GET['ModifyOrderNumber']) && is_numeric($_GET['ModifyOrderNumber'])) {
40
41         $_SESSION['page_title'] = _($help_context = "Modify Purchase Order #") . $_GET['ModifyOrderNumber'];
42         create_cart(ST_PURCHORDER, $_GET['ModifyOrderNumber']);
43         copy_from_cart();
44 } elseif (isset($_GET['NewOrder'])) {
45
46         $_SESSION['page_title'] = _($help_context = "Purchase Order Entry");
47         create_cart(ST_PURCHORDER, 0);
48         copy_from_cart();
49 } elseif (isset($_GET['NewGRN'])) {
50
51         $_SESSION['page_title'] = _($help_context = "Direct GRN Entry");
52         create_cart(ST_SUPPRECEIVE, 0);
53         copy_from_cart();
54 } elseif (isset($_GET['NewInvoice'])) {
55
56         create_cart(ST_SUPPINVOICE, 0);
57         copy_from_cart();
58
59         if (isset($_GET['FixedAsset'])) {
60                 $_SESSION['page_title'] = _($help_context = "Fixed Asset Purchase Invoice Entry");
61                 $_SESSION['PO']->fixed_asset = true;
62         } else
63                 $_SESSION['page_title'] = _($help_context = "Direct Purchase Invoice Entry");
64 }
65
66 page($_SESSION['page_title'], false, false, "", $js);
67
68 if (isset($_GET['ModifyOrderNumber']))
69         check_is_editable(ST_PURCHORDER, $_GET['ModifyOrderNumber']);
70
71 //---------------------------------------------------------------------------------------------------
72
73 check_db_has_suppliers(_("There are no suppliers defined in the system."));
74
75 //---------------------------------------------------------------------------------------------------------------
76
77 if (isset($_GET['AddedID'])) 
78 {
79         $order_no = $_GET['AddedID'];
80         $trans_type = ST_PURCHORDER;    
81
82         if (!isset($_GET['Updated']))
83                 display_notification_centered(_("Purchase Order has been entered"));
84         else
85                 display_notification_centered(_("Purchase Order has been updated") . " #$order_no");
86         display_note(get_trans_view_str($trans_type, $order_no, _("&View this order")), 0, 1);
87
88         display_note(print_document_link($order_no, _("&Print This Order"), true, $trans_type), 0, 1);
89
90         display_note(print_document_link($order_no, _("&Email This Order"), true, $trans_type, false, "printlink", "", 1));
91
92         hyperlink_params($path_to_root . "/purchasing/po_receive_items.php", _("&Receive Items on this Purchase Order"), "PONumber=$order_no");
93
94   // TODO, for fixed asset
95         hyperlink_params($_SERVER['PHP_SELF'], _("Enter &Another Purchase Order"), "NewOrder=yes");
96         
97         hyperlink_no_params($path_to_root."/purchasing/inquiry/po_search.php", _("Select An &Outstanding Purchase Order"));
98         
99         display_footer_exit();  
100
101 } elseif (isset($_GET['AddedGRN'])) {
102
103         $trans_no = $_GET['AddedGRN'];
104         $trans_type = ST_SUPPRECEIVE;
105
106         display_notification_centered(_("Direct GRN has been entered"));
107
108         display_note(get_trans_view_str($trans_type, $trans_no, _("&View this GRN")), 0);
109
110     $clearing_act = get_company_pref('grn_clearing_act');
111         if ($clearing_act)      
112                 display_note(get_gl_view_str($trans_type, $trans_no, _("View the GL Journal Entries for this Delivery")), 1);
113
114         hyperlink_params("$path_to_root/purchasing/supplier_invoice.php",
115                 _("Entry purchase &invoice for this receival"), "New=1");
116
117         hyperlink_params("$path_to_root/admin/attachments.php", _("Add an Attachment"), 
118                 "filterType=$trans_type&trans_no=$trans_no");
119
120         hyperlink_params($_SERVER['PHP_SELF'], _("Enter &Another GRN"), "NewGRN=Yes");
121         
122         display_footer_exit();  
123
124 } elseif (isset($_GET['AddedPI'])) {
125
126         $trans_no = $_GET['AddedPI'];
127         $trans_type = ST_SUPPINVOICE;
128
129         display_notification_centered(_("Direct Purchase Invoice has been entered"));
130
131         display_note(get_trans_view_str($trans_type, $trans_no, _("&View this Invoice")), 0);
132
133         display_note(get_gl_view_str($trans_type, $trans_no, _("View the GL Journal Entries for this Invoice")), 1);
134
135         hyperlink_params("$path_to_root/purchasing/supplier_payment.php", _("Entry supplier &payment for this invoice"),
136                 "trans_type=$trans_type&PInvoice=".$trans_no);
137
138         hyperlink_params("$path_to_root/admin/attachments.php", _("Add an Attachment"), 
139                 "filterType=$trans_type&trans_no=$trans_no");
140
141         hyperlink_params($_SERVER['PHP_SELF'], _("Enter &Another Direct Invoice"), "NewInvoice=Yes");
142         
143         display_footer_exit();  
144 }
145
146 if ($_SESSION['PO']->fixed_asset)
147   check_db_has_purchasable_fixed_assets(_("There are no purchasable fixed assets defined in the system."));
148 else
149   check_db_has_purchasable_items(_("There are no purchasable inventory items defined in the system."));
150 //--------------------------------------------------------------------------------------------------
151
152 function line_start_focus() {
153   global        $Ajax;
154
155   $Ajax->activate('items_table');
156   set_focus('_stock_id_edit');
157 }
158 //--------------------------------------------------------------------------------------------------
159
160 function unset_form_variables() {
161         unset($_POST['stock_id']);
162     unset($_POST['qty']);
163     unset($_POST['price']);
164     unset($_POST['req_del_date']);
165 }
166
167 //---------------------------------------------------------------------------------------------------
168
169 function handle_delete_item($line_no)
170 {
171         if($_SESSION['PO']->some_already_received($line_no) == 0)
172         {
173                 $_SESSION['PO']->remove_from_order($line_no);
174                 unset_form_variables();
175         } 
176         else 
177         {
178                 display_error(_("This item cannot be deleted because some of it has already been received."));
179         }       
180     line_start_focus();
181 }
182
183 //---------------------------------------------------------------------------------------------------
184
185 function handle_cancel_po()
186 {
187         global $path_to_root;
188         
189         //need to check that not already dispatched or invoiced by the supplier
190         if(($_SESSION['PO']->order_no != 0) && 
191                 $_SESSION['PO']->any_already_received() == 1)
192         {
193                 display_error(_("This order cannot be cancelled because some of it has already been received.") 
194                         . "<br>" . _("The line item quantities may be modified to quantities more than already received. prices cannot be altered for lines that have already been received and quantities cannot be reduced below the quantity already received."));
195                 return;
196         }
197
198         $fixed_asset = $_SESSION['PO']->fixed_asset;
199
200         if($_SESSION['PO']->order_no != 0)
201                 delete_po($_SESSION['PO']->order_no);
202         else {
203                 unset($_SESSION['PO']);
204
205         if ($fixed_asset)
206                         meta_forward($path_to_root.'/index.php','application=assets');
207                 else
208                         meta_forward($path_to_root.'/index.php','application=AP');
209         }
210
211         $_SESSION['PO']->clear_items();
212         $_SESSION['PO'] = new purch_order;
213
214         display_notification(_("This purchase order has been cancelled."));
215
216         hyperlink_params($path_to_root . "/purchasing/po_entry_items.php", _("Enter a new purchase order"), "NewOrder=Yes");
217         echo "<br>";
218
219         end_page();
220         exit;
221 }
222
223 //---------------------------------------------------------------------------------------------------
224
225 function check_data()
226 {
227         if(!get_post('stock_id_text', true)) {
228                 display_error( _("Item description cannot be empty."));
229                 set_focus('stock_id_edit');
230                 return false;
231         }
232
233         $dec = get_qty_dec($_POST['stock_id']);
234         $min = 1 / pow(10, $dec);
235     if (!check_num('qty',$min))
236     {
237         $min = number_format2($min, $dec);
238                 display_error(_("The quantity of the order item must be numeric and not less than ").$min);
239                 set_focus('qty');
240                 return false;
241     }
242
243     if (!check_num('price', 0))
244     {
245                 display_error(_("The price entered must be numeric and not less than zero."));
246                 set_focus('price');
247                 return false;      
248     }
249     if ($_SESSION['PO']->trans_type == ST_PURCHORDER && !is_date($_POST['req_del_date'])){
250                 display_error(_("The date entered is in an invalid format."));
251                 set_focus('req_del_date');
252                 return false;            
253     }
254      
255     return true;        
256 }
257
258 //---------------------------------------------------------------------------------------------------
259
260 function handle_update_item()
261 {
262         $allow_update = check_data(); 
263
264         if ($allow_update)
265         {
266                 if ($_SESSION['PO']->line_items[$_POST['line_no']]->qty_inv > input_num('qty') ||
267                         $_SESSION['PO']->line_items[$_POST['line_no']]->qty_received > input_num('qty'))
268                 {
269                         display_error(_("You are attempting to make the quantity ordered a quantity less than has already been invoiced or received.  This is prohibited.") .
270                                 "<br>" . _("The quantity received can only be modified by entering a negative receipt and the quantity invoiced can only be reduced by entering a credit note against this item."));
271                         set_focus('qty');
272                         return;
273                 }
274         
275                 $_SESSION['PO']->update_order_item($_POST['line_no'], input_num('qty'), input_num('price'),
276                         @$_POST['req_del_date'], $_POST['item_description'] );
277                 unset_form_variables();
278         }       
279     line_start_focus();
280 }
281
282 //---------------------------------------------------------------------------------------------------
283
284 function handle_add_new_item()
285 {
286         $allow_update = check_data();
287         
288         if ($allow_update == true)
289         { 
290                 if (count($_SESSION['PO']->line_items) > 0)
291                 {
292                     foreach ($_SESSION['PO']->line_items as $order_item) 
293                     {
294                         /* do a loop round the items on the order to see that the item
295                         is not already on this order */
296                             if (($order_item->stock_id == $_POST['stock_id'])) 
297                             {
298                                         display_warning(_("The selected item is already on this order."));
299                             }
300                     } /* end of the foreach loop to look for pre-existing items of the same code */
301                 }
302
303                 if ($allow_update == true)
304                 {
305                         $result = get_short_info($_POST['stock_id']);
306
307                         if (db_num_rows($result) == 0)
308                         {
309                                 $allow_update = false;
310                         }
311
312                         if ($allow_update)
313                         {
314                                 $_SESSION['PO']->add_to_order($_POST['stock_id'], input_num('qty'), 
315                                         get_post('stock_id_text'), input_num('price'), 
316                                         $_SESSION['PO']->trans_type == ST_PURCHORDER ? $_POST['req_del_date'] : '', 0, 0);
317
318                                 unset_form_variables();
319                                 $_POST['stock_id']      = "";
320                         } 
321                         else 
322                         {
323                              display_error(_("The selected item does not exist or it is a kit part and therefore cannot be purchased."));
324                         }
325
326                 } /* end of if not already on the order and allow input was true*/
327     }
328         line_start_focus();
329 }
330
331 //---------------------------------------------------------------------------------------------------
332
333 function can_commit()
334 {
335         if (!get_post('supplier_id')) 
336         {
337                 display_error(_("There is no supplier selected."));
338                 set_focus('supplier_id');
339                 return false;
340         } 
341
342         if (!is_date($_POST['OrderDate'])) 
343         {
344                 display_error(_("The entered order date is invalid."));
345                 set_focus('OrderDate');
346                 return false;
347         } 
348         if (($_SESSION['PO']->trans_type == ST_SUPPRECEIVE || $_SESSION['PO']->trans_type == ST_SUPPINVOICE) 
349                 && !is_date_in_fiscalyear($_POST['OrderDate'])) {
350                 display_error(_("The entered date is out of fiscal year or is closed for further data entry."));
351                 set_focus('OrderDate');
352                 return false;
353         }
354
355         if (($_SESSION['PO']->trans_type==ST_SUPPINVOICE) && !is_date($_POST['due_date'])) 
356         {
357                 display_error(_("The entered due date is invalid."));
358                 set_focus('due_date');
359                 return false;
360         } 
361
362         if (!$_SESSION['PO']->order_no) 
363         {
364         if (!check_reference(get_post('ref'), $_SESSION['PO']->trans_type))
365         {
366                         set_focus('ref');
367                 return false;
368         }
369         }
370
371         if ($_SESSION['PO']->trans_type == ST_SUPPINVOICE && trim(get_post('supp_ref')) == false)
372         {
373                 display_error(_("You must enter a supplier's invoice reference."));
374                 set_focus('supp_ref');
375                 return false;
376         }
377         if ($_SESSION['PO']->trans_type==ST_SUPPINVOICE 
378                 && is_reference_already_there($_SESSION['PO']->supplier_id, get_post('supp_ref'), $_SESSION['PO']->order_no))
379         {
380                 display_error(_("This invoice number has already been entered. It cannot be entered again.") . " (" . get_post('supp_ref') . ")");
381                 set_focus('supp_ref');
382                 return false;
383         }
384         if ($_SESSION['PO']->trans_type == ST_PURCHORDER && get_post('delivery_address') == '')
385         {
386                 display_error(_("There is no delivery address specified."));
387                 set_focus('delivery_address');
388                 return false;
389         } 
390         if (get_post('StkLocation') == '')
391         {
392                 display_error(_("There is no location specified to move any items into."));
393                 set_focus('StkLocation');
394                 return false;
395         } 
396         if (!db_has_currency_rates($_SESSION['PO']->curr_code, $_POST['OrderDate'], true))
397                 return false;
398         if ($_SESSION['PO']->order_has_items() == false)
399         {
400         display_error (_("The order cannot be placed because there are no lines entered on this order."));
401         return false;
402         }
403         if (floatcmp(input_num('prep_amount'), $_SESSION['PO']->get_trans_total()) > 0)
404         {
405                 display_error(_("Required prepayment is greater than total invoice value."));
406                 set_focus('prep_amount');
407                 return false;
408         }
409
410         return true;
411 }
412
413 function handle_commit_order()
414 {
415         $cart = &$_SESSION['PO'];
416
417         if (can_commit()) {
418
419                 copy_to_cart();
420                 new_doc_date($cart->tran_date);
421                 if ($cart->order_no == 0) { // new po/grn/invoice
422                         $trans_no = add_direct_supp_trans($cart);
423                         if ($trans_no) {
424                                 unset($_SESSION['PO']);
425                                 if ($cart->trans_type == ST_PURCHORDER)
426                                         meta_forward($_SERVER['PHP_SELF'], "AddedID=$trans_no");
427                                 elseif ($cart->trans_type == ST_SUPPRECEIVE)
428                                         meta_forward($_SERVER['PHP_SELF'], "AddedGRN=$trans_no");
429                                 else
430                                         meta_forward($_SERVER['PHP_SELF'], "AddedPI=$trans_no");
431                         }
432                 } else { // order modification
433                         $order_no = update_po($cart);
434                         unset($_SESSION['PO']);
435                 meta_forward($_SERVER['PHP_SELF'], "AddedID=$order_no&Updated=1");      
436                 }
437         }
438 }
439 //---------------------------------------------------------------------------------------------------
440 if (isset($_POST['update'])) {
441         copy_to_cart();
442         $Ajax->activate('items_table');
443 }
444
445 $id = find_submit('Delete');
446 if ($id != -1)
447         handle_delete_item($id);
448
449 if (isset($_POST['Commit']))
450 {
451         handle_commit_order();
452 }
453 if (isset($_POST['UpdateLine']))
454         handle_update_item();
455
456 if (isset($_POST['EnterLine']))
457         handle_add_new_item();
458
459 if (isset($_POST['CancelOrder'])) 
460         handle_cancel_po();
461
462 if (isset($_POST['CancelUpdate']))
463         unset_form_variables();
464
465 if (isset($_POST['CancelUpdate']) || isset($_POST['UpdateLine'])) {
466         line_start_focus();
467 }
468
469 //---------------------------------------------------------------------------------------------------
470
471 start_form();
472
473 display_po_header($_SESSION['PO']);
474 echo "<br>";
475
476 display_po_items($_SESSION['PO']);
477
478 start_table(TABLESTYLE2);
479
480
481 if ($_SESSION['PO']->trans_type == ST_SUPPINVOICE) {
482         cash_accounts_list_row(_("Payment:"), 'cash_account', null, false, _('Delayed'));
483 }
484
485 textarea_row(_("Memo:"), 'Comments', null, 70, 4);
486
487 end_table(1);
488
489 div_start('controls', 'items_table');
490 $process_txt = _("Place Order");
491 $update_txt = _("Update Order");
492 $cancel_txt = _("Cancel Order");
493 if ($_SESSION['PO']->trans_type == ST_SUPPRECEIVE) {
494         $process_txt = _("Process GRN");
495         $update_txt = _("Update GRN");
496         $cancel_txt = _("Cancel GRN");
497 }       
498 elseif ($_SESSION['PO']->trans_type == ST_SUPPINVOICE) {
499         $process_txt = _("Process Invoice");
500         $update_txt = _("Update Invoice");
501         $cancel_txt = _("Cancel Invoice");
502 }       
503 if ($_SESSION['PO']->order_has_items()) 
504 {
505         if ($_SESSION['PO']->order_no)
506                 submit_center_first('Commit', $update_txt, '', 'default');
507         else
508                 submit_center_first('Commit', $process_txt, '', 'default');
509         submit_center_last('CancelOrder', $cancel_txt);         
510 }
511 else
512         submit_center('CancelOrder', $cancel_txt, true, false, 'cancel');
513 div_end();
514 //---------------------------------------------------------------------------------------------------
515
516 end_form();
517 end_page();