Fixed account editing.
This commit is contained in:
parent
807259b2a5
commit
abf132ec99
|
@ -1,8 +1,10 @@
|
||||||
package com.andrewlalis.perfin.control;
|
package com.andrewlalis.perfin.control;
|
||||||
|
|
||||||
import com.andrewlalis.javafx_scene_router.RouteSelectionListener;
|
import com.andrewlalis.javafx_scene_router.RouteSelectionListener;
|
||||||
|
import com.andrewlalis.perfin.data.util.CurrencyUtil;
|
||||||
import com.andrewlalis.perfin.model.Account;
|
import com.andrewlalis.perfin.model.Account;
|
||||||
import com.andrewlalis.perfin.model.AccountType;
|
import com.andrewlalis.perfin.model.AccountType;
|
||||||
|
import com.andrewlalis.perfin.model.MoneyValue;
|
||||||
import com.andrewlalis.perfin.model.Profile;
|
import com.andrewlalis.perfin.model.Profile;
|
||||||
import com.andrewlalis.perfin.view.component.PropertiesPane;
|
import com.andrewlalis.perfin.view.component.PropertiesPane;
|
||||||
import com.andrewlalis.perfin.view.component.validation.ValidationApplier;
|
import com.andrewlalis.perfin.view.component.validation.ValidationApplier;
|
||||||
|
@ -52,20 +54,20 @@ public class EditAccountController implements RouteSelectionListener {
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
var nameValid = new ValidationApplier<>(new PredicateValidator<String>()
|
var nameValid = new ValidationApplier<>(new PredicateValidator<String>()
|
||||||
.addTerminalPredicate(s -> s != null && !s.isBlank(), "Name should not be empty.")
|
.addTerminalPredicate(s -> s != null && !s.isBlank(), "Name should not be empty.")
|
||||||
.addPredicate(s -> s.length() <= 63, "Name is too long.")
|
.addPredicate(s -> s.strip().length() <= 63, "Name is too long.")
|
||||||
).attachToTextField(accountNameField);
|
).attachToTextField(accountNameField);
|
||||||
|
|
||||||
var numberValid = new ValidationApplier<>(new PredicateValidator<String>()
|
var numberValid = new ValidationApplier<>(new PredicateValidator<String>()
|
||||||
.addTerminalPredicate(s -> s != null && !s.isBlank(), "Account number should not be empty.")
|
.addTerminalPredicate(s -> s != null && !s.isBlank(), "Account number should not be empty.")
|
||||||
.addPredicate(s -> s.length() <= 255, "Account number is too long.")
|
.addPredicate(s -> s.strip().length() <= 255, "Account number is too long.")
|
||||||
).attachToTextField(accountNumberField);
|
).attachToTextField(accountNumberField);
|
||||||
|
|
||||||
var balanceValid = new ValidationApplier<>(
|
var balanceValid = new ValidationApplier<>(
|
||||||
new CurrencyAmountValidator(() -> accountCurrencyComboBox.getValue(), false, false)
|
new CurrencyAmountValidator(() -> accountCurrencyComboBox.getValue(), true, false)
|
||||||
).attachToTextField(initialBalanceField, accountCurrencyComboBox.valueProperty());
|
).attachToTextField(initialBalanceField, accountCurrencyComboBox.valueProperty());
|
||||||
|
|
||||||
// Combine validity of all fields for an expression that determines if the whole form is valid.
|
// Combine validity of all fields for an expression that determines if the whole form is valid.
|
||||||
BooleanExpression formValid = nameValid.and(numberValid).and(balanceValid);
|
BooleanExpression formValid = nameValid.and(numberValid).and(balanceValid.or(creatingNewAccount.not()));
|
||||||
saveButton.disableProperty().bind(formValid.not());
|
saveButton.disableProperty().bind(formValid.not());
|
||||||
|
|
||||||
List<Currency> priorityCurrencies = Stream.of("USD", "EUR", "GBP", "CAD", "AUD")
|
List<Currency> priorityCurrencies = Stream.of("USD", "EUR", "GBP", "CAD", "AUD")
|
||||||
|
@ -104,34 +106,35 @@ public class EditAccountController implements RouteSelectionListener {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void save() {
|
public void save() {
|
||||||
|
String name = accountNameField.getText().strip();
|
||||||
|
String number = accountNumberField.getText().strip();
|
||||||
|
AccountType type = accountTypeChoiceBox.getValue();
|
||||||
|
Currency currency = accountCurrencyComboBox.getValue();
|
||||||
try (
|
try (
|
||||||
var accountRepo = Profile.getCurrent().dataSource().getAccountRepository();
|
var accountRepo = Profile.getCurrent().dataSource().getAccountRepository();
|
||||||
var balanceRepo = Profile.getCurrent().dataSource().getBalanceRecordRepository()
|
var balanceRepo = Profile.getCurrent().dataSource().getBalanceRecordRepository()
|
||||||
) {
|
) {
|
||||||
if (creatingNewAccount.get()) {
|
if (creatingNewAccount.get()) {
|
||||||
String name = accountNameField.getText().strip();
|
|
||||||
String number = accountNumberField.getText().strip();
|
|
||||||
AccountType type = accountTypeChoiceBox.getValue();
|
|
||||||
Currency currency = accountCurrencyComboBox.getValue();
|
|
||||||
BigDecimal initialBalance = new BigDecimal(initialBalanceField.getText().strip());
|
BigDecimal initialBalance = new BigDecimal(initialBalanceField.getText().strip());
|
||||||
List<Path> attachments = Collections.emptyList();
|
List<Path> attachments = Collections.emptyList();
|
||||||
|
|
||||||
boolean success = Popups.confirm(accountNameField, "Are you sure you want to create this account?");
|
String prompt = String.format(
|
||||||
|
"Are you sure you want to create this account?\nName: %s\nNumber: %s\nType: %s\nInitial Balance: %s",
|
||||||
|
name,
|
||||||
|
number,
|
||||||
|
type.toString(),
|
||||||
|
CurrencyUtil.formatMoneyWithCurrencyPrefix(new MoneyValue(initialBalance, currency))
|
||||||
|
);
|
||||||
|
boolean success = Popups.confirm(accountNameField, prompt);
|
||||||
if (success) {
|
if (success) {
|
||||||
long id = accountRepo.insert(type, number, name, currency);
|
long id = accountRepo.insert(type, number, name, currency);
|
||||||
balanceRepo.insert(LocalDateTime.now(ZoneOffset.UTC), id, initialBalance, currency, attachments);
|
balanceRepo.insert(LocalDateTime.now(ZoneOffset.UTC), id, initialBalance, currency, attachments);
|
||||||
|
|
||||||
// Once we create the new account, go to the account.
|
// Once we create the new account, go to the account.
|
||||||
Account newAccount = accountRepo.findById(id).orElseThrow();
|
Account newAccount = accountRepo.findById(id).orElseThrow();
|
||||||
router.replace("account", newAccount);
|
router.replace("account", newAccount);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.debug("Updating account {}", account.id);
|
accountRepo.update(account.id, type, number, name, currency);
|
||||||
account.setName(accountNameField.getText().strip());
|
|
||||||
account.setAccountNumber(accountNumberField.getText().strip());
|
|
||||||
account.setType(accountTypeChoiceBox.getValue());
|
|
||||||
account.setCurrency(accountCurrencyComboBox.getValue());
|
|
||||||
accountRepo.update(account);
|
|
||||||
Account updatedAccount = accountRepo.findById(account.id).orElseThrow();
|
Account updatedAccount = accountRepo.findById(account.id).orElseThrow();
|
||||||
router.replace("account", updatedAccount);
|
router.replace("account", updatedAccount);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,7 @@ public interface AccountRepository extends Repository, AutoCloseable {
|
||||||
List<Account> findTopNRecentlyActive(int n, int daysSinceLastActive);
|
List<Account> findTopNRecentlyActive(int n, int daysSinceLastActive);
|
||||||
List<Account> findAllByCurrency(Currency currency);
|
List<Account> findAllByCurrency(Currency currency);
|
||||||
Optional<Account> findById(long id);
|
Optional<Account> findById(long id);
|
||||||
void updateName(long id, String name);
|
void update(long accountId, AccountType type, String accountNumber, String name, Currency currency);
|
||||||
void update(Account account);
|
|
||||||
void delete(Account account);
|
void delete(Account account);
|
||||||
void archive(long accountId);
|
void archive(long accountId);
|
||||||
void unarchive(long accountId);
|
void unarchive(long accountId);
|
||||||
|
|
|
@ -113,11 +113,6 @@ public record JdbcAccountRepository(Connection conn, Path contentDir) implements
|
||||||
return DbUtil.findById(conn, "SELECT * FROM account WHERE id = ?", id, JdbcAccountRepository::parseAccount);
|
return DbUtil.findById(conn, "SELECT * FROM account WHERE id = ?", id, JdbcAccountRepository::parseAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateName(long id, String name) {
|
|
||||||
DbUtil.updateOne(conn, "UPDATE account SET name = ? WHERE id = ? AND NOT archived", List.of(name, id));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BigDecimal deriveBalance(long accountId, Instant timestamp) {
|
public BigDecimal deriveBalance(long accountId, Instant timestamp) {
|
||||||
// First find the account itself, since its properties influence the balance.
|
// First find the account itself, since its properties influence the balance.
|
||||||
|
@ -215,18 +210,33 @@ public record JdbcAccountRepository(Connection conn, Path contentDir) implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(Account account) {
|
public void update(long accountId, AccountType type, String accountNumber, String name, Currency currency) {
|
||||||
DbUtil.updateOne(
|
DbUtil.doTransaction(conn, () -> {
|
||||||
conn,
|
Account account = findById(accountId).orElse(null);
|
||||||
"UPDATE account SET name = ?, account_number = ?, currency = ?, account_type = ? WHERE id = ?",
|
if (account == null) return;
|
||||||
List.of(
|
List<String> updateMessages = new ArrayList<>();
|
||||||
account.getName(),
|
if (account.getType() != type) {
|
||||||
account.getAccountNumber(),
|
DbUtil.updateOne(conn, "UPDATE account SET account_type = ? WHERE id = ?", type, accountId);
|
||||||
account.getCurrency().getCurrencyCode(),
|
updateMessages.add(String.format("Updated account type from %s to %s.", account.getType().toString(), type.toString()));
|
||||||
account.getType().name(),
|
}
|
||||||
account.id
|
if (!account.getAccountNumber().equals(accountNumber)) {
|
||||||
)
|
DbUtil.updateOne(conn, "UPDATE account SET account_number = ? WHERE id = ?", accountNumber, accountId);
|
||||||
);
|
updateMessages.add(String.format("Updated account number from %s to %s.", account.getAccountNumber(), accountNumber));
|
||||||
|
}
|
||||||
|
if (!account.getName().equals(name)) {
|
||||||
|
DbUtil.updateOne(conn, "UPDATE account SET name = ? WHERE id = ?", name, accountId);
|
||||||
|
updateMessages.add(String.format("Updated account name from \"%s\" to \"%s\".", account.getName(), name));
|
||||||
|
}
|
||||||
|
if (account.getCurrency() != currency) {
|
||||||
|
DbUtil.updateOne(conn, "UPDATE account SET currency = ? WHERE id = ?", currency.getCurrencyCode(), accountId);
|
||||||
|
updateMessages.add(String.format("Updated account currency from %s to %s.", account.getCurrency(), currency));
|
||||||
|
}
|
||||||
|
if (!updateMessages.isEmpty()) {
|
||||||
|
var historyRepo = new JdbcHistoryRepository(conn);
|
||||||
|
long historyId = historyRepo.getOrCreateHistoryForAccount(accountId);
|
||||||
|
historyRepo.addTextItem(historyId, String.join("\n", updateMessages));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -11,10 +11,10 @@ public class Account extends IdEntity {
|
||||||
private final LocalDateTime createdAt;
|
private final LocalDateTime createdAt;
|
||||||
private final boolean archived;
|
private final boolean archived;
|
||||||
|
|
||||||
private AccountType type;
|
private final AccountType type;
|
||||||
private String accountNumber;
|
private final String accountNumber;
|
||||||
private String name;
|
private final String name;
|
||||||
private Currency currency;
|
private final Currency currency;
|
||||||
|
|
||||||
public Account(long id, LocalDateTime createdAt, boolean archived, AccountType type, String accountNumber, String name, Currency currency) {
|
public Account(long id, LocalDateTime createdAt, boolean archived, AccountType type, String accountNumber, String name, Currency currency) {
|
||||||
super(id);
|
super(id);
|
||||||
|
@ -62,22 +62,6 @@ public class Account extends IdEntity {
|
||||||
return currency;
|
return currency;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setType(AccountType type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAccountNumber(String accountNumber) {
|
|
||||||
this.accountNumber = accountNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCurrency(Currency currency) {
|
|
||||||
this.currency = currency;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalDateTime getCreatedAt() {
|
public LocalDateTime getCreatedAt() {
|
||||||
return createdAt;
|
return createdAt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class AccountsModule extends DashboardModule {
|
||||||
|
|
||||||
Label nameLabel = new Label(account.getName());
|
Label nameLabel = new Label(account.getName());
|
||||||
nameLabel.getStyleClass().addAll("bold-text");
|
nameLabel.getStyleClass().addAll("bold-text");
|
||||||
Label numberLabel = new Label(account.getAccountNumber());
|
Label numberLabel = new Label(account.getAccountNumberSuffix());
|
||||||
numberLabel.getStyleClass().addAll("mono-font");
|
numberLabel.getStyleClass().addAll("mono-font");
|
||||||
Label typeLabel = new Label(account.getType().toString());
|
Label typeLabel = new Label(account.getType().toString());
|
||||||
typeLabel.getStyleClass().add("bold-text");
|
typeLabel.getStyleClass().add("bold-text");
|
||||||
|
|
Loading…
Reference in New Issue