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
                });
            }
        }
Ejemplo n.º 3
0
        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;
            }
        }