Added better currency and exchange information.

This commit is contained in:
Andrew Lalis 2022-02-10 14:48:06 +01:00
parent c643475f45
commit 5ffe9b3a84
8 changed files with 127 additions and 11 deletions

View File

@ -5,6 +5,9 @@ import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import javax.persistence.*; import javax.persistence.*;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
@ -31,5 +34,11 @@ public class Account {
@OneToMany(mappedBy = "account", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) @OneToMany(mappedBy = "account", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Balance> balances; private Set<Balance> balances;
public Map<Currency, BigDecimal> getMappedBalances() {
Map<Currency, BigDecimal> b = new HashMap<>();
for (var bal : getBalances()) {
b.put(bal.getCurrency(), bal.getAmount());
}
return b;
}
} }

View File

@ -19,6 +19,6 @@ public class Balance {
@ManyToOne(optional = false, fetch = FetchType.EAGER) @ManyToOne(optional = false, fetch = FetchType.EAGER)
private Currency currency; private Currency currency;
@Column(nullable = false, precision = 24, scale = 4) @Column(nullable = false, precision = 24, scale = 10)
private BigDecimal amount; private BigDecimal amount;
} }

View File

@ -3,6 +3,7 @@ package nl.andrewl.coyotecredit.model;
import lombok.Getter; import lombok.Getter;
import javax.persistence.*; import javax.persistence.*;
import java.util.Objects;
/** /**
* Represents a type of currency. This can be an actual fiat currency, or * Represents a type of currency. This can be an actual fiat currency, or
@ -10,6 +11,7 @@ import javax.persistence.*;
* exchange. * exchange.
*/ */
@Entity @Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"identifier", "type"}))
@Getter @Getter
public class Currency { public class Currency {
@Id @Id
@ -19,9 +21,28 @@ public class Currency {
@Column(nullable = false) @Column(nullable = false)
private String identifier; private String identifier;
@Enumerated(EnumType.STRING)
private CurrencyType type;
@Column(nullable = false) @Column(nullable = false)
private String name; private String name;
@Column @Column
private String description; private String description;
@Column(nullable = false)
private float minDenomination = 0.01f;
@Override
public boolean equals(Object other) {
if (!(other instanceof Currency c)) return false;
if (c.getId() != null && this.getId() != null) return this.getId().equals(c.getId());
return this.identifier.equals(c.getIdentifier()) &&
this.type.equals(c.getType());
}
@Override
public int hashCode() {
return Objects.hash(this.identifier, this.type);
}
} }

View File

@ -0,0 +1,7 @@
package nl.andrewl.coyotecredit.model;
public enum CurrencyType {
FIAT,
CRYPTO,
STOCK
}

View File

@ -3,6 +3,7 @@ package nl.andrewl.coyotecredit.model;
import lombok.Getter; import lombok.Getter;
import javax.persistence.*; import javax.persistence.*;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
/** /**
@ -21,11 +22,15 @@ public class Exchange {
@Column(nullable = false) @Column(nullable = false)
private String name; private String name;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @OneToMany(mappedBy = "exchange")
@JoinTable( private Set<ExchangePair> currencyPairs;
name = "exchange_supported_currency",
joinColumns = @JoinColumn(name = "currency_id"), public Set<Currency> getSupportedCurrencies() {
inverseJoinColumns = @JoinColumn(name = "exchange_id") Set<Currency> currencies = new HashSet<>();
) for (var pair : getCurrencyPairs()) {
private Set<Currency> supportedCurrencies; currencies.add(pair.getFromCurrency());
currencies.add(pair.getToCurrency());
}
return currencies;
}
} }

View File

@ -0,0 +1,30 @@
package nl.andrewl.coyotecredit.model;
import lombok.Getter;
import javax.persistence.*;
import java.math.BigDecimal;
/**
* Represents a pair of currencies that can be exchanged at a set exchange rate.
*/
@Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"from_currency_id", "to_currency_id", "exchange_id"}))
@Getter
public class ExchangePair {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)
private Exchange exchange;
@ManyToOne(optional = false)
private Currency fromCurrency;
@ManyToOne(optional = false)
private Currency toCurrency;
@Column(nullable = false, precision = 24, scale = 10)
private BigDecimal exchangeRate = new BigDecimal("1.0");
}

View File

@ -1,5 +1,6 @@
package nl.andrewl.coyotecredit.service; package nl.andrewl.coyotecredit.service;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import nl.andrewl.coyotecredit.dao.AccountRepository; import nl.andrewl.coyotecredit.dao.AccountRepository;
import nl.andrewl.coyotecredit.model.Account; import nl.andrewl.coyotecredit.model.Account;
@ -9,6 +10,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException; import org.springframework.web.server.ResponseStatusException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
@Service @Service
@ -29,13 +31,36 @@ public class AccountService {
.toList(); .toList();
} }
public static class FullAccountData {
public long id;
public String number;
public String exchangeName;
public List<BalanceData> balances;
}
@AllArgsConstructor
public static class BalanceData {
public String currencyIdentifier;
public String amount;
}
@Transactional(readOnly = true) @Transactional(readOnly = true)
public AccountData getAccountData(User user, long accountId) { public FullAccountData getAccountData(User user, long accountId) {
Account account = accountRepository.findById(accountId) Account account = accountRepository.findById(accountId)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
if (!account.getUser().getId().equals(user.getId())) { if (!account.getUser().getId().equals(user.getId())) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND); throw new ResponseStatusException(HttpStatus.NOT_FOUND);
} }
return new AccountData(account.getId(), account.getNumber(), account.getExchange().getName()); FullAccountData d = new FullAccountData();
d.id = account.getId();
d.number = account.getNumber();
d.exchangeName = account.getExchange().getName();
List<BalanceData> balanceData = new ArrayList<>();
for (var bal : account.getBalances()) {
balanceData.add(new BalanceData(bal.getCurrency().getIdentifier(), bal.getAmount().toPlainString()));
}
d.balances = balanceData;
return d;
} }
} }

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html
lang="en"
xmlns:th="http://www.thymeleaf.org"
>
<head>
<title>CC - Account</title>
</head>
<body>
<h1>Account <span th:text="${account.number}"></span></h1>
<h3>Balance</h3>
<ul>
<li th:each="balance : ${account.balances}">
<span th:text="${balance.currencyIdentifier}"></span> - <span th:text="${balance.amount}"></span>
</li>
</ul>
</body>