Splitter Test written. Doesn't pass.
[order_line_extra.git] / haxe / ItemScheduler.hx
index be596ac4d121b87f0f547ed3e59984c3c4dbf2fd..274f562b256a1999e3a04296c2a6d3686f73473c 100644 (file)
 import php.Lib;
+using DateTools;
 
-enum Maybe<T> {
-       Nothing;
-       Just(v : T);
+typedef Detail = {
+       id : String,
+       quantity : Int,
+       position : Int,
 }
 
-class QueryIterator<T> {
-       var result : Dynamic;
-       var nextValue : Maybe<T>;
-       public function new(result) {
-               this.result= result;
-               /* We fetch the first row , so we can answer hasNext */
-               fetch();
-       }
+typedef Order = {
+               id:String
+               ,quantity:String
+               ,priority:Date
+               ,delivery_date:String
 
-       private function fetch() {
-               var next : Dynamic = untyped __call__('db_fetch', this.result);
-               nextValue = if(next) Just(next) else Nothing;
-       }
+}
 
-       public function  hasNext() : Bool {
-               return this.nextValue != Nothing;
-       }
+enum ScheduleMode {
+       Update;
+       Cancel;
+       Move;
+}
 
-       public function next() : T {
-               switch(this.nextValue) {
-               case Nothing : throw 'Iterator exhausted';
-               case Just(v) :  {
-                       this.fetch();
-                       return v;
-               };
+class ScheduleParameters {
+       var row_id : String;
+       var rowDetails: Hash<Detail>;
+       public var mode:ScheduleMode;
+
+       function new(rawData : Dynamic) {
+               var data  = php.Lib.hashOfAssociativeArray(rawData);
+               row_id = data.get('row_id');
+               var raw_order : Dynamic = data.get('row_order');
+               mode = ScheduleMode.Move;
+
+               var row_ids = php.Lib.toHaxeArray(raw_order);
+               if (row_ids!= null) {
+                       rowDetails = new Hash<Detail>();
+                       var position = 1;
+                       for(id in row_ids) {
+                               var d : Dynamic = data.get(id);
+
+                               var quantity : Int = null;
+                               if(d != null) {
+                                               var o = php.Lib.objectOfAssociativeArray(d);
+                                               quantity = Std.parseInt(o.quantity);
+                               }
+                               
+
+                               rowDetails.set(id, {
+                                       id: id
+                                       ,quantity: quantity
+                                       ,position: position
+                                       });
+                               position+=1;
+                       }
                }
        }
-}
-class FA {
-       static public function query(sql: String) {
-               var result = untyped __call__('db_query', sql, sql);
-               return new QueryIterator(result);
+
+       public function setMode(action:String) {
+               mode = switch(action) {
+                       case "update" :
+                               ScheduleMode.Update;
+                       case "cancel" :
+                               ScheduleMode.Cancel;
+                       default:
+                               ScheduleMode.Move;
+               };
        }
 
-       static public function tb() : String {
-               return untyped __php__('TB_PREF');
+       public function position(id: String) : Null<Int> {
+               if(rowDetails == null) return null;
+               return rowDetails.get(id).position;
+
        }
 
-       static public function sql2date(sqlDate:Dynamic) : Null<Date> {
-               return sqlDate == null ? null : Date.fromString(sqlDate);
+       public function priority(order : {id: String, priority: Date})  : Int {
+               var orderId = ItemScheduler.orderId(order);
+               var orderPosition = position(orderId);
+               return orderPosition != null  ? orderPosition : cast(order.priority.getTime(), Int);
        }
 }
+
+
 class ItemScheduler {
        var stock_id:String;
        var startLocation:String;
+       var parameters:ScheduleParameters; 
        var qoh: Int;
-       function new(stock_id: String, startLocation) {
+       function new(stock_id: String, startLocation, parameters : Null<ScheduleParameters>) {
                this.stock_id = stock_id;
                this.startLocation = startLocation;
-               qoh =  untyped __call__('get_qoh_on_date', this.stock_id, 'DEF');
+               this.parameters = parameters;
+               qoh =  untyped __call__('get_qoh_on_date', this.stock_id, startLocation);
        }
 
        function tableHeader() {
                return ["Order", "Customer", "Quantity", "Before", "After", "Loc", "From",  "Required Date", "Comment"];
        }
 
-/*
-       function generateTablex(): Void {
-               for(location in locations()) {
-                       formatLocation(location, null);
-               }
-               for(order in this.orders()) {
-                       this.formatRow(order);
-               }
-       }
-*/
-
        function generateTable(): Void {
-                       var startDate = Date.fromTime(0);
-                       for(order in orders()) {
-                                       var obj = php.Lib.objectOfAssociativeArray(order);
-
-                       }       
-
-                       // Sort location by datae
-                       var locations = this.locations();
-                       locations.sort(function(a, b) {
-                               return cast(a.delivery.getTime() - b.delivery.getTime(), Int );
+               var startDate = Date.fromTime(0);
+
+               // Sort location by date
+               var locations = this.locations();
+               locations.sort(function(a, b) {
+                       var as = a.delivery.getTime();
+                       var bs = b.delivery.getTime();
+                       if(as < bs) 
+                               return -1;
+                       else if(as > bs)
+                               return 1;
+                       else return 0;
                                });
 
                // Get the start location, it should be the first one
@@ -95,23 +122,30 @@ class ItemScheduler {
                // We display the order ordered by priority 
                // But insert the location when needed (meaning
                // when we run out of item available
-               for(orderRow in orders()) {
-                       var order = php.Lib.objectOfAssociativeArray(orderRow);
+               for(order in orders()) {
                        var quantity : Int = Std.parseInt(order.quantity);
 
-                       while(0 > left && locationIter.hasNext()) {
+                       while(0 >= left && locationIter.hasNext()) {
                                location = locationIter.next();
-                               var quantityForLocation : Int = location.quantityOnHand(stock_id, null);
-                               if(quantityForLocation == null || quantityForLocation == 0) continue;
+                               var quantityForLocation : Int = location.quantityOnHand(stock_id, null) + location.quantityOnOrder(stock_id);
+                               if(quantityForLocation == null || quantityForLocation == 0 || location.delivery == null) continue;
                                left += quantityForLocation;
                                formatLocation(location, "Delivery", left);
                        }
                        left -= quantity;
 
                        formatOrder(order, left, location.delivery);
-                       
+
                }
-                       
+               // display the left locations
+                       while(0 >= left && locationIter.hasNext()) {
+                               location = locationIter.next();
+                               var quantityForLocation : Int = location.quantityOnHand(stock_id, null);
+                               if(quantityForLocation == null || quantityForLocation == 0) continue;
+                               left += quantityForLocation;
+                               formatLocation(location, "Delivery", left);
+                       }
+
        }
 
        function printRow(tds : Array<Dynamic>, attributes : Array<String>) {
@@ -126,29 +160,33 @@ class ItemScheduler {
                php.Lib.print('</tr>');
        }
 
+       static public function orderId(order) {
+               return 'order_'+order.id;
+       }
+
        function formatOrder(order : Dynamic, left : Int, date : Date) {
-                       var row_id = 'order_'+order.id;
-                       var attributes = ['id = "'+row_id+'"'];
-                       var classes = [];
-                       var before : Int = left + order.quantity;
-                       /* We have basically 3 different cases;
-                        * - the order can be fullfilled
-                        * - the order can be partially 
-                  * - not at all
-                        */
-                       if (before < 0 ) {
-                                       classes.push('soldout');
-                       }
-                       else if(left < 0) {
-                                       classes.push('partial');
-                       }
-                       else {
-                                       classes.push('full');
-                       }
+               var row_id = orderId(order);
+               var attributes = ['id = "'+row_id+'"'];
+               var classes = [];
+               var before : Int = left + order.quantity;
+               /* We have basically 3 different cases;
+                * - the order can be fullfilled
+                * - the order can be partially 
+                * - not at all
+                */
+               if (before < 0 ) {
+                       classes.push('soldout');
+               }
+               else if(left < 0) {
+                       classes.push('partial');
+               }
+               else {
+                       classes.push('full');
+               }
 
-                       /* The order can also be late if we need
-                        * to wait for a delivery to get it
-                        */
+               /* The order can also be late if we need
+                * to wait for a delivery to get it
+                */
                var required_by : Date = FA.sql2date(order.required_date);
                if(required_by == null) required_by = FA.sql2date(order.delivery_date);
                if(required_by.getTime() < date.getTime()) {
@@ -157,50 +195,21 @@ class ItemScheduler {
                else {
                        classes.push('on_time');
                }
-                       var cells : Array <Dynamic> = [
-                               order.order_id
-                               , '<a href="/modules/order_line_extra/order_lines_view.php?customer_id='+Std.string(order.debtor_no)+'">'+order.deliver_to+'</a>'
+               var cells : Array <Dynamic> = [
+                       order.order_id
+                       , '<a href="/modules/order_line_extra/order_lines_view.php?customer_id='+Std.string(order.debtor_no)+'">'+order.deliver_to+'</a>'
                        ,'<input type="text" name="'+row_id+'[quantity]" value="'+order.quantity+'">'
-                               ,before
-                               ,left
-                               ,order.from_stk_loc
-                               ,order.delivery_date
-                               ,order.required_date 
-                               ,order.comment
+                       ,before
+                       ,left
+                       ,order.from_stk_loc
+                       ,order.delivery_date
+                       ,order.required_date 
+                       ,order.comment
                        ];
 
-                       attributes.push('class="'+classes.join(' ')+'"');
-                       printRow(cells, attributes);
-
-       }
+               attributes.push('class="'+classes.join(' ')+'"');
+               printRow(cells, attributes);
 
-       function formatRow(row) {
-               var array = php.Lib.hashOfAssociativeArray(row);
-               var quantity_before : Int = array.get('quantity_before');
-               var quantity_available = qoh - quantity_before;
-               var quantity: Int = array.get('quantity');
-
-               var status : String = if(quantity_available < quantity) 'overduebg';
-
-               var cells : Array<Dynamic> = [
-                       array.get('order_id')
-                       ,array.get('deliver_to')
-                       ,'<input type="text" name="quantity">'+quantity+'</input>'
-                       ,quantity_available-quantity
-                       ,quantity_available
-                       ,array.get('from_stk_loc')
-                       ,array.get('delivery_date')
-               ];
-
-               php.Lib.print('<tr class="'+status+'">');
-               for(cell in cells) {
-                       php.Lib.print('<td>');
-                       php.Lib.print(cell);
-                       php.Lib.print('</td>');
-               }
-               php.Lib.print('</tr>');
-               
-               
        }
 
        function formatLocation(location : Location, type: String,  left : Int) {
@@ -211,56 +220,131 @@ class ItemScheduler {
                        ,left-location.quantityOnHand(stock_id, null)
                        ,left
                        ,location.code
-                       ,location.delivery
+                       ,location.delivery.getTime() == 0 ? '' : location.delivery.format("%F")
                        ,""
                        ,""
-               ];
+                       ];
 
                printRow(cells, ['class = "tableheader location"', 'id = "loc_'+location.code+'"']);
        }
 
-/*
-       function schedules() {
-               //return orders()+locations();
-               //return  orders();
-               return cast(locations(), Array<Dynamic>);
+       /*
+                function schedules() {
+//return orders()+locations();
+//return  orders();
+return cast(locations(), Array<Dynamic>);
 
-       }
-*/
-
-       function orders() {
-               var tb : String =  untyped __php__('TB_PREF');
-               var sql : String = "SELECT *  
-                                               FROM "+tb+"denorm_order_details_queue  d
-                                               JOIN "+tb+"sales_order_details od ON (od.id = d.id)
-                                               JOIN "+tb+"sales_orders so ON (so.order_no = d.order_id)
-                                               WHERE stock_id = '"+this.stock_id+"'
-                                               AND od.trans_type = 30
-                                               ORDER by quantity_before";
-       
-               return FA.query(sql);
-       }
+}
+        */
+
+private function loadOrders() {
+       var tb : String =  untyped __php__('TB_PREF');
+       var sql : String = "SELECT *  , d.quantity as qty,   d.priority AS pp
+               FROM "+tb+"denorm_order_details_queue  d
+               JOIN "+tb+"sales_order_details od ON (od.id = d.id)
+               JOIN "+tb+"sales_orders so ON (so.order_no = d.order_id)
+               WHERE stock_id = '"+this.stock_id+"'
+               AND od.trans_type = 30
+               ORDER by d.priority";
+
+       return FA.query(sql);
+}
 
-       function locations() {
-               var TB = FA.tb();
-               var sql = 'SELECT * 
-                                                       FROM '+TB+'locations';
-               var _locs = [];
-               for(row in FA.query(sql)) {
-                       var location = new Location(row);
-                       if(location.code == startLocation) {
-                        location.delivery =  Date.fromTime(0);
-                       }
-                       _locs.push(location);
+function orders():Array<Order>  {
+       var rows = loadOrders();
+       var orderList = [];
+       for(row in rows) {
+               // for some reason, priority is null
+               // so we use the pp field
+               var a:Dynamic = php.Lib.objectOfAssociativeArray(row);
+               var order:Order = a;
+               order.priority = Date.fromString(a.pp);
+               order.quantity = a.qty;
+               orderList.push(order);
+       };
+
+       if(parameters != null) {
+               orderList.sort(function(a, b) { return parameters.priority(a)-parameters.priority(b); });
+
+       }
+               for(order in orderList) {
                }
 
-               return _locs;
-               
+       return orderList;
+}
+
+
+
+function locations() {
+       var TB = FA.tb();
+       var sql = 'SELECT * 
+               FROM '+TB+'locations';
+       var _locs = [];
+       for(row in FA.query(sql)) {
+               var location = new Location(row);
+               if(location.code == startLocation) {
+                       location.delivery =  Date.fromTime(0);
+               }
+               else if(location.delivery == null) {
+               continue;
+               }
+               _locs.push(location);
        }
 
+       return _locs;
+
+}
+
 
        function purcharseOrders()  {
+               var TB = FA.tb();
+               var sql = 'SELECT SUM(quantity_ordered - quantity_received) as quantity
+                       into_stock_location AS location
+                       FROM '+TB+'purch_order_details
+                       NATURAL JOIN '+TB+'purch_orders
+                       WHERE item_code = "'+this.stock_id+'"
+                       AND quantity_ordered > quantity_received
+                       GROUP by item_code,delivery_date, into_stock_location
+                       ORDER by delivery_date' ;
+
+               return  FA.query(sql);
+       }
+
+       public function needsUpdate():Bool {
+               return parameters != null && parameters.mode == ScheduleMode.Move;
+       }
+
+       function update() {
+               var orders = this.orders();
+               var priorities = Lambda.array(Lambda.map(orders, function(o) { return o.priority;}));
+               priorities.sort(function(a,b) {
+                       var as = a.toString();
+                       var bs = b.toString();
+                       if (as < bs) return -1;
+                       if( as > bs) return 1;
+                       return 0;
+                       });
+
+               var iter = priorities.iterator();
+               var p = iter.next();
+               var position:Int = 0-priorities.length;
+               for(order in orders) {
+                       var new_priority = DateTools.delta(p, 1000*position);
+                       untyped __call__ ('update_order_detail_priority', order.id, new_priority.toString());
+                       
+                       position +=1;
+                       p = iter.next();
+               }
+                       untyped __call__ ('update_queue_quantity_for_item', stock_id);
+               
        }
+       
+       public function action() {
+               if(parameters != null && parameters.mode == ScheduleMode.Update) {
+                       update();
+               }
+       }
+
 
 }