public async Task UpdateProfile(KycProfile profile, string operation, string agent, string comment) { await using var context = new DatabaseContext(_dbContextOptionsBuilder.Options); await context.UpsertAsync(new[] { profile }); await _cache.InsertOrReplaceAsync(KycProfileNoSqlEntity.Create(profile)); await _cache.CleanAndKeepMaxRecords(KycProfileNoSqlEntity.GeneratePartitionKey(), 10000); context.AuditLogs.Add(KycAuditLog.Create(profile, operation, agent, comment)); await context.SaveChangesAsync(); }
public async Task <OperationResponse> UploadDocument(UploadDocumentRequest request) { try { _logger.LogInformation("Uploading documents with type {type} for client {clientId}", request.Type, request.ClientId); var profile = await _repository.GetOrCreateProfile(request.ClientId); if (string.IsNullOrEmpty(profile.ApplicantId)) { _logger.LogInformation("Creating applicant id for client {clientId}", request.ClientId); profile.ApplicantId = await _httpService.CreateApplicantId(request.ClientId); await _repository.UpdateProfile(profile, "Created applicant id", "automatic", null); } var existingDocumentId = profile.Documents.FirstOrDefault(t => t.Type == request.Type)?.DocumentId; var(documentId, file1, file2) = await _httpService.UploadDocument(profile.ApplicantId, request.FileSide1, request.FileSide2, request.Type, request.FileType, existingDocumentId); await using var context = new DatabaseContext(_dbContextOptionsBuilder.Options); var document = new KycDocument() { DocumentId = documentId, ClientId = profile.ClientId, Type = request.Type, FileId1 = file1, FileId2 = file2, Verified = false, DeclineReason = string.Empty }; await context.UpsertAsync(new[] { document }); context.AuditLogs.Add(KycAuditLog.Create(document, "Document upload", "automatic", null)); await context.SaveChangesAsync(); return(new OperationResponse() { IsSuccess = true }); } catch (Exception e) { _logger.LogError(e, "When uploading document for clientId {clientId}", request.ClientId); return(new OperationResponse() { IsSuccess = false, Error = e.Message }); } }
private async ValueTask HandleEvents(KycVerificationResultMessage message) { try { _logger.LogInformation( "Verification {verificationId} is finished. Result {result}. ApplicantId {applicantId}", message.VerificationId, message.Verified, message.ApplicantId); var profile = await _repository.GetProfileByApplicantId(message.ApplicantId); if (profile == null) { _logger.LogWarning( "Received verification for applicant without profile. Applicant id {applicantId}; Client {clientId}", message.ApplicantId, message.ExternalApplicantId); return; } var applicantResponse = await _kycAidHttpService.GetApplicant(message.ApplicantId); if (applicantResponse == null) { _logger.LogWarning( "Unable to get applicant data from KycAid. Applicant id {applicantId}; Client {clientId}", message.ApplicantId, message.ExternalApplicantId); return; } var existingUsers = new List <PersonalDataGrpcModel>(); if (DateTime.TryParse(applicantResponse.DateOfBirth, out var dateBirth) && !string.IsNullOrEmpty(applicantResponse.FirstName) && !string.IsNullOrEmpty(applicantResponse.LastName)) { var existingUsersResp = await _personalData.SearchAsync(new SearchRequest() { SearchText = applicantResponse.LastName }); existingUsers = (existingUsersResp.PersonalDatas ?? new List <PersonalDataGrpcModel>()) .Where(e => e.DateOfBirth == dateBirth && e.FirstName == applicantResponse.FirstName && e.LastName == applicantResponse.LastName && e.Id != applicantResponse.ExternalApplicantId) .ToList(); } var oldProfile = (KycProfile)profile.Clone(); var updatedDocs = new List <KycDocument>(); foreach (var documentCheck in applicantResponse.Documents) { var document = profile.Documents.FirstOrDefault(t => t.DocumentId == documentCheck.DocumentId); if (document != null) { document.Verified = documentCheck.Status == "valid"; document.DeclineReason = String.Join(", ", documentCheck.DeclineReasons); updatedDocs.Add(document); } } await using var context = new DatabaseContext(_dbContextOptionsBuilder.Options); await context.UpsertAsync(new List <Verification>(){ new Verification { VerificationId = message.VerificationId, ClientId = profile.ClientId, Status = applicantResponse.Status, Verified = applicantResponse.Verified, DocumentResults = applicantResponse.Documents.ToDictionary(t => t.DocumentId, t => new VerificationResult { Verified = t.Status == "valid", Comment = t.Comment, DeclineReasons = String.Join(", ", t.DeclineReasons), DocumentType = t.Type }) } }); if (updatedDocs.Any()) { await context.UpsertAsync(updatedDocs); context.AuditLogs.AddRange(updatedDocs.Select(doc => KycAuditLog.Create(doc, $"Verification {message.VerificationId}", "automatic", null))); await context.SaveChangesAsync(); } profile.ActiveVerificationId = String.Empty; if (Boolean.TryParse(applicantResponse.Pep, out var pep)) { profile.Pep = pep; } profile.Country = applicantResponse.ResidenceCountry; await _statusSetter.UpdateProfileState(profile); if (existingUsers.Any()) { profile.DepositStatus = KycOperationStatus.Blocked; profile.TradeStatus = KycOperationStatus.Blocked; profile.WithdrawalStatus = KycOperationStatus.Blocked; profile.BlockingReason = "Client has same First name, Last name and DataBirth with another clients"; var report = new AddClientCommentRequest() { ClientId = profile.ClientId, ManagerId = "KYC service", Text = "Client KYC Blocked Deposit, Trade, Withdrawal because user has same First name, Last name and DataBirth with another clients: " }; foreach (var user in existingUsers) { report.Text += $"{user.Id}, "; } await _clientCommentsService.AddAsync(report); } await _repository.UpdateProfile(profile, "Verification result received", "automatic", null); await _publisher.PublishAsync(new KycProfileUpdatedMessage() { ClientId = profile.ClientId, OldProfile = oldProfile, NewProfile = profile }); var request = new UpdatePersonalDataGrpcContract { Id = profile.ClientId, FirstName = applicantResponse.FirstName, LastName = applicantResponse.LastName, CountryOfResidence = applicantResponse.ResidenceCountry, City = applicantResponse.Addresses?.FirstOrDefault()?.City, PostalCode = applicantResponse.Addresses?.FirstOrDefault()?.PostalCode, AuditLog = new AuditLogGrpcContract { TraderId = profile.ClientId, ServiceName = "Service.KYC", ProcessId = Guid.NewGuid().ToString("N"), Context = $"KYC Verification {message.VerificationId}" }, Address = $"{applicantResponse.Addresses?.FirstOrDefault()?.StreetName}, {applicantResponse.Addresses?.FirstOrDefault()?.BuildingNumber}, unit: {applicantResponse.Addresses?.FirstOrDefault()?.UnitNumber}", }; if (DateTime.TryParse(applicantResponse.DateOfBirth, out var dob)) { request.DateOfBirth = dob; } var response = await _personalData.UpdateAsync(request); _logger.LogInformation("Updating personal data. Update result: {result}", response.Ok); } catch (Exception e) { _logger.LogError(e, "When handling message about verification {verificationId}", message.VerificationId); throw; } }