Exemplo n.º 1
0
        public async Task <LimitationCheckResult> CheckCashOperationLimitAsync(
            string clientId,
            string assetId,
            double amount,
            CurrencyOperationType currencyOperationType)
        {
            var originalAsset  = assetId;
            var originalAmount = amount;

            amount = Math.Abs(amount);

            if (currencyOperationType == CurrencyOperationType.CryptoCashOut)
            {
                var asset = _assets.Get(assetId);

                if (amount < asset.CashoutMinimalAmount)
                {
                    var minimalAmount = asset.CashoutMinimalAmount.GetFixedAsString(asset.Accuracy).TrimEnd('0');

                    return(new LimitationCheckResult {
                        IsValid = false, FailMessage = $"The minimum amount to cash out is {minimalAmount}"
                    });
                }

                if (asset.LowVolumeAmount.HasValue && amount < asset.LowVolumeAmount)
                {
                    var settings = await _limitSettingsRepository.GetAsync();

                    var timeout     = TimeSpan.FromMinutes(settings.LowCashOutTimeoutMins);
                    var callHistory = await _callTimeLimitsRepository.GetCallHistoryAsync("CashOutOperation", clientId, timeout);

                    var cashoutEnabled = !callHistory.Any() || callHistory.IsCallEnabled(timeout, settings.LowCashOutLimit);

                    if (!cashoutEnabled)
                    {
                        return new LimitationCheckResult {
                                   IsValid = false, FailMessage = "You have exceeded cash out operations limit. Please try again later."
                        }
                    }
                    ;
                }
            }

            if (currencyOperationType == CurrencyOperationType.SwiftTransferOut)
            {
                var error = await CheckSwiftWithdrawLimitations(assetId, (decimal)amount);

                if (error != null)
                {
                    return(new LimitationCheckResult {
                        IsValid = false, FailMessage = error
                    });
                }
            }

            if (currencyOperationType != CurrencyOperationType.CryptoCashIn &&
                currencyOperationType != CurrencyOperationType.CryptoCashOut)
            {
                (assetId, amount) = await _currencyConverter.ConvertAsync(
                    assetId,
                    _currencyConverter.DefaultAsset,
                    amount);
            }

            var limitationTypes = LimitMapHelper.MapOperationType(currencyOperationType);
            var typeLimits      = _limits.Where(l => limitationTypes.Contains(l.LimitationType)).ToList();

            if (!typeLimits.Any())
            {
                try
                {
                    await _limitOperationsApi.AddOperationAttemptAsync(
                        clientId,
                        originalAsset,
                        originalAmount,
                        currencyOperationType == CurrencyOperationType.CardCashIn
                        ?CashOperationsTimeoutInMinutes
                        : _attemptRetainInMinutes,
                        currencyOperationType);
                }
                catch (Exception ex)
                {
                    _log.Error(ex, context: new { Type = "Attempt", clientId, originalAmount, originalAsset });
                }
                return(new LimitationCheckResult {
                    IsValid = true
                });
            }

            //To handle parallel request
            await _lock.WaitAsync();

            try
            {
                var    assetLimits = typeLimits.Where(l => l.Asset == assetId).ToList();
                string error       = await DoPeriodCheckAsync(
                    assetLimits,
                    LimitationPeriod.Month,
                    clientId,
                    assetId,
                    amount,
                    currencyOperationType,
                    false);

                if (error != null)
                {
                    return new LimitationCheckResult {
                               IsValid = false, FailMessage = error
                    }
                }
                ;

                error = await DoPeriodCheckAsync(
                    assetLimits,
                    LimitationPeriod.Day,
                    clientId,
                    assetId,
                    amount,
                    currencyOperationType,
                    false);

                if (error != null)
                {
                    return new LimitationCheckResult {
                               IsValid = false, FailMessage = error
                    }
                }
                ;

                if (currencyOperationType == CurrencyOperationType.CryptoCashOut)
                {
                    assetLimits = typeLimits.Where(l => l.Asset == _currencyConverter.DefaultAsset).ToList();

                    var(assetTo, convertedAmount) = await _currencyConverter.ConvertAsync(
                        assetId,
                        _currencyConverter.DefaultAsset,
                        amount,
                        true);

                    error = await DoPeriodCheckAsync(
                        assetLimits,
                        LimitationPeriod.Month,
                        clientId,
                        assetTo,
                        convertedAmount,
                        currencyOperationType,
                        true);

                    if (error != null)
                    {
                        return new LimitationCheckResult {
                                   IsValid = false, FailMessage = error
                        }
                    }
                    ;

                    error = await DoPeriodCheckAsync(
                        assetLimits,
                        LimitationPeriod.Day,
                        clientId,
                        assetTo,
                        convertedAmount,
                        currencyOperationType,
                        true);

                    if (error != null)
                    {
                        return new LimitationCheckResult {
                                   IsValid = false, FailMessage = error
                        }
                    }
                    ;
                }

                try
                {
                    await _limitOperationsApi.AddOperationAttemptAsync(
                        clientId,
                        originalAsset,
                        originalAmount,
                        currencyOperationType == CurrencyOperationType.CardCashIn
                        ?CashOperationsTimeoutInMinutes
                        : _attemptRetainInMinutes,
                        currencyOperationType);
                }
                catch (Exception ex)
                {
                    _log.Error(ex, context: new { Type = "Attempt", clientId, originalAmount, originalAsset });
                }
            }
            finally
            {
                _lock.Release();
            }

            return(new LimitationCheckResult {
                IsValid = true
            });
        }