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