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