Add balance record "type" attribute, for cash and assets.
This commit is contained in:
parent
d4bd5cc6ec
commit
feda2e1897
|
@ -6,6 +6,7 @@ import com.andrewlalis.perfin.data.BalanceRecordRepository;
|
||||||
import com.andrewlalis.perfin.data.util.CurrencyUtil;
|
import com.andrewlalis.perfin.data.util.CurrencyUtil;
|
||||||
import com.andrewlalis.perfin.data.util.DateUtil;
|
import com.andrewlalis.perfin.data.util.DateUtil;
|
||||||
import com.andrewlalis.perfin.model.Account;
|
import com.andrewlalis.perfin.model.Account;
|
||||||
|
import com.andrewlalis.perfin.model.BalanceRecordType;
|
||||||
import com.andrewlalis.perfin.model.MoneyValue;
|
import com.andrewlalis.perfin.model.MoneyValue;
|
||||||
import com.andrewlalis.perfin.model.Profile;
|
import com.andrewlalis.perfin.model.Profile;
|
||||||
import com.andrewlalis.perfin.view.component.FileSelectionArea;
|
import com.andrewlalis.perfin.view.component.FileSelectionArea;
|
||||||
|
@ -29,6 +30,10 @@ import java.time.format.DateTimeParseException;
|
||||||
|
|
||||||
import static com.andrewlalis.perfin.PerfinApp.router;
|
import static com.andrewlalis.perfin.PerfinApp.router;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for the page where users can create a balance record for an
|
||||||
|
* account.
|
||||||
|
*/
|
||||||
public class CreateBalanceRecordController implements RouteSelectionListener {
|
public class CreateBalanceRecordController implements RouteSelectionListener {
|
||||||
@FXML public TextField timestampField;
|
@FXML public TextField timestampField;
|
||||||
@FXML public TextField balanceField;
|
@FXML public TextField balanceField;
|
||||||
|
@ -102,6 +107,7 @@ public class CreateBalanceRecordController implements RouteSelectionListener {
|
||||||
repo.insert(
|
repo.insert(
|
||||||
DateUtil.localToUTC(localTimestamp),
|
DateUtil.localToUTC(localTimestamp),
|
||||||
account.id,
|
account.id,
|
||||||
|
BalanceRecordType.CASH,
|
||||||
reportedBalance,
|
reportedBalance,
|
||||||
account.getCurrency(),
|
account.getCurrency(),
|
||||||
attachmentSelectionArea.getSelectedPaths()
|
attachmentSelectionArea.getSelectedPaths()
|
||||||
|
|
|
@ -2,10 +2,7 @@ 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.data.util.CurrencyUtil;
|
||||||
import com.andrewlalis.perfin.model.Account;
|
import com.andrewlalis.perfin.model.*;
|
||||||
import com.andrewlalis.perfin.model.AccountType;
|
|
||||||
import com.andrewlalis.perfin.model.MoneyValue;
|
|
||||||
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;
|
||||||
import com.andrewlalis.perfin.view.component.validation.validators.CurrencyAmountValidator;
|
import com.andrewlalis.perfin.view.component.validation.validators.CurrencyAmountValidator;
|
||||||
|
@ -132,7 +129,7 @@ public class EditAccountController implements RouteSelectionListener {
|
||||||
boolean success = Popups.confirm(accountNameField, prompt);
|
boolean success = Popups.confirm(accountNameField, prompt);
|
||||||
if (success) {
|
if (success) {
|
||||||
long id = accountRepo.insert(type, number, name, currency, description);
|
long id = accountRepo.insert(type, number, name, currency, description);
|
||||||
balanceRepo.insert(LocalDateTime.now(ZoneOffset.UTC), id, initialBalance, currency, attachments);
|
balanceRepo.insert(LocalDateTime.now(ZoneOffset.UTC), id, BalanceRecordType.CASH, 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);
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.andrewlalis.perfin.data;
|
||||||
|
|
||||||
import com.andrewlalis.perfin.model.Attachment;
|
import com.andrewlalis.perfin.model.Attachment;
|
||||||
import com.andrewlalis.perfin.model.BalanceRecord;
|
import com.andrewlalis.perfin.model.BalanceRecord;
|
||||||
|
import com.andrewlalis.perfin.model.BalanceRecordType;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
@ -11,11 +12,11 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public interface BalanceRecordRepository extends Repository, AutoCloseable {
|
public interface BalanceRecordRepository extends Repository, AutoCloseable {
|
||||||
long insert(LocalDateTime utcTimestamp, long accountId, BigDecimal balance, Currency currency, List<Path> attachments);
|
long insert(LocalDateTime utcTimestamp, long accountId, BalanceRecordType type, BigDecimal balance, Currency currency, List<Path> attachments);
|
||||||
BalanceRecord findLatestByAccountId(long accountId);
|
BalanceRecord findLatestByAccountId(long accountId, BalanceRecordType type);
|
||||||
Optional<BalanceRecord> findById(long id);
|
Optional<BalanceRecord> findById(long id);
|
||||||
Optional<BalanceRecord> findClosestBefore(long accountId, LocalDateTime utcTimestamp);
|
Optional<BalanceRecord> findClosestBefore(long accountId, BalanceRecordType type, LocalDateTime utcTimestamp);
|
||||||
Optional<BalanceRecord> findClosestAfter(long accountId, LocalDateTime utcTimestamp);
|
Optional<BalanceRecord> findClosestAfter(long accountId, BalanceRecordType type, LocalDateTime utcTimestamp);
|
||||||
List<Attachment> findAttachments(long recordId);
|
List<Attachment> findAttachments(long recordId);
|
||||||
void deleteById(long id);
|
void deleteById(long id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,7 +122,7 @@ public record JdbcAccountRepository(Connection conn, Path contentDir) implements
|
||||||
BalanceRecordRepository balanceRecordRepo = new JdbcBalanceRecordRepository(conn, contentDir);
|
BalanceRecordRepository balanceRecordRepo = new JdbcBalanceRecordRepository(conn, contentDir);
|
||||||
AccountEntryRepository accountEntryRepo = new JdbcAccountEntryRepository(conn);
|
AccountEntryRepository accountEntryRepo = new JdbcAccountEntryRepository(conn);
|
||||||
// Find the most recent balance record before timestamp.
|
// Find the most recent balance record before timestamp.
|
||||||
Optional<BalanceRecord> closestPastRecord = balanceRecordRepo.findClosestBefore(account.id, utcTimestamp);
|
Optional<BalanceRecord> closestPastRecord = balanceRecordRepo.findClosestBefore(account.id, BalanceRecordType.CASH, utcTimestamp);
|
||||||
if (closestPastRecord.isPresent()) {
|
if (closestPastRecord.isPresent()) {
|
||||||
// Then find any entries on the account since that balance record and the timestamp.
|
// Then find any entries on the account since that balance record and the timestamp.
|
||||||
List<AccountEntry> entriesBetweenRecentRecordAndNow = accountEntryRepo.findAllByAccountIdBetween(
|
List<AccountEntry> entriesBetweenRecentRecordAndNow = accountEntryRepo.findAllByAccountIdBetween(
|
||||||
|
@ -133,7 +133,7 @@ public record JdbcAccountRepository(Connection conn, Path contentDir) implements
|
||||||
return computeBalanceWithEntries(account.getType(), closestPastRecord.get(), entriesBetweenRecentRecordAndNow);
|
return computeBalanceWithEntries(account.getType(), closestPastRecord.get(), entriesBetweenRecentRecordAndNow);
|
||||||
} else {
|
} else {
|
||||||
// There is no balance record present before the given timestamp. Try and find the closest one after.
|
// There is no balance record present before the given timestamp. Try and find the closest one after.
|
||||||
Optional<BalanceRecord> closestFutureRecord = balanceRecordRepo.findClosestAfter(account.id, utcTimestamp);
|
Optional<BalanceRecord> closestFutureRecord = balanceRecordRepo.findClosestAfter(account.id, BalanceRecordType.CASH, utcTimestamp);
|
||||||
if (closestFutureRecord.isPresent()) {
|
if (closestFutureRecord.isPresent()) {
|
||||||
// Now find any entries on the account from the timestamp until that balance record.
|
// Now find any entries on the account from the timestamp until that balance record.
|
||||||
List<AccountEntry> entriesBetweenNowAndFutureRecord = accountEntryRepo.findAllByAccountIdBetween(
|
List<AccountEntry> entriesBetweenNowAndFutureRecord = accountEntryRepo.findAllByAccountIdBetween(
|
||||||
|
@ -145,7 +145,7 @@ public record JdbcAccountRepository(Connection conn, Path contentDir) implements
|
||||||
} else {
|
} else {
|
||||||
// No balance records exist for the account! Assume balance of 0 when the account was created.
|
// No balance records exist for the account! Assume balance of 0 when the account was created.
|
||||||
log.warn("No balance record exists for account {}! Assuming balance was 0 at account creation.", account.getShortName());
|
log.warn("No balance record exists for account {}! Assuming balance was 0 at account creation.", account.getShortName());
|
||||||
BalanceRecord placeholder = new BalanceRecord(-1, account.getCreatedAt(), account.id, BigDecimal.ZERO, account.getCurrency());
|
BalanceRecord placeholder = new BalanceRecord(-1, account.getCreatedAt(), account.id, BalanceRecordType.CASH, BigDecimal.ZERO, account.getCurrency());
|
||||||
List<AccountEntry> entriesSinceAccountCreated = accountEntryRepo.findAllByAccountIdBetween(account.id, account.getCreatedAt(), utcTimestamp);
|
List<AccountEntry> entriesSinceAccountCreated = accountEntryRepo.findAllByAccountIdBetween(account.id, account.getCreatedAt(), utcTimestamp);
|
||||||
return computeBalanceWithEntries(account.getType(), placeholder, entriesSinceAccountCreated);
|
return computeBalanceWithEntries(account.getType(), placeholder, entriesSinceAccountCreated);
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,7 @@ public record JdbcAccountRepository(Connection conn, Path contentDir) implements
|
||||||
LEFT JOIN history_account ha ON history_item.history_id = ha.history_id
|
LEFT JOIN history_account ha ON history_item.history_id = ha.history_id
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT id, timestamp, 'BALANCE_RECORD' AS type, account_id
|
SELECT id, timestamp, 'BALANCE_RECORD' AS type, account_id
|
||||||
FROM balance_record
|
FROM balance_record WHERE type = 'CASH'
|
||||||
)
|
)
|
||||||
WHERE account_id = ? AND timestamp < ?
|
WHERE account_id = ? AND timestamp < ?
|
||||||
ORDER BY timestamp DESC
|
ORDER BY timestamp DESC
|
||||||
|
|
|
@ -5,6 +5,7 @@ import com.andrewlalis.perfin.data.BalanceRecordRepository;
|
||||||
import com.andrewlalis.perfin.data.util.DbUtil;
|
import com.andrewlalis.perfin.data.util.DbUtil;
|
||||||
import com.andrewlalis.perfin.model.Attachment;
|
import com.andrewlalis.perfin.model.Attachment;
|
||||||
import com.andrewlalis.perfin.model.BalanceRecord;
|
import com.andrewlalis.perfin.model.BalanceRecord;
|
||||||
|
import com.andrewlalis.perfin.model.BalanceRecordType;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
@ -18,12 +19,12 @@ import java.util.Optional;
|
||||||
|
|
||||||
public record JdbcBalanceRecordRepository(Connection conn, Path contentDir) implements BalanceRecordRepository {
|
public record JdbcBalanceRecordRepository(Connection conn, Path contentDir) implements BalanceRecordRepository {
|
||||||
@Override
|
@Override
|
||||||
public long insert(LocalDateTime utcTimestamp, long accountId, BigDecimal balance, Currency currency, List<Path> attachments) {
|
public long insert(LocalDateTime utcTimestamp, long accountId, BalanceRecordType type, BigDecimal balance, Currency currency, List<Path> attachments) {
|
||||||
return DbUtil.doTransaction(conn, () -> {
|
return DbUtil.doTransaction(conn, () -> {
|
||||||
long recordId = DbUtil.insertOne(
|
long recordId = DbUtil.insertOne(
|
||||||
conn,
|
conn,
|
||||||
"INSERT INTO balance_record (timestamp, account_id, balance, currency) VALUES (?, ?, ?, ?)",
|
"INSERT INTO balance_record (timestamp, account_id, type, balance, currency) VALUES (?, ?, ?, ?, ?)",
|
||||||
List.of(DbUtil.timestampFromUtcLDT(utcTimestamp), accountId, balance, currency.getCurrencyCode())
|
List.of(DbUtil.timestampFromUtcLDT(utcTimestamp), accountId, type.name(), balance, currency.getCurrencyCode())
|
||||||
);
|
);
|
||||||
// Insert attachments.
|
// Insert attachments.
|
||||||
AttachmentRepository attachmentRepo = new JdbcAttachmentRepository(conn, contentDir);
|
AttachmentRepository attachmentRepo = new JdbcAttachmentRepository(conn, contentDir);
|
||||||
|
@ -39,11 +40,11 @@ public record JdbcBalanceRecordRepository(Connection conn, Path contentDir) impl
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BalanceRecord findLatestByAccountId(long accountId) {
|
public BalanceRecord findLatestByAccountId(long accountId, BalanceRecordType type) {
|
||||||
return DbUtil.findOne(
|
return DbUtil.findOne(
|
||||||
conn,
|
conn,
|
||||||
"SELECT * FROM balance_record WHERE account_id = ? ORDER BY timestamp DESC LIMIT 1",
|
"SELECT * FROM balance_record WHERE account_id = ? AND type = ? ORDER BY timestamp DESC LIMIT 1",
|
||||||
List.of(accountId),
|
List.of(accountId, type.name()),
|
||||||
JdbcBalanceRecordRepository::parse
|
JdbcBalanceRecordRepository::parse
|
||||||
).orElse(null);
|
).orElse(null);
|
||||||
}
|
}
|
||||||
|
@ -59,21 +60,21 @@ public record JdbcBalanceRecordRepository(Connection conn, Path contentDir) impl
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<BalanceRecord> findClosestBefore(long accountId, LocalDateTime utcTimestamp) {
|
public Optional<BalanceRecord> findClosestBefore(long accountId, BalanceRecordType type, LocalDateTime utcTimestamp) {
|
||||||
return DbUtil.findOne(
|
return DbUtil.findOne(
|
||||||
conn,
|
conn,
|
||||||
"SELECT * FROM balance_record WHERE account_id = ? AND timestamp <= ? ORDER BY timestamp DESC LIMIT 1",
|
"SELECT * FROM balance_record WHERE account_id = ? AND type = ? AND timestamp <= ? ORDER BY timestamp DESC LIMIT 1",
|
||||||
List.of(accountId, DbUtil.timestampFromUtcLDT(utcTimestamp)),
|
List.of(accountId, type.name(), DbUtil.timestampFromUtcLDT(utcTimestamp)),
|
||||||
JdbcBalanceRecordRepository::parse
|
JdbcBalanceRecordRepository::parse
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<BalanceRecord> findClosestAfter(long accountId, LocalDateTime utcTimestamp) {
|
public Optional<BalanceRecord> findClosestAfter(long accountId, BalanceRecordType type, LocalDateTime utcTimestamp) {
|
||||||
return DbUtil.findOne(
|
return DbUtil.findOne(
|
||||||
conn,
|
conn,
|
||||||
"SELECT * FROM balance_record WHERE account_id = ? AND timestamp >= ? ORDER BY timestamp ASC LIMIT 1",
|
"SELECT * FROM balance_record WHERE account_id = ? AND type = ? AND timestamp >= ? ORDER BY timestamp ASC LIMIT 1",
|
||||||
List.of(accountId, DbUtil.timestampFromUtcLDT(utcTimestamp)),
|
List.of(accountId, type.name(), DbUtil.timestampFromUtcLDT(utcTimestamp)),
|
||||||
JdbcBalanceRecordRepository::parse
|
JdbcBalanceRecordRepository::parse
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -108,6 +109,7 @@ public record JdbcBalanceRecordRepository(Connection conn, Path contentDir) impl
|
||||||
rs.getLong("id"),
|
rs.getLong("id"),
|
||||||
DbUtil.utcLDTFromTimestamp(rs.getTimestamp("timestamp")),
|
DbUtil.utcLDTFromTimestamp(rs.getTimestamp("timestamp")),
|
||||||
rs.getLong("account_id"),
|
rs.getLong("account_id"),
|
||||||
|
BalanceRecordType.valueOf(rs.getString("type").toUpperCase()),
|
||||||
rs.getBigDecimal("balance"),
|
rs.getBigDecimal("balance"),
|
||||||
Currency.getInstance(rs.getString("currency"))
|
Currency.getInstance(rs.getString("currency"))
|
||||||
);
|
);
|
||||||
|
|
|
@ -34,8 +34,11 @@ public class JdbcDataSourceFactory implements DataSourceFactory {
|
||||||
* loaded with an old schema version, then we'll migrate to the latest. If
|
* loaded with an old schema version, then we'll migrate to the latest. If
|
||||||
* the profile has a newer schema version, we'll exit and prompt the user
|
* the profile has a newer schema version, we'll exit and prompt the user
|
||||||
* to update their app.
|
* to update their app.
|
||||||
|
* <p>
|
||||||
|
* This value should be one higher than the
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
public static final int SCHEMA_VERSION = 4;
|
public static final int SCHEMA_VERSION = 5;
|
||||||
|
|
||||||
public DataSource getDataSource(String profileName) throws ProfileLoadException {
|
public DataSource getDataSource(String profileName) throws ProfileLoadException {
|
||||||
final boolean dbExists = Files.exists(getDatabaseFile(profileName));
|
final boolean dbExists = Files.exists(getDatabaseFile(profileName));
|
||||||
|
|
|
@ -19,6 +19,7 @@ public class Migrations {
|
||||||
migrations.put(1, new PlainSQLMigration("/sql/migration/M001_AddTransactionProperties.sql"));
|
migrations.put(1, new PlainSQLMigration("/sql/migration/M001_AddTransactionProperties.sql"));
|
||||||
migrations.put(2, new PlainSQLMigration("/sql/migration/M002_RefactorHistories.sql"));
|
migrations.put(2, new PlainSQLMigration("/sql/migration/M002_RefactorHistories.sql"));
|
||||||
migrations.put(3, new PlainSQLMigration("/sql/migration/M003_AddLineItemCategoryAndAccountDescription.sql"));
|
migrations.put(3, new PlainSQLMigration("/sql/migration/M003_AddLineItemCategoryAndAccountDescription.sql"));
|
||||||
|
migrations.put(4, new PlainSQLMigration("/sql/migration/M004_AddBrokerageValueRecords.sql"));
|
||||||
return migrations;
|
return migrations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,20 +5,20 @@ import java.time.LocalDateTime;
|
||||||
import java.util.Currency;
|
import java.util.Currency;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A recording of an account's real reported balance at a given point in time,
|
* A recording of an account's real reported balance at a given point in time.
|
||||||
* used as a sanity check for ensuring that an account's entries add up to the
|
|
||||||
* correct balance.
|
|
||||||
*/
|
*/
|
||||||
public class BalanceRecord extends IdEntity implements Timestamped {
|
public class BalanceRecord extends IdEntity implements Timestamped {
|
||||||
private final LocalDateTime timestamp;
|
private final LocalDateTime timestamp;
|
||||||
private final long accountId;
|
private final long accountId;
|
||||||
|
private final BalanceRecordType type;
|
||||||
private final BigDecimal balance;
|
private final BigDecimal balance;
|
||||||
private final Currency currency;
|
private final Currency currency;
|
||||||
|
|
||||||
public BalanceRecord(long id, LocalDateTime timestamp, long accountId, BigDecimal balance, Currency currency) {
|
public BalanceRecord(long id, LocalDateTime timestamp, long accountId, BalanceRecordType type, BigDecimal balance, Currency currency) {
|
||||||
super(id);
|
super(id);
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.accountId = accountId;
|
this.accountId = accountId;
|
||||||
|
this.type = type;
|
||||||
this.balance = balance;
|
this.balance = balance;
|
||||||
this.currency = currency;
|
this.currency = currency;
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,10 @@ public class BalanceRecord extends IdEntity implements Timestamped {
|
||||||
return accountId;
|
return accountId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BalanceRecordType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
public BigDecimal getBalance() {
|
public BigDecimal getBalance() {
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.andrewlalis.perfin.model;
|
||||||
|
|
||||||
|
public enum BalanceRecordType {
|
||||||
|
CASH("Cash"),
|
||||||
|
ASSETS("Assets");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
BalanceRecordType(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
This migration adds a new entity specifically for brokerage accounts: the asset
|
||||||
|
value record. This records the approximate value of the brokerage account assets
|
||||||
|
excluding cash (which is already recorded).
|
||||||
|
|
||||||
|
This allows users to include their brokerage/investment assets in their Perfin
|
||||||
|
profile for analysis, and paves the way for adding integrations with brokerage
|
||||||
|
APIs to automate asset value record fetching.
|
||||||
|
|
||||||
|
Note that at the moment, asset value records only make sense for brokerage
|
||||||
|
accounts, but in the future more account types might be added for which this
|
||||||
|
would make sense.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ALTER TABLE balance_record
|
||||||
|
ADD COLUMN type ENUM('CASH', 'ASSETS') NOT NULL DEFAULT 'CASH' AFTER account_id;
|
|
@ -128,6 +128,7 @@ CREATE TABLE balance_record (
|
||||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||||
timestamp TIMESTAMP NOT NULL,
|
timestamp TIMESTAMP NOT NULL,
|
||||||
account_id BIGINT NOT NULL,
|
account_id BIGINT NOT NULL,
|
||||||
|
type ENUM('CASH', 'ASSETS') NOT NULL DEFAULT 'CASH',
|
||||||
balance NUMERIC(12, 4) NOT NULL,
|
balance NUMERIC(12, 4) NOT NULL,
|
||||||
currency VARCHAR(3) NOT NULL,
|
currency VARCHAR(3) NOT NULL,
|
||||||
CONSTRAINT fk_balance_record_account
|
CONSTRAINT fk_balance_record_account
|
||||||
|
|
Loading…
Reference in New Issue