simple-ynab 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/bin/simple-ynab +113 -27
  3. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9a881eee0ab99fe8a8d82d526a29f16793682fc8
4
- data.tar.gz: 02b3e8d3895b1a3e27d0ae71225a2dd44e80a9ca
3
+ metadata.gz: 01d194396c8cdff4df84b40021ac98a64a572f69
4
+ data.tar.gz: 06ea74ea4e20eccd2924b295f866f8c695505fc0
5
5
  SHA512:
6
- metadata.gz: 720f9333ce2434522d154742548f0eb652eb7e1f41b2fe2786fc9161eb3562c16a2b49c6ad16ca594caf14a0a97a6626f706fbab451cc96f3ebcf5c6a809087c
7
- data.tar.gz: 2cdc73c61b92a69068de418ba4ac53c8b4ff839241f55590706aa2a62b7c18ab5288e3602bc9e8944bea96218081f2d1f4709abdbad3134d7dade85014f4ee78
6
+ metadata.gz: 754c93c1147dcea2fa632c8eedb534094a555ce9b00bbbfd2d820c4f102a2a84cc12d87f56ba879c0c5119a80f3ec2dcdb6f5d4e2e724838fd1e004e84e34ba4
7
+ data.tar.gz: 9fca07efdd7b2db2737093f4236ba47b5940e54fefeb19e7ecad00fad059e00ae8e8be36550dfda0c61056fda17bbad35539b8f535fe236594fb4a86d0aa6447
@@ -1,49 +1,135 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ # Converts the CSV generated by Simple Bank into a CSV understandable by YNAB
3
4
  require 'csv'
5
+ require 'slop'
6
+ require 'colorize'
7
+ require 'Date'
4
8
 
9
+ opts = Slop.parse(:banner => 'simple-ynab', :help => true ) do
10
+ on 'd', 'days=', 'Strips all rows before x days ago, e.g -d 30 ', :argument => true
11
+ on 'y', 'ynab_date', 'Converts date to MM/DD/YYYY. SEE README.md FOR WARNINGS!!!', :argument => false
12
+ on 'p', 'pending', 'Include pending transactions', :argument => false
13
+ on 'v', 'verbose', 'Print debug information', :argument => false
14
+ on 'x', 'very_verbose', 'Prints an uncomfortable amount of debugging information to terminal, does not replace -v', :argument => false
15
+ end
5
16
 
6
- @simple_keywords = ["Date", "Description", "Category", "Memo", "Amount"]
7
- @ynab_keywords = ["Date", "Payee", "Category", "Memo", "Amount"]
8
-
9
- @newcsv = []
10
- puts ""
11
-
17
+ # Which column headers in the Simple CSV match up with the columns headers needed by YNAB
18
+ simple_keywords = ["Date", "Description", "Category", "Memo", "Amount"]
19
+ ynab_keywords = ["Date", "Payee", "Category", "Memo", "Amount"]
12
20
 
13
- # Get the csv file from args or prompt user
21
+ ##### Get the csv file from args
14
22
  ARGV.each do |argument|
15
- @csvfile = ARGV[0]
23
+ @csvfile = ARGV[0]
16
24
  end
17
25
 
26
+ Kernel.trap('INT') { Kernel.exit } #Exit cleanly with ctrl+c
27
+
18
28
  if ARGV.empty?
19
- print "No file detected, enter file name: "
20
- @csvfile = gets
29
+ print "No file detected, enter file name: "
30
+ @csvfile = gets
21
31
  end
22
32
 
33
+
23
34
  # Import csv
24
- csv = CSV.read(@csvfile, headers: true) #http://bit.ly/1mSlqfA
25
- # @headers = CSV.open('foo.csv','r', :headers => true).read.headers
35
+ if opts.verbose? then puts "Importing CSV".magenta end
36
+ simplecsv = CSV.read(@csvfile) #http://bit.ly/1mSlqfA
37
+ if opts.verbose? then puts "Headers are: #{simplecsv[0]}".blue end
26
38
 
27
- # Rename the Simple csv headers to match the ynab csv headers
28
- indicies = @simple_keywords.map{ |column| csv.headers.index(column)}
29
39
 
30
- # Create a new csv file with the columns in the ynab order
31
- @newcsv = csv.map { |row| row.values_at(*indicies) }
40
+ # Get the 'simple' header indicies
41
+ simple_headers = simple_keywords.map{ |column| simplecsv[0].index(column)}
42
+ if opts.verbose? then puts "Simple_headers indexes are #{simple_headers}".blue end
32
43
 
33
44
 
34
- filename = File.basename(@csvfile,".*")
35
- pathname = File.join( File.dirname(@csvfile), "#{filename}.simple.csv" )
45
+ # Create a new array that omits the CSV rows when the value in the 'Pending' column = true
46
+ if opts.verbose? then puts "Removing pending transactions".magenta end
47
+ if opts.pending? then puts "User chose to include pending transactions".blue end
48
+ no_pending_array = Array.new()
49
+ pending = simplecsv[0].find_index('Pending') # Column number that contains 'Pending'
50
+ simplecsv.each do |row|
51
+ # If -p (Pending) option is not provided, Only push rows with 'false' in the pending column.
52
+ # Make sure header (row 0) gets included too.
53
+ if opts.pending? or row[pending].to_s.casecmp('false') == 0 or row[pending].to_s.casecmp('Pending') == 0
54
+ no_pending_array.push(row)
55
+ else
56
+ if opts.verbose? then puts "Removing pending transaction #{row}".yellow end
57
+ end
58
+ end
59
+
60
+
61
+ # Create a new array that only includes the YNAB columns
62
+ ynab_array = Array.new()
63
+ no_pending_array.each do |row| #Itterate over every row in new 'pending free' array
64
+ newrow = Array.new() #Create a temporary array
65
+ simple_headers.each do | desired_index | #Itterate over each of the columsn we want e.g. [0, 7, 9, 16, 3]
66
+ newrow.push(row[desired_index]) #Add the new value to the temporary array
67
+ end
68
+ ynab_array.push(newrow) #Add each row to the new YNAB array
69
+ end
36
70
 
