Add simplified ticket completion flow
This commit is contained in:
@@ -90,6 +90,29 @@ namespace C4IT.FASD.Cockpit.Communication
|
|||||||
public abstract Task<bool> UpdateHealthcardTableData(cF4SDWriteParameters dataParameter);
|
public abstract Task<bool> UpdateHealthcardTableData(cF4SDWriteParameters dataParameter);
|
||||||
public abstract Task<bool> Matrix42TicketFinalization(cApiM42Ticket ticketData);
|
public abstract Task<bool> Matrix42TicketFinalization(cApiM42Ticket ticketData);
|
||||||
|
|
||||||
|
public virtual async Task<cTicketFinalizationResult> FinalizeTicketAsync(cApiM42Ticket ticketData)
|
||||||
|
{
|
||||||
|
var success = await Matrix42TicketFinalization(ticketData);
|
||||||
|
var ticketId = ticketData?.Ticket;
|
||||||
|
if (ticketId == Guid.Empty)
|
||||||
|
ticketId = null;
|
||||||
|
|
||||||
|
return new cTicketFinalizationResult
|
||||||
|
{
|
||||||
|
Success = success,
|
||||||
|
TicketId = ticketId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Task<cTicketExternalLinkResult> GetTicketExternalLinkAsync(Guid ticketId, enumTicketExternalOpenMode mode)
|
||||||
|
{
|
||||||
|
return Task.FromResult(new cTicketExternalLinkResult
|
||||||
|
{
|
||||||
|
Success = false,
|
||||||
|
Mode = enumTicketExternalOpenMode.None
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public abstract Task<List<List<object>>> GetQuickActionHistory(string QuickActionName, int OrgId, int DeviceId, int? UserId);
|
public abstract Task<List<List<object>>> GetQuickActionHistory(string QuickActionName, int OrgId, int DeviceId, int? UserId);
|
||||||
|
|
||||||
public abstract Task<bool> GetAgentApiAccessInfo();
|
public abstract Task<bool> GetAgentApiAccessInfo();
|
||||||
|
|||||||
@@ -1515,6 +1515,12 @@ namespace C4IT.FASD.Cockpit.Communication
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
public override async Task<bool> Matrix42TicketFinalization(cApiM42Ticket ticketData)
|
public override async Task<bool> Matrix42TicketFinalization(cApiM42Ticket ticketData)
|
||||||
|
{
|
||||||
|
var result = await FinalizeTicketAsync(ticketData);
|
||||||
|
return result?.Success == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<cTicketFinalizationResult> FinalizeTicketAsync(cApiM42Ticket ticketData)
|
||||||
{
|
{
|
||||||
var CM = MethodBase.GetCurrentMethod();
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
LogMethodBegin(CM);
|
LogMethodBegin(CM);
|
||||||
@@ -1522,7 +1528,6 @@ namespace C4IT.FASD.Cockpit.Communication
|
|||||||
var apiError = 0;
|
var apiError = 0;
|
||||||
var timeStart = DateTime.UtcNow;
|
var timeStart = DateTime.UtcNow;
|
||||||
|
|
||||||
bool output = false;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var http = GetHttpHelper(true);
|
var http = GetHttpHelper(true);
|
||||||
@@ -1532,7 +1537,7 @@ namespace C4IT.FASD.Cockpit.Communication
|
|||||||
var result = await http.PostJsonAsync(url, payload, 20000, CancellationToken.None);
|
var result = await http.PostJsonAsync(url, payload, 20000, CancellationToken.None);
|
||||||
|
|
||||||
if (result.IsOk)
|
if (result.IsOk)
|
||||||
return true;
|
return ParseTicketFinalizationResult(result.Result, ticketData?.Ticket);
|
||||||
else
|
else
|
||||||
apiError = (int)result.Status;
|
apiError = (int)result.Status;
|
||||||
}
|
}
|
||||||
@@ -1547,7 +1552,102 @@ namespace C4IT.FASD.Cockpit.Communication
|
|||||||
LogMethodEnd(CM);
|
LogMethodEnd(CM);
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return new cTicketFinalizationResult { Success = false };
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static cTicketFinalizationResult ParseTicketFinalizationResult(string response, Guid? fallbackTicketId)
|
||||||
|
{
|
||||||
|
if (fallbackTicketId == Guid.Empty)
|
||||||
|
fallbackTicketId = null;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(response))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var token = JToken.Parse(response);
|
||||||
|
if (token.Type == JTokenType.Object)
|
||||||
|
{
|
||||||
|
var result = token.ToObject<cTicketFinalizationResult>();
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
if (result.Success && (!result.TicketId.HasValue || result.TicketId.Value == Guid.Empty))
|
||||||
|
result.TicketId = fallbackTicketId;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (token.Type == JTokenType.String &&
|
||||||
|
Guid.TryParse(token.Value<string>(), out var createdTicketId))
|
||||||
|
{
|
||||||
|
return new cTicketFinalizationResult
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
TicketId = createdTicketId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (JsonException)
|
||||||
|
{
|
||||||
|
if (Guid.TryParse(response.Trim().Trim('"'), out var createdTicketId))
|
||||||
|
{
|
||||||
|
return new cTicketFinalizationResult
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
TicketId = createdTicketId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Older providers returned an empty JSON value for successful updates.
|
||||||
|
return new cTicketFinalizationResult
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
TicketId = fallbackTicketId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<cTicketExternalLinkResult> GetTicketExternalLinkAsync(Guid ticketId, enumTicketExternalOpenMode mode)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
|
||||||
|
var apiError = 0;
|
||||||
|
var timeStart = DateTime.UtcNow;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (ticketId == Guid.Empty || mode == enumTicketExternalOpenMode.None)
|
||||||
|
return new cTicketExternalLinkResult { Success = false, Mode = enumTicketExternalOpenMode.None };
|
||||||
|
|
||||||
|
var http = GetHttpHelper(true);
|
||||||
|
var url = $"api/Ticketing/GetExternalLink?ticketId={ticketId:D}&mode={Uri.EscapeDataString(mode.ToString())}";
|
||||||
|
var result = await http.GetHttpJson(url, 20000, CancellationToken.None);
|
||||||
|
|
||||||
|
if (result.IsOk)
|
||||||
|
{
|
||||||
|
return JsonConvert.DeserializeObject<cTicketExternalLinkResult>(result.Result)
|
||||||
|
?? new cTicketExternalLinkResult { Success = false, Mode = enumTicketExternalOpenMode.None };
|
||||||
|
}
|
||||||
|
|
||||||
|
apiError = (int)result.Status;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
apiError = E.HResult;
|
||||||
|
LogException(E);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (Debug_apiTiming) SaveApiTimingEntry("Ticketing-GetExternalLink", timeStart, apiError);
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new cTicketExternalLinkResult
|
||||||
|
{
|
||||||
|
Success = false,
|
||||||
|
Mode = enumTicketExternalOpenMode.None
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<bool> GetAgentApiAccessInfo()
|
public override async Task<bool> GetAgentApiAccessInfo()
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
<TicketConfiguration>
|
<TicketConfiguration>
|
||||||
<DisableAutomaticTimeTracking Policy="Mandatory" Value="true" />
|
<DisableAutomaticTimeTracking Policy="Mandatory" Value="true" />
|
||||||
<CompletitionPolicy Policy="Mandatory" Value="IfRequired" />
|
<CompletitionPolicy Policy="Mandatory" Value="IfRequired" />
|
||||||
|
<UseSimplifiedCaseCompletionDialog Policy="Hidden" Value="false" />
|
||||||
|
<SimplifiedCaseCompletionTicketOpenMode Policy="Hidden" Value="Preview" />
|
||||||
<NotesMandatory Policy="Mandatory" Value="true" />
|
<NotesMandatory Policy="Mandatory" Value="true" />
|
||||||
<ShowOverview Policy="Mandatory" Value="true" />
|
<ShowOverview Policy="Mandatory" Value="true" />
|
||||||
<OpenActivitiesExternally Policy="Mandatory" Value="false">
|
<OpenActivitiesExternally Policy="Mandatory" Value="false">
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using C4IT.FASD.Base;
|
using C4IT.FASD.Base;
|
||||||
|
using C4IT.FASD.Cockpit.Communication;
|
||||||
using C4IT.Logging;
|
using C4IT.Logging;
|
||||||
|
|
||||||
using FasdDesktopUi.Basics;
|
using FasdDesktopUi.Basics;
|
||||||
@@ -15,6 +17,33 @@ namespace FasdDesktopUi.Basics.Helper
|
|||||||
{
|
{
|
||||||
private const string DefaultTicketActivityType = "SPSActivityTypeTicket";
|
private const string DefaultTicketActivityType = "SPSActivityTypeTicket";
|
||||||
|
|
||||||
|
internal static async Task<bool> TryOpenFinalizedTicketExternallyAsync(Guid ticketId, enumTicketExternalOpenMode mode)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (ticketId == Guid.Empty || mode == enumTicketExternalOpenMode.None)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var linkResult = await cFasdCockpitCommunicationBase.Instance.GetTicketExternalLinkAsync(ticketId, mode);
|
||||||
|
if (linkResult?.Success != true ||
|
||||||
|
!Uri.TryCreate(linkResult.Url, UriKind.Absolute, out var ticketUri) ||
|
||||||
|
(ticketUri.Scheme != Uri.UriSchemeHttp && ticketUri.Scheme != Uri.UriSchemeHttps))
|
||||||
|
{
|
||||||
|
LogEntry($"Could not resolve an external link for ticket '{ticketId:D}'.", LogLevels.Warning);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
new cBrowsers().Start("default", ticketUri.AbsoluteUri);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
internal static bool TryOpenTicketRelationExternally(cF4sdApiSearchResultRelation relation, bool forceExternal = false)
|
internal static bool TryOpenTicketRelationExternally(cF4sdApiSearchResultRelation relation, bool forceExternal = false)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -104,6 +104,13 @@ namespace FasdDesktopUi.Basics.UserControls
|
|||||||
public bool AreCaseNotesMandatory =>
|
public bool AreCaseNotesMandatory =>
|
||||||
cFasdCockpitConfig.Instance?.Global?.TicketConfiguration?.NotesMandatory ?? false;
|
cFasdCockpitConfig.Instance?.Global?.TicketConfiguration?.NotesMandatory ?? false;
|
||||||
|
|
||||||
|
private bool UseSimplifiedCaseCompletionDialog =>
|
||||||
|
cFasdCockpitConfig.Instance?.Global?.TicketConfiguration?.UseSimplifiedCaseCompletionDialog == true;
|
||||||
|
|
||||||
|
private enumTicketExternalOpenMode SimplifiedCaseCompletionTicketOpenMode =>
|
||||||
|
cFasdCockpitConfig.Instance?.Global?.TicketConfiguration?.SimplifiedCaseCompletionTicketOpenMode
|
||||||
|
?? enumTicketExternalOpenMode.Preview;
|
||||||
|
|
||||||
private static class TicketInfoKeys
|
private static class TicketInfoKeys
|
||||||
{
|
{
|
||||||
public const string ActivityType = "ActivityType";
|
public const string ActivityType = "ActivityType";
|
||||||
@@ -531,6 +538,8 @@ namespace FasdDesktopUi.Basics.UserControls
|
|||||||
|
|
||||||
private void CloseCaseDialogWithTicket_Loaded(object sender, RoutedEventArgs e)
|
private void CloseCaseDialogWithTicket_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
UpdateTicketComponentVisibility();
|
||||||
|
|
||||||
Window _parentWindow = Window.GetWindow(this);
|
Window _parentWindow = Window.GetWindow(this);
|
||||||
|
|
||||||
if (!(_parentWindow is TicketCompletion _msgBox))
|
if (!(_parentWindow is TicketCompletion _msgBox))
|
||||||
@@ -623,10 +632,17 @@ namespace FasdDesktopUi.Basics.UserControls
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var _isVisible = checkTicketActive() && !_skipTicketPillSelected;
|
var _isVisible = checkTicketActive() && !_skipTicketPillSelected;
|
||||||
|
var useSimplifiedDialog = _isVisible && UseSimplifiedCaseCompletionDialog;
|
||||||
|
|
||||||
|
if (useSimplifiedDialog)
|
||||||
|
SelectSaveTicketAction();
|
||||||
|
|
||||||
TicketSelectionCategory.Visibility = _isVisible ? Visibility.Visible : Visibility.Collapsed;
|
TicketSelectionCategory.Visibility = _isVisible ? Visibility.Visible : Visibility.Collapsed;
|
||||||
StatusSelectionBorder.Visibility = _isVisible ? Visibility.Visible : Visibility.Collapsed;
|
StatusSelectionBorder.Visibility = _isVisible && !useSimplifiedDialog ? Visibility.Visible : Visibility.Collapsed;
|
||||||
CopyDisclaimerTextBox.Visibility = _isVisible ? Visibility.Collapsed : Visibility.Visible;
|
CopyDisclaimerTextBox.Visibility = _isVisible ? Visibility.Collapsed : Visibility.Visible;
|
||||||
|
|
||||||
|
if (!_isVisible || useSimplifiedDialog)
|
||||||
|
DynamicStatusAdditionBorder.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
catch (Exception E)
|
catch (Exception E)
|
||||||
{
|
{
|
||||||
@@ -634,6 +650,21 @@ namespace FasdDesktopUi.Basics.UserControls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SelectSaveTicketAction()
|
||||||
|
{
|
||||||
|
var saveItem = TicketStatusCombobox.Items
|
||||||
|
.OfType<ComboBoxItem>()
|
||||||
|
.FirstOrDefault(item =>
|
||||||
|
Enum.TryParse(item.Tag?.ToString(), out enumCloseCaseTicketStatus action) &&
|
||||||
|
action == enumCloseCaseTicketStatus.Save);
|
||||||
|
|
||||||
|
if (saveItem != null && !ReferenceEquals(TicketStatusCombobox.SelectedItem, saveItem))
|
||||||
|
TicketStatusCombobox.SelectedItem = saveItem;
|
||||||
|
|
||||||
|
DynamicStatusAdditionBorder.Child = null;
|
||||||
|
DynamicStatusAdditionBorder.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
private UIElement GetTicketUiElement(cF4sdApiSearchResultRelation ticketRelation)
|
private UIElement GetTicketUiElement(cF4sdApiSearchResultRelation ticketRelation)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -2011,7 +2042,20 @@ namespace FasdDesktopUi.Basics.UserControls
|
|||||||
ticketData.AdditionalValues.Add("Dialog.CloseCase.AssetNotFoundInMatrix42", cMultiLanguageSupport.GetItem("Dialog.CloseCase.AssetNotFoundInMatrix42"));
|
ticketData.AdditionalValues.Add("Dialog.CloseCase.AssetNotFoundInMatrix42", cMultiLanguageSupport.GetItem("Dialog.CloseCase.AssetNotFoundInMatrix42"));
|
||||||
ticketData.AdditionalValues.Add("Dialog.CloseCase.ReopenReasonText", cMultiLanguageSupport.GetItem("Dialog.CloseCase.ReopenReasonText"));
|
ticketData.AdditionalValues.Add("Dialog.CloseCase.ReopenReasonText", cMultiLanguageSupport.GetItem("Dialog.CloseCase.ReopenReasonText"));
|
||||||
ticketData.AdditionalValues.Add("Dialog.CloseCase.ReopenReasonTextHtml", cMultiLanguageSupport.GetItem("Dialog.CloseCase.ReopenReasonTextHtml"));
|
ticketData.AdditionalValues.Add("Dialog.CloseCase.ReopenReasonTextHtml", cMultiLanguageSupport.GetItem("Dialog.CloseCase.ReopenReasonTextHtml"));
|
||||||
var _res = await cFasdCockpitCommunicationBase.Instance.Matrix42TicketFinalization(ticketData);
|
var finalizationResult = await cFasdCockpitCommunicationBase.Instance.FinalizeTicketAsync(ticketData);
|
||||||
|
if (finalizationResult?.Success != true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (UseSimplifiedCaseCompletionDialog &&
|
||||||
|
SimplifiedCaseCompletionTicketOpenMode != enumTicketExternalOpenMode.None &&
|
||||||
|
finalizationResult.TicketId is Guid finalizedTicketId &&
|
||||||
|
finalizedTicketId != Guid.Empty)
|
||||||
|
{
|
||||||
|
await TicketExternalLinkHelper.TryOpenFinalizedTicketExternallyAsync(
|
||||||
|
finalizedTicketId,
|
||||||
|
SimplifiedCaseCompletionTicketOpenMode);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|||||||
Reference in New Issue
Block a user