public GenericActionstepRequest(TokenSetQuery tokenSetQuery, string relativeResourcePath, HttpMethod httpMethod, object jsonPayload = null) { TokenSetQuery = tokenSetQuery; RelativeResourcePath = relativeResourcePath; HttpMethod = httpMethod; JsonPayload = jsonPayload; }
public Task Remove(TokenSetQuery tokenSetQuery) { var itemToRemove = TokenSets.SingleOrDefault(t => t.UserId == tokenSetQuery.UserId && t.OrgKey == tokenSetQuery.OrgKey); if (itemToRemove != null) { TokenSets.Remove(itemToRemove); } return(Task.CompletedTask); }
public async Task <GetActionstepActionsResponse> Handle(GetActionstepActionsCommand command, CancellationToken cancellationToken) { if (command is null) { throw new System.ArgumentNullException(nameof(command)); } var tokenSetQuery = new TokenSetQuery(command.AuthenticatedUser?.Id, command.ActionstepOrgKey); var apiParams = string.Join(",", command.MatterIds); return(await _actionstepService.Handle <GetActionstepActionsResponse>(new GenericActionstepRequest(tokenSetQuery, $"rest/actions/{apiParams}", HttpMethod.Get))); }
public async Task <ListDisbursementsResponse> Handle(CreateDisbursementsCommand request, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } // Get Actionstep matter info var tokenSetQuery = new TokenSetQuery(request.AuthenticatedUser?.Id, request.ActionstepOrg); var createDisbursementsRequest = new CreateDisbursementsRequest() { TokenSetQuery = tokenSetQuery }; createDisbursementsRequest.Disbursements.Add(new Disbursement() { Date = LocalDate.FromDateTime(DateTime.Now), Description = "Premium", ImportExternalReference = request.PolicyNumber, Quantity = 1, UnitPrice = request.FirstTitlePrice.Premium, UnitPriceIncludesTax = false, Links = { Action = 23, TaxCode = 7 // S 10.0 } }); createDisbursementsRequest.Disbursements.Add(new Disbursement() { Date = LocalDate.FromDateTime(DateTime.Now), Description = "StampDuty", ImportExternalReference = request.PolicyNumber, Quantity = 1, UnitPrice = request.FirstTitlePrice.StampDuty, UnitPriceIncludesTax = false, Links = { Action = 23, TaxCode = 8 // BAS Excluded } }); var response = await _actionstepService.Handle <ListDisbursementsResponse>(createDisbursementsRequest); return(response); }
public async Task <ActionstepMatterValidationResult> Handle(ValidateActionstepMatterCommand request, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } _validator.ValidateAndThrow(request); var tokenSetQuery = new TokenSetQuery(request.ActionstepUserId, request.ActionstepOrgKey); int? matterId = null; bool isMapped = false; // First check for mapping to see if this GlobalX Matter reference has been mapped to another Actionstep Matter ID var gxMapping = await _wCADbContext.GlobalXMatterMappings.FindAsync(request.ActionstepOrgKey, request.MatterId); if (!(gxMapping is null)) { matterId = gxMapping.ActionstepMatterId; isMapped = true; }
public async Task <ActionstepDocument> Handle(ActionstepSavePDFCommand message, CancellationToken token) { if (message is null) { throw new ArgumentNullException(nameof(message)); } ValidationResult result = _validator.Validate(message); if (!result.IsValid) { throw new ValidationException("Invalid input.", result.Errors); } TokenSetQuery tokenSetQuery = new TokenSetQuery(message.AuthenticatedUser?.Id, message.OrgKey); var actionResponse = await _actionstepService.Handle <GetActionResponse>(new GetActionRequest(tokenSetQuery, message.MatterId)); string fileName = $"{message.MatterId}_Settlement Statement_{DateTime.UtcNow.ToString("_yyyy-MM-dd hh-mm", CultureInfo.InvariantCulture)}.pdf"; UploadFileResponse file = await _actionstepService.UploadFile(tokenSetQuery, fileName, message.FilePath); #region Check Documents Folder ActionFolder actionFolder = new ActionFolder(actionResponse.Action.Id); GetActionFolderRequest folderRequest = new GetActionFolderRequest(tokenSetQuery, actionFolder); ListActionFolderResponse folderResponse = await _actionstepService.Handle <ListActionFolderResponse>(folderRequest); var parentFolderId = folderResponse.ActionFolders.Where(af => af.Name == "Documents").Select(af => af.Id).FirstOrDefault(); #endregion ActionDocument document = new ActionDocument(actionResponse.Action.Id, fileName, file, parentFolderId); SaveActionDocumentRequest saveRequest = new SaveActionDocumentRequest(tokenSetQuery, document); var saveResponse = await _actionstepService.Handle <SaveActionDocumentResponse>(saveRequest); var fileUrl = new Uri(saveResponse.ActionDocument.SharepointUrl); string documentUrl = $"https://{fileUrl.Host}/mym/asfw/workflow/documents/views/action_id/{actionResponse.Action.Id}#mode=browse&view=list&folder={parentFolderId}&drive=DL"; return(new ActionstepDocument(fileUrl, fileName, new Uri(documentUrl))); }
public Task <TokenSet> GetTokenSet(TokenSetQuery tokenSetQuery) { // Use a separate scope for each method call to prevent DBContext caching using var scope = _serviceScopeFactory.CreateScope(); using var dbContext = scope.ServiceProvider.GetService <WCADbContext>(); if (tokenSetQuery is null) { throw new ArgumentNullException(nameof(tokenSetQuery)); } var userToGetCredentialsFor = tokenSetQuery.UserId; // Check to see if there is a substitute var substitute = dbContext .ActionstepCredentialSubstitutions .AsNoTracking() .Include(e => e.SubstituteWithOwner) .SingleOrDefault(e => e.ForOwner.Id == tokenSetQuery.UserId); if (substitute != null) { userToGetCredentialsFor = substitute.SubstituteWithOwner.Id; } var tokenSet = dbContext .ActionstepCredentials .AsNoTracking() .Include(c => c.Owner) .Include(c => c.ActionstepOrg) .ForOwnerAndOrg(userToGetCredentialsFor, tokenSetQuery.OrgKey) .SingleOrDefault(); if (tokenSet == null) { return(Task.FromResult <TokenSet>(null)); } return(Task.FromResult(tokenSet.ToTokenSet())); }
/// <summary> /// Does NOT use substitution. /// </summary> /// <param name="tokenSetQuery"></param> /// <returns></returns> public async Task Remove(TokenSetQuery tokenSetQuery) { // Use a separate scope for each method call to prevent DBContext caching using var scope = _serviceScopeFactory.CreateScope(); using var dbContext = scope.ServiceProvider.GetService <WCADbContext>(); if (tokenSetQuery is null) { throw new ArgumentNullException(nameof(tokenSetQuery)); } var itemToRemove = dbContext .ActionstepCredentials .ForOwnerAndOrg(tokenSetQuery.UserId, tokenSetQuery.OrgKey) .SingleOrDefault(); if (itemToRemove != null) { dbContext.ActionstepCredentials.Remove(itemToRemove); await dbContext.SaveChangesAsync(); } }
public async Task <FTAttachment> Handle(SavePolicyPDFToActionstepCommand request, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } // Get Actionstep matter info var tokenSetQuery = new TokenSetQuery(request.AuthenticatedUser?.Id, request.ActionstepOrg); var actionResponse = await _actionstepService.Handle <GetActionResponse>(new GetActionRequest(tokenSetQuery, request.MatterId)); UploadFileResponse file = await _actionstepService.UploadFile(tokenSetQuery, request.FileName, request.FilePath); #region Check Documents Folder ActionFolder actionFolder = new ActionFolder(actionResponse.Action.Id); GetActionFolderRequest folderRequest = new GetActionFolderRequest(tokenSetQuery, actionFolder); ListActionFolderResponse folderResponse = await _actionstepService.Handle <ListActionFolderResponse>(folderRequest); var parentFolderId = folderResponse.ActionFolders.Where(af => af.Name == "Documents").Select(af => af.Id).FirstOrDefault(); #endregion ActionDocument document = new ActionDocument(actionResponse.Action.Id, request.FileName, file, parentFolderId); SaveActionDocumentRequest saveRequest = new SaveActionDocumentRequest(tokenSetQuery, document); var saveResponse = await _actionstepService.Handle <SaveActionDocumentResponse>(saveRequest); var fileUrl = new Uri(saveResponse.ActionDocument.SharepointUrl); string documentUrl = $"https://{fileUrl.Host}/mym/asfw/workflow/documents/views/action_id/{actionResponse.Action.Id}#mode=browse&view=list&folder={parentFolderId}&drive=DL"; return(new FTAttachment() { FileName = request.FileName, FileUrl = documentUrl }); }
public async Task <SendMappingsToInfoTrack.SendMappingsToInfoTrackCommand> Handle(GetMappingDataFromActionstepQuery message, CancellationToken token) { if (message is null) { throw new ArgumentNullException(nameof(message)); } telemetryLogger.TrackTrace("GetMappingDataFromActionstep handler called", WCASeverityLevel.Information, null); try { ValidationResult validationResult = validator.Validate(message); if (!validationResult.IsValid) { throw new ValidationException("Invalid input.", validationResult.Errors); } // If we get this far, we know that the user has permisisons to the Actionstep org. // We must only get InfoTrack credentials if the user var infoTrackCredentials = await infoTrackCredentialRepository.FindCredential(message.ActionstepOrgKey); if (infoTrackCredentials == null) { throw new InfoTrackCredentialsNotFoundException(message.ActionstepOrgKey, message.AuthenticatedUser); } var tokenSetQuery = new TokenSetQuery(message.AuthenticatedUser?.Id, message.ActionstepOrgKey); // Response 1 Get Action Participants var allParticipants = await actionstepService.Handle <ActionParticipantsResponse>( new GenericActionstepRequest( tokenSetQuery, $"/rest/actionparticipants?action={message.MatterId}&include=participantType,participant", HttpMethod.Get)); // Response 2 Data collection info var dataCollectionRecordValues = await actionstepService.Handle <dynamic>( new GenericActionstepRequest( tokenSetQuery, "/rest/datacollectionrecordvalues" + $"?action={message.MatterId}" + $"&dataCollectionRecord[dataCollection][name_in]=property,convdet,keydates" + $"&dataCollectionField[name_in]=titleref,lotno,planno,plantype,lotno2,planno2,plantype2,smtdateonly,smttime,purprice" + $"&include=dataCollectionField,dataCollection", HttpMethod.Get)); // Prepare result types for population var queryResult = new SendMappingsToInfoTrack.SendMappingsToInfoTrackCommand() { AuthenticatedUser = message.AuthenticatedUser, InfoTrackCredentials = infoTrackCredentials, InfoTrackMappingData = new InfoTrackMappingData() { ClientReference = message.MatterId.ToString(CultureInfo.InvariantCulture), RetailerReference = $"WCA_{message.ActionstepOrgKey}|{message.AuthenticatedUser.Id}" } }; // Read responses and populate result object if (allParticipants != null) { foreach (var propertyAddressParticipant in FindParticipantsByName(allParticipants, "Property_Address")) { (string streetNumber, string streetName) = AddressHelper.ParseStreetNumber( propertyAddressParticipant.physicalAddressLine1, propertyAddressParticipant.physicalAddressLine2); queryResult.InfoTrackMappingData.PropertyDetails.Add(new InfoTrackMappingData.PropertyDetail() { PropertyAddress = new InfoTrackMappingData.Address() { StreetNumber = streetNumber, StreetName = streetName, Suburb = propertyAddressParticipant.physicalCity, State = propertyAddressParticipant.physicalStateProvince, PostCode = propertyAddressParticipant.physicalPostCode } }); // We currently want this to be empty as it affects the InfoTrack entrypoint. // This might change in the near future. //queryResult.State = propertyAddressParticipant.physicalStateProvince; // If there are multiple participants in the Property_Address field, we only want the first one break; } //var conveyancerTypeId = allParticipants.linked.participanttypes.FirstOrDefault(t => t.name == "Conveyancer")?.id; var organisationNameSet = false; foreach (var conveyancerParticipant in FindParticipantsByName(allParticipants, "Conveyancer")) { if (!organisationNameSet) { queryResult.InfoTrackMappingData.LawyerDetail.Organisation.Name = conveyancerParticipant.companyName; } (string addressStreetNumber, string addressStreetName) = AddressHelper.ParseStreetNumber( conveyancerParticipant.physicalAddressLine1, conveyancerParticipant.physicalAddressLine2); (string mailingStreetNumber, string mailingStreetName) = AddressHelper.ParseStreetNumber( conveyancerParticipant.mailingAddressLine1, conveyancerParticipant.mailingAddressLine2); queryResult.InfoTrackMappingData.LawyerDetail.ContactDetails.Add(new InfoTrackMappingData.Contactdetail() { Email = conveyancerParticipant.email, Phone = GetBestPhoneForParticipant(conveyancerParticipant), Fax = conveyancerParticipant.fax, Individual = new InfoTrackMappingData.Individual() { Title = conveyancerParticipant.salutation, GivenName = conveyancerParticipant.firstName, GivenName2 = conveyancerParticipant.middleName, Surname = conveyancerParticipant.lastName, Gender = conveyancerParticipant.gender, DateOfBirth = ParseDateForInfoTrack(conveyancerParticipant.birthTimestamp), }, Address = new InfoTrackMappingData.Address() { StreetNumber = addressStreetNumber, StreetName = addressStreetName, Suburb = conveyancerParticipant.physicalCity, State = conveyancerParticipant.physicalStateProvince, PostCode = conveyancerParticipant.physicalPostCode, }, PoBoxAddress = new InfoTrackMappingData.Poboxaddress() { PoBoxType = mailingStreetName, Number = mailingStreetNumber, Suburb = conveyancerParticipant.mailingCity, State = conveyancerParticipant.mailingStateProvince, PostCode = conveyancerParticipant.mailingPostCode } }); } foreach (var buyerParticipant in FindParticipantsByName(allParticipants, "Buyer")) { (string addressStreetNumber, string addressStreetName) = AddressHelper.ParseStreetNumber( buyerParticipant.physicalAddressLine1, buyerParticipant.physicalAddressLine2); if (queryResult.InfoTrackMappingData.PropertyDetails.Count < 1) { queryResult.InfoTrackMappingData.PropertyDetails.Add(new InfoTrackMappingData.PropertyDetail()); } queryResult.InfoTrackMappingData.PropertyDetails[0].Purchasers.Add(new InfoTrackMappingData.Purchaser() { Organisation = new InfoTrackMappingData.Organisation() { Name = buyerParticipant.companyName, AcnOrAbn = buyerParticipant.taxNumber, Abn = buyerParticipant.taxNumber }, Email = buyerParticipant.email, Phone = GetBestPhoneForParticipant(buyerParticipant), Fax = buyerParticipant.fax, Individual = new InfoTrackMappingData.Individual() { Title = buyerParticipant.salutation, GivenName = buyerParticipant.firstName, GivenName2 = buyerParticipant.middleName, Surname = buyerParticipant.lastName, Gender = buyerParticipant.gender, DateOfBirth = ParseDateForInfoTrack(buyerParticipant.birthTimestamp) }, Address = new InfoTrackMappingData.Address() { StreetNumber = addressStreetNumber, StreetName = addressStreetName, Suburb = buyerParticipant.physicalCity, State = buyerParticipant.physicalStateProvince, PostCode = buyerParticipant.physicalPostCode } }); } foreach (var sellerParticipant in FindParticipantsByName(allParticipants, "Seller")) { (string addressStreetNumber, string addressStreetName) = AddressHelper.ParseStreetNumber( sellerParticipant.physicalAddressLine1, sellerParticipant.physicalAddressLine2); if (queryResult.InfoTrackMappingData.PropertyDetails.Count < 1) { queryResult.InfoTrackMappingData.PropertyDetails.Add(new InfoTrackMappingData.PropertyDetail()); } queryResult.InfoTrackMappingData.PropertyDetails[0].Vendors.Add(new InfoTrackMappingData.Vendor() { Organisation = new InfoTrackMappingData.Organisation() { Name = sellerParticipant.companyName, AcnOrAbn = sellerParticipant.taxNumber, Abn = sellerParticipant.taxNumber }, Email = sellerParticipant.email, Phone = GetBestPhoneForParticipant(sellerParticipant), Fax = sellerParticipant.fax, Individual = new InfoTrackMappingData.Individual() { Title = sellerParticipant.salutation, GivenName = sellerParticipant.firstName, GivenName2 = sellerParticipant.middleName, Surname = sellerParticipant.lastName, Gender = sellerParticipant.gender, DateOfBirth = ParseDateForInfoTrack(sellerParticipant.birthTimestamp), }, Address = new InfoTrackMappingData.Address() { StreetNumber = addressStreetNumber, StreetName = addressStreetName, Suburb = sellerParticipant.physicalCity, State = sellerParticipant.physicalStateProvince, PostCode = sellerParticipant.physicalPostCode } }); } } if (queryResult.InfoTrackMappingData.PropertyDetails.Count < 1) { queryResult.InfoTrackMappingData.PropertyDetails.Add(new InfoTrackMappingData.PropertyDetail()); } if (dataCollectionRecordValues != null && dataCollectionRecordValues.datacollectionrecordvalues != null) { int?propertyDataCollectionId = ((IEnumerable <dynamic>)dataCollectionRecordValues?.linked?.datacollections)?.FirstOrDefault(d => d.name == "property")?.id; if (propertyDataCollectionId.HasValue) { // Get Title Reference and copy it to PropertyReferences var titleReference = ReadDataCollectionRecordValueString("titleref", propertyDataCollectionId.Value, dataCollectionRecordValues); queryResult.InfoTrackMappingData.PropertyDetails[0].PropertyReferences.Add( new InfoTrackMappingData.PropertyReference() { Reference = titleReference }); // Lot details and copy them to the first property queryResult.InfoTrackMappingData.PropertyDetails[0].PropertyAddress.LotNumber = ReadDataCollectionRecordValueString("lotno", propertyDataCollectionId.Value, dataCollectionRecordValues); queryResult.InfoTrackMappingData.PropertyDetails[0].LotPlans.Add(new InfoTrackMappingData.Lotplan() { Lot = queryResult.InfoTrackMappingData.PropertyDetails[0].PropertyAddress.LotNumber, PlanNumber = ReadDataCollectionRecordValueString("planno", propertyDataCollectionId.Value, dataCollectionRecordValues), PlanType = ReadDataCollectionRecordValueString("plantype", propertyDataCollectionId.Value, dataCollectionRecordValues), TitleReference = titleReference }); var lot2 = new InfoTrackMappingData.Lotplan() { Lot = ReadDataCollectionRecordValueString("lotno2", propertyDataCollectionId.Value, dataCollectionRecordValues), PlanNumber = ReadDataCollectionRecordValueString("planno2", propertyDataCollectionId.Value, dataCollectionRecordValues), PlanType = ReadDataCollectionRecordValueString("plantype2", propertyDataCollectionId.Value, dataCollectionRecordValues), TitleReference = titleReference }; if (lot2.ContainsLotData()) { queryResult.InfoTrackMappingData.PropertyDetails[0].LotPlans.Add(lot2); } } int?convdetDataCollectionId = ((IEnumerable <dynamic>)dataCollectionRecordValues?.linked?.datacollections)?.FirstOrDefault(d => d.name == "convdet")?.id; if (convdetDataCollectionId.HasValue) { queryResult.InfoTrackMappingData.PropertyDetails[0].SettlementTime = ReadDataCollectionRecordValueString("smttime", convdetDataCollectionId.Value, dataCollectionRecordValues); queryResult.InfoTrackMappingData.PropertyDetails[0].PurchasePrice = ReadDataCollectionRecordValueString("purprice", convdetDataCollectionId.Value, dataCollectionRecordValues); } int?keydatesDataCollectionId = ((IEnumerable <dynamic>)dataCollectionRecordValues?.linked?.datacollections)?.FirstOrDefault(d => d.name == "keydates")?.id; if (keydatesDataCollectionId.HasValue) { queryResult.InfoTrackMappingData.PropertyDetails[0].SettlementDate = ParseDateForInfoTrack(ReadDataCollectionRecordValueString("smtdateonly", keydatesDataCollectionId.Value, dataCollectionRecordValues)); } } return(queryResult); } catch (Exception ex) { telemetryLogger.TrackTrace( "Unexpected exception getting InfoTrack mapping URL", WCASeverityLevel.Error, new Dictionary <string, string>() { { "Actionstep Org", message.ActionstepOrgKey }, { "Matter", message.MatterId.ToString(CultureInfo.InvariantCulture) }, { "User", message.AuthenticatedUser.Id }, { "Exception Message", ex.Message }, { "Stack Trace", ex.StackTrace } }); throw; } }
public GetActionRequest(TokenSetQuery tokenSetQuery, int actionId) { TokenSetQuery = tokenSetQuery; ActionId = actionId; }
public static async Task CanCreateAndReadDisbursement(this IActionstepService actionstepService, int actionId, TokenSetQuery tokenSetQuery) { if (actionstepService is null) { throw new ArgumentNullException(nameof(actionstepService)); } if (tokenSetQuery is null) { throw new ArgumentNullException(nameof(tokenSetQuery)); } var newDisbursement = new Disbursement() { Description = "Test from API", Links = { Action = actionId } }; var newDisbursementRequest = new CreateDisbursementsRequest() { Disbursements = { newDisbursement }, TokenSetQuery = tokenSetQuery }; var result = await actionstepService.Handle <ListDisbursementsResponse>(newDisbursementRequest); }
public Task <UploadFileResponse> UploadFile(TokenSetQuery tokenSetQuery, string fileName, Stream stream) { throw new NotImplementedException(); }
public Task <PEXAWorkspaceCreationRequestWithActionstepResponse> Handle(PEXAWorkspaceCreationRequestFromActionstepQuery request, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } // Get Actionstep matter info var tokenSetQuery = new TokenSetQuery(request.AuthenticatedUser?.Id, request.ActionstepOrg); try { // New token refresh handling means these can run in parallel. var actionResponseTask = _actionstepService.Handle <GetActionResponse>(new GetActionRequest { ActionId = request.MatterId, TokenSetQuery = tokenSetQuery }); var actionParticipantsResponseTask = _actionstepService.Handle <ListActionParticipantsResponse>(new ListActionParticipantsRequest { ActionstepId = request.MatterId, TokenSetQuery = tokenSetQuery }); var dataCollectionRecordValuesResponseTask = _actionstepService.Handle <ListDataCollectionRecordValuesResponse>(new ListDataCollectionRecordValuesRequest { ActionstepId = request.MatterId, TokenSetQuery = tokenSetQuery, DataCollectionRecordNames = { "property", "convdet", "keydates" }, DataCollectionFieldNames = { "titleref", "lotno", "planno", "plantype", "smtdateonly", "smttime", "purprice", "ConveyType" } }); Task.WaitAll(actionResponseTask, actionParticipantsResponseTask, dataCollectionRecordValuesResponseTask); // Transform Actionstep matter info into generic WCA Conveyancing Matter type // using specific configuration for this client (to account for Actionstep // action type configuration). var wCAConveyancingMatter = _actionstepToWCAMapper.MapFromActionstepTypes( actionResponseTask.Result, actionParticipantsResponseTask.Result, dataCollectionRecordValuesResponseTask.Result); PEXAWorkspaceCreationRequestWithActionstepResponse pexaWorkspaceRequestWithActionstepData = new PEXAWorkspaceCreationRequestWithActionstepResponse { CreatePexaWorkspaceCommand = new CreatePexaWorkspaceCommand() { PexaWorkspaceCreationRequest = new WorkspaceCreationRequest(), OrgKey = request.ActionstepOrg, MatterId = request.MatterId }, PexaRoleSpecified = true, ActionstepData = wCAConveyancingMatter }; var landTitle = _mapper.Map <PropertyDetails, WorkspaceCreationRequestTypeLandTitleDetailsLandTitle>(wCAConveyancingMatter.PropertyDetails); pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.ParticipantSettlementAcceptanceStatus = "Accepted"; pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.LandTitleDetails = new WorkspaceCreationRequestTypeLandTitleDetails(); pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.LandTitleDetails.LandTitle.Add(landTitle); var actionTypeAlias = String.Empty; switch (wCAConveyancingMatter.ActionType) { case "Conveyancing - NSW": actionTypeAlias = "NSW"; break; case "Conveyancing - Queensland": actionTypeAlias = "QLD"; break; case "Conveyancing - Victoria": actionTypeAlias = "VIC"; break; default: actionTypeAlias = String.Empty; break; } if (!string.IsNullOrEmpty(actionTypeAlias)) { pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.Jurisdiction = actionTypeAlias; } if (wCAConveyancingMatter.ConveyancingType == ConveyancingType.Purchase) { pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.Role = PexaRole.Incoming_Proprietor; } else if (wCAConveyancingMatter.ConveyancingType == ConveyancingType.Sale) { pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.Role = PexaRole.Proprietor_on_Title; } else { pexaWorkspaceRequestWithActionstepData.PexaRoleSpecified = false; } if (!string.IsNullOrEmpty(request.ActionstepOrg) && request.MatterId > 0) { pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.SubscriberReference = ActionstepMatter.ConstructId(request.ActionstepOrg, request.MatterId); } if (wCAConveyancingMatter.SettlementDate != null) { pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.SettlementDate = wCAConveyancingMatter.SettlementDate.ToDateTimeUnspecified(); } if (pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.SettlementDate == DateTime.MinValue) { pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.SettlementDate = null; } if (pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.Role == PexaRole.Consentor || pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.Role == PexaRole.CT_Controller) { pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.LandTitleDetails.ParentTitle = "No"; pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.RequestLandTitleData = "No"; pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.FinancialSettlement = "Yes"; } else { pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.LandTitleDetails.ParentTitle = "No"; pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.RequestLandTitleData = "Yes"; pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.FinancialSettlement = "Yes"; } pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.PartyDetails = new Collection <WorkspaceCreationRequestTypePartyDetailsParty>(); foreach (var buyer in wCAConveyancingMatter.Buyers) { var buyerPartyDetails = MapPartyDetails(buyer, "Incoming Proprietor"); pexaWorkspaceRequestWithActionstepData.CreatePexaWorkspaceCommand.PexaWorkspaceCreationRequest.PartyDetails.Add(buyerPartyDetails); } return(Task.FromResult(pexaWorkspaceRequestWithActionstepData)); } catch (AggregateException ex) { if (ex.InnerExceptions.All(e => e is InvalidTokenSetException || e is InvalidCredentialsForActionstepApiCallException)) { throw ex.InnerExceptions.FirstOrDefault(); } throw ex; } }
protected override async Task Handle(SaveResourcesCommand message, CancellationToken token) { if (message is null) { throw new ArgumentNullException(nameof(message)); } ValidationResult result = _validator.Validate(message); if (!result.IsValid) { throw new ValidationException("Unable to save Property Resources, the command message was invalid.", result.Errors); } using (var request = new HttpRequestMessage(HttpMethod.Get, message.ResourceURL)) { var byteArray = Encoding.ASCII.GetBytes($"{message.InfoTrackCredentials.Username}:{message.InfoTrackCredentials.Password}"); request.Headers.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); using (var infoTrackFileDownloadResponse = await _infoTrackService.Client.SendAsync(request)) { infoTrackFileDownloadResponse.EnsureSuccessStatusCode(); using (var infoTrackFileStream = await infoTrackFileDownloadResponse.Content.ReadAsStreamAsync()) { if (infoTrackFileStream.Length <= 0) { throw new HttpRequestException($"Unable to download the resource from InfoTrack."); } else { var tokenSetQuery = new TokenSetQuery(message.AuthenticatedUser?.Id, message.ActionstepOrgKey); var fileNameWithExtension = DetermineBestFileNameWithExtension(message, infoTrackFileDownloadResponse); var fileUploadResponse = await _actionstepService.UploadFile(tokenSetQuery, fileNameWithExtension, infoTrackFileStream); if (fileUploadResponse == null) { throw new Exception("Unknown error uploading document to Actionstep."); } // Get all folders for matter and check to see if the specified folder exists. If it does, we need its ID. var actionFolder = new ActionFolder(message.MatterId); var getFolderRequest = new GetActionFolderRequest(tokenSetQuery, actionFolder); var folderResponse = await _actionstepService.Handle <ListActionFolderResponse>(getFolderRequest); /// Will be null if <see cref="SaveResourcesCommand.FolderName"/> wasn't found. In which case the document will be saved at the root of the matter. var parentFolderId = folderResponse.ActionFolders.FirstOrDefault(af => af.Name == message.FolderName)?.Id; /// <see cref="ActionstepDocument"/> represents the object in "Matter Documents", as opposed to the file content from above (which is just in a big bucket). var document = new ActionDocument(message.MatterId, fileNameWithExtension, fileUploadResponse, parentFolderId); var saveRequest = new SaveActionDocumentRequest(tokenSetQuery, document); await _actionstepService.Handle <SaveActionDocumentResponse>(saveRequest); } } } } }
public SaveActionDocumentRequest(TokenSetQuery tokenSetQuery, ActionDocument actionDocument) { TokenSetQuery = tokenSetQuery; ActionDocument = actionDocument; }
protected override async Task Handle(UpdateOrderCommand command, CancellationToken token) { if (command is null) { throw new ArgumentNullException(nameof(command)); } var infoTrackOrderUpdateMessage = _wCADbContext.InfoTrackOrderUpdateMessageHistory.Find(command.InfoTrackOrderUpdateMessageId); infoTrackOrderUpdateMessage.MarkProcessInProgress(); await _wCADbContext.SaveChangesAsync(); var executionId = Guid.NewGuid(); _telemetryLogger.TrackTrace( $"{typeof(Handler).FullName}: Entered UpdateOrder.", WCASeverityLevel.Information, new Dictionary <string, string>() { { "InfoTrackOrderId", infoTrackOrderUpdateMessage.InfoTrackOrderId.ToString(CultureInfo.InvariantCulture) }, { "Actionstep matter", infoTrackOrderUpdateMessage.InfoTrackClientReference }, { "InfoTrackOrderUpdateMessageId", command.InfoTrackOrderUpdateMessageId.ToString(CultureInfo.InvariantCulture) }, { "ExecutionId", executionId.ToString() } }); int matterId = int.Parse(infoTrackOrderUpdateMessage.InfoTrackClientReference, CultureInfo.InvariantCulture); string[] retailerReference = infoTrackOrderUpdateMessage.InfoTrackRetailerReference.Split('|'); var orgKey = string.Empty; var wcaUserId = string.Empty; if (retailerReference.Length >= 2) { // Substring removes the "WCA_" prefix. We know the prefix is present because // the message passed Validation to get here. orgKey = retailerReference[0].Substring(4); wcaUserId = retailerReference[1]; } if (string.IsNullOrEmpty(wcaUserId)) { throw new InvalidInfoTrackOrderUserException( "InfoTrack order information was supplied without WCA user ID. " + "Cannot process the order."); } var userWhoPlacedOrder = await _wCADbContext.Users.FindAsync(wcaUserId); if (userWhoPlacedOrder == null) { throw new InvalidInfoTrackOrderUserException( "InfoTrack order information was supplied with an invalid WCA user ID. " + "Cannot process the order."); } // Update the current record for this order var infoTrackOrder = await _wCADbContext.InfoTrackOrders.FindAsync(infoTrackOrderUpdateMessage.InfoTrackOrderId); if (infoTrackOrder == null) { infoTrackOrder = new InfoTrackOrder(); infoTrackOrder.DateCreatedUtc = DateTime.UtcNow; infoTrackOrder.LastUpdatedUtc = infoTrackOrder.DateCreatedUtc; infoTrackOrder.CreatedBy = userWhoPlacedOrder; infoTrackOrder.UpdatedBy = userWhoPlacedOrder; await _wCADbContext.AddAsync(infoTrackOrder); } var previousFileHash = infoTrackOrder.InfoTrackFileHash; var previousOrderTotalFeeTotal = infoTrackOrder.InfoTrackTotalFeeTotal; infoTrackOrder = _mapper.Map(infoTrackOrderUpdateMessage, infoTrackOrder); infoTrackOrder.OrderedByWCAUser = userWhoPlacedOrder; infoTrackOrder.ActionstepMatterId = matterId; infoTrackOrder.LastUpdatedUtc = DateTime.UtcNow; var existingOrg = await _wCADbContext.ActionstepOrgs.FindAsync(orgKey); infoTrackOrder.ActionstepOrg = existingOrg ?? throw new InvalidOperationException( "InfoTrack order information references an invalid Actonstep org key. " + "WCA doesn't have any information or API credentials for the specified " + "org key. Cannot continue."); // Update current record with values from history - checkpoint await _wCADbContext.SaveChangesAsync(); var tokenSetQuery = new TokenSetQuery(userWhoPlacedOrder.Id, orgKey); var processingErrors = new StringBuilder(); // Save InfoTrack Title Order Resources (Files) to Actionstep // We only want to upload documents if the filehash has changed, and if there's // actually a download url. if (string.IsNullOrEmpty(infoTrackOrderUpdateMessage.InfoTrackDownloadUrl)) { _telemetryLogger.TrackTrace( $"{typeof(Handler).FullName}: InfoTrackDownloadUrl is empty. No document to upload.", WCASeverityLevel.Verbose, new Dictionary <string, string>() { { "InfoTrackOrderUpdateMessageId", command.InfoTrackOrderUpdateMessageId.ToString(CultureInfo.InvariantCulture) }, { "Actionstep org key", orgKey }, { "Actionstep matter", matterId.ToString(CultureInfo.InvariantCulture) }, { "ExecutionId", executionId.ToString() } }); infoTrackOrder.LastUpdatedUtc = DateTime.UtcNow; infoTrackOrder.ActionstepDocumentUploadStatusUpdatedUtc = infoTrackOrder.LastUpdatedUtc; infoTrackOrder.ActionstepDocumentUploadStatus = ActionstepDocumentUploadStatus.NotApplicable; await _wCADbContext.SaveChangesAsync(); } else if (previousFileHash == infoTrackOrderUpdateMessage.InfoTrackFileHash) { _telemetryLogger.TrackTrace( $"{typeof(Handler).FullName}: FileHash has not changed. Skipping document upload.", WCASeverityLevel.Verbose, new Dictionary <string, string>() { { "InfoTrackOrderUpdateMessageId", command.InfoTrackOrderUpdateMessageId.ToString(CultureInfo.InvariantCulture) }, { "Actionstep org key", orgKey }, { "Actionstep matter", matterId.ToString(CultureInfo.InvariantCulture) }, { "ExecutionId", executionId.ToString() } }); // Don't update ActionstepDocumentUploadStatus here because the existing status on the record // is still valid and informative. } else { // If we're here, we have a download url, and the FileHash is new (either becaues it's changed or // there was no prior FileHash). try { infoTrackOrder.LastUpdatedUtc = DateTime.UtcNow; infoTrackOrder.ActionstepDocumentUploadStatusUpdatedUtc = infoTrackOrder.LastUpdatedUtc; infoTrackOrder.ActionstepDocumentUploadStatus = ActionstepDocumentUploadStatus.UploadInProgress; await _wCADbContext.SaveChangesAsync(); var infoTrackCredentials = await _infoTrackCredentialRepository.FindCredential(orgKey); await _mediator.Send(new SaveResources.SaveResourcesCommand { AuthenticatedUser = userWhoPlacedOrder, MatterId = matterId, ActionstepOrgKey = orgKey, InfoTrackCredentials = infoTrackCredentials, ResourceURL = infoTrackOrderUpdateMessage.InfoTrackDownloadUrl, FolderName = "_SEARCHES", FileNameWithoutExtensionIfNotAvailableFromHeader = infoTrackOrder.InfoTrackServiceName, FileNameAddition = " - Updated at " + DateTime.UtcNow.ToString("dd MMM yyyy hh-mm tt", CultureInfo.InvariantCulture) }); infoTrackOrder.LastUpdatedUtc = DateTime.UtcNow; infoTrackOrder.ActionstepDocumentUploadStatusUpdatedUtc = infoTrackOrder.LastUpdatedUtc; infoTrackOrder.ActionstepDocumentUploadStatus = ActionstepDocumentUploadStatus.UploadedSuccessfully; await _wCADbContext.SaveChangesAsync(); } catch (Exception ex) { infoTrackOrder.LastUpdatedUtc = DateTime.UtcNow; infoTrackOrder.ActionstepDocumentUploadStatusUpdatedUtc = infoTrackOrder.LastUpdatedUtc; infoTrackOrder.ActionstepDocumentUploadStatus = ActionstepDocumentUploadStatus.UploadFailed; await _wCADbContext.SaveChangesAsync(); var message = $"Failed to upload InfoTrack document to Actionstep for ID: {command.InfoTrackOrderUpdateMessageId}"; _logger.LogError(ex, message, null); _telemetryLogger.TrackTrace( message, WCASeverityLevel.Error, new Dictionary <string, string>() { { "InfoTrackOrderUpdateMessageId", command.InfoTrackOrderUpdateMessageId.ToString(CultureInfo.InvariantCulture) }, { "Actionstep org key", orgKey }, { "Actionstep matter", matterId.ToString(CultureInfo.InvariantCulture) }, { "Exception Message", ex.Message }, { "Stack Trace", ex.StackTrace.ToString(CultureInfo.InvariantCulture) }, { "ExecutionId", executionId.ToString() } }); processingErrors.Append(message + "<br/>"); } } if (infoTrackOrder.ActionstepDisbursementStatus == ActionstepDisbursementStatus.CreatedSuccessfully) { _telemetryLogger.TrackTrace( $"{typeof(Handler).FullName}: ActionstepDisbursementStatus is CreatedSucessfully, skipping processing of disbursements.", WCASeverityLevel.Information, new Dictionary <string, string>() { { "InfoTrackOrderUpdateMessageId", command.InfoTrackOrderUpdateMessageId.ToString(CultureInfo.InvariantCulture) }, { "Actionstep org key", orgKey }, { "Actionstep matter", matterId.ToString(CultureInfo.InvariantCulture) }, { "ExecutionId", executionId.ToString() } }); } else { ValidateFees(infoTrackOrderUpdateMessage); // Negative values are allowed as this represents a refund. if (infoTrackOrderUpdateMessage.InfoTrackTotalFeeTotal != 0) { _telemetryLogger.TrackTrace( $"{typeof(Handler).FullName}: Disbursements have not yet been created and TotalFeeTotal != 0. Processing disbursements now.", WCASeverityLevel.Information, new Dictionary <string, string>() { { "InfoTrackOrderUpdateMessageId", command.InfoTrackOrderUpdateMessageId.ToString(CultureInfo.InvariantCulture) }, { "Actionstep org key", orgKey }, { "Actionstep matter", matterId.ToString(CultureInfo.InvariantCulture) }, { "InfoTrackTotalFeeTotal", infoTrackOrderUpdateMessage.InfoTrackTotalFeeTotal.ToString(CultureInfo.InvariantCulture) }, { "ExecutionId", executionId.ToString() } }); try { infoTrackOrder.LastUpdatedUtc = DateTime.UtcNow; infoTrackOrder.ActionstepDisbursementStatusUpdatedUtc = infoTrackOrder.LastUpdatedUtc; infoTrackOrder.ActionstepDisbursementStatus = ActionstepDisbursementStatus.CreationInProgress; await _wCADbContext.SaveChangesAsync(); (int?gstTaxCodeId, int?nonGstTaxCodeId) = await GetTaxCodeIds( _actionstepService, tokenSetQuery, _telemetryLogger, infoTrackOrderUpdateMessage.InfoTrackOrderId, orgKey, matterId, executionId); // Save under disbursments // If GST values match, we'll create a single disbursement. If they don't match, // we need to create two different disbursements to account for the differing GST amounts. dynamic disbursement; // If they have the same GST status, then we can combine to a single disbursement. // I.e. either if they both have GST, or if neither of them have GST. bool retailerHasGST = infoTrackOrderUpdateMessage.InfoTrackRetailerFeeGST != 0; bool supplierHasGST = infoTrackOrderUpdateMessage.InfoTrackSupplierFeeGST != 0; bool splitDisbursements = false; if (retailerHasGST == supplierHasGST) { disbursement = PrepareSingleDisbursement(infoTrackOrderUpdateMessage, matterId, gstTaxCodeId, nonGstTaxCodeId); } else { splitDisbursements = true; disbursement = PrepareSplitDisbursements(infoTrackOrderUpdateMessage, matterId, gstTaxCodeId, nonGstTaxCodeId); } if (disbursement != null) { _telemetryLogger.TrackTrace( $"{typeof(Handler).FullName}: Creating disbursements.", WCASeverityLevel.Information, new Dictionary <string, string>() { { "InfoTrackOrderUpdateMessageId", command.InfoTrackOrderUpdateMessageId.ToString(CultureInfo.InvariantCulture) }, { "Actionstep org key", orgKey }, { "Actionstep matter", matterId.ToString(CultureInfo.InvariantCulture) }, { "InfoTrackTotalFeeTotal", infoTrackOrderUpdateMessage.InfoTrackTotalFeeTotal.ToString(CultureInfo.InvariantCulture) }, { "SplitDisbursements", splitDisbursements.ToString(CultureInfo.InvariantCulture) }, { "ExecutionId", executionId.ToString() } }); var response = await _actionstepService.Handle <dynamic>(new GenericActionstepRequest( tokenSetQuery, $"/rest/disbursements", HttpMethod.Post, disbursement)); infoTrackOrder.LastUpdatedUtc = DateTime.UtcNow; infoTrackOrder.ActionstepDisbursementStatusUpdatedUtc = infoTrackOrder.LastUpdatedUtc; infoTrackOrder.ActionstepDisbursementStatus = ActionstepDisbursementStatus.CreatedSuccessfully; await _wCADbContext.SaveChangesAsync(); } else { _telemetryLogger.TrackTrace( $"{typeof(Handler).FullName}: After processing it was determined that no disbursements need to be created.", WCASeverityLevel.Information, new Dictionary <string, string>() { { "InfoTrackOrderUpdateMessageId", command.InfoTrackOrderUpdateMessageId.ToString(CultureInfo.InvariantCulture) }, { "Actionstep org key", orgKey }, { "Actionstep matter", matterId.ToString(CultureInfo.InvariantCulture) }, { "InfoTrackTotalFeeTotal", infoTrackOrderUpdateMessage.InfoTrackTotalFeeTotal.ToString(CultureInfo.InvariantCulture) }, { "ExecutionId", executionId.ToString() } }); infoTrackOrder.LastUpdatedUtc = DateTime.UtcNow; infoTrackOrder.ActionstepDisbursementStatusUpdatedUtc = infoTrackOrder.LastUpdatedUtc; infoTrackOrder.ActionstepDisbursementStatus = ActionstepDisbursementStatus.NotApplicable; await _wCADbContext.SaveChangesAsync(); } } catch (Exception ex) { infoTrackOrder.LastUpdatedUtc = DateTime.UtcNow; infoTrackOrder.ActionstepDisbursementStatusUpdatedUtc = infoTrackOrder.LastUpdatedUtc; infoTrackOrder.ActionstepDisbursementStatus = ActionstepDisbursementStatus.CreationFailed; await _wCADbContext.SaveChangesAsync(); var message = $"Failed to process disbursements for InfoTrack order for ID: {command.InfoTrackOrderUpdateMessageId}"; _logger.LogError(ex, message, null); _telemetryLogger.TrackTrace( message, WCASeverityLevel.Error, new Dictionary <string, string>() { { "InfoTrackOrderUpdateMessageId", command.InfoTrackOrderUpdateMessageId.ToString(CultureInfo.InvariantCulture) }, { "Actionstep org key", orgKey }, { "Actionstep matter", matterId.ToString(CultureInfo.InvariantCulture) }, { "Exception Message", ex.Message }, { "Stack Trace", ex.StackTrace.ToString(CultureInfo.InvariantCulture) }, { "ExecutionId", executionId.ToString() } }); processingErrors.Append(message + "<br/>"); } } else { _telemetryLogger.TrackTrace( $"{typeof(Handler).FullName}: Disbursement amounts remain at 0. Skipping disbursements.", WCASeverityLevel.Information, new Dictionary <string, string>() { { "InfoTrackOrderUpdateMessageId", command.InfoTrackOrderUpdateMessageId.ToString(CultureInfo.InvariantCulture) }, { "Actionstep org key", orgKey }, { "Actionstep matter", matterId.ToString(CultureInfo.InvariantCulture) }, { "InfoTrackTotalFeeTotal", infoTrackOrderUpdateMessage.InfoTrackTotalFeeTotal.ToString(CultureInfo.InvariantCulture) }, { "ExecutionId", executionId.ToString() } }); infoTrackOrder.LastUpdatedUtc = DateTime.UtcNow; infoTrackOrder.ActionstepDisbursementStatusUpdatedUtc = infoTrackOrder.LastUpdatedUtc; infoTrackOrder.ActionstepDisbursementStatus = ActionstepDisbursementStatus.NotApplicable; await _wCADbContext.SaveChangesAsync(); } } var errorMessage = processingErrors.ToString(); var processingErrorsEncountered = !String.IsNullOrEmpty(errorMessage); if (processingErrorsEncountered) { infoTrackOrderUpdateMessage.MarkProcessedWithErrors(); } else { infoTrackOrderUpdateMessage.MarkProcessed(); } await _wCADbContext.SaveChangesAsync(); _telemetryLogger.TrackTrace( processingErrorsEncountered ? $"{typeof(Handler).FullName}: Finished UpdateOrder with errors." : $"{typeof(Handler).FullName}: Finished UpdateOrder.", WCASeverityLevel.Information, new Dictionary <string, string>() { { "InfoTrackOrderUpdateMessageId", command.InfoTrackOrderUpdateMessageId.ToString(CultureInfo.InvariantCulture) }, { "Actionstep org key", orgKey }, { "Actionstep matter", matterId.ToString(CultureInfo.InvariantCulture) }, { "ExecutionId", executionId.ToString() } }); if (processingErrorsEncountered) { var ex = new ApplicationException("Errors were encountered while processing message"); ex.Data.Add("message", errorMessage); ex.Data.Add("contentType", "text/html"); throw ex; } }
private async Task <(int?gstTaxCodeId, int?nonGstTaxCodeId)> GetTaxCodeIds( IActionstepService actionstepService, TokenSetQuery tokenSetQuery, ITelemetryLogger telemetryLogger, int infoTrackOrderId, string orgKey, int matterId, Guid executionId) { // Get GST and Non GST tax codes for disbursement creation var taxCodeInfo = await actionstepService.Handle <dynamic>(new GenericActionstepRequest(tokenSetQuery, $"/rest/taxcodes?fields=code", HttpMethod.Get)); var gstTaxCodeNames = new[] { "S 10.0", "GST" }; int?gstTaxCodeId = LookupTaxCodeId(taxCodeInfo?.taxcodes, gstTaxCodeNames); if (gstTaxCodeId == null) { telemetryLogger.TrackTrace( "Couldn't determine GST Tax Code when creating InfoTrack disbursement. " + "Actionstep default will be used instead.", WCASeverityLevel.Warning, new Dictionary <string, string>() { { "GST Tax Code names attempted", string.Join(", ", gstTaxCodeNames) }, { "InfoTrack Order ID", infoTrackOrderId.ToString(CultureInfo.InvariantCulture) }, { "Actionstep org key", orgKey }, { "Actionstep matter", matterId.ToString(CultureInfo.InvariantCulture) }, { "ExecutionId", executionId.ToString() } }); } var nonGstTaxCodeNames = new[] { "N-T", "GST Free", "Other GST Free", "No Tax" }; // TODO: Make this properly configurable! This is just a quick hack :( // See: // - PBI: https://dev.azure.com/workcloudapps/WorkCloudApps/_backlogs/backlog/WorkCloudApps%20Team/Backlog%20items/?workitem=700 // - Ticket: https://workcloud.freshdesk.com/a/tickets/10010?note=6238878382 if (!string.IsNullOrEmpty(orgKey) && orgKey.Equals("swslawyers", StringComparison.InvariantCulture)) { nonGstTaxCodeNames = new[] { "BAS Excluded", "N-T", "GST Free", "Other GST Free", "No Tax" }; } int?nonGstTaxCodeId = LookupTaxCodeId(taxCodeInfo.taxcodes, nonGstTaxCodeNames); if (nonGstTaxCodeId == null) { telemetryLogger.TrackTrace( "Couldn't determine Non-GST Tax Code when creating InfoTrack disbursement. " + "Actionstep default will be used instead.", WCASeverityLevel.Warning, new Dictionary <string, string>() { { "Non-GST Tax Code names attempted", string.Join(", ", nonGstTaxCodeNames) }, { "InfoTrack Order ID", infoTrackOrderId.ToString(CultureInfo.InvariantCulture) }, { "Actionstep org key", orgKey }, { "Actionstep matter", matterId.ToString(CultureInfo.InvariantCulture) }, { "ExecutionId", executionId.ToString() } }); } return(gstTaxCodeId, nonGstTaxCodeId); }
public Task <FirstTitlePolicyRequestFromActionstepResponse> Handle(FirstTitlePolicyRequestFromActionstepQuery request, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } // Get Actionstep matter info var tokenSetQuery = new TokenSetQuery(request.AuthenticatedUser?.Id, request.OrgKey); try { // New token refresh handling means these can run in parallel. var actionResponseTask = _actionstepService.Handle <GetActionResponse>(new GetActionRequest { ActionId = request.MatterId, TokenSetQuery = tokenSetQuery }); var actionParticipantsResponseTask = _actionstepService.Handle <ListActionParticipantsResponse>(new ListActionParticipantsRequest { ActionstepId = request.MatterId, TokenSetQuery = tokenSetQuery }); var dataCollectionRecordValuesResponseTask = _actionstepService.Handle <ListDataCollectionRecordValuesResponse>(new ListDataCollectionRecordValuesRequest { ActionstepId = request.MatterId, TokenSetQuery = tokenSetQuery, DataCollectionRecordNames = { "property", "convdet", "keydates" }, DataCollectionFieldNames = { "titleref", "lotno", "planno", "plantype", "smtdateonly", "smttime", "purprice", "ConveyType" } }); Task.WaitAll(actionResponseTask, actionParticipantsResponseTask, dataCollectionRecordValuesResponseTask); // Transform Actionstep matter info into generic WCA Conveyancing Matter type // using specific configuration for this client (to account for Actionstep // action type configuration). var wCAConveyancingMatter = _actionstepToWCAMapper.MapFromActionstepTypes( actionResponseTask.Result, actionParticipantsResponseTask.Result, dataCollectionRecordValuesResponseTask.Result); var asSourceProperty = wCAConveyancingMatter.PropertyAddresses.FirstOrDefault(); var sourceProperty = asSourceProperty == default(Domain.Conveyancing.Party) ? new FTParty() : FTParty.FromASParty(asSourceProperty); var actionstepData = new FTActionstepMatter() { Title = new FTTitle() { TitleInfoType = TitleInfoType.Reference, TitleReference = wCAConveyancingMatter.PropertyDetails.TitleReference }, SourceProperty = sourceProperty, PurchasePrice = wCAConveyancingMatter.PurchasePrice, SettlementDate = wCAConveyancingMatter.SettlementDate.ToDateTimeUnspecified() }; foreach (var buyer in wCAConveyancingMatter.Buyers) { actionstepData.Buyers.Add(FTParty.FromASParty(buyer)); } FirstTitlePolicyRequestFromActionstepResponse firstTitlePolicyRequestFromActionstepResponse = new FirstTitlePolicyRequestFromActionstepResponse { ActionstepData = actionstepData, RequestPolicyOptions = new RequestPolicyOptions() }; return(Task.FromResult(firstTitlePolicyRequestFromActionstepResponse)); } catch (UnauthorizedAccessException uax) { throw new InvalidCredentialsForActionstepApiCallException(string.Empty, uax) { ActionstepOrgKey = request.OrgKey, User = request.AuthenticatedUser, }; } }
public async Task <RequestPropertyInformationFromActionstepResponse> Handle(ConveyancingDataFromActionstepQuery request, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } // Get Actionstep matter info var tokenSetQuery = new TokenSetQuery(request.AuthenticatedUser?.Id, request.OrgKey); try { // New token refresh handling means these can run in parallel. var actionResponseTask = _actionstepService.Handle <GetActionResponse>(new GetActionRequest { ActionId = request.MatterId, TokenSetQuery = tokenSetQuery }); var actionParticipantsResponseTask = _actionstepService.Handle <ListActionParticipantsResponse>(new ListActionParticipantsRequest { ActionstepId = request.MatterId, TokenSetQuery = tokenSetQuery }); var dataCollectionRecordValuesResponseTask = _actionstepService.Handle <ListDataCollectionRecordValuesResponse>(new ListDataCollectionRecordValuesRequest { ActionstepId = request.MatterId, TokenSetQuery = tokenSetQuery, DataCollectionRecordNames = { "property", "convdet", "keydates" }, DataCollectionFieldNames = { "titleref", "lotno", "planno", "plantype", "smtdateonly", "smttime", "purprice", "ConveyType" } }); Task.WaitAll(actionResponseTask, actionParticipantsResponseTask, dataCollectionRecordValuesResponseTask); // Transform Actionstep matter info into generic WCA Conveyancing Matter type // using specific configuration for this client (to account for Actionstep // action type configuration). var wCAConveyancingMatter = _actionstepToWCAMapper.MapFromActionstepTypes( actionResponseTask.Result, actionParticipantsResponseTask.Result, dataCollectionRecordValuesResponseTask.Result); var state = State.Unknown; switch (wCAConveyancingMatter.ActionType) { case "Conveyancing - NSW": state = State.NSW; break; case "Conveyancing - Queensland": state = State.QLD; break; case "Conveyancing - Victoria": state = State.Vic; break; default: state = State.Unknown; break; } var matter = new Matter { MatterReference = request.MatterId.ToString(CultureInfo.InvariantCulture), MatterEntity = new RealProperty { TitleReference = wCAConveyancingMatter?.PropertyDetails?.TitleReference, LotPlan = new LotPlan() { Lot = wCAConveyancingMatter?.PropertyDetails?.LotNo }, } }; var version = new WCA.GlobalX.Client.Version { ModelVersion = "http://globalx.com.au/common/model/matter/2013/07/31", ApplicationName = "Konekta", ApplicationVersion = "1.0" }; var settings = new JsonSerializerSettings { SerializationBinder = new GXSerializationBinder(), TypeNameHandling = TypeNameHandling.All }; var entryPoint = string.IsNullOrEmpty(request.EntryPoint) ? "web" : request.EntryPoint; var response = new RequestPropertyInformationFromActionstepResponse { Matter = JsonConvert.SerializeObject(matter, settings), Version = JsonConvert.SerializeObject(version, settings), GXUri = new Uri(_globalXService.BaseWebUrl, $"{entryPoint}?embed={request.Embed}&state={state}") }; return(response); } catch (AggregateException ex) { if (ex.InnerExceptions.All(e => e is InvalidTokenSetException || e is InvalidCredentialsForActionstepApiCallException)) { throw ex.InnerExceptions.FirstOrDefault(); } throw; } }
public async Task <DocumentRelationship> Handle(CopyDocumentVersionToActionstepCommand request, CancellationToken cancellationToken) { if (request is null) { throw new System.ArgumentNullException(nameof(request)); } _validator.ValidateAndThrow(request); var tempFilePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); DocumentFileInfo globalXDocumentFileInfo; var tokenSetQuery = new TokenSetQuery(request.ActionstepUserId, request.ActionstepOrgKey); // Check to make sure this matter exists first. This will throw if it's not found. var matterInfo = await _actionstepService.Handle <GetActionResponse>(new GetActionRequest(tokenSetQuery, request.ActionstepMatterId)); if (matterInfo is null) { throw new InvalidActionstepMatterException($"Matter '{request.ActionstepMatterId}' was not found in Actionstep."); } try { try { globalXDocumentFileInfo = await _globalXService.DownloadDocument( request.DocumentVersion.DocumentId.Value, request.DocumentVersion.DocumentVersionId.Value, tempFilePath, request.GlobalXUserId); } catch (Exception ex) { throw new FailedToDownloadGlobalXDocumentException(ex); } try { var fileName = !string.IsNullOrEmpty(globalXDocumentFileInfo?.FileName) ? globalXDocumentFileInfo.FileName : request.DocumentVersion.DocumentName; var fileUploadResponse = await _actionstepService.UploadFile(tokenSetQuery, fileName, tempFilePath); if (fileUploadResponse is null) { throw new Exception("Unknown error uploading document to Actionstep."); } // Get all folders for matter and check to see if the specified folder exists. If it does, we need its ID. var actionFolder = new ActionFolder(request.ActionstepMatterId); var getFolderRequest = new GetActionFolderRequest(tokenSetQuery, actionFolder); var folderResponse = await _actionstepService.Handle <ListActionFolderResponse>(getFolderRequest); /// Will be null if the folder name wasn't found. In which case the document will be saved at the root of the matter. var parentFolderId = folderResponse?.ActionFolders?.FirstOrDefault(af => af.Name == ActionstepFolderFirstPreference)?.Id ?? folderResponse?.ActionFolders?.FirstOrDefault(af => af.Name == ActionstepFolderSecondPreference)?.Id; /// <see cref="ActionstepDocument"/> represents the object in "Matter Documents", as opposed to the file content from above (which is just in a big bucket). var document = new ActionDocument(request.ActionstepMatterId, fileName, fileUploadResponse, parentFolderId); var saveActionDocumentRequest = new SaveActionDocumentRequest(tokenSetQuery, document); var saveActionDocumentResponse = await _actionstepService.Handle <SaveActionDocumentResponse>(saveActionDocumentRequest); return(new DocumentRelationship( request.DocumentVersion.DocumentId.Value, request.DocumentVersion.DocumentVersionId.Value, fileName, request.DocumentVersion.MimeType, request.ActionstepOrgKey, request.ActionstepMatterId, saveActionDocumentResponse.ActionDocument.Id, new Uri(saveActionDocumentResponse.ActionDocument.SharepointUrl))); } catch (InvalidTokenSetException ex) { throw new FailedToUploadGlobalXDocumentToActionstepException( $"Invalid Actionstep Token, unable to upload document. Token revoked at '{ex.TokenSet?.RevokedAt}', Token ID '{ex.TokenSet?.Id}'.", ex); } catch (Exception ex) { throw new FailedToUploadGlobalXDocumentToActionstepException(ex.Message, ex); } } finally { if (File.Exists(tempFilePath)) { File.Delete(tempFilePath); } } }
public Task <TokenSet> GetTokenSet(TokenSetQuery tokenSetQuery) { return(Task.FromResult(TokenSets.SingleOrDefault(t => t.UserId == tokenSetQuery.UserId && t.OrgKey == tokenSetQuery.OrgKey))); }
public GetCurrentUserRequest(TokenSetQuery tokenSetQuery) { TokenSetQuery = tokenSetQuery; }
public Task <UploadFileResponse> UploadFile(TokenSetQuery tokenSetQuery, string fileName, string tempContentFilePath) { throw new NotImplementedException(); }
public async Task <bool> Handle(StorePexaWorkspaceIdInActionstepMatterCommand command, CancellationToken cancellationToken) { if (command is null) { throw new System.ArgumentNullException(nameof(command)); } var tokenSetQuery = new TokenSetQuery(command.AuthenticatedUser?.Id, command.ActionstepOrg); var actionResponse = await _actionstepService.Handle <GetActionResponse>(new GetActionRequest { TokenSetQuery = tokenSetQuery, ActionId = command.MatterId }); var convdetDataCollectionFields = await _actionstepService.Handle <ListDataCollectionFieldResponse>(new ListDataCollectionFieldsRequest { DataCollectionNames = { "convdet" }, TokenSetQuery = tokenSetQuery, ActionTypes = { actionResponse.Action.Links.ActionType } }); if (!convdetDataCollectionFields.DataCollectionFields.Exists(f => f.Name == "pexa_workspace_id")) { var createDataCollectionFieldRequest = new CreateDataCollectionFieldRequest(); var dataCollectionId = convdetDataCollectionFields.Linked.DataCollections.Single().Id; var dataCollectionField = new DataCollectionField { Id = dataCollectionId + "--pexa_workspace_id", Name = "pexa_workspace_id", DataType = "String", Label = "Pexa Workspace ID", CustomHtmlAbove = "", CustomHtmlBelow = "", Description = "", Links = new DataCollectionFieldLink { DataCollection = dataCollectionId.ToString(CultureInfo.InvariantCulture) } }; createDataCollectionFieldRequest.DataCollectionFields.Add(dataCollectionField); createDataCollectionFieldRequest.TokenSetQuery = tokenSetQuery; var listActionstepUsersRequest = new ListActionstepUsersRequest(); listActionstepUsersRequest.TokenSetQuery = tokenSetQuery; // Add a filter to get only the authorized users listActionstepUsersRequest.Filter = "hasAuthority_eq=T"; var listActionstepUsers = await _actionstepService.Handle <ListActionstepUsersResponse>(listActionstepUsersRequest); if (listActionstepUsers == null) { throw new UnauthorizedAccessException("No ActionstepCredential available to create the field!"); } var currentUser = listActionstepUsers.Users.FirstOrDefault(u => u.EmailAddress == command.AuthenticatedUser?.Email); if (currentUser == default(ActionstepUser)) { var actionstepCredential = _wCADbContext.ActionstepCredentials.FirstOrDefault(ac => ac.ActionstepOrg.Key == command.ActionstepOrg && listActionstepUsers.Users.Any(au => au.EmailAddress == ac.Owner.Email) ); if (actionstepCredential == default(ActionstepCredential)) { throw new UnauthorizedAccessException("No ActionstepCredential available to create the field!"); } var newTokenSetQuery = new TokenSetQuery(actionstepCredential.Owner.Id, command.ActionstepOrg); createDataCollectionFieldRequest.TokenSetQuery = newTokenSetQuery; } await _actionstepService.Handle(createDataCollectionFieldRequest); } var dataCollectionRecordValuesResponse = await _actionstepService.Handle <ListDataCollectionRecordValuesResponse>(new ListDataCollectionRecordValuesRequest { ActionstepId = command.MatterId, TokenSetQuery = tokenSetQuery, DataCollectionRecordNames = { "convdet" }, DataCollectionFieldNames = { "pexa_workspace_id" } }); dataCollectionRecordValuesResponse["convdet", "pexa_workspace_id"] = command.WorkspaceId; var updateDataCollectionRecordValuesRequest = new UpdateDataCollectionRecordValuesRequest(); updateDataCollectionRecordValuesRequest.TokenSetQuery = tokenSetQuery; foreach (var recordValue in dataCollectionRecordValuesResponse.DataCollectionRecordValues) { updateDataCollectionRecordValuesRequest.DataCollectionRecordValues.Add(recordValue); } await _actionstepService.Handle(updateDataCollectionRecordValuesRequest); return(true); }
public GetActionFolderRequest(TokenSetQuery tokenSetQuery, ActionFolder actionFolder) { TokenSetQuery = tokenSetQuery; ActionFolder = actionFolder; }
public async Task <string> Handle(SettlementCalculatorUrlQuery request, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } string resultUrl = string.Empty; var tokenSetQuery = new TokenSetQuery(request.AuthenticatedUser?.Id, request.OrgKey); var actionResponse = await _actionstepService.Handle <GetActionResponse>(new GetActionRequest { TokenSetQuery = tokenSetQuery, ActionId = request.MatterId }); var action = actionResponse.Action; if (actionResponse.ActionTypeName.Equals("Conveyancing - Victoria", StringComparison.OrdinalIgnoreCase)) { resultUrl += _settings.SettlementCalculatorBaseUrlVIC; } // The Konekta add-on uses "Conveyancing - NSW" // bytherules use "NSW Conveyancing" // Not using property address state as it's a free text field, to avoid issues with typos etc. else if (actionResponse.ActionTypeName.Equals("Conveyancing - NSW", StringComparison.OrdinalIgnoreCase) || actionResponse.ActionTypeName.Equals("NSW Conveyancing", StringComparison.OrdinalIgnoreCase)) { resultUrl += _settings.SettlementCalculatorBaseUrlNSW; } else { // The QLD Action Type display name is "Conveyancing - Queensland" (yes, with the double space). // The Conveyancing Action Type for BTR's org "dv4642" is just "Conveyancing". // However, we'll just fallback to QLD by default which will catch both of these and any others. resultUrl += _settings.SettlementCalculatorBaseUrlQLD; } var dataCollectionRecordValueResponse = await _actionstepService.Handle <ListDataCollectionRecordValuesResponse>(new ListDataCollectionRecordValuesRequest { TokenSetQuery = tokenSetQuery, ActionstepId = action.Id, DataCollectionRecordNames = { "property", "convdet", "keydates" }, DataCollectionFieldNames = { "lotno", "purprice", "depamount", "adjustdate", "smtdateonly", "smtven", "smttime" } }); var actionParticipantsResponse = await _actionstepService.Handle <ListActionParticipantsResponse>(new ListActionParticipantsRequest { TokenSetQuery = tokenSetQuery, ActionstepId = request.MatterId }); var settlementVenueRawValue = dataCollectionRecordValueResponse["convdet", "smtven"]; var settlementVenueString = string.Empty; if (int.TryParse(settlementVenueRawValue, out int settlementVenueParticipantId)) { var settlementVenueParticipantResponse = await _actionstepService.Handle <GetParticipantResponse>(new GetParticipantRequest { TokenSetQuery = tokenSetQuery, Id = settlementVenueParticipantId }); settlementVenueString = settlementVenueParticipantResponse?.Participant?.DisplayName; } var orgParticipantResponse = await _actionstepService.Handle <GetParticipantResponse>(new GetParticipantRequest { TokenSetQuery = tokenSetQuery, Id = 4 }); var conveyancer = actionParticipantsResponse["Conveyancer"].FirstOrDefault(); var propertyAddress = actionParticipantsResponse["Property_Address"].FirstOrDefault(); if (!resultUrl.EndsWith("/", StringComparison.OrdinalIgnoreCase)) { resultUrl += "/"; } resultUrl += $"{action.Id}_{request.OrgKey}"; resultUrl += $"?id={action.Id}_{request.OrgKey}"; resultUrl += ParamValueOrAsterisks("&matter", action.Name); resultUrl += ParamValueOrAsterisks("&address", propertyAddress?.DisplayName); resultUrl += ParseAndFormatCurrencyParam("&purprice", dataCollectionRecordValueResponse["convdet", "purprice"]); resultUrl += ParseAndFormatCurrencyParam("&depamount", dataCollectionRecordValueResponse["convdet", "depamount"]); resultUrl += ParseAndFormatDateParam("&adjustdate", dataCollectionRecordValueResponse["keydates", "adjustdate"]); resultUrl += ParseAndFormatDateParam("&settledate", dataCollectionRecordValueResponse["keydates", "smtdateonly"]); resultUrl += ParamValueOrAsterisks("&lc", conveyancer?.Email); resultUrl += ParamValueOrAsterisks("&div", orgParticipantResponse?.Participant?.CompanyName); resultUrl += ParamValueOrAsterisks("&smtloc", settlementVenueString); resultUrl += ParamValueOrAsterisks("&smttime", dataCollectionRecordValueResponse["convdet", "smttime"]); return(resultUrl); }