2c9817741640e8abcf4cdcfa41f332a8a203547e
[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_'] = new_doc_date();
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         new_doc_date($_POST['date_']);
266         meta_forward($_SERVER['PHP_SELF'], "AddedID=$id&type=".$_POST['type']."&date=".$_POST['date_']);
267 }
268
269 //-------------------------------------------------------------------------------------
270
271 if (isset($_POST['UPDATE_ITEM']) && can_process())
272 {
273
274         update_work_order($selected_id, $_POST['StockLocation'], input_num('quantity'),
275                 $_POST['stock_id'],  $_POST['date_'], $_POST['RequDate'], $_POST['memo_']);
276         new_doc_date($_POST['date_']);
277         meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$selected_id");
278 }
279
280 //--------------------------------------------------------------------------------------
281
282 if (isset($_POST['delete']))
283 {
284         //the link to delete a selected record was clicked instead of the submit button
285
286         $cancel_delete = false;
287
288         // can't delete it there are productions or issues
289         if (work_order_has_productions($selected_id) ||
290                 work_order_has_issues($selected_id)     ||
291                 work_order_has_payments($selected_id))
292         {
293                 display_error(_("This work order cannot be deleted because it has already been processed."));
294                 $cancel_delete = true;
295         }
296
297         if ($cancel_delete == false)
298         { //ie not cancelled the delete as a result of above tests
299
300                 // delete the actual work order
301                 delete_work_order($selected_id);
302                 meta_forward($_SERVER['PHP_SELF'], "DeletedID=$selected_id");
303         }
304 }
305
306 //-------------------------------------------------------------------------------------
307
308 if (isset($_POST['close']))
309 {
310
311         // update the closed flag in the work order
312         close_work_order($selected_id);
313         meta_forward($_SERVER['PHP_SELF'], "ClosedID=$selected_id");
314 }
315
316 //-------------------------------------------------------------------------------------
317 if (get_post('_type_update')) 
318 {
319   $Ajax->activate('_page_body');
320 }
321 //-------------------------------------------------------------------------------------
322
323 start_form();
324
325 start_table($table_style2);
326
327 $existing_comments = "";
328
329 $dec = 0;
330 if (isset($selected_id))
331 {
332         $myrow = get_work_order($selected_id);
333
334         if (strlen($myrow[0]) == 0)
335         {
336                 echo _("The order number sent is not valid.");
337                 safe_exit();
338         }
339
340         // if it's a closed work order can't edit it
341         if ($myrow["closed"] == 1)
342         {
343                 echo "<center>";
344                 display_error(_("This work order is closed and cannot be edited."));
345                 safe_exit();
346         }
347
348         $_POST['wo_ref'] = $myrow["wo_ref"];
349         $_POST['stock_id'] = $myrow["stock_id"];
350         $_POST['quantity'] = qty_format($myrow["units_reqd"], $_POST['stock_id'], $dec);
351         $_POST['StockLocation'] = $myrow["loc_code"];
352         $_POST['released'] = $myrow["released"];
353         $_POST['closed'] = $myrow["closed"];
354         $_POST['type'] = $myrow["type"];
355         $_POST['date_'] = sql2date($myrow["date_"]);
356         $_POST['RequDate'] = sql2date($myrow["required_by"]);
357         $_POST['released_date'] = sql2date($myrow["released_date"]);
358         $_POST['memo_'] = "";
359         $_POST['units_issued'] = $myrow["units_issued"];
360         $_POST['Costs'] = price_format($myrow["additional_costs"]);
361
362         $_POST['memo_'] = get_comments_string(systypes::work_order(), $selected_id);
363
364         hidden('wo_ref', $_POST['wo_ref']);
365         hidden('units_issued', $_POST['units_issued']);
366         hidden('released', $_POST['released']);
367         hidden('released_date', $_POST['released_date']);
368         hidden('selected_id',  $selected_id);
369         hidden('old_qty', $myrow["units_reqd"]);
370         hidden('old_stk_id', $myrow["stock_id"]);
371
372         label_row(_("Reference:"), $_POST['wo_ref']);
373         label_row(_("Type:"), wo_types::name($_POST['type']));
374         hidden('type', $myrow["type"]);
375 }
376 else
377 {
378         $_POST['units_issued'] = $_POST['released'] = 0;
379         ref_row(_("Reference:"), 'wo_ref', '', references::get_next(systypes::work_order()));
380
381         wo_types_list_row(_("Type:"), 'type', null);
382 }
383
384 if (get_post('released'))
385 {
386         hidden('stock_id', $_POST['stock_id']);
387         hidden('StockLocation', $_POST['StockLocation']);
388         hidden('type', $_POST['type']);
389
390         label_row(_("Item:"), $myrow["StockItemName"]);
391         label_row(_("Destination Location:"), $myrow["location_name"]);
392 }
393 else
394 {
395         stock_manufactured_items_list_row(_("Item:"), 'stock_id', null, false, true);
396         if (list_updated('stock_id'))
397                 $Ajax->activate('quantity');
398
399         locations_list_row(_("Destination Location:"), 'StockLocation', null);
400 }
401
402 if (!isset($_POST['quantity']))
403         $_POST['quantity'] = qty_format(1, $_POST['stock_id'], $dec);
404 else
405         $_POST['quantity'] = qty_format($_POST['quantity'], $_POST['stock_id'], $dec);
406         
407
408 if (get_post('type') == wo_types::advanced())
409 {
410     qty_row(_("Quantity Required:"), 'quantity', null, null, null, $dec);
411     if ($_POST['released'])
412         label_row(_("Quantity Manufactured:"), number_format($_POST['units_issued'], get_qty_dec($_POST['stock_id'])));
413     date_row(_("Date") . ":", 'date_', '', true);
414         date_row(_("Date Required By") . ":", 'RequDate', '', null, sys_prefs::default_wo_required_by());
415 }
416 else
417 {
418     qty_row(_("Quantity:"), 'quantity', null, null, null, $dec);
419     date_row(_("Date") . ":", 'date_', '', true);
420         hidden('RequDate', '');
421
422         $sql = "SELECT DISTINCT account_code FROM ".TB_PREF."bank_accounts";
423         $rs = db_query($sql,"could not get bank accounts");
424         $r = db_fetch_row($rs);
425         if (!isset($_POST['Labour']))
426         {
427                 $_POST['Labour'] = price_format(0);
428                 $_POST['cr_lab_acc'] = $r[0];
429         }
430         amount_row($wo_cost_types[WO_LABOUR], 'Labour');
431         gl_all_accounts_list_row(_("Credit Labour Account"), 'cr_lab_acc', null);
432         if (!isset($_POST['Costs']))
433         {
434                 $_POST['Costs'] = price_format(0);
435                 $_POST['cr_acc'] = $r[0];
436         }
437         amount_row($wo_cost_types[WO_OVERHEAD], 'Costs');
438         gl_all_accounts_list_row(_("Credit Overhead Account"), 'cr_acc', null);
439         
440 }
441
442 if (get_post('released'))
443         label_row(_("Released On:"),$_POST['released_date']);
444
445 textarea_row(_("Memo:"), 'memo_', null, 40, 5);
446
447 end_table(1);
448
449 if (isset($selected_id))
450 {
451         echo "<table align=center><tr>";
452
453         submit_cells('UPDATE_ITEM', _("Update"), '', _('Save changes to work order'), 'default');
454         if (get_post('released'))
455         {
456                 submit_cells('close', _("Close This Work Order"),'','',true);
457         }
458         submit_cells('delete', _("Delete This Work Order"),'','',true);
459
460         echo "</tr></table>";
461 }
462 else
463 {
464         submit_center('ADD_ITEM', _("Add Workorder"), true, '', 'default');
465 }
466
467 end_form();
468 end_page();
469
470 ?>