Esempio n. 1
0
        public async Task <ActionResult> ImportMappingAsync()
        {
            // getting the posted file.
            var file = this.HttpContext.Request.Form.Files[0];

            bool isValidFile = true;
            int  noOfColumns = 0;

            if (file != null)
            {
                using (XLWorkbook workbook = new XLWorkbook(file.OpenReadStream()))
                {
                    var worksheet = workbook.Worksheet(1);

                    // validation to check if row other than column exists
                    if (worksheet.RowsUsed().Count() == 1)
                    {
                        isValidFile = false;
                        return(this.Json(new { response = isValidFile }));
                    }

                    // getting count of total used cells
                    var usedCellsCount = worksheet.RowsUsed().CellsUsed().Count();

                    foreach (IXLRow row in worksheet.RowsUsed())
                    {
                        if (row.RangeAddress.FirstAddress.RowNumber == 1)
                        {
                            // getting count of total coumns available in the template
                            noOfColumns = row.CellsUsed().Count();
                            continue;
                        }

                        // validation to check if any cell has empty value
                        if ((usedCellsCount % noOfColumns) != 0 || noOfColumns != Convert.ToInt16(Resources.NoOfColumnsInUserExcel, CultureInfo.InvariantCulture))
                        {
                            isValidFile = false;
                            return(this.Json(new { response = isValidFile }));
                        }

                        AllUserMappingEntity entity = new AllUserMappingEntity()
                        {
                            PartitionKey         = Utility.OrgJobPathDBConversion(row.Cell(1).Value.ToString()),
                            RowKey               = row.Cell(2).Value.ToString(),
                            KronosUserName       = row.Cell(3).Value.ToString(),
                            ShiftUserAadObjectId = row.Cell(4).Value.ToString(),
                            ShiftUserDisplayName = row.Cell(5).Value.ToString(),
                            ShiftUserUpn         = row.Cell(6).Value.ToString(),
                        };

                        if (isValidFile)
                        {
                            isValidFile = await this.userMappingProvider.KronosShiftUsersMappingAsync(entity).ConfigureAwait(false);
                        }
                    }
                }
            }

            return(this.Json(new { response = isValidFile }));
        }
Esempio n. 2
0
        /// <summary>
        /// Creates and stores a shift mapping entity.
        /// </summary>
        /// <param name="shift">A shift from Shifts.</param>
        /// <param name="user">A user mapping entity.</param>
        /// <param name="mappedTeam">A team mapping entity.</param>
        /// <param name="monthPartitionKey">The partition key for the shift.</param>
        /// <returns>A task.</returns>
        private async Task CreateAndStoreShiftMapping(ShiftsShift shift, AllUserMappingEntity user, TeamToDepartmentJobMappingEntity mappedTeam, List <string> monthPartitionKey)
        {
            var kronosUniqueId     = this.utility.CreateShiftUniqueId(shift, mappedTeam.KronosTimeZone);
            var shiftMappingEntity = this.CreateNewShiftMappingEntity(shift, kronosUniqueId, user.RowKey, mappedTeam.TeamId);

            await this.shiftMappingEntityProvider.SaveOrUpdateShiftMappingEntityAsync(shiftMappingEntity, shift.Id, monthPartitionKey[0]).ConfigureAwait(false);
        }
        /// <summary>
        /// Method to save or update the user mapping.
        /// </summary>
        /// <param name="entity">Mapping entity reference.</param>
        /// <returns>http status code representing the asynchronous operation.</returns>
        public Task SaveOrUpdateUserMappingEntityAsync(AllUserMappingEntity entity)
        {
            if (entity is null)
            {
                throw new ArgumentNullException(nameof(entity));
            }

            return(this.StoreOrUpdateEntityAsync(entity));
        }
