fix: exchange method fixes
This commit is contained in:
parent
c87bcc8b54
commit
71109174f7
2 changed files with 73 additions and 13 deletions
|
@ -9,6 +9,8 @@ import eu.ztsh.wymiana.web.model.CurrencyExchangeRequest;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -35,8 +37,13 @@ public class CurrencyService {
|
||||||
}
|
}
|
||||||
// End: unlock other currencies
|
// End: unlock other currencies
|
||||||
|
|
||||||
var exchanged = performExchange(user.currencies().get(request.from().toUpperCase()),
|
var from = user.currencies().get(request.from().toUpperCase());
|
||||||
user.currencies().get(request.to().toUpperCase()),
|
if (from == null) {
|
||||||
|
// There is no currency 'from' opened so no need to check if user has funds to exchange
|
||||||
|
throw new InsufficientFundsException();
|
||||||
|
}
|
||||||
|
var exchanged = performExchange(from,
|
||||||
|
Optional.ofNullable(user.currencies().get(request.to().toUpperCase())).orElse(create(request.to())),
|
||||||
Optional.ofNullable(request.toSell()).orElse(0D),
|
Optional.ofNullable(request.toSell()).orElse(0D),
|
||||||
Optional.ofNullable(request.toBuy()).orElse(0D));
|
Optional.ofNullable(request.toBuy()).orElse(0D));
|
||||||
user.currencies().putAll(exchanged);
|
user.currencies().putAll(exchanged);
|
||||||
|
@ -45,18 +52,23 @@ public class CurrencyService {
|
||||||
.orElseThrow(ExchangeFailedException::new);
|
.orElseThrow(ExchangeFailedException::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Currency create(String symbol) {
|
||||||
|
// TODO: check if supported
|
||||||
|
return new Currency(symbol.toUpperCase(), 0D);
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, Currency> performExchange(Currency from, Currency to, double toSell, double toBuy) {
|
private Map<String, Currency> performExchange(Currency from, Currency to, double toSell, double toBuy) {
|
||||||
double exchangeRate;
|
double exchangeRate;
|
||||||
double neededFromAmount;
|
double neededFromAmount;
|
||||||
double requestedToAmount;
|
double requestedToAmount;
|
||||||
if (from.symbol().equalsIgnoreCase("PLN")) {
|
if (from.symbol().equalsIgnoreCase("PLN")) {
|
||||||
exchangeRate = nbpService.getSellRate(to.symbol());
|
exchangeRate = nbpService.getSellRate(to.symbol());
|
||||||
neededFromAmount = toBuy != 0 ? toBuy * exchangeRate : toSell;
|
neededFromAmount = round(toBuy != 0 ? toBuy * exchangeRate : toSell);
|
||||||
requestedToAmount = toBuy != 0 ? toBuy : toSell / exchangeRate;
|
requestedToAmount = round(toBuy != 0 ? toBuy : toSell / exchangeRate);
|
||||||
} else {
|
} else {
|
||||||
exchangeRate = nbpService.getSellRate(from.symbol());
|
exchangeRate = nbpService.getBuyRate(from.symbol());
|
||||||
neededFromAmount = toBuy != 0 ? toBuy / exchangeRate : toSell;
|
neededFromAmount = round(toBuy != 0 ? toBuy / exchangeRate : toSell);
|
||||||
requestedToAmount = toBuy != 0 ? toBuy : toSell * exchangeRate;
|
requestedToAmount = round(toBuy != 0 ? toBuy : toSell * exchangeRate);
|
||||||
}
|
}
|
||||||
if (neededFromAmount > from.amount()) {
|
if (neededFromAmount > from.amount()) {
|
||||||
throw new InsufficientFundsException();
|
throw new InsufficientFundsException();
|
||||||
|
@ -66,4 +78,8 @@ public class CurrencyService {
|
||||||
return Stream.of(newFrom, newTo).collect(Collectors.toMap(Currency::symbol, currency -> currency));
|
return Stream.of(newFrom, newTo).collect(Collectors.toMap(Currency::symbol, currency -> currency));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private double round(double input) {
|
||||||
|
return BigDecimal.valueOf(input).setScale(2, RoundingMode.HALF_UP).doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@ class CurrencyServiceTest extends RepositoryBasedTest {
|
||||||
public CurrencyServiceTest(UserRepository userRepository, InstanceValidator instanceValidator) {
|
public CurrencyServiceTest(UserRepository userRepository, InstanceValidator instanceValidator) {
|
||||||
super(userRepository);
|
super(userRepository);
|
||||||
var nbp = Mockito.mock(NbpService.class);
|
var nbp = Mockito.mock(NbpService.class);
|
||||||
Mockito.when(nbp.getSellRate("USD")).thenReturn(USD_SELL);
|
Mockito.when(nbp.getSellRate("USD")).thenReturn(SELL_RATE);
|
||||||
Mockito.when(nbp.getBuyRate("USD")).thenReturn(USD_BUY);
|
Mockito.when(nbp.getBuyRate("USD")).thenReturn(BUY_RATE);
|
||||||
currencyService = new CurrencyService(new UserService(userRepository, instanceValidator), nbp, instanceValidator);
|
currencyService = new CurrencyService(new UserService(userRepository, instanceValidator), nbp, instanceValidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,10 +65,11 @@ class CurrencyServiceTest extends RepositoryBasedTest {
|
||||||
var expected = EntityCreator.user().pln(0).usd(USD_BUY).build();
|
var expected = EntityCreator.user().pln(0).usd(USD_BUY).build();
|
||||||
expect(expected);
|
expect(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Test
|
@Test
|
||||||
void usdToPlnToSellSuccessTest() {
|
void usdToPlnToSellSuccessTest() {
|
||||||
var entity = EntityCreator.user().build();
|
var entity = EntityCreator.user().pln(0).usd(USD_SELL).build();
|
||||||
userRepository.save(entity);
|
userRepository.save(entity);
|
||||||
var result = currencyService.exchange(EntityCreator.exchangeRequest()
|
var result = currencyService.exchange(EntityCreator.exchangeRequest()
|
||||||
.from(USD_SYMBOL)
|
.from(USD_SYMBOL)
|
||||||
|
@ -84,7 +85,7 @@ class CurrencyServiceTest extends RepositoryBasedTest {
|
||||||
@Transactional
|
@Transactional
|
||||||
@Test
|
@Test
|
||||||
void usdToPlnToBuySuccessTest() {
|
void usdToPlnToBuySuccessTest() {
|
||||||
var entity = EntityCreator.user().build();
|
var entity = EntityCreator.user().pln(0).usd(USD_SELL).build();
|
||||||
userRepository.save(entity);
|
userRepository.save(entity);
|
||||||
var result = currencyService.exchange(EntityCreator.exchangeRequest()
|
var result = currencyService.exchange(EntityCreator.exchangeRequest()
|
||||||
.from(USD_SYMBOL)
|
.from(USD_SYMBOL)
|
||||||
|
@ -97,14 +98,57 @@ class CurrencyServiceTest extends RepositoryBasedTest {
|
||||||
expect(expected);
|
expect(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Test
|
||||||
|
void usdToPlnNoUsdCurrencyTest() {
|
||||||
|
var entity = EntityCreator.user().build();
|
||||||
|
userRepository.save(entity);
|
||||||
|
var request = EntityCreator.exchangeRequest()
|
||||||
|
.from(USD_SYMBOL)
|
||||||
|
.to(PLN_SYMBOL)
|
||||||
|
.toBuy(PLN)
|
||||||
|
.build();
|
||||||
|
assertThatThrownBy(() -> currencyService.exchange(request))
|
||||||
|
.isInstanceOf(InsufficientFundsException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Test
|
||||||
|
void doubleExchangeTest() {
|
||||||
|
var initialValue = 100;
|
||||||
|
var entity = EntityCreator.user().pln(initialValue).build();
|
||||||
|
userRepository.save(entity);
|
||||||
|
var result1 = currencyService.exchange(EntityCreator.exchangeRequest()
|
||||||
|
.from(PLN_SYMBOL)
|
||||||
|
.to(USD_SYMBOL)
|
||||||
|
.toBuy(USD_BUY)
|
||||||
|
.build());
|
||||||
|
var result2 = currencyService.exchange(EntityCreator.exchangeRequest()
|
||||||
|
.from(USD_SYMBOL)
|
||||||
|
.to(PLN_SYMBOL)
|
||||||
|
.toSell(USD_BUY)
|
||||||
|
.build());
|
||||||
|
var resultOptional = userRepository.findById(entity.getPesel());
|
||||||
|
assertThat(resultOptional)
|
||||||
|
.isNotEmpty();
|
||||||
|
var resultEntity = resultOptional.get();
|
||||||
|
assertThat(resultEntity.getCurrencies()
|
||||||
|
.stream()
|
||||||
|
.filter(c -> c.getSymbol().equalsIgnoreCase("PLN"))
|
||||||
|
.findFirst()).isNotEmpty().get().matches(currencyEntity -> currencyEntity.getAmount() < initialValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
@Test
|
@Test
|
||||||
void insufficientFundsTest() {
|
void insufficientFundsTest() {
|
||||||
var entity = EntityCreator.exchangeRequest()
|
var entity = EntityCreator.user().build();
|
||||||
|
userRepository.save(entity);
|
||||||
|
var request = EntityCreator.exchangeRequest()
|
||||||
.from(PLN_SYMBOL)
|
.from(PLN_SYMBOL)
|
||||||
.to(USD_SYMBOL)
|
.to(USD_SYMBOL)
|
||||||
.toBuy(PLN)
|
.toBuy(PLN)
|
||||||
.build();
|
.build();
|
||||||
assertThatThrownBy(() -> currencyService.exchange(entity))
|
assertThatThrownBy(() -> currencyService.exchange(request))
|
||||||
.isInstanceOf(InsufficientFundsException.class);
|
.isInstanceOf(InsufficientFundsException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue