25 class ScheduleParameters {
27 var rowDetails: Hash<Detail>;
28 public var mode:ScheduleMode;
30 function new(rawData : Dynamic) {
31 var data = php.Lib.hashOfAssociativeArray(rawData);
32 row_id = data.get('row_id');
33 var raw_order : Dynamic = data.get('row_order');
34 mode = ScheduleMode.Move;
36 var row_ids = php.Lib.toHaxeArray(raw_order);
38 rowDetails = new Hash<Detail>();
41 var d : Dynamic = data.get(id);
43 var to_pick : Int = null;
45 var o = php.Lib.objectOfAssociativeArray(d);
46 to_pick = Std.parseInt(o.to_pick);
60 public function setMode(action:String) {
61 mode = switch(action) {
71 public function position(id: String) : Null<Int> {
72 if(rowDetails == null) return null;
73 return rowDetails.get(id).position;
77 public function toPick(order: {id:String}) : Null<Int> {
78 var orderId = ItemScheduler.orderId(order);
79 if(rowDetails == null) return null;
80 return rowDetails.get(orderId).to_pick;
84 public function priority(order : {id: String, priority: Date}) : Int {
85 var orderId = ItemScheduler.orderId(order);
86 var orderPosition = position(orderId);
87 return orderPosition != null ? orderPosition : cast(order.priority.getTime(), Int);
94 var startLocation:String;
95 var parameters:ScheduleParameters;
97 function new(stock_id: String, startLocation, parameters : Null<ScheduleParameters>) {
98 this.stock_id = stock_id;
99 this.startLocation = startLocation;
100 this.parameters = parameters;
101 qoh = untyped __call__('get_qoh_on_date', this.stock_id, startLocation);
104 function tableHeader() {
105 return ["Order", "Customer", "Quantity", "Before", "After", "Loc", "From", "Required Date", "Comment", "To Pick"];
108 function generateTable(): Void {
109 var startDate = Date.fromTime(0);
111 // Sort location by date
112 var locations = this.locations();
113 locations.sort(function(a, b) {
114 var as = a.delivery.getTime();
115 var bs = b.delivery.getTime();
123 // Get the start location, it should be the first one
124 var locationIter = locations.iterator();
125 var location = locationIter.next();
126 var qoh : Int = location.quantityOnHand(stock_id, null);
129 // Get the total picked
130 var orders = this.orders();
131 var total_picked = 0;
132 for(order in orders) {
133 total_picked += toPick(order);
136 left -= total_picked;
137 if(left<0) FA.error('There is more items to pick than in stock');
138 formatLocation(location, "Initial", left);
140 // We display the order ordered by priority
141 // But insert the location when needed (meaning
142 // when we run out of item available
144 for(order in orders) {
145 var quantity : Int = Std.parseInt(order.quantity);
146 var to_pick = toPick(order);
147 // We don't need to remove the quantity which is picked
148 // as we have already counted it in the initial location calculation.
150 while(0 >= left && locationIter.hasNext()) {
151 location = locationIter.next();
152 var quantityForLocation : Int = location.quantityOnHand(stock_id, null) + location.quantityOnOrder(stock_id);
153 if(quantityForLocation == null || quantityForLocation == 0 || location.delivery == null) continue;
154 left += quantityForLocation;
155 formatLocation(location, "Delivery", left);
162 var now = Date.now();
163 formatOrder(order, to_pick>0 ? qoh : left, now.getTime() > location.delivery.getTime() ? now : location.delivery, now);
166 // display the left locations
167 while(0 >= left && locationIter.hasNext()) {
168 location = locationIter.next();
169 var quantityForLocation : Int = location.quantityOnHand(stock_id, null);
170 if(quantityForLocation == null || quantityForLocation == 0) continue;
171 left += quantityForLocation;
172 formatLocation(location, "Delivery", left);
177 function printRow(tds : Array<Dynamic>, attributes : Array<String>) {
178 php.Lib.print('<tr '+attributes.join(' ')+'>');
179 var position : Int = 1;
181 php.Lib.print('<td class="cell_'+position+'">');
182 if(td) php.Lib.print(td);
183 php.Lib.print('</td>');
186 php.Lib.print('</tr>');
189 static public function orderId(order) {
190 return 'order_'+order.id;
193 function formatOrder(order : Dynamic, left : Int, date : Date, now : Date) {
194 var row_id = orderId(order);
195 var attributes = ['id = "'+row_id+'"'];
197 var to_pick = toPick(order);
198 var before : Int = left + order.quantity- to_pick;
199 /* We have basically 3 different cases;
200 * - the order can be fullfilled
201 * - the order can be partially
205 classes.push('soldout');
208 classes.push('partial');
211 classes.push('full');
214 /* The order can also be late if we need
215 * to wait for a delivery to get it
216 * or early if the item is on hold.
218 var required_by : Date = FA.sql2date(order.required_date);
219 if(required_by == null) required_by = FA.sql2date(order.expiry_date);
221 classes.push('picked');
223 else if(required_by != null && required_by.getTime() < date.getTime()) {
224 classes.push('late');
227 var hold_until : Date = FA.sql2date(order.hold_until_date);
228 //php.Lib.print(hold_until);
229 //php.Lib.print(date);
230 if(hold_until == null) hold_until = FA.sql2date(order.delivery_date);
231 if((hold_until.getTime() - FA.preHoldOffset()) > date.getTime()) {
232 classes.push('early');
235 classes.push('on_time');
239 // Check if the order is expired
240 var expiry_date : Date = FA.sql2date(order.expiry_date);
241 if(expiry_date != null && (now.getTime() > expiry_date.getTime())) classes.push('expired');
243 var cells : Array <Dynamic> = [
245 , '<a href="/modules/order_line_extra/order_lines_view.php?customer_id='+Std.string(order.debtor_no)+'">'+order.deliver_to+'</a>'
246 , order.quantity // '<input type="text" name="'+row_id+'[quantity]" value="'+order.quantity+'">'
250 ,order.hold_until_date
253 ,quantity_box(row_id, order, left)
256 attributes.push('class="'+classes.join(' ')+'"');
257 printRow(cells, attributes);
261 function quantity_box(row_id, order, left:Int) {
262 var maxQuantity = order.quantity;
263 var quantity = order.to_pick;
264 var available = order.quantity > left ? left : order.quantity;
265 var user_pick = parameters == null ? quantity : parameters.toPick(order);
266 if (user_pick == null) user_pick = 0;
267 var inputs : Array<String> = [];
268 if(maxQuantity > 12) {
269 inputs.push('<span class="picked">'+(quantity == null ? 0 : quantity)+' </span>');
270 inputs.push('<input type="text" name="'+row_id+'[to_pick]" value="'+user_pick+'" onchange=\'onPick(this);\'>');
273 inputs.push('<span class="pickable">');
274 for(q in 0...(maxQuantity+1)) {
275 var last_available = untyped __php__(' $q == $available ? true: false');
276 var current_pick = untyped __php__(' $q == $user_pick ? true:false');
277 var picked = untyped __php__(' $q == $quantity');
278 var differs = untyped __php__('$user_pick != $quantity');
279 var checked = current_pick ? "checked": "";
280 var klass : String = q > available ? 'early' : "";
281 inputs.push('<input type="radio" name="'+row_id+'[to_pick]" value="'+q+'" '+checked+' class="'+klass+'"
282 onclick=\'onPick(this);\'
284 inputs.push(picked ? '<span class="picked">'+q+'</span>' : ''+q);
285 inputs.push('</input>');
287 inputs.push('</span>');
288 inputs.push('<span class="partial">');
291 inputs.push('</span>');
294 return inputs.join('');
297 function formatLocation(location : Location, type: String, left : Int) {
301 ,location.quantityOnHand(stock_id, null)
302 ,left-location.quantityOnHand(stock_id, null)
305 ,location.delivery.getTime() == 0 ? '' : location.delivery.format("%F")
311 printRow(cells, ['class = "tableheader location"', 'id = "loc_'+location.code+'"']);
315 function schedules() {
316 //return orders()+locations();
318 return cast(locations(), Array<Dynamic>);
323 private function loadOrders() {
324 var tb : String = untyped __php__('TB_PREF');
325 var sql : String = "SELECT * , d.quantity as qty, d.priority AS pp, p.quantity AS to_pick
326 FROM "+tb+"denorm_order_details_queue d
327 JOIN "+tb+"sales_order_details od ON (od.id = d.id)
328 JOIN "+tb+"sales_orders so ON (so.order_no = d.order_id)
329 LEFT JOIN ("+FA.pick_query()+") p ON (p.detail_id = od.id)
330 WHERE stock_id = '"+this.stock_id+"'
331 AND od.trans_type = 30
332 ORDER by quantity_before, d.priority";
334 return FA.query(sql);
337 function orders():Array<Order> {
338 var rows = loadOrders();
341 // for some reason, priority is null
342 // so we use the pp field
343 var a:Dynamic = php.Lib.objectOfAssociativeArray(row);
345 order.priority = Date.fromString(a.pp);
346 order.quantity = a.qty;
347 orderList.push(order);
350 if(parameters != null) {
351 orderList.sort(function(a, b) { return parameters.priority(a)-parameters.priority(b); });
354 for(order in orderList) {
362 function locations() {
365 FROM '+TB+'locations';
367 for(row in FA.query(sql)) {
368 var location = new Location(row);
369 if(location.code == startLocation) {
370 location.delivery = Date.fromTime(0);
372 else if(location.delivery == null) {
375 _locs.push(location);
383 function purcharseOrders() {
385 var sql = 'SELECT SUM(quantity_ordered - quantity_received) as quantity
386 into_stock_location AS location
387 FROM '+TB+'purch_order_details
388 NATURAL JOIN '+TB+'purch_orders
389 WHERE item_code = "'+this.stock_id+'"
390 AND quantity_ordered > quantity_received
391 GROUP by item_code,delivery_date, into_stock_location
392 ORDER by delivery_date' ;
394 return FA.query(sql);
397 public function needsUpdate():Bool {
398 return parameters != null && parameters.mode == ScheduleMode.Move;
402 var orders = this.orders();
403 var priorities = Lambda.array(Lambda.map(orders, function(o) { return o.priority;}));
404 priorities.sort(function(a,b) {
405 var as = a.toString();
406 var bs = b.toString();
407 if (as < bs) return -1;
408 if( as > bs) return 1;
412 var iter = priorities.iterator();
414 var position:Int = 0-priorities.length;
415 for(order in orders) {
416 var new_priority = DateTools.delta(p, 1000*position);
418 untyped __call__ ('update_order_detail_priority', order.id, new_priority.toString());
420 // Update to pick table if needed
421 if (Std.parseInt(order.to_pick) != toPick(order)) {
422 untyped __call__ ('update_pick', order.id, toPick(order));
429 untyped __call__ ('update_queue_quantity_for_item', stock_id);
433 public function action() {
434 if(parameters != null && parameters.mode == ScheduleMode.Update) {
439 public function toPick(order) {
440 var picked : Int = Std.parseInt(order.to_pick);
441 var user_picked : Int = null;
442 if(parameters != null) user_picked = parameters.toPick(order);
443 return user_picked == null ? picked : user_picked ;