private static void SetLevels(KycProfile profile)
        {
            if (!profile.PhoneVerified)
            {
                profile.RequiredVerifications.Add(VerificationType.ProofOfPhone);
            }

            if (profile.KycLevel == KycLevel.Level1)
            {
                profile.RequiredVerifications.Add(VerificationType.ProofOfIdentity);
            }
            if (profile.KycLevel == KycLevel.Level2)
            {
                profile.RequiredVerifications.Add(VerificationType.ProofOfIdentity);
                profile.RequiredVerifications.Add(VerificationType.ProofOfAddress);
            }
            if (profile.KycLevel == KycLevel.Level3)
            {
                profile.RequiredVerifications.Add(VerificationType.ProofOfIdentity);
                profile.RequiredVerifications.Add(VerificationType.ProofOfAddress);
                profile.RequiredVerifications.Add(VerificationType.ProofOfFunds);
            }

            profile.RequiredVerifications = profile.RequiredVerifications.Distinct().ToList();
        }
        private async Task CheckCountry(KycProfile profile)
        {
            if (string.IsNullOrEmpty(profile.Country))
            {
                return;
            }

            var country = await _countryRepository.GetCountry(profile.Country);

            if (country == null)
            {
                profile.DepositStatus    = KycOperationStatus.Blocked;
                profile.TradeStatus      = KycOperationStatus.Blocked;
                profile.WithdrawalStatus = KycOperationStatus.Blocked;
                profile.BlockingReason   = "Country is not supported";
                return;
            }

            if (country.IsBlocked)
            {
                profile.DepositStatus    = KycOperationStatus.Blocked;
                profile.TradeStatus      = KycOperationStatus.Blocked;
                profile.WithdrawalStatus = KycOperationStatus.Blocked;
                profile.BlockingReason   = "Country is blocked";
                return;
            }
        }
        public async Task <KycProfile> GetOrCreateProfile(string clientId)
        {
            await using var context = new DatabaseContext(_dbContextOptionsBuilder.Options);
            var kycProfile = context.KycProfiles.Include(t => t.Documents).FirstOrDefault(t => t.ClientId == clientId);

            if (kycProfile != null)
            {
                return(kycProfile);
            }

            _logger.LogInformation("Profile for clientId {clientId} not found. Creating new profile", clientId);

            var profile = new KycProfile
            {
                ClientId              = clientId,
                ApplicantId           = null,
                ActiveVerificationId  = null,
                DepositStatus         = KycOperationStatus.KycRequired,
                TradeStatus           = KycOperationStatus.KycRequired,
                WithdrawalStatus      = KycOperationStatus.KycRequired,
                PhoneVerified         = false,
                RequiredVerifications = new List <VerificationType>(),
                Documents             = new List <KycDocument>(),
                KycLevel              = KycLevel.Level1,
            };

            await _statusSetter.UpdateProfileState(profile);

            await UpdateProfile(profile, "Profile creation", "automatic", null);

            return(profile);
        }
        public async Task UpdateProfileState(KycProfile profile)
        {
            SetLevels(profile);
            await CheckCountry(profile);
            await CheckDocuments(profile);

            SetStatuses(profile);
        }
 public static KycProfileNoSqlEntity Create(KycProfile profile)
 {
     return(new KycProfileNoSqlEntity()
     {
         PartitionKey = GeneratePartitionKey(),
         RowKey = GenerateRowKey(profile.ClientId),
         Profile = profile
     });
 }
        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 KycStatusResponse(string brokerId, KycProfile profile)
 {
     BrokerId               = brokerId;
     ClientId               = profile.ClientId;
     Level                  = profile.KycLevel;
     RequiredDocuments      = KycLevelHelper.GetRequiredDocuments(profile);
     RequiredVerifications  = profile.RequiredVerifications;
     DepositStatus          = profile.DepositStatus;
     WithdrawalStatus       = profile.WithdrawalStatus;
     TradeStatus            = profile.TradeStatus;
     VerificationInProgress = string.IsNullOrEmpty(profile.ActiveVerificationId);
     Pep            = profile.Pep;
     Country        = profile.Country;
     BlockingReason = profile.BlockingReason;
 }
        private async Task CheckDocuments(KycProfile profile)
        {
            if (profile.PhoneVerified)
            {
                profile.RequiredVerifications.Remove(VerificationType.ProofOfPhone);
            }

            if (!string.IsNullOrWhiteSpace(profile.Country))
            {
                var country = await _countryRepository.GetCountry(profile.Country);

                if (country == null)
                {
                    return;
                }

                if (profile.Documents.Any(document => KycLevelHelper.ProofOfIdentityTypes.Contains(document.Type) &&
                                          (country.AcceptedDocuments?.Contains(document.Type) ?? false) &&
                                          document.Verified) &&
                    profile.Documents.Any(document => document.Type == DocumentType.SelfieImage && document.Verified))
                {
                    profile.RequiredVerifications.Remove(VerificationType.ProofOfIdentity);
                }
            }
            else
            {
                if (profile.Documents.Any(document => KycLevelHelper.ProofOfIdentityTypes.Contains(document.Type) &&
                                          document.Verified) &&
                    profile.Documents.Any(document => document.Type == DocumentType.SelfieImage && document.Verified))
                {
                    profile.RequiredVerifications.Remove(VerificationType.ProofOfIdentity);
                }
            }

            if (profile.Documents.Any(document => KycLevelHelper.ProofOfAddressTypes.Contains(document.Type) && document.Verified))
            {
                profile.RequiredVerifications.Remove(VerificationType.ProofOfAddress);
            }

            if (profile.Documents.Any(document => KycLevelHelper.ProofOfFundsTypes.Contains(document.Type) && document.Verified))
            {
                profile.RequiredVerifications.Remove(VerificationType.ProofOfIdentity);
            }
        }
        private static void SetStatuses(KycProfile profile)
        {
            if (profile.DepositStatus == KycOperationStatus.Blocked ||
                profile.TradeStatus == KycOperationStatus.Blocked ||
                profile.WithdrawalStatus == KycOperationStatus.Blocked)
            {
                return;
            }

            if (profile.Pep)
            {
                profile.DepositStatus    = KycOperationStatus.Blocked;
                profile.TradeStatus      = KycOperationStatus.Blocked;
                profile.WithdrawalStatus = KycOperationStatus.Blocked;
                profile.BlockingReason   = "User identified as PEP";
                return;
            }

            if (!string.IsNullOrEmpty(profile.ActiveVerificationId))
            {
                profile.DepositStatus    = KycOperationStatus.KycInProgress;
                profile.TradeStatus      = KycOperationStatus.KycInProgress;
                profile.WithdrawalStatus = KycOperationStatus.KycInProgress;
                return;
            }

            if (profile.RequiredVerifications.Contains(VerificationType.ProofOfIdentity) ||
                profile.RequiredVerifications.Contains(VerificationType.ProofOfPhone))
            {
                profile.DepositStatus    = KycOperationStatus.KycRequired;
                profile.TradeStatus      = KycOperationStatus.KycRequired;
                profile.WithdrawalStatus = KycOperationStatus.KycRequired;
            }
            else
            {
                profile.DepositStatus    = KycOperationStatus.Allowed;
                profile.TradeStatus      = KycOperationStatus.Allowed;
                profile.WithdrawalStatus = KycOperationStatus.Allowed;
            }
        }