sie 2.2.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.travis.yml +1 -1
- data/README.md +14 -1
- data/lib/sie/document.rb +19 -3
- data/lib/sie/document/renderer.rb +3 -3
- data/lib/sie/parser/build_entry.rb +37 -17
- data/lib/sie/parser/tokenizer.rb +1 -0
- data/lib/sie/version.rb +1 -1
- data/spec/unit/build_entry_spec.rb +16 -0
- data/spec/unit/document_spec.rb +44 -11
- data/spec/unit/parser/line_parser_spec.rb +3 -7
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YTQzMmU0NGU3NmVhMDY1OWM0OWJmZWMxY2I3M2IyZDJjZTVmMDRiYQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MWNlN2E5OWE3ZGRmZmZkNmRiZmI0MGVkNGZmMThlMDI3M2EwZjE3Yw==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NGY1ZTViZWQyNGUwMzVkNjhlMDI3ZTk4NDYyODg2MjZjYTY2M2Y5YzI0NzI1
|
10
|
+
NTNhODYzZmEwMWQ1ZjExYmU3YTVlMzNmMzAxNDNkNTkzOWQzMThjNGY1OTE2
|
11
|
+
YzQxM2Y1ZGJhZWQ5ZDhiMzljZDk4OWQ0MmVjYjliM2RjYWE0ZGQ=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MTUyMjk5NmMwYzZkZTEyZmU5YTM3MGMwYWQ5YzQ5YzQ1OGFmODU5MmY2ODI5
|
14
|
+
NmVkNTE4ZjcwNDU4YjRjZmVkNTk3MDA3ZWYyOTY0NmEyMmE0OWI1NWQxMTMz
|
15
|
+
NWU3YjhlNWEwMDY5OTNlNzQzYWU3ODYzZjdlN2NhNzY1YzVhOGQ=
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -64,6 +64,18 @@ class YourDataSource
|
|
64
64
|
[ 3100 ]
|
65
65
|
end
|
66
66
|
|
67
|
+
def dimensions
|
68
|
+
[
|
69
|
+
{
|
70
|
+
number: 6,
|
71
|
+
description: "Projekt",
|
72
|
+
objects: [
|
73
|
+
{ number: 1, description: "Education" }
|
74
|
+
]
|
75
|
+
}
|
76
|
+
]
|
77
|
+
end
|
78
|
+
|
67
79
|
# Used to calculate balance before (and on) the given date for an account.
|
68
80
|
def balance_before(account_number, date)
|
69
81
|
# ActiveRecord example:
|
@@ -90,7 +102,8 @@ class YourDataSource
|
|
90
102
|
},
|
91
103
|
{
|
92
104
|
account_number: 3100, amount: -512.0,
|
93
|
-
booked_on: Date.today, description: "Item 1"
|
105
|
+
booked_on: Date.today, description: "Item 1",
|
106
|
+
dimensions: { 6 => 1 }
|
94
107
|
},
|
95
108
|
]
|
96
109
|
}
|
data/lib/sie/document.rb
CHANGED
@@ -14,6 +14,7 @@ module Sie
|
|
14
14
|
add_header
|
15
15
|
add_financial_years
|
16
16
|
add_accounts
|
17
|
+
add_dimensions
|
17
18
|
add_balances
|
18
19
|
add_vouchers
|
19
20
|
|
@@ -24,7 +25,7 @@ module Sie
|
|
24
25
|
|
25
26
|
delegate :program, :program_version, :generated_on, :company_name,
|
26
27
|
:accounts, :balance_account_numbers, :closing_account_numbers,
|
27
|
-
:balance_before, :each_voucher,
|
28
|
+
:balance_before, :each_voucher, :dimensions,
|
28
29
|
to: :data_source
|
29
30
|
|
30
31
|
def add_header
|
@@ -66,6 +67,20 @@ module Sie
|
|
66
67
|
end
|
67
68
|
end
|
68
69
|
|
70
|
+
def add_dimensions
|
71
|
+
dimensions.each do |dimension|
|
72
|
+
dimension_number = dimension.fetch(:number)
|
73
|
+
dimension_description = dimension.fetch(:description)
|
74
|
+
add_line("DIM", dimension_number, dimension_description)
|
75
|
+
|
76
|
+
dimension.fetch(:objects).each do |object|
|
77
|
+
object_number = object.fetch(:number)
|
78
|
+
object_description = object.fetch(:description)
|
79
|
+
add_line("OBJEKT", dimension_number, object_number, object_description)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
69
84
|
def add_vouchers
|
70
85
|
each_voucher do |voucher|
|
71
86
|
add_voucher(voucher)
|
@@ -90,17 +105,18 @@ module Sie
|
|
90
105
|
account_number = line.fetch(:account_number)
|
91
106
|
amount = line.fetch(:amount)
|
92
107
|
booked_on = line.fetch(:booked_on)
|
108
|
+
dimensions = line.fetch(:dimensions, {}).flatten
|
93
109
|
# Some SIE-importers (fortnox) cannot handle descriptions longer than 30 characters,
|
94
110
|
# but the specification has no limit.
|
95
111
|
description = line.fetch(:description).slice(0, DESCRIPTION_LENGTH_MAX)
|
96
112
|
|
97
|
-
add_line("TRANS", account_number,
|
113
|
+
add_line("TRANS", account_number, dimensions, amount, booked_on, description)
|
98
114
|
|
99
115
|
# Some consumers of SIE cannot handle single voucher lines (fortnox), so add another empty one to make
|
100
116
|
# it balance. The spec just requires the sum of lines to be 0, so single lines with zero amount would conform,
|
101
117
|
# but break for these implementations.
|
102
118
|
if voucher_lines.size < 2 && amount.zero?
|
103
|
-
add_line("TRANS", account_number,
|
119
|
+
add_line("TRANS", account_number, dimensions, amount, booked_on, description)
|
104
120
|
end
|
105
121
|
end
|
106
122
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require "stringio"
|
2
2
|
|
3
3
|
class Sie::Document::Renderer
|
4
|
-
EMPTY_ARRAY = :empty_array
|
5
4
|
ENCODING = Encoding::CP437
|
6
5
|
|
7
6
|
def initialize
|
@@ -44,8 +43,9 @@ class Sie::Document::Renderer
|
|
44
43
|
case value
|
45
44
|
when Date
|
46
45
|
value.strftime("%Y%m%d")
|
47
|
-
when
|
48
|
-
|
46
|
+
when Array
|
47
|
+
subvalues = value.map { |subvalue| format_value(subvalue.to_s) }
|
48
|
+
"{#{subvalues.join(' ')}}"
|
49
49
|
when Numeric
|
50
50
|
value.to_s
|
51
51
|
else
|
@@ -19,38 +19,58 @@ module Sie
|
|
19
19
|
|
20
20
|
def build_complete_entry
|
21
21
|
entry = build_empty_entry
|
22
|
-
entry_type = first_token.entry_type
|
23
22
|
|
24
|
-
|
25
|
-
|
23
|
+
attributes_with_tokens.each do |attr, *attr_tokens|
|
24
|
+
label = attr.is_a?(Hash) ? attr.fetch(:name) : attr
|
26
25
|
|
27
|
-
if
|
28
|
-
|
29
|
-
next
|
26
|
+
if attr_tokens.size == 1
|
27
|
+
entry.attributes[label] = attr_tokens.first
|
30
28
|
else
|
31
|
-
|
32
|
-
|
29
|
+
type = attr.fetch(:type)
|
30
|
+
values = attr_tokens.
|
31
|
+
each_slice(type.size).
|
32
|
+
map { |slice| Hash[type.zip(slice)] }
|
33
|
+
|
34
|
+
entry.attributes[label] = values
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
38
|
entry
|
37
39
|
end
|
38
40
|
|
41
|
+
def attributes_with_tokens
|
42
|
+
line_entry_type.map { |attr_entry_type|
|
43
|
+
token = tokens.shift
|
44
|
+
next unless token
|
45
|
+
|
46
|
+
if attr_entry_type.is_a?(String)
|
47
|
+
[ attr_entry_type, token.value ]
|
48
|
+
else
|
49
|
+
unless token.is_a?(Tokenizer::BeginArrayToken)
|
50
|
+
raise InvalidEntryError, "Unexpected token: #{token.inspect}"
|
51
|
+
end
|
52
|
+
|
53
|
+
hash_tokens = []
|
54
|
+
while token = tokens.shift
|
55
|
+
break if token.is_a?(Tokenizer::EndArrayToken)
|
56
|
+
hash_tokens << token.value
|
57
|
+
end
|
58
|
+
|
59
|
+
[ attr_entry_type, *hash_tokens ]
|
60
|
+
end
|
61
|
+
}.compact
|
62
|
+
end
|
63
|
+
|
39
64
|
def build_empty_entry
|
40
65
|
Entry.new(first_token.label)
|
41
66
|
end
|
42
67
|
|
43
|
-
def
|
44
|
-
|
68
|
+
def line_entry_type
|
69
|
+
first_token.entry_type
|
45
70
|
end
|
46
71
|
|
47
|
-
def
|
48
|
-
|
49
|
-
!tokens[i+1].is_a?(Tokenizer::EndArrayToken)
|
50
|
-
raise "We currently don't support metadata within entries as we haven't had a need for it yet (the data between {} in #{line})."
|
51
|
-
end
|
52
|
-
|
53
|
-
tokens.reject! { |token| token.is_a?(Tokenizer::EndArrayToken) }
|
72
|
+
def raise_invalid_entry_error
|
73
|
+
raise InvalidEntryError, "Unknown entry type: #{first_token.label}"
|
54
74
|
end
|
55
75
|
end
|
56
76
|
end
|
data/lib/sie/parser/tokenizer.rb
CHANGED
data/lib/sie/version.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "sie/parser/build_entry"
|
3
|
+
require "sie/parser/tokenizer"
|
4
|
+
|
5
|
+
describe Sie::Parser::BuildEntry, "call" do
|
6
|
+
context "with an unexpected token at start of array" do
|
7
|
+
it "raises InvalidEntryError" do
|
8
|
+
line = '#TRANS 2400 [] -200 20130101 "Foocorp expense"'
|
9
|
+
tokens = Sie::Parser::Tokenizer.new(line).tokenize
|
10
|
+
first_token = tokens.shift
|
11
|
+
build_entry = Sie::Parser::BuildEntry.new(line, first_token, tokens, false)
|
12
|
+
|
13
|
+
expect { build_entry.call }.to raise_error(Sie::Parser::BuildEntry::InvalidEntryError)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/spec/unit/document_spec.rb
CHANGED
@@ -22,15 +22,35 @@ describe Sie::Document, "#render" do
|
|
22
22
|
{
|
23
23
|
creditor: false, type: :invoice, number: 1, booked_on: Date.new(2011, 9, 3), description: "Invoice 1",
|
24
24
|
voucher_lines: [
|
25
|
-
{
|
26
|
-
|
25
|
+
{
|
26
|
+
account_number: 1500, amount: 512.0, booked_on: Date.new(2011, 9, 3), description: "Item 1",
|
27
|
+
dimensions: { 6 => 1 }
|
28
|
+
},
|
29
|
+
{
|
30
|
+
account_number: 3100, amount: -512.0, booked_on: Date.new(2011, 9, 3), description: "Item 1",
|
31
|
+
dimensions: { 6 => 1 }
|
32
|
+
},
|
27
33
|
]
|
28
34
|
},
|
29
35
|
{
|
30
36
|
creditor: true, type: :payment, number: 2, booked_on: Date.new(2012, 8, 31), description: "Payout 1",
|
31
37
|
voucher_lines: [
|
32
|
-
{
|
33
|
-
|
38
|
+
{
|
39
|
+
account_number: 2400, amount: 256.0, booked_on: Date.new(2012, 8, 31), description: "Payout line 1"
|
40
|
+
},
|
41
|
+
{
|
42
|
+
account_number: 1970, amount: -256.0, booked_on: Date.new(2012, 8, 31), description: "Payout line 2"
|
43
|
+
},
|
44
|
+
]
|
45
|
+
}
|
46
|
+
]
|
47
|
+
}
|
48
|
+
let(:dimensions) {
|
49
|
+
[
|
50
|
+
{
|
51
|
+
number: 6, description: "Project",
|
52
|
+
objects: [
|
53
|
+
{ number: 1, description: "Education" }
|
34
54
|
]
|
35
55
|
}
|
36
56
|
]
|
@@ -39,7 +59,7 @@ describe Sie::Document, "#render" do
|
|
39
59
|
class TestDataSource
|
40
60
|
attr_accessor :program, :program_version, :generated_on, :company_name,
|
41
61
|
:accounts, :balance_account_numbers, :closing_account_numbers,
|
42
|
-
:vouchers, :financial_years
|
62
|
+
:vouchers, :financial_years, :dimensions
|
43
63
|
|
44
64
|
# vouchers is not part of the expected interface so making it private.
|
45
65
|
#
|
@@ -73,9 +93,10 @@ describe Sie::Document, "#render" do
|
|
73
93
|
company_name: "Foocorp",
|
74
94
|
financial_years: financial_years,
|
75
95
|
balance_account_numbers: [ 1500, 2400 ],
|
76
|
-
closing_account_numbers: [ 3100 ]
|
96
|
+
closing_account_numbers: [ 3100 ],
|
97
|
+
dimensions: dimensions
|
77
98
|
)
|
78
|
-
|
99
|
+
Sie::Document.new(data_source)
|
79
100
|
}
|
80
101
|
|
81
102
|
let(:sie_file) { Sie::Parser.new.parse(doc.render) }
|
@@ -106,6 +127,14 @@ describe Sie::Document, "#render" do
|
|
106
127
|
expect(indexed_entry_attributes("konto", 0)).to eq("kontonr" => "1500", "kontonamn" => "Customer ledger")
|
107
128
|
end
|
108
129
|
|
130
|
+
it "has dimensions" do
|
131
|
+
expect(indexed_entry_attributes("dim", 0)).to eq("dimensionsnr" => "6", "namn" => "Project")
|
132
|
+
end
|
133
|
+
|
134
|
+
it "has objects" do
|
135
|
+
expect(indexed_entry_attributes("objekt", 0)).to eq("dimensionsnr" => "6", "objektnr" => "1", "objektnamn" => "Education")
|
136
|
+
end
|
137
|
+
|
109
138
|
it "has balances brought forward (ingående balans)" do
|
110
139
|
expect(indexed_entry_attributes("ib", 0)).to eq("arsnr" => "0", "konto" => "1500", "saldo" => "1600.0")
|
111
140
|
expect(indexed_entry_attributes("ib", 1)).to eq("arsnr" => "0", "konto" => "2400", "saldo" => "2500.0")
|
@@ -137,11 +166,13 @@ describe Sie::Document, "#render" do
|
|
137
166
|
)
|
138
167
|
expect(indexed_voucher_entries(0)[0].attributes).to eq(
|
139
168
|
"kontonr" => "1500", "belopp" => "512.0",
|
140
|
-
"transdat" => "20110903", "transtext" => "Item 1"
|
169
|
+
"transdat" => "20110903", "transtext" => "Item 1",
|
170
|
+
"objektlista" => [{"dimensionsnr" => "6", "objektnr" => "1"}]
|
141
171
|
)
|
142
172
|
expect(indexed_voucher_entries(0)[1].attributes).to eq(
|
143
173
|
"kontonr" => "3100", "belopp" => "-512.0",
|
144
|
-
"transdat" => "20110903", "transtext" => "Item 1"
|
174
|
+
"transdat" => "20110903", "transtext" => "Item 1",
|
175
|
+
"objektlista" => [{"dimensionsnr" => "6", "objektnr" => "1"}]
|
145
176
|
)
|
146
177
|
|
147
178
|
expect(indexed_entry("ver", 1).attributes).to eq(
|
@@ -150,11 +181,13 @@ describe Sie::Document, "#render" do
|
|
150
181
|
)
|
151
182
|
expect(indexed_voucher_entries(1)[0].attributes).to eq(
|
152
183
|
"kontonr" => "2400", "belopp" => "256.0",
|
153
|
-
"transdat" => "20120831", "transtext" => "Payout line 1"
|
184
|
+
"transdat" => "20120831", "transtext" => "Payout line 1",
|
185
|
+
"objektlista" => []
|
154
186
|
)
|
155
187
|
expect(indexed_voucher_entries(1)[1].attributes).to eq(
|
156
188
|
"kontonr" => "1970", "belopp" => "-256.0",
|
157
|
-
"transdat" => "20120831", "transtext" => "Payout line 2"
|
189
|
+
"transdat" => "20120831", "transtext" => "Payout line 2",
|
190
|
+
"objektlista" => []
|
158
191
|
)
|
159
192
|
end
|
160
193
|
|
@@ -3,14 +3,15 @@ require "sie/parser/line_parser"
|
|
3
3
|
|
4
4
|
describe Sie::Parser::LineParser, "parse" do
|
5
5
|
it "parses lines from a sie file" do
|
6
|
-
parser = Sie::Parser::LineParser.new('#TRANS 2400 {} -200 20130101 "Foocorp expense"')
|
6
|
+
parser = Sie::Parser::LineParser.new('#TRANS 2400 {"3" "5"} -200 20130101 "Foocorp expense"')
|
7
7
|
entry = parser.parse
|
8
8
|
expect(entry.label).to eq("trans")
|
9
9
|
expect(entry.attributes).to eq({
|
10
10
|
"kontonr" => "2400",
|
11
11
|
"belopp" => "-200",
|
12
12
|
"transdat" => "20130101",
|
13
|
-
"transtext" => "Foocorp expense"
|
13
|
+
"transtext" => "Foocorp expense",
|
14
|
+
"objektlista" => [{"dimensionsnr" => "3", "objektnr" => "5"}],
|
14
15
|
})
|
15
16
|
end
|
16
17
|
|
@@ -33,9 +34,4 @@ describe Sie::Parser::LineParser, "parse" do
|
|
33
34
|
end
|
34
35
|
end
|
35
36
|
end
|
36
|
-
|
37
|
-
it "fails if you have non empty metadata arrays until there is a need to support that" do
|
38
|
-
parser = Sie::Parser::LineParser.new('#TRANS 2400 { 1 "2" } -200 20130101 "Foocorp expense"')
|
39
|
-
expect(-> { parser.parse }).to raise_error(/don't support metadata/)
|
40
|
-
end
|
41
37
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Barsoom AB
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: attr_extras
|
@@ -117,6 +117,7 @@ files:
|
|
117
117
|
- spec/fixtures/sie_file_with_unknown_entries.se
|
118
118
|
- spec/integration/parser_spec.rb
|
119
119
|
- spec/spec_helper.rb
|
120
|
+
- spec/unit/build_entry_spec.rb
|
120
121
|
- spec/unit/document/renderer_spec.rb
|
121
122
|
- spec/unit/document/voucher_series_spec.rb
|
122
123
|
- spec/unit/document_spec.rb
|
@@ -152,6 +153,7 @@ test_files:
|
|
152
153
|
- spec/fixtures/sie_file_with_unknown_entries.se
|
153
154
|
- spec/integration/parser_spec.rb
|
154
155
|
- spec/spec_helper.rb
|
156
|
+
- spec/unit/build_entry_spec.rb
|
155
157
|
- spec/unit/document/renderer_spec.rb
|
156
158
|
- spec/unit/document/voucher_series_spec.rb
|
157
159
|
- spec/unit/document_spec.rb
|