示例#1
0
        /// <summary>
        /// Method that will calculate the end date accordingly.
        /// </summary>
        /// <param name="requestItem">An object of type <see cref="GlobalTimeOffRequestItem"/>.</param>
        /// <returns>A type of DateTimeOffset.</returns>
        private DateTimeOffset CalculateEndDate(GlobalTimeOffRequestItem requestItem)
        {
            var correctStartDate   = this.utility.CalculateStartDateTime(requestItem);
            var provider           = CultureInfo.InvariantCulture;
            var kronosTimeZoneId   = this.appSettings.KronosTimeZone;
            var kronosTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(kronosTimeZoneId);

            var telemetryProps = new Dictionary <string, string>()
            {
                { "CorrectedStartDate", correctStartDate.ToString("o", provider) },
                { "TimeOffPeriodDuration", requestItem.TimeOffPeriods.TimeOffPeriod.Duration.ToString(CultureInfo.InvariantCulture) },
            };

            if (requestItem.TimeOffPeriods.TimeOffPeriod.Duration == Resource.DurationInFullDay)
            {
                // If the time off request is for a full-day.
                // Add 24 hours to the correct start date.
                telemetryProps.Add("TimeOffPeriodLength", "24");
                this.telemetryClient.TrackTrace(MethodBase.GetCurrentMethod().Name, telemetryProps);
                var dateTimeEnd   = DateTime.ParseExact(requestItem.TimeOffPeriods.TimeOffPeriod.EndDate, "M/dd/yyyy", CultureInfo.InvariantCulture);
                var dateTimeStart = DateTime.ParseExact(requestItem.TimeOffPeriods.TimeOffPeriod.StartDate, "M/dd/yyyy", CultureInfo.InvariantCulture);
                if (dateTimeEnd.Equals(dateTimeStart))
                {
                    return(correctStartDate.AddHours(24));
                }
                else
                {
                    return(TimeZoneInfo.ConvertTimeToUtc(dateTimeEnd, kronosTimeZoneInfo).AddHours(24));
                }
            }
            else if (requestItem.TimeOffPeriods.TimeOffPeriod.Duration == Resource.DurationInHour)
            {
                // If the time off has a number of hours attached to it.
                // Take the necessary start date and start time, and add the hours to the time off.
                var timeSpan = TimeSpan.Parse(requestItem.TimeOffPeriods.TimeOffPeriod.Length, CultureInfo.InvariantCulture);
                telemetryProps.Add("TimeOffPeriodLength", timeSpan.Hours.ToString(CultureInfo.InvariantCulture));
                this.telemetryClient.TrackTrace(MethodBase.GetCurrentMethod().Name, telemetryProps);

                return(correctStartDate.AddHours(timeSpan.Hours));
            }
            else
            {
                // If the time off is either a first-half day, second-half day, or half-day.
                // Add 12 hours to the correct start date.
                return(correctStartDate.AddHours(12));
            }
        }
