예제 #1
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>
        /// Creates a shift mapping entity to be stored in the table.
        /// </summary>
        /// <param name="shift">The shift received from Shifts.</param>
        /// <param name="uniqueId">The unique ID for the shift.</param>
        /// <param name="kronoUserId">The user id of the user in Kronos.</param>
        /// <returns>Returns a <see cref="TeamsShiftMappingEntity"/>.</returns>
        public TeamsShiftMappingEntity CreateNewShiftMappingEntity(
            Microsoft.Teams.Shifts.Integration.API.Models.IntegrationAPI.Shift shift,
            string uniqueId,
            string kronoUserId)
        {
            var createNewShiftMappingEntityProps = new Dictionary <string, string>()
            {
                { "GraphShiftId", shift?.Id },
                { "KronosUniqueId", uniqueId },
                { "CallingAssembly", Assembly.GetCallingAssembly().GetName().Name },
            };

            var startDateTime = DateTime.SpecifyKind(shift.SharedShift.StartDateTime, DateTimeKind.Utc);
            var endDateTime   = DateTime.SpecifyKind(shift.SharedShift.EndDateTime, DateTimeKind.Utc);

            TeamsShiftMappingEntity shiftMappingEntity = new TeamsShiftMappingEntity
            {
                AadUserId          = shift.UserId,
                KronosUniqueId     = uniqueId,
                KronosPersonNumber = kronoUserId,
                ShiftStartDate     = startDateTime,
                ShiftEndDate       = endDateTime,
            };

            this.telemetryClient.TrackTrace("Creating new shift mapping entity.", createNewShiftMappingEntityProps);

            return(shiftMappingEntity);
        }
예제 #3
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));
        }
예제 #4
0
        /// <summary>
        /// This method will cause the thread to wait allowing us to retrun a success response
        /// for the delete WFI request. It will then share the changes.
        /// </summary>
        /// <param name="shift">The shift we want to share.</param>
        /// <param name="mappedTeam">The team details of the schedule we want to share.</param>
        /// <param name="allRequiredConfigurations">The required configuration.</param>
        /// <returns>A unit of execution.</returns>
        private async Task ShareScheduleAfterShiftDeletion(ShiftsShift shift, TeamToDepartmentJobMappingEntity mappedTeam, IntegrationApi.SetupDetails allRequiredConfigurations)
        {
            // We want to wait so that there is time to respond a success to the WFI request
            // meaning the shift will be deleted in Teams.
            Thread.Sleep(int.Parse(appSettings.AutoShareScheduleWaitTime));

            // We now want to share the schedule between the start and end time of the deleted shift.
            await this.graphUtility.ShareSchedule(
                allRequiredConfigurations.GraphConfigurationDetails,
                mappedTeam.TeamId,
                shift.SharedShift.StartDateTime,
                shift.SharedShift.EndDateTime,
                false).ConfigureAwait(false);
        }
예제 #5
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));
        }
예제 #6
0
        /// <summary>
        /// Removes a shift mapping entity.
        /// </summary>
        /// <param name="shift">A shift from Shifts.</param>
        /// <returns>A task.</returns>
        private async Task DeleteShiftMapping(ShiftsShift shift)
        {
            var shiftMappingEntity = await this.shiftMappingEntityProvider.GetShiftMappingEntityByRowKeyAsync(shift.Id).ConfigureAwait(false);

            await this.shiftMappingEntityProvider.DeleteOrphanDataFromShiftMappingAsync(shiftMappingEntity).ConfigureAwait(false);
        }
예제 #7
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));
        }