vfwcash 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +107 -0
- data/Rakefile +2 -0
- data/bin/vfwcash +5 -0
- data/lib/models/audit.rb +228 -0
- data/lib/models/balance.rb +95 -0
- data/lib/models/between.rb +100 -0
- data/lib/models/cash_account.rb +69 -0
- data/lib/models/gcash.rb +189 -0
- data/lib/models/ledger.rb +109 -0
- data/lib/models/register.rb +54 -0
- data/lib/models/split.rb +26 -0
- data/lib/models/split_ledger.rb +69 -0
- data/lib/models/sqlite_base.rb +10 -0
- data/lib/models/summary.rb +98 -0
- data/lib/models/tran.rb +12 -0
- data/lib/templates/vfw-gray.png +0 -0
- data/lib/templates/vfwcash.gnucash +0 -0
- data/lib/templates/vfwcash.yml +95 -0
- data/lib/vfwcash/api.rb +48 -0
- data/lib/vfwcash/cli.rb +195 -0
- data/lib/vfwcash/controller.rb +83 -0
- data/lib/vfwcash/version.rb +3 -0
- data/lib/vfwcash.rb +90 -0
- data/pdf_examples/audit_201507.pdf +2826 -0
- data/pdf_examples/balance_201508.pdf +2283 -0
- data/pdf_examples/controllers/checkbooks_controller.rb +99 -0
- data/pdf_examples/ledger_201504.pdf +5758 -0
- data/pdf_examples/ledger_summary.pdf +5719 -0
- data/pdf_examples/register_201508.pdf +1157 -0
- data/pdf_examples/split_201508.pdf +4930 -0
- data/pdf_examples/views/checkbooks/balance.html.slim +53 -0
- data/pdf_examples/views/checkbooks/between.html.slim +53 -0
- data/pdf_examples/views/checkbooks/index.html.slim +57 -0
- data/pdf_examples/views/checkbooks/ledger.html.slim +58 -0
- data/pdf_examples/views/checkbooks/register.html.slim +44 -0
- data/pdf_examples/views/checkbooks/split.html.slim +45 -0
- data/pdf_examples/views/checkbooks/summary.html.slim +56 -0
- data/vfwcash.gemspec +31 -0
- metadata +198 -0
data/lib/vfwcash/api.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
module Vfwcash
|
3
|
+
class Api
|
4
|
+
attr_accessor :config, :cash
|
5
|
+
def initialize(date=nil)
|
6
|
+
@date = date
|
7
|
+
require_relative '../models/sqlite_base'
|
8
|
+
@config = Vfwcash::Config
|
9
|
+
Dir.glob(File.join(LibPath,'models/*')).each do |file|
|
10
|
+
require file
|
11
|
+
end
|
12
|
+
@cash = Gcash.new(@config)
|
13
|
+
unless @cash.dates.include?(@date)
|
14
|
+
puts "No transactions exist for #{@date.beginning_of_month}"
|
15
|
+
exit(0)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def between(from,to)
|
20
|
+
pdf = Pdf::Between.new(@date,@cash,from,to)
|
21
|
+
end
|
22
|
+
|
23
|
+
def ledger
|
24
|
+
pdf = Pdf::Ledger.new(@date,@cash)
|
25
|
+
end
|
26
|
+
|
27
|
+
def summary
|
28
|
+
pdf = Pdf::Summary.new(@cash)
|
29
|
+
end
|
30
|
+
|
31
|
+
def register
|
32
|
+
pdf = Pdf::Register.new(@date,@cash)
|
33
|
+
end
|
34
|
+
|
35
|
+
def split
|
36
|
+
pdf = Pdf::SplitLedger.new(@date,@cash)
|
37
|
+
end
|
38
|
+
|
39
|
+
def audit
|
40
|
+
pdf = Pdf::Audit.new(@date,@cash)
|
41
|
+
end
|
42
|
+
|
43
|
+
def balance
|
44
|
+
pdf = Pdf::Balance.new(@date,@cash)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
data/lib/vfwcash/cli.rb
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
require 'thor'
|
2
|
+
# require 'vfwcash/cli/register'
|
3
|
+
require 'chronic'
|
4
|
+
require 'active_support'
|
5
|
+
|
6
|
+
|
7
|
+
module Vfwcash
|
8
|
+
|
9
|
+
class Checkbook < Thor
|
10
|
+
map %w[--dates -d] => :__print_date_help
|
11
|
+
|
12
|
+
desc "--dates, -d", "print date format options"
|
13
|
+
def __print_date_help
|
14
|
+
puts <<-DATE_HELP
|
15
|
+
The DATE parameter is optional on all reports requiring a date and will default to the current date if not present.
|
16
|
+
|
17
|
+
All dates will be converted to the first of the month requardless of the date entered.
|
18
|
+
|
19
|
+
Entered dates are parsed using Chronic (https://github.com/mojombo/chronic).
|
20
|
+
Chronic provide a wide range options.
|
21
|
+
|
22
|
+
Probably the easiest option is the yyyy-mm format (again day is optional) but you can do stuff like:
|
23
|
+
last-may
|
24
|
+
last-October
|
25
|
+
'oct 2014'
|
26
|
+
DATE_HELP
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "between date1 date2", "Get balances between two dates"
|
30
|
+
long_desc <<-HELLO_WORLD
|
31
|
+
|
32
|
+
Produces a Fund Balance summary between two dates (beginning balance, debits, credits, ending balance) in a compact format.
|
33
|
+
|
34
|
+
HELLO_WORLD
|
35
|
+
|
36
|
+
def between(first, last)
|
37
|
+
sdate = get_date(first)
|
38
|
+
edate = get_date(last)
|
39
|
+
bom = sdate - sdate.day + 1
|
40
|
+
Controller.new(bom).between(sdate,edate)
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
######### VERSION
|
45
|
+
map %w[--version -v] => :__print_version
|
46
|
+
|
47
|
+
desc "--version, -v", "print the version"
|
48
|
+
def __print_version
|
49
|
+
puts "Version: #{Vfwcash::VERSION}"
|
50
|
+
end
|
51
|
+
|
52
|
+
######### INSTALL
|
53
|
+
desc "install [--dir --db]", "Install config files and optional test DB in pwd or pwd/--dir"
|
54
|
+
long_desc <<-HELLO_WORLD
|
55
|
+
|
56
|
+
Install will create two directories [config,pdf]in your current working directory.
|
57
|
+
The PDF directory will contain copies of the generated PDF reports.
|
58
|
+
The config directory will contain a vfwcash.yml file that contains post information,
|
59
|
+
path to sqlit3 database
|
60
|
+
and other configuration data needed to generate a Trustees' Report of Audit.
|
61
|
+
|
62
|
+
-- dir='dirname' will create a new directory in the working directory before the copies
|
63
|
+
|
64
|
+
-- db will copy a GnuCash test sqlite3 database into the config directory
|
65
|
+
|
66
|
+
HELLO_WORLD
|
67
|
+
method_option :dir, type: :string,
|
68
|
+
desc: "Create a new directory",
|
69
|
+
required: false
|
70
|
+
method_option :db, type: :boolean,
|
71
|
+
default: false,
|
72
|
+
desc: "Copy a Test GnuCash Database to the config directory"
|
73
|
+
|
74
|
+
|
75
|
+
def install
|
76
|
+
Vfwcash.install(options)
|
77
|
+
end
|
78
|
+
|
79
|
+
######### REGISTER
|
80
|
+
desc "register [DATE]", "Checkbook register report"
|
81
|
+
long_desc <<-HELLO_WORLD
|
82
|
+
|
83
|
+
Produces a PDF reports of the checkbook register by month. All tranasaction for the month
|
84
|
+
are displayed, ordered by date and check number. A running balance is displayed starting with the
|
85
|
+
beginning balance. There is one line per transaction. Savings account transactions are displayed
|
86
|
+
but the amount is not added to the running balance.
|
87
|
+
|
88
|
+
The --split option displays the same information, but lines are added for each transaction showing
|
89
|
+
the amount of each split by fund or income/expense account
|
90
|
+
|
91
|
+
|
92
|
+
HELLO_WORLD
|
93
|
+
def register( date=nil )
|
94
|
+
bom = get_date(date)
|
95
|
+
Controller.new(bom).register
|
96
|
+
end
|
97
|
+
|
98
|
+
######### SPLIT
|
99
|
+
desc "split [DATE]", "Checkbook split register report"
|
100
|
+
long_desc <<-HELLO_WORLD
|
101
|
+
|
102
|
+
Produces a PDF reports of the checkbook register by month. All tranasaction for the month
|
103
|
+
are displayed, ordered by date and check number. A running balance is displayed starting with the
|
104
|
+
beginning balance. Savings account transactions are displayed
|
105
|
+
but the amount is not added to the running balance.
|
106
|
+
|
107
|
+
Each transaction will have multiple lines displaying
|
108
|
+
the amount of each split by fund or income/expense account
|
109
|
+
|
110
|
+
|
111
|
+
HELLO_WORLD
|
112
|
+
def split( date=nil )
|
113
|
+
bom = get_date(date)
|
114
|
+
Controller.new(bom).split
|
115
|
+
end
|
116
|
+
|
117
|
+
######### LEDGER
|
118
|
+
desc "ledger [DATE]", "General Ledger report by month"
|
119
|
+
long_desc <<-HELLO_WORLD
|
120
|
+
|
121
|
+
Produces a PDF report of the Post's General Ledger formated much like the VFW Ledger book.
|
122
|
+
|
123
|
+
Each transaction displays tranaction information along with each fund distribution. Balances include
|
124
|
+
the beginning balance, total debits(increases) and credits(decreases) and ending balance.
|
125
|
+
|
126
|
+
HELLO_WORLD
|
127
|
+
|
128
|
+
option :summary
|
129
|
+
def ledger( date=nil )
|
130
|
+
bom = get_date(date)
|
131
|
+
Controller.new(bom).ledger
|
132
|
+
end
|
133
|
+
|
134
|
+
######### SUMMARY
|
135
|
+
desc "summary [DATE]", "General Ledger Summary Report"
|
136
|
+
long_desc <<-HELLO_WORLD
|
137
|
+
|
138
|
+
Produces a PDF report containing only a monthly summary of Post's General Ledger.
|
139
|
+
|
140
|
+
The report displays all months in the checkbook but only contains balances, debits and credits sums.
|
141
|
+
|
142
|
+
HELLO_WORLD
|
143
|
+
|
144
|
+
option :summary
|
145
|
+
def summary( date=nil )
|
146
|
+
bom = get_date(date)
|
147
|
+
Controller.new(bom).summary
|
148
|
+
end
|
149
|
+
|
150
|
+
######### Audit
|
151
|
+
desc "audit [DATE]", "Trustee Audit Report "
|
152
|
+
long_desc <<-HELLO_WORLD
|
153
|
+
|
154
|
+
Productes a Trustee Audit Report for the ending quarter that ended before
|
155
|
+
the date enter. If date is not ended, it will be the last report.
|
156
|
+
|
157
|
+
HELLO_WORLD
|
158
|
+
|
159
|
+
def audit( date=nil )
|
160
|
+
bom = get_date(date)
|
161
|
+
Controller.new(bom).audit
|
162
|
+
end
|
163
|
+
|
164
|
+
######### Balance
|
165
|
+
desc "balance [DATE]", "Monthly Fund Balance Summary "
|
166
|
+
long_desc <<-HELLO_WORLD
|
167
|
+
|
168
|
+
Produces a Monthly Fund Balance summary (beginning balance, debits, credits, ending balance) for only one month in a compact format.
|
169
|
+
|
170
|
+
HELLO_WORLD
|
171
|
+
def balance( date=nil )
|
172
|
+
bom = get_date(date)
|
173
|
+
Controller.new(bom).balance
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
|
178
|
+
def get_date(date)
|
179
|
+
if date.nil?
|
180
|
+
bom = Date.today
|
181
|
+
else
|
182
|
+
bom = Chronic.parse(date)
|
183
|
+
if bom.nil?
|
184
|
+
puts "Invalid date #{date}"
|
185
|
+
exit(0)
|
186
|
+
else
|
187
|
+
bom = bom.to_date
|
188
|
+
end
|
189
|
+
end
|
190
|
+
bom
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'sqlite3'
|
3
|
+
require "prawn/table"
|
4
|
+
require "prawn"
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
module Vfwcash
|
8
|
+
class Controller
|
9
|
+
attr_accessor :config, :cash
|
10
|
+
def initialize(date)
|
11
|
+
require_relative '../models/sqlite_base'
|
12
|
+
@config = Vfwcash::Config
|
13
|
+
@date = date
|
14
|
+
Dir.glob(File.join(LibPath,'models/*')).each do |file|
|
15
|
+
require file
|
16
|
+
end
|
17
|
+
@cash = Gcash.new(@config)
|
18
|
+
unless @cash.dates.include?(@date)
|
19
|
+
puts "No transactions exist for #{@date.beginning_of_month}"
|
20
|
+
exit(0)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def between(from,to)
|
25
|
+
pdf = Pdf::Between.new(@date,@cash,from,to)
|
26
|
+
filename = "#{PWD}/pdf/between_#{from}_#{to}.pdf"
|
27
|
+
pdf.render_file(filename)
|
28
|
+
open_pdf(filename)
|
29
|
+
end
|
30
|
+
|
31
|
+
def ledger
|
32
|
+
pdf = Pdf::Ledger.new(@date,@cash)
|
33
|
+
filename = "#{PWD}/pdf/ledger_#{Vfwcash.yyyymm(@date)}.pdf"
|
34
|
+
pdf.render_file(filename)
|
35
|
+
open_pdf(filename)
|
36
|
+
end
|
37
|
+
|
38
|
+
def summary
|
39
|
+
pdf = Pdf::Summary.new(@cash)
|
40
|
+
filename = "#{PWD}/pdf/ledger_summary.pdf"
|
41
|
+
pdf.render_file(filename)
|
42
|
+
open_pdf(filename)
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def register
|
47
|
+
pdf = Pdf::Register.new(@date,@cash)
|
48
|
+
filename = "#{PWD}/pdf/register_#{Vfwcash.yyyymm(@date)}.pdf"
|
49
|
+
pdf.render_file(filename)
|
50
|
+
open_pdf(filename)
|
51
|
+
end
|
52
|
+
|
53
|
+
def split
|
54
|
+
pdf = Pdf::SplitLedger.new(@date,@cash)
|
55
|
+
filename = "#{PWD}/pdf/split_#{Vfwcash.yyyymm(@date)}.pdf"
|
56
|
+
pdf.render_file(filename)
|
57
|
+
open_pdf(filename)
|
58
|
+
end
|
59
|
+
|
60
|
+
def audit
|
61
|
+
pdf = Pdf::Audit.new(@date,@cash)
|
62
|
+
filename = "#{PWD}/pdf/audit_#{Vfwcash.yyyymm(@date.beginning_of_quarter)}.pdf"
|
63
|
+
pdf.render_file(filename)
|
64
|
+
open_pdf(filename)
|
65
|
+
end
|
66
|
+
|
67
|
+
def balance
|
68
|
+
pdf = Pdf::Balance.new(@date,@cash)
|
69
|
+
filename = "#{PWD}/pdf/balance_#{Vfwcash.yyyymm(@date)}.pdf"
|
70
|
+
pdf.render_file(filename)
|
71
|
+
open_pdf(filename)
|
72
|
+
end
|
73
|
+
|
74
|
+
def open_pdf(filename)
|
75
|
+
if Gem::Platform.local.os == 'darwin'
|
76
|
+
`open #{filename}`
|
77
|
+
else
|
78
|
+
`start #{filename}`
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
data/lib/vfwcash.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require "vfwcash/version"
|
2
|
+
require 'vfwcash/cli'
|
3
|
+
require 'vfwcash/controller'
|
4
|
+
require 'vfwcash/api'
|
5
|
+
|
6
|
+
module Vfwcash
|
7
|
+
# Define constants to define where your are and location of config file
|
8
|
+
LibPath = File.expand_path(File.dirname(__FILE__))
|
9
|
+
PWD = Dir.pwd
|
10
|
+
Config = YAML.load_file(File.join(PWD,'config/vfwcash.yml'))
|
11
|
+
|
12
|
+
def self.yyyymm(date=nil)
|
13
|
+
date = Vfwcash.set_date(date)
|
14
|
+
yyyymm = date.strftime('%Y%m') # "#{date.year}#{date.month.to_s.rjust(2,'0')}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.transaction_range
|
18
|
+
t = Tran.order(:post_date)
|
19
|
+
first = Date.parse(t.first.post_date).beginning_of_month
|
20
|
+
last = Date.parse(t.last.post_date).end_of_month
|
21
|
+
first..last
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.set_date(date=nil)
|
25
|
+
if date.nil? || date == ""
|
26
|
+
date = Date.today
|
27
|
+
elsif date.class == Date
|
28
|
+
else
|
29
|
+
if date.length == 6
|
30
|
+
date += '01'
|
31
|
+
end
|
32
|
+
date = Date.parse(date)
|
33
|
+
end
|
34
|
+
date
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.money(int)
|
38
|
+
dollars = int / 100
|
39
|
+
cents = (int % 100) / 100.0
|
40
|
+
amt = dollars + cents
|
41
|
+
set_zero = sprintf('%.2f',amt) # now have a string to 2 decimals
|
42
|
+
set_zero.gsub(/(\d)(?=(\d{3})+(?!\d))/, "\\1,") # add commas
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.valid_root?
|
46
|
+
unless Dir.exist?(PWD+'/config') && Dir.exist?(PWD+'/pdf') && File.exist?(PWD+"/config/"+"vfwcash.yml")
|
47
|
+
puts "Error: vfwcash must be run from a diectory containing valid configuration files"
|
48
|
+
exit(0)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.install(options)
|
53
|
+
wd = PWD
|
54
|
+
ok = true
|
55
|
+
if options['dir'].present?
|
56
|
+
unless Dir.exist?(wd+options['dir'])
|
57
|
+
Dir.mkdir(wd+'/'+options['dir'])
|
58
|
+
puts "Created a new directory in #{wd}"
|
59
|
+
ok = false
|
60
|
+
Dir.chdir(wd+'/'+options['dir'])
|
61
|
+
wd = Dir.pwd
|
62
|
+
end
|
63
|
+
end
|
64
|
+
unless Dir.exist?(wd+'/config')
|
65
|
+
Dir.mkdir(wd+'/config')
|
66
|
+
puts "Created config directory in #{wd}"
|
67
|
+
ok = false
|
68
|
+
end
|
69
|
+
unless Dir.exist?(wd+'/pdf')
|
70
|
+
Dir.mkdir(wd+'/pdf')
|
71
|
+
puts "Created pdf directory in #{wd}"
|
72
|
+
ok = false
|
73
|
+
end
|
74
|
+
unless File.exist?(wd+"/config/"+"vfwcash.yml")
|
75
|
+
FileUtils.cp((LibPath+"/templates/vfwcash.yml"),(wd+"/config/"+"vfwcash.yml"))
|
76
|
+
puts "Created vfwcash.yml file in config directory, must be edited for your post."
|
77
|
+
ok = false
|
78
|
+
end
|
79
|
+
if options['db']
|
80
|
+
unless File.exist?(wd+"/config/"+"vfwcash.gnucash")
|
81
|
+
FileUtils.cp((LibPath+"/templates/vfwcash.gnucash"),(wd+"/config/"+"vfwcash.gnucash"))
|
82
|
+
puts "Created vfwcash.gnucash db in config directory."
|
83
|
+
ok = false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
puts "No installation required" if ok
|
88
|
+
puts "Installation complete. Edit your vfwcash.yml file to set your post information." if !ok
|
89
|
+
end
|
90
|
+
end
|