Esempio n. 4
0
        /// <summary>
        /// Having the ability to create a new TeamsShiftMappingEntity.
        /// </summary>
        /// <param name="shift">The Shift model.</param>
        /// <param name="userMappingEntity">Details of user from User Mapping Entity table.</param>
        /// <param name="kronosUniqueId">Kronos Unique Id corresponds to the shift.</param>
        /// <returns>Mapping Entity associated with Team and Shift.</returns>
        public static TeamsShiftMappingEntity CreateShiftMappingEntity(
            Models.IntegrationAPI.Shift shift,
            AllUserMappingEntity userMappingEntity,
            string kronosUniqueId)
        {
            TeamsShiftMappingEntity teamsShiftMappingEntity = new TeamsShiftMappingEntity
            {
                AadUserId          = shift?.UserId,
                KronosUniqueId     = kronosUniqueId,
                KronosPersonNumber = userMappingEntity?.RowKey,
            };

            return(teamsShiftMappingEntity);
        }
Esempio n. 5
0
        /// <summary>
        /// Having the ability to create a new TeamsShiftMappingEntity.
        /// </summary>
        /// <param name="shift">The Shift model.</param>
        /// <param name="userMappingEntity">Details of user from User Mapping Entity table.</param>
        /// <param name="kronosUniqueId">Kronos Unique Id corresponds to the shift.</param>
        /// <returns>Mapping Entity associated with Team and Shift.</returns>
        public TeamsShiftMappingEntity CreateShiftMappingEntity(
            Models.IntegrationAPI.Shift shift,
            AllUserMappingEntity userMappingEntity,
            string kronosUniqueId)
        {
            TeamsShiftMappingEntity teamsShiftMappingEntity = new TeamsShiftMappingEntity
            {
                AadUserId          = shift?.UserId,
                KronosUniqueId     = kronosUniqueId,
                KronosPersonNumber = userMappingEntity?.RowKey,
                ShiftStartDate     = this.UTCToKronosTimeZone(shift.SharedShift.StartDateTime),
            };

            return(teamsShiftMappingEntity);
        }
        /// <summary>
        /// Gets a user model from Shifts in order to return the Org Job Path.
        /// </summary>
        /// <returns>A task.</returns>
        private async Task <UserDetailsModel> GetMappedUserDetailsAsync(
            string workForceIntegrationId,
            string userAadObjectId,
            string teamsId)
        {
            UserDetailsModel     kronosUser;
            AllUserMappingEntity mappedUsersResult = await this.userMappingProvider.GetUserMappingEntityAsyncNew(userAadObjectId, teamsId).ConfigureAwait(false);

            if (mappedUsersResult != null)
            {
                var teamMappingEntity = await this.teamDepartmentMappingProvider.GetTeamMappingForOrgJobPathAsync(
                    workForceIntegrationId,
                    mappedUsersResult.PartitionKey).ConfigureAwait(false);

                if (teamMappingEntity != null)
                {
                    kronosUser = new UserDetailsModel()
                    {
                        KronosPersonNumber   = mappedUsersResult.RowKey,
                        ShiftUserId          = mappedUsersResult.ShiftUserAadObjectId,
                        ShiftTeamId          = teamsId,
                        ShiftScheduleGroupId = teamMappingEntity.TeamsScheduleGroupId,
                        OrgJobPath           = mappedUsersResult.PartitionKey,
                    };
                }
                else
                {
                    this.telemetryClient.TrackTrace($"Team id {teamsId} is not mapped.");

                    kronosUser = new UserDetailsModel()
                    {
                        Error = Resource.UserTeamNotExists,
                    };
                }
            }
            else
            {
                this.telemetryClient.TrackTrace($"User id {userAadObjectId} is not mapped.");

                kronosUser = new UserDetailsModel()
                {
                    Error = Resource.UserMappingNotFound,
                };
            }

            return(kronosUser);
        }
