public static void UpdateRetryTargetDate(IOrganizationService service, CustomJob job, CrmLog log) { DateTime?nextRecurrence; if (job.RetrySchedule == null) { log.Log("No retry schedule."); nextRecurrence = DateTime.UtcNow.AddMinutes(1); } else { log.Log($"Getting next retry occurrence for {job.RetrySchedule}.", LogLevel.Debug); var action = new GlobalActions.ldv_CustomJobGetNextRecurrenceDate( new EntityReference(RecurrenceRule.EntityLogicalName, job.RetrySchedule.Value), service); nextRecurrence = action.Execute().NextTargetDate; log.Log($"Next retry occurrence: '{nextRecurrence}'."); } var targetDate = nextRecurrence > new DateTime(1900) ? nextRecurrence : null; log.Log($"Updating target date to '{targetDate}' UTC ...", LogLevel.Debug); service.Update( new CustomJob { Id = job.Id, TargetDate = targetDate }); log.Log($"Updated target date to '{targetDate}' UTC"); }
internal static JobRun GetJobRun(CustomJob job, bool isRetry, IOrganizationService service, IOrganizationServiceFactory factory, CrmLog log) { try { log.LogFunctionStart(); if (IsRecurrent(job, log)) { return(new RecurrentRunJob(job, service, log)); } log.Log("Single run job."); JobTarget target; if (IsSingleOrNoTarget(job, log)) { target = new SingleTargetJob(job, service, factory, log); } else if (IsPaging(job, log)) { if (isRetry) { target = new PagingRetryJob(job, service, factory, log); } else { target = new PagingNormalJob(job, service, factory, log); } } else { if (isRetry) { target = new NoPagingRetryJob(job, service, factory, log); } else { target = new NoPagingNormalJob(job, service, factory, log); } } return(new SingleRunJob(job, target, service, log)); } catch (Exception ex) { log.Log(ex); throw; } finally { log.LogFunctionEnd(); } }
static void Main(string[] args) { var log = new CrmLog(true, LogLevel.Debug); log.InitOfflineLog("log.csv", false, new FileConfiguration { FileSplitMode = SplitMode.Size, MaxFileSize = 1024, FileDateFormat = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss-fff}" }); try { var settings = GetConfigurationParams(args); var service = ConnectToCrm(settings.ConnectionString, log); if (service == null) { return; } foreach (var solutionConfig in settings.SolutionConfigs) { try { var(solutionVersion, exportXml) = RetrieveSolution(solutionConfig.SolutionName, log, service); var outputPath = string.IsNullOrWhiteSpace(solutionConfig.OutputPath) ? settings.DefaultOutputPath : solutionConfig.OutputPath; var fullPath = BuildOutputPath(outputPath, solutionConfig.OutputFilename, solutionConfig.SolutionName, solutionVersion); Directory.CreateDirectory(outputPath); log.Log($"Writing solution to '{fullPath}'..."); File.WriteAllBytes($"{fullPath}", exportXml); log.Log($"Solution file written."); } catch (Exception e) { log.Log(e); } } } catch (Exception e) { log.Log(e); log.ExecutionFailed(); } finally { log.LogExecutionEnd(); } }
static int Main(string[] args) { args.RequireCountAtLeast(2, "Command Line Arguments", "A JSON file name must be passed to the program as argument."); var logLevel = ConfigurationManager.AppSettings["LogLevel"]; log = new CrmLog(true, (LogLevel)int.Parse(logLevel)); log.InitOfflineLog("log.csv", false, new FileConfiguration { FileSplitMode = SplitMode.Size, MaxFileSize = 1024, FileDateFormat = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss-fff}" }); try { ParseCmdArgs(args); foreach (var config in configs) { log.Log($"Parsing config file {config} ..."); var settings = GetConfigurationParams(config); var result = ProcessConfiguration(settings); log.Log($"Finished parsing config file {config}."); if (result > 0) { return(result); } } return(0); } catch (Exception e) { log.Log(e); log.ExecutionFailed(); return(1); } finally { log.LogExecutionEnd(); if (isPauseOnExit) { Console.WriteLine(); Console.WriteLine("Press any key to exit ..."); Console.ReadKey(); } } }
// POST api/<controller> public async Task <IHttpActionResult> Post() { log.Log($"Importing data using Post ..."); var exportedData = await Request.Content.ReadAsStringAsync(); if (string.IsNullOrEmpty(exportedData)) { return(BadRequest("Exported data cannot be empty.")); } log.Log($"Importing ..."); var result = crmImporter.ImportRecords(exportedData); log.Log($"Finished importing data."); return(Ok(result)); }
private static bool IsPaging(CustomJob job, CrmLog log) { try { log.LogFunctionStart(); var isPaging = job.RecordsPerPage > 0; log.Log($"{isPaging}"); return(isPaging); } catch (Exception ex) { log.Log(ex); throw; } finally { log.LogFunctionEnd(); } }
private static bool IsRecurrent(CustomJob job, CrmLog log) { try { log.LogFunctionStart(); var isRecurrent = job.RecurrentJob == true; log.Log($"{isRecurrent}"); return(isRecurrent); } catch (Exception ex) { log.Log(ex); throw; } finally { log.LogFunctionEnd(); } }
private static CrmServiceClient ConnectToCrm(string connectionString, CrmLog log) { log.Log($"Connecting to '{connectionString}' ..."); var service = new CrmServiceClient(connectionString); if (!string.IsNullOrWhiteSpace(service.LastCrmError) || service.LastCrmException != null) { log.LogError($"Failed to connect => {service.LastCrmError}"); if (service.LastCrmException != null) { throw service.LastCrmException; } return(null); } log.Log($"Connected!"); return(service); }
private static bool IsSingleOrNoTarget(CustomJob job, CrmLog log) { try { log.LogFunctionStart(); var isSingleOrNoTarget = string.IsNullOrWhiteSpace(job.TargetLogicalName) || job.TargetID?.Split(',').Length <= 1; log.Log($"{isSingleOrNoTarget}"); return(isSingleOrNoTarget); } catch (Exception ex) { log.Log(ex); throw; } finally { log.LogFunctionEnd(); } }
// POST api/<controller> public async Task <IHttpActionResult> Post() { log.Log($"Exporting data using Post ..."); var configuration = await Request.Content.ReadAsStringAsync(); log.Log(new LogEntry($"'Post' body.", information: configuration)); if (string.IsNullOrEmpty(configuration)) { return(BadRequest("Configuration cannot be empty.")); } log.Log($"Converting from JSON to object ..."); var jsonObject = ExportConfiguration.FromJson(configuration); log.Log($"Finished creating JSON object."); log.Log($"Exporting ..."); var data = crmExporter.ExportRecords(jsonObject); log.Log($"Finished exporting data."); return(Ok(data)); }
private static (string solutionVersion, byte[] exportXml) RetrieveSolution(string solutionName, CrmLog log, CrmServiceClient service) { var query = new QueryExpression { EntityName = Solution.EntityLogicalName, ColumnSet = new ColumnSet(Solution.Fields.Version), Criteria = new FilterExpression() }; query.Criteria.AddCondition(Solution.Fields.Name, ConditionOperator.Equal, solutionName); log.Log($"Retrieving solution version for solution '{solutionName}'..."); var solution = service.RetrieveMultiple(query).Entities.FirstOrDefault()?.ToEntity <Solution>(); log.Log($"Version: {solution?.Version}."); if (solution == null) { throw new NotFoundException("Couldn't find solution in CRM."); } var request = new ExportSolutionRequest { Managed = false, SolutionName = solutionName }; log.Log($"Exporting solution '{solutionName}'..."); var response = (ExportSolutionResponse)service.Execute(request); log.Log($"Exported!"); var exportXml = response.ExportSolutionFile; return(solution.Version, exportXml); }
private static AutoNumbering GetBackloggedConfig(IPluginExecutionContext currentContext, IOrganizationService service, CrmLog log) { var xrmContext = new XrmServiceContext(service) { MergeOption = MergeOption.NoTracking }; var triggerIdGuid = GetTriggerId(currentContext); // check backlog if necessary if (triggerIdGuid == null) { log.Log("No trigger ID found."); return(null); } var triggerId = triggerIdGuid.ToString(); log.Log($"Found trigger ID '{triggerId}' in shared variables."); log.Log("Retrieving backlog entry ..."); var triggerBacklog = (from backlogQ in xrmContext.AutoNumberingBacklogSet join autonumberQ in xrmContext.AutoNumberingSet on backlogQ.AutoNumberingConfig equals autonumberQ.AutoNumberingId where backlogQ.TriggerID == triggerId select new AutoNumberingBacklog { Id = backlogQ.Id, IndexValue = backlogQ.IndexValue, AutoNumberingConfig = backlogQ.AutoNumberingConfig, AutoNumberingAsAutoNumberingConfig = autonumberQ }).FirstOrDefault(); log.Log("Finished retrieving backlog entry."); if (triggerBacklog == null) { log.LogWarning($"Couldn't find backlog entry for trigger ID '{triggerId}'."); return(null); } log.Log($"Using backlog '{triggerBacklog.Id}' with index {triggerBacklog.IndexValue}."); triggerBacklog.AutoNumberingAsAutoNumberingConfig.CurrentIndex = triggerBacklog.IndexValue; log.Log("Deleting backlog entry ..."); service.Delete(triggerBacklog.LogicalName, triggerBacklog.Id); log.Log("Finished deleting backlog entry."); return(triggerBacklog.AutoNumberingAsAutoNumberingConfig); }
private static bool IsSinglePage(CustomJob job, CrmLog log, IOrganizationService service) { if (string.IsNullOrWhiteSpace(job.TargetXML) || IsSingleOrNoTarget(job, log)) { return(true); } log.Log("Converting FetchXML to QueryExpression ...", LogLevel.Debug); var query = ((FetchXmlToQueryExpressionResponse) service.Execute( new FetchXmlToQueryExpressionRequest { FetchXml = job.TargetXML })).Query; log.Log("Converted.", LogLevel.Debug); // we only need to check if there are more pages or not query.ColumnSet = new ColumnSet(false); query.PageInfo = new PagingInfo { Count = job.RecordsPerPage ?? 5000, PageNumber = job.PageNumber ?? 1, PagingCookie = job.PagingCookie }; log.Log($"Retrieving a max of {query.PageInfo.Count} per page ...", LogLevel.Debug); log.Log($"Retrieving page {query.PageInfo.PageNumber} ...", LogLevel.Debug); var result = service.RetrieveMultiple(query); log.Log($"More records: {result.MoreRecords}."); return(result.MoreRecords); }
public string ExportRecords(ExportConfiguration configuration) { try { log.Log(new LogEntry("Exporting records using provided configuration.", information: configuration.ToJson())); options = configuration.ExportOptions; log.Log($"Going over {configuration.Records.Count} record definitions in parallel ..."); Parallel.ForEach(configuration.Records, new ParallelOptions { MaxDegreeOfParallelism = CrmService.Threads }, recordsConfig => LoadEntities(recordsConfig)); log.Log($"Finished going over record definitions."); if (configuration.ExportOptions.IsExcludeOwner == true) { log.Log("Removing owner values from all records ..."); foreach (var record in recordsMap.Values .Select(e => e.Record) .Where(e => e.Attributes.Keys.Intersect(ownerFields).Any())) { var recordOwnerFields = record.Attributes.Keys.Intersect(ownerFields).ToArray(); foreach (var field in recordOwnerFields) { record.Attributes.Remove(field); } log.Log($"Removed '${recordOwnerFields.Aggregate((f1, f2) => $"{f1},{f2}")}'."); } log.Log("Finished removing owner values from all records."); } log.Log("Clearing formatted values from all records ..."); foreach (var formattedValues in recordsMap.Values .Select(e => e.Record.FormattedValues) .Where(f => f.Any())) { formattedValues.Clear(); } log.Log("Finished cleared formatted values from all records."); var exportedData = new ExportedData { Configuration = configuration, EntityDefinition = recordsMap, RelationDefinition = relationsMap, Queries = queries }; log.Log("Serialising exported data ..."); var serialisedData = configuration.ExportOptions.IsCompressData == true ? Helpers.Helpers.Compress(exportedData) : Encoding.UTF8.GetString(Helpers.Helpers.Serialise(exportedData)); log.Log("Finished serialising exported data."); log.Log($"Finished exporting records using provided configuration."); return(serialisedData); } catch (AggregateException exception) { throw new Exception(exception.InnerExceptions .Select(e => $"{e.GetType()} => {e.Message}" + $"{(e.InnerException == null ? "" : $"{e.InnerException.GetType()} => {e.InnerException.Message}")}") .Aggregate((e1, e2) => $"{e1} ||| {e2}")); } }
internal Result GenerateAndUpdateRecord(bool useService = true, bool isUpdate = false, bool isBackLogged = false) { var autoNumberConfigId = autoNumberConfig.Id; if (autoNumberConfig.FormatString == null) { throw new InvalidPluginExecutionException("Couldn't find a format string in the auto-numbering configuration."); } var updatedAutoNumbering = new AutoNumbering { Id = autoNumberConfigId }; // generate a string, and make sure it's unique var field = autoNumberConfig.FieldLogicalName?.Trim(); var result = GenerateUniqueString(isUpdate, updatedAutoNumbering, field); log.Log($"Final auto-number: {result}"); // if target and field exist, then user wants to update the record if (target != null && field != null) { log.Log($"Adding generated number: '{result.GeneratedString}', to field: '{field}' ..."); if (useService) { var updatedTarget = new Entity(target.LogicalName) { Id = target.Id, [field] = result.GeneratedString }; service.Update(updatedTarget); } else { target[field] = result.GeneratedString; } } if (!isInlineConfig && !isBackLogged) { log.Log($"Updating auto-numbering with index {updatedAutoNumbering.CurrentIndex} ..."); // set the new dates and index in the auto-numbering record service.Update(updatedAutoNumbering); } return(result); }
private void LogRunStatus(JobRunStatus runStatus) { if (!runStatus.IsSuccess && runStatus.RunTargetFailures?.Any() == true) { runStatus.LatestRunMessage = "Failed run.\r\n\r\nFirst Exception: " + runStatus.RunTargetFailures.FirstOrDefault()?.FailureMessage; } else { runStatus.LatestRunMessage = runStatus.LatestRunMessage ?? (runStatus.IsSuccess ? "Successful run." : "Failed run."); } log.Log($"Updating latest run message: '{runStatus.LatestRunMessage}' ...", LogLevel.Debug); log.Log($"Updating latest date: '{Job.TargetDate ?? DateTime.UtcNow}' UTC ...", LogLevel.Debug); Service.Update( new CustomJob { Id = Job.Id, LatestRunMessage = runStatus.LatestRunMessage, PreviousTargetDate = Job.TargetDate ?? DateTime.UtcNow }); log.Log($"Updated latest run message: '{runStatus.LatestRunMessage}'."); log.Log($"Updated latest date: '{Job.TargetDate ?? DateTime.UtcNow}' UTC."); if (Job.GenerateLogs == true) { log.Log("Creating log entry ...", LogLevel.Debug); var logEntry = new CustomJobLog { Message = DateTime.Now + ": " + (runStatus.IsSuccess ? "Successful run." : "Failed run."), ExecutionDate = Job.TargetDate ?? DateTime.UtcNow, ExecutionFullMessage = runStatus.LatestRunMessage, CustomJob = Job.Id, StatusReason = runStatus.IsSuccess ? CustomJobLog.StatusReasonEnum.Success : CustomJobLog.StatusReasonEnum.Failure }; if (runStatus.RunTargetFailures?.Any() == true) { runStatus.RunTargetFailures.ForEach(failure => failure.CustomJob = null); logEntry.CustomJobFailedTargetsOfLogEntry = runStatus.RunTargetFailures.ToArray(); } Service.Create(logEntry); log.Log("Created log entry."); if (runStatus.ParentId.HasValue) { logEntry.Message += " [Sub-Job]"; logEntry.CustomJob = runStatus.ParentId.Value; Service.Create(logEntry); log.Log("Created log entry in parent."); } } }
protected ExecutionFailures Execute(JobPagingInfo pagingInfo) { var result = new ExecutionFailures(); var contextService = GetServiceInContext(); var targets = pagingInfo.Targets; Guid workflowId; if (Guid.TryParse(Job.ActionName, out workflowId) || ((workflowId = Job.Workflow.GetValueOrDefault()) != Guid.Empty)) { log.Log($"Running workflow '{workflowId}' ..."); if (targets?.Any() == true) { foreach (var target in targets) { try { log.Log($"Running workflow on '{target}'."); contextService.Execute( new ExecuteWorkflowRequest { EntityId = target, WorkflowId = workflowId }); } catch (Exception ex) { log.Log($"Failed at '{target}':'{ex.Message}'."); result.Exceptions[target] = ex; if (Job.ContinueOnError == false) { break; } } } } else { log.Log("No targets to run workflow on."); } log.Log($"Finished running workflow '{workflowId}'."); } else { var action = new OrganizationRequest(Job.ActionName); if (!string.IsNullOrEmpty(Job.SerialisedInputParams)) { log.Log($"Inputs: '{Job.SerialisedInputParams}'."); action.Parameters.AddRange(GetInputs()); } log.Log($"Executing action '{Job.ActionName}' ..."); if (targets?.Any() == true) { foreach (var target in targets) { try { log.Log($"Executing action on '{target}' ..."); action["Target"] = new EntityReference(Job.TargetLogicalName, target); contextService.Execute(action); } catch (Exception ex) { log.Log($"Failed at '{target}':'{ex.Message}'."); result.Exceptions[target] = ex; if (Job.ContinueOnError == false) { break; } } } } else if (string.IsNullOrEmpty(Job.TargetLogicalName)) { try { log.Log($"Executing global action ..."); contextService.Execute(action); } catch (Exception ex) { log.Log($"Failed: '{ex.Message}'."); result.Exceptions[Job.Id] = ex; } } log.Log($"Executed action '{Job.ActionName}'."); } return(result); }
internal EntityReference RouteToRole(EntityReference recordRef, Guid?roleId, Entity record, Guid?defaultRoutingUser = null, bool isPickRegarding = true, bool isLeastLoadedRouting = false) { try { log.LogFunctionStart(); if (roleId == null) { throw new InvalidPluginExecutionException("Role in stage configuration is not set."); } var role = service.Retrieve(RoleConfiguration.EntityLogicalName, roleId.Value, new ColumnSet(RoleConfiguration.Fields.Type, RoleConfiguration.Fields.Queue, RoleConfiguration.Fields.Team, RoleConfiguration.Fields.User)).ToEntity <RoleConfiguration>(); log.Log("Retrieved role.", LogLevel.Debug); if (role.Type == null) { throw new InvalidPluginExecutionException("Role type is not specified."); } log.LogLine(); var owner = (EntityReference)record["ownerid"]; switch (role.Type) { case RoleConfiguration.TypeEnum.Queue: if (role.Queue == null) { throw new InvalidPluginExecutionException("Queue role is not set in role configuration."); } log.LogLine(); if (defaultRoutingUser.HasValue) { owner = new EntityReference(User.EntityLogicalName, defaultRoutingUser.Value); AssignRecord(recordRef, owner); log.Log($"Assigned record to default user: {defaultRoutingUser}"); } AddToQueue(recordRef, role.Queue.Value); log.Log($"Assigned to queue: {role.QueueName}"); // if 'pick record' is set in role config, then set it in task to assign the record to same user as task when picking if (recordRef.LogicalName == Task.EntityLogicalName && isPickRegarding) { service.Update(new Task { Id = recordRef.Id, PickRecord = true }); log.Log("Set 'pick record' flag to 'true'."); } break; case RoleConfiguration.TypeEnum.Team: if (role.Team == null) { throw new InvalidPluginExecutionException("Team role is not set in role configuration."); } log.Log($"Record: {recordRef.Name}, ID: {recordRef.Id}" + $". Team: {role.TeamName}" + (role.Team != null ? $", ID: {role.Team}" : "")); owner = new EntityReference(Team.EntityLogicalName, role.Team.Value); // check least loaded user if (isLeastLoadedRouting) { var userId = GetLeastLoadedUser(role.Team.Value, record.LogicalName); if (userId != null) { owner = new EntityReference(User.EntityLogicalName, userId.Value); log.Log("Assigned to least loaded user."); } } AssignRecord(recordRef, owner); log.Log($"Assigned to team: {role.TeamName}"); break; case RoleConfiguration.TypeEnum.User: if (role.User == null) { throw new InvalidPluginExecutionException("User role is not set in role configuration."); } log.LogLine(); owner = new EntityReference(User.EntityLogicalName, role.User.Value); AssignRecord(recordRef, owner); log.Log($"Assigned to user: {role.User}"); break; } return(owner); } catch (Exception ex) { log.Log(ex); throw; } finally { log.LogFunctionEnd(); } }
internal static AutoNumbering GetAutoNumberingConfig(Entity target, string config, IPluginExecutionContext context, IOrganizationService service, CrmLog log, out bool isBackLogged) { var xrmContext = new XrmServiceContext(service) { MergeOption = MergeOption.NoTracking }; var configIds = config.Split(',').Select(item => item.Trim()).ToArray(); var isInlineConfig = config.Contains(";;"); AutoNumbering autoNumberConfig = null; if (isInlineConfig) { autoNumberConfig = GetInlineConfig(config, context.UserId); } // get it once to check for generator field update below log.Log("Getting auto-numbering config ..."); // if a condition is found in any of the configs, then don't throw an error if none match // it simply means that the user wants the auto-numbering to work only if the condition is satisified // this is useful for multiple fields var isConditioned = false; // if using a backlog, then no need to lock isBackLogged = false; if (!isInlineConfig) { var autoNumberConfigTemp = GetBackloggedConfig(context, service, log); if (autoNumberConfigTemp == null) { foreach (var configId in configIds) { autoNumberConfigTemp = (from autoNumberQ in xrmContext.AutoNumberingSet where autoNumberQ.UniqueID == configId || autoNumberQ.Name == configId && autoNumberQ.Status == AutoNumbering.StatusEnum.Active select autoNumberQ).FirstOrDefault(); if (autoNumberConfigTemp == null) { continue; } if (autoNumberConfigTemp.Condition != null) { isConditioned = true; log.Log($"Checking condition for '{autoNumberConfigTemp.Name}':'{autoNumberConfigTemp.Id}' ..."); var parsedCondition = ParseAttributeVariables(service, autoNumberConfigTemp.Condition, target, context.UserId, context.OrganizationId.ToString()); var isConditionMet = IsConditionMet(service, parsedCondition, target.ToEntityReference(), context.OrganizationId.ToString()); if (isConditionMet) { log.Log("Condition met for auto-numbering record."); autoNumberConfig = autoNumberConfigTemp; break; } log.Log("Condition not met for auto-numbering record."); } else if (autoNumberConfig == null) { autoNumberConfig = autoNumberConfigTemp; } } } else { autoNumberConfig = autoNumberConfigTemp; isBackLogged = true; } } return(PreValidation(service, target, autoNumberConfig, log, isConditioned, isBackLogged)); }
internal static AutoNumbering PreValidation(IOrganizationService service, Entity target, AutoNumbering autoNumberingConfig, CrmLog log, bool isConditioned, bool isBackLogged) { if (autoNumberingConfig == null) { // condition satisfaction failed before, so there's nothing to do here if (isConditioned) { return(null); } throw new InvalidPluginExecutionException("Couldn't find an auto-numbering configuration."); } // if the auto-numbering is inactive, then don't apply if (autoNumberingConfig.Status == AutoNumbering.StatusEnum.Inactive) { //throw new InvalidPluginExecutionException("Autonumbering config record is inactive."); log.Log("AutoNumbering record is inactive."); return(null); } // exit if auto-number field is updating to prevent looping if (target != null && autoNumberingConfig.FieldLogicalName != null && target.Contains(autoNumberingConfig.FieldLogicalName)) { log.Log("Numbering is in progress in another instance."); return(null); } if (autoNumberingConfig.Id == Guid.Empty) { log.Log("Using inline config."); return(autoNumberingConfig); } if (autoNumberingConfig.Condition != null && autoNumberingConfig.EntityLogicalName_ldv_EntityLogicalName == null) { throw new InvalidPluginExecutionException("Condition is set but entity name is not set in auto-numbering config."); } // only lock if an index is needed if (autoNumberingConfig.FormatString.Contains("{!index!}") && !isBackLogged) { log.Log("Locking ...", LogLevel.Debug); // ensure locking service.Update( new AutoNumbering { Id = autoNumberingConfig.Id, Locking = new Random().Next(999999, 999999999).ToString() }); log.Log("Refetching numbering record ...", LogLevel.Debug); // get it again to ensure locking took effect var currentIndex = (from autoNumberQ in new XrmServiceContext(service).AutoNumberingSet where autoNumberQ.AutoNumberingId == autoNumberingConfig.Id && autoNumberQ.Status == AutoNumbering.StatusEnum.Active select autoNumberQ.CurrentIndex).First(); autoNumberingConfig.CurrentIndex = currentIndex; } return(autoNumberingConfig); }
public DateTime GetSlaTime(DateTime startTime, double notificationDuration, string durationUnit) { var notificationTime = startTime; //set to initial value of the day at 12:00 AM //DateTime dayClosingTime = notificationTime.AddSeconds(-1 * notificationTime.TimeOfDay.TotalSeconds); var dayClosingTime = notificationTime.Date; var dayStartingTime = notificationTime.Date; //set to initial value of the next day at 12:00 AM // DateTime nextDay = notificationTime.AddSeconds(-1 * notificationTime.TimeOfDay.TotalSeconds).AddDays(1); var nextDay = notificationTime.Date.AddDays(1); try { log.Log("inside GetSLATime", LogLevel.Debug); log.Log("Start Time" + startTime, LogLevel.Debug); log.Log("Duration" + notificationDuration, LogLevel.Debug); // DynamicEntity caseRecord = helper.RetrieveDynamicEntity(CaseId, EntityName.incident.ToString()); var vacations = GetVacations(); var standardWorkingHoursEntity = GetStandardWorkingHours(); //i.e: 8 hrs if (standardWorkingHoursEntity == null) { //standardWorkingHoursMessage = "ساعات العمل الاعتيادية غير معرفة في النظام.برجاء الاتصال بالمسئول عن النظام.";//Resources.CalculateSLAPlugin_Ar.StandardWorkingHoursValidation; const string standardWorkingHoursMessage = "The standard working hours are not defined in the system. Please contact your system administrator"; throw new InvalidPluginExecutionException(standardWorkingHoursMessage); } var exceptionalWorkingHoursCollection = GetExceptionalWorkingHours(); var durationInHours = notificationDuration; //sla of Task Config or Case config #region minutes #region draft //if (durationUnit.ToLower() == "minutes") //{ // log.LogComment("inside minutes M="+durationInHours); // durationInHours = durationInHours / 60; // log.LogComment("Houres Calculated "+durationInHours); //} #endregion if (durationUnit.ToLower() == "minutes") { durationInHours = notificationDuration / 60; log.Log("minutes calculated " + durationInHours, LogLevel.Debug); #region today is vacation /*var isVacation = IsVacation(DateTime.Now, * GetDayWorkingHours(DateTime.Now, standardWorkingHoursEntity, exceptionalWorkingHoursCollection), * GetVactions()); * if (isVacation) * { * var nextDate = FindNextWorkingDay(DateTime.Now); * var nextDayWorkingHours = GetDayWorkingHours(nextDate, * standardWorkingHoursEntity, * exceptionalWorkingHoursCollection); * * DateTime start = (DateTime)nextDayWorkingHours["ldv_workinghoursstart"]; * notificationTime = start.AddMinutes(notificationDuration); * return notificationTime; * }*/ #endregion #region not in working hours //var toDayWorkingHours = GetDayWorkingHours(DateTime.Now, standardWorkingHoursEntity, // exceptionalWorkingHoursCollection); //if (DateTime.Now > ()DateTimetoDayWorkingHours["ldv_workinghoursstart"]) #endregion #region in working houres (default) /*notificationTime = DateTime.Now.AddMinutes(notificationDuration); * return notificationTime; */ #endregion } #endregion if (durationUnit.ToLower() == "days") { if (standardWorkingHoursEntity.Contains("ldv_workinghours")) { durationInHours = durationInHours * double.Parse(standardWorkingHoursEntity["ldv_workinghours"].ToString()); } } var currentDayWorkingHours = GetDayWorkingHours(startTime, standardWorkingHoursEntity, exceptionalWorkingHoursCollection); if (currentDayWorkingHours.Contains("ldv_workinghoursend")) //("new_to")) { //string hoursToText = ((Picklist)workingDays.Properties["ld_to"]).name; var hoursToText = currentDayWorkingHours.FormattedValues["ldv_workinghoursend"]; var hoursToParts = hoursToText.Split(' '); var hoursTo = double.Parse(hoursToParts[0].Split(':')[0]); var minutesTo = double.Parse(hoursToParts[0].Split(':')[1]); if (hoursToParts[1].ToLower() == "pm" && hoursTo != 12) { hoursTo += 12; } if (minutesTo == 30) { hoursTo += 0.5; } dayClosingTime = dayClosingTime.AddHours(hoursTo); } if (currentDayWorkingHours.Contains("ldv_workinghoursstart")) //("new_from")) { //string hoursFromText = ((Picklist)workingDays.Properties["ld_from"]).name; var hoursFromText = currentDayWorkingHours.FormattedValues["ldv_workinghoursstart"]; var hoursFromParts = hoursFromText.Split(' '); var hoursFrom = double.Parse(hoursFromParts[0].Split(':')[0]); var minutesFrom = double.Parse(hoursFromParts[0].Split(':')[1]); if (hoursFromParts[1].ToLower() == "pm" && hoursFrom != 12) { hoursFrom += 12; } if (minutesFrom == 30) { hoursFrom += 0.5; } dayStartingTime = dayStartingTime.AddHours(hoursFrom); } if (IsVacation(startTime, currentDayWorkingHours, vacations) || startTime > dayClosingTime) { } else { if (startTime < dayStartingTime) { startTime = dayStartingTime; } notificationTime = startTime.AddHours(durationInHours); if (notificationTime <= dayClosingTime) { durationInHours = 0; } else { var nextDayRemainingTime = notificationTime - dayClosingTime; durationInHours = nextDayRemainingTime.TotalHours; } } while (durationInHours > 0) { var nextDayStartTime = nextDay; var nextDayWorkingHours = GetDayWorkingHours(nextDay, standardWorkingHoursEntity, exceptionalWorkingHoursCollection); while (IsVacation(nextDay, nextDayWorkingHours, vacations)) { nextDay = nextDay.AddDays(1); nextDayWorkingHours = GetDayWorkingHours(nextDay, standardWorkingHoursEntity, exceptionalWorkingHoursCollection); } double nextDayTotalWorkingHours = 0; if (nextDayWorkingHours.Contains("ldv_workinghours")) { nextDayTotalWorkingHours = double.Parse(nextDayWorkingHours["ldv_workinghours"].ToString()); } if (nextDayWorkingHours.Contains("ldv_workinghoursstart")) { //string hoursFromText = ((Picklist)workingDays.Properties["ld_from"]).name; var hoursFromText = nextDayWorkingHours.FormattedValues["ldv_workinghoursstart"]; var hoursFromParts = hoursFromText.Split(' '); var hoursFrom = double.Parse(hoursFromParts[0].Split(':')[0]); var minutesFrom = double.Parse(hoursFromParts[0].Split(':')[1]); if (hoursFromParts[1].ToLower() == "pm" && hoursFrom != 12) { hoursFrom += 12; } if (minutesFrom == 30) { hoursFrom += 0.5; } nextDayStartTime = nextDay.AddHours(hoursFrom); } if (durationInHours <= nextDayTotalWorkingHours) { notificationTime = nextDayStartTime.AddHours(durationInHours); durationInHours = 0; } else { nextDay = nextDay.AddDays(1); durationInHours = durationInHours - nextDayTotalWorkingHours; } } return(notificationTime); } catch (Exception ex) { log.Log(ex.Message, LogLevel.Error); //log.CatchException(ex); throw; } }
public bool ImportRecords(string rawData) { var splitRawData = rawData.Split(new[] { "<|||>" }, StringSplitOptions.RemoveEmptyEntries); if (!splitRawData.Any()) { throw new Exception("Data given is empty."); } var rawStringData = splitRawData[0]; if (splitRawData.Length > 1 && splitRawData[1] == "TRUE") { data = Helpers.Helpers.Decompress <ExportedData>(rawStringData); if (splitRawData.Length > 2) { options = ImportOptions.FromJson(splitRawData[2]); } } else { data = Helpers.Helpers.Deserialise <ExportedData>(Encoding.UTF8.GetBytes(rawStringData)); } if (data?.EntityDefinition == null) { log.LogWarning("Import data is empty, skipping ..."); return(true); } log.Log($"Importing {data.EntityDefinition?.Count} records."); log.Log($"Importing {data.RelationDefinition?.Count} relations."); Initialise(); ProcessObsoleteRecordsRemoval(); var dependencyRequests = ProcessDependencies(recordsMap.Values.ToArray()).ToList(); var requests = GetSyncRequests(); idsMap = requests .ToDictionary(e => GetIdFromRequestResponse(e) ?? Guid.Empty, e => GetIdFromRequestResponse(e) ?? Guid.Empty); foreach (var key in recordsMap.Keys.Except(idsMap.Keys)) { idsMap[key] = key; } idsMap[Guid.Empty] = Guid.Empty; var keyedRecords = recordsMap .Where(e => e.Value.IsUseAlternateKeys && e.Value.Record.KeyAttributes.Any()) .Select(e => e.Value.Record).ToArray(); log.Log($"Clearing IDs of ${keyedRecords.Length} keyed records ..."); foreach (var record in keyedRecords) { record.Id = Guid.Empty; } var responses = ExecuteRequests(requests, "Failed in record sync step."); MapOldIdsToNewIds(requests, responses.Values); UpdateRelationRequestIds(); ProcessObsoleteRelationsRemoval(); UpdateLookupRequestIds(dependencyRequests); ExecuteRequests(dependencyRequests.Cast <OrganizationRequest>().ToList(), "Failed in lookup dependencies update step."); var associateRequests = CreateAssociateRequests().ToArray(); ExecuteRequests(associateRequests.Cast <OrganizationRequest>().ToList(), "Failed in association step.", faultMessage => faultMessage != null && !faultMessage.Contains("Cannot insert duplicate key")); return(true); }
private static int ProcessConfiguration(Settings settings) { settings.Require(nameof(settings)); var importSolutions = new List <ExportedSolution>(); var exportSolutions = settings.SolutionConfigs .Where(s => s.SolutionName.IsNotEmpty()).ToArray(); if (connectionFile.IsNotEmpty()) { var connectionParams = GetConnectionParams(); if (settings.SourceConnectionString.IsEmpty()) { log.Log("Using default source connection string from file."); settings.SourceConnectionString = connectionParams.SourceConnectionString; } if (settings.DestinationConnectionStrings?.Any() != true) { log.Log("Using default destination connection strings from file."); settings.DestinationConnectionStrings = connectionParams.DestinationConnectionStrings; } } if (exportSolutions.Any()) { importSolutions.AddRange(ExportSolutions(settings.SourceConnectionString, exportSolutions)); } var loadSolutionsConfig = settings.SolutionConfigs .Where(s => s.SolutionFile.IsNotEmpty()) .Select(s => s).ToArray(); if (loadSolutionsConfig.Any()) { importSolutions.AddRange(LoadSolutions(loadSolutionsConfig)); } var failures = new Dictionary <string, List <ExportedSolution> >(); ImportSolutions(settings.DestinationConnectionStrings, importSolutions, failures); while (failures.Any()) { log.Log("Some solutions failed to import.", LogLevel.Warning); if (isAutoRetryOnError) { log.Log($"Remaining retries: {retryCount}."); if (retryCount-- <= 0) { log.Log("Retry count has expired.", LogLevel.Warning); return(1); } log.Log($"Automatically retrying to import ..."); } else { Console.WriteLine(); Console.Write($"{failures.Sum(p => p.Value.Count)} total failures. Try again [y/n]? "); var answer = Console.ReadKey().KeyChar; Console.WriteLine(); if (answer != 'y') { return(1); } Console.WriteLine(); } var failuresCopy = failures.ToArray(); failures = new Dictionary <string, List <ExportedSolution> >(); foreach (var pair in failuresCopy) { ImportSolutions(new[] { pair.Key }, pair.Value, failures); } } return(0); }