示例#2
0
        /// <summary>
        /// Method to decline the time off request.
        /// </summary>
        /// <param name="globalTimeOffRequestItem">The time off request item.</param>
        /// <param name="user">The user.</param>
        /// <param name="timeOffId">The time off Id from Kronos.</param>
        /// <param name="accessToken">The MS Graph Access token.</param>
        /// <param name="monthPartitionKey">The month wise partition key.</param>
        /// <returns>A unit of execution.</returns>
        private async Task DeclineTimeOffRequestAsync(
            GlobalTimeOffRequestItem globalTimeOffRequestItem,
            UserDetailsModel user,
            string timeOffId,
            string accessToken,
            string monthPartitionKey)
        {
            this.telemetryClient.TrackTrace($"DeclineTimeOffRequestAsync started for time off id {timeOffId}.");
            var httpClient = this.httpClientFactory.CreateClient("ShiftsAPI");

            httpClient.DefaultRequestHeaders.Authorization =
                new AuthenticationHeaderValue("Bearer", accessToken);
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "teams/" + user.ShiftTeamId + "/schedule/timeOffRequests/" + timeOffId + "/decline"))
            {
                var response = await httpClient.SendAsync(httpRequestMessage).ConfigureAwait(false);

                if (response.IsSuccessStatusCode)
                {
                    var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                    TimeOffMappingEntity timeOffMappingEntity = new TimeOffMappingEntity
                    {
                        Duration           = globalTimeOffRequestItem.TimeOffPeriods.TimeOffPeriod.Duration,
                        EndDate            = globalTimeOffRequestItem.TimeOffPeriods.TimeOffPeriod.EndDate,
                        StartDate          = globalTimeOffRequestItem.TimeOffPeriods.TimeOffPeriod.StartDate,
                        StartTime          = globalTimeOffRequestItem.TimeOffPeriods.TimeOffPeriod.StartTime,
                        PayCodeName        = globalTimeOffRequestItem.TimeOffPeriods.TimeOffPeriod.PayCodeName,
                        KronosPersonNumber = globalTimeOffRequestItem.Employee.PersonIdentity.PersonNumber,
                        PartitionKey       = monthPartitionKey,
                        RowKey             = globalTimeOffRequestItem.Id,
                        ShiftsRequestId    = timeOffId,
                        IsActive           = true,
                        KronosRequestId    = globalTimeOffRequestItem.Id,
                        StatusName         = globalTimeOffRequestItem.StatusName,
                    };

                    this.AddorUpdateTimeOffMappingAsync(timeOffMappingEntity);
                }
            }

            this.telemetryClient.TrackTrace($"DeclineTimeOffRequestAsync ended for time off id {timeOffId}.");
        }
        /// <summary>
        /// Method to decline the time off request.
        /// </summary>
        /// <param name="globalTimeOffRequestItem">The time off request item.</param>
        /// <param name="user">The user.</param>
        /// <param name="timeOffId">The time off Id from Kronos.</param>
        /// <param name="configurationDetails">The configuration details.</param>
        /// <param name="monthPartitionKey">The month wise partition key.</param>
        /// <returns>A unit of execution.</returns>
        private async Task DeclineTimeOffRequestAsync(
            GlobalTimeOffRequestItem globalTimeOffRequestItem,
            UserDetailsModel user,
            string timeOffId,
            SetupDetails configurationDetails,
            string monthPartitionKey)
        {
            this.telemetryClient.TrackTrace($"DeclineTimeOffRequestAsync started for time off id {timeOffId}.");

            var httpClient = this.httpClientFactory.CreateClient("ShiftsAPI");

            // Send Passthrough header to indicate the sender of request in outbound call.
            httpClient.DefaultRequestHeaders.Add("X-MS-WFMPassthrough", configurationDetails.WFIId);

            var requestUrl = $"teams/" + user.ShiftTeamId + "/schedule/timeOffRequests/" + timeOffId + "/decline";

            var response = await this.graphUtility.SendHttpRequest(configurationDetails.GraphConfigurationDetails, httpClient, HttpMethod.Post, requestUrl).ConfigureAwait(false);

            if (response.IsSuccessStatusCode)
            {
                TimeOffMappingEntity timeOffMappingEntity = new TimeOffMappingEntity
                {
                    Duration           = globalTimeOffRequestItem.TimeOffPeriods.TimeOffPeriod.Duration,
                    EndDate            = globalTimeOffRequestItem.TimeOffPeriods.TimeOffPeriod.EndDate,
                    StartDate          = globalTimeOffRequestItem.TimeOffPeriods.TimeOffPeriod.StartDate,
                    StartTime          = globalTimeOffRequestItem.TimeOffPeriods.TimeOffPeriod.StartTime,
                    PayCodeName        = globalTimeOffRequestItem.TimeOffPeriods.TimeOffPeriod.PayCodeName,
                    KronosPersonNumber = globalTimeOffRequestItem.Employee.PersonIdentity.PersonNumber,
                    PartitionKey       = monthPartitionKey,
                    RowKey             = globalTimeOffRequestItem.Id,
                    ShiftsRequestId    = timeOffId,
                    IsActive           = true,
                    KronosRequestId    = globalTimeOffRequestItem.Id,
                    ShiftsStatus       = globalTimeOffRequestItem.StatusName,
                    KronosStatus       = ApiConstants.Refused,
                };

                this.AddorUpdateTimeOffMappingAsync(timeOffMappingEntity);
            }

            this.telemetryClient.TrackTrace($"DeclineTimeOffRequestAsync ended for time off id {timeOffId}.");
        }