Esempio n. 7
0
        /// <summary>
        /// Method to save or update the user mapping.
        /// </summary>
        /// <param name="entity">Mapping entity reference.</param>
        /// <returns>http status code representing the asynchronous operation.</returns>
        public async Task <bool> KronosShiftUsersMappingAsync(AllUserMappingEntity entity)
        {
            if (entity is null)
            {
                throw new ArgumentNullException(nameof(entity));
            }

            try
            {
                var result = await this.StoreOrUpdateEntityAsync(entity).ConfigureAwait(false);

                return(result.HttpStatusCode == (int)HttpStatusCode.NoContent);
            }
            catch (Exception)
            {
                return(false);

                throw;
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Edits a shift in Kronos and updates the database.
        /// </summary>
        /// <param name="editedShift">The shift to edit.</param>
        /// <param name="user">The user the shift is for.</param>
        /// <param name="mappedTeam">The team the user is in.</param>
        /// <returns>A response for teams.</returns>
        public async Task <ShiftsIntegResponse> EditShiftInKronosAsync(ShiftsShift editedShift, AllUserMappingEntity user, TeamToDepartmentJobMappingEntity mappedTeam)
        {
            // The connector does not support drafting entities as it is not possible to draft shifts in Kronos.
            // Likewise there is no share schedule WFI call.
            if (editedShift.DraftShift != null)
            {
                return(ResponseHelper.CreateBadResponse(editedShift.Id, error: "Editing a shift as a draft is not supported for your team in Teams. Please publish changes directly using the 'Share' button."));
            }

            if (editedShift.SharedShift == null)
            {
                return(ResponseHelper.CreateBadResponse(editedShift.Id, error: "An unexpected error occured. Could not edit the shift."));
            }

            // We use the display name to indicate shift transfers. As we cannot support editing shifts
            // with a transfer we block edits on shifts containing the transfer string.
            if (editedShift.SharedShift.DisplayName.Contains(appSettings.TransferredShiftDisplayName))
            {
                return(ResponseHelper.CreateBadResponse(editedShift.Id, error: "You can't edit a shift that includes a shift transfer. Please make your changes in Kronos"));
            }

            // We do not support editing activities in Teamsand cannot support editing shift transfers
            // therefore we only expect activities with the regular segment type. Anything else means the
            // manager has modified or added an activity.
            var invalidActivities = editedShift.SharedShift.Activities.Where(x => x.DisplayName != ApiConstants.RegularSegmentType);

            if (invalidActivities.Any())
            {
                return(ResponseHelper.CreateBadResponse(editedShift.Id, error: "Editing shift activities is not supported for your team in Teams."));
            }

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

            if ((allRequiredConfigurations?.IsAllSetUpExists).ErrorIfNull(editedShift.Id, "App configuration incorrect.", out var response))
            {
                return(response);
            }

            // We need to get all other shifts the employee works that day.
            var kronosStartDateTime = this.utility.UTCToKronosTimeZone(editedShift.SharedShift.StartDateTime, mappedTeam.KronosTimeZone);
            var kronosEndDateTime   = this.utility.UTCToKronosTimeZone(editedShift.SharedShift.EndDateTime, mappedTeam.KronosTimeZone);

            var monthPartitionKey = Utility.GetMonthPartition(this.utility.FormatDateForKronos(kronosStartDateTime), this.utility.FormatDateForKronos(kronosEndDateTime));

            var shiftToReplace = await this.shiftMappingEntityProvider.GetShiftMappingEntityByRowKeyAsync(editedShift.Id).ConfigureAwait(false);

            var shiftToReplaceStartDateTime = this.utility.UTCToKronosTimeZone(shiftToReplace.ShiftStartDate, mappedTeam.KronosTimeZone);
            var shiftToReplaceEndDateTime   = this.utility.UTCToKronosTimeZone(shiftToReplace.ShiftEndDate, mappedTeam.KronosTimeZone);

            var commentTimeStamp = this.utility.UTCToKronosTimeZone(DateTime.UtcNow, mappedTeam.KronosTimeZone).ToString(CultureInfo.InvariantCulture);
            var shiftComments    = XmlHelper.GenerateEditedShiftKronosComments(editedShift.SharedShift.Notes, this.appSettings.ShiftNotesCommentText, commentTimeStamp);

            var editResponse = await this.shiftsActivity.EditShift(
                new Uri(allRequiredConfigurations.WfmEndPoint),
                allRequiredConfigurations.KronosSession,
                this.utility.FormatDateForKronos(kronosStartDateTime),
                this.utility.FormatDateForKronos(kronosEndDateTime),
                kronosEndDateTime.Day > kronosStartDateTime.Day,
                Utility.OrgJobPathKronosConversion(user.PartitionKey),
                user.RowKey,
                kronosStartDateTime.TimeOfDay.ToString(),
                kronosEndDateTime.TimeOfDay.ToString(),
                this.utility.FormatDateForKronos(shiftToReplaceStartDateTime),
                this.utility.FormatDateForKronos(shiftToReplaceEndDateTime),
                shiftToReplaceStartDateTime.TimeOfDay.ToString(),
                shiftToReplaceEndDateTime.TimeOfDay.ToString(),
                shiftComments).ConfigureAwait(false);

            if (editResponse.Status != Success)
            {
                return(ResponseHelper.CreateBadResponse(editedShift.Id, error: "Shift could not be edited in Kronos."));
            }

            await this.DeleteShiftMapping(editedShift).ConfigureAwait(false);

            await this.CreateAndStoreShiftMapping(editedShift, user, mappedTeam, monthPartitionKey).ConfigureAwait(false);

            return(ResponseHelper.CreateSuccessfulResponse(editedShift.Id));
        }
Esempio n. 9
0
        /// <summary>
        /// Adds the shift to Kronos and the database.
        /// </summary>
        /// <param name="shift">The shift to add.</param>
        /// <param name="user">The user the shift is for.</param>
        /// <param name="mappedTeam">The team the user is in.</param>
        /// <returns>A response for teams.</returns>
        public async Task <ShiftsIntegResponse> CreateShiftInKronosAsync(ShiftsShift shift, AllUserMappingEntity user, TeamToDepartmentJobMappingEntity mappedTeam)
        {
            // The connector does not support drafting entities as it is not possible to draft shifts in Kronos.
            // Likewise there is no share schedule WFI call.
            if (shift.DraftShift != null)
            {
                return(ResponseHelper.CreateBadResponse(shift.Id, error: "Creating a shift as a draft is not supported for your team in Teams. Please publish changes directly using the 'Share' button."));
            }

            if (shift.SharedShift == null)
            {
                return(ResponseHelper.CreateBadResponse(shift.Id, error: "An unexpected error occured. Could not create the shift."));
            }

            if (shift.SharedShift.Activities.Any())
            {
                return(ResponseHelper.CreateBadResponse(shift.Id, error: "Adding activities to shifts is not supported for your team in Teams. Remove all activities and try sharing again."));
            }

            if (user.ErrorIfNull(shift.Id, "User could not be found.", out var response))
            {
                return(response);
            }

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

            if ((allRequiredConfigurations?.IsAllSetUpExists).ErrorIfNull(shift.Id, "App configuration incorrect.", out response))
            {
                return(response);
            }

            var kronosStartDateTime = this.utility.UTCToKronosTimeZone(shift.SharedShift.StartDateTime, mappedTeam.KronosTimeZone);
            var kronosEndDateTime   = this.utility.UTCToKronosTimeZone(shift.SharedShift.EndDateTime, mappedTeam.KronosTimeZone);

            var commentTimeStamp = this.utility.UTCToKronosTimeZone(DateTime.UtcNow, mappedTeam.KronosTimeZone).ToString(CultureInfo.InvariantCulture);
            var comments         = XmlHelper.GenerateKronosComments(shift.SharedShift.Notes, this.appSettings.ShiftNotesCommentText, commentTimeStamp);

            var creationResponse = await this.shiftsActivity.CreateShift(
                new Uri(allRequiredConfigurations.WfmEndPoint),
                allRequiredConfigurations.KronosSession,
                this.utility.FormatDateForKronos(kronosStartDateTime),
                this.utility.FormatDateForKronos(kronosEndDateTime),
                kronosEndDateTime.Day > kronosStartDateTime.Day,
                Utility.OrgJobPathKronosConversion(user.PartitionKey),
                user.RowKey,
                kronosStartDateTime.TimeOfDay.ToString(),
                kronosEndDateTime.TimeOfDay.ToString(),
                comments).ConfigureAwait(false);

            if (creationResponse.Status != Success)
            {
                return(ResponseHelper.CreateBadResponse(shift.Id, error: "Shift was not created successfully in Kronos."));
            }

            var monthPartitionKey = Utility.GetMonthPartition(this.utility.FormatDateForKronos(kronosStartDateTime), this.utility.FormatDateForKronos(kronosEndDateTime));

            await this.CreateAndStoreShiftMapping(shift, user, mappedTeam, monthPartitionKey).ConfigureAwait(false);

            return(ResponseHelper.CreateSuccessfulResponse(shift.Id));
        }
Esempio n. 10
0
        /// <summary>
        /// Deletes the shift from Kronos and the database.
        /// </summary>
        /// <param name="shift">The shift to remove.</param>
        /// <param name="user">The user the shift is for.</param>
        /// <param name="mappedTeam">The team the user is in.</param>
        /// <returns>A response for teams.</returns>
        public async Task <ShiftsIntegResponse> DeleteShiftInKronosAsync(ShiftsShift shift, AllUserMappingEntity user, TeamToDepartmentJobMappingEntity mappedTeam)
        {
            if (shift.SharedShift == null)
            {
                return(ResponseHelper.CreateBadResponse(shift.Id, error: "An unexpected error occured. Could not delete the shift."));
            }

            if (user.ErrorIfNull(shift.Id, "User could not be found.", out var response))
            {
                return(response);
            }

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

            if ((allRequiredConfigurations?.IsAllSetUpExists == false).ErrorIfNull(shift.Id, "App configuration incorrect.", out response))
            {
                return(response);
            }

            // Convert to Kronos local time.
            var kronosStartDateTime = this.utility.UTCToKronosTimeZone(shift.SharedShift.StartDateTime, mappedTeam.KronosTimeZone);
            var kronosEndDateTime   = this.utility.UTCToKronosTimeZone(shift.SharedShift.EndDateTime, mappedTeam.KronosTimeZone);

            var deletionResponse = await this.shiftsActivity.DeleteShift(
                new Uri(allRequiredConfigurations.WfmEndPoint),
                allRequiredConfigurations.KronosSession,
                this.utility.FormatDateForKronos(kronosStartDateTime),
                this.utility.FormatDateForKronos(kronosEndDateTime),
                kronosEndDateTime.Day > kronosStartDateTime.Day,
                Utility.OrgJobPathKronosConversion(user.PartitionKey),
                user.RowKey,
                kronosStartDateTime.TimeOfDay.ToString(),
                kronosEndDateTime.TimeOfDay.ToString()).ConfigureAwait(false);

            if (deletionResponse.Status != Success)
            {
                return(ResponseHelper.CreateBadResponse(shift.Id, error: "Shift was not successfully removed from Kronos."));
            }

            await this.DeleteShiftMapping(shift).ConfigureAwait(false);

#pragma warning disable CS4014 // We do not want to await this call as we need the shift to be deleted in Teams before sharing the schedule.
            Task.Run(() => this.ShareScheduleAfterShiftDeletion(shift, mappedTeam, allRequiredConfigurations));
#pragma warning restore CS4014

            return(ResponseHelper.CreateSuccessfulResponse(shift.Id));
        }