modifier tr + ajout/modifier ac
This commit is contained in:
83
src/app.rs
83
src/app.rs
@@ -11,6 +11,7 @@ pub struct App {
|
|||||||
pub new_account: Account,
|
pub new_account: Account,
|
||||||
pub new_transaction: Transaction,
|
pub new_transaction: Transaction,
|
||||||
pub selected_transaction_input: TransactionInput,
|
pub selected_transaction_input: TransactionInput,
|
||||||
|
pub selected_account_input: AccountInput,
|
||||||
pub current_input: String,
|
pub current_input: String,
|
||||||
pub connection: Connection,
|
pub connection: Connection,
|
||||||
}
|
}
|
||||||
@@ -35,6 +36,7 @@ impl App {
|
|||||||
new_account: Account::new(0, String::new(), 0.0, AccountType::Cash),
|
new_account: Account::new(0, String::new(), 0.0, AccountType::Cash),
|
||||||
new_transaction: Transaction::new_empty(),
|
new_transaction: Transaction::new_empty(),
|
||||||
selected_transaction_input: TransactionInput::Type,
|
selected_transaction_input: TransactionInput::Type,
|
||||||
|
selected_account_input: AccountInput::Asset,
|
||||||
current_input: String::new(),
|
current_input: String::new(),
|
||||||
connection: con,
|
connection: con,
|
||||||
};
|
};
|
||||||
@@ -66,15 +68,24 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_new_account(&mut self) {
|
pub fn save_new_account(&mut self) {
|
||||||
|
let new = self.new_account.get_id() == 0;
|
||||||
|
self.next_ac_input();
|
||||||
let ac = data_layer::upsert_account(&self.connection, self.new_account.clone());
|
let ac = data_layer::upsert_account(&self.connection, self.new_account.clone());
|
||||||
self.acc_list.add_account(ac);
|
if new {
|
||||||
|
self.acc_list.add_account(ac);
|
||||||
|
}
|
||||||
self.new_account = Account::new(0, String::new(), 0.0, AccountType::Cash);
|
self.new_account = Account::new(0, String::new(), 0.0, AccountType::Cash);
|
||||||
|
self.current_input = String::new();
|
||||||
|
self.selected_account_input = AccountInput::Asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_new_tr(&mut self) {
|
pub fn save_new_tr(&mut self) {
|
||||||
|
let new = self.new_transaction.get_id() == 0;
|
||||||
self.next_tr_input();
|
self.next_tr_input();
|
||||||
let tr = data_layer::upsert_transaction(&self.connection, self.new_transaction.clone());
|
let tr = data_layer::upsert_transaction(&self.connection, self.new_transaction.clone());
|
||||||
self.trx_table.add_tr(tr);
|
if new {
|
||||||
|
self.trx_table.add_tr(tr);
|
||||||
|
}
|
||||||
self.new_transaction = Transaction::new_empty();
|
self.new_transaction = Transaction::new_empty();
|
||||||
self.current_input = String::new();
|
self.current_input = String::new();
|
||||||
self.selected_transaction_input = TransactionInput::Type;
|
self.selected_transaction_input = TransactionInput::Type;
|
||||||
@@ -119,7 +130,7 @@ impl App {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.set_current_input();
|
self.set_current_input_tr();
|
||||||
}
|
}
|
||||||
pub fn previous_tr_input(&mut self) {
|
pub fn previous_tr_input(&mut self) {
|
||||||
match self.selected_transaction_input {
|
match self.selected_transaction_input {
|
||||||
@@ -160,9 +171,57 @@ impl App {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.set_current_input();
|
self.set_current_input_tr();
|
||||||
}
|
}
|
||||||
fn set_current_input(&mut self) {
|
pub fn next_ac_input(&mut self) {
|
||||||
|
match self.selected_account_input {
|
||||||
|
AccountInput::Asset => {
|
||||||
|
self.selected_account_input = AccountInput::Name;
|
||||||
|
self.new_account.set_asset_price(
|
||||||
|
self.current_input
|
||||||
|
.parse::<f64>()
|
||||||
|
.expect("Failed to parse data"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
AccountInput::Name => {
|
||||||
|
self.selected_account_input = AccountInput::Type;
|
||||||
|
self.new_account.set_name(self.current_input.clone());
|
||||||
|
}
|
||||||
|
AccountInput::Type => {
|
||||||
|
self.new_account.set_type(AccountType::from_usize(
|
||||||
|
self.current_input
|
||||||
|
.parse::<usize>()
|
||||||
|
.expect("Failed to parse data"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.set_current_input_ac();
|
||||||
|
}
|
||||||
|
pub fn previous_ac_input(&mut self) {
|
||||||
|
match self.selected_account_input {
|
||||||
|
AccountInput::Asset => {
|
||||||
|
self.new_account.set_asset_price(
|
||||||
|
self.current_input
|
||||||
|
.parse::<f64>()
|
||||||
|
.expect("Failed to parse data"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
AccountInput::Name => {
|
||||||
|
self.new_account.set_name(self.current_input.clone());
|
||||||
|
self.selected_account_input = AccountInput::Asset;
|
||||||
|
}
|
||||||
|
AccountInput::Type => {
|
||||||
|
self.new_account.set_type(AccountType::from_usize(
|
||||||
|
self.current_input
|
||||||
|
.parse::<usize>()
|
||||||
|
.expect("Failed to parse data"),
|
||||||
|
));
|
||||||
|
self.selected_account_input = AccountInput::Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.set_current_input_ac();
|
||||||
|
}
|
||||||
|
pub fn set_current_input_tr(&mut self) {
|
||||||
match self.selected_transaction_input {
|
match self.selected_transaction_input {
|
||||||
TransactionInput::Type => {
|
TransactionInput::Type => {
|
||||||
self.current_input = self.new_transaction.get_type().get_id().to_string()
|
self.current_input = self.new_transaction.get_type().get_id().to_string()
|
||||||
@@ -183,4 +242,18 @@ impl App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn set_current_input_ac(&mut self) {
|
||||||
|
match self.selected_account_input {
|
||||||
|
AccountInput::Asset => {
|
||||||
|
self.current_input = self.new_account.get_asset_price().to_string();
|
||||||
|
}
|
||||||
|
AccountInput::Name => {
|
||||||
|
self.current_input = self.new_account.get_name();
|
||||||
|
}
|
||||||
|
AccountInput::Type => {
|
||||||
|
let ac_type = self.new_account.get_ac_type() as usize;
|
||||||
|
self.current_input = ac_type.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,17 +45,20 @@ pub fn upsert_account(con: &Connection, ac: Account) -> Account {
|
|||||||
let query;
|
let query;
|
||||||
let ac_type = ac.get_ac_type() as i64;
|
let ac_type = ac.get_ac_type() as i64;
|
||||||
if ac.get_id() == 0 {
|
if ac.get_id() == 0 {
|
||||||
query = "INSERT INTO Accounts (name, type) VALUES (?, ?) RETURNING id;";
|
query = "INSERT INTO Accounts (name, type, asset_price) VALUES (:name, :type, :asset_price) RETURNING id;";
|
||||||
} else {
|
} else {
|
||||||
query = "UPDATE Accounts SET name = ?, type = ? WHERE id = ? RETURNING id;";
|
query = "UPDATE Accounts SET name = :name, type = :type, asset_price = :asset_price WHERE id = :id RETURNING id;";
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut statement = con.prepare(query).unwrap();
|
let mut statement = con.prepare(query).unwrap();
|
||||||
statement.bind((1, &ac.get_name() as &str)).unwrap();
|
statement.bind((":name", &ac.get_name() as &str)).unwrap();
|
||||||
statement.bind((2, ac_type)).unwrap();
|
statement.bind((":type", ac_type)).unwrap();
|
||||||
|
statement
|
||||||
|
.bind((":asset_price", ac.get_asset_price()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
if ac.get_id() != 0 {
|
if ac.get_id() != 0 {
|
||||||
statement.bind((3, ac.get_id())).unwrap();
|
statement.bind((":id", ac.get_id())).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let id;
|
let id;
|
||||||
@@ -95,15 +98,25 @@ pub fn get_account(con: &Connection, id: i64) -> Account {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_account_total(id: i64, con: &Connection) -> f64 {
|
pub fn get_account_total(id: i64, con: &Connection) -> f64 {
|
||||||
let mut query = "SELECT SUM(amount) as total FROM Transactions".to_owned();
|
let mut query = "
|
||||||
|
SELECT
|
||||||
|
SUM(
|
||||||
|
CASE
|
||||||
|
WHEN a.type = 2 THEN t.asset_amount * a.asset_price
|
||||||
|
ELSE t.amount
|
||||||
|
END
|
||||||
|
) AS total
|
||||||
|
FROM Transactions t
|
||||||
|
JOIN Accounts a ON t.account_id = a.id"
|
||||||
|
.to_owned();
|
||||||
if id != 0 {
|
if id != 0 {
|
||||||
query.push_str(" WHERE account_id = ?")
|
query.push_str(" WHERE account_id = :id")
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut statement = con.prepare(query).unwrap();
|
let mut statement = con.prepare(query).unwrap();
|
||||||
|
|
||||||
if id != 0 {
|
if id != 0 {
|
||||||
statement.bind((1, id)).unwrap();
|
statement.bind((":id", id)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(State::Row) = statement.next() {
|
if let Ok(State::Row) = statement.next() {
|
||||||
@@ -200,7 +213,7 @@ pub fn upsert_transaction(con: &Connection, tr: Transaction) -> Transaction {
|
|||||||
RETURNING id;";
|
RETURNING id;";
|
||||||
} else {
|
} else {
|
||||||
query = "UPDATE Transactions
|
query = "UPDATE Transactions
|
||||||
SET account_id = :ac_id, type_id = :type_id, amount = :amnt, date = :date, description = :desc, asset_amount = asset_amnt
|
SET account_id = :ac_id, type_id = :type_id, amount = :amnt, date = :date, description = :desc, asset_amount = :asset_amnt
|
||||||
WHERE id = :id RETURNING id;";
|
WHERE id = :id RETURNING id;";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,12 +27,21 @@ impl Account {
|
|||||||
pub fn get_name(&self) -> String {
|
pub fn get_name(&self) -> String {
|
||||||
return self.name.clone();
|
return self.name.clone();
|
||||||
}
|
}
|
||||||
|
pub fn set_name(&mut self, name: String) {
|
||||||
|
self.name = name;
|
||||||
|
}
|
||||||
pub fn get_asset_price(&self) -> f64 {
|
pub fn get_asset_price(&self) -> f64 {
|
||||||
return self.asset_price;
|
return self.asset_price;
|
||||||
}
|
}
|
||||||
|
pub fn set_asset_price(&mut self, asset_price: f64) {
|
||||||
|
self.asset_price = asset_price;
|
||||||
|
}
|
||||||
pub fn get_ac_type(&self) -> AccountType {
|
pub fn get_ac_type(&self) -> AccountType {
|
||||||
return AccountType::try_from(self.ac_type as i64).unwrap();
|
return AccountType::try_from(self.ac_type as i64).unwrap();
|
||||||
}
|
}
|
||||||
|
pub fn set_type(&mut self, ac_type: AccountType) {
|
||||||
|
self.ac_type = ac_type;
|
||||||
|
}
|
||||||
pub fn get_total(&self, con: &Connection) -> f64 {
|
pub fn get_total(&self, con: &Connection) -> f64 {
|
||||||
return data_layer::get_account_total(self.id, con);
|
return data_layer::get_account_total(self.id, con);
|
||||||
}
|
}
|
||||||
@@ -43,6 +52,17 @@ pub enum AccountType {
|
|||||||
Cash = 1,
|
Cash = 1,
|
||||||
Assets,
|
Assets,
|
||||||
}
|
}
|
||||||
|
impl AccountType {
|
||||||
|
pub fn from_usize(v: usize) -> Self {
|
||||||
|
const CASH: usize = AccountType::Cash as usize;
|
||||||
|
const ASSET: usize = AccountType::Assets as usize;
|
||||||
|
match v {
|
||||||
|
CASH => return Self::Cash,
|
||||||
|
ASSET => return Self::Assets,
|
||||||
|
_ => return Self::Cash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<i64> for AccountType {
|
impl TryFrom<i64> for AccountType {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|||||||
@@ -32,6 +32,13 @@ impl AccountList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn selected_ac(&self) -> Account {
|
||||||
|
if let Some(i) = self.state.selected() {
|
||||||
|
return self.accounts.get(i).unwrap().clone();
|
||||||
|
}
|
||||||
|
return Account::new(0, String::new(), 0.0, AccountType::Cash);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_account(&mut self, ac: Account) {
|
pub fn add_account(&mut self, ac: Account) {
|
||||||
self.accounts.push(ac);
|
self.accounts.push(ac);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,13 @@ impl TrxTable {
|
|||||||
return self.trx.clone();
|
return self.trx.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn selected_tr(&self) -> Transaction {
|
||||||
|
if let Some(i) = self.state.selected() {
|
||||||
|
return self.trx.get(i).unwrap().clone();
|
||||||
|
}
|
||||||
|
return Transaction::new_empty();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_tr(&mut self, tr: Transaction) {
|
pub fn add_tr(&mut self, tr: Transaction) {
|
||||||
self.trx.insert(0, tr);
|
self.trx.insert(0, tr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,3 +17,10 @@ pub enum TransactionInput {
|
|||||||
Description,
|
Description,
|
||||||
Asset,
|
Asset,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub enum AccountInput {
|
||||||
|
Asset,
|
||||||
|
Name,
|
||||||
|
Type,
|
||||||
|
}
|
||||||
|
|||||||
24
src/main.rs
24
src/main.rs
@@ -101,9 +101,33 @@ where
|
|||||||
app.new_transaction.set_date(Local::now());
|
app.new_transaction.set_date(Local::now());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
KeyCode::Char('m') => match app.current_widget {
|
||||||
|
CurrentWidget::AccountList => {
|
||||||
|
app.current_screen = CurrentScreen::NewAccount;
|
||||||
|
app.new_account = app.acc_list.selected_ac();
|
||||||
|
app.set_current_input_ac();
|
||||||
|
}
|
||||||
|
CurrentWidget::TrxList => {
|
||||||
|
app.current_screen = CurrentScreen::NewTransaction;
|
||||||
|
app.new_transaction = app.trx_table.selected_tr();
|
||||||
|
app.set_current_input_tr();
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
CurrentScreen::NewAccount => match key.code {
|
CurrentScreen::NewAccount => match key.code {
|
||||||
|
KeyCode::Down => {
|
||||||
|
app.next_ac_input();
|
||||||
|
}
|
||||||
|
KeyCode::Up => {
|
||||||
|
app.previous_ac_input();
|
||||||
|
}
|
||||||
|
KeyCode::Backspace => {
|
||||||
|
app.current_input.pop();
|
||||||
|
}
|
||||||
|
KeyCode::Char(value) => {
|
||||||
|
app.current_input.push(value);
|
||||||
|
}
|
||||||
KeyCode::Enter => {
|
KeyCode::Enter => {
|
||||||
app.save_new_account();
|
app.save_new_account();
|
||||||
app.current_screen = CurrentScreen::Main;
|
app.current_screen = CurrentScreen::Main;
|
||||||
|
|||||||
49
src/ui.rs
49
src/ui.rs
@@ -112,6 +112,35 @@ pub fn ui(frame: &mut Frame, app: &mut App) {
|
|||||||
let area = centered_rect(50, 40, frame.area());
|
let area = centered_rect(50, 40, frame.area());
|
||||||
frame.render_widget(Clear, area);
|
frame.render_widget(Clear, area);
|
||||||
frame.render_widget(popup, area);
|
frame.render_widget(popup, area);
|
||||||
|
|
||||||
|
let chunks = Layout::default()
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.margin(1)
|
||||||
|
.constraints([
|
||||||
|
Constraint::Length(3),
|
||||||
|
Constraint::Length(3),
|
||||||
|
Constraint::Length(3),
|
||||||
|
])
|
||||||
|
.split(area);
|
||||||
|
|
||||||
|
let ac_asset = Paragraph::new(ac_input_str(AccountInput::Asset, app))
|
||||||
|
.style(ac_input_style(AccountInput::Asset, app))
|
||||||
|
.block(
|
||||||
|
Block::default()
|
||||||
|
.borders(Borders::BOTTOM)
|
||||||
|
.title("Asset Price"),
|
||||||
|
);
|
||||||
|
frame.render_widget(ac_asset, chunks[0]);
|
||||||
|
|
||||||
|
let ac_name = Paragraph::new(ac_input_str(AccountInput::Name, app))
|
||||||
|
.style(ac_input_style(AccountInput::Name, app))
|
||||||
|
.block(Block::default().borders(Borders::BOTTOM).title("Name"));
|
||||||
|
frame.render_widget(ac_name, chunks[1]);
|
||||||
|
|
||||||
|
let ac_type = Paragraph::new(ac_input_str(AccountInput::Type, app))
|
||||||
|
.style(ac_input_style(AccountInput::Type, app))
|
||||||
|
.block(Block::default().borders(Borders::BOTTOM).title("Type"));
|
||||||
|
frame.render_widget(ac_type, chunks[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let CurrentScreen::NewTransaction = app.current_screen {
|
if let CurrentScreen::NewTransaction = app.current_screen {
|
||||||
@@ -233,7 +262,25 @@ fn tr_input_str(input: TransactionInput, app: &mut App) -> String {
|
|||||||
TransactionInput::Asset => app.new_transaction.get_asset_amnt().to_string(),
|
TransactionInput::Asset => app.new_transaction.get_asset_amnt().to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn ac_input_style(input: AccountInput, app: &mut App) -> Style {
|
||||||
|
if app.selected_account_input == input {
|
||||||
|
return SELECTED_STYLE;
|
||||||
|
}
|
||||||
|
return Style::default();
|
||||||
|
}
|
||||||
|
fn ac_input_str(input: AccountInput, app: &mut App) -> String {
|
||||||
|
if app.selected_account_input == input {
|
||||||
|
return app.current_input.clone();
|
||||||
|
}
|
||||||
|
match input {
|
||||||
|
AccountInput::Name => app.new_account.get_name(),
|
||||||
|
AccountInput::Type => {
|
||||||
|
let ac_type = app.new_account.get_ac_type() as usize;
|
||||||
|
return ac_type.to_string();
|
||||||
|
}
|
||||||
|
AccountInput::Asset => app.new_account.get_asset_price().to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
impl From<&Account> for ListItem<'_> {
|
impl From<&Account> for ListItem<'_> {
|
||||||
fn from(value: &Account) -> Self {
|
fn from(value: &Account) -> Self {
|
||||||
let line = Line::styled(
|
let line = Line::styled(
|
||||||
|
|||||||
Reference in New Issue
Block a user