diff --git a/pom.xml b/pom.xml
index 4b5bbcb..fd79a14 100644
--- a/pom.xml
+++ b/pom.xml
@@ -57,6 +57,12 @@
5.10.0
test
+
+ org.junit.jupiter
+ junit-jupiter-params
+ 5.10.0
+ test
+
org.junit.jupiter
junit-jupiter-engine
diff --git a/src/main/java/com/andrewlalis/perfin/data/util/CurrencyUtil.java b/src/main/java/com/andrewlalis/perfin/data/util/CurrencyUtil.java
index 010482e..44a1fde 100644
--- a/src/main/java/com/andrewlalis/perfin/data/util/CurrencyUtil.java
+++ b/src/main/java/com/andrewlalis/perfin/data/util/CurrencyUtil.java
@@ -5,10 +5,12 @@ import com.andrewlalis.perfin.model.MoneyValue;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
+import java.util.Locale;
public class CurrencyUtil {
public static String formatMoney(MoneyValue money) {
- NumberFormat nf = NumberFormat.getCurrencyInstance();
+ // TODO: Use locale-dependent formatting.
+ NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.US);
nf.setCurrency(money.currency());
nf.setMaximumFractionDigits(money.currency().getDefaultFractionDigits());
nf.setMinimumFractionDigits(money.currency().getDefaultFractionDigits());
diff --git a/src/main/java/com/andrewlalis/perfin/model/MoneyValue.java b/src/main/java/com/andrewlalis/perfin/model/MoneyValue.java
index 1115bc5..09f9030 100644
--- a/src/main/java/com/andrewlalis/perfin/model/MoneyValue.java
+++ b/src/main/java/com/andrewlalis/perfin/model/MoneyValue.java
@@ -8,4 +8,8 @@ import java.util.Currency;
* @param amount The amount of money.
* @param currency The currency of the money.
*/
-public record MoneyValue(BigDecimal amount, Currency currency) {}
+public record MoneyValue(BigDecimal amount, Currency currency) {
+ public static MoneyValue from(String amountStr, String currencyCode) {
+ return new MoneyValue(new BigDecimal(amountStr), Currency.getInstance(currencyCode));
+ }
+}
diff --git a/src/main/java/com/andrewlalis/perfin/model/history/AccountHistoryItem.java b/src/main/java/com/andrewlalis/perfin/model/history/AccountHistoryItem.java
index 4d1e4e1..565452e 100644
--- a/src/main/java/com/andrewlalis/perfin/model/history/AccountHistoryItem.java
+++ b/src/main/java/com/andrewlalis/perfin/model/history/AccountHistoryItem.java
@@ -1,5 +1,7 @@
package com.andrewlalis.perfin.model.history;
+import com.andrewlalis.perfin.model.IdEntity;
+
import java.time.LocalDateTime;
/**
@@ -8,23 +10,18 @@ import java.time.LocalDateTime;
* what exactly it means, and could be something like an account entry, balance
* record, or modifications to the account's properties.
*/
-public class AccountHistoryItem {
- private final long id;
+public class AccountHistoryItem extends IdEntity {
private final LocalDateTime timestamp;
private final long accountId;
private final AccountHistoryItemType type;
public AccountHistoryItem(long id, LocalDateTime timestamp, long accountId, AccountHistoryItemType type) {
- this.id = id;
+ super(id);
this.timestamp = timestamp;
this.accountId = accountId;
this.type = type;
}
- public long getId() {
- return id;
- }
-
public LocalDateTime getTimestamp() {
return timestamp;
}
diff --git a/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryAccountEntryTile.java b/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryAccountEntryTile.java
index 20b01c1..d78d42c 100644
--- a/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryAccountEntryTile.java
+++ b/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryAccountEntryTile.java
@@ -14,7 +14,7 @@ import static com.andrewlalis.perfin.PerfinApp.router;
public class AccountHistoryAccountEntryTile extends AccountHistoryItemTile {
public AccountHistoryAccountEntryTile(AccountHistoryItem item, AccountHistoryItemRepository repo) {
super(item);
- AccountEntry entry = repo.getAccountEntryItem(item.getId());
+ AccountEntry entry = repo.getAccountEntryItem(item.id);
if (entry == null) {
setCenter(new TextFlow(new Text("Deleted account entry because of deleted transaction.")));
return;
diff --git a/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryBalanceRecordTile.java b/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryBalanceRecordTile.java
index 8d11d31..c9f3c04 100644
--- a/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryBalanceRecordTile.java
+++ b/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryBalanceRecordTile.java
@@ -15,7 +15,7 @@ import javafx.scene.text.TextFlow;
public class AccountHistoryBalanceRecordTile extends AccountHistoryItemTile {
public AccountHistoryBalanceRecordTile(AccountHistoryItem item, AccountHistoryItemRepository repo, AccountViewController controller) {
super(item);
- BalanceRecord balanceRecord = repo.getBalanceRecordItem(item.getId());
+ BalanceRecord balanceRecord = repo.getBalanceRecordItem(item.id);
if (balanceRecord == null) {
setCenter(new TextFlow(new Text("Deleted balance record was added.")));
return;
diff --git a/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryTextTile.java b/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryTextTile.java
index 1fecb55..22f6c7d 100644
--- a/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryTextTile.java
+++ b/src/main/java/com/andrewlalis/perfin/view/component/AccountHistoryTextTile.java
@@ -8,7 +8,7 @@ import javafx.scene.text.TextFlow;
public class AccountHistoryTextTile extends AccountHistoryItemTile {
public AccountHistoryTextTile(AccountHistoryItem item, AccountHistoryItemRepository repo) {
super(item);
- String text = repo.getTextItem(item.getId());
+ String text = repo.getTextItem(item.id);
setCenter(new TextFlow(new Text(text)));
}
}
diff --git a/src/test/java/com/andrewlalis/perfin/data/pagination/PageRequestTest.java b/src/test/java/com/andrewlalis/perfin/data/pagination/PageRequestTest.java
new file mode 100644
index 0000000..2b06066
--- /dev/null
+++ b/src/test/java/com/andrewlalis/perfin/data/pagination/PageRequestTest.java
@@ -0,0 +1,28 @@
+package com.andrewlalis.perfin.data.pagination;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class PageRequestTest {
+ @Test
+ public void testToSQL() {
+ assertEquals("LIMIT 5 OFFSET 0", PageRequest.of(0, 5).toSQL());
+ assertEquals("LIMIT 5 OFFSET 5", PageRequest.of(1, 5).toSQL());
+ assertEquals("LIMIT 10 OFFSET 0", PageRequest.of(0, 10).toSQL());
+ assertEquals("LIMIT 10 OFFSET 20", PageRequest.of(2, 10).toSQL());
+ assertEquals("LIMIT 10 OFFSET 30", PageRequest.of(2, 10).next().toSQL());
+ assertEquals("LIMIT 10 OFFSET 10", PageRequest.of(2, 10).previous().toSQL());
+ assertEquals(
+ "ORDER BY id DESC LIMIT 5 OFFSET 0",
+ PageRequest.of(0, 5, Sort.desc("id")).toSQL()
+ );
+ assertEquals(
+ "ORDER BY timestamp DESC, name ASC LIMIT 10 OFFSET 30",
+ PageRequest.of(3, 10, Sort.desc("timestamp"), Sort.asc("name")).toSQL()
+ );
+ assertEquals("", PageRequest.unpaged().toSQL());
+ assertEquals("ORDER BY id ASC", PageRequest.unpaged(Sort.asc("id")).toSQL());
+
+ }
+}
diff --git a/src/test/java/com/andrewlalis/perfin/data/pagination/SortTest.java b/src/test/java/com/andrewlalis/perfin/data/pagination/SortTest.java
new file mode 100644
index 0000000..a32ce97
--- /dev/null
+++ b/src/test/java/com/andrewlalis/perfin/data/pagination/SortTest.java
@@ -0,0 +1,13 @@
+package com.andrewlalis.perfin.data.pagination;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class SortTest {
+ @Test
+ public void testToSQL() {
+ assertEquals("date ASC", Sort.asc("date").toSQL());
+ assertEquals("id DESC", Sort.desc("id").toSQL());
+ }
+}
diff --git a/src/test/java/com/andrewlalis/perfin/data/util/CurrencyUtilTest.java b/src/test/java/com/andrewlalis/perfin/data/util/CurrencyUtilTest.java
new file mode 100644
index 0000000..a6dc734
--- /dev/null
+++ b/src/test/java/com/andrewlalis/perfin/data/util/CurrencyUtilTest.java
@@ -0,0 +1,39 @@
+package com.andrewlalis.perfin.data.util;
+
+import com.andrewlalis.perfin.model.MoneyValue;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class CurrencyUtilTest {
+ @ParameterizedTest
+ @MethodSource("testFormatMoneyParams")
+ public void testFormatMoney(MoneyValue money, String expectedFormat) {
+ assertEquals(expectedFormat, CurrencyUtil.formatMoney(money));
+ }
+
+ static Stream testFormatMoneyParams() {
+ return Stream.of(
+ Arguments.of(MoneyValue.from("1.23", "USD"), "$1.23"),
+ Arguments.of(MoneyValue.from("1000", "USD"), "$1,000.00"),
+ Arguments.of(MoneyValue.from("10000", "USD"), "$10,000.00"),
+ Arguments.of(MoneyValue.from("0", "USD"), "$0.00"),
+ Arguments.of(MoneyValue.from("-4.213", "USD"), "-$4.21"),
+ Arguments.of(MoneyValue.from("5.6781", "USD"), "$5.68"),
+ Arguments.of(MoneyValue.from("1.23", "EUR"), "€1.23"),
+ Arguments.of(MoneyValue.from("212331", "JPY"), "¥212,331")
+ );
+ }
+
+ @Test
+ public void testFormatMoneyAsBasicNumber() {
+ assertEquals("1.23", CurrencyUtil.formatMoneyAsBasicNumber(MoneyValue.from("1.23", "USD")));
+ assertEquals("5438", CurrencyUtil.formatMoneyAsBasicNumber(MoneyValue.from("5438.213", "JPY")));
+ assertEquals("0.00", CurrencyUtil.formatMoneyAsBasicNumber(MoneyValue.from("0", "USD")));
+ }
+}
diff --git a/src/test/java/com/andrewlalis/perfin/model/AccountEntryTest.java b/src/test/java/com/andrewlalis/perfin/model/AccountEntryTest.java
new file mode 100644
index 0000000..1310884
--- /dev/null
+++ b/src/test/java/com/andrewlalis/perfin/model/AccountEntryTest.java
@@ -0,0 +1,37 @@
+package com.andrewlalis.perfin.model;
+
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.Currency;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class AccountEntryTest {
+ @Test
+ public void testGetEffectiveValue() {
+ // Debit entry on various accounts.
+ AccountEntry debitEntry = getMockEntry(new BigDecimal("3.14"), AccountEntry.Type.DEBIT);
+ assertEquals(new BigDecimal("3.14"), debitEntry.getEffectiveValue(AccountType.CHECKING));
+ assertEquals(new BigDecimal("3.14"), debitEntry.getEffectiveValue(AccountType.SAVINGS));
+ assertEquals(new BigDecimal("-3.14"), debitEntry.getEffectiveValue(AccountType.CREDIT_CARD));
+
+ AccountEntry creditEntry = getMockEntry(new BigDecimal("1.23"), AccountEntry.Type.CREDIT);
+ assertEquals(new BigDecimal("-1.23"), creditEntry.getEffectiveValue(AccountType.CHECKING));
+ assertEquals(new BigDecimal("-1.23"), creditEntry.getEffectiveValue(AccountType.SAVINGS));
+ assertEquals(new BigDecimal("1.23"), creditEntry.getEffectiveValue(AccountType.CREDIT_CARD));
+ }
+
+ private AccountEntry getMockEntry(BigDecimal amount, AccountEntry.Type type) {
+ return new AccountEntry(
+ 1,
+ LocalDateTime.of(2024, 1, 4, 9, 56),
+ 1,
+ 1,
+ amount,
+ type,
+ Currency.getInstance("USD")
+ );
+ }
+}