/// <summary> /// Function used to Find a TreeItem with the specified id /// </summary> /// <param name="item">Item to check if has the correct id</param> /// <param name="data">DataRow containing the value of the group (contains id, dgrp_id, and so on).</param> /// <returns>true of item has the correctid</returns> protected bool FindItemById(UnorderedTree.TreeItem item, object data) { CmpStatus.StatusTreeItem stitem = (CmpStatus.StatusTreeItem)item.Data; DataRow group = (DataRow)data; bool bType = Convert.ToBoolean(group["TipoAgrupacion"]); int id = Convert.ToInt32(group["Agrupacion"]); bool bRet = bType ? stitem.IdType == id : stitem.Id == id; return(bRet); }
/// <summary> /// Filters the OPERATIONS DataTable /// </summary> /// <param name="dtOperations">DataTable to filter</param> /// <param name="titem">Item which represents the group filtered by</param> protected void FilterOperationsTableByGroup(DataTable dtOperations, UnorderedTree.TreeItem titem) { if (dtOperations.Columns["TMP_MANTAIN"] == null) { DataColumn dc = dtOperations.Columns.Add("TMP_MANTAIN", typeof(bool)); } DoFilterOperationsTableByGroup(dtOperations, titem); // Remove all rows that have TMP_MANTAIN distinct of true foreach (DataRow dr in dtOperations.Rows) { if (dr["TMP_MANTAIN"] == DBNull.Value || Convert.ToBoolean(dr["TMP_MANTAIN"]) != true) { dr.Delete(); } } // Remove the temporal column used... dtOperations.Columns.Remove("TMP_MANTAIN"); dtOperations.AcceptChanges(); }
/// <summary> /// Computes the minimum MP. /// Foreach group in the table of groups: /// Get all operations of the group (for article and vehicle passed) /// Sums all OPE_DURATION times /// Set CalculoMP of the group to the value MP - Sum(OPE_DURATION) /// The dtConstraints DataTable is modified (CalculoMP field is set). /// </summary> /// <param name="dtConstraints">DataTable of constraints (obtained with CmpConstraints::GetConstraints())</param> /// <param name="artid">ID of the article (use -1 for NULL)</param> /// <param name="vehid">ID of the vehicle (cannot be NULL)</param> /// <param name="pInDate">DateTime of the new intended operation (OPE_INIDATE or OPE_MOVDATE if passed in the message).</param> public void CalculateMP(DataTable dtConstraints, DateTime pInDate, int artid, string vehid) { CmpOperationsDB cmp = new CmpOperationsDB(); _treeGroups.EvalHandler = new OTS.Framework.Collections.UnorderedTree.EvalItem(TreeItemToId); foreach (DataRow drGroup in dtConstraints.Rows) { // Can use Agrupación, we don't have GROUP_TYPEs at that step // (were all removed in FilterConstraintsTable) int group = Convert.ToInt32(drGroup["Agrupacion"]); UnorderedTree.TreeItem titem = _treeGroups.FindItem(new UnorderedTree.FindItemDelegate(FindItemById), drGroup); // Get an arraylist with the IDs of all descendants of the current group. ArrayList groupChilds = titem.MapcarDescendants(); // Get all operations. int mp = drGroup["MP"] != DBNull.Value ? Convert.ToInt32(drGroup["MP"]) : 0; DateTime opend = pInDate; if (mp > 0) { opend = opend.Subtract(new TimeSpan(0, mp, 0)); } DataTable dtOperations = cmp.GetData(null, "OPE_ENDDATE > @OPERATIONS.OPE_ENDDATE@ AND OPE_ART_ID = @OPERATIONS.OPE_ART_ID@ AND OPE_VEHICLEID = @OPERATIONS.OPE_VEHICLEID@", "OPE_ENDDATE DESC", new object[] { opend, artid != -1 ? (object)artid : (object)DBNull.Value, vehid }); // Iterates throught the operations DataTable. We will exit when we found an OPERATION that: // a) Were not related to the group we are processing (group variable) // b) AND were not related to any of the group_childs of the group... int sumOpeDuration = 0; foreach (DataRow drOperation in dtOperations.Rows) { int opeGroup = Convert.ToInt32(drOperation["OPE_GRP_ID"]); // Check if opeGroup (group of the operation) is the group we are processing (group) or any // descendant of the group we are processing.. if (!groupChilds.Contains(opeGroup)) { break; // finish the iteration over operations table } sumOpeDuration += Convert.ToInt32(drOperation["OPE_DURATION"]); } // At that point we have the sumOpeDuration for the current group, so store it in the CalculoMP row drGroup["CalculoMP"] = mp - sumOpeDuration; } // Now we have "CalculoMP" computed by all operations. _treeGroups.EvalHandler = null; }
/// <summary> /// Marks with true all the rows of their OPE_ID is equal to the ID of titem. /// Do a recursive call to check all childs of the titem. /// </summary> /// <param name="dtOperations">DataTable to filter</param> /// <param name="titem">UnorderedTree::TreeItem which the group to filter by.</param> protected void DoFilterOperationsTableByGroup(DataTable dtOperations, UnorderedTree.TreeItem titem) { // Filter by the childs of stitem. if (titem.ChildsCount > 0) { foreach (object o in titem.Childs) { //FilterOperationsTableByGroup (dtOperations, (UnorderedTree.TreeItem)o); DoFilterOperationsTableByGroup(dtOperations, (UnorderedTree.TreeItem)o); } } // Filter by stitem... foreach (DataRow dr in dtOperations.Rows) { int grpid = Convert.ToInt32(dr["OPE_GRP_ID"]); if (grpid == ((CmpStatus.StatusTreeItem)titem.Data).Id) { dr["TMP_MANTAIN"] = true; } } }
// That method is used to sort the list obtained by the tree... The list will be // sorted by the PHY_ORDER of the StatusTreeItem contained in the TreeItem objects of the // tree private int CompareStatusTreeItems(UnorderedTree.TreeItem item1, UnorderedTree.TreeItem item2) { StatusTreeItem sitem1 = (StatusTreeItem)item1.Data; StatusTreeItem sitem2 = (StatusTreeItem)item2.Data; if ((sitem1.IsUnit && sitem2.IsUnit) && (sitem1.Id == sitem2.Id)) { return(0); } else if (sitem1.PhyOrder < sitem2.PhyOrder || sitem1.IsUnit) { return(-1); } else if (sitem1.PhyOrder > sitem2.PhyOrder) { return(1); } else { return(0); } }
/// <summary> /// Method used to evaluate a TreeItem, and returning the id of the group contained by that item. /// </summary> /// <param name="item">Item to evaluate</param> /// <returns>Int32 with the Id or null if item is not a group (is Unit or Type)</returns> private object TreeItemToId(UnorderedTree.TreeItem item) { CmpStatus.StatusTreeItem stitem = (CmpStatus.StatusTreeItem)item.Data; return(stitem.IsGroup ? (object)stitem.Id : (object)null); }
/// <summary> /// Validates the TR (tiempo de reentrada) constraints for a given table of constraints and groups /// That method is called after get the constraints (CmpConstraints::GetConstraints) and /// after filtering the constraints obtained (CmpConstraints::FilterConstraintsTable) /// </summary> /// <param name="dtConstraints">DataTable with constraints and groups (not groups_types) to process.</param> /// <param name="pInDate">DateTime when te operation was done (usually MOV_OPDATE of M01 message)</param> /// <param name="artid">ID of the ARTICLE (-1 for NULL)</param> /// <param name="vehicleid">ID of the VEHICLE (CANNOT be null)</param> /// <param name="operationId">OUT parameter with value of DATE of previous Operation (only used if return code is PreviousDate)</param> /// <returns>A ValidateTRReturnCodes specifying the result of validation (non valid, ok with previous date, ok)</returns> public ValidateTRReturnCodes ValidateTR(DataTable dtConstraints, DateTime pInDate, int artid, string vehicleid, out int operationId) { //previousDate = DateTime.MinValue; operationId = -1; CmpOperationsDB cmp = new CmpOperationsDB(); foreach (DataRow group in dtConstraints.Rows) { int tr = group["TR"] != DBNull.Value ? Convert.ToInt32(group["TR"]) : 0; int tc = group["TC"] != DBNull.Value ? Convert.ToInt32(group["TC"]) : 0; DateTime opend = pInDate.Subtract(new TimeSpan(0, tr, 0)); DataTable dtOperations; if (artid != -1) { dtOperations = cmp.GetAllData(null, "OPE_ENDDATE >= @OPERATIONS.OPE_ENDDATE@ " + "AND OPE_VEHICLEID = @OPERATIONS.OPE_VEHICLEID@ " + "AND OPE_ART_ID = @OPERATIONS.OPE_ART_ID@", "OPE_ENDDATE DESC", new object[] { opend, vehicleid, artid }); } else { dtOperations = cmp.GetAllData(null, "OPE_ENDDATE >= @OPERATIONS.OPE_ENDDATE@ " + "AND OPE_VEHICLEID = @OPERATIONS.OPE_VEHICLEID@", "OPE_ENDDATE DESC", new object[] { opend, vehicleid }); } if (dtOperations.Rows.Count > 0) { // Ok.. At that point we have: // ALL operations of the current vehicle and current article for ALL zones in the TR period of time. // We must filter that table for having only the operations for the CURRENT zone and ALL HIS CHILDS. // The rest of operations are discarded at that point (but, of course, we could find them again when // processing another zone UnorderedTree.TreeItem titem = _treeGroups.FindItem(new UnorderedTree.FindItemDelegate(FindItemById), group); // Delete from dtOperations table ALL operations that are not associated by titem or any childs of titem. FilterOperationsTableByGroup(dtOperations, titem); } if (dtOperations.Rows.Count > 0) { // return ValidateTRReturnCodes.OperationNonValid; // At that point we have only the operations related with the current group (or any of his childs). DataRow operation = dtOperations.Rows[0]; DateTime opendtc = Convert.ToDateTime(operation["OPE_ENDDATE"]).AddMinutes(tc); if (pInDate > opendtc) { // Operation not valid. At the first non-valid operation we return return(ValidateTRReturnCodes.OperationNonValid); } else // An ampliation of previous operation is possible { // Find the group of the current operation int currentGroup = -1; foreach (object o in _lstGroups) { CmpStatus.StatusTreeItem item = (CmpStatus.StatusTreeItem)((UnorderedTree.TreeItem)o).Data; if (item.IsUnit) { continue; } else if (item.IsGroup) { currentGroup = item.Id; break; } } // Let's check if the groups are the same. // If not, exit as an extension is not possible. int operationGroup = Convert.ToInt32(operation["OPE_GRP_ID"]); if (currentGroup != operationGroup) { return(ValidateTRReturnCodes.OperationNonValid); } operationId = Convert.ToInt32(operation["OPE_ID"]); return(ValidateTRReturnCodes.Extension); ///////////////////////////////////////////////////////// //int groupid = Convert.ToInt32 (group["Agrupacion"]); //if (opeid == groupid && Convert.ToBoolean (group["PagoTC"])) //{ // // An ampliation is allowed. // previousDate = Convert.ToDateTime (operation["OPE_ENDDATE"]); // return ValidateTRReturnCodes.PreviousDate; //} } } } return(ValidateTRReturnCodes.OnlyOk); }
/// <summary> /// Get the list of all parent (and parent types) of the group or unit specified by groupid /// </summary> /// <param name="groupId">ID of the group</param> /// <param name="isUnit">true if groupId is a ID of a UNIT instead a ID of a GROUP</param> /// <param name="searchPhyGroups">If true, only physical groups (DGRP_PHYORDER NOT NULL) will be searched</param> /// <param name="tree">Out parameter containing the tree of GROUP with groupId and ALL HIS parents</param> /// <returns>An ArrayList of OTS.Framework.Collection.UnorderedTree::TreeItem objects. /// Each item of ArrayList contains a CmpStatus::StatusTreeItem object in its Data property</returns> public ArrayList GetUnitTree(int groupId, bool isUnit, bool searchPhyGroups, out UnorderedTree tree) { tree = null; // Find the group type and physical order for the passed groupId int groupDefId = -1; int groupDefPhyorder = -1; CmpGroupsDefDB gddb = new CmpGroupsDefDB(); DataTable dtgd = gddb.GetGroupDefByGroup(groupId); if (dtgd.Rows.Count > 0) { groupDefId = Convert.ToInt32(dtgd.Rows[0]["DGRP_ID"]); groupDefPhyorder = Convert.ToInt32(dtgd.Rows[0]["DGRP_PHYORDER"]); } StatusTreeItem item = new StatusTreeItem(groupId, groupDefId, groupDefPhyorder, false, isUnit); GetUnitTree(item, null, ref tree, searchPhyGroups); ArrayList list = tree.ToArrayList(new UnorderedTree.OrderItemDelegate(CompareStatusTreeItems)); // At that point we have the list the groupId and ALL his parents. Now we have to put the GROUPS_DEF // items in the list (such as <sectores> or <zonas>,... (the list must have at least two elements: groupId and // his parent) StatusTreeItem itemAnt = null; StatusTreeItem itemAct = null; if (list.Count > 1) { itemAnt = (StatusTreeItem)((UnorderedTree.TreeItem)list[0]).Data; for (int i = 1; i < list.Count; i++) { itemAct = (StatusTreeItem)((UnorderedTree.TreeItem)list[i]).Data; if (itemAnt.IdType != itemAct.IdType && !itemAnt.IsUnit) { // We must insert a new item AFTER itemAnt // (for example list[i-1] is a Zona and list[i] is a Sector, so we have to add // a <Zona> element in middle of both StatusTreeItem toInsert = new StatusTreeItem(-1, itemAnt.IdType, itemAnt.PhyOrder, true, false); // In order for consistency insert the StatusTreeItem in the tree. The item is inserted // as an Orphan item, because there is not really a parent-child relation... UnorderedTree.TreeItem titem = tree.Add(toInsert); // For consistency again: Insert a UnorderedTree::TreeItem in the list // instead of a StatusTreeItem. Of course tha UnorderedTree::TreeItem inserted // will have only a StatusTreeItem object (in its data property) list.Insert(i, titem); i++; // just skip the new element } itemAnt = (StatusTreeItem)((UnorderedTree.TreeItem)list[i]).Data; } } // Add the final GROUPS_DEF item (the GROUPS_DEF item corresponding to the last element) item = (StatusTreeItem)((UnorderedTree.TreeItem)list[list.Count - 1]).Data; if (item.IsGroup) // item must be a group, nor a type or unit { StatusTreeItem toInsert = new StatusTreeItem(-1, item.IdType, item.PhyOrder, true, false); // Insert the last item in the tree AND in the list UnorderedTree.TreeItem titem = tree.Add(toInsert); list.Add(titem); } return(list); }