Added account filter to transactions list.
This commit is contained in:
parent
8539ddec70
commit
9e0e0a51c5
|
@ -5,21 +5,26 @@ import com.andrewlalis.perfin.data.pagination.Page;
|
|||
import com.andrewlalis.perfin.data.pagination.PageRequest;
|
||||
import com.andrewlalis.perfin.data.pagination.Sort;
|
||||
import com.andrewlalis.perfin.data.util.Pair;
|
||||
import com.andrewlalis.perfin.model.Account;
|
||||
import com.andrewlalis.perfin.model.Profile;
|
||||
import com.andrewlalis.perfin.model.Transaction;
|
||||
import com.andrewlalis.perfin.view.AccountComboBoxCellFactory;
|
||||
import com.andrewlalis.perfin.view.SceneUtil;
|
||||
import com.andrewlalis.perfin.view.component.DataSourcePaginationControls;
|
||||
import com.andrewlalis.perfin.view.component.TransactionTile;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.andrewlalis.perfin.PerfinApp.router;
|
||||
|
||||
|
@ -35,6 +40,7 @@ public class TransactionsViewController implements RouteSelectionListener {
|
|||
public record RouteContext(Long selectedTransactionId) {}
|
||||
|
||||
@FXML public BorderPane transactionsListBorderPane;
|
||||
@FXML public ComboBox<Account> filterByAccountComboBox;
|
||||
@FXML public VBox transactionsVBox;
|
||||
private DataSourcePaginationControls paginationControls;
|
||||
|
||||
|
@ -44,20 +50,40 @@ public class TransactionsViewController implements RouteSelectionListener {
|
|||
|
||||
@FXML public void initialize() {
|
||||
// Initialize the left-hand paginated transactions list.
|
||||
var accountCellFactory = new AccountComboBoxCellFactory("All");
|
||||
filterByAccountComboBox.setCellFactory(accountCellFactory);
|
||||
filterByAccountComboBox.setButtonCell(accountCellFactory.call(null));
|
||||
filterByAccountComboBox.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
paginationControls.setPage(1);
|
||||
selectedTransaction.set(null);
|
||||
});
|
||||
|
||||
this.paginationControls = new DataSourcePaginationControls(
|
||||
transactionsVBox.getChildren(),
|
||||
new DataSourcePaginationControls.PageFetcherFunction() {
|
||||
@Override
|
||||
public Page<? extends Node> fetchPage(PageRequest pagination) throws Exception {
|
||||
Account accountFilter = filterByAccountComboBox.getValue();
|
||||
try (var repo = Profile.getCurrent().getDataSource().getTransactionRepository()) {
|
||||
return repo.findAll(pagination).map(TransactionsViewController.this::makeTile);
|
||||
Page<Transaction> result;
|
||||
if (accountFilter == null) {
|
||||
result = repo.findAll(pagination);
|
||||
} else {
|
||||
result = repo.findAllByAccounts(Set.of(accountFilter.id), pagination);
|
||||
}
|
||||
return result.map(TransactionsViewController.this::makeTile);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalCount() throws Exception {
|
||||
Account accountFilter = filterByAccountComboBox.getValue();
|
||||
try (var repo = Profile.getCurrent().getDataSource().getTransactionRepository()) {
|
||||
return (int) repo.countAll();
|
||||
if (accountFilter == null) {
|
||||
return (int) repo.countAll();
|
||||
} else {
|
||||
return (int) repo.countAllByAccounts(Set.of(accountFilter.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,6 +121,21 @@ public class TransactionsViewController implements RouteSelectionListener {
|
|||
paginationControls.sorts.setAll(DEFAULT_SORTS);
|
||||
paginationControls.itemsPerPage.set(DEFAULT_ITEMS_PER_PAGE);
|
||||
|
||||
// Refresh account filter options.
|
||||
Thread.ofVirtual().start(() -> {
|
||||
Profile.getCurrent().getDataSource().useAccountRepository(repo -> {
|
||||
List<Account> accounts = repo.findAll(PageRequest.unpaged(Sort.asc("name"))).items();
|
||||
accounts.add(null);
|
||||
Platform.runLater(() -> {
|
||||
filterByAccountComboBox.getItems().clear();
|
||||
filterByAccountComboBox.getItems().addAll(accounts);
|
||||
filterByAccountComboBox.getSelectionModel().selectLast();
|
||||
filterByAccountComboBox.getButtonCell().updateIndex(accounts.size() - 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// If a transaction id is given in the route context, navigate to the page it's on and select it.
|
||||
if (context instanceof RouteContext ctx && ctx.selectedTransactionId != null) {
|
||||
Thread.ofVirtual().start(() -> {
|
||||
|
@ -108,6 +149,7 @@ public class TransactionsViewController implements RouteSelectionListener {
|
|||
});
|
||||
} else {
|
||||
paginationControls.setPage(1);
|
||||
selectedTransaction.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ public interface TransactionRepository extends AutoCloseable {
|
|||
Page<Transaction> findAll(PageRequest pagination);
|
||||
long countAll();
|
||||
long countAllAfter(long transactionId);
|
||||
long countAllByAccounts(Set<Long> accountIds);
|
||||
Page<Transaction> findAllByAccounts(Set<Long> accountIds, PageRequest pagination);
|
||||
CreditAndDebitAccounts findLinkedAccounts(long transactionId);
|
||||
List<Attachment> findAttachments(long transactionId);
|
||||
|
|
|
@ -82,6 +82,18 @@ public record JdbcTransactionRepository(Connection conn, Path contentDir) implem
|
|||
).orElse(0L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countAllByAccounts(Set<Long> accountIds) {
|
||||
String idsStr = accountIds.stream().map(String::valueOf).collect(Collectors.joining(","));
|
||||
String query = String.format("""
|
||||
SELECT COUNT(transaction.id)
|
||||
FROM transaction
|
||||
LEFT JOIN account_entry ON account_entry.transaction_id = transaction.id
|
||||
WHERE account_entry.account_id IN (%s)
|
||||
""", idsStr);
|
||||
return DbUtil.findOne(conn, query, Collections.emptyList(), rs -> rs.getLong(1)).orElse(0L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Transaction> findAllByAccounts(Set<Long> accountIds, PageRequest pagination) {
|
||||
String idsStr = accountIds.stream().map(String::valueOf).collect(Collectors.joining(","));
|
||||
|
|
|
@ -7,10 +7,22 @@ import javafx.scene.control.ListView;
|
|||
import javafx.util.Callback;
|
||||
|
||||
public class AccountComboBoxCellFactory implements Callback<ListView<Account>, ListCell<Account>> {
|
||||
private final String emptyCellText;
|
||||
|
||||
public AccountComboBoxCellFactory(String emptyCellText) {
|
||||
this.emptyCellText = emptyCellText;
|
||||
}
|
||||
|
||||
public AccountComboBoxCellFactory() {
|
||||
this("None");
|
||||
}
|
||||
|
||||
public static class AccountListCell extends ListCell<Account> {
|
||||
private final Label label = new Label();
|
||||
private final String emptyCellText;
|
||||
|
||||
public AccountListCell() {
|
||||
public AccountListCell(String emptyCellText) {
|
||||
this.emptyCellText = emptyCellText;
|
||||
label.setStyle("-fx-text-fill: black;");
|
||||
}
|
||||
|
||||
|
@ -18,7 +30,7 @@ public class AccountComboBoxCellFactory implements Callback<ListView<Account>, L
|
|||
protected void updateItem(Account item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item == null || empty) {
|
||||
label.setText("None");
|
||||
label.setText(emptyCellText);
|
||||
} else {
|
||||
label.setText(item.getName() + " (" + item.getAccountNumberSuffix() + ")");
|
||||
}
|
||||
|
@ -28,6 +40,6 @@ public class AccountComboBoxCellFactory implements Callback<ListView<Account>, L
|
|||
|
||||
@Override
|
||||
public ListCell<Account> call(ListView<Account> param) {
|
||||
return new AccountListCell();
|
||||
return new AccountListCell(emptyCellText);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import com.andrewlalis.perfin.view.component.PropertiesPane?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ComboBox?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.ScrollPane?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<BorderPane xmlns="http://javafx.com/javafx"
|
||||
|
@ -15,6 +18,14 @@
|
|||
<center>
|
||||
<HBox>
|
||||
<BorderPane fx:id="transactionsListBorderPane" HBox.hgrow="ALWAYS">
|
||||
<top>
|
||||
<HBox styleClass="std-padding,std-spacing">
|
||||
<PropertiesPane hgap="5" vgap="5">
|
||||
<Label text="Filter by Account"/>
|
||||
<ComboBox fx:id="filterByAccountComboBox"/>
|
||||
</PropertiesPane>
|
||||
</HBox>
|
||||
</top>
|
||||
<center>
|
||||
<ScrollPane fitToHeight="true" fitToWidth="true">
|
||||
<VBox fx:id="transactionsVBox" styleClass="std-padding,spacing-extra"/>
|
||||
|
|
Loading…
Reference in New Issue