| | 1 | | using Application.Abstractions; |
| | 2 | | using Application.Currencies.ConvertCurrency.Dtos; |
| | 3 | | using Domain.Common; |
| | 4 | | using Domain.Currencies; |
| | 5 | | using MediatR; |
| | 6 | | using Microsoft.Extensions.Logging; |
| | 7 | |
|
| | 8 | | namespace Application.Currencies.ConvertCurrency |
| | 9 | | { |
| | 10 | | public class ConvertCurrencyHandler : IRequestHandler<ConvertCurrencyQuery, Result<ConvertCurrencyResultDto>> |
| | 11 | | { |
| | 12 | | private readonly IExchangeProviderFactory _exchangeFactory; |
| | 13 | | private readonly ILogger<ConvertCurrencyHandler> _logger; |
| | 14 | | private readonly ICacheService _cacheService; |
| | 15 | |
|
| 21 | 16 | | public ConvertCurrencyHandler(IExchangeProviderFactory exchangeFactory, |
| 21 | 17 | | ILogger<ConvertCurrencyHandler> logger, |
| 21 | 18 | | ICacheService cacheService) |
| 21 | 19 | | { |
| 21 | 20 | | _cacheService = cacheService; |
| 21 | 21 | | _exchangeFactory = exchangeFactory; |
| 21 | 22 | | _logger = logger; |
| 21 | 23 | | } |
| | 24 | |
|
| | 25 | | public async Task<Result<ConvertCurrencyResultDto>> Handle(ConvertCurrencyQuery command, CancellationToken cance |
| 21 | 26 | | { |
| 21 | 27 | | var targetCurrencyCodeResult = CurrencyCode.FromCode(command.TargetCurrencyCode); |
| 21 | 28 | | if (targetCurrencyCodeResult.IsFailure) |
| 1 | 29 | | { |
| 1 | 30 | | return Result.Failure<ConvertCurrencyResultDto>(targetCurrencyCodeResult.Error); |
| | 31 | | } |
| 20 | 32 | | var targetCode = targetCurrencyCodeResult.Value; |
| | 33 | |
|
| 20 | 34 | | if (!CurrencySnapshot.IsLegalConversion(targetCode)) |
| 4 | 35 | | { |
| 4 | 36 | | return Result.Failure<ConvertCurrencyResultDto>(new Error(ErrorCode.BadInput, $"{command.TargetCurrencyC |
| | 37 | | } |
| | 38 | |
|
| 16 | 39 | | var baseCurrencyCodeResult = CurrencyCode.FromCode(command.BaseCurrencyCode); |
| 16 | 40 | | if (baseCurrencyCodeResult.IsFailure) |
| 1 | 41 | | { |
| 1 | 42 | | return Result.Failure<ConvertCurrencyResultDto>(baseCurrencyCodeResult.Error); |
| | 43 | | } |
| 15 | 44 | | var baseCode = baseCurrencyCodeResult.Value; |
| | 45 | |
|
| 15 | 46 | | var exchangeProvider = _exchangeFactory.GetProvider(ExchangeProviderType.Frankfurter); |
| 15 | 47 | | if (exchangeProvider == null) |
| 1 | 48 | | { |
| 1 | 49 | | _logger.LogError("Could not find an exchange provider, {requestedProvider}", ExchangeProviderType.Frankf |
| 1 | 50 | | return Result.Failure<ConvertCurrencyResultDto>(Error.SystemError); |
| | 51 | | } |
| 14 | 52 | | var cacheKey = $"latest-{baseCode.Value}"; |
| 14 | 53 | | var currencySnapShot = await _cacheService.GetAsync<CurrencySnapshot>(cacheKey, cancellationToken); |
| 14 | 54 | | if (currencySnapShot == null) |
| 12 | 55 | | { |
| 12 | 56 | | var result = await exchangeProvider.FindLatestAsync(baseCode); |
| 12 | 57 | | if (result.IsFailure) |
| 1 | 58 | | { |
| 1 | 59 | | return Result.Failure<ConvertCurrencyResultDto>(result.Error); |
| | 60 | | } |
| 11 | 61 | | currencySnapShot = result.Value; |
| 11 | 62 | | await _cacheService.SetAsync(cacheKey, currencySnapShot, cancellationToken); |
| 11 | 63 | | } |
| 13 | 64 | | var conversionResult = currencySnapShot.Convert(command.BaseAmount, targetCode); |
| 13 | 65 | | if (conversionResult.IsFailure) |
| 1 | 66 | | { |
| 1 | 67 | | return Result.Failure<ConvertCurrencyResultDto>(conversionResult.Error); |
| | 68 | | } |
| 12 | 69 | | return new ConvertCurrencyResultDto(currencySnapShot.DateCaptured, |
| 12 | 70 | | conversionResult.Value.Code.Value, |
| 12 | 71 | | conversionResult.Value.Amount); |
| 21 | 72 | | } |
| | 73 | | } |
| | 74 | | } |