credger/ledger.cr

102 lines
3.2 KiB
Crystal
Raw Normal View History

2017-11-24 10:58:58 +01:00
# encoding: utf-8
require "csv"
# Crystal wrapper module for calling ledger
class Ledger
2017-11-24 16:09:55 +01:00
def initialize( binary : String = "ledger",
2019-02-14 11:59:31 +01:00
ledger_file : String = ENV[ "LEDGER_FILE" ] ||= "${ENV[ \"HOME\" ]}/org/comptes.ledger" )
2017-11-24 10:58:58 +01:00
@binary = binary
@file = ledger_file
2021-04-10 17:39:24 +02:00
@cache = Hash(String, String).new
2017-11-24 10:58:58 +01:00
end
def run( options : String, command : String = "", command_parameters : String = "" ) : String
2021-04-10 17:39:24 +02:00
command = "#{@binary} -f #{@file} #{options} #{command} #{command_parameters}"
STDERR.puts command
mtime = File.info(@file).modification_time
key = "#{mtime}#{command}"
@cache[ key ] = `#{command}` unless @cache.has_key?( key )
@cache[ key ]
2017-11-24 10:58:58 +01:00
end
def version : String
run "--version"
end
def accounts( depth : Number = 9999 ) : Array( Array( String ) )
accounts = run( "", "accounts" )
.split( "\n" )
.map do |a|
a.split( ":" )
.each_slice( depth )
.to_a.first
end.uniq
accounts.map{|a| a.size}.max.times do |i|
accounts += accounts.map { |acc| acc.first( i ) }
end
accounts
.uniq
.sort
.reject { |a| a.empty? || a.first.empty? }
.sort_by { |a| a.size }
end
2017-11-24 16:09:55 +01:00
def balance( cleared : Bool = false,
depth : Int32 = 9999,
period : String = nil,
categories : String = "" ) : Array( NamedTuple( account: String, amount: Float64 ) )
2017-11-24 10:58:58 +01:00
period = period.nil? ? "" : "-p '#{period}'"
depth = depth.nil? ? "" : "--depth #{depth}"
operation = cleared ? "cleared" : "balance"
2019-02-14 11:59:31 +01:00
run( "--flat --no-total --exchange '#{ENV["CREDGER_CURRENCY"]}' #{period} #{depth}", operation, categories )
2017-11-24 10:58:58 +01:00
.split( "\n" )
.reject {|line| line.empty?}
.map do |line|
2019-02-14 11:59:31 +01:00
line_array = line.split( ENV["CREDGER_CURRENCY"] )
2017-11-24 10:58:58 +01:00
{ account: line_array[ 1 ].strip,
2019-02-14 11:59:31 +01:00
amount: line_array[ 0 ].tr( ENV["CREDGER_SEPARATOR"], "." ).to_f }
2017-11-24 10:58:58 +01:00
end
end
2017-11-24 16:09:55 +01:00
def graph_values( period : String = "",
2017-12-15 20:25:37 +01:00
granularity : String = "",
2017-11-24 16:09:55 +01:00
categories : Array(String) = ["Expenses"] ) : Hash( String, Array( NamedTuple( date: String, amount: String, currency: String ) ) )
2017-11-24 10:58:58 +01:00
period = period == "" ? "" : "-p '#{period}'"
result = {} of String => Array(NamedTuple(date: String, amount: String, currency: String))
categories.map do |category|
result[category] = CSV
2019-02-14 11:59:31 +01:00
.parse( run( "-MAn --exchange '#{ENV["CREDGER_CURRENCY"]}' #{period} #{granularity}", "csv --no-revalued", category ) )
2017-11-24 10:58:58 +01:00
.map do |row|
{ date: row[ 0 ],
amount: row[ 5 ],
currency: row[ 4 ] }
end
end
result
end
2017-11-24 14:58:56 +01:00
2017-11-24 16:09:55 +01:00
def register( period : String = "",
categories : Array(String) = ["Expenses"] ) : Array( NamedTuple( date: String, payee: String, account: String, amount: String, currency: String ) )
2017-11-24 14:58:56 +01:00
period = period == "" ? "" : "-p '#{period}'"
CSV
2019-02-14 11:59:31 +01:00
.parse( run( "--exchange '#{ENV["CREDGER_CURRENCY"]}' #{period}", "csv --no-revalued", categories.join(" ") ) )
2017-11-24 14:58:56 +01:00
.map do |row|
{ date: row[ 0 ],
payee: row[ 2 ],
account: row[ 3 ],
amount: row[ 5 ],
currency: row[ 4 ] }
end
end
2017-11-24 10:58:58 +01:00
end