paperless_to_xero 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +22 -0
- data/Rakefile +21 -91
- data/VERSION +1 -0
- data/lib/paperless_to_xero/converter.rb +31 -13
- data/lib/paperless_to_xero/errors.rb +15 -0
- data/lib/paperless_to_xero/invoice_item.rb +3 -0
- data/paperless_to_xero.gemspec +91 -0
- data/spec/fixtures/dodgy-header.csv +2 -0
- data/spec/fixtures/multi-item-mixed_vat_and_exempt.csv +2 -0
- data/spec/fixtures/single-vat-2008-11-30.csv +2 -0
- data/spec/fixtures/single-vat-2008-12-01.csv +2 -0
- data/spec/fixtures/single-vat-2009-12-31.csv +2 -0
- data/spec/fixtures/single-vat-2009.csv +2 -0
- data/spec/fixtures/single-vat-2010-01-01.csv +2 -0
- data/spec/fixtures/single-vat-pre-2008-12.csv +2 -0
- data/spec/paperless_to_xero/converter_spec.rb +130 -1
- data/spec/paperless_to_xero/errors_spec.rb +7 -0
- data/spec/paperless_to_xero/invoice_item_spec.rb +2 -1
- data/spec/paperless_to_xero/invoice_spec.rb +1 -1
- metadata +46 -20
data/MIT-LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2009 Matt Patterson
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "rubygems"
|
1
2
|
require 'rake'
|
2
3
|
require 'rake/rdoctask'
|
3
4
|
gem 'rspec'
|
@@ -39,101 +40,30 @@ namespace :spec do
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
|
-
|
43
|
-
require
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
s.version = PaperlessToXero::Version()
|
55
|
-
s.summary = "Convert Paperless CSV exports to Xero invoice import CSV"
|
56
|
-
s.description = File.read('README.rdoc')
|
57
|
-
s.author = "Matt Patterson"
|
58
|
-
s.email = "matt@reprocessed.org"
|
59
|
-
s.homepage = "http://reprocessed.org/"
|
60
|
-
|
61
|
-
s.has_rdoc = true
|
62
|
-
s.extra_rdoc_files = %w(README.rdoc)
|
63
|
-
s.rdoc_options = %w(--main README.rdoc)
|
64
|
-
|
65
|
-
# Add any extra files to include in the gem
|
66
|
-
s.files = %w(Rakefile README.rdoc) + Dir.glob("{bin,spec,lib}/**/*")
|
67
|
-
s.executables = FileList["bin/**"].map { |f| File.basename(f) }
|
68
|
-
|
69
|
-
s.require_paths = ["lib"]
|
70
|
-
|
71
|
-
# If you want to depend on other gems, add them here, along with any
|
72
|
-
# relevant versions
|
73
|
-
|
74
|
-
s.add_development_dependency("rspec") # add any other gems for testing/development
|
43
|
+
begin
|
44
|
+
require 'jeweler'
|
45
|
+
Jeweler::Tasks.new do |s|
|
46
|
+
s.name = "paperless_to_xero"
|
47
|
+
s.summary = "Convert Paperless CSV exports to Xero invoice import CSV"
|
48
|
+
s.description = File.read('README.rdoc')
|
49
|
+
s.authors = ["Matt Patterson"]
|
50
|
+
s.email = "matt@reprocessed.org"
|
51
|
+
s.homepage = "http://github.com/fidothe/paperless_to_xero/"
|
52
|
+
|
53
|
+
s.extra_rdoc_files = %w(README.rdoc)
|
54
|
+
s.rdoc_options = %w(--main README.rdoc)
|
75
55
|
|
76
|
-
|
77
|
-
# to tweak this, and the publishing task below too.
|
78
|
-
s.rubyforge_project = "paperless_to_xero"
|
79
|
-
end
|
56
|
+
s.require_paths = ["lib"]
|
80
57
|
|
81
|
-
#
|
82
|
-
#
|
83
|
-
# be automatically building a gem for this project. If you're not
|
84
|
-
# using GitHub, edit as appropriate.
|
85
|
-
Rake::GemPackageTask.new(spec) do |pkg|
|
86
|
-
pkg.gem_spec = spec
|
87
|
-
|
88
|
-
# Generate the gemspec file for github.
|
89
|
-
file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
|
90
|
-
File.open(file, "w") {|f| f << spec.to_ruby }
|
91
|
-
end
|
58
|
+
# If you want to depend on other gems, add them here, along with any
|
59
|
+
# relevant versions
|
92
60
|
|
93
|
-
|
94
|
-
task :clean => [:clobber_rdoc, :clobber_package] do
|
95
|
-
rm "#{spec.name}.gemspec"
|
96
|
-
end
|
61
|
+
s.add_development_dependency("rspec") # add any other gems for testing/development
|
97
62
|
|
98
|
-
# If you want to publish to
|
99
|
-
#
|
100
|
-
|
101
|
-
# gem; you'll need to run `rubyforge setup` and `rubyforge config` at
|
102
|
-
# the very least.
|
103
|
-
begin
|
104
|
-
require "rake/contrib/sshpublisher"
|
105
|
-
namespace :rubyforge do
|
106
|
-
|
107
|
-
desc "Release gem and RDoc documentation to RubyForge"
|
108
|
-
task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
|
109
|
-
|
110
|
-
namespace :release do
|
111
|
-
desc "Release a new version of this gem"
|
112
|
-
task :gem => [:package] do
|
113
|
-
require 'rubyforge'
|
114
|
-
rubyforge = RubyForge.new
|
115
|
-
rubyforge.configure
|
116
|
-
rubyforge.login
|
117
|
-
rubyforge.userconfig['release_notes'] = spec.summary
|
118
|
-
path_to_gem = File.join(File.dirname(__FILE__), "pkg", "#{spec.name}-#{spec.version}.gem")
|
119
|
-
puts "Publishing #{spec.name}-#{spec.version.to_s} to Rubyforge..."
|
120
|
-
rubyforge.add_release(spec.rubyforge_project, spec.name, spec.version.to_s, path_to_gem)
|
121
|
-
end
|
122
|
-
|
123
|
-
desc "Publish RDoc to RubyForge."
|
124
|
-
task :docs => [:rdoc] do
|
125
|
-
config = YAML.load(
|
126
|
-
File.read(File.expand_path('~/.rubyforge/user-config.yml'))
|
127
|
-
)
|
128
|
-
|
129
|
-
host = "#{config['username']}@rubyforge.org"
|
130
|
-
remote_dir = "/var/www/gforge-projects/coop_to_ofx/" # Should be the same as the rubyforge project name
|
131
|
-
local_dir = 'rdoc'
|
132
|
-
|
133
|
-
Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
|
134
|
-
end
|
135
|
-
end
|
63
|
+
# If you want to publish automatically to rubyforge, you'll may need
|
64
|
+
# to tweak this, and the publishing task below too.
|
65
|
+
s.rubyforge_project = "paperless_to_xero"
|
136
66
|
end
|
137
67
|
rescue LoadError
|
138
|
-
puts "
|
68
|
+
puts "Jeweler not available. Install it with: sudo gem install jeweler"
|
139
69
|
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.2.0
|
@@ -1,8 +1,12 @@
|
|
1
1
|
require 'csv'
|
2
2
|
require 'date'
|
3
|
+
require 'paperless_to_xero/errors'
|
3
4
|
|
4
5
|
module PaperlessToXero
|
6
|
+
PAPERLESS_HEADER_ROW = ["Date","Merchant","Currency","Amount","Tax","Category","Payment Method","Notes","Description","Reference #","Status"]
|
5
7
|
class Converter
|
8
|
+
VAT_RATE_CHANGE_2008_12_01 = Date.parse('2008-12-01')
|
9
|
+
VAT_RATE_CHANGE_2010_01_01 = Date.parse('2010-01-01')
|
6
10
|
attr_reader :input_path, :output_path
|
7
11
|
|
8
12
|
def initialize(input_path, output_path)
|
@@ -13,12 +17,17 @@ module PaperlessToXero
|
|
13
17
|
@invoices ||= []
|
14
18
|
end
|
15
19
|
|
20
|
+
def verify_header_row!(row)
|
21
|
+
raise UnknownHeaderRow unless row == PaperlessToXero::PAPERLESS_HEADER_ROW
|
22
|
+
end
|
23
|
+
|
16
24
|
def parse
|
17
25
|
input_csv = CSV.read(input_path)
|
18
|
-
#
|
19
|
-
input_csv.shift
|
26
|
+
# verify Paperless header row
|
27
|
+
verify_header_row!(input_csv.shift)
|
20
28
|
|
21
|
-
input_csv.
|
29
|
+
input_csv.each_with_index do |row, index|
|
30
|
+
line_number = index + 1
|
22
31
|
date, merchant, paperless_currency, amount, vat, category, payment_method, notes_field, description, reference, status, *extras = row
|
23
32
|
negative = amount.index('--') == 0
|
24
33
|
category = category[0..2] unless category.nil?
|
@@ -30,17 +39,25 @@ module PaperlessToXero
|
|
30
39
|
total_vat = vat.nil? ? "0.00" : vat
|
31
40
|
invoice = PaperlessToXero::Invoice.new(extract_date(date), merchant, reference, amount, total_vat, inc_vat?(notes), extract_currency(notes))
|
32
41
|
if extras.empty?
|
33
|
-
|
42
|
+
begin
|
43
|
+
invoice.add_item(description, amount, vat, category, extract_vat_note(invoice.date, vat, notes))
|
44
|
+
rescue
|
45
|
+
raise BadItem.new(line_number, row, "Couldn't process this item")
|
46
|
+
end
|
34
47
|
else
|
35
|
-
raise
|
48
|
+
raise IncorrectNumberOfColumns.new(line_number, row, "Extra items are badly formatted") unless extras.size % 6 == 0
|
36
49
|
items = chunk_extras(extras)
|
37
50
|
items.each do |item|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
51
|
+
begin
|
52
|
+
description, paperless_currency, amount, unknown, category, notes_field = item
|
53
|
+
category = category[0..2]
|
54
|
+
notes = extract_notes(notes_field)
|
55
|
+
vat_amount = extract_vat_amount(notes)
|
56
|
+
vat_note = extract_vat_note(invoice.date, vat_amount, notes)
|
57
|
+
invoice.add_item(description, amount, vat_amount, category, vat_note)
|
58
|
+
rescue
|
59
|
+
raise BadItem.new(line_number, row, "Couldn't process this item")
|
60
|
+
end
|
44
61
|
end
|
45
62
|
end
|
46
63
|
invoices << invoice
|
@@ -117,7 +134,7 @@ module PaperlessToXero
|
|
117
134
|
nil
|
118
135
|
end
|
119
136
|
|
120
|
-
def extract_vat_note(vat_amount, notes)
|
137
|
+
def extract_vat_note(date, vat_amount, notes)
|
121
138
|
notes.each do |item|
|
122
139
|
return item if item.match(/^VAT/)
|
123
140
|
end
|
@@ -128,7 +145,8 @@ module PaperlessToXero
|
|
128
145
|
when nil
|
129
146
|
'No VAT'
|
130
147
|
else
|
131
|
-
'VAT - 15%'
|
148
|
+
return 'VAT - 15%' if date >= VAT_RATE_CHANGE_2008_12_01 && date < VAT_RATE_CHANGE_2010_01_01
|
149
|
+
'VAT - 17.5%'
|
132
150
|
end
|
133
151
|
end
|
134
152
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module PaperlessToXero
|
2
|
+
class UnknownHeaderRow < StandardError; end
|
3
|
+
class RowError < StandardError
|
4
|
+
def initialize(line_number, row, explanation = "")
|
5
|
+
@line_number, @row, @explanation = line_number, row, explanation
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_s
|
9
|
+
"Error processing line #{@line_number.to_s}: #{@explanation}. Row was #{@row.inspect}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class IncorrectNumberOfColumns < RowError; end
|
14
|
+
class BadItem < RowError; end
|
15
|
+
end
|
@@ -17,6 +17,7 @@ module PaperlessToXero
|
|
17
17
|
'21.5% (Ireland, VAT on expenses)' => 1.215.to_d,
|
18
18
|
'15% (EU VAT ID)' => 1.15.to_d,
|
19
19
|
'15% (VAT on expenses)' => 1.15.to_d,
|
20
|
+
'17.5% (VAT on expenses)' => 1.175.to_d,
|
20
21
|
'Zero Rated Expenses' => 0,
|
21
22
|
'15% (Luxembourg, VAT on expenses)' => 1.15.to_d
|
22
23
|
}
|
@@ -76,6 +77,8 @@ module PaperlessToXero
|
|
76
77
|
'15% (EU VAT ID)'
|
77
78
|
when 'VAT - 15%'
|
78
79
|
'15% (VAT on expenses)'
|
80
|
+
when 'VAT - 17.5%'
|
81
|
+
'17.5% (VAT on expenses)'
|
79
82
|
when 'VAT - 0%'
|
80
83
|
'Zero Rated Expenses'
|
81
84
|
when 'No VAT'
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{paperless_to_xero}
|
8
|
+
s.version = "1.2.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Matt Patterson"]
|
12
|
+
s.date = %q{2010-02-27}
|
13
|
+
s.default_executable = %q{paperless_to_xero}
|
14
|
+
s.description = %q{= Paperless-to-Xero
|
15
|
+
|
16
|
+
A simple translator which takes a CSV file from Mariner's Paperless receipt/document management software and makes a Xero accounts payable invoice CSV, for import into Xero.
|
17
|
+
|
18
|
+
Formatting in Paperless is very important, so you probably want to wait until I've written the docs}
|
19
|
+
s.email = %q{matt@reprocessed.org}
|
20
|
+
s.executables = ["paperless_to_xero"]
|
21
|
+
s.extra_rdoc_files = [
|
22
|
+
"README.rdoc"
|
23
|
+
]
|
24
|
+
s.files = [
|
25
|
+
"MIT-LICENSE",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"bin/paperless_to_xero",
|
30
|
+
"lib/paperless_to_xero.rb",
|
31
|
+
"lib/paperless_to_xero/converter.rb",
|
32
|
+
"lib/paperless_to_xero/decimal_helpers.rb",
|
33
|
+
"lib/paperless_to_xero/errors.rb",
|
34
|
+
"lib/paperless_to_xero/invoice.rb",
|
35
|
+
"lib/paperless_to_xero/invoice_item.rb",
|
36
|
+
"lib/paperless_to_xero/version.rb",
|
37
|
+
"paperless_to_xero.gemspec",
|
38
|
+
"spec/fixtures/dodgy-header.csv",
|
39
|
+
"spec/fixtures/end_to_end-input.csv",
|
40
|
+
"spec/fixtures/end_to_end-output.csv",
|
41
|
+
"spec/fixtures/multi-ex-vat.csv",
|
42
|
+
"spec/fixtures/multi-foreign.csv",
|
43
|
+
"spec/fixtures/multi-item-mixed_vat_and_exempt.csv",
|
44
|
+
"spec/fixtures/multi-item.csv",
|
45
|
+
"spec/fixtures/single-1000.csv",
|
46
|
+
"spec/fixtures/single-basic.csv",
|
47
|
+
"spec/fixtures/single-dkk.csv",
|
48
|
+
"spec/fixtures/single-foreign.csv",
|
49
|
+
"spec/fixtures/single-no-vat.csv",
|
50
|
+
"spec/fixtures/single-vat-2008-11-30.csv",
|
51
|
+
"spec/fixtures/single-vat-2008-12-01.csv",
|
52
|
+
"spec/fixtures/single-vat-2009-12-31.csv",
|
53
|
+
"spec/fixtures/single-vat-2009.csv",
|
54
|
+
"spec/fixtures/single-vat-2010-01-01.csv",
|
55
|
+
"spec/fixtures/single-vat-pre-2008-12.csv",
|
56
|
+
"spec/fixtures/single-zero_rated.csv",
|
57
|
+
"spec/paperless_to_xero/converter_spec.rb",
|
58
|
+
"spec/paperless_to_xero/errors_spec.rb",
|
59
|
+
"spec/paperless_to_xero/invoice_item_spec.rb",
|
60
|
+
"spec/paperless_to_xero/invoice_spec.rb",
|
61
|
+
"spec/spec.opts",
|
62
|
+
"spec/spec_helper.rb"
|
63
|
+
]
|
64
|
+
s.homepage = %q{http://github.com/fidothe/paperless_to_xero/}
|
65
|
+
s.rdoc_options = ["--main", "README.rdoc"]
|
66
|
+
s.require_paths = ["lib"]
|
67
|
+
s.rubyforge_project = %q{paperless_to_xero}
|
68
|
+
s.rubygems_version = %q{1.3.6}
|
69
|
+
s.summary = %q{Convert Paperless CSV exports to Xero invoice import CSV}
|
70
|
+
s.test_files = [
|
71
|
+
"spec/paperless_to_xero/converter_spec.rb",
|
72
|
+
"spec/paperless_to_xero/errors_spec.rb",
|
73
|
+
"spec/paperless_to_xero/invoice_item_spec.rb",
|
74
|
+
"spec/paperless_to_xero/invoice_spec.rb",
|
75
|
+
"spec/spec_helper.rb"
|
76
|
+
]
|
77
|
+
|
78
|
+
if s.respond_to? :specification_version then
|
79
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
80
|
+
s.specification_version = 3
|
81
|
+
|
82
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
83
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
84
|
+
else
|
85
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
86
|
+
end
|
87
|
+
else
|
88
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
@@ -0,0 +1,2 @@
|
|
1
|
+
"Date","Merchant","Currency","Amount","Tax","Category","Payment Method","Notes","Description","Reference #","Status"
|
2
|
+
23/07/2009,"Post Office","£","3.55","0.29","425 - Postage, Freight & Courier","Credit Card",,,"2009-07-23-03",,"Envelopes","£","2.19",,"429 - General Expenses","0.29; VAT - 15%","Postage","£","1.36",,"425 - Postage, Freight & Courier","VAT - 0%"
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
require 'tempfile'
|
3
3
|
|
4
4
|
Spec::Matchers.define :have_detail_matching do |key, value|
|
@@ -48,6 +48,13 @@ describe PaperlessToXero::Converter do
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
+
describe "checking the header row" do
|
52
|
+
it "should raise an UnknownHeaderRow error if it doesn't recognise the header..." do
|
53
|
+
@converter.stubs(:input_path).returns(fixture_path('dodgy-header'))
|
54
|
+
lambda { @converter.parse }.should raise_error(PaperlessToXero::UnknownHeaderRow)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
51
58
|
describe "single item inputs" do
|
52
59
|
it "should able to create an invoice for a basic single-item invoice" do
|
53
60
|
@converter.stubs(:input_path).returns(fixture_path('single-basic'))
|
@@ -133,6 +140,110 @@ describe PaperlessToXero::Converter do
|
|
133
140
|
]
|
134
141
|
)
|
135
142
|
end
|
143
|
+
|
144
|
+
describe "UK VAT rate changes" do
|
145
|
+
describe "pre 2008-12 17.5% VAT" do
|
146
|
+
it "correctly handles days in that VAT rate" do
|
147
|
+
@converter.stubs(:input_path).returns(fixture_path('single-vat-pre-2008-12'))
|
148
|
+
@converter.parse
|
149
|
+
|
150
|
+
verify_invoice_details(
|
151
|
+
:invoice => {:date => Date.parse('2008-05-18'), :merchant => 'Apple Store, Regent Street',
|
152
|
+
:reference_id => '2008-05-18-05', :inc_vat_total => '117.50', :vat_total => '17.50',
|
153
|
+
:ex_vat_total => '100.00', :currency => 'GBP'},
|
154
|
+
:vat_inclusive => true,
|
155
|
+
:line_items => [
|
156
|
+
{:description => 'Phone case', :category => '429', :vat_type => '17.5% (VAT on expenses)',
|
157
|
+
:vat_inclusive_amount => '117.50', :vat_exclusive_amount => '100.00', :vat_amount => '17.50'}
|
158
|
+
]
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "correctly handles the last day of that VAT rate" do
|
163
|
+
@converter.stubs(:input_path).returns(fixture_path('single-vat-2008-11-30'))
|
164
|
+
@converter.parse
|
165
|
+
|
166
|
+
verify_invoice_details(
|
167
|
+
:invoice => {:date => Date.parse('2008-11-30'), :merchant => 'Apple Store, Regent Street',
|
168
|
+
:reference_id => '2008-11-30-05', :inc_vat_total => '117.50', :vat_total => '17.50',
|
169
|
+
:ex_vat_total => '100.00', :currency => 'GBP'},
|
170
|
+
:vat_inclusive => true,
|
171
|
+
:line_items => [
|
172
|
+
{:description => 'Phone case', :category => '429', :vat_type => '17.5% (VAT on expenses)',
|
173
|
+
:vat_inclusive_amount => '117.50', :vat_exclusive_amount => '100.00', :vat_amount => '17.50'}
|
174
|
+
]
|
175
|
+
)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "2009's 15% VAT rate" do
|
180
|
+
it "correctly handles the first day of that VAT rate" do
|
181
|
+
@converter.stubs(:input_path).returns(fixture_path('single-vat-2008-12-01'))
|
182
|
+
@converter.parse
|
183
|
+
|
184
|
+
verify_invoice_details(
|
185
|
+
:invoice => {:date => Date.parse('2008-12-01'), :merchant => 'Apple Store, Regent Street',
|
186
|
+
:reference_id => '2008-12-01-05', :inc_vat_total => '115.00', :vat_total => '15.00',
|
187
|
+
:ex_vat_total => '100.00', :currency => 'GBP'},
|
188
|
+
:vat_inclusive => true,
|
189
|
+
:line_items => [
|
190
|
+
{:description => 'Phone case', :category => '429', :vat_type => '15% (VAT on expenses)',
|
191
|
+
:vat_inclusive_amount => '115.00', :vat_exclusive_amount => '100.00', :vat_amount => '15.00'}
|
192
|
+
]
|
193
|
+
)
|
194
|
+
end
|
195
|
+
|
196
|
+
it "correctly handles days in that VAT rate" do
|
197
|
+
@converter.stubs(:input_path).returns(fixture_path('single-vat-2009'))
|
198
|
+
@converter.parse
|
199
|
+
|
200
|
+
verify_invoice_details(
|
201
|
+
:invoice => {:date => Date.parse('2009-06-01'), :merchant => 'Apple Store, Regent Street',
|
202
|
+
:reference_id => '2009-06-01-05', :inc_vat_total => '115.00', :vat_total => '15.00',
|
203
|
+
:ex_vat_total => '100.00', :currency => 'GBP'},
|
204
|
+
:vat_inclusive => true,
|
205
|
+
:line_items => [
|
206
|
+
{:description => 'Phone case', :category => '429', :vat_type => '15% (VAT on expenses)',
|
207
|
+
:vat_inclusive_amount => '115.00', :vat_exclusive_amount => '100.00', :vat_amount => '15.00'}
|
208
|
+
]
|
209
|
+
)
|
210
|
+
end
|
211
|
+
|
212
|
+
it "correctly handles the last day of that VAT rate" do
|
213
|
+
@converter.stubs(:input_path).returns(fixture_path('single-vat-2009-12-31'))
|
214
|
+
@converter.parse
|
215
|
+
|
216
|
+
verify_invoice_details(
|
217
|
+
:invoice => {:date => Date.parse('2009-12-31'), :merchant => 'Apple Store, Regent Street',
|
218
|
+
:reference_id => '2009-12-31-05', :inc_vat_total => '115.00', :vat_total => '15.00',
|
219
|
+
:ex_vat_total => '100.00', :currency => 'GBP'},
|
220
|
+
:vat_inclusive => true,
|
221
|
+
:line_items => [
|
222
|
+
{:description => 'Phone case', :category => '429', :vat_type => '15% (VAT on expenses)',
|
223
|
+
:vat_inclusive_amount => '115.00', :vat_exclusive_amount => '100.00', :vat_amount => '15.00'}
|
224
|
+
]
|
225
|
+
)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
describe "2010-01-01's return to 17.5% VAT" do
|
230
|
+
it "correctly handles the first day of that VAT rate" do
|
231
|
+
@converter.stubs(:input_path).returns(fixture_path('single-vat-2010-01-01'))
|
232
|
+
@converter.parse
|
233
|
+
|
234
|
+
verify_invoice_details(
|
235
|
+
:invoice => {:date => Date.parse('2010-01-01'), :merchant => 'Apple Store, Regent Street',
|
236
|
+
:reference_id => '2010-01-01-05', :inc_vat_total => '117.50', :vat_total => '17.50',
|
237
|
+
:ex_vat_total => '100.00', :currency => 'GBP'},
|
238
|
+
:vat_inclusive => true,
|
239
|
+
:line_items => [
|
240
|
+
{:description => 'Phone case', :category => '429', :vat_type => '17.5% (VAT on expenses)',
|
241
|
+
:vat_inclusive_amount => '117.50', :vat_exclusive_amount => '100.00', :vat_amount => '17.50'}
|
242
|
+
]
|
243
|
+
)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
136
247
|
end
|
137
248
|
|
138
249
|
describe "multi-item inputs" do
|
@@ -192,6 +303,24 @@ describe PaperlessToXero::Converter do
|
|
192
303
|
]
|
193
304
|
)
|
194
305
|
end
|
306
|
+
|
307
|
+
it "should be able to cope with an multi-line invoice with mixed VAT and VAT-exempt lines" do
|
308
|
+
@converter.stubs(:input_path).returns(fixture_path('multi-item-mixed_vat_and_exempt'))
|
309
|
+
@converter.parse
|
310
|
+
|
311
|
+
verify_invoice_details(
|
312
|
+
:invoice => {:date => Date.parse('2009-07-23'), :merchant => 'Post Office',
|
313
|
+
:reference_id => '2009-07-23-03', :inc_vat_total => '3.55', :vat_total => '0.29',
|
314
|
+
:ex_vat_total => '3.26', :currency => 'GBP'},
|
315
|
+
:vat_inclusive => false,
|
316
|
+
:line_items => [
|
317
|
+
{:description => 'Envelopes', :category => '429', :vat_type => '15% (VAT on expenses)',
|
318
|
+
:vat_inclusive_amount => '2.19', :vat_exclusive_amount => '1.90', :vat_amount => '0.29'},
|
319
|
+
{:description => 'Postage', :category => '425', :vat_type => 'Zero Rated Expenses',
|
320
|
+
:vat_inclusive_amount => '1.36', :vat_exclusive_amount => '1.36', :vat_amount => '0.00'}
|
321
|
+
]
|
322
|
+
)
|
323
|
+
end
|
195
324
|
end
|
196
325
|
|
197
326
|
describe "end-to-end" do
|
@@ -0,0 +1,7 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PaperlessToXero::RowError do
|
4
|
+
it "should be able to be instantiated with the line number, row contents and error message" do
|
5
|
+
PaperlessToXero::RowError.new(1, ["thing", "other thing"], "Bad thing happened").should be_instance_of(PaperlessToXero::RowError)
|
6
|
+
end
|
7
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe PaperlessToXero::InvoiceItem do
|
4
4
|
describe "the creation basics" do
|
@@ -144,6 +144,7 @@ describe PaperlessToXero::InvoiceItem do
|
|
144
144
|
'VAT - Luxembourg' => '15% (Luxembourg, VAT on expenses)',
|
145
145
|
'VAT - EU' => '15% (EU VAT ID)',
|
146
146
|
'VAT - EU - EU372000063' => '15% (EU VAT ID)',
|
147
|
+
'VAT - 17.5%' => '17.5% (VAT on expenses)',
|
147
148
|
'VAT - 15%' => '15% (VAT on expenses)',
|
148
149
|
'VAT - 0%' => 'Zero Rated Expenses',
|
149
150
|
'VAT' => '15% (VAT on expenses)',
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paperless_to_xero
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 1.2.0
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Matt Patterson
|
@@ -9,19 +14,21 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date:
|
13
|
-
default_executable:
|
17
|
+
date: 2010-02-27 00:00:00 +00:00
|
18
|
+
default_executable: paperless_to_xero
|
14
19
|
dependencies:
|
15
20
|
- !ruby/object:Gem::Dependency
|
16
21
|
name: rspec
|
17
|
-
|
18
|
-
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
24
|
requirements:
|
21
25
|
- - ">="
|
22
26
|
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
23
29
|
version: "0"
|
24
|
-
|
30
|
+
type: :development
|
31
|
+
version_requirements: *id001
|
25
32
|
description: |-
|
26
33
|
= Paperless-to-Xero
|
27
34
|
|
@@ -36,33 +43,46 @@ extensions: []
|
|
36
43
|
extra_rdoc_files:
|
37
44
|
- README.rdoc
|
38
45
|
files:
|
39
|
-
-
|
46
|
+
- MIT-LICENSE
|
40
47
|
- README.rdoc
|
48
|
+
- Rakefile
|
49
|
+
- VERSION
|
41
50
|
- bin/paperless_to_xero
|
51
|
+
- lib/paperless_to_xero.rb
|
52
|
+
- lib/paperless_to_xero/converter.rb
|
53
|
+
- lib/paperless_to_xero/decimal_helpers.rb
|
54
|
+
- lib/paperless_to_xero/errors.rb
|
55
|
+
- lib/paperless_to_xero/invoice.rb
|
56
|
+
- lib/paperless_to_xero/invoice_item.rb
|
57
|
+
- lib/paperless_to_xero/version.rb
|
58
|
+
- paperless_to_xero.gemspec
|
59
|
+
- spec/fixtures/dodgy-header.csv
|
42
60
|
- spec/fixtures/end_to_end-input.csv
|
43
61
|
- spec/fixtures/end_to_end-output.csv
|
44
62
|
- spec/fixtures/multi-ex-vat.csv
|
45
63
|
- spec/fixtures/multi-foreign.csv
|
64
|
+
- spec/fixtures/multi-item-mixed_vat_and_exempt.csv
|
46
65
|
- spec/fixtures/multi-item.csv
|
47
66
|
- spec/fixtures/single-1000.csv
|
48
67
|
- spec/fixtures/single-basic.csv
|
49
68
|
- spec/fixtures/single-dkk.csv
|
50
69
|
- spec/fixtures/single-foreign.csv
|
51
70
|
- spec/fixtures/single-no-vat.csv
|
71
|
+
- spec/fixtures/single-vat-2008-11-30.csv
|
72
|
+
- spec/fixtures/single-vat-2008-12-01.csv
|
73
|
+
- spec/fixtures/single-vat-2009-12-31.csv
|
74
|
+
- spec/fixtures/single-vat-2009.csv
|
75
|
+
- spec/fixtures/single-vat-2010-01-01.csv
|
76
|
+
- spec/fixtures/single-vat-pre-2008-12.csv
|
52
77
|
- spec/fixtures/single-zero_rated.csv
|
53
78
|
- spec/paperless_to_xero/converter_spec.rb
|
79
|
+
- spec/paperless_to_xero/errors_spec.rb
|
54
80
|
- spec/paperless_to_xero/invoice_item_spec.rb
|
55
81
|
- spec/paperless_to_xero/invoice_spec.rb
|
56
82
|
- spec/spec.opts
|
57
83
|
- spec/spec_helper.rb
|
58
|
-
- lib/paperless_to_xero/converter.rb
|
59
|
-
- lib/paperless_to_xero/decimal_helpers.rb
|
60
|
-
- lib/paperless_to_xero/invoice.rb
|
61
|
-
- lib/paperless_to_xero/invoice_item.rb
|
62
|
-
- lib/paperless_to_xero/version.rb
|
63
|
-
- lib/paperless_to_xero.rb
|
64
84
|
has_rdoc: true
|
65
|
-
homepage: http://
|
85
|
+
homepage: http://github.com/fidothe/paperless_to_xero/
|
66
86
|
licenses: []
|
67
87
|
|
68
88
|
post_install_message:
|
@@ -75,20 +95,26 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
75
95
|
requirements:
|
76
96
|
- - ">="
|
77
97
|
- !ruby/object:Gem::Version
|
98
|
+
segments:
|
99
|
+
- 0
|
78
100
|
version: "0"
|
79
|
-
version:
|
80
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
102
|
requirements:
|
82
103
|
- - ">="
|
83
104
|
- !ruby/object:Gem::Version
|
105
|
+
segments:
|
106
|
+
- 0
|
84
107
|
version: "0"
|
85
|
-
version:
|
86
108
|
requirements: []
|
87
109
|
|
88
110
|
rubyforge_project: paperless_to_xero
|
89
|
-
rubygems_version: 1.3.
|
111
|
+
rubygems_version: 1.3.6
|
90
112
|
signing_key:
|
91
113
|
specification_version: 3
|
92
114
|
summary: Convert Paperless CSV exports to Xero invoice import CSV
|
93
|
-
test_files:
|
94
|
-
|
115
|
+
test_files:
|
116
|
+
- spec/paperless_to_xero/converter_spec.rb
|
117
|
+
- spec/paperless_to_xero/errors_spec.rb
|
118
|
+
- spec/paperless_to_xero/invoice_item_spec.rb
|
119
|
+
- spec/paperless_to_xero/invoice_spec.rb
|
120
|
+
- spec/spec_helper.rb
|