示例#4
0
        /// <summary>
        /// Method to properly calculate the StartDateTime in the context of the time off.
        /// </summary>
        /// <param name="requestItem">An item that is type of <see cref="GlobalTimeOffRequestItem"/> that contains the start and end dates.</param>
        /// <returns>The type <see cref="DateTimeOffset"/> representing the right start time.</returns>
        public DateTime CalculateStartDateTime(GlobalTimeOffRequestItem requestItem)
        {
            if (requestItem is null)
            {
                throw new ArgumentNullException(nameof(requestItem));
            }

            // Step 1: Take the raw Kronos date time, and convert it to the Kronos date time zone.
            // Step 2: Convert the Kronos date time to UTC.
            // Step 3: Convert the UTC time to Shifts Time Zone.
            var kronosTimeZoneId   = this.appSettings.KronosTimeZone;
            var kronosTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(kronosTimeZoneId);
            var incomingKronosDate = requestItem.TimeOffPeriods.TimeOffPeriod.StartDate;

            string   startTimeString;
            DateTime dateTimeStr, utcTime;

            if (requestItem.TimeOffPeriods.TimeOffPeriod.Duration == Resource.DurationInHour)
            {
                // If the duration of the time-off is set for a number of hours.
                startTimeString = requestItem.TimeOffPeriods.TimeOffPeriod.StartTime.ToString(CultureInfo.InvariantCulture);
                dateTimeStr     = DateTime.Parse($"{incomingKronosDate} {startTimeString}", CultureInfo.InvariantCulture);
                utcTime         = TimeZoneInfo.ConvertTimeToUtc(dateTimeStr, kronosTimeZoneInfo);
            }
            else if (requestItem.TimeOffPeriods.TimeOffPeriod.Duration == Resource.DurationInHalfDay)
            {
                dateTimeStr = DateTime.ParseExact($"{incomingKronosDate} 12:00 PM", "M/d/yyyy h:mm tt", CultureInfo.InvariantCulture);
                utcTime     = TimeZoneInfo.ConvertTimeToUtc(dateTimeStr, kronosTimeZoneInfo);
            }
            else
            {
                dateTimeStr = DateTime.ParseExact(incomingKronosDate, "M/dd/yyyy", CultureInfo.InvariantCulture);
                utcTime     = TimeZoneInfo.ConvertTimeToUtc(dateTimeStr, kronosTimeZoneInfo);
            }

            return(utcTime);
        }
        /// <summary>
        /// create approval confirmation card.
        /// </summary>
        /// <param name="context">Dialog context.</param>
        /// <param name="status">Request status.</param>
        /// <param name="reviewer">Reviewer name.</param>
        /// <param name="note">Reviewer note.</param>
        /// <param name="details">Request details from API.</param>
        /// <returns>Employee notification card.</returns>
        public AdaptiveCard GetApprovalConfirmationCard(IDialogContext context, string status, string reviewer, string note, GlobalTimeOffRequestItem details)
        {
            var    activity    = context.Activity as Activity;
            JToken token       = JObject.Parse(activity.Value.ToString());
            var    repoMessage = context.MakeMessage();

            string fullPath = HttpContext.Current.Server.MapPath("/Cards/AdaptiveCards/TimeOff/ApprovalConfirmationCard.json");

            string personNumber = (string)token.SelectToken("PersonNumber");
            string employee     = (string)token.SelectToken("Employee");
            string date         = (string)token.SelectToken("Date");
            string payCode      = (string)token.SelectToken("PayCode");
            string timePeriod   = (string)token.SelectToken("TimePeriod");
            string requestId    = (string)token.SelectToken("RequestId");
            var    adaptiveCard = File.ReadAllText(fullPath);

            JObject tenant   = context.Activity.ChannelData as JObject;
            string  tenantId = tenant["tenant"].SelectToken("id").ToString();

            adaptiveCard = adaptiveCard.Replace("{Title}", KronosResourceText.TimeOffRequstText).Replace("{Info}", KronosResourceText.SupervisorTimeOffPostApprovalInfoText).Replace("{Status_txt}", KronosResourceText.Status);
            adaptiveCard = adaptiveCard.Replace("{Employee_txt}", KronosResourceText.Employee).Replace("{Paycode_txt}", KronosResourceText.PayCode).Replace("{Status_txt}", KronosResourceText.Status).Replace("{Date_txt}", KronosResourceText.Date);
            adaptiveCard = adaptiveCard.Replace("{Status}", status).Replace("{Color}", status.ToLower() == Constants.Approved.ToLower() ? Constants.Green : Constants.Red);
            adaptiveCard = adaptiveCard.Replace("{Note_txt}", KronosResourceText.Note).Replace("{Date}", date).Replace("{Employee}", employee).Replace("{PayCode}", payCode).Replace("{PayCode_Info}", payCode.ToLowerInvariant()).Replace("{TimePeriod}", timePeriod);
            adaptiveCard = adaptiveCard.Replace("{Note}", string.IsNullOrEmpty(note) ? KronosResourceText.NoComment : note).Replace("{ShowHistory}", KronosResourceText.ShowHistory);

            var           historyItem = File.ReadAllText(HttpContext.Current.Server.MapPath("/Cards/AdaptiveCards/TimeOff/HistoryItem.json"));
            var           first       = true;
            StringBuilder sb          = new StringBuilder();

            foreach (var item in details?.RequestStatusChanges?.RequestStatusChange)
            {
                sb.Append("," + historyItem.Replace("{Seperator}", first == true ? "False" : "True").Replace("{Status}", item.ToStatusName).Replace("{Person}", item.User.PersonIdentity.PersonNumber).Replace("{Datetime}", item.ChangeDateTime));
                first = false;
            }

            adaptiveCard = adaptiveCard.Replace("{rows}", details?.RequestStatusChanges.RequestStatusChange.Count == 0 ? null : sb.ToString());
            var card = AdaptiveCard.FromJson(adaptiveCard).Card;

            return(card);
        }
        /// <summary>
        /// Create supervisor approval notification card.
        /// </summary>
        /// <param name="context">Dialog context.</param>
        /// <param name="reqId">Created request Id.</param>
        /// <param name="personNumber">Person number of request creator.</param>
        /// <param name="paycode">Paycode for request.</param>
        /// <param name="timePeriod">Time period for request.</param>
        /// <param name="details">Request details from API.</param>
        /// <param name="note">Comment by requestor while creating request.</param>
        /// <param name="requestor">Request creator name.</param>
        /// <param name="comments">List of comments to which note will be attached.</param>
        /// <param name="advancedTimeOff">Advanced time off request object.</param>
        /// <returns>Supervisor notification card.</returns>
        public AdaptiveCard GetSupervisorNotificationCard(IDialogContext context, string reqId, string personNumber, string paycode, string timePeriod, GlobalTimeOffRequestItem details, string note, string requestor, Models.ResponseEntities.CommentList.Response comments, AdvancedTimeOff advancedTimeOff = null)
        {
            var    repoMessage  = context.MakeMessage();
            var    adaptiveCard = File.ReadAllText(HttpContext.Current.Server.MapPath("/Cards/AdaptiveCards/TimeOff/SupervisorNotificationCard.json"));
            var    activity     = context.Activity as Activity;
            JToken token        = JObject.Parse(activity.Value.ToString());

            DateTime sdt, edt;

            if (advancedTimeOff == null)
            {
                DateTime.TryParse((string)token.SelectToken("sdt"), CultureInfo.InvariantCulture, DateTimeStyles.None, out sdt);
                DateTime.TryParse((string)token.SelectToken("edt"), CultureInfo.InvariantCulture, DateTimeStyles.None, out edt);
            }
            else
            {
                DateTime.TryParse(advancedTimeOff.sdt, CultureInfo.InvariantCulture, DateTimeStyles.None, out sdt);
                DateTime.TryParse(advancedTimeOff.edt, CultureInfo.InvariantCulture, DateTimeStyles.None, out edt);
            }

            edt = edt.AddHours(23);
            edt = edt.AddMinutes(59);
            var days = (int)Math.Round(edt.Subtract(sdt).TotalDays, MidpointRounding.AwayFromZero);

            adaptiveCard = adaptiveCard.Replace("{Title}", KronosResourceText.TimeOffRequstText).Replace("{Status_txt}", KronosResourceText.Status).Replace("{Employee_txt}", KronosResourceText.Employee);
            adaptiveCard = adaptiveCard.Replace("{Paycode_txt}", KronosResourceText.PayCode).Replace("{Date_txt}", KronosResourceText.Date).Replace("{TimePeriod_txt}", KronosResourceText.TimePeriod);
            adaptiveCard = adaptiveCard.Replace("{Note_txt}", KronosResourceText.Note).Replace("{SelectComment}", KronosResourceText.SelectComment).Replace("{EnterNote}", KronosResourceText.EnterNote);
            adaptiveCard = adaptiveCard.Replace("{Submit}", KronosResourceText.Submit).Replace("{Refuse}", KronosResourceText.Refuse);
            adaptiveCard = adaptiveCard.Replace("{Days}", days.ToString() + (days > 1 ? " Days" : " Day"));
            adaptiveCard = adaptiveCard.Replace("{StartDate}", sdt.ToString("MMM d, yyyy", CultureInfo.InvariantCulture));
            adaptiveCard = adaptiveCard.Replace("{Approve}", KronosResourceText.Approve).Replace("{Submit}", KronosResourceText.Submit).Replace("{Refuse}", KronosResourceText.Refuse).Replace("{ShowHistory}", KronosResourceText.ShowHistory);
            if (timePeriod.ToLowerInvariant() == Constants.FullDay.ToLowerInvariant() && days == 0)
            {
                adaptiveCard = adaptiveCard.Replace("- {EndDate}", string.Empty);
            }
            else
            {
                adaptiveCard = adaptiveCard.Replace("{EndDate}", edt.ToString("MMM d, yyyy", CultureInfo.InvariantCulture));
            }

            adaptiveCard = adaptiveCard.Replace("{RequestId}", reqId).Replace("{PersonNumber}", personNumber).Replace("{Status}", KronosResourceText.Submitted);
            adaptiveCard = adaptiveCard.Replace("{Color}", Constants.Default).Replace("{Employee}", requestor).Replace("{PayCode}", paycode);
            adaptiveCard = adaptiveCard.Replace("{TimePeriod}", timePeriod).Replace("{QueryDateSpan}", sdt.ToString("M/d/yyyy", CultureInfo.InvariantCulture) + "-" + edt.ToString("M/d/yyyy", CultureInfo.InvariantCulture));
            adaptiveCard = adaptiveCard.Replace("{Note}", note ?? KronosResourceText.NoComment);

            var           historyItem = File.ReadAllText(HttpContext.Current.Server.MapPath("/Cards/AdaptiveCards/TimeOff/HistoryItem.json"));
            var           first       = true;
            StringBuilder sb          = new StringBuilder();

            foreach (var item in details?.RequestStatusChanges?.RequestStatusChange)
            {
                sb.Append("," + historyItem.Replace("{Seperator}", first == true ? "False" : "True").Replace("{Status}", item.ToStatusName).Replace("{Person}", item.User.PersonIdentity.PersonNumber).Replace("{Datetime}", item.ChangeDateTime));
                first = false;
            }

            adaptiveCard = adaptiveCard.Replace("{rows}", details?.RequestStatusChanges.RequestStatusChange.Count == 0 ? null : sb.ToString());

            var row = "{\"title\": \"{Text}\",\"value\": \"{Value}\"}";

            sb = new StringBuilder();
            for (int i = 0; i < comments.Comments.Count; i++)
            {
                if (i == 0)
                {
                    sb.Append(row.Replace("{Text}", comments.Comments[i].CommentText).Replace("{Value}", comments.Comments[i].CommentText));
                    adaptiveCard.Replace("{CommentValue}", comments.Comments[i].CommentText);
                }
                else
                {
                    sb.Append(", " + row.Replace("{Text}", comments.Comments[i].CommentText).Replace("{Value}", comments.Comments[i].CommentText));
                }
            }

            adaptiveCard = adaptiveCard.Replace("{CommentRows}", sb.ToString());
            var card = AdaptiveCard.FromJson(adaptiveCard).Card;

            return(card);
        }
        /// <summary>
        /// create employee notification card.
        /// </summary>
        /// <param name="context">dialog context.</param>
        /// <param name="status">request status.</param>
        /// <param name="reviewer">reviewer name.</param>
        /// <param name="note">note while approval.</param>
        /// <param name="details">time off request details.</param>
        /// <returns>employee notification card.</returns>
        public AdaptiveCard GetEmployeeNotificationCard(IDialogContext context, string status, string reviewer, string note, GlobalTimeOffRequestItem details)
        {
            var    activity     = context.Activity as Activity;
            JToken token        = JObject.Parse(activity.Value.ToString());
            var    repoMessage  = context.MakeMessage();
            string employee     = (string)token.SelectToken("EmpName");
            string personNumber = (string)token.SelectToken("PersonNumber");
            string requestId    = (string)token.SelectToken("RequestId");
            string fullPath     = HttpContext.Current.Server.MapPath("/Cards/AdaptiveCards/TimeOff/EmployeeNotificationCard.json");

            DateTime.TryParse(details.TimeOffPeriods.TimeOffPeriod.StartDate, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime sdt);
            DateTime.TryParse(details.TimeOffPeriods.TimeOffPeriod.EndDate, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime edt);
            edt = edt.AddHours(23);
            edt = edt.AddMinutes(59);
            var timePeriod = details.TimeOffPeriods.TimeOffPeriod.Duration.ToLowerInvariant() == Constants.full_day.ToLowerInvariant() ? Constants.FullDay : details.TimeOffPeriods.TimeOffPeriod.Duration.ToLowerInvariant() == Constants.half_day.ToLowerInvariant() ? Constants.HalfDay : details.TimeOffPeriods.TimeOffPeriod.Duration.ToLowerInvariant() == Constants.first_half_day.ToLowerInvariant() ? Constants.FirstHalfDay : Constants.Hours;
            var days       = (int)Math.Round(edt.Subtract(sdt).TotalDays, MidpointRounding.AwayFromZero);
            var date       = "{StartDate} - {EndDate} ({Days})";

            date = date.Replace("{Days}", days.ToString() + (days > 1 ? " " + KronosResourceText.Days : " " + KronosResourceText.Day));
            date = date.Replace("{StartDate}", sdt.ToString("MMM d, yyyy", CultureInfo.InvariantCulture));
            if (timePeriod.ToLowerInvariant() == Constants.FullDay.ToLowerInvariant() && days == 0)
            {
                date = date.Replace("- {EndDate}", string.Empty);
            }
            else
            {
                date = date.Replace("{EndDate}", edt.ToString("MMM d,yyyy", CultureInfo.InvariantCulture));
            }

            if (timePeriod.ToLowerInvariant() == Constants.Hours)
            {
                var start = "08-15-2019 " + details.TimeOffPeriods.TimeOffPeriod.StartTime.Substring(0, 4) + " " + details.TimeOffPeriods.TimeOffPeriod.StartTime.Substring(4, 2);
                DateTime.TryParse(start, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime startDate);
                var lenHr   = Convert.ToDouble(details.TimeOffPeriods.TimeOffPeriod.Length.Split(':')[0]);
                var lenMin  = Convert.ToDouble(details.TimeOffPeriods.TimeOffPeriod.Length.Split(':')[1]);
                var endDate = startDate.AddHours(lenHr).AddMinutes(lenMin);

                timePeriod += $" ({startDate.ToString("h:mm tt", CultureInfo.InvariantCulture)} - {endDate.ToString("h:mm tt", CultureInfo.InvariantCulture)})";
            }

            JObject tenant       = context.Activity.ChannelData as JObject;
            string  tenantId     = tenant["tenant"].SelectToken("id").ToString();
            var     adaptiveCard = File.ReadAllText(fullPath);

            adaptiveCard = adaptiveCard.Replace("{RequestId}", requestId);
            adaptiveCard = adaptiveCard.Replace("{PersonNumber}", personNumber);
            adaptiveCard = adaptiveCard.Replace("{Reviewer}", reviewer);
            adaptiveCard = adaptiveCard.Replace("{Status}", status.ToLowerInvariant() == Constants.Approved.ToLowerInvariant() ? Resources.KronosResourceText.Approved : Resources.KronosResourceText.Refused);
            adaptiveCard = adaptiveCard.Replace("{Color}", status.ToLower() == Constants.Approved.ToLower() ? Constants.Green : Constants.Red);
            adaptiveCard = adaptiveCard.Replace("{Date}", date);
            adaptiveCard = adaptiveCard.Replace("{Employee}", employee);
            adaptiveCard = adaptiveCard.Replace("{PayCode}", details.TimeOffPeriods.TimeOffPeriod.PayCodeName);
            adaptiveCard = adaptiveCard.Replace("{TimePeriod}", timePeriod);
            adaptiveCard = adaptiveCard.Replace("{Comment}", string.IsNullOrEmpty(note) ? Resources.KronosResourceText.NoComment : note);

            var           historyItem = File.ReadAllText(HttpContext.Current.Server.MapPath("/Cards/AdaptiveCards/TimeOff/HistoryItem.json"));
            var           first       = true;
            StringBuilder sb          = new StringBuilder();

            foreach (var item in details?.RequestStatusChanges?.RequestStatusChange)
            {
                if (first == true)
                {
                    var r = historyItem.Replace("{Seperator}", "False").Replace("{Status}", item.ToStatusName).Replace("{Person}", item.User.PersonIdentity.PersonNumber).Replace("{Datetime}", item.ChangeDateTime);
                    sb.Append("," + r);
                }
                else
                {
                    var r = historyItem.Replace("{Seperator}", "True").Replace("{Status}", item.ToStatusName).Replace("{Person}", item.User.PersonIdentity.PersonNumber).Replace("{Datetime}", item.ChangeDateTime);
                    sb.Append("," + r);
                }

                first = false;
            }

            if (details?.RequestStatusChanges.RequestStatusChange.Count == 0)
            {
                adaptiveCard = adaptiveCard.Replace("{rows}", null);
            }
            else
            {
                adaptiveCard = adaptiveCard.Replace("{rows}", sb.ToString());
            }

            var card = AdaptiveCard.FromJson(adaptiveCard).Card;

            return(card);
        }