diff --git a/src/main/java/nl/andrewl/coyotecredit/model/Account.java b/src/main/java/nl/andrewl/coyotecredit/model/Account.java index f018934..62e35aa 100644 --- a/src/main/java/nl/andrewl/coyotecredit/model/Account.java +++ b/src/main/java/nl/andrewl/coyotecredit/model/Account.java @@ -5,6 +5,9 @@ import lombok.Getter; import lombok.NoArgsConstructor; import javax.persistence.*; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; import java.util.Set; /** @@ -31,5 +34,11 @@ public class Account { @OneToMany(mappedBy = "account", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) private Set balances; - + public Map getMappedBalances() { + Map b = new HashMap<>(); + for (var bal : getBalances()) { + b.put(bal.getCurrency(), bal.getAmount()); + } + return b; + } } diff --git a/src/main/java/nl/andrewl/coyotecredit/model/Balance.java b/src/main/java/nl/andrewl/coyotecredit/model/Balance.java index 8f3d8a7..cfb4f93 100644 --- a/src/main/java/nl/andrewl/coyotecredit/model/Balance.java +++ b/src/main/java/nl/andrewl/coyotecredit/model/Balance.java @@ -19,6 +19,6 @@ public class Balance { @ManyToOne(optional = false, fetch = FetchType.EAGER) private Currency currency; - @Column(nullable = false, precision = 24, scale = 4) + @Column(nullable = false, precision = 24, scale = 10) private BigDecimal amount; } diff --git a/src/main/java/nl/andrewl/coyotecredit/model/Currency.java b/src/main/java/nl/andrewl/coyotecredit/model/Currency.java index 59436dc..8dc2f00 100644 --- a/src/main/java/nl/andrewl/coyotecredit/model/Currency.java +++ b/src/main/java/nl/andrewl/coyotecredit/model/Currency.java @@ -3,6 +3,7 @@ package nl.andrewl.coyotecredit.model; import lombok.Getter; import javax.persistence.*; +import java.util.Objects; /** * Represents a type of currency. This can be an actual fiat currency, or @@ -10,6 +11,7 @@ import javax.persistence.*; * exchange. */ @Entity +@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"identifier", "type"})) @Getter public class Currency { @Id @@ -19,9 +21,28 @@ public class Currency { @Column(nullable = false) private String identifier; + @Enumerated(EnumType.STRING) + private CurrencyType type; + @Column(nullable = false) private String name; @Column 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); + } } diff --git a/src/main/java/nl/andrewl/coyotecredit/model/CurrencyType.java b/src/main/java/nl/andrewl/coyotecredit/model/CurrencyType.java new file mode 100644 index 0000000..31a4644 --- /dev/null +++ b/src/main/java/nl/andrewl/coyotecredit/model/CurrencyType.java @@ -0,0 +1,7 @@ +package nl.andrewl.coyotecredit.model; + +public enum CurrencyType { + FIAT, + CRYPTO, + STOCK +} diff --git a/src/main/java/nl/andrewl/coyotecredit/model/Exchange.java b/src/main/java/nl/andrewl/coyotecredit/model/Exchange.java index a0428af..c42590c 100644 --- a/src/main/java/nl/andrewl/coyotecredit/model/Exchange.java +++ b/src/main/java/nl/andrewl/coyotecredit/model/Exchange.java @@ -3,6 +3,7 @@ package nl.andrewl.coyotecredit.model; import lombok.Getter; import javax.persistence.*; +import java.util.HashSet; import java.util.Set; /** @@ -21,11 +22,15 @@ public class Exchange { @Column(nullable = false) private String name; - @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL) - @JoinTable( - name = "exchange_supported_currency", - joinColumns = @JoinColumn(name = "currency_id"), - inverseJoinColumns = @JoinColumn(name = "exchange_id") - ) - private Set supportedCurrencies; + @OneToMany(mappedBy = "exchange") + private Set currencyPairs; + + public Set getSupportedCurrencies() { + Set currencies = new HashSet<>(); + for (var pair : getCurrencyPairs()) { + currencies.add(pair.getFromCurrency()); + currencies.add(pair.getToCurrency()); + } + return currencies; + } } diff --git a/src/main/java/nl/andrewl/coyotecredit/model/ExchangePair.java b/src/main/java/nl/andrewl/coyotecredit/model/ExchangePair.java new file mode 100644 index 0000000..bd1491c --- /dev/null +++ b/src/main/java/nl/andrewl/coyotecredit/model/ExchangePair.java @@ -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"); +} diff --git a/src/main/java/nl/andrewl/coyotecredit/service/AccountService.java b/src/main/java/nl/andrewl/coyotecredit/service/AccountService.java index 271b0fd..d6c349d 100644 --- a/src/main/java/nl/andrewl/coyotecredit/service/AccountService.java +++ b/src/main/java/nl/andrewl/coyotecredit/service/AccountService.java @@ -1,5 +1,6 @@ package nl.andrewl.coyotecredit.service; +import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; import nl.andrewl.coyotecredit.dao.AccountRepository; import nl.andrewl.coyotecredit.model.Account; @@ -9,6 +10,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.server.ResponseStatusException; +import java.util.ArrayList; import java.util.List; @Service @@ -29,13 +31,36 @@ public class AccountService { .toList(); } + public static class FullAccountData { + public long id; + public String number; + public String exchangeName; + public List balances; + } + + @AllArgsConstructor + public static class BalanceData { + public String currencyIdentifier; + public String amount; + } + @Transactional(readOnly = true) - public AccountData getAccountData(User user, long accountId) { + public FullAccountData getAccountData(User user, long accountId) { Account account = accountRepository.findById(accountId) .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + if (!account.getUser().getId().equals(user.getId())) { 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 = new ArrayList<>(); + for (var bal : account.getBalances()) { + balanceData.add(new BalanceData(bal.getCurrency().getIdentifier(), bal.getAmount().toPlainString())); + } + d.balances = balanceData; + return d; } } diff --git a/src/main/resources/templates/account.html b/src/main/resources/templates/account.html new file mode 100644 index 0000000..de0c6c1 --- /dev/null +++ b/src/main/resources/templates/account.html @@ -0,0 +1,19 @@ + + + + CC - Account + + + +

Account

+ +

Balance

+
    +
  • + - +
  • +
+ \ No newline at end of file