Skip to content

Commit

Permalink
Merge pull request #32 from frosklis/automated_27
Browse files Browse the repository at this point in the history
This adds automated transaction support with value expressions
  • Loading branch information
frosklis authored Feb 20, 2021
2 parents 76284bc + d9a6c69 commit 05c802b
Show file tree
Hide file tree
Showing 15 changed files with 731 additions and 117 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ authors = ["Claudio Noguera <[email protected]>"]
edition = "2018"
readme = "README.md"
description = "A command line ledger tool"
keywords = ["ledger"]
keywords = ["ledger", "plaintext-accounting"]
license = "MIT"
homepage = "https://github.com/frosklis/dinero-rs"
repository = "https://github.com/frosklis/dinero-rs"
Expand All @@ -31,3 +31,5 @@ shellexpand = "2.1.0"
two_timer = "2.2.0"
assert_cmd = "1.0.3"
terminal_size = "0.1.16"
pest = "2.0"
pest_derive = "2.0"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ Currently supported are:

Report filtering by account name and by date.

Run ```dinero --help``` for a list of available commands and options.
Run ```dinero --help``` for a list of available commands and options.
19 changes: 19 additions & 0 deletions examples/automated.ledger
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
; This should fail because the added posting makes the transaction unbalanced
; Different formats for currencies used, different operations
= Income:Salary
(Savings) 600 EUR
(Free spending) (abs(amount) - EUR 600)
= Savings
(Savings:Risky investments) (amount * 0.10)
(Savings:Deposits) 0.40
(Savings:Shares) (amount / 2)
= Expenses:Rent
Expenses:Rent EUR 553.12
Expenses:Utilities (amount - 553.12 EUR)
Expenses:Rent (-amount)
2021-01-01 * Flights
Income:Salary -1000 EUR
Assets:Checking account
2021-01-05 * Rent
Expenses:Rent 705.43 EUR
Assets:Checking account
11 changes: 11 additions & 0 deletions examples/automated_fail.ledger
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
; This should fail because the added posting makes the transaction unbalanced

= flights
[Bugdet:Holiday] -1

2021-01-01 * Flights
; :holiday:
Expenses:Flights 200 USD
Assets:Checking account


65 changes: 65 additions & 0 deletions src/grammar/value_expression.pest
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Grammar specification for value expressions

value_expr = {"(" ~ ws* ~ expr ~ ws* ~ ")"}
term = _{ variable | money | number }
money = { (number ~ ws* ~ currency) | (currency ~ ws* ~ number) }
currency = { LETTER+ | ("\"" ~ (!"\"" ~ ANY)+ ~ "\"")}
variable = _{ date | amount | total_amount | cost | value | gain | depth | posting_number | posting_count | cleared | real | not_automated | running_total }

number = { "-"? ~ bigint ~ ("." ~ bigint)? }
bigint = _{ ASCII_DIGIT+ }
ws = _{" "}
/* Not yet implemented
ternary = { expr ~ ws* ~ "?" ~ ws* ~ expr ~ ws* ~ ":" ~ ws* ~ expr}
binary = { expr ~ ws* ~
("<=" | ">=" | "<" | ">" | "&" | "|" )
~ ws* ~ expr}

*/

expr = { or_expr }
or_expr = { and_expr ~ ws* ~ ( or ~ ws* ~ and_expr ) * }
and_expr = { additive_expr ~ ws* ~ ( or ~ ws* ~ additive_expr ) * }
additive_expr = { multiplicative_expr ~ ws* ~ ( add ~ ws* ~ multiplicative_expr ) * }
multiplicative_expr = { primary ~ ws* ~ ( mult ~ ws* ~ primary )* }
primary = {
("(" ~ ws* ~ expr ~ ws* ~ ")") |
term |
(unary ~ ws* ~ primary) |
(unary_function ~ ws* ~ "(" ~ expr ~ ws* ~ ")")
}

add = { "+" | "-" }
mult = { "*" | "/" }
and = {"&"}
or = {"|"}
unary = { "-" | "!"}
unary_function = { "abs" }

total_amount = {"T"}
// A posting’s date, as the number of seconds past the epoch. This is always “today” for an account.
date = {"d"}
// The posting’s amount; the balance of an account, without considering children.
amount = {"amount" | "t"}
// The cost of a posting; the cost of an account, without its children.
cost = {"b"}
// The market value of a posting or an account, without its children.
value = {"v"}
// The net gain (market value minus cost basis), for a posting or an account, without its children. It is the same as ‘v-b’.
gain = {"g"}
// The depth (“level”) of an account. If an account has one parent, its depth is one.
depth = {"l"}
// The index of a posting, or the count of postings affecting an account.
posting_number = {"n"}
// ‘1’ if a posting’s transaction has been cleared, ‘0’ otherwise.
cleared = {"X"}
// ‘1’ if a posting is not virtual, ‘0’ otherwise.
real = {"R"}
// ‘1’ if a posting is not automated, ‘0’ otherwise.
not_automated = {"Z"}

// The total of all postings seen so far, or the total of an account and all its children.
running_total = {"O"}

// The total count of postings affecting an account and all its children.
posting_count = {"N"}
9 changes: 6 additions & 3 deletions src/lib/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ pub fn filter(options: &CommonOpts, transaction: &Transaction<Posting>, posting:
// Get what's needed
let predicate = &options.query;
let real = options.real;
let name = posting.account.get_name().to_lowercase();

// Check for real postings
if real {
Expand All @@ -27,11 +26,15 @@ pub fn filter(options: &CommonOpts, transaction: &Transaction<Posting>, posting:
return false;
}
}

return filter_predicate(predicate, posting);
}
pub fn filter_predicate(predicate: &Vec<String>, posting: &Posting) -> bool {
let name = posting.account.get_name().to_lowercase();
if predicate.len() == 0 {
return true;
}
for p in predicate {
for pred in predicate {
let p = pred.trim();
if p.starts_with("%") {
// look in the posting tags
for tag in posting.tags.iter() {
Expand Down
4 changes: 4 additions & 0 deletions src/lib/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
extern crate pest;
#[macro_use]
extern crate pest_derive;

pub mod commands;
mod error;
mod filter;
Expand Down
Loading

0 comments on commit 05c802b

Please sign in to comment.