Beispiel #1
0
        /// <summary>
        /// Start shifts sync from Kronos to Shifts.
        /// </summary>
        /// <param name="isRequestFromLogicApp">Checks if request is coming from logic app or portal.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        internal async Task ProcessShiftsAsync(string isRequestFromLogicApp)
        {
            this.telemetryClient.TrackTrace($"{Resource.ProcessShiftsAsync} starts at: {DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture)} for isRequestFromLogicApp: {isRequestFromLogicApp}");

            this.utility.SetQuerySpan(Convert.ToBoolean(isRequestFromLogicApp, CultureInfo.InvariantCulture), out string shiftStartDate, out string shiftEndDate);
            var allRequiredConfigurations = await this.utility.GetAllConfigurationsAsync().ConfigureAwait(false);

            // Check whether date range are in correct format.
            var isCorrectDateRange = Utility.CheckDates(shiftStartDate, shiftEndDate);

            if (allRequiredConfigurations != null && (bool)allRequiredConfigurations?.IsAllSetUpExists && isCorrectDateRange)
            {
                // Get the mapped user details from user to user mapping table.
                var kronosUsers = await this.GetAllMappedUserDetailsAsync(allRequiredConfigurations.WFIId).ConfigureAwait(false);

                if (kronosUsers.Any())
                {
                    var monthPartitions = Utility.GetMonthPartition(shiftStartDate, shiftEndDate);

                    if (monthPartitions.Count > 0)
                    {
                        var processNumberOfUsersInBatch = this.appSettings.ProcessNumberOfUsersInBatch;
                        var userCount     = kronosUsers.Count();
                        int userIteration = Utility.GetIterablesCount(Convert.ToInt32(processNumberOfUsersInBatch, CultureInfo.InvariantCulture), userCount);

                        foreach (var monthPartitionKey in monthPartitions)
                        {
                            string queryStartDate, queryEndDate;
                            Utility.GetNextDateSpan(
                                monthPartitionKey,
                                monthPartitions.FirstOrDefault(),
                                monthPartitions.LastOrDefault(),
                                shiftStartDate,
                                shiftEndDate,
                                out queryStartDate,
                                out queryEndDate);

                            var processUsersInBatchList = new List <App.KronosWfc.Models.ResponseEntities.HyperFind.ResponseHyperFindResult>();
                            foreach (var item in kronosUsers?.ToList())
                            {
                                processUsersInBatchList.Add(new App.KronosWfc.Models.ResponseEntities.HyperFind.ResponseHyperFindResult
                                {
                                    PersonNumber = item.KronosPersonNumber,
                                });
                            }

                            var processBatchUsersQueue  = new Queue <App.KronosWfc.Models.ResponseEntities.HyperFind.ResponseHyperFindResult>(processUsersInBatchList);
                            var processKronosUsersQueue = new Queue <UserDetailsModel>(kronosUsers);

                            for (int batchedUserCount = 0; batchedUserCount < userIteration; batchedUserCount++)
                            {
                                var processKronosUsersQueueInBatch = processKronosUsersQueue?.Skip(Convert.ToInt32(processNumberOfUsersInBatch, CultureInfo.InvariantCulture) * batchedUserCount).Take(Convert.ToInt32(processNumberOfUsersInBatch, CultureInfo.InvariantCulture));
                                var processBatchUsersQueueInBatch  = processBatchUsersQueue?.Skip(Convert.ToInt32(processNumberOfUsersInBatch, CultureInfo.InvariantCulture) * batchedUserCount).Take(Convert.ToInt32(processNumberOfUsersInBatch, CultureInfo.InvariantCulture));

                                var lookUpData = await this.shiftMappingEntityProvider.GetAllShiftMappingEntitiesInBatchAsync(
                                    processKronosUsersQueueInBatch,
                                    monthPartitionKey,
                                    queryStartDate,
                                    queryEndDate).ConfigureAwait(false);

                                // Get shift response for a batch of users.
                                var shiftsResponse = await this.shiftsActivity.ShowUpcomingShiftsInBatchAsync(
                                    new Uri(allRequiredConfigurations.WfmEndPoint),
                                    allRequiredConfigurations.KronosSession,
                                    DateTime.Now.ToString(queryStartDate, CultureInfo.InvariantCulture),
                                    DateTime.Now.ToString(queryEndDate, CultureInfo.InvariantCulture),
                                    processBatchUsersQueueInBatch.ToList()).ConfigureAwait(false);

                                // Kronos api returns any shifts that occur in the date span provided.
                                // We want only the entities that started within the query date span.
                                var shifts = ControllerHelper.FilterEntitiesByQueryDateSpan(shiftsResponse?.Schedule?.ScheduleItems?.ScheduleShifts, queryStartDate, queryEndDate);

                                var lookUpEntriesFoundList = new List <TeamsShiftMappingEntity>();
                                var shiftsNotFoundList     = new List <Shift>();

                                var userModelList         = new List <UserDetailsModel>();
                                var userModelNotFoundList = new List <UserDetailsModel>();

                                await this.ProcessShiftEntitiesBatchAsync(
                                    allRequiredConfigurations,
                                    lookUpEntriesFoundList,
                                    shiftsNotFoundList,
                                    userModelList,
                                    userModelNotFoundList,
                                    lookUpData,
                                    processKronosUsersQueueInBatch,
                                    shifts,
                                    monthPartitionKey).ConfigureAwait(false);
                            }
                        }
                    }
                }
            }
            else
            {
                this.telemetryClient.TrackTrace("SyncShiftsFromKronos - " + Resource.SetUpNotDoneMessage);
            }

            this.telemetryClient.TrackTrace($"{Resource.ProcessShiftsAsync} completed at: {DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture)}" + " for isRequestFromLogicApp: " + isRequestFromLogicApp);
        }
        /// <summary>
        /// Get the list of open shift entities from Kronos and pushes to Shifts.
        /// </summary>
        /// <param name="isRequestFromLogicApp">Checks if request is coming from logic app or portal.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        internal async Task ProcessOpenShiftsAsync(string isRequestFromLogicApp)
        {
            this.telemetryClient.TrackTrace($"{Resource.ProcessOpenShiftsAsync} started at: {DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture)} for isRequestFromLogicApp:  {isRequestFromLogicApp}");

            // Adding the telemetry properties.
            var telemetryProps = new Dictionary <string, string>()
            {
                { "MethodName", Resource.ProcessOpenShiftsAsync },
                { "CallingAssembly", Assembly.GetCallingAssembly().GetName().Name },
            };

            if (isRequestFromLogicApp == null)
            {
                throw new ArgumentNullException(nameof(isRequestFromLogicApp));
            }

            var allRequiredConfigurations = await this.utility.GetAllConfigurationsAsync().ConfigureAwait(false);

            if (allRequiredConfigurations?.IsAllSetUpExists == false)
            {
                throw new Exception($"{Resource.SyncOpenShiftsFromKronos} - {Resource.SetUpNotDoneMessage} - Some configuration settings were missing.");
            }

            this.utility.SetQuerySpan(Convert.ToBoolean(isRequestFromLogicApp, CultureInfo.InvariantCulture), out var openShiftStartDate, out var openShiftEndDate);

            // Check whether date range are in correct format.
            if (!Utility.CheckDates(openShiftStartDate, openShiftEndDate))
            {
                throw new Exception($"{Resource.SyncOpenShiftsFromKronos} - Query date was invalid.");
            }

            var monthPartitions = Utility.GetMonthPartition(openShiftStartDate, openShiftEndDate);

            if (monthPartitions?.Count > 0)
            {
                telemetryProps.Add("MonthPartitionsStatus", "There are no month partitions found!");
            }

            var orgJobBatchSize = int.Parse(this.appSettings.ProcessNumberOfOrgJobsInBatch, CultureInfo.InvariantCulture);
            var orgJobPaths     = await this.teamDepartmentMappingProvider.GetAllOrgJobPathsAsync().ConfigureAwait(false);

            var mappedTeams = await this.teamDepartmentMappingProvider.GetMappedTeamToDeptsWithJobPathsAsync().ConfigureAwait(false);

            int orgJobPathIterations = Utility.GetIterablesCount(orgJobBatchSize, orgJobPaths.Count);

            // The monthPartitions is a list of strings which are formatted as: MM_YYYY to allow processing in batches
            foreach (var monthPartitionKey in monthPartitions)
            {
                if (monthPartitionKey == null)
                {
                    this.telemetryClient.TrackTrace($"{Resource.MonthPartitionKeyStatus} - MonthPartitionKey cannot be found please check the data.");
                    this.telemetryClient.TrackTrace(Resource.SyncOpenShiftsFromKronos, telemetryProps);
                    continue;
                }

                this.telemetryClient.TrackTrace($"Processing data for the month partition: {monthPartitionKey} at {DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture)}");

                Utility.GetNextDateSpan(
                    monthPartitionKey,
                    monthPartitions.FirstOrDefault(),
                    monthPartitions.LastOrDefault(),
                    openShiftStartDate,
                    openShiftEndDate,
                    out string queryStartDate,
                    out string queryEndDate);

                var orgJobPathList = new List <string>(orgJobPaths);

                // This for loop will iterate over the batched Org Job Paths.
                for (int iteration = 0; iteration < orgJobPathIterations; iteration++)
                {
                    this.telemetryClient.TrackTrace($"OpenShiftController - Processing on iteration number: {iteration}");

                    var orgJobsInBatch = orgJobPathList?.Skip(orgJobBatchSize * iteration).Take(orgJobBatchSize);

                    // Get the response for a batch of org job paths.
                    var openShiftsResponse = await this.GetOpenShiftResultsByOrgJobPathInBatchAsync(
                        allRequiredConfigurations.WFIId,
                        allRequiredConfigurations.WfmEndPoint,
                        allRequiredConfigurations.KronosSession,
                        orgJobsInBatch.ToList(),
                        queryStartDate,
                        queryEndDate).ConfigureAwait(false);

                    if (openShiftsResponse != null)
                    {
                        foreach (var orgJob in orgJobsInBatch)
                        {
                            this.telemetryClient.TrackTrace($"OpenShiftController - Processing the org job path: {orgJob}");

                            // Open Shift models for Create/Update operation
                            var lookUpEntriesFoundList = new List <AllOpenShiftMappingEntity>();
                            var openShiftsFoundList    = new List <OpenShiftRequestModel>();
                            var openShiftsNotFoundList = new List <OpenShiftRequestModel>();

                            var formattedOrgJob    = Utility.OrgJobPathDBConversion(orgJob);
                            var mappedOrgJobEntity = mappedTeams?.FirstOrDefault(x => x.PartitionKey == allRequiredConfigurations.WFIId && x.RowKey == formattedOrgJob);

                            // Retrieve lookUpData for the open shift entity.
                            var lookUpData = await this.openShiftMappingEntityProvider.GetAllOpenShiftMappingEntitiesInBatch(
                                monthPartitionKey,
                                formattedOrgJob,
                                queryStartDate,
                                queryEndDate).ConfigureAwait(false);

                            if (lookUpData != null)
                            {
                                // This foreach loop will process the openShiftSchedule item(s) that belong to a specific Kronos Org Job Path.
                                foreach (var openShiftSchedule in openShiftsResponse?.Schedules.Where(x => x.OrgJobPath == orgJob))
                                {
                                    this.telemetryClient.TrackTrace($"OpenShiftController - Processing the Open Shift schedule for: {openShiftSchedule.OrgJobPath}, and date range: {openShiftSchedule.QueryDateSpan}");

                                    // Kronos api returns any open shifts that occur in the date span provided.
                                    // We want only the entities that started within the query date span.
                                    var openShifts = ControllerHelper.FilterEntitiesByQueryDateSpan(openShiftSchedule.ScheduleItems?.ScheduleShifts, queryStartDate, queryEndDate);

                                    if (mappedOrgJobEntity == null)
                                    {
                                        this.telemetryClient.TrackTrace($"{Resource.SyncOpenShiftsFromKronos} - There is no mappedTeam found with WFI ID: {allRequiredConfigurations.WFIId}");
                                        continue;
                                    }

                                    if (openShifts.Count == 0)
                                    {
                                        this.telemetryClient.TrackTrace($"OpenShiftCount - {openShifts.Count} for {openShiftSchedule.OrgJobPath}");
                                        continue;
                                    }

                                    this.telemetryClient.TrackTrace($"OpenShiftController - Processing Open Shifts for the mapped team: {mappedOrgJobEntity.ShiftsTeamName}");

                                    // This foreach builds the Open Shift object to push to Shifts via Graph API.
                                    foreach (var openShift in openShifts)
                                    {
                                        this.telemetryClient.TrackTrace($"OpenShiftController - Processing {openShift.StartDate} with {openShift.ShiftSegments.ShiftSegment.Count} segments.");

                                        var teamsOpenShiftEntity = this.GenerateTeamsOpenShiftEntity(openShift, mappedOrgJobEntity);

                                        if (lookUpData.Count == 0)
                                        {
                                            this.telemetryClient.TrackTrace($"OpenShiftController - Adding {teamsOpenShiftEntity.KronosUniqueId} to the openShiftsNotFoundList as the lookUpData count = 0");
                                            openShiftsNotFoundList.Add(teamsOpenShiftEntity);
                                        }
                                        else
                                        {
                                            var kronosUniqueIdExists = lookUpData.Where(c => c.KronosOpenShiftUniqueId == teamsOpenShiftEntity.KronosUniqueId);

                                            if ((kronosUniqueIdExists != default(List <AllOpenShiftMappingEntity>)) && kronosUniqueIdExists.Any())
                                            {
                                                this.telemetryClient.TrackTrace($"OpenShiftController - Adding {kronosUniqueIdExists.FirstOrDefault().KronosOpenShiftUniqueId} to the lookUpEntriesFoundList as there is data in the lookUpData list.");
                                                lookUpEntriesFoundList.AddRange(kronosUniqueIdExists);
                                                openShiftsFoundList.Add(teamsOpenShiftEntity);
                                            }
                                            else
                                            {
                                                this.telemetryClient.TrackTrace($"OpenShiftController - Adding {teamsOpenShiftEntity.KronosUniqueId} to the openShiftsNotFoundList.");
                                                openShiftsNotFoundList.Add(teamsOpenShiftEntity);
                                            }
                                        }
                                    }
                                }

                                // We now want to process open shifts that are identical to one or more other open shifts,
                                // this includes open shifts with a slot count in Teams as well as any open shift with a matching hash.
                                await this.ProcessIdenticalOpenShifts(allRequiredConfigurations, monthPartitionKey, openShiftsFoundList, lookUpEntriesFoundList, mappedOrgJobEntity, lookUpData).ConfigureAwait(false);

                                if (lookUpData.Except(lookUpEntriesFoundList).Any())
                                {
                                    this.telemetryClient.TrackTrace($"OpenShiftController - The lookUpEntriesFoundList has {lookUpEntriesFoundList.Count} items which could be deleted");
                                    await this.DeleteOrphanDataOpenShiftsEntityMappingAsync(allRequiredConfigurations, lookUpEntriesFoundList, lookUpData, mappedOrgJobEntity).ConfigureAwait(false);
                                }

                                if (openShiftsNotFoundList.Count > 0)
                                {
                                    this.telemetryClient.TrackTrace($"OpenShiftController - The openShiftsNotFoundList has {openShiftsNotFoundList.Count} items which could be added.");
                                    await this.CreateEntryOpenShiftsEntityMappingAsync(allRequiredConfigurations, openShiftsNotFoundList, lookUpEntriesFoundList, monthPartitionKey, mappedOrgJobEntity).ConfigureAwait(false);
                                }
                            }
                            else
                            {
                                this.telemetryClient.TrackTrace($"{Resource.SyncOpenShiftsFromKronos} - There is no lookup data present with the schedulingGroupId: " + mappedOrgJobEntity?.TeamsScheduleGroupId);
                                continue;
                            }
                        }
                    }
                }
            }

            this.telemetryClient.TrackTrace($"{Resource.ProcessOpenShiftsAsync} ended at: {DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture)} for isRequestFromLogicApp:  {isRequestFromLogicApp}");
        }