stripe-iiftoqbo 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.rspec +4 -0
- data/LICENSE +22 -0
- data/README.md +97 -0
- data/bin/stripe-iiftoqbo +53 -0
- data/lib/iif/entry.rb +6 -0
- data/lib/iif/parser.rb +92 -0
- data/lib/iif/transaction.rb +9 -0
- data/lib/iif.rb +15 -0
- data/lib/ofx/transaction.rb +14 -0
- data/lib/ofx.rb +156 -0
- data/lib/stripe-iiftoqbo.rb +138 -0
- data/spec/iif_spec.rb +43 -0
- data/spec/ofx_spec.rb +59 -0
- data/spec/sample-data/basic.csv +12 -0
- data/spec/sample-data/basic.iif +28 -0
- data/spec/sample-data/basic.qbo +11 -0
- data/spec/sample-data/empty.csv +1 -0
- data/spec/sample-data/empty.iif +0 -0
- data/spec/sample-data/empty.ofx +11 -0
- data/spec/sample-data/empty.qbo +11 -0
- data/spec/sample-data/with-bank-info.ofx +11 -0
- data/spec/sample-data/with-transaction.ofx +11 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/stripe-iiftoqbo_spec.rb +31 -0
- data/stripe-iiftoqbo.gemspec +18 -0
- metadata +106 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
MIT License
|
2
|
+
-----------
|
3
|
+
|
4
|
+
Copyright (c) 2014, Gilman Tolle
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
14
|
+
all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
## Stripe IIF to QuickBooks Online QBO File Translator
|
2
|
+
|
3
|
+
Does your company use Stripe to charge credit cards?
|
4
|
+
|
5
|
+
Does your company use QuickBooks Online for accounting?
|
6
|
+
|
7
|
+
Did you export your full transaction history from Stripe as an .IIF file?
|
8
|
+
|
9
|
+
Did you hope to import that transaction history into QuickBooks Online to do your taxes?
|
10
|
+
|
11
|
+
Did you realize that QBO doesn't support importing data from .IIF files, which is what Stripe gave you?
|
12
|
+
|
13
|
+
Then this tool might be helpful.
|
14
|
+
|
15
|
+
Stripe-iiftoqbo takes an IIF file and produces a QBO file that you can import into QuickBooks Online.
|
16
|
+
|
17
|
+
It's pretty hacky, and I've only tested it for my use case. My IIF file had:
|
18
|
+
|
19
|
+
* Credit Card Payments
|
20
|
+
* Subscription Credit Card Payments
|
21
|
+
* Credit Card Refunds
|
22
|
+
* Transfers to our Checking Account
|
23
|
+
* Payouts to Third Parties
|
24
|
+
* Stripe Connect Fees Collected
|
25
|
+
* Stripe Connect Fees Refunded
|
26
|
+
* … and Stripe Transaction Fees, of course :)
|
27
|
+
|
28
|
+
But now our 2013 taxes are done!
|
29
|
+
|
30
|
+
I used the Stripe export to come up with our top-line revenue (from credit card payments), and our cost of goods sold (since we're a marketplace, that's payouts to vendors and stripe fees). And all the transfers to our checking account tallied with transfers into our checking account (as seen by our bank).
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
Usage: stripe-iiftoqbo [-p PAYMENTS_CSV_FILE] [-c] ACCOUNT_NAME IIF_FILE
|
35
|
+
|
36
|
+
## Quickstart
|
37
|
+
|
38
|
+
First, get your IIF file from Stripe.
|
39
|
+
|
40
|
+
Go to your Stripe Dashboard, then your account menu, then Account Settings. Go to the Data tab, and hit "Export to Quickbooks". Choose your date range (e.g. all of 2013), and hit Export to IIF.
|
41
|
+
|
42
|
+
Double-check your file to make sure it's an .IIF.
|
43
|
+
|
44
|
+
$ head balance_history.iif
|
45
|
+
!TRNS TRNSID TRNSTYPE DATE ACCNT AMOUNT MEMO
|
46
|
+
!SPL TRNSID TRNSTYPE DATE ACCNT AMOUNT MEMO
|
47
|
+
!ENDTRNS
|
48
|
+
TRNS PAYOUT (FIRST LAST) 01/23/2014 Third-party Account 135.15 Transfer from Stripe: tr_3MCmCnHFyYXFB5
|
49
|
+
SPL PAYOUT (FIRST LAST) 01/23/2014 Stripe Account -135.4 Transfer from Stripe: tr_3MCmCnHFyYXFB5
|
50
|
+
SPL GENERAL JOURNAL 01/23/2014 Stripe Payment Processing Fees 0.25 Fees for transfer ID: tr_3MCmCnHFyYXFB5
|
51
|
+
ENDTRNS
|
52
|
+
|
53
|
+
Pick a name for your company (e.g. MyCompanyName). It's going to be saved into the QBO file. I'd recommend using your Stripe Account Name.
|
54
|
+
|
55
|
+
Then, run the app:
|
56
|
+
|
57
|
+
ruby -Ilib bin/stripe-iiftoqbo MyCompanyName balance_history.iif > balance_history.qbo
|
58
|
+
|
59
|
+
You'll get a nice .QBO file with all of your transactions.
|
60
|
+
|
61
|
+
Now, go to QuickBooks Online. Go to the 'gear' menu and hit 'Chart of Accounts'. Create a new 'Bank' > 'Checking' account and call it 'Stripe'.
|
62
|
+
|
63
|
+
Now go to the Transactions > Banking page. Hit the dropdown arrow next to Update and choose 'File Upload'.
|
64
|
+
|
65
|
+
Upload your new .QBO file. You should see the company name you specified, and a date range from the IIF file. Choose your 'Stripe' account from the QuickBooks Online dropdown.
|
66
|
+
|
67
|
+
You should see a line item for each:
|
68
|
+
|
69
|
+
* Credit Card Charge you collected
|
70
|
+
* Stripe Fee you paid on that charge
|
71
|
+
* Transfer to your checking account
|
72
|
+
* Transfer to a third-party using Stripe Payounts
|
73
|
+
* Stripe Fee you paid on that transfer
|
74
|
+
* Stripe Connect Fee you collected
|
75
|
+
* Credit Card Charge that was refunded
|
76
|
+
* Refund of Stripe Fee for that charge
|
77
|
+
|
78
|
+
Categorize and accept each transaction. Now you can see how much you made, how much you paid to Stripe, and how much you paid to your vendors.
|
79
|
+
|
80
|
+
## Extras
|
81
|
+
|
82
|
+
If you want to merge the description for each payment into the 'memo' field of your QBO file so you can see them in QuickBooks, go to the Stripe Payments page and export your payments as a CSV. It'll look like this:
|
83
|
+
|
84
|
+
$ head payments.csv
|
85
|
+
id,Description,Created,Amount,Amount Refunded,Currency,Converted Amount,Converted Amount Refunded,Fee,Converted Currency,Mode,Status,Customer ID,Customer Description,Customer Email,Captured,Card Last4,Card Type,Card Exp Month,Card Exp Year,Card Name,Card Address Line1,Card Address Line2,Card Address City,Card Address State,Card Address Country,Card Address Zip,Card Issue Country,Card Fingerprint,Card CVC Status,Card AVS Zip Status,Card AVS Line1 Status,Dispute Status
|
86
|
+
ch_3QSlijsVumgdnQ,,2014-02-03 01:47,19.00,0.00,usd,19.00,0.00,0.85,usd,Live,Paid,cus_29a92b191,test@test.com,,true,1111,Visa,1,2016,,,,,,,,US,ztg6Hv5g3sbjBE57,,,,
|
87
|
+
ch_3PimG0oAu3LRSg,Test Description To Merge,2014-02-01 02:16,249.00,0.00,usd,249.00,0.00,7.52,usd,Live,Paid,cus_292ab3c2b,test@test.com,,true,2222,Visa,1,2016,,,,,,,,US,2Xv5QDDhdKj23Z0l,,,,
|
88
|
+
|
89
|
+
Then, run the tool again with ```-p payments.csv```. For each charge in the IIF, if there's a matching Charge ID in the payments file, the tool will merge it into the QBO memo.
|
90
|
+
|
91
|
+
If you want to inspect the transactions from your .IIF file in CSV format (using Excel, for example), give the '-c' flag. It'll dump CSV instead of QBO.
|
92
|
+
|
93
|
+
## License
|
94
|
+
|
95
|
+
New MIT License - Copyright (c) 2014, Gilman Tolle
|
96
|
+
|
97
|
+
See LICENSE for details
|
data/bin/stripe-iiftoqbo
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'bigdecimal'
|
5
|
+
require 'csv'
|
6
|
+
require 'pp'
|
7
|
+
|
8
|
+
require 'stripe-iiftoqbo'
|
9
|
+
|
10
|
+
account_id = nil
|
11
|
+
iif_file = nil
|
12
|
+
dump_csv = false
|
13
|
+
payments_file = nil
|
14
|
+
|
15
|
+
optparser = OptionParser.new do |opts|
|
16
|
+
executable_name = File.split($0)[1]
|
17
|
+
opts.banner = <<-EOS
|
18
|
+
|
19
|
+
Usage: #{executable_name} [-p PAYMENTS_CSV_FILE] [-c] ACCOUNT_NAME IIF_FILE
|
20
|
+
|
21
|
+
Stripe-iiftoqbo converts an .iif file of your live transaction data
|
22
|
+
exported from Stripe into a .qbo file that can be imported into
|
23
|
+
QuickBooks Online.
|
24
|
+
|
25
|
+
ACCOUNT_NAME : the name of your Stripe account to be included into your .qbo file (required)
|
26
|
+
IIF_FILE : the .iif file to convert (required)
|
27
|
+
|
28
|
+
EOS
|
29
|
+
|
30
|
+
opts.on('-p', '--payments [PAYMENTS_CSV_FILE]', "Populate .qbo transaction memo using memo field from a Stripe Payments CSV export") do |filename|
|
31
|
+
payments_file = filename
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on('-c', '--csv', "Output CSV of transactions instead of QBO, for debugging and analysis") do
|
35
|
+
dump_csv = true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
optparser.parse!
|
40
|
+
|
41
|
+
if ARGV.length < 2
|
42
|
+
puts optparser
|
43
|
+
exit(-1)
|
44
|
+
end
|
45
|
+
|
46
|
+
iiftoqbo = StripeIIFToQBO::Converter.new( :account_id => ARGV[0],
|
47
|
+
:iif_file => ARGV[1],
|
48
|
+
:payments_file => payments_file )
|
49
|
+
if dump_csv
|
50
|
+
puts iiftoqbo.to_csv
|
51
|
+
else
|
52
|
+
puts iiftoqbo.to_qbo
|
53
|
+
end
|
data/lib/iif/entry.rb
ADDED
data/lib/iif/parser.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
|
3
|
+
require_relative 'transaction'
|
4
|
+
require_relative 'entry'
|
5
|
+
|
6
|
+
module IIF
|
7
|
+
class Parser
|
8
|
+
attr_accessor :definitions
|
9
|
+
attr_accessor :entries
|
10
|
+
attr_accessor :transactions
|
11
|
+
|
12
|
+
def initialize(resource)
|
13
|
+
@definitions = {}
|
14
|
+
@entries = []
|
15
|
+
@transactions = []
|
16
|
+
|
17
|
+
resource = open_resource(resource)
|
18
|
+
resource.rewind
|
19
|
+
parse_file(resource)
|
20
|
+
create_transactions
|
21
|
+
end
|
22
|
+
|
23
|
+
def open_resource(resource)
|
24
|
+
if resource.respond_to?(:read)
|
25
|
+
resource
|
26
|
+
else
|
27
|
+
open(resource)
|
28
|
+
end
|
29
|
+
rescue Exception
|
30
|
+
StringIO.new(resource)
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse_file(resource)
|
34
|
+
resource.each_line do |line|
|
35
|
+
fields = line.strip.split(/\t/)
|
36
|
+
if fields[0][0] == '!'
|
37
|
+
parse_definition(fields)
|
38
|
+
else
|
39
|
+
parse_data(fields)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse_definition(fields)
|
45
|
+
key = fields[0][1..-1]
|
46
|
+
values = fields[1..-1]
|
47
|
+
@definitions[key] = values.map { |v| v.downcase }
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_data(fields)
|
51
|
+
definition = @definitions[fields[0]]
|
52
|
+
|
53
|
+
entry = Entry.new
|
54
|
+
entry.type = fields[0]
|
55
|
+
|
56
|
+
fields[1..-1].each_with_index do |field, idx|
|
57
|
+
entry.send(definition[idx] + "=", field)
|
58
|
+
end
|
59
|
+
|
60
|
+
entry.amount = BigDecimal.new(entry.amount) if entry.amount
|
61
|
+
entry.date = Date.strptime(entry.date, "%m/%d/%Y") if entry.date
|
62
|
+
|
63
|
+
@entries.push(entry)
|
64
|
+
end
|
65
|
+
|
66
|
+
def create_transactions
|
67
|
+
transaction = nil
|
68
|
+
in_transaction = false
|
69
|
+
|
70
|
+
@entries.each do |entry|
|
71
|
+
|
72
|
+
case entry.type
|
73
|
+
|
74
|
+
when "TRNS"
|
75
|
+
if in_transaction
|
76
|
+
@transactions.push(transaction)
|
77
|
+
in_transaction = false
|
78
|
+
end
|
79
|
+
transaction = Transaction.new
|
80
|
+
in_transaction = true
|
81
|
+
|
82
|
+
when "ENDTRNS"
|
83
|
+
@transactions.push(transaction)
|
84
|
+
in_transaction = false
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
transaction.entries.push(entry) if in_transaction
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/iif.rb
ADDED
data/lib/ofx.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
|
3
|
+
require "ofx/transaction"
|
4
|
+
|
5
|
+
module OFX
|
6
|
+
class Builder
|
7
|
+
|
8
|
+
attr_accessor :fi_org
|
9
|
+
attr_accessor :fi_fid
|
10
|
+
attr_accessor :dtserver
|
11
|
+
|
12
|
+
attr_accessor :bank_id
|
13
|
+
attr_accessor :acct_id
|
14
|
+
attr_accessor :acct_type # CHECKING, SAVINGS, MONEYMRKT, CREDITLINE
|
15
|
+
|
16
|
+
attr_accessor :dtstart
|
17
|
+
attr_accessor :dtend
|
18
|
+
|
19
|
+
attr_accessor :transactions
|
20
|
+
|
21
|
+
attr_accessor :bal_amt
|
22
|
+
attr_accessor :dtasof
|
23
|
+
|
24
|
+
def initialize(&block)
|
25
|
+
@headers = [
|
26
|
+
[ "OFXHEADER", "100" ],
|
27
|
+
[ "DATA", "OFXSGML" ],
|
28
|
+
[ "VERSION", "103" ],
|
29
|
+
[ "SECURITY", "NONE" ],
|
30
|
+
[ "ENCODING", "USASCII" ],
|
31
|
+
[ "CHARSET", "1252" ],
|
32
|
+
[ "COMPRESSION", "NONE" ],
|
33
|
+
[ "OLDFILEUID", "NONE" ],
|
34
|
+
[ "NEWFILEUID", "NONE" ]
|
35
|
+
]
|
36
|
+
@transactions = []
|
37
|
+
self.dtserver = Date.today
|
38
|
+
if block_given?
|
39
|
+
yield self
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def bal_amt=(amt)
|
44
|
+
@bal_amt = BigDecimal.new(amt)
|
45
|
+
end
|
46
|
+
|
47
|
+
def transaction(&block)
|
48
|
+
transaction = OFX::Transaction.new
|
49
|
+
yield transaction
|
50
|
+
self.transactions.push transaction
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_ofx
|
54
|
+
print_headers +
|
55
|
+
print_body
|
56
|
+
end
|
57
|
+
|
58
|
+
def print_headers
|
59
|
+
@headers.map { |key, value| "#{key}:#{value}" }.join("\n") + "\n\n"
|
60
|
+
end
|
61
|
+
|
62
|
+
def print_body
|
63
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
64
|
+
xml.OFX {
|
65
|
+
xml.SIGNONMSGSRSV1 {
|
66
|
+
xml.SONRS {
|
67
|
+
xml.STATUS {
|
68
|
+
xml.CODE "0"
|
69
|
+
xml.SEVERITY "INFO"
|
70
|
+
}
|
71
|
+
xml.DTSERVER format_datetime(self.dtserver)
|
72
|
+
xml.LANGUAGE "ENG"
|
73
|
+
xml.FI {
|
74
|
+
xml.ORG self.fi_org
|
75
|
+
xml.FID self.fi_fid
|
76
|
+
}
|
77
|
+
xml.send "INTU.BID", self.fi_fid
|
78
|
+
}
|
79
|
+
}
|
80
|
+
xml.BANKMSGSRSV1 {
|
81
|
+
xml.STMTTRNRS {
|
82
|
+
xml.TRNUID "0"
|
83
|
+
xml.STATUS {
|
84
|
+
xml.CODE "0"
|
85
|
+
xml.SEVERITY "INFO"
|
86
|
+
}
|
87
|
+
xml.STMTRS {
|
88
|
+
xml.CURDEF "USD"
|
89
|
+
xml.BANKACCTFROM {
|
90
|
+
xml.BANKID self.bank_id
|
91
|
+
xml.ACCTID self.acct_id
|
92
|
+
xml.ACCTTYPE self.acct_type
|
93
|
+
}
|
94
|
+
xml.BANKTRANLIST {
|
95
|
+
if self.dtstart
|
96
|
+
xml.DTSTART format_date(self.dtstart)
|
97
|
+
end
|
98
|
+
if self.dtend
|
99
|
+
xml.DTEND format_date(self.dtend)
|
100
|
+
end
|
101
|
+
self.transactions.each do |transaction|
|
102
|
+
xml.STMTTRN {
|
103
|
+
xml.TRNTYPE format_trntype(transaction.trnamt)
|
104
|
+
xml.DTPOSTED format_date(transaction.dtposted)
|
105
|
+
xml.TRNAMT format_amount(transaction.trnamt)
|
106
|
+
xml.FITID transaction.fitid
|
107
|
+
xml.NAME transaction.name
|
108
|
+
xml.MEMO transaction.memo
|
109
|
+
}
|
110
|
+
end
|
111
|
+
}
|
112
|
+
xml.LEDGERBAL {
|
113
|
+
if self.bal_amt
|
114
|
+
xml.BALAMT format_balance(self.bal_amt)
|
115
|
+
end
|
116
|
+
if self.dtasof
|
117
|
+
xml.DTASOF format_date(self.dtasof)
|
118
|
+
end
|
119
|
+
}
|
120
|
+
}
|
121
|
+
}
|
122
|
+
}
|
123
|
+
}
|
124
|
+
end
|
125
|
+
builder.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML | Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
|
126
|
+
end
|
127
|
+
|
128
|
+
def format_datetime(time)
|
129
|
+
time.strftime("%Y%m%d000000")
|
130
|
+
end
|
131
|
+
|
132
|
+
def format_date(time)
|
133
|
+
time.strftime("%Y%m%d")
|
134
|
+
end
|
135
|
+
|
136
|
+
def format_amount(amount)
|
137
|
+
if amount > 0
|
138
|
+
"+#{amount.to_s('F')}"
|
139
|
+
else
|
140
|
+
"#{amount.to_s('F')}"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def format_trntype(amount)
|
145
|
+
if amount > 0
|
146
|
+
"CREDIT"
|
147
|
+
else
|
148
|
+
"DEBIT"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def format_balance(balance)
|
153
|
+
balance.to_s('F')
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'csv'
|
2
|
+
require_relative 'iif'
|
3
|
+
require_relative 'ofx'
|
4
|
+
|
5
|
+
module StripeIIFToQBO
|
6
|
+
class Converter
|
7
|
+
def initialize( options={} )
|
8
|
+
@account_id = options[:account_id] if options[:account_id]
|
9
|
+
@iif_file = options[:iif_file] if options[:iif_file]
|
10
|
+
@payments_file = options[:payments_file] if options[:payments_file]
|
11
|
+
@server_time = options[:server_time] || Date.today
|
12
|
+
|
13
|
+
load_payments_file(@payments_file)
|
14
|
+
load_iif_file(@iif_file)
|
15
|
+
end
|
16
|
+
|
17
|
+
def load_payments_file(payments_file)
|
18
|
+
@payments = {}
|
19
|
+
|
20
|
+
if payments_file
|
21
|
+
CSV.foreach(payments_file, :headers => true, :encoding => 'windows-1251:utf-8') do |row|
|
22
|
+
@payments[row["id"]] = row["Description"] || ""
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def load_iif_file(iif_file)
|
28
|
+
@ofx_entries = []
|
29
|
+
|
30
|
+
if iif_file
|
31
|
+
IIF(iif_file) do |iif|
|
32
|
+
iif.transactions.each do |transaction|
|
33
|
+
transaction.entries.each do |iif_entry|
|
34
|
+
ofx_entry = convert_iif_entry_to_ofx(iif_entry)
|
35
|
+
if ofx_entry
|
36
|
+
@ofx_entries.push( ofx_entry )
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def convert_iif_entry_to_ofx(iif_entry)
|
45
|
+
ofx_entry = {}
|
46
|
+
|
47
|
+
ofx_entry[:date] = iif_entry.date
|
48
|
+
ofx_entry[:fitid] = iif_entry.memo
|
49
|
+
ofx_entry[:accnt] = iif_entry.accnt
|
50
|
+
ofx_entry[:trnstype] = iif_entry.trnstype
|
51
|
+
ofx_entry[:memo] = iif_entry.memo
|
52
|
+
|
53
|
+
case iif_entry.accnt
|
54
|
+
|
55
|
+
when "Stripe Third-party Account"
|
56
|
+
ofx_entry[:amount] = -iif_entry.amount
|
57
|
+
ofx_entry[:name] = iif_entry.name
|
58
|
+
when "Stripe Payment Processing Fees"
|
59
|
+
ofx_entry[:amount] = -iif_entry.amount
|
60
|
+
ofx_entry[:name] = "Stripe"
|
61
|
+
when "Stripe Checking Account"
|
62
|
+
ofx_entry[:amount] = -iif_entry.amount
|
63
|
+
ofx_entry[:name] = "Transfer to #{iif_entry.accnt}"
|
64
|
+
when "Stripe Sales"
|
65
|
+
ofx_entry[:amount] = -iif_entry.amount
|
66
|
+
|
67
|
+
if iif_entry.memo =~ /Stripe Connect fee/
|
68
|
+
ofx_entry[:name] = "Stripe Connect Charge"
|
69
|
+
elsif iif_entry.memo =~ /Charge/
|
70
|
+
ofx_entry[:name] = "Credit Card Charge"
|
71
|
+
else
|
72
|
+
ofx_entry[:name] = iif_entry.accnt
|
73
|
+
end
|
74
|
+
|
75
|
+
ofx_entry[:memo] =~ /Charge ID: (.*)/
|
76
|
+
charge_id = $1
|
77
|
+
|
78
|
+
if @payments[charge_id]
|
79
|
+
ofx_entry[:memo] = "#{@payments[charge_id]} #{iif_entry.memo}"
|
80
|
+
end
|
81
|
+
|
82
|
+
when "Stripe Returns"
|
83
|
+
ofx_entry[:amount] = -iif_entry.amount
|
84
|
+
ofx_entry[:name] = "Credit Card Refund"
|
85
|
+
when "Stripe Account"
|
86
|
+
return nil
|
87
|
+
end
|
88
|
+
|
89
|
+
return ofx_entry
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_csv
|
93
|
+
rows = []
|
94
|
+
rows.push(["Date", "Name", "Account", "Memo", "Amount"].to_csv)
|
95
|
+
@ofx_entries.each do |ofx_entry|
|
96
|
+
rows.push([ ofx_entry[:date].strftime("%m/%d/%Y"), ofx_entry[:name], ofx_entry[:accnt], "#{ofx_entry[:trnstype]} #{ofx_entry[:memo]}", ofx_entry[:amount].to_s('F') ].to_csv)
|
97
|
+
end
|
98
|
+
return rows.join
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_qbo
|
102
|
+
min_date = nil
|
103
|
+
max_date = nil
|
104
|
+
|
105
|
+
@ofx_entries.each do |e|
|
106
|
+
if e[:date]
|
107
|
+
min_date = e[:date] if min_date.nil? or e[:date] < min_date
|
108
|
+
max_date = e[:date] if max_date.nil? or e[:date] > max_date
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
ofx_builder = OFX::Builder.new do |ofx|
|
113
|
+
ofx.dtserver = @server_time
|
114
|
+
ofx.fi_org = "Stripe"
|
115
|
+
ofx.fi_fid = "0"
|
116
|
+
ofx.bank_id = "123456789"
|
117
|
+
ofx.acct_id = @account_id
|
118
|
+
ofx.acct_type = "CHECKING"
|
119
|
+
ofx.dtstart = min_date
|
120
|
+
ofx.dtend = max_date
|
121
|
+
ofx.bal_amt = 0
|
122
|
+
ofx.dtasof = max_date
|
123
|
+
end
|
124
|
+
|
125
|
+
@ofx_entries.each do |ofx_entry|
|
126
|
+
ofx_builder.transaction do |ofx_tr|
|
127
|
+
ofx_tr.dtposted = ofx_entry[:date]
|
128
|
+
ofx_tr.trnamt = ofx_entry[:amount]
|
129
|
+
ofx_tr.fitid = ofx_entry[:fitid]
|
130
|
+
ofx_tr.name = ofx_entry[:name]
|
131
|
+
ofx_tr.memo = ofx_entry[:memo]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
return ofx_builder.to_ofx
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/spec/iif_spec.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
describe IIF do
|
2
|
+
|
3
|
+
empty_iif = File.read(File.dirname(__FILE__) + "/sample-data/empty.iif")
|
4
|
+
basic_iif = File.read(File.dirname(__FILE__) + "/sample-data/basic.iif")
|
5
|
+
|
6
|
+
it "should parse empty IIF files" do
|
7
|
+
iif = IIF( empty_iif )
|
8
|
+
expect( iif.transactions.length ).to eq(0)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should parse basic IIF files" do
|
12
|
+
iif = IIF( basic_iif )
|
13
|
+
expect( iif.transactions.length ).to eq(7)
|
14
|
+
first_transaction = iif.transactions.first
|
15
|
+
expect( first_transaction.entries.length ).to eq(3)
|
16
|
+
first_entry = first_transaction.entries.first
|
17
|
+
|
18
|
+
expect( first_entry.type ).to eq("TRNS")
|
19
|
+
expect( first_entry.trnstype ).to eq("PAYOUT (TEST USER)")
|
20
|
+
expect( first_entry.date ).to eq(Date.new(2014,1,23))
|
21
|
+
expect( first_entry.accnt ).to eq("Third-party Account")
|
22
|
+
expect( first_entry.amount ).to eq(135.15)
|
23
|
+
expect( first_entry.memo ).to eq("Transfer from Stripe: tr_3MCmCnHFyYXFB5")
|
24
|
+
|
25
|
+
second_entry = first_transaction.entries[1]
|
26
|
+
|
27
|
+
expect( second_entry.type ).to eq("SPL")
|
28
|
+
expect( second_entry.trnstype ).to eq("PAYOUT (TEST USER)")
|
29
|
+
expect( second_entry.date ).to eq(Date.new(2014,1,23))
|
30
|
+
expect( second_entry.accnt ).to eq("Stripe Account")
|
31
|
+
expect( second_entry.amount ).to eq(-135.40)
|
32
|
+
expect( second_entry.memo ).to eq("Transfer from Stripe: tr_3MCmCnHFyYXFB5")
|
33
|
+
|
34
|
+
third_entry = first_transaction.entries[2]
|
35
|
+
|
36
|
+
expect( third_entry.type ).to eq("SPL")
|
37
|
+
expect( third_entry.trnstype ).to eq("GENERAL JOURNAL")
|
38
|
+
expect( third_entry.date ).to eq(Date.new(2014,1,23))
|
39
|
+
expect( third_entry.accnt ).to eq("Stripe Payment Processing Fees")
|
40
|
+
expect( third_entry.amount ).to eq(0.25)
|
41
|
+
expect( third_entry.memo ).to eq("Fees for transfer ID: tr_3MCmCnHFyYXFB5")
|
42
|
+
end
|
43
|
+
end
|
data/spec/ofx_spec.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
describe OFX do
|
2
|
+
empty_ofx = File.read(File.dirname(__FILE__) + "/sample-data/empty.ofx")
|
3
|
+
ofx_with_info = File.read(File.dirname(__FILE__) + "/sample-data/with-bank-info.ofx")
|
4
|
+
ofx_with_transaction = File.read(File.dirname(__FILE__) + "/sample-data/with-transaction.ofx")
|
5
|
+
|
6
|
+
it "should generate empty OFX files" do
|
7
|
+
ofx_builder = OFX::Builder.new do |ofx|
|
8
|
+
ofx.dtserver = Date.new(2014,2,11)
|
9
|
+
end
|
10
|
+
|
11
|
+
ofx = ofx_builder.to_ofx
|
12
|
+
expect( ofx ).to eq(empty_ofx)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should generate OFX files with bank info but no transactions" do
|
16
|
+
ofx_builder = OFX::Builder.new do |ofx|
|
17
|
+
ofx.dtserver = Date.new(2014,2,11)
|
18
|
+
ofx.fi_org = "Stripe"
|
19
|
+
ofx.fi_fid = "0"
|
20
|
+
ofx.bank_id = "123456789"
|
21
|
+
ofx.acct_id = "Test"
|
22
|
+
ofx.acct_type = "CHECKING"
|
23
|
+
ofx.dtstart = Date.new(2014,1,1)
|
24
|
+
ofx.dtend = Date.new(2014,2,1)
|
25
|
+
ofx.bal_amt = 0
|
26
|
+
ofx.dtasof = Date.new(2014,2,1)
|
27
|
+
end
|
28
|
+
|
29
|
+
ofx = ofx_builder.to_ofx
|
30
|
+
expect( ofx ).to eq(ofx_with_info)
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
it "should generate OFX files with transactions" do
|
35
|
+
ofx_builder = OFX::Builder.new do |ofx|
|
36
|
+
ofx.dtserver = Date.new(2014,2,11)
|
37
|
+
ofx.fi_org = "Stripe"
|
38
|
+
ofx.fi_fid = "0"
|
39
|
+
ofx.bank_id = "123456789"
|
40
|
+
ofx.acct_id = "Test"
|
41
|
+
ofx.acct_type = "CHECKING"
|
42
|
+
ofx.dtstart = Date.new(2014,1,1)
|
43
|
+
ofx.dtend = Date.new(2014,2,1)
|
44
|
+
ofx.bal_amt = 0
|
45
|
+
ofx.dtasof = Date.new(2014,2,1)
|
46
|
+
end
|
47
|
+
|
48
|
+
ofx_builder.transaction do |ofx_tr|
|
49
|
+
ofx_tr.dtposted = Date.new(2014,1,1)
|
50
|
+
ofx_tr.trnamt = "100.23"
|
51
|
+
ofx_tr.fitid = "Test"
|
52
|
+
ofx_tr.name = "Name"
|
53
|
+
ofx_tr.memo = "Memo memo"
|
54
|
+
end
|
55
|
+
|
56
|
+
ofx = ofx_builder.to_ofx
|
57
|
+
expect( ofx ).to eq(ofx_with_transaction)
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Date,Name,Account,Memo,Amount
|
2
|
+
01/23/2014,Test User,Third-party Account,PAYOUT (TEST USER) Transfer from Stripe: tr_3MCmCnHFyYXFB5,-135.15
|
3
|
+
01/23/2014,Stripe,Stripe Payment Processing Fees,GENERAL JOURNAL Fees for transfer ID: tr_3MCmCnHFyYXFB5,-0.25
|
4
|
+
01/23/2014,Transfer to Checking Account,Checking Account,DEPOSIT Transfer from Stripe: tr_3MCmQsVsNuIX7J,-85.0
|
5
|
+
01/22/2014,Credit Card Charge,Stripe Sales,GENERAL JOURNAL Charge ID: ch_3M1PskZ2rglde3,249.0
|
6
|
+
01/22/2014,Stripe,Stripe Payment Processing Fees,GENERAL JOURNAL Fees for charge ID: ch_3M1PskZ2rglde3,-7.52
|
7
|
+
07/10/2013,Credit Card Refund,Stripe Returns,GENERAL JOURNAL Refund of charge ch_2AaUvVOXTJxqgU,-60.0
|
8
|
+
07/10/2013,Stripe,Stripe Payment Processing Fees,GENERAL JOURNAL Refund of fees for ch_2AaUvVOXTJxqgU,2.04
|
9
|
+
07/10/2013,Credit Card Charge,Stripe Sales,GENERAL JOURNAL Charge ID: ch_2AaUVt4SQVF5mE,60.0
|
10
|
+
07/10/2013,Stripe,Stripe Payment Processing Fees,GENERAL JOURNAL Fees for charge ID: ch_2AaUVt4SQVF5mE,-2.04
|
11
|
+
12/10/2012,Transfer to Checking Account,Checking Account,DEPOSIT Transfer from Stripe: ach_0qt6m5dlIL2XMq,-15.0
|
12
|
+
12/03/2012,Stripe Connect Charge,Stripe Sales,GENERAL JOURNAL Stripe Connect fee for transaction ID: ch_0qbUpzmgBi6WVJ,15.0
|
@@ -0,0 +1,28 @@
|
|
1
|
+
!TRNS TRNSID TRNSTYPE DATE ACCNT AMOUNT MEMO
|
2
|
+
!SPL TRNSID TRNSTYPE DATE ACCNT AMOUNT MEMO
|
3
|
+
!ENDTRNS
|
4
|
+
TRNS PAYOUT (TEST USER) 01/23/2014 Third-party Account 135.15 Transfer from Stripe: tr_3MCmCnHFyYXFB5
|
5
|
+
SPL PAYOUT (TEST USER) 01/23/2014 Stripe Account -135.4 Transfer from Stripe: tr_3MCmCnHFyYXFB5
|
6
|
+
SPL GENERAL JOURNAL 01/23/2014 Stripe Payment Processing Fees 0.25 Fees for transfer ID: tr_3MCmCnHFyYXFB5
|
7
|
+
ENDTRNS
|
8
|
+
TRNS DEPOSIT 01/23/2014 Checking Account 85.0 Transfer from Stripe: tr_3MCmQsVsNuIX7J
|
9
|
+
SPL DEPOSIT 01/23/2014 Stripe Account -85.0 Transfer from Stripe: tr_3MCmQsVsNuIX7J
|
10
|
+
ENDTRNS
|
11
|
+
TRNS GENERAL JOURNAL 01/22/2014 Stripe Sales -249.0 Charge ID: ch_3M1PskZ2rglde3
|
12
|
+
SPL GENERAL JOURNAL 01/22/2014 Stripe Payment Processing Fees 7.52 Fees for charge ID: ch_3M1PskZ2rglde3
|
13
|
+
SPL GENERAL JOURNAL 01/22/2014 Stripe Account 241.48 Net for charge ID: ch_3M1PskZ2rglde3
|
14
|
+
ENDTRNS
|
15
|
+
TRNS GENERAL JOURNAL 07/10/2013 Stripe Returns 60.0 Refund of charge ch_2AaUvVOXTJxqgU
|
16
|
+
SPL GENERAL JOURNAL 07/10/2013 Stripe Account -57.96 Refund for refunded charge ID: ch_2AaUvVOXTJxqgU
|
17
|
+
SPL GENERAL JOURNAL 07/10/2013 Stripe Payment Processing Fees -2.04 Refund of fees for ch_2AaUvVOXTJxqgU
|
18
|
+
ENDTRNS
|
19
|
+
TRNS GENERAL JOURNAL 07/10/2013 Stripe Sales -60.0 Charge ID: ch_2AaUVt4SQVF5mE
|
20
|
+
SPL GENERAL JOURNAL 07/10/2013 Stripe Payment Processing Fees 2.04 Fees for charge ID: ch_2AaUVt4SQVF5mE
|
21
|
+
SPL GENERAL JOURNAL 07/10/2013 Stripe Account 57.96 Net for charge ID: ch_2AaUVt4SQVF5mE
|
22
|
+
ENDTRNS
|
23
|
+
TRNS DEPOSIT 12/10/2012 Checking Account 15.0 Transfer from Stripe: ach_0qt6m5dlIL2XMq
|
24
|
+
SPL DEPOSIT 12/10/2012 Stripe Account -15.0 Transfer from Stripe: ach_0qt6m5dlIL2XMq
|
25
|
+
ENDTRNS
|
26
|
+
TRNS GENERAL JOURNAL 12/03/2012 Stripe Sales -15.0 Stripe Connect fee for transaction ID: ch_0qbUpzmgBi6WVJ
|
27
|
+
SPL GENERAL JOURNAL 12/03/2012 Stripe Account 15.0 Stripe Connect fee for transaction ID: ch_0qbUpzmgBi6WVJ
|
28
|
+
ENDTRNS
|
@@ -0,0 +1,11 @@
|
|
1
|
+
OFXHEADER:100
|
2
|
+
DATA:OFXSGML
|
3
|
+
VERSION:103
|
4
|
+
SECURITY:NONE
|
5
|
+
ENCODING:USASCII
|
6
|
+
CHARSET:1252
|
7
|
+
COMPRESSION:NONE
|
8
|
+
OLDFILEUID:NONE
|
9
|
+
NEWFILEUID:NONE
|
10
|
+
|
11
|
+
<OFX><SIGNONMSGSRSV1><SONRS><STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS><DTSERVER>20140211000000</DTSERVER><LANGUAGE>ENG</LANGUAGE><FI><ORG>Stripe</ORG><FID>0</FID></FI><INTU.BID>0</INTU.BID></SONRS></SIGNONMSGSRSV1><BANKMSGSRSV1><STMTTRNRS><TRNUID>0</TRNUID><STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS><STMTRS><CURDEF>USD</CURDEF><BANKACCTFROM><BANKID>123456789</BANKID><ACCTID/><ACCTTYPE>CHECKING</ACCTTYPE></BANKACCTFROM><BANKTRANLIST><DTSTART>20121203</DTSTART><DTEND>20140123</DTEND><STMTTRN><TRNTYPE>DEBIT</TRNTYPE><DTPOSTED>20140123</DTPOSTED><TRNAMT>-135.15</TRNAMT><FITID>Transfer from Stripe: tr_3MCmCnHFyYXFB5</FITID><NAME>Test User</NAME><MEMO>Transfer from Stripe: tr_3MCmCnHFyYXFB5</MEMO></STMTTRN><STMTTRN><TRNTYPE>DEBIT</TRNTYPE><DTPOSTED>20140123</DTPOSTED><TRNAMT>-0.25</TRNAMT><FITID>Fees for transfer ID: tr_3MCmCnHFyYXFB5</FITID><NAME>Stripe</NAME><MEMO>Fees for transfer ID: tr_3MCmCnHFyYXFB5</MEMO></STMTTRN><STMTTRN><TRNTYPE>DEBIT</TRNTYPE><DTPOSTED>20140123</DTPOSTED><TRNAMT>-85.0</TRNAMT><FITID>Transfer from Stripe: tr_3MCmQsVsNuIX7J</FITID><NAME>Transfer to Checking Account</NAME><MEMO>Transfer from Stripe: tr_3MCmQsVsNuIX7J</MEMO></STMTTRN><STMTTRN><TRNTYPE>CREDIT</TRNTYPE><DTPOSTED>20140122</DTPOSTED><TRNAMT>+249.0</TRNAMT><FITID>Charge ID: ch_3M1PskZ2rglde3</FITID><NAME>Credit Card Charge</NAME><MEMO>Charge ID: ch_3M1PskZ2rglde3</MEMO></STMTTRN><STMTTRN><TRNTYPE>DEBIT</TRNTYPE><DTPOSTED>20140122</DTPOSTED><TRNAMT>-7.52</TRNAMT><FITID>Fees for charge ID: ch_3M1PskZ2rglde3</FITID><NAME>Stripe</NAME><MEMO>Fees for charge ID: ch_3M1PskZ2rglde3</MEMO></STMTTRN><STMTTRN><TRNTYPE>DEBIT</TRNTYPE><DTPOSTED>20130710</DTPOSTED><TRNAMT>-60.0</TRNAMT><FITID>Refund of charge ch_2AaUvVOXTJxqgU</FITID><NAME>Credit Card Refund</NAME><MEMO>Refund of charge ch_2AaUvVOXTJxqgU</MEMO></STMTTRN><STMTTRN><TRNTYPE>CREDIT</TRNTYPE><DTPOSTED>20130710</DTPOSTED><TRNAMT>+2.04</TRNAMT><FITID>Refund of fees for ch_2AaUvVOXTJxqgU</FITID><NAME>Stripe</NAME><MEMO>Refund of fees for ch_2AaUvVOXTJxqgU</MEMO></STMTTRN><STMTTRN><TRNTYPE>CREDIT</TRNTYPE><DTPOSTED>20130710</DTPOSTED><TRNAMT>+60.0</TRNAMT><FITID>Charge ID: ch_2AaUVt4SQVF5mE</FITID><NAME>Credit Card Charge</NAME><MEMO>Charge ID: ch_2AaUVt4SQVF5mE</MEMO></STMTTRN><STMTTRN><TRNTYPE>DEBIT</TRNTYPE><DTPOSTED>20130710</DTPOSTED><TRNAMT>-2.04</TRNAMT><FITID>Fees for charge ID: ch_2AaUVt4SQVF5mE</FITID><NAME>Stripe</NAME><MEMO>Fees for charge ID: ch_2AaUVt4SQVF5mE</MEMO></STMTTRN><STMTTRN><TRNTYPE>DEBIT</TRNTYPE><DTPOSTED>20121210</DTPOSTED><TRNAMT>-15.0</TRNAMT><FITID>Transfer from Stripe: ach_0qt6m5dlIL2XMq</FITID><NAME>Transfer to Checking Account</NAME><MEMO>Transfer from Stripe: ach_0qt6m5dlIL2XMq</MEMO></STMTTRN><STMTTRN><TRNTYPE>CREDIT</TRNTYPE><DTPOSTED>20121203</DTPOSTED><TRNAMT>+15.0</TRNAMT><FITID>Stripe Connect fee for transaction ID: ch_0qbUpzmgBi6WVJ</FITID><NAME>Stripe Connect Charge</NAME><MEMO>Stripe Connect fee for transaction ID: ch_0qbUpzmgBi6WVJ</MEMO></STMTTRN></BANKTRANLIST><LEDGERBAL><BALAMT>0.0</BALAMT><DTASOF>20140123</DTASOF></LEDGERBAL></STMTRS></STMTTRNRS></BANKMSGSRSV1></OFX>
|
@@ -0,0 +1 @@
|
|
1
|
+
Date,Name,Account,Memo,Amount
|
File without changes
|
@@ -0,0 +1,11 @@
|
|
1
|
+
OFXHEADER:100
|
2
|
+
DATA:OFXSGML
|
3
|
+
VERSION:103
|
4
|
+
SECURITY:NONE
|
5
|
+
ENCODING:USASCII
|
6
|
+
CHARSET:1252
|
7
|
+
COMPRESSION:NONE
|
8
|
+
OLDFILEUID:NONE
|
9
|
+
NEWFILEUID:NONE
|
10
|
+
|
11
|
+
<OFX><SIGNONMSGSRSV1><SONRS><STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS><DTSERVER>20140211000000</DTSERVER><LANGUAGE>ENG</LANGUAGE><FI><ORG/><FID/></FI><INTU.BID/></SONRS></SIGNONMSGSRSV1><BANKMSGSRSV1><STMTTRNRS><TRNUID>0</TRNUID><STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS><STMTRS><CURDEF>USD</CURDEF><BANKACCTFROM><BANKID/><ACCTID/><ACCTTYPE/></BANKACCTFROM><BANKTRANLIST/><LEDGERBAL/></STMTRS></STMTTRNRS></BANKMSGSRSV1></OFX>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
OFXHEADER:100
|
2
|
+
DATA:OFXSGML
|
3
|
+
VERSION:103
|
4
|
+
SECURITY:NONE
|
5
|
+
ENCODING:USASCII
|
6
|
+
CHARSET:1252
|
7
|
+
COMPRESSION:NONE
|
8
|
+
OLDFILEUID:NONE
|
9
|
+
NEWFILEUID:NONE
|
10
|
+
|
11
|
+
<OFX><SIGNONMSGSRSV1><SONRS><STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS><DTSERVER>20140211000000</DTSERVER><LANGUAGE>ENG</LANGUAGE><FI><ORG>Stripe</ORG><FID>0</FID></FI><INTU.BID>0</INTU.BID></SONRS></SIGNONMSGSRSV1><BANKMSGSRSV1><STMTTRNRS><TRNUID>0</TRNUID><STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS><STMTRS><CURDEF>USD</CURDEF><BANKACCTFROM><BANKID>123456789</BANKID><ACCTID/><ACCTTYPE>CHECKING</ACCTTYPE></BANKACCTFROM><BANKTRANLIST/><LEDGERBAL><BALAMT>0.0</BALAMT></LEDGERBAL></STMTRS></STMTTRNRS></BANKMSGSRSV1></OFX>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
OFXHEADER:100
|
2
|
+
DATA:OFXSGML
|
3
|
+
VERSION:103
|
4
|
+
SECURITY:NONE
|
5
|
+
ENCODING:USASCII
|
6
|
+
CHARSET:1252
|
7
|
+
COMPRESSION:NONE
|
8
|
+
OLDFILEUID:NONE
|
9
|
+
NEWFILEUID:NONE
|
10
|
+
|
11
|
+
<OFX><SIGNONMSGSRSV1><SONRS><STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS><DTSERVER>20140211000000</DTSERVER><LANGUAGE>ENG</LANGUAGE><FI><ORG>Stripe</ORG><FID>0</FID></FI><INTU.BID>0</INTU.BID></SONRS></SIGNONMSGSRSV1><BANKMSGSRSV1><STMTTRNRS><TRNUID>0</TRNUID><STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS><STMTRS><CURDEF>USD</CURDEF><BANKACCTFROM><BANKID>123456789</BANKID><ACCTID>Test</ACCTID><ACCTTYPE>CHECKING</ACCTTYPE></BANKACCTFROM><BANKTRANLIST><DTSTART>20140101</DTSTART><DTEND>20140201</DTEND></BANKTRANLIST><LEDGERBAL><BALAMT>0.0</BALAMT><DTASOF>20140201</DTASOF></LEDGERBAL></STMTRS></STMTTRNRS></BANKMSGSRSV1></OFX>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
OFXHEADER:100
|
2
|
+
DATA:OFXSGML
|
3
|
+
VERSION:103
|
4
|
+
SECURITY:NONE
|
5
|
+
ENCODING:USASCII
|
6
|
+
CHARSET:1252
|
7
|
+
COMPRESSION:NONE
|
8
|
+
OLDFILEUID:NONE
|
9
|
+
NEWFILEUID:NONE
|
10
|
+
|
11
|
+
<OFX><SIGNONMSGSRSV1><SONRS><STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS><DTSERVER>20140211000000</DTSERVER><LANGUAGE>ENG</LANGUAGE><FI><ORG>Stripe</ORG><FID>0</FID></FI><INTU.BID>0</INTU.BID></SONRS></SIGNONMSGSRSV1><BANKMSGSRSV1><STMTTRNRS><TRNUID>0</TRNUID><STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS><STMTRS><CURDEF>USD</CURDEF><BANKACCTFROM><BANKID>123456789</BANKID><ACCTID>Test</ACCTID><ACCTTYPE>CHECKING</ACCTTYPE></BANKACCTFROM><BANKTRANLIST><DTSTART>20140101</DTSTART><DTEND>20140201</DTEND><STMTTRN><TRNTYPE>CREDIT</TRNTYPE><DTPOSTED>20140101</DTPOSTED><TRNAMT>+100.23</TRNAMT><FITID>Test</FITID><NAME>Name</NAME><MEMO>Memo memo</MEMO></STMTTRN></BANKTRANLIST><LEDGERBAL><BALAMT>0.0</BALAMT><DTASOF>20140201</DTASOF></LEDGERBAL></STMTRS></STMTTRNRS></BANKMSGSRSV1></OFX>
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
|
+
config.run_all_when_everything_filtered = true
|
10
|
+
# config.filter_run :focus
|
11
|
+
|
12
|
+
# Run specs in random order to surface order dependencies. If you find an
|
13
|
+
# order dependency and want to debug it, you can fix the order by providing
|
14
|
+
# the seed, which is printed after each run.
|
15
|
+
# --seed 1234
|
16
|
+
config.order = 'random'
|
17
|
+
end
|
18
|
+
|
19
|
+
require_relative '../lib/iif'
|
20
|
+
require_relative '../lib/ofx'
|
21
|
+
require_relative '../lib/stripe-iiftoqbo'
|
22
|
+
|
23
|
+
|
24
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
describe StripeIIFToQBO do
|
2
|
+
empty_qbo = File.read(File.dirname(__FILE__) + "/sample-data/empty.qbo")
|
3
|
+
empty_csv = File.read(File.dirname(__FILE__) + "/sample-data/empty.csv")
|
4
|
+
basic_iif = File.read(File.dirname(__FILE__) + "/sample-data/basic.iif")
|
5
|
+
basic_qbo = File.read(File.dirname(__FILE__) + "/sample-data/basic.qbo")
|
6
|
+
basic_csv = File.read(File.dirname(__FILE__) + "/sample-data/basic.csv")
|
7
|
+
|
8
|
+
it "should create an empty QBO file" do
|
9
|
+
iiftoqbo = StripeIIFToQBO::Converter.new( :server_time => Date.new(2014,2,11) )
|
10
|
+
qbo = iiftoqbo.to_qbo
|
11
|
+
expect( qbo ).to eq(empty_qbo)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should create an empty CSV file" do
|
15
|
+
iiftoqbo = StripeIIFToQBO::Converter.new( :server_time => Date.new(2014,2,11) )
|
16
|
+
csv = iiftoqbo.to_csv
|
17
|
+
expect( csv ).to eq(empty_csv)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should create a basic QBO file" do
|
21
|
+
iiftoqbo = StripeIIFToQBO::Converter.new( :server_time => Date.new(2014,2,11), :iif_file => basic_iif )
|
22
|
+
qbo = iiftoqbo.to_qbo
|
23
|
+
expect( qbo ).to eq(basic_qbo)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should create a basic CSV file" do
|
27
|
+
iiftoqbo = StripeIIFToQBO::Converter.new( :server_time => Date.new(2014,2,11), :iif_file => basic_iif )
|
28
|
+
csv = iiftoqbo.to_csv
|
29
|
+
expect( csv ).to eq(basic_csv)
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.name = 'stripe-iiftoqbo'
|
4
|
+
s.version = '0.1.1'
|
5
|
+
s.summary = 'Stripe IIF-to-QBO converter for Quickbooks Online'
|
6
|
+
s.description = 'Converts Stripe\'s IIF transaction file into a QBO file for importing into Quickbooks Online. A QBO file is in OFX (Open Financial Exchange) format.'
|
7
|
+
s.homepage = 'https://github.com/gtolle/stripe-iiftoqbo'
|
8
|
+
s.email = ['gilman.tolle@gmail.com']
|
9
|
+
s.authors = ['Gilman Tolle']
|
10
|
+
s.license = 'MIT'
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
|
14
|
+
s.executables << 'stripe-iiftoqbo'
|
15
|
+
|
16
|
+
s.add_runtime_dependency 'bigdecimal', '~> 1.2'
|
17
|
+
s.add_runtime_dependency 'nokogiri', '~> 1.6'
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stripe-iiftoqbo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Gilman Tolle
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-06-24 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bigdecimal
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.2'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.2'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: nokogiri
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.6'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.6'
|
46
|
+
description: Converts Stripe's IIF transaction file into a QBO file for importing
|
47
|
+
into Quickbooks Online. A QBO file is in OFX (Open Financial Exchange) format.
|
48
|
+
email:
|
49
|
+
- gilman.tolle@gmail.com
|
50
|
+
executables:
|
51
|
+
- stripe-iiftoqbo
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- .gitignore
|
56
|
+
- .rspec
|
57
|
+
- LICENSE
|
58
|
+
- README.md
|
59
|
+
- bin/stripe-iiftoqbo
|
60
|
+
- lib/iif.rb
|
61
|
+
- lib/iif/entry.rb
|
62
|
+
- lib/iif/parser.rb
|
63
|
+
- lib/iif/transaction.rb
|
64
|
+
- lib/ofx.rb
|
65
|
+
- lib/ofx/transaction.rb
|
66
|
+
- lib/stripe-iiftoqbo.rb
|
67
|
+
- spec/iif_spec.rb
|
68
|
+
- spec/ofx_spec.rb
|
69
|
+
- spec/sample-data/basic.csv
|
70
|
+
- spec/sample-data/basic.iif
|
71
|
+
- spec/sample-data/basic.qbo
|
72
|
+
- spec/sample-data/empty.csv
|
73
|
+
- spec/sample-data/empty.iif
|
74
|
+
- spec/sample-data/empty.ofx
|
75
|
+
- spec/sample-data/empty.qbo
|
76
|
+
- spec/sample-data/with-bank-info.ofx
|
77
|
+
- spec/sample-data/with-transaction.ofx
|
78
|
+
- spec/spec_helper.rb
|
79
|
+
- spec/stripe-iiftoqbo_spec.rb
|
80
|
+
- stripe-iiftoqbo.gemspec
|
81
|
+
homepage: https://github.com/gtolle/stripe-iiftoqbo
|
82
|
+
licenses:
|
83
|
+
- MIT
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 1.8.25
|
103
|
+
signing_key:
|
104
|
+
specification_version: 3
|
105
|
+
summary: Stripe IIF-to-QBO converter for Quickbooks Online
|
106
|
+
test_files: []
|