simple-ynab 0.0.3 → 0.1.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.
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: