Added Item Code Entry in Work Order Entry and quantity decimals now follows the item
[fa-stable.git] / manufacturing / work_order_entry.php
1 <?php
2 /**********************************************************************
3     Copyright (C) FrontAccounting, LLC.
4         Released under the terms of the GNU General Public License, GPL, 
5         as published by the Free Software Foundation, either version 3 
6         of the License, or (at your option) any later version.
7     This program is distributed in the hope that it will be useful,
8     but WITHOUT ANY WARRANTY; without even the implied warranty of
9     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
10     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
11 ***********************************************************************/
12 $page_security = 10;
13 $path_to_root="..";
14
15 include_once($path_to_root . "/includes/session.inc");
16
17 include_once($path_to_root . "/includes/date_functions.inc");
18 include_once($path_to_root . "/includes/manufacturing.inc");
19 include_once($path_to_root . "/includes/data_checks.inc");
20
21 include_once($path_to_root . "/manufacturing/includes/manufacturing_db.inc");
22 include_once($path_to_root . "/manufacturing/includes/manufacturing_ui.inc");
23
24 $js = "";
25 if ($use_popup_windows)
26         $js .= get_js_open_window(900, 500);
27 if ($use_date_picker)
28         $js .= get_js_date_picker();
29 page(_("Work Order Entry"), false, false, "", $js);
30
31
32 check_db_has_manufacturable_items(_("There are no manufacturable items defined in the system."));
33
34 check_db_has_locations(("There are no inventory locations defined in the system."));
35
36 //---------------------------------------------------------------------------------------
37
38 if (isset($_GET['trans_no']))
39 {
40         $selected_id = $_GET['trans_no'];
41 }
42 elseif(isset($_POST['selected_id']))
43 {
44         $selected_id = $_POST['selected_id'];
45 }
46
47 //---------------------------------------------------------------------------------------
48
49 if (isset($_GET['AddedID']))
50 {
51         $id = $_GET['AddedID'];
52         $stype = systypes::work_order();
53
54         display_notification_centered(_("The work order been added."));
55
56     display_note(get_trans_view_str($stype, $id, _("View this Work Order")));
57
58         if ($_GET['type'] != wo_types::advanced())
59         {
60                 include_once($path_to_root . "/reporting/includes/reporting.inc");
61         display_note(get_gl_view_str($stype, $id, _("View the GL Journal Entries for this Work Order")), 1);
62         $ar = array('PARAM_0' => $_GET['date'], 'PARAM_1' => $_GET['date'], 'PARAM_2' => $stype); 
63         display_note(print_link(_("Print the GL Journal Entries for this Work Order"), 702, $ar), 1);
64         }
65         
66         safe_exit();
67 }
68
69 //---------------------------------------------------------------------------------------
70
71 if (isset($_GET['UpdatedID']))
72 {
73         $id = $_GET['UpdatedID'];
74
75         display_notification_centered(_("The work order been updated."));
76         safe_exit();
77 }
78
79 //---------------------------------------------------------------------------------------
80
81 if (isset($_GET['DeletedID']))
82 {
83         $id = $_GET['DeletedID'];
84
85         display_notification_centered(_("Work order has been deleted."));
86         safe_exit();
87 }
88
89 //---------------------------------------------------------------------------------------
90
91 if (isset($_GET['ClosedID']))
92 {
93         $id = $_GET['ClosedID'];
94
95         display_notification_centered(_("This work order has been closed. There can be no more issues against it.") . " #$id");
96         safe_exit();
97 }
98
99 //---------------------------------------------------------------------------------------
100
101 function safe_exit()
102 {
103         global $path_to_root;
104
105         hyperlink_no_params("", _("Enter a new work order"));
106         hyperlink_no_params("search_work_orders.php", _("Select an existing work order"));
107         
108         display_footer_exit();
109 }
110
111 //-------------------------------------------------------------------------------------
112 if (!isset($_POST['date_']))
113 {
114         $_POST['date_'] = Today();
115         if (!is_date_in_fiscalyear($_POST['date_']))
116                 $_POST['date_'] = end_fiscalyear();
117 }
118
119 function can_process()
120 {
121         global $selected_id;
122
123         if (!isset($selected_id))
124         {
125         if (!references::is_valid($_POST['wo_ref']))
126         {
127                 display_error(_("You must enter a reference."));
128                         set_focus('wo_ref');
129                 return false;
130         }
131
132         if (!is_new_reference($_POST['wo_ref'], systypes::work_order()))
133         {
134                 display_error(_("The entered reference is already in use."));
135                         set_focus('wo_ref');
136                 return false;
137         }
138         }
139
140         if (!check_num('quantity', 0))
141         {
142                 display_error( _("The quantity entered is invalid or less than zero."));
143                 set_focus('quantity');
144                 return false;
145         }
146
147         if (!is_date($_POST['date_']))
148         {
149                 display_error( _("The date entered is in an invalid format."));
150                 set_focus('date_');
151                 return false;
152         }
153         elseif (!is_date_in_fiscalyear($_POST['date_']))
154         {
155                 display_error(_("The entered date is not in fiscal year."));
156                 set_focus('date_');
157                 return false;
158         }
159         // only check bom and quantites if quick assembly
160         if (!($_POST['type'] == wo_types::advanced()))
161         {
162         if (!has_bom($_POST['stock_id']))
163         {
164                 display_error(_("The selected item to manufacture does not have a bom."));
165                         set_focus('stock_id');
166                 return false;
167         }
168
169                 if ($_POST['Labour'] == "")
170                         $_POST['Labour'] = price_format(0);
171         if (!check_num('Labour', 0))
172         {
173                 display_error( _("The labour cost entered is invalid or less than zero."));
174                         set_focus('Labour');
175                 return false;
176         }
177                 if ($_POST['Costs'] == "")
178                         $_POST['Costs'] = price_format(0);
179         if (!check_num('Costs', 0))
180         {
181                 display_error( _("The cost entered is invalid or less than zero."));
182                         set_focus('Costs');
183                 return false;
184         }
185
186         if (!sys_prefs::allow_negative_stock())
187         {
188                 if ($_POST['type'] == wo_types::assemble())
189                 {
190                         // check bom if assembling
191                 $result = get_bom($_POST['stock_id']);
192
193                 while ($bom_item = db_fetch($result))
194                 {
195
196                         if (has_stock_holding($bom_item["ResourceType"]))
197                         {
198
199                                 $quantity = $bom_item["quantity"] * input_num('quantity');
200
201                         $qoh = get_qoh_on_date($bom_item["component"], $bom_item["loc_code"], $_POST['date_']);
202                                 if (-$quantity + $qoh < 0)
203                                 {
204                                         display_error(_("The work order cannot be processed because there is an insufficient quantity for component:") .
205                                                 " " . $bom_item["component"] . " - " .  $bom_item["description"] . ".  " . _("Location:") . " " . $bom_item["location_name"]);
206                                                         set_focus('quantity');
207                                                 return false;
208                                 }
209                         }
210                 }
211                 }
212                 elseif ($_POST['type'] == wo_types::unassemble())
213                 {
214                         // if unassembling, check item to unassemble
215                                 $qoh = get_qoh_on_date($_POST['stock_id'], $_POST['StockLocation'], $_POST['date_']);
216                         if (-input_num('quantity') + $qoh < 0)
217                         {
218                                 display_error(_("The selected item cannot be unassembled because there is insufficient stock."));
219                                         return false;
220                         }
221                 }
222         }
223      }
224      else
225      {
226         if (!is_date($_POST['RequDate']))
227         {
228                         set_focus('RequDate');
229                 display_error( _("The date entered is in an invalid format."));
230                 return false;
231                 }
232                 //elseif (!is_date_in_fiscalyear($_POST['RequDate']))
233                 //{
234                 //      display_error(_("The entered date is not in fiscal year."));
235                 //      return false;
236                 //}
237         if (isset($selected_id))
238         {
239                 $myrow = get_work_order($selected_id, true);
240
241                 if ($_POST['units_issued'] > input_num('quantity'))
242                 {
243                                 set_focus('quantity');
244                         display_error(_("The quantity cannot be changed to be less than the quantity already manufactured for this order."));
245                         return false;
246                 }
247         }
248         }
249
250         return true;
251 }
252
253 //-------------------------------------------------------------------------------------
254
255 if (isset($_POST['ADD_ITEM']) && can_process())
256 {
257         if (!isset($_POST['cr_acc']))
258                 $_POST['cr_acc'] = "";
259         if (!isset($_POST['cr_lab_acc']))
260                 $_POST['cr_lab_acc'] = "";
261         $id = add_work_order($_POST['wo_ref'], $_POST['StockLocation'], input_num('quantity'),
262                 $_POST['stock_id'],  $_POST['type'], $_POST['date_'],
263                 $_POST['RequDate'], $_POST['memo_'], input_num('Costs'), $_POST['cr_acc'], input_num('Labour'), $_POST['cr_lab_acc']);
264
265         meta_forward($_SERVER['PHP_SELF'], "AddedID=$id&type=".$_POST['type']."&date=".$_POST['date_']);
266 }
267
268 //-------------------------------------------------------------------------------------
269
270 if (isset($_POST['UPDATE_ITEM']) && can_process())
271 {
272
273         update_work_order($selected_id, $_POST['StockLocation'], input_num('quantity'),
274                 $_POST['stock_id'],  $_POST['date_'], $_POST['RequDate'], $_POST['memo_']);
275
276         meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$selected_id");
277 }
278
279 //--------------------------------------------------------------------------------------
280
281 if (isset($_POST['delete']))
282 {
283         //the link to delete a selected record was clicked instead of the submit button
284
285         $cancel_delete = false;
286
287         // can't delete it there are productions or issues
288         if (work_order_has_productions($selected_id) ||
289                 work_order_has_issues($selected_id)     ||
290                 work_order_has_payments($selected_id))
291         {
292                 display_error(_("This work order cannot be deleted because it has already been processed."));
293                 $cancel_delete = true;
294         }
295
296         if ($cancel_delete == false)
297         { //ie not cancelled the delete as a result of above tests
298
299                 // delete the actual work order
300                 delete_work_order($selected_id);
301                 meta_forward($_SERVER['PHP_SELF'], "DeletedID=$selected_id");
302         }
303 }
304
305 //-------------------------------------------------------------------------------------
306
307 if (isset($_POST['close']))
308 {
309
310         // update the closed flag in the work order
311         close_work_order($selected_id);
312         meta_forward($_SERVER['PHP_SELF'], "ClosedID=$selected_id");
313 }
314
315 //-------------------------------------------------------------------------------------
316 if (get_post('_type_update')) 
317 {
318   $Ajax->activate('_page_body');
319 }
320 //-------------------------------------------------------------------------------------
321
322 start_form();
323
324 start_table($table_style2);
325
326 $existing_comments = "";
327
328 $dec = 0;
329 if (isset($selected_id))
330 {
331         $myrow = get_work_order($selected_id);
332
333         if (strlen($myrow[0]) == 0)
334         {
335                 echo _("The order number sent is not valid.");
336                 safe_exit();
337         }
338
339         // if it's a closed work order can't edit it
340         if ($myrow["closed"] == 1)
341         {
342                 echo "<center>";
343                 display_error(_("This work order is closed and cannot be edited."));
344                 safe_exit();
345         }
346
347         $_POST['wo_ref'] = $myrow["wo_ref"];
348         $_POST['stock_id'] = $myrow["stock_id"];
349         $_POST['quantity'] = qty_format($myrow["units_reqd"], $_POST['stock_id'], $dec);
350         $_POST['StockLocation'] = $myrow["loc_code"];
351         $_POST['released'] = $myrow["released"];
352         $_POST['closed'] = $myrow["closed"];
353         $_POST['type'] = $myrow["type"];
354         $_POST['date_'] = sql2date($myrow["date_"]);
355         $_POST['RequDate'] = sql2date($myrow["required_by"]);
356         $_POST['released_date'] = sql2date($myrow["released_date"]);
357         $_POST['memo_'] = "";
358         $_POST['units_issued'] = $myrow["units_issued"];
359         $_POST['Costs'] = price_format($myrow["additional_costs"]);
360
361         $_POST['memo_'] = get_comments_string(systypes::work_order(), $selected_id);
362
363         hidden('wo_ref', $_POST['wo_ref']);
364         hidden('units_issued', $_POST['units_issued']);
365         hidden('released', $_POST['released']);
366         hidden('released_date', $_POST['released_date']);
367         hidden('selected_id',  $selected_id);
368         hidden('old_qty', $myrow["units_reqd"]);
369         hidden('old_stk_id', $myrow["stock_id"]);
370
371         label_row(_("Reference:"), $_POST['wo_ref']);
372         label_row(_("Type:"), wo_types::name($_POST['type']));
373         hidden('type', $myrow["type"]);
374 }
375 else
376 {
377         $_POST['units_issued'] = $_POST['released'] = 0;
378         ref_row(_("Reference:"), 'wo_ref', '', references::get_next(systypes::work_order()));
379
380         wo_types_list_row(_("Type:"), 'type', null);
381 }
382
383 if (get_post('released'))
384 {
385         hidden('stock_id', $_POST['stock_id']);
386         hidden('StockLocation', $_POST['StockLocation']);
387         hidden('type', $_POST['type']);
388
389         label_row(_("Item:"), $myrow["StockItemName"]);
390         label_row(_("Destination Location:"), $myrow["location_name"]);
391 }
392 else
393 {
394         stock_manufactured_items_list_row(_("Item:"), 'stock_id', null, false, true);
395         if (list_updated('stock_id'))
396                 $Ajax->activate('quantity');
397
398         locations_list_row(_("Destination Location:"), 'StockLocation', null);
399 }
400
401 if (!isset($_POST['quantity']))
402         $_POST['quantity'] = qty_format(1, $_POST['stock_id'], $dec);
403 else
404         $_POST['quantity'] = qty_format($_POST['quantity'], $_POST['stock_id'], $dec);
405         
406
407 if (get_post('type') == wo_types::advanced())
408 {
409     qty_row(_("Quantity Required:"), 'quantity', null, null, null, $dec);
410     if ($_POST['released'])
411         label_row(_("Quantity Manufactured:"), number_format($_POST['units_issued'], get_qty_dec($_POST['stock_id'])));
412     date_row(_("Date") . ":", 'date_');
413         date_row(_("Date Required By") . ":", 'RequDate', '', null, sys_prefs::default_wo_required_by());
414 }
415 else
416 {
417     qty_row(_("Quantity:"), 'quantity', null, null, null, $dec);
418     date_row(_("Date") . ":", 'date_');
419         hidden('RequDate', '');
420
421         $sql = "SELECT DISTINCT account_code FROM ".TB_PREF."bank_accounts";
422         $rs = db_query($sql,"could not get bank accounts");
423         $r = db_fetch_row($rs);
424         if (!isset($_POST['Labour']))
425         {
426                 $_POST['Labour'] = price_format(0);
427                 $_POST['cr_lab_acc'] = $r[0];
428         }
429         amount_row($wo_cost_types[WO_LABOUR], 'Labour');
430         gl_all_accounts_list_row(_("Credit Labour Account"), 'cr_lab_acc', null);
431         if (!isset($_POST['Costs']))
432         {
433                 $_POST['Costs'] = price_format(0);
434                 $_POST['cr_acc'] = $r[0];
435         }
436         amount_row($wo_cost_types[WO_OVERHEAD], 'Costs');
437         gl_all_accounts_list_row(_("Credit Overhead Account"), 'cr_acc', null);
438         
439 }
440
441 if (get_post('released'))
442         label_row(_("Released On:"),$_POST['released_date']);
443
444 textarea_row(_("Memo:"), 'memo_', null, 40, 5);
445
446 end_table(1);
447
448 if (isset($selected_id))
449 {
450         echo "<table align=center><tr>";
451
452         submit_cells('UPDATE_ITEM', _("Update"), '', _('Save changes to work order'), true);
453         if (get_post('released'))
454         {
455                 submit_cells('close', _("Close This Work Order"),'','',true);
456         }
457         submit_cells('delete', _("Delete This Work Order"),'','',true);
458
459         echo "</tr></table>";
460 }
461 else
462 {
463         submit_center('ADD_ITEM', _("Add Workorder"), true, '', true);
464 }
465
466 end_form();
467 end_page();
468
469 ?>