More regarding costing valuations
[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_SUPPINVOICE) && !is_date($_POST['due_date'])) 
339         {
340                 display_error(_("The entered due date is invalid."));
341                 set_focus('due_date');
342                 return false;
343         } 
344         
345         if (!$_SESSION['PO']->order_no) 
346         {
347         if (!$Refs->is_valid(get_post('ref'))) 
348         {
349                 display_error(_("There is no reference entered for this purchase order."));
350                         set_focus('ref');
351                 return false;
352         } 
353         
354         if (!is_new_reference(get_post('ref'), $_SESSION['PO']->trans_type)) 
355         {
356                 display_error(_("The entered reference is already in use."));
357                         set_focus('ref');
358                 return false;
359         }
360         }
361         
362         if ($_SESSION['PO']->trans_type == ST_SUPPINVOICE && !$Refs->is_valid(get_post('supp_ref'))) 
363         {
364                 display_error(_("You must enter a supplier's invoice reference."));
365                 set_focus('supp_ref');
366                 return false;
367         }
368         if ($_SESSION['PO']->trans_type == ST_PURCHORDER && get_post('delivery_address') == '')
369         {
370                 display_error(_("There is no delivery address specified."));
371                 set_focus('delivery_address');
372                 return false;
373         } 
374         if (get_post('StkLocation') == '')
375         {
376                 display_error(_("There is no location specified to move any items into."));
377                 set_focus('StkLocation');
378                 return false;
379         } 
380         
381         if ($_SESSION['PO']->order_has_items() == false)
382         {
383         display_error (_("The order cannot be placed because there are no lines entered on this order."));
384         return false;
385         }
386                 
387         return true;
388 }
389
390 //---------------------------------------------------------------------------------------------------
391
392 function handle_commit_order()
393 {
394         $cart = &$_SESSION['PO'];
395
396         if (can_commit()) {
397
398                 copy_to_cart();
399                 if ($cart->trans_type != ST_PURCHORDER) {
400                         // for direct grn/invoice set same dates for lines as for whole document
401                         foreach ($cart->line_items as $line_no =>$line)
402                                 $cart->line_items[$line_no]->req_del_date = $cart->orig_order_date;
403                 }
404                 if ($cart->order_no == 0) { // new po/grn/invoice
405                         /*its a new order to be inserted */
406                         $ref = $cart->reference;
407                         if ($cart->trans_type != ST_PURCHORDER) {
408                                 $cart->reference = 'auto';
409                                 begin_transaction();    // all db changes as single transaction for direct document
410                         }
411                         $order_no = add_po($cart);
412                         new_doc_date($cart->orig_order_date); 
413                 $cart->order_no = $order_no;
414
415                         if ($cart->trans_type == ST_PURCHORDER) {
416                                 unset($_SESSION['PO']);
417                         meta_forward($_SERVER['PHP_SELF'], "AddedID=$order_no");
418                 }
419                         //Direct GRN
420                         if ($cart->trans_type == ST_SUPPRECEIVE)
421                                 $cart->reference = $ref;
422                         $cart->Comments = $cart->reference; //grn does not hold supp_ref
423                         foreach($cart->line_items as $key => $line)
424                                 $cart->line_items[$key]->receive_qty = $line->quantity;
425                         $grn_no = add_grn($cart);
426                         if ($cart->trans_type == ST_SUPPRECEIVE) {
427                                 commit_transaction(); // save PO+GRN
428                                 unset($_SESSION['PO']);
429                         meta_forward($_SERVER['PHP_SELF'], "AddedGRN=$grn_no");
430                         }
431 //                      Direct Purchase Invoice
432                         $inv = new supp_trans(ST_SUPPINVOICE);
433                         $inv->Comments = $cart->Comments;
434                         $inv->supplier_id = $cart->supplier_id;
435                         $inv->tran_date = $cart->orig_order_date;
436                         $inv->due_date = $cart->due_date;
437                         $inv->reference = $ref;
438                         $inv->supp_reference = $cart->supp_ref;
439                         $inv->tax_included = $cart->tax_included;
440                         $supp = get_supplier($cart->supplier_id);
441                         $inv->tax_group_id = $supp['tax_group_id'];
442 //                      $inv->ov_discount 'this isn't used at all'
443                         $inv->ov_amount = $inv->ov_gst = 0;
444                         
445                         foreach($cart->line_items as $key => $line) {
446                                 $inv->add_grn_to_trans($line->grn_item_id, $line->po_detail_rec, $line->stock_id,
447                                         $line->item_description, $line->receive_qty, 0, $line->receive_qty,
448                                         $line->price, $line->price, true, get_standard_cost($line->stock_id), '');
449                                 $inv->ov_amount += round2(($line->receive_qty * $line->price), user_price_dec());
450                         }
451                         $taxes = $inv->get_taxes($inv->tax_group_id, 0, false);
452                         foreach( $taxes as $taxitem) {
453                                 $inv->ov_gst += round2($taxitem['Value'], user_price_dec());
454                         }
455                         $inv_no = add_supp_invoice($inv);
456                         commit_transaction(); // save PO+GRN+PI
457                         // FIXME payment for cash terms. (Needs cash account selection)
458                         unset($_SESSION['PO']);
459                 meta_forward($_SERVER['PHP_SELF'], "AddedPI=$inv_no");
460                 }
461                 else { // order modification
462                 
463                         $order_no = update_po($cart);
464                         unset($_SESSION['PO']);
465                 meta_forward($_SERVER['PHP_SELF'], "AddedID=$order_no&Updated=1");      
466                 }
467         }
468 }
469 //---------------------------------------------------------------------------------------------------
470 $id = find_submit('Delete');
471 if ($id != -1)
472         handle_delete_item($id);
473
474 if (isset($_POST['Commit']))
475 {
476         handle_commit_order();
477 }
478 if (isset($_POST['UpdateLine']))
479         handle_update_item();
480
481 if (isset($_POST['EnterLine']))
482         handle_add_new_item();
483
484 if (isset($_POST['CancelOrder'])) 
485         handle_cancel_po();
486
487 if (isset($_POST['CancelUpdate']))
488         unset_form_variables();
489
490 if (isset($_POST['CancelUpdate']) || isset($_POST['UpdateLine'])) {
491         line_start_focus();
492 }
493
494 //---------------------------------------------------------------------------------------------------
495
496 start_form();
497
498 display_po_header($_SESSION['PO']);
499 echo "<br>";
500
501 display_po_items($_SESSION['PO']);
502
503 start_table(TABLESTYLE2);
504 textarea_row(_("Memo:"), 'Comments', null, 70, 4);
505
506 end_table(1);
507
508 div_start('controls', 'items_table');
509 $process_txt = _("Place Order");
510 $update_txt = _("Update Order");
511 $cancel_txt = _("Cancel Order");
512 if ($_SESSION['PO']->trans_type == ST_SUPPRECEIVE) {
513         $process_txt = _("Process GRN");
514         $update_txt = _("Update GRN");
515         $cancel_txt = _("Cancel GRN");
516 }       
517 elseif ($_SESSION['PO']->trans_type == ST_SUPPINVOICE) {
518         $process_txt = _("Process Invoice");
519         $update_txt = _("Update Invoice");
520         $cancel_txt = _("Cancel Invoice");
521 }       
522 if ($_SESSION['PO']->order_has_items()) 
523 {
524         if ($_SESSION['PO']->order_no)
525                 submit_center_first('Commit', $update_txt, '', 'default');
526         else
527                 submit_center_first('Commit', $process_txt, '', 'default');
528         submit_center_last('CancelOrder', $cancel_txt);         
529 }
530 else
531         submit_center('CancelOrder', $cancel_txt, true, false, 'cancel');
532 div_end();
533 //---------------------------------------------------------------------------------------------------
534
535 end_form();
536 end_page();
537 ?>