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