Fix delete.
[order_line_extra.git] / hincludes / lib / ItemScheduler.class.php
1 <?php
2
3 class ItemScheduler {
4         public function __construct($stock_id, $startLocation, $parameters) {
5                 if(!php_Boot::$skip_constructor) {
6                 $this->stock_id = $stock_id;
7                 $this->startLocation = $startLocation;
8                 $this->parameters = $parameters;
9                 $this->qoh = get_qoh_on_date($this->stock_id, $startLocation);
10         }}
11         public function toPick($order) {
12                 $picked = Std::parseInt($order->to_pick);
13                 $user_picked = null;
14                 if($this->parameters !== null) {
15                         $user_picked = $this->parameters->toPick($order);
16                 }
17                 return (($user_picked === null) ? $picked : $user_picked);
18         }
19         public function action() {
20                 if($this->parameters !== null && $this->parameters->mode == ScheduleMode::$Update) {
21                         $this->update();
22                 }
23         }
24         public function update() {
25                 $orders = $this->orders();
26                 $priorities = Lambda::harray(Lambda::map($orders, array(new _hx_lambda(array(&$orders), "ItemScheduler_0"), 'execute')));
27                 $priorities->sort(array(new _hx_lambda(array(&$orders, &$priorities), "ItemScheduler_1"), 'execute'));
28                 $iter = $priorities->iterator();
29                 $p = $iter->next();
30                 $position = 0 - $priorities->length;
31                 {
32                         $_g = 0;
33                         while($_g < $orders->length) {
34                                 $order = $orders[$_g];
35                                 ++$_g;
36                                 $new_priority = DateTools::delta($p, 1000 * $position);
37                                 update_order_detail_priority($order->id, $new_priority->toString());
38                                 if(Std::parseInt($order->to_pick) !== $this->toPick($order)) {
39                                         update_pick($order->id, $this->toPick($order));
40                                 }
41                                 $position += 1;
42                                 $p = $iter->next();
43                                 unset($order,$new_priority);
44                         }
45                 }
46                 update_queue_quantity_for_item($this->stock_id);
47         }
48         public function needsUpdate() {
49                 return $this->parameters !== null && $this->parameters->mode == ScheduleMode::$Move;
50         }
51         public function purcharseOrders() {
52                 $TB = FA::tb();
53                 $sql = "SELECT SUM(quantity_ordered - quantity_received) as quantity\x0A\x09\x09into_stock_location AS location\x0A\x09\x09FROM " . $TB . "purch_order_details\x0A\x09\x09NATURAL JOIN " . $TB . "purch_orders\x0A\x09\x09WHERE item_code = \"" . $this->stock_id . "\"\x0A\x09\x09AND quantity_ordered > quantity_received\x0A\x09\x09GROUP by item_code,delivery_date, into_stock_location\x0A\x09\x09ORDER by delivery_date";
54                 return FA::query($sql);
55         }
56         public function locations() {
57                 $TB = FA::tb();
58                 $sql = "SELECT * \x0A\x09\x09FROM " . $TB . "locations";
59                 $_locs = new _hx_array(array());
60                 if(null == _hx_qtype("FA")) throw new HException('null iterable');
61                 $»it = FA::query($sql);
62                 while($»it->hasNext()) {
63                         $row = $»it->next();
64                         $location = new Location($row);
65                         if($location->code === $this->startLocation) {
66                                 $location->delivery = Date::fromTime(0);
67                         } else {
68                                 if($location->delivery === null) {
69                                         continue;
70                                 }
71                         }
72                         $_locs->push($location);
73                         unset($location);
74                 }
75                 return $_locs;
76         }
77         public function orders() {
78                 $_g = $this;
79                 $rows = $this->loadOrders();
80                 $orderList = new _hx_array(array());
81                 $»it = $rows;
82                 while($»it->hasNext()) {
83                         $row = $»it->next();
84                         $a = php_Lib::objectOfAssociativeArray($row);
85                         $order = $a;
86                         $order->priority = Date::fromString($a->pp);
87                         $order->quantity = $a->qty;
88                         $orderList->push($order);
89                         unset($order,$a);
90                 }
91                 if($this->parameters !== null) {
92                         $orderList->sort(array(new _hx_lambda(array(&$_g, &$orderList, &$rows), "ItemScheduler_2"), 'execute'));
93                 }
94                 {
95                         $_g1 = 0;
96                         while($_g1 < $orderList->length) {
97                                 $order = $orderList[$_g1];
98                                 ++$_g1;
99                                 unset($order);
100                         }
101                 }
102                 return $orderList;
103         }
104         public function loadOrders() {
105                 $tb = TB_PREF;
106                 $sql = "SELECT *  , d.quantity as qty,   d.priority AS pp, p.quantity AS to_pick\x0A\x09\x09FROM " . $tb . "denorm_order_details_queue  d\x0A\x09\x09JOIN " . $tb . "sales_order_details od ON (od.id = d.id)\x0A\x09\x09JOIN " . $tb . "sales_orders so ON (so.order_no = d.order_id)\x0A\x09\x09LEFT JOIN (" . FA::pick_query() . ") p ON (p.detail_id = od.id)\x0A\x09\x09WHERE stock_id = '" . $this->stock_id . "'\x0A\x09\x09AND od.trans_type = 30\x0A\x09\x09ORDER by quantity_before, d.priority";
107                 return FA::query($sql);
108         }
109         public function formatLocation($location, $type, $left) {
110                 $cells = new _hx_array(array($type, $location->name, $location->quantityOnHand($this->stock_id, null), $left - $location->quantityOnHand($this->stock_id, null), $left, $location->code, ((_hx_equal($location->delivery->getTime(), 0)) ? "" : DateTools::format($location->delivery, "%F")), "", "", ""));
111                 $this->printRow($cells, new _hx_array(array("class = \"tableheader location\"", "id = \"loc_" . $location->code . "\"")));
112         }
113         public function quantity_box($row_id, $order, $left) {
114                 $maxQuantity = $order->quantity;
115                 $quantity = $order->to_pick;
116                 $available = ItemScheduler_3($this, $left, $maxQuantity, $order, $quantity, $row_id);
117                 $user_pick = (($this->parameters === null) ? $quantity : $this->parameters->toPick($order));
118                 if($user_pick === null) {
119                         $user_pick = 0;
120                 }
121                 $inputs = new _hx_array(array());
122                 if($maxQuantity > 12) {
123                         $inputs->push("<span class=\"picked\">" . _hx_string_rec($quantity, "") . " </span>");
124                         $inputs->push("<input type=\"text\" name=\"" . $row_id . "[to_pick]\" value=\"" . _hx_string_rec($user_pick, "") . "\" onchange='onPick(this);'>");
125                 } else {
126                         $inputs->push("<span class=\"pickable\">");
127                         {
128                                 $_g1 = 0; $_g = $maxQuantity + 1;
129                                 while($_g1 < $_g) {
130                                         $q = $_g1++;
131                                         $last_available =  $q == $available ? true: false;
132                                         $current_pick =  $q == $user_pick ? true:false;
133                                         $picked =  $q == $quantity;
134                                         $differs = $user_pick != $quantity;
135                                         $checked = (($current_pick) ? "checked" : "");
136                                         $klass = (($q > $available) ? "early" : "");
137                                         $inputs->push("<input type=\"radio\" name=\"" . $row_id . "[to_pick]\" value=\"" . _hx_string_rec($q, "") . "\" " . $checked . " class=\"" . $klass . "\"\x0A\x09\x09\x09\x09onclick='onPick(this);'\x0A\x09\x09\x09\x09>");
138                                         $inputs->push(ItemScheduler_4($this, $_g, $_g1, $available, $checked, $current_pick, $differs, $inputs, $klass, $last_available, $left, $maxQuantity, $order, $picked, $q, $quantity, $row_id, $user_pick));
139                                         $inputs->push("</input>");
140                                         if($last_available) {
141                                                 $inputs->push("</span>");
142                                                 $inputs->push("<span class=\"partial\">");
143                                         }
144                                         unset($q,$picked,$last_available,$klass,$differs,$current_pick,$checked);
145                                 }
146                         }
147                         $inputs->push("</span>");
148                 }
149                 return $inputs->join("");
150         }
151         public function formatOrder($order, $left, $date, $now) {
152                 $row_id = ItemScheduler::orderId($order);
153                 $attributes = new _hx_array(array("id = \"" . $row_id . "\""));
154                 $classes = new _hx_array(array());
155                 $to_pick = $this->toPick($order);
156                 $before = $left + $order->quantity - $to_pick;
157                 if($before < 0) {
158                         $classes->push("soldout");
159                 } else {
160                         if($left < 0) {
161                                 $classes->push("partial");
162                         } else {
163                                 $classes->push("full");
164                         }
165                 }
166                 $required_by = FA::sql2date($order->required_date);
167                 if($required_by === null) {
168                         $required_by = FA::sql2date($order->expiry_date);
169                 }
170                 if($to_pick > 0) {
171                         $classes->push("picked");
172                 } else {
173                         if($required_by !== null && $required_by->getTime() < $date->getTime()) {
174                                 $classes->push("late");
175                         } else {
176                                 $hold_until = FA::sql2date($order->hold_until_date);
177                                 if($hold_until === null) {
178                                         $hold_until = FA::sql2date($order->delivery_date);
179                                 }
180                                 if($hold_until->getTime() - FA::preHoldOffset() > $date->getTime()) {
181                                         $classes->push("early");
182                                 } else {
183                                         $classes->push("on_time");
184                                 }
185                         }
186                 }
187                 $expiry_date = FA::sql2date($order->expiry_date);
188                 if($expiry_date !== null && $now->getTime() > $expiry_date->getTime()) {
189                         $classes->push("expired");
190                 }
191                 $cells = new _hx_array(array($order->order_id, "<a href=\"/modules/order_line_extra/order_lines_view.php?customer_id=" . Std::string($order->debtor_no) . "\">" . Std::string($order->deliver_to) . "</a>", $order->quantity, $before, $left, $order->from_stk_loc, $order->hold_until_date, $order->required_date, $order->comment, $this->quantity_box($row_id, $order, $left)));
192                 $attributes->push("class=\"" . $classes->join(" ") . "\"");
193                 $this->printRow($cells, $attributes);
194         }
195         public function printRow($tds, $attributes) {
196                 php_Lib::hprint("<tr " . $attributes->join(" ") . ">");
197                 $position = 1;
198                 {
199                         $_g = 0;
200                         while($_g < $tds->length) {
201                                 $td = $tds[$_g];
202                                 ++$_g;
203                                 php_Lib::hprint("<td class=\"cell_" . _hx_string_rec($position, "") . "\">");
204                                 if($td) {
205                                         php_Lib::hprint($td);
206                                 }
207                                 php_Lib::hprint("</td>");
208                                 $position++;
209                                 unset($td);
210                         }
211                 }
212                 php_Lib::hprint("</tr>");
213         }
214         public function generateTable() {
215                 $startDate = Date::fromTime(0);
216                 $locations = $this->locations();
217                 $locations->sort(array(new _hx_lambda(array(&$locations, &$startDate), "ItemScheduler_5"), 'execute'));
218                 $locationIter = $locations->iterator();
219                 $location = $locationIter->next();
220                 $qoh = $location->quantityOnHand($this->stock_id, null);
221                 $left = $qoh;
222                 $orders = $this->orders();
223                 $total_picked = 0;
224                 {
225                         $_g = 0;
226                         while($_g < $orders->length) {
227                                 $order = $orders[$_g];
228                                 ++$_g;
229                                 $total_picked += $this->toPick($order);
230                                 unset($order);
231                         }
232                 }
233                 $left -= $total_picked;
234                 if($left < 0) {
235                         FA::error("There is more items to pick than in stock");
236                 }
237                 $this->formatLocation($location, "Initial", $left);
238                 {
239                         $_g = 0;
240                         while($_g < $orders->length) {
241                                 $order = $orders[$_g];
242                                 ++$_g;
243                                 $quantity = Std::parseInt($order->quantity);
244                                 $to_pick = $this->toPick($order);
245                                 while(0 >= $left && $locationIter->hasNext()) {
246                                         $location = $locationIter->next();
247                                         $quantityForLocation = $location->quantityOnHand($this->stock_id, null) + $location->quantityOnOrder($this->stock_id);
248                                         if($quantityForLocation === null || $quantityForLocation === 0 || $location->delivery === null) {
249                                                 continue;
250                                         }
251                                         $left += $quantityForLocation;
252                                         $this->formatLocation($location, "Delivery", $left);
253                                         unset($quantityForLocation);
254                                 }
255                                 if($to_pick > 0) {
256                                         $qoh -= $quantity;
257                                 } else {
258                                         $left -= $quantity;
259                                 }
260                                 $now = Date::now();
261                                 $this->formatOrder($order, (($to_pick > 0) ? $qoh : $left), ItemScheduler_6($this, $_g, $left, $location, $locationIter, $locations, $now, $order, $orders, $qoh, $quantity, $startDate, $to_pick, $total_picked), $now);
262                                 unset($to_pick,$quantity,$order,$now);
263                         }
264                 }
265                 while(0 >= $left && $locationIter->hasNext()) {
266                         $location = $locationIter->next();
267                         $quantityForLocation = $location->quantityOnHand($this->stock_id, null);
268                         if($quantityForLocation === null || $quantityForLocation === 0) {
269                                 continue;
270                         }
271                         $left += $quantityForLocation;
272                         $this->formatLocation($location, "Delivery", $left);
273                         unset($quantityForLocation);
274                 }
275         }
276         public function tableHeader() {
277                 return new _hx_array(array("Order", "Customer", "Quantity", "Before", "After", "Loc", "From", "Required Date", "Comment", "To Pick"));
278         }
279         public $qoh;
280         public $parameters;
281         public $startLocation;
282         public $stock_id;
283         public function __call($m, $a) {
284                 if(isset($this->$m) && is_callable($this->$m))
285                         return call_user_func_array($this->$m, $a);
286                 else if(isset($this->»dynamics[$m]) && is_callable($this->»dynamics[$m]))
287                         return call_user_func_array($this->»dynamics[$m], $a);
288                 else if('toString' == $m)
289                         return $this->__toString();
290                 else
291                         throw new HException('Unable to call «'.$m.'»');
292         }
293         static function orderId($order) {
294                 return "order_" . $order->id;
295         }
296         function __toString() { return 'ItemScheduler'; }
297 }
298 function ItemScheduler_0(&$orders, $o) {
299         {
300                 return $o->priority;
301         }
302 }
303 function ItemScheduler_1(&$orders, &$priorities, $a, $b) {
304         {
305                 $as = $a->toString();
306                 $bs = $b->toString();
307                 if($as < $bs) {
308                         return -1;
309                 }
310                 if($as > $bs) {
311                         return 1;
312                 }
313                 return 0;
314         }
315 }
316 function ItemScheduler_2(&$_g, &$orderList, &$rows, $a, $b) {
317         {
318                 return $_g->parameters->priority($a) - $_g->parameters->priority($b);
319         }
320 }
321 function ItemScheduler_3(&$»this, &$left, &$maxQuantity, &$order, &$quantity, &$row_id) {
322         if($order->quantity > $left) {
323                 return $left;
324         } else {
325                 return $order->quantity;
326         }
327 }
328 function ItemScheduler_4(&$»this, &$_g, &$_g1, &$available, &$checked, &$current_pick, &$differs, &$inputs, &$klass, &$last_available, &$left, &$maxQuantity, &$order, &$picked, &$q, &$quantity, &$row_id, &$user_pick) {
329         if($picked) {
330                 return "<span class=\"picked\">" . _hx_string_rec($q, "") . "</span>";
331         } else {
332                 return "" . _hx_string_rec($q, "");
333         }
334 }
335 function ItemScheduler_5(&$locations, &$startDate, $a, $b) {
336         {
337                 $as = $a->delivery->getTime();
338                 $bs = $b->delivery->getTime();
339                 if($as < $bs) {
340                         return -1;
341                 } else {
342                         if($as > $bs) {
343                                 return 1;
344                         } else {
345                                 return 0;
346                         }
347                 }
348         }
349 }
350 function ItemScheduler_6(&$»this, &$_g, &$left, &$location, &$locationIter, &$locations, &$now, &$order, &$orders, &$qoh, &$quantity, &$startDate, &$to_pick, &$total_picked) {
351         if($now->getTime() > $location->delivery->getTime()) {
352                 return $now;
353         } else {
354                 return $location->delivery;
355         }
356 }