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");
        }
Example #2
0
        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();
            }
        }
Example #3
0
        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();
            }
        }
Example #4
0
        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();
                }
            }
        }
Example #5
0
        // 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));
        }
Example #6
0
        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();
            }
        }
Example #7
0
        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();
            }
        }
Example #8
0
        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);
        }
Example #9
0
        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();
            }
        }
Example #10
0
        // 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));
        }
Example #11
0
        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);
        }
Example #12
0
        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);
        }
Example #13
0
        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.");
                }
            }
        }
Example #17
0
        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();
            }
        }
Example #19
0
        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));
        }
Example #20
0
        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);
        }
Example #21
0
        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;
            }
        }
Example #22
0
        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);
        }
Example #23
0
        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);
        }