/// <summary> /// Formats the SellableCapacityPerRack value. /// </summary> /// <param name="config">The configuration.</param> /// <param name="sellableCapacityPerRackAttributeId">The sellable capacity per rack attribute identifier.</param> /// <returns>Configuration instance that SellableCapacityPerRack was formatted.</returns> private static Configuration FormatCapacityPerRackValue(Configuration config, int sellableCapacityPerRackAttributeId) { var sellableCapacityPerRackAttribute = config.AttributeList.Single(a => a.AttributeId == sellableCapacityPerRackAttributeId); var sellableCapacityPerRackValue = sellableCapacityPerRackAttribute.AttributeValue; var valList = sellableCapacityPerRackValue.Split(','); var valSet = new HashSet<string>(); for (var i = 0; i < valList.Count(); i++) { valSet.Add(valList[i]); } var valSortedList = valSet.ToList() .OrderBy(v => Convert.ToDateTime(v.Split(':').ToList()[0].ToString())) .ToList(); var sb = new StringBuilder(); for (var i = 0; i < valSortedList.Count; i++) { if (i > 0) { sb.Append("," + valSortedList[i]); } else { sb.Append(valSortedList[i]); } } sellableCapacityPerRackAttribute.AttributeValue = sb.ToString(); return config; }
/// <summary> /// Creates the configuration from CSV. /// </summary> /// <param name="filePath">The file path.</param> /// <param name="templateId">The template identifier.</param> /// <returns>A list of configuration instances.</returns> public static List<Configuration> CreateConfigurationsFromCsv(string filePath, int templateId) { var configListFromCsv = new List<Configuration>(); //Get template from service to help validate the csv file is in correct format to create qualifier var response = QueryService(PlanningConfigServiceRootUrl + "api/template/" + templateId); //Parse response as template in JObject var templateJObjectFromService = response.Content.ReadAsAsync<JObject>().Result; //Get attributes of the template from service var attributesOfTemplateFromService = QueryService(PlanningConfigServiceRootUrl + "api/template/" + templateId + "/attributes") .Content.ReadAsAsync<List<JObject>>() .Result; //Get qualifiers of the template from service var qualifiersOfTemplateFromService = QueryService(PlanningConfigServiceRootUrl + "api/template/" + templateId + "/qualifiers") .Content.ReadAsAsync<List<JObject>>() .Result; var numAttributesOfTemplateFromService = attributesOfTemplateFromService.Count(); var numQualifiersOfTemplateFromService = qualifiersOfTemplateFromService.Count(); //Create the map for attributes and qualifiers keyed by their names var attributesMapKeyedByName = attributesOfTemplateFromService.ToDictionary( attributeJObject => attributeJObject["Name"].ToString().ToLower()); var qualifiersMapKeyedByName = qualifiersOfTemplateFromService.ToDictionary( qualifierJObject => qualifierJObject["Name"].ToString().ToLower()); using (var csvReader = new StreamReader(File.OpenRead(filePath))) { using ( var logWriter = new StreamWriter(Directory.GetCurrentDirectory() + @"\ConfigurationsHelperValidationErrorLog.txt")) { //MembersOfConfigLine is the first line of the Csv file, which contains Name, NameOfQuaifiers[], NameOfAttributes[], StartDate, EndDate var membersOfConfigLine = csvReader.ReadLine(); if (membersOfConfigLine == null) { throw new Exception("Invalid Csv file for Configuration"); } //Split first line to a list var membersOfConfigList = SplitCsv(membersOfConfigLine) .Select(attribute => attribute.ToLower()) .ToList(); //Validate the first line matches the Template of Configuration from service if ( ValidateCsvFormat(membersOfConfigList, qualifiersOfTemplateFromService, attributesOfTemplateFromService) == false) { throw new Exception( "Configuration in csv does not match corresponding template from service"); } var lineCount = 1; //Read begin from second line of Csv file, each line contains information for a configuration while (!csvReader.EndOfStream) { var line = csvReader.ReadLine(); lineCount++; if (line == null) { continue; } //Split readed line to a list that contains members of a Configuration class var valueListForOneLine = SplitCsv(line).ToList(); if (!valueListForOneLine.Any() || valueListForOneLine.Count != membersOfConfigList.Count) { continue; } //First element is the name for a configuration var configName = valueListForOneLine[0]; //CategoryId of a Configuration equals to CategoryId of the Template for this configuration var configCategoryId = (int) templateJObjectFromService["CategoryId"]; //Template Id is passed outside of the function var configTemplateId = templateId; //Element in valueListForOneLine before the last one is the StartDate DateTime dateTimeResult; var configStartDate = DateTime.TryParse(valueListForOneLine[valueListForOneLine.Count - 2], out dateTimeResult) ? dateTimeResult : DateTime.Now; //Last element in valueListForOneLine is the EndDate var configEndDate = DateTime.TryParse(valueListForOneLine[valueListForOneLine.Count - 1], out dateTimeResult) ? dateTimeResult : configStartDate.AddDays(36); //Create configQualifier list and configAttribute list for the configuration var configQualifierList = new List<ConfigQualifier>(); var configAttributeList = new List<ConfigAttribute>(); var passValidation = true; var errorMsg = ""; for (var i = 1; i <= numQualifiersOfTemplateFromService + numAttributesOfTemplateFromService; i++) { if (i <= numQualifiersOfTemplateFromService) { //Fetch the qualifier using the map keyed by name var targetQualifierJObject = qualifiersMapKeyedByName[membersOfConfigList[i]]; if (targetQualifierJObject == null) { throw new Exception( "Configuration in csv does not match corresponding template from service"); } var qualifierId = (int) targetQualifierJObject["Id"]; var qualifierValue = valueListForOneLine[i]; //Test the value for the Qualifier, whether it is there in the VALUES list //In case of validation failure, add a error message to the console/log file if (!ValidateQualifierValue(qualifierValue, targetQualifierJObject)) { errorMsg += "[Qualifier:" + membersOfConfigList[i] + "]Invalid qualifierValue: " + qualifierValue; passValidation = false; break; } var configQualifierVal = new ConfigQualifier { QualifierId = qualifierId, QualifierValue = valueListForOneLine[i] }; configQualifierList.Add(configQualifierVal); } else { var targetAttributeJObject = attributesMapKeyedByName[membersOfConfigList[i]]; if (targetAttributeJObject == null) { throw new Exception( "Configuration in csv does not match corresponding template from service"); } //Fetch the attributes using the map //Test the value for the attribute, whether it passes the rule //In case of validation failure, add a error message to the console/log file var attributeId = (int) targetAttributeJObject["Id"]; var attributeValue = valueListForOneLine[i]; if (!ValidateAttributeValue(attributeValue, targetAttributeJObject)) { errorMsg += "[Attribute:" + membersOfConfigList[i] + "]Invalid attributeValue: " + attributeValue; passValidation = false; break; } var configAttributeVal = new ConfigAttribute { AttributeId = attributeId, AttributeValue = attributeValue, Version = 1 }; configAttributeList.Add(configAttributeVal); } } if (passValidation == false) { logWriter.WriteLine("[Line: " + lineCount + "] could not pass validation, the Configuration Name is: " + configName); logWriter.WriteLine(errorMsg); continue; } var config = new Configuration { Name = configName, Active = true, CategoryId = configCategoryId, QualifierList = configQualifierList, AttributeList = configAttributeList, TemplateId = configTemplateId, StartDate = configStartDate, EndDate = configEndDate }; Console.WriteLine("[Line: " + lineCount + "]" + "Configuration Name: " + configName + " passes the validation"); configListFromCsv.Add(config); } } } return configListFromCsv; }
/// <summary> /// Adds the configuration to planning configuration service. /// </summary> /// <param name="url">The URL.</param> /// <param name="config">The configuration.</param> /// <returns></returns> /// <exception cref="System.ArgumentException">Invalid url</exception> /// <exception cref="System.Exception">Calling servise insuccess</exception> private static HttpResponseMessage AddConfigurationToService(string url, Configuration config) { if (!Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute)) { throw new ArgumentException("Invalid url"); } using (var client = new HttpClient()) { using (var request = new HttpRequestMessage(HttpMethod.Post, url)) { request.Content = new StringContent(JsonConvert.SerializeObject(config), Encoding.UTF8, "application/json"); var response = client.SendAsync(request, CancellationToken.None).Result; return response; } } }
/// <summary> /// Creates the sellable capacity configs from CSV. /// </summary> /// <param name="filePath">The file path.</param> /// <param name="templateId">The template identifier.</param> /// <returns>A list of configuration instances.</returns> public static List<Configuration> CreateSellableCapacityConfigsFromCsv(string filePath, int templateId) { var scConfigList = new List<Configuration>(); //Get template from service to help validate the csv file is in correct format to create qualifier var response = QueryService(PlanningConfigServiceRootUrl + "api/template/" + templateId); //Parse response as template in JObject var templateJObjectFromService = response.Content.ReadAsAsync<JObject>().Result; //Get attributes of the template from service var attributesOfTemplateFromService = QueryService(PlanningConfigServiceRootUrl + "api/template/" + templateId + "/attributes") .Content.ReadAsAsync<List<JObject>>() .Result; //Get qualifiers of the template from service var qualifiersOfTemplateFromService = QueryService(PlanningConfigServiceRootUrl + "api/template/" + templateId + "/qualifiers") .Content.ReadAsAsync<List<JObject>>() .Result; var numAttributesOfTemplateFromService = attributesOfTemplateFromService.Count(); var numQualifiersOfTemplateFromService = qualifiersOfTemplateFromService.Count(); //Create the map for attributes and qualifiers keyed by their names var attributesMapKeyedByName = attributesOfTemplateFromService.ToDictionary( attributeJObject => attributeJObject["Name"].ToString().ToLower()); var qualifiersMapKeyedByName = qualifiersOfTemplateFromService.ToDictionary( qualifierJObject => qualifierJObject["Name"].ToString().ToLower()); using (var csvReader = new StreamReader(filePath)) { using ( var logWriter = new StreamWriter(Directory.GetCurrentDirectory() + @"\ConfigurationsHelperValidationErrorLog.txt")) { //Read the schema of Csv var firstLine = csvReader.ReadLine(); if (firstLine == null) { throw new Exception("File format Invalid"); } var membersOfConfigList = SplitCsv(firstLine).ToList() .Select(attribute => attribute.ToLower()) .ToList(); var sellableCapacityPerRackIndex = membersOfConfigList.FindIndex(s => s.Equals("sellablecapacityperrack")); var sellableCapacityPerRackStartDateIndex = membersOfConfigList.FindIndex(s => s.Equals("start date")); var sellableCapacityPerRackAttributeId = (int)attributesMapKeyedByName["sellablecapacityperrack"]["Id"]; //Read values and form a Map var scMap = new Dictionary<string, Configuration>(); var lineCount = 1; while (!csvReader.EndOfStream) { var line = csvReader.ReadLine(); lineCount++; if (line == null) { continue; } var valueListForOneLine = SplitCsv(line).ToList(); if (!valueListForOneLine.Any() || valueListForOneLine.Count != membersOfConfigList.Count) { continue; } //Concatenate qualifier value to form a key of map var sb = new StringBuilder(); for (var i = 0; i < numQualifiersOfTemplateFromService; i++) { if (i > 0) { sb.Append("," + valueListForOneLine[i]); } else { sb.Append(valueListForOneLine[i]); } } var key = sb.ToString(); //If key in the map then update config's CapacityPerRack, StartDate and EndDate if (scMap.ContainsKey(key)) { var newTimeSeriesNumber = valueListForOneLine[sellableCapacityPerRackStartDateIndex] + ":" + valueListForOneLine[sellableCapacityPerRackIndex]; var config = scMap[key]; var errorMsg = ""; var sellableCapacityPerRackAttribute = config.AttributeList.Single( a => a.AttributeId == sellableCapacityPerRackAttributeId); if ( !ValidateAttributeValue(newTimeSeriesNumber, attributesMapKeyedByName["sellablecapacityperrack"])) { errorMsg += "[Attribute: CapacityPerRack" + "]Invalid attributeValue: " + newTimeSeriesNumber; logWriter.WriteLine("[Line: " + lineCount + "] could not pass validation, the Configuration Name is: " + config.Name); logWriter.WriteLine(errorMsg); continue; } //Append a new TimeSeriesNumber sellableCapacityPerRackAttribute.AttributeValue += "," + newTimeSeriesNumber; DateTime dateTimeResult; var configStartDate = DateTime.TryParse( valueListForOneLine[valueListForOneLine.Count - 2], out dateTimeResult) ? dateTimeResult : DateTime.Now; //Update start date and end date var configEndDate = DateTime.TryParse( valueListForOneLine[valueListForOneLine.Count - 2], out dateTimeResult) ? dateTimeResult : configStartDate.AddDays(36); config.StartDate = configStartDate.CompareTo(config.StartDate) < 0 ? configStartDate : config.StartDate; config.EndDate = configStartDate.CompareTo(config.EndDate) > 0 ? configEndDate : config.EndDate; scMap[key] = config; } //Else create a new configuration and add to map else { var timeSeriesNumber = valueListForOneLine[sellableCapacityPerRackStartDateIndex] + ":" + valueListForOneLine[sellableCapacityPerRackIndex]; var configName = key; var configCategoryId = (int)templateJObjectFromService["CategoryId"]; var configTemplateId = templateId; DateTime dateTimeResult; var configStartDate = DateTime.TryParse( valueListForOneLine[valueListForOneLine.Count - 2], out dateTimeResult) ? dateTimeResult : DateTime.Now; //Update start date and end date var configEndDate = DateTime.TryParse( valueListForOneLine[valueListForOneLine.Count - 2], out dateTimeResult) ? dateTimeResult : configStartDate.AddDays(36); var configQualifierList = new List<ConfigQualifier>(); var configAttributeList = new List<ConfigAttribute>(); var passValidation = true; var errorMsg = ""; for (var i = 0; i < numQualifiersOfTemplateFromService + numAttributesOfTemplateFromService; i++) { if (i < numQualifiersOfTemplateFromService) { var qualifierName = membersOfConfigList[i].ToLower(); var targetQualifierJObject = qualifiersMapKeyedByName[qualifierName]; if (targetQualifierJObject == null) { throw new Exception( "Configuration in csv does not match corresponding template from service"); } var qualifierId = (int)targetQualifierJObject["Id"]; var qualifierValue = valueListForOneLine[i]; if ( !ValidateQualifierValue(qualifierValue, targetQualifierJObject)) { errorMsg += "[Qualifier:" + membersOfConfigList[i] + "]Invalid qualifierValue: " + qualifierValue; passValidation = false; break; } var configQualifierVal = new ConfigQualifier { QualifierId = qualifierId, QualifierValue = qualifierValue }; configQualifierList.Add(configQualifierVal); } else { var targetAttributeJObject = attributesMapKeyedByName[membersOfConfigList[i].ToLower()]; if (targetAttributeJObject == null) { throw new Exception( "Configuration in csv does not match corresponding template from service"); } var attributeId = (int)targetAttributeJObject["Id"]; var attributeValue = valueListForOneLine[i]; if (targetAttributeJObject["Name"].ToString().ToLower() == "sellablecapacityperrack") { attributeValue = timeSeriesNumber; } if ( !ValidateAttributeValue(attributeValue, targetAttributeJObject)) { errorMsg += "[Attribute:" + membersOfConfigList[i] + "]Invalid attributeValue: " + attributeValue; passValidation = false; break; } var configAttributeVal = new ConfigAttribute { AttributeId = attributeId, AttributeValue = attributeValue, Version = 1 }; configAttributeList.Add(configAttributeVal); } } if (passValidation == false) { logWriter.WriteLine("[Line: " + lineCount + "] could not pass validation, the Configuration Name is: " + configName); logWriter.WriteLine(errorMsg); continue; } var config = new Configuration { Name = configName, Active = true, CategoryId = configCategoryId, QualifierList = configQualifierList, AttributeList = configAttributeList, TemplateId = configTemplateId, StartDate = configStartDate, EndDate = configEndDate }; scMap.Add(key, config); } } //Process Map and create sellable capacity configuration list scConfigList.AddRange( scMap.Keys.Select( key => FormatCapacityPerRackValue(scMap[key], sellableCapacityPerRackAttributeId))); } } return scConfigList; }