37
71
 
38
- # Save headers to file
39
- puts "Saving new file to #{pathname}"
40
- CSV.open(pathname, 'w') do |the_csv|
41
- the_csv << @ynab_keywords
72
+ # Replace the headers with the YNAB headers
73
+ if opts.verbose?
74
+ puts "Replacing csv headers with ynab headers".magenta
75
+ puts "Simple column headers #{ynab_array[0]}".blue
42
76
  end
77
+ ynab_array[0] = ynab_keywords
78
+ if opts.verbose? then puts "YNAB column headers are #{ynab_array[0]}".blue end
79
+
80
+
81
+ # Only include dates within the specified range
82
+ ynab_array_less_dates = Array.new()
83
+ ynab_array_less_dates[0] = ynab_array[0] # Copy the header to new array
84
+ days_ago = Date.today() - opts[:days].to_i
85
+ date_column = ynab_array[0].find_index('Date') #Find the index of colum that contains 'Date' data (usually [0])
86
+ ynab_array.each do | row |
87
+ if opts.days? # User specified number of days to copy from CSV
88
+ if row[date_column] =~ /\d/ and Date.parse(row[date_column]) >= days_ago #Only apply to rows that contain dates, skip rows without nummbers (e.g. header row)
89
+ if opts.very_verbose? then puts "Transaction was less than #{opts[:days].to_i} days ago: #{row}".light_green end
90
+ ynab_array_less_dates.push(row) # Only push rows less than x number of days old
91
+ else
92
+ if opts.very_verbose? then puts "Transaction was more than #{opts[:days].to_i} days ago: #{row}".yellow end
93
+ end
94
+ else
95
+ ynab_array_less_dates.push(row) # Push all rows
96
+ end
97
+ end
98
+
99
+
100
+ # Change the dates from YYYY-MM-DD to MM-DD-YYYY, saves 1 click when importing in YNAB
101
+ # Has side affect of sometimes causing YNAB to fail to match previously imported transactions
102
+ if opts.ynab_date?
103
+ puts "WARNING: YNAB may fail to match transactions previously imported with different date formats".red
104
+ puts "Converting dates to MM/DD/YYYY".red
105
+ if opts.verbose? then puts "Changing simple dates to ynab dates".magenta end
106
+ if ynab_array_less_dates[0].any?{|s| s.casecmp('date')==0}
107
+ date_column = ynab_array_less_dates[0].find_index('Date') #Find the index of colum that contains 'Date' data (usually [0])
108
+ else
109
+ puts "Unable to find word 'Date' in csv header. #{ynab_array_less_dates[0]}".red
110
+ exit
111
+ end
112
+ if opts.verbose? then puts "The date column in ynab_array_less_dates is #{date_column}: #{ynab_array_less_dates[0][date_column]}".blue end
113
+ ynab_array_less_dates.each do |row|
114
+ if row[date_column] =~ /\d/ #Only apply to rows that contain dates, skip rows without nummbers (e.g. header row)
115
+ row[date_column] = Date.parse(row[date_column]).strftime(format='%m/%d/%Y').to_s
116
+ else
117
+ if opts.verbose? then puts "Not changing date syntax on header row #{row}".blue end
118
+ end
119
+ end
120
+ end
121
+
122
+
123
+ # Save to file
124
+ if opts.verbose? then puts "Saving to CSV file".magenta end
125
+
126
+ filename = File.basename(@csvfile,".*")
127
+ pathname = File.join( File.dirname(@csvfile), "#{filename}.simple.csv" )
128
+ puts ""
129
+ puts "Saving to new file: #{pathname}".green
43
130
 
44
- # Append the new csv to the file
45
- CSV.open(pathname, 'a+') do |the_csv|
46
- @newcsv.each do |row|
47
- the_csv << row
48
- end
131
+ CSV.open(pathname,'w') do |csv|
132
+ ynab_array_less_dates.each do | row |
133
+ csv << row
134
+ end
49
135
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple-ynab
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Spencer Owen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-19 00:00:00.000000000 Z
11
+ date: 2014-11-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Converts simple bank csv to ynab csv
14
14
  email: owenspencer@gmail.com
@@ -18,7 +18,7 @@ extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
20
  - bin/simple-ynab
21
- homepage:
21
+ homepage: https://github.com/spuder/simple-ynab
22
22
  licenses:
23
23
  - MIT
24
24
  metadata: {}
@@ -43,3 +43,4 @@ signing_key:
43
43
  specification_version: 4
44
44
  summary: Converts csv from simple format to ynab format
45
45
  test_files: []
46
+ has_rdoc: