/// <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)); } }
/// <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}."); }
/// <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); }