Added db_write/db_void hooks.
[fa-stable.git] / manufacturing / includes / db / work_orders_db.inc
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 //--------------------------------------------------------------------------------------
13
14 function add_material_cost($stock_id, $qty, $date_)
15 {
16         $m_cost = 0;
17     $result = get_bom($stock_id);
18         while ($bom_item = db_fetch($result))
19         {
20                 $standard_cost = get_standard_cost($bom_item['component']);
21                 $m_cost += ($bom_item['quantity'] * $standard_cost);
22         }
23         //$dec = user_price_dec();
24         //price_decimal_format($m_cost, $dec);
25         $sql = "SELECT material_cost FROM ".TB_PREF."stock_master WHERE stock_id = "
26                 .db_escape($stock_id);
27         $result = db_query($sql);
28         $myrow = db_fetch($result);
29         $material_cost =  $myrow['material_cost'];
30         //$qoh = get_qoh_on_date($stock_id, null, $date_);
31         $qoh = get_qoh_on_date($stock_id);
32         if ($qoh < 0)
33                 $qoh = 0;
34         if ($qoh + $qty != 0)   
35                 $material_cost = ($qoh * $material_cost + $qty * $m_cost) /     ($qoh + $qty);
36         //$material_cost = round2($material_cost, $dec);        
37         $sql = "UPDATE ".TB_PREF."stock_master SET material_cost=$material_cost
38                 WHERE stock_id=".db_escape($stock_id);
39         db_query($sql,"The cost details for the inventory item could not be updated");
40 }
41
42 function add_overhead_cost($stock_id, $qty, $date_, $costs)
43 {
44         //$dec = user_price_dec();
45         //price_decimal_format($costs, $dec); 
46         if ($qty != 0)
47                 $costs /= $qty;
48         $sql = "SELECT overhead_cost FROM ".TB_PREF."stock_master WHERE stock_id = "
49                 .db_escape($stock_id);
50         $result = db_query($sql);
51         $myrow = db_fetch($result);
52         $overhead_cost =  $myrow['overhead_cost'];
53         //$qoh = get_qoh_on_date($stock_id, null, $date_);
54         $qoh = get_qoh_on_date($stock_id);
55         if ($qoh < 0)
56                 $qoh = 0;
57         if ($qoh + $qty != 0)   
58                 $overhead_cost = ($qoh * $overhead_cost + $qty * $costs) /      ($qoh + $qty);
59         //$overhead_cost = round2($overhead_cost, $dec);        
60         $sql = "UPDATE ".TB_PREF."stock_master SET overhead_cost=".db_escape($overhead_cost)."
61                 WHERE stock_id=".db_escape($stock_id);
62         db_query($sql,"The cost details for the inventory item could not be updated");
63 }
64
65 function add_labour_cost($stock_id, $qty, $date_, $costs)
66 {
67         //$dec = user_price_dec();
68         //price_decimal_format($costs, $dec); 
69         if ($qty != 0)
70                 $costs /= $qty;
71         $sql = "SELECT labour_cost FROM ".TB_PREF."stock_master WHERE stock_id = "
72                 .db_escape($stock_id);
73         $result = db_query($sql);
74         $myrow = db_fetch($result);
75         $labour_cost =  $myrow['labour_cost'];
76         //$qoh = get_qoh_on_date($stock_id, null, $date_);
77         $qoh = get_qoh_on_date($stock_id);
78         if ($qoh < 0)
79                 $qoh = 0;
80         if ($qoh + $qty != 0)   
81                 $labour_cost = ($qoh * $labour_cost + $qty * $costs) /  ($qoh + $qty);
82         //$labour_cost = round2($labour_cost, $dec);    
83         $sql = "UPDATE ".TB_PREF."stock_master SET labour_cost=".db_escape($labour_cost)."
84                 WHERE stock_id=".db_escape($stock_id);
85         db_query($sql,"The cost details for the inventory item could not be updated");
86 }
87
88 function add_issue_cost($stock_id, $qty, $date_, $costs)
89 {
90         if ($qty != 0)
91                 $costs /= $qty;
92         $sql = "SELECT material_cost FROM ".TB_PREF."stock_master WHERE stock_id = "
93                 .db_escape($stock_id);
94         $result = db_query($sql);
95         $myrow = db_fetch($result);
96         $material_cost =  $myrow['material_cost'];
97         //$dec = user_price_dec();
98         //price_decimal_format($material_cost, $dec); 
99         //$qoh = get_qoh_on_date($stock_id, null, $date_);
100         $qoh = get_qoh_on_date($stock_id);
101         if ($qoh < 0)
102                 $qoh = 0;
103         if ($qoh + $qty != 0)   
104                 $material_cost = ($qty * $costs) /      ($qoh + $qty);
105         //$material_cost = round2($material_cost, $dec);        
106         $sql = "UPDATE ".TB_PREF."stock_master SET material_cost=material_cost+"
107                 .db_escape($material_cost)
108                 ." WHERE stock_id=".db_escape($stock_id);
109         db_query($sql,"The cost details for the inventory item could not be updated");
110 }
111
112 function add_work_order($wo_ref, $loc_code, $units_reqd, $stock_id,
113         $type, $date_, $required_by, $memo_, $costs, $cr_acc, $labour, $cr_lab_acc)
114 {
115         global $Refs;
116
117         if (!($type == WO_ADVANCED))
118                 return add_work_order_quick($wo_ref, $loc_code, $units_reqd, $stock_id, $type, $date_, $memo_, $costs, $cr_acc, $labour, $cr_lab_acc);
119
120         begin_transaction();
121         $args = func_get_args();
122         $args = (object)array_combine(array('wo_ref', 'loc_code', 'units_reqd', 'stock_id',
123                 'type', 'date_', 'required_by', 'memo_', 'costs', 'cr_acc', 'labour', 'cr_lab_acc'), $args);
124         $args->woid = 0;
125         hook_db_prewrite($args, ST_WORKORDER);
126
127         add_material_cost($stock_id, $units_reqd, $date_);
128
129         $date = date2sql($date_);
130         $required = date2sql($required_by);
131
132         $sql = "INSERT INTO ".TB_PREF."workorders (wo_ref, loc_code, units_reqd, stock_id,
133                 type, date_, required_by)
134         VALUES (".db_escape($wo_ref).", ".db_escape($loc_code).", "
135         .db_escape($units_reqd).", ".db_escape($stock_id).",
136                 ".db_escape($type).", '$date', ".db_escape($required).")";
137         db_query($sql, "could not add work order");
138
139         $woid = db_insert_id();
140
141         add_comments(ST_WORKORDER, $woid, $required_by, $memo_);
142
143         $Refs->save(ST_WORKORDER, $woid, $wo_ref);
144         add_audit_trail(ST_WORKORDER, $woid, $date_);
145
146         $args->woid = $woid;
147         hook_db_postwrite($args, ST_WORKORDER);
148         commit_transaction();
149
150         return $woid;
151 }
152
153 //--------------------------------------------------------------------------------------
154
155 function update_work_order($woid, $loc_code, $units_reqd, $stock_id,
156                                         $date_, $required_by, $memo_)
157 {
158         begin_transaction();
159         $args = func_get_args();
160         $args = (object)array_combine(array('woid', 'loc_code', 'units_reqd', 'stock_id',
161                 'date_', 'required_by', 'memo_'), $args);
162         hook_db_prewrite($args, ST_WORKORDER);
163
164         add_material_cost($_POST['old_stk_id'], -$_POST['old_qty'], $date_);
165         add_material_cost($stock_id, $units_reqd, $date_);
166
167         $date = date2sql($date_);
168         $required = date2sql($required_by);
169
170         $sql = "UPDATE ".TB_PREF."workorders SET loc_code=".db_escape($loc_code).",
171                 units_reqd=".db_escape($units_reqd).", stock_id=".db_escape($stock_id).",
172                 required_by=".db_escape($required).",
173                 date_='$date'
174                 WHERE id = ".db_escape($woid);
175
176         db_query($sql, "could not update work order");
177
178         update_comments(ST_WORKORDER, $woid, null, $memo_);
179         add_audit_trail(ST_WORKORDER, $woid, $date_, _("Updated."));
180
181         hook_db_postwrite($args, ST_WORKORDER);
182         commit_transaction();
183 }
184
185 function delete_work_order($woid)
186 {
187         begin_transaction();
188         hook_db_prevoid(ST_WORKORDER, $woid);
189
190         add_material_cost($_POST['stock_id'], -$_POST['quantity'], $_POST['date_']);
191
192         // delete the work order requirements
193         delete_wo_requirements($woid);
194
195         // delete the actual work order
196         $sql = "DELETE FROM ".TB_PREF."workorders WHERE id=".db_escape($woid);
197         db_query($sql,"The work order could not be deleted");
198
199         delete_comments(ST_WORKORDER, $woid);
200         add_audit_trail(ST_WORKORDER, $woid, $_POST['date_'], _("Canceled."));
201
202         commit_transaction();
203 }
204
205 //--------------------------------------------------------------------------------------
206
207 function get_work_order($woid, $allow_null=false)
208 {
209     $sql = "SELECT wo.*,st.description As StockItemName,l.location_name,
210                 l.delivery_address,l.email, l.contact
211                 FROM ".TB_PREF."workorders wo, ".TB_PREF."stock_master st, ".TB_PREF."locations l
212                 WHERE st.stock_id=wo.stock_id
213                 AND     l.loc_code=wo.loc_code
214                 AND wo.id=".db_escape($woid)."
215                 GROUP BY wo.id";
216
217         $result = db_query($sql, "The work order issues could not be retrieved");
218
219         if (!$allow_null && db_num_rows($result) == 0)
220                 display_db_error("Could not find work order $woid", $sql);
221
222         return db_fetch($result);
223 }
224
225 //--------------------------------------------------------------------------------------
226
227 function work_order_has_productions($woid)
228 {
229         $sql = "SELECT COUNT(*) FROM ".TB_PREF."wo_manufacture WHERE workorder_id=".db_escape($woid);
230         $result = db_query($sql, "query work order for productions");
231
232         $myrow = db_fetch_row($result);
233         return ($myrow[0] > 0);
234 }
235
236
237 //--------------------------------------------------------------------------------------
238
239 function work_order_has_issues($woid)
240 {
241         $sql = "SELECT COUNT(*) FROM ".TB_PREF."wo_issues WHERE workorder_id=".db_escape($woid);
242         $result = db_query($sql, "query work order for issues");
243
244         $myrow = db_fetch_row($result);
245         return ($myrow[0] > 0);
246 }
247
248 //--------------------------------------------------------------------------------------
249
250 function work_order_has_payments($woid)
251 {
252         $result = get_gl_wo_cost_trans($woid);
253
254     return (db_num_rows($result) != 0);
255 }
256
257 //--------------------------------------------------------------------------------------
258
259 function release_work_order($woid, $releaseDate, $memo_)
260 {
261         begin_transaction();
262
263         $myrow = get_work_order($woid);
264         $stock_id = $myrow["stock_id"];
265
266         $date = date2sql($releaseDate);
267
268         $sql = "UPDATE ".TB_PREF."workorders SET released_date='$date',
269                 released=1 WHERE id = ".db_escape($woid);
270         db_query($sql, "could not release work order");
271
272         // create Work Order Requirements based on the bom
273         create_wo_requirements($woid, $stock_id);
274
275         add_comments(ST_WORKORDER, $woid, $releaseDate, $memo_);
276         add_audit_trail(ST_WORKORDER, $woid, $releaseDate,_("Released."));
277
278         commit_transaction();
279 }
280
281 //--------------------------------------------------------------------------------------
282
283 function close_work_order($woid)
284 {
285         $sql = "UPDATE ".TB_PREF."workorders SET closed=1 WHERE id = ".db_escape($woid);
286         db_query($sql, "could not close work order");
287 }
288
289 //--------------------------------------------------------------------------------------
290
291 function work_order_is_closed($woid)
292 {
293         $sql = "SELECT closed FROM ".TB_PREF."workorders WHERE id = ".db_escape($woid);
294         $result = db_query($sql, "could not query work order");
295         $row = db_fetch_row($result);
296         return ($row[0] > 0);
297 }
298
299 //--------------------------------------------------------------------------------------
300
301 function work_order_update_finished_quantity($woid, $quantity, $force_close=0)
302 {
303         $sql = "UPDATE ".TB_PREF."workorders SET units_issued = units_issued + ".db_escape($quantity).",
304                 closed = ((units_issued >= units_reqd) OR ".db_escape($force_close).")
305                 WHERE id = ".db_escape($woid);
306
307         db_query($sql, "The work order issued quantity couldn't be updated");
308 }
309
310 //--------------------------------------------------------------------------------------
311
312 function void_work_order($woid)
313 {
314         begin_transaction();
315         hook_db_prevoid(ST_WORKORDER, $woid);
316
317         $work_order = get_work_order($woid);
318         if (!($work_order["type"] == WO_ADVANCED))
319         {
320                 $date = sql2date($work_order['date_']);
321                 $qty = $work_order['units_reqd'];
322                 add_material_cost($work_order['stock_id'], -$qty, $date); // remove avg. cost for qty
323                 $cost = get_gl_wo_cost($woid, WO_LABOUR); // get the labour cost and reduce avg cost
324                 if ($cost != 0)
325                         add_labour_cost($work_order['stock_id'], -$qty, $date, $cost);
326                 $cost = get_gl_wo_cost($woid, WO_OVERHEAD); // get the overhead cost and reduce avg cost
327                 if ($cost != 0)
328                         add_overhead_cost($work_order['stock_id'], -$qty, $date, $cost);
329
330                 $sql = "UPDATE ".TB_PREF."workorders SET closed=1,units_reqd=0,units_issued=0 WHERE id = "
331                         .db_escape($woid);
332                 db_query($sql, "The work order couldn't be voided");
333
334                 // void all related stock moves
335                 void_stock_move(ST_WORKORDER, $woid);
336
337                 // void any related gl trans
338                 void_gl_trans(ST_WORKORDER, $woid, true);
339
340                 // clear the requirements units received
341                 void_wo_requirements($woid);
342         }
343         else
344         {
345                 // void everything inside the work order : issues, productions, payments
346                 $date = sql2date($work_order['date_']);
347                 add_material_cost($work_order['stock_id'], -$work_order['units_reqd'], $date); // remove avg. cost for qty
348                 $result = get_work_order_productions($woid); // check the produced quantity
349                 $qty = 0;
350                 while ($row = db_fetch($result))
351                 {
352                         $qty += $row['quantity'];
353                         // clear the production record
354                         $sql = "UPDATE ".TB_PREF."wo_manufacture SET quantity=0 WHERE id=".$$row['id'];
355                         db_query($sql, "Cannot void a wo production");
356                         
357                         void_stock_move(ST_MANURECEIVE, $row['id']); // and void the stock moves; 
358                 }
359                 $result = get_additional_issues($woid); // check the issued quantities
360                 $cost = 0;
361                 $issue_no = 0;
362                 while ($row = db_fetch($result))
363                 {
364                         $std_cost = get_standard_cost($row['stock_id']);
365                         $icost = $std_cost * $row['qty_issued'];
366                         $cost += $icost;
367                         if ($issue_no == 0)
368                                 $issue_no = $row['issue_no'];
369                         // void the actual issue items and their quantities
370                         $sql = "UPDATE ".TB_PREF."wo_issue_items SET qty_issued = 0 WHERE issue_id="
371                                 .db_escape($row['id']);
372                         db_query($sql,"A work order issue item could not be voided");
373                 }       
374                 if ($issue_no != 0)
375                         void_stock_move(ST_MANUISSUE, $issue_no); // and void the stock moves 
376                 if ($cost != 0)
377                         add_issue_cost($work_order['stock_id'], -$qty, $date, $cost);
378
379                 $cost = get_gl_wo_cost($woid, WO_LABOUR); // get the labour cost and reduce avg cost
380                 if ($cost != 0)
381                         add_labour_cost($work_order['stock_id'], -$qty, $date, $cost);
382                 $cost = get_gl_wo_cost($woid, WO_OVERHEAD); // get the overhead cost and reduce avg cost
383                 if ($cost != 0)
384                         add_overhead_cost($work_order['stock_id'], -$qty, $date, $cost);
385                 
386                 $sql = "UPDATE ".TB_PREF."workorders SET closed=1,units_reqd=0,units_issued=0 WHERE id = "
387                         .db_escape($woid);
388                 db_query($sql, "The work order couldn't be voided");
389
390                 // void all related stock moves
391                 void_stock_move(ST_WORKORDER, $woid);
392
393                 // void any related gl trans
394                 void_gl_trans(ST_WORKORDER, $woid, true);
395
396                 // clear the requirements units received
397                 void_wo_requirements($woid);
398         }
399         commit_transaction();
400 }
401
402 function get_sql_for_work_orders($outstanding_only, $all_items)
403 {
404         $sql = "SELECT
405                 workorder.id,
406                 workorder.wo_ref,
407                 workorder.type,
408                 location.location_name,
409                 item.description,
410                 workorder.units_reqd,
411                 workorder.units_issued,
412                 workorder.date_,
413                 workorder.required_by,
414                 workorder.released_date,
415                 workorder.closed,
416                 workorder.released,
417                 workorder.stock_id,
418                 unit.decimals
419                 FROM ".TB_PREF."workorders as workorder,"
420                         .TB_PREF."stock_master as item,"
421                         .TB_PREF."item_units as unit,"
422                         .TB_PREF."locations as location
423                 WHERE workorder.stock_id=item.stock_id 
424                         AND workorder.loc_code=location.loc_code
425                         AND item.units=unit.abbr";
426
427         if (check_value('OpenOnly') || $outstanding_only != 0)
428         {
429                 $sql .= " AND workorder.closed=0";
430         }
431
432         if (isset($_POST['StockLocation']) && $_POST['StockLocation'] != $all_items)
433         {
434                 $sql .= " AND workorder.loc_code=".db_escape($_POST['StockLocation']);
435         }
436
437         if (isset($_POST['OrderNumber']) && $_POST['OrderNumber'] != "")
438         {
439                 $sql .= " AND workorder.wo_ref LIKE ".db_escape('%'.$_POST['OrderNumber'].'%');
440         }
441
442         if (isset($_POST['SelectedStockItem']) && $_POST['SelectedStockItem'] != $all_items)
443         {
444                 $sql .= " AND workorder.stock_id=".db_escape($_POST['SelectedStockItem']);
445         }
446
447         if (check_value('OverdueOnly'))
448         {
449                 $Today = date2sql(Today());
450
451                 $sql .= " AND workorder.required_by < '$Today' ";
452         }
453         return $sql;
454 }
455
456 function get_sql_for_where_used()
457 {
458         $sql = "SELECT 
459                         bom.parent,
460                         workcentre.name As WorkCentreName,
461                         location.location_name,
462                         bom.quantity,
463                         parent.description
464                         FROM ".TB_PREF."bom as bom, "
465                                 .TB_PREF."stock_master as parent, "
466                                 .TB_PREF."workcentres as workcentre, "
467                                 .TB_PREF."locations as location
468                         WHERE bom.parent = parent.stock_id 
469                                 AND bom.workcentre_added = workcentre.id
470                                 AND bom.loc_code = location.loc_code
471                                 AND bom.component=".db_escape($_POST['stock_id']);
472         return $sql;                    
473 }
474 //--------------------------------------------------------------------------------------
475 function get_gl_wo_cost($woid, $cost_type)
476 {
477         $cost = 0;
478         $result = get_gl_wo_cost_trans($woid, $cost_type);
479         while ($row = db_fetch($result))
480                 $cost += -$row['amount'];
481         return $cost;   
482 }
483
484 ?>