sie 3.2.0 → 4.1.1
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.
- checksums.yaml +5 -5
- data/README.md +8 -3
- data/lib/sie/document/renderer.rb +2 -2
- data/lib/sie/document.rb +8 -4
- data/lib/sie/parser/build_entry.rb +4 -3
- data/lib/sie/parser/entry_types.rb +35 -35
- data/lib/sie/parser/tokenizer/token.rb +1 -1
- data/lib/sie/parser/tokenizer.rb +2 -2
- data/lib/sie/version.rb +1 -1
- metadata +18 -51
- data/.gitignore +0 -18
- data/.rspec +0 -2
- data/.rvmrc +0 -1
- data/.travis.yml +0 -4
- data/Gemfile +0 -4
- data/Rakefile +0 -15
- data/script/bootstrap +0 -3
- data/script/refresh +0 -25
- data/script/test +0 -6
- data/script/turbux_rspec +0 -6
- data/sie.gemspec +0 -27
- data/spec/fixtures/sie_file.se +0 -28
- data/spec/fixtures/sie_file_with_unknown_entries.se +0 -32
- data/spec/integration/parser_spec.rb +0 -56
- data/spec/spec_helper.rb +0 -5
- data/spec/unit/build_entry_spec.rb +0 -17
- data/spec/unit/document/renderer_spec.rb +0 -13
- data/spec/unit/document/voucher_series_spec.rb +0 -41
- data/spec/unit/document_spec.rb +0 -294
- data/spec/unit/parser/line_parser_spec.rb +0 -37
- data/spec/unit/parser/tokenizer_spec.rb +0 -98
- data/spec/unit/parser_spec.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 26526531e52a08b42e851ecb48e7139284c0d123497e0690b96e034568d80260
|
4
|
+
data.tar.gz: 66f9a81079464969de19e6fdd5a5b35c2eda75376ec6495b7afe31d3bf3e9b45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a00336cae71fa202912e83f523fd3229600f6712f12531425e841cb328c2a45fd3f2203e009266b467ca9e544fcb3abbfceef8b5dc6254f324f88213957f217
|
7
|
+
data.tar.gz: 3fa86473dd8b9ade5ba84fd227fca41be16bb7c6e4cfc15ae27cb9cb1a4d2a1d3a765b7bd6134b3d6765a2446b74e6a209d3e355756d62d2c2de165a21a54749
|
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
# Sie
|
2
2
|
|
3
|
-
[](https://github.com/barsoom/sie/actions/workflows/ci.yml)
|
4
|
+
[](https://codeclimate.com/github/barsoom/sie)
|
5
5
|
|
6
|
+
SIE parser and generator supporting the [format "SIE typ 1-4 – Klassisk SIE"](https://sie.se/format/).
|
6
7
|
|
7
8
|
## Installation
|
8
9
|
|
@@ -161,7 +162,11 @@ Getting the latest code and gems:
|
|
161
162
|
|
162
163
|
## Resources
|
163
164
|
|
164
|
-
[SIE format specification rev 4B (
|
165
|
+
[SIE format specification rev 4B (Swedish)](https://sie.se/wp-content/uploads/2020/05/SIE_filformat_ver_4B_080930.pdf)
|
166
|
+
|
167
|
+
## See also
|
168
|
+
|
169
|
+
* [PHP port of this library](https://github.com/neam/php-sie)
|
165
170
|
|
166
171
|
|
167
172
|
## Contributing
|
@@ -9,7 +9,7 @@ class Sie::Document::Renderer
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def add_line(label, *values)
|
12
|
-
append ["##{
|
12
|
+
append [ "##{label}", *format_values(values) ].join(" ")
|
13
13
|
end
|
14
14
|
|
15
15
|
def add_array
|
@@ -36,7 +36,7 @@ class Sie::Document::Renderer
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def encoded(text)
|
39
|
-
text.encode(ENCODING, :
|
39
|
+
text.encode(ENCODING, invalid: :replace, undef: :replace, replace: "?")
|
40
40
|
end
|
41
41
|
|
42
42
|
def format_value(value)
|
data/lib/sie/document.rb
CHANGED
@@ -5,10 +5,12 @@ require "active_support/core_ext/module/delegation"
|
|
5
5
|
|
6
6
|
module Sie
|
7
7
|
class Document
|
8
|
-
# Because
|
9
|
-
|
8
|
+
# Because some accounting software have limits
|
9
|
+
# - Fortnox should handle 200
|
10
|
+
# - Visma etc -> 100
|
11
|
+
DESCRIPTION_LENGTH_MAX = 100
|
10
12
|
|
11
|
-
pattr_initialize :data_source
|
13
|
+
pattr_initialize :data_source, [ exclude_balance_rows: false ]
|
12
14
|
|
13
15
|
def render
|
14
16
|
add_header
|
@@ -53,6 +55,8 @@ module Sie
|
|
53
55
|
end
|
54
56
|
|
55
57
|
def add_balances
|
58
|
+
return if exclude_balance_rows
|
59
|
+
|
56
60
|
financial_years.each_with_index do |date_range, index|
|
57
61
|
add_balance_rows("IB", -index, balance_account_numbers, date_range.begin)
|
58
62
|
add_balance_rows("UB", -index, balance_account_numbers, date_range.end)
|
@@ -111,7 +115,7 @@ module Sie
|
|
111
115
|
amount = line.fetch(:amount)
|
112
116
|
booked_on = line.fetch(:booked_on)
|
113
117
|
dimensions = line.fetch(:dimensions, {}).flatten
|
114
|
-
# Some SIE-importers (fortnox) cannot handle descriptions longer than
|
118
|
+
# Some SIE-importers (fortnox) cannot handle descriptions longer than 200 characters,
|
115
119
|
# but the specification has no limit.
|
116
120
|
description = line.fetch(:description).slice(0, DESCRIPTION_LENGTH_MAX)
|
117
121
|
|
@@ -27,9 +27,9 @@ module Sie
|
|
27
27
|
entry.attributes[label] = attr_tokens.first
|
28
28
|
else
|
29
29
|
type = attr.fetch(:type)
|
30
|
-
values = attr_tokens
|
31
|
-
each_slice(type.size)
|
32
|
-
map { |slice| Hash[type.zip(slice)] }
|
30
|
+
values = attr_tokens
|
31
|
+
.each_slice(type.size)
|
32
|
+
.map { |slice| Hash[type.zip(slice)] }
|
33
33
|
|
34
34
|
entry.attributes[label] = values
|
35
35
|
end
|
@@ -53,6 +53,7 @@ module Sie
|
|
53
53
|
hash_tokens = []
|
54
54
|
while token = tokens.shift
|
55
55
|
break if token.is_a?(Tokenizer::EndArrayToken)
|
56
|
+
|
56
57
|
hash_tokens << token.value
|
57
58
|
end
|
58
59
|
|
@@ -1,41 +1,41 @@
|
|
1
1
|
module Sie
|
2
2
|
class Parser
|
3
3
|
ENTRY_TYPES = {
|
4
|
-
"adress" => [
|
5
|
-
"bkod" => [
|
6
|
-
"dim" => [
|
7
|
-
"enhet" => [
|
8
|
-
"flagga" => [
|
9
|
-
"fnamn" => [
|
10
|
-
"fnr" => [
|
11
|
-
"format" => [
|
12
|
-
"ftyp" => [
|
13
|
-
"gen" => [
|
14
|
-
"ib" => [
|
15
|
-
"konto" => [
|
16
|
-
"kptyp" => [
|
17
|
-
"ktyp" => [
|
18
|
-
"objekt" => [
|
19
|
-
"oib" => [
|
20
|
-
"omfattn" => [
|
21
|
-
"orgnr" => [
|
22
|
-
"oub" => [
|
23
|
-
"pbudget" => [
|
24
|
-
"program" => [
|
25
|
-
"prosa" => [
|
26
|
-
"psaldo" => [
|
27
|
-
"rar" => [
|
28
|
-
"res" => [
|
29
|
-
"sietyp" => [
|
30
|
-
"sru" => [
|
31
|
-
"taxar" => [
|
32
|
-
"trans" => [
|
33
|
-
"rtrans" => [
|
34
|
-
"btrans" => [
|
35
|
-
"ub" => [
|
36
|
-
"underdim" => [
|
37
|
-
"valuta" => [
|
38
|
-
"ver" => [
|
4
|
+
"adress" => [ "kontakt", "utdelningsadr", "postadr", "tel" ],
|
5
|
+
"bkod" => [ "SNI-kod" ],
|
6
|
+
"dim" => [ "dimensionsnr", "namn" ],
|
7
|
+
"enhet" => [ "kontonr", "enhet" ],
|
8
|
+
"flagga" => [ "x" ],
|
9
|
+
"fnamn" => [ "foretagsnamn" ],
|
10
|
+
"fnr" => [ "foretagsid" ],
|
11
|
+
"format" => [ "PC8" ],
|
12
|
+
"ftyp" => [ "foretagstyp" ],
|
13
|
+
"gen" => [ "datum", "sign" ],
|
14
|
+
"ib" => [ "arsnr", "konto", "saldo", "kvantitet" ],
|
15
|
+
"konto" => [ "kontonr", "kontonamn" ],
|
16
|
+
"kptyp" => [ "typ" ],
|
17
|
+
"ktyp" => [ "kontonr", "kontotyp" ],
|
18
|
+
"objekt" => [ "dimensionsnr", "objektnr", "objektnamn" ],
|
19
|
+
"oib" => [ "arsnr", "konto", { name: "objekt", type: [ "dimensionsnr", "objektnr" ] }, "saldo", "kvantitet" ],
|
20
|
+
"omfattn" => [ "datum" ],
|
21
|
+
"orgnr" => [ "orgnr", "forvnr", "verknr" ],
|
22
|
+
"oub" => [ "arsnr", "konto", { name: "objekt", type: [ "dimensionsnr", "objektnr" ] }, "saldo", "kvantitet" ],
|
23
|
+
"pbudget" => [ "arsnr", "period", "konto", { name: "objekt", type: [ "dimensionsnr", "objektnr" ] }, "saldo", "kvantitet" ],
|
24
|
+
"program" => [ "programnamn", "version" ],
|
25
|
+
"prosa" => [ "text" ],
|
26
|
+
"psaldo" => [ "arsnr", "period", "konto", { name: "objekt", type: [ "dimensionsnr", "objektnr" ] }, "saldo", "kvantitet" ],
|
27
|
+
"rar" => [ "arsnr", "start", "slut" ],
|
28
|
+
"res" => [ "ars", "konto", "saldo", "kvantitet" ],
|
29
|
+
"sietyp" => [ "typnr" ],
|
30
|
+
"sru" => [ "konto", "SRU-kod" ],
|
31
|
+
"taxar" => [ "ar" ],
|
32
|
+
"trans" => [ "kontonr", { name: "objektlista", type: [ "dimensionsnr", "objektnr" ], many: true }, "belopp", "transdat", "transtext", "kvantitet", "sign" ],
|
33
|
+
"rtrans" => [ "kontonr", { name: "objektlista", type: [ "dimensionsnr", "objektnr" ], many: true }, "belopp", "transdat", "transtext", "kvantitet", "sign" ],
|
34
|
+
"btrans" => [ "kontonr", { name: "objektlista", type: [ "dimensionsnr", "objektnr" ], many: true }, "belopp", "transdat", "transtext", "kvantitet", "sign" ],
|
35
|
+
"ub" => [ "arsnr", "konto", "saldo", "kvantitet" ],
|
36
|
+
"underdim" => [ "dimensionsnr", "namn", "superdimension" ],
|
37
|
+
"valuta" => [ "valutakod" ],
|
38
|
+
"ver" => [ "serie", "vernr", "verdatum", "vertext", "regdatum", "sign" ],
|
39
39
|
}
|
40
40
|
end
|
41
41
|
end
|
data/lib/sie/parser/tokenizer.rb
CHANGED
@@ -67,7 +67,7 @@ module Sie
|
|
67
67
|
match = find_quoted_string || find_unquoted_string
|
68
68
|
|
69
69
|
if match
|
70
|
-
|
70
|
+
remove_unnecessary_escapes(match)
|
71
71
|
else
|
72
72
|
nil
|
73
73
|
end
|
@@ -91,7 +91,7 @@ module Sie
|
|
91
91
|
scanner.scan(/\S+/)
|
92
92
|
end
|
93
93
|
|
94
|
-
def
|
94
|
+
def remove_unnecessary_escapes(match)
|
95
95
|
match.gsub(/\\([\\"])/, "\\1")
|
96
96
|
end
|
97
97
|
|
data/lib/sie/version.rb
CHANGED
metadata
CHANGED
@@ -1,83 +1,83 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Barsoom AB
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: attr_extras
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '1.3'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
description: SIE parser and generator
|
@@ -87,13 +87,7 @@ executables: []
|
|
87
87
|
extensions: []
|
88
88
|
extra_rdoc_files: []
|
89
89
|
files:
|
90
|
-
- .gitignore
|
91
|
-
- .rspec
|
92
|
-
- .rvmrc
|
93
|
-
- .travis.yml
|
94
|
-
- Gemfile
|
95
90
|
- README.md
|
96
|
-
- Rakefile
|
97
91
|
- lib/sie.rb
|
98
92
|
- lib/sie/document.rb
|
99
93
|
- lib/sie/document/renderer.rb
|
@@ -107,55 +101,28 @@ files:
|
|
107
101
|
- lib/sie/parser/tokenizer.rb
|
108
102
|
- lib/sie/parser/tokenizer/token.rb
|
109
103
|
- lib/sie/version.rb
|
110
|
-
- script/bootstrap
|
111
|
-
- script/refresh
|
112
|
-
- script/test
|
113
|
-
- script/turbux_rspec
|
114
|
-
- sie.gemspec
|
115
|
-
- spec/fixtures/sie_file.se
|
116
|
-
- spec/fixtures/sie_file_with_unknown_entries.se
|
117
|
-
- spec/integration/parser_spec.rb
|
118
|
-
- spec/spec_helper.rb
|
119
|
-
- spec/unit/build_entry_spec.rb
|
120
|
-
- spec/unit/document/renderer_spec.rb
|
121
|
-
- spec/unit/document/voucher_series_spec.rb
|
122
|
-
- spec/unit/document_spec.rb
|
123
|
-
- spec/unit/parser/line_parser_spec.rb
|
124
|
-
- spec/unit/parser/tokenizer_spec.rb
|
125
|
-
- spec/unit/parser_spec.rb
|
126
104
|
homepage: ''
|
127
105
|
licenses:
|
128
106
|
- MIT
|
129
|
-
metadata:
|
107
|
+
metadata:
|
108
|
+
rubygems_mfa_required: 'true'
|
130
109
|
post_install_message:
|
131
110
|
rdoc_options: []
|
132
111
|
require_paths:
|
133
112
|
- lib
|
134
113
|
required_ruby_version: !ruby/object:Gem::Requirement
|
135
114
|
requirements:
|
136
|
-
- -
|
115
|
+
- - ">="
|
137
116
|
- !ruby/object:Gem::Version
|
138
117
|
version: '0'
|
139
118
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
119
|
requirements:
|
141
|
-
- -
|
120
|
+
- - ">="
|
142
121
|
- !ruby/object:Gem::Version
|
143
122
|
version: '0'
|
144
123
|
requirements: []
|
145
|
-
|
146
|
-
rubygems_version: 2.4.5
|
124
|
+
rubygems_version: 3.2.31
|
147
125
|
signing_key:
|
148
126
|
specification_version: 4
|
149
127
|
summary: Parses and generates SIE files (http://sie.se/)
|
150
|
-
test_files:
|
151
|
-
- spec/fixtures/sie_file.se
|
152
|
-
- spec/fixtures/sie_file_with_unknown_entries.se
|
153
|
-
- spec/integration/parser_spec.rb
|
154
|
-
- spec/spec_helper.rb
|
155
|
-
- spec/unit/build_entry_spec.rb
|
156
|
-
- spec/unit/document/renderer_spec.rb
|
157
|
-
- spec/unit/document/voucher_series_spec.rb
|
158
|
-
- spec/unit/document_spec.rb
|
159
|
-
- spec/unit/parser/line_parser_spec.rb
|
160
|
-
- spec/unit/parser/tokenizer_spec.rb
|
161
|
-
- spec/unit/parser_spec.rb
|
128
|
+
test_files: []
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.rvmrc
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
rvm ruby-2.0.0-p643@sie --create
|
data/.travis.yml
DELETED
data/Gemfile
DELETED
data/Rakefile
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
2
|
-
|
3
|
-
namespace :spec do
|
4
|
-
task :unit do
|
5
|
-
puts "Running unit tests:"
|
6
|
-
system("rspec spec/unit/**_spec.rb") || exit(1)
|
7
|
-
end
|
8
|
-
|
9
|
-
task :integration do
|
10
|
-
puts "Running integrated tests:"
|
11
|
-
system("rspec spec/integration/**_spec.rb") || exit(1)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
task :default => [ :"spec:unit", :"spec:integration" ]
|
data/script/bootstrap
DELETED
data/script/refresh
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
#!/bin/bash
|
2
|
-
|
3
|
-
printf "\e[00;34mGetting the latest version\e[00m... "
|
4
|
-
|
5
|
-
(git status|grep 'nothing to commit' 1> /dev/null)
|
6
|
-
|
7
|
-
if [ ! $? -eq 0 ]
|
8
|
-
then
|
9
|
-
set -e
|
10
|
-
git stash 1> /dev/null
|
11
|
-
git pull --rebase 1> /dev/null
|
12
|
-
git stash pop 1> /dev/null
|
13
|
-
else
|
14
|
-
set -e
|
15
|
-
git pull --rebase 1> /dev/null
|
16
|
-
fi
|
17
|
-
|
18
|
-
echo "done"
|
19
|
-
|
20
|
-
printf "\e[00;34mBundling\e[00m... "
|
21
|
-
bundle 1> /dev/null
|
22
|
-
echo "done"
|
23
|
-
echo
|
24
|
-
|
25
|
-
rake
|
data/script/test
DELETED
data/script/turbux_rspec
DELETED
data/sie.gemspec
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'sie/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "sie"
|
8
|
-
spec.version = Sie::VERSION
|
9
|
-
spec.authors = ["Barsoom AB"]
|
10
|
-
spec.email = ["all@barsoom.se"]
|
11
|
-
spec.description = %q{SIE parser and generator}
|
12
|
-
spec.summary = %q{Parses and generates SIE files (http://sie.se/)}
|
13
|
-
spec.homepage = ""
|
14
|
-
spec.license = "MIT"
|
15
|
-
|
16
|
-
spec.files = `git ls-files`.split($/)
|
17
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = ["lib"]
|
20
|
-
|
21
|
-
spec.add_dependency "attr_extras"
|
22
|
-
spec.add_dependency "activesupport"
|
23
|
-
|
24
|
-
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
-
spec.add_development_dependency "rake"
|
26
|
-
spec.add_development_dependency "rspec"
|
27
|
-
end
|
data/spec/fixtures/sie_file.se
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
#FLAGGA 0
|
2
|
-
#PROGRAM "fooconomic" "1.0"
|
3
|
-
#FORMAT PC8
|
4
|
-
#GEN 20130101
|
5
|
-
#SIETYP 4
|
6
|
-
#ORGNR 555555-5555
|
7
|
-
#FNAMN "Foocorp"
|
8
|
-
#ADRESS "Foocorp" "" "12345 City" "555-12345"
|
9
|
-
#KONTO 1510 "Accounts receivable"
|
10
|
-
#KTYP 1510 T
|
11
|
-
#SRU 1510 204
|
12
|
-
#KONTO 1930 "Bank account"
|
13
|
-
#KTYP 1930 T
|
14
|
-
#SRU 1930 200
|
15
|
-
#KONTO 2440 Supplier
|
16
|
-
#KTYP 2440 S
|
17
|
-
#SRU 2440 300
|
18
|
-
#VER A 1 20130101 "Invoice" 20120105
|
19
|
-
{
|
20
|
-
#TRANS 1510 {} -200 20130101 "Coffee machine"
|
21
|
-
#TRANS 4100 {} 180 20130101 "Coffee machine"
|
22
|
-
#TRANS 2611 {} -20 20130101 "VAT"
|
23
|
-
}
|
24
|
-
#VER A 2 20130102 "Payment" 20120105
|
25
|
-
{
|
26
|
-
#TRANS 1510 {} -200 20130101 "Payment: Coffee machine"
|
27
|
-
#TRANS 1970 {} 200 20130101 "Payment: Coffee machine"
|
28
|
-
}
|
@@ -1,32 +0,0 @@
|
|
1
|
-
#FLAGGA 0
|
2
|
-
#PROGRAM "fooconomic" "1.0"
|
3
|
-
#FORMAT PC8
|
4
|
-
#GEN 20130101
|
5
|
-
#SIETYP 4
|
6
|
-
#ORGNR 555555-5555
|
7
|
-
#FNAMN "Foocorp"
|
8
|
-
#ADRESS "Foocorp" "" "12345 City" "555-12345"
|
9
|
-
#KONTO 1510 "Accounts receivable"
|
10
|
-
#KTYP 1510 T
|
11
|
-
#SRU 1510 204
|
12
|
-
#KONTO 1930 "Bank account"
|
13
|
-
#KTYP 1930 T
|
14
|
-
#SRU 1930 200
|
15
|
-
#KONTO 2440 Supplier
|
16
|
-
#KTYP 2440 S
|
17
|
-
#SRU 2440 300
|
18
|
-
#KONTO 2610 "Utgaende moms, oreducerad "
|
19
|
-
#KTYP 2610 S
|
20
|
-
#SRU 2610 7369
|
21
|
-
#MOMSKOD 2610 10
|
22
|
-
#VER A 1 20130101 "Invoice" 20120105
|
23
|
-
{
|
24
|
-
#TRANS 1510 {} -200 20130101 "Coffee machine"
|
25
|
-
#TRANS 4100 {} 180 20130101 "Coffee machine"
|
26
|
-
#TRANS 2611 {} -20 20130101 "VAT"
|
27
|
-
}
|
28
|
-
#VER A 2 20130102 "Payment" 20120105
|
29
|
-
{
|
30
|
-
#TRANS 1510 {} -200 20130101 "Payment: Coffee machine"
|
31
|
-
#TRANS 1970 {} 200 20130101 "Payment: Coffee machine"
|
32
|
-
}
|
@@ -1,56 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
describe Sie::Parser do
|
6
|
-
it "parses a file" do
|
7
|
-
parser = Sie::Parser.new
|
8
|
-
|
9
|
-
open_file("fixtures/sie_file.se") do |f|
|
10
|
-
sie_file = parser.parse(f)
|
11
|
-
|
12
|
-
expect(sie_file.entries_with_label("fnamn").first.attributes["foretagsnamn"]).to eq("Foocorp")
|
13
|
-
|
14
|
-
account = sie_file.entries_with_label("konto").first
|
15
|
-
expect(account.attributes["kontonr"]).to eq("1510")
|
16
|
-
expect(account.attributes["kontonamn"]).to eq("Accounts receivable")
|
17
|
-
expect(sie_file.entries_with_label("ver").size).to eq(2)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
context "with unknown entries" do
|
22
|
-
let(:file_with_unknown_entries) { "fixtures/sie_file_with_unknown_entries.se" }
|
23
|
-
|
24
|
-
context "using a lenient parser" do
|
25
|
-
let(:parser) { Sie::Parser.new(lenient: true) }
|
26
|
-
|
27
|
-
it "handles unknown entries without raising error" do
|
28
|
-
open_file(file_with_unknown_entries) do |f|
|
29
|
-
expect { parser.parse(f) }.not_to raise_error
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
it "continues to parse the complete file after unknown entries" do
|
34
|
-
open_file(file_with_unknown_entries) do |f|
|
35
|
-
sie_file = parser.parse(f)
|
36
|
-
|
37
|
-
expect(sie_file.entries_with_label("ver").size).to eq(2)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
context "with strict parser" do
|
43
|
-
let(:parser) { Sie::Parser.new }
|
44
|
-
|
45
|
-
it "raises error when encountering unknown entries" do
|
46
|
-
open_file(file_with_unknown_entries) do |f|
|
47
|
-
expect { parser.parse(f) }.to raise_error(/Unknown entry type: momskod.+Pass 'lenient: true'/)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def open_file(fixture_file, &block)
|
54
|
-
File.open(File.join(File.dirname(__FILE__), "../#{fixture_file}"), &block)
|
55
|
-
end
|
56
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,17 +0,0 @@
|
|
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
|
-
|
12
|
-
expect {
|
13
|
-
Sie::Parser::BuildEntry.call(line, first_token, tokens, false)
|
14
|
-
}.to raise_error(Sie::Parser::BuildEntry::InvalidEntryError)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
describe Sie::Document::Renderer, "#add_line" do
|
6
|
-
it "replaces input of the wrong encoding with '?'" do
|
7
|
-
renderer = Sie::Document::Renderer.new
|
8
|
-
renderer.add_line "Hello ☃", 1
|
9
|
-
output = renderer.render
|
10
|
-
|
11
|
-
expect(output).to eq "#Hello ? 1\n"
|
12
|
-
end
|
13
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Sie::Document::VoucherSeries, ".for" do
|
4
|
-
subject(:series) { Sie::Document::VoucherSeries.for(creditor, type) }
|
5
|
-
|
6
|
-
let(:type) { :invoice }
|
7
|
-
|
8
|
-
context "when on the creditor side" do
|
9
|
-
let(:creditor) { true }
|
10
|
-
|
11
|
-
context "with an invoice" do
|
12
|
-
let(:type) { :invoice }
|
13
|
-
it { should == "LF" }
|
14
|
-
end
|
15
|
-
|
16
|
-
context "with a payment" do
|
17
|
-
let(:type) { :payment }
|
18
|
-
it { should == "KB" }
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
context "when on the debtor side" do
|
23
|
-
let(:creditor) { false }
|
24
|
-
|
25
|
-
context "with an invoice" do
|
26
|
-
let(:type) { :invoice }
|
27
|
-
it { should == "KF" }
|
28
|
-
end
|
29
|
-
|
30
|
-
context "with a payment" do
|
31
|
-
let(:type) { :payment }
|
32
|
-
it { should == "KI" }
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
context "when neither a payment or invoice" do
|
37
|
-
let(:creditor) { false }
|
38
|
-
let(:type) { :manual_bookable }
|
39
|
-
it { should == "LV" }
|
40
|
-
end
|
41
|
-
end
|
data/spec/unit/document_spec.rb
DELETED
@@ -1,294 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require "spec_helper"
|
3
|
-
require "sie"
|
4
|
-
require "active_support/core_ext/date/calculations"
|
5
|
-
|
6
|
-
describe Sie::Document, "#render" do
|
7
|
-
let(:financial_years) {
|
8
|
-
[
|
9
|
-
Date.new(2011, 1, 1)..Date.new(2011, 12, 31),
|
10
|
-
Date.new(2012, 1, 1)..Date.new(2012, 12, 31),
|
11
|
-
Date.new(2013, 1, 1)..Date.new(2013, 12, 31),
|
12
|
-
]
|
13
|
-
}
|
14
|
-
let(:generated_on) { Date.yesterday }
|
15
|
-
let(:accounts) {
|
16
|
-
[
|
17
|
-
number: 1500, description: "Customer ledger",
|
18
|
-
]
|
19
|
-
}
|
20
|
-
let(:vouchers) {
|
21
|
-
[
|
22
|
-
{
|
23
|
-
creditor: false, type: :invoice, number: 1, booked_on: Date.new(2011, 9, 3), description: "Invoice 1",
|
24
|
-
voucher_lines: [
|
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
|
-
},
|
33
|
-
]
|
34
|
-
},
|
35
|
-
{
|
36
|
-
creditor: true, type: :payment, number: 2, booked_on: Date.new(2012, 8, 31), description: "Payout 1",
|
37
|
-
voucher_lines: [
|
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" }
|
54
|
-
]
|
55
|
-
}
|
56
|
-
]
|
57
|
-
}
|
58
|
-
|
59
|
-
class TestDataSource
|
60
|
-
attr_accessor :program, :program_version, :generated_on, :company_name,
|
61
|
-
:accounts, :balance_account_numbers, :closing_account_numbers,
|
62
|
-
:vouchers, :financial_years, :dimensions
|
63
|
-
|
64
|
-
# vouchers is not part of the expected interface so making it private.
|
65
|
-
#
|
66
|
-
# Sie::Document uses #each_voucher so that you can build documents for huge sets of vouchers
|
67
|
-
# by loading them in batches.
|
68
|
-
private :vouchers
|
69
|
-
|
70
|
-
def initialize(hash)
|
71
|
-
hash.each do |k, v|
|
72
|
-
public_send("#{k}=", v)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def each_voucher(&block)
|
77
|
-
vouchers.each(&block)
|
78
|
-
end
|
79
|
-
|
80
|
-
def balance_before(account_number, date)
|
81
|
-
if account_number == 9999
|
82
|
-
# So we can test empty balances.
|
83
|
-
nil
|
84
|
-
else
|
85
|
-
# Faking a fetch based on date and number.
|
86
|
-
account_number.to_i + (date.mday * 100).to_f
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
let(:doc) {
|
92
|
-
data_source = TestDataSource.new(
|
93
|
-
accounts: accounts,
|
94
|
-
vouchers: vouchers,
|
95
|
-
program: "Foonomic",
|
96
|
-
program_version: "3.11",
|
97
|
-
generated_on: generated_on,
|
98
|
-
company_name: "Foocorp",
|
99
|
-
financial_years: financial_years,
|
100
|
-
balance_account_numbers: [ 1500, 2400, 9999 ],
|
101
|
-
closing_account_numbers: [ 3100, 9999 ],
|
102
|
-
dimensions: dimensions
|
103
|
-
)
|
104
|
-
Sie::Document.new(data_source)
|
105
|
-
}
|
106
|
-
|
107
|
-
let(:sie_file) { Sie::Parser.new.parse(doc.render) }
|
108
|
-
|
109
|
-
it "adds a header" do
|
110
|
-
expect(entry_attribute("flagga", "x")).to eq("0")
|
111
|
-
expect(entry_attribute("program", "programnamn")).to eq("Foonomic")
|
112
|
-
expect(entry_attribute("program", "version")).to eq("3.11")
|
113
|
-
expect(entry_attribute("format", "PC8")).to eq("PC8")
|
114
|
-
expect(entry_attribute("gen", "datum")).to eq(generated_on.strftime("%Y%m%d"))
|
115
|
-
expect(entry_attribute("sietyp", "typnr")).to eq("4")
|
116
|
-
expect(entry_attribute("fnamn", "foretagsnamn")).to eq("Foocorp")
|
117
|
-
end
|
118
|
-
|
119
|
-
it "has accounting years" do
|
120
|
-
expect(indexed_entry_attribute("rar", 0, "arsnr")).to eq("0")
|
121
|
-
expect(indexed_entry_attribute("rar", 0, "start")).to eq("20130101")
|
122
|
-
expect(indexed_entry_attribute("rar", 0, "slut")).to eq("20131231")
|
123
|
-
expect(indexed_entry_attribute("rar", 1, "arsnr")).to eq("-1")
|
124
|
-
expect(indexed_entry_attribute("rar", 1, "start")).to eq("20120101")
|
125
|
-
expect(indexed_entry_attribute("rar", 1, "slut")).to eq("20121231")
|
126
|
-
expect(indexed_entry_attribute("rar", 2, "arsnr")).to eq("-2")
|
127
|
-
expect(indexed_entry_attribute("rar", 2, "start")).to eq("20110101")
|
128
|
-
expect(indexed_entry_attribute("rar", 2, "slut")).to eq("20111231")
|
129
|
-
end
|
130
|
-
|
131
|
-
it "has accounts" do
|
132
|
-
expect(indexed_entry_attributes("konto", 0)).to eq("kontonr" => "1500", "kontonamn" => "Customer ledger")
|
133
|
-
end
|
134
|
-
|
135
|
-
it "has dimensions" do
|
136
|
-
expect(indexed_entry_attributes("dim", 0)).to eq("dimensionsnr" => "6", "namn" => "Project")
|
137
|
-
end
|
138
|
-
|
139
|
-
it "has objects" do
|
140
|
-
expect(indexed_entry_attributes("objekt", 0)).to eq("dimensionsnr" => "6", "objektnr" => "1", "objektnamn" => "Education")
|
141
|
-
end
|
142
|
-
|
143
|
-
it "has balances brought forward (ingående balans)" do
|
144
|
-
expect(indexed_entry_attributes("ib", 0)).not_to eq("arsnr" => "0", "konto" => "9999", "saldo" => "")
|
145
|
-
expect(indexed_entry_attributes("ib", 0)).to eq("arsnr" => "0", "konto" => "1500", "saldo" => "1600.0")
|
146
|
-
expect(indexed_entry_attributes("ib", 1)).to eq("arsnr" => "0", "konto" => "2400", "saldo" => "2500.0")
|
147
|
-
expect(indexed_entry_attributes("ib", 2)).to eq("arsnr" => "-1", "konto" => "1500", "saldo" => "1600.0")
|
148
|
-
expect(indexed_entry_attributes("ib", 3)).to eq("arsnr" => "-1", "konto" => "2400", "saldo" => "2500.0")
|
149
|
-
expect(indexed_entry_attributes("ib", 4)).to eq("arsnr" => "-2", "konto" => "1500", "saldo" => "1600.0")
|
150
|
-
expect(indexed_entry_attributes("ib", 5)).to eq("arsnr" => "-2", "konto" => "2400", "saldo" => "2500.0")
|
151
|
-
end
|
152
|
-
|
153
|
-
it "has balances carried forward (utgående balans)" do
|
154
|
-
expect(indexed_entry_attributes("ub", 0)).not_to eq("arsnr" => "0", "konto" => "9999", "saldo" => "")
|
155
|
-
expect(indexed_entry_attributes("ub", 0)).to eq("arsnr" => "0", "konto" => "1500", "saldo" => "4600.0")
|
156
|
-
expect(indexed_entry_attributes("ub", 1)).to eq("arsnr" => "0", "konto" => "2400", "saldo" => "5500.0")
|
157
|
-
expect(indexed_entry_attributes("ub", 2)).to eq("arsnr" => "-1", "konto" => "1500", "saldo" => "4600.0")
|
158
|
-
expect(indexed_entry_attributes("ub", 3)).to eq("arsnr" => "-1", "konto" => "2400", "saldo" => "5500.0")
|
159
|
-
expect(indexed_entry_attributes("ub", 4)).to eq("arsnr" => "-2", "konto" => "1500", "saldo" => "4600.0")
|
160
|
-
expect(indexed_entry_attributes("ub", 5)).to eq("arsnr" => "-2", "konto" => "2400", "saldo" => "5500.0")
|
161
|
-
end
|
162
|
-
|
163
|
-
it "has closing account balances (saldo för resultatkonto)" do
|
164
|
-
expect(indexed_entry_attributes("res", 0)).not_to eq("ars" => "0", "konto" => "9999", "saldo" => "")
|
165
|
-
expect(indexed_entry_attributes("res", 0)).to eq("ars" => "0", "konto" => "3100", "saldo" => "6200.0")
|
166
|
-
expect(indexed_entry_attributes("res", 1)).to eq("ars" => "-1", "konto" => "3100", "saldo" => "6200.0")
|
167
|
-
expect(indexed_entry_attributes("res", 2)).to eq("ars" => "-2", "konto" => "3100", "saldo" => "6200.0")
|
168
|
-
end
|
169
|
-
|
170
|
-
it "has vouchers" do
|
171
|
-
expect(indexed_entry("ver", 0).attributes).to eq(
|
172
|
-
"serie" => "KF", "vernr" => "1",
|
173
|
-
"verdatum" => "20110903", "vertext" => "Invoice 1"
|
174
|
-
)
|
175
|
-
expect(indexed_voucher_entries(0)[0].attributes).to eq(
|
176
|
-
"kontonr" => "1500", "belopp" => "512.0",
|
177
|
-
"transdat" => "20110903", "transtext" => "Item 1",
|
178
|
-
"objektlista" => [{"dimensionsnr" => "6", "objektnr" => "1"}]
|
179
|
-
)
|
180
|
-
expect(indexed_voucher_entries(0)[1].attributes).to eq(
|
181
|
-
"kontonr" => "3100", "belopp" => "-512.0",
|
182
|
-
"transdat" => "20110903", "transtext" => "Item 1",
|
183
|
-
"objektlista" => [{"dimensionsnr" => "6", "objektnr" => "1"}]
|
184
|
-
)
|
185
|
-
|
186
|
-
expect(indexed_entry("ver", 1).attributes).to eq(
|
187
|
-
"serie" => "KB", "vernr" => "2",
|
188
|
-
"verdatum" => "20120831", "vertext" => "Payout 1"
|
189
|
-
)
|
190
|
-
expect(indexed_voucher_entries(1)[0].attributes).to eq(
|
191
|
-
"kontonr" => "2400", "belopp" => "256.0",
|
192
|
-
"transdat" => "20120831", "transtext" => "Payout line 1",
|
193
|
-
"objektlista" => []
|
194
|
-
)
|
195
|
-
expect(indexed_voucher_entries(1)[1].attributes).to eq(
|
196
|
-
"kontonr" => "1970", "belopp" => "-256.0",
|
197
|
-
"transdat" => "20120831", "transtext" => "Payout line 2",
|
198
|
-
"objektlista" => []
|
199
|
-
)
|
200
|
-
end
|
201
|
-
|
202
|
-
context "with really long descriptions" do
|
203
|
-
let(:accounts) {
|
204
|
-
[
|
205
|
-
number: 1500, description: "Customer ledger with really really long description blablabla"
|
206
|
-
]
|
207
|
-
}
|
208
|
-
let(:vouchers) {
|
209
|
-
[
|
210
|
-
build_voucher(
|
211
|
-
description: "Payout 1 with really really long description blablabla",
|
212
|
-
voucher_lines: [
|
213
|
-
build_voucher_line(description: "Payout line 1 with really really long description blablabla"),
|
214
|
-
build_voucher_line(description: "Payout line 2"),
|
215
|
-
]
|
216
|
-
)
|
217
|
-
]
|
218
|
-
}
|
219
|
-
|
220
|
-
it "truncates the descriptions" do
|
221
|
-
expect(indexed_entry_attributes("konto", 0)).to eq("kontonr" => "1500", "kontonamn" => "Customer ledger with really re")
|
222
|
-
expect(indexed_entry("ver", 0).attributes["vertext"]).to eq("Payout 1 with really really lo")
|
223
|
-
expect(indexed_voucher_entries(0)[0].attributes["transtext"]).to eq("Payout line 1 with really real")
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
context "with a zeroed single voucher line" do
|
228
|
-
let(:vouchers) {
|
229
|
-
[
|
230
|
-
build_voucher(voucher_lines: [ build_voucher_line(amount: 0) ])
|
231
|
-
]
|
232
|
-
}
|
233
|
-
|
234
|
-
it "ensures there are at least two lines" do
|
235
|
-
expect(indexed_voucher_entries(0).size).to eq(2)
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
context "with a series defined" do
|
240
|
-
let(:vouchers) {
|
241
|
-
[
|
242
|
-
build_voucher(series: "X"),
|
243
|
-
]
|
244
|
-
}
|
245
|
-
|
246
|
-
it "reads the series from the voucher" do
|
247
|
-
expect(indexed_entry("ver", 0).attributes["serie"]).to eq("X")
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
private
|
252
|
-
|
253
|
-
def build_voucher(attributes)
|
254
|
-
defaults = {
|
255
|
-
creditor: true,
|
256
|
-
type: :payment,
|
257
|
-
number: 1,
|
258
|
-
booked_on: Date.today,
|
259
|
-
description: "A voucher",
|
260
|
-
voucher_lines: [
|
261
|
-
build_voucher_line,
|
262
|
-
build_voucher_line,
|
263
|
-
],
|
264
|
-
}
|
265
|
-
defaults.merge(attributes)
|
266
|
-
end
|
267
|
-
|
268
|
-
def build_voucher_line(attributes = {})
|
269
|
-
defaults = { account_number: 1234, amount: 1, booked_on: Date.today, description: "A voucher line" }
|
270
|
-
defaults.merge(attributes)
|
271
|
-
end
|
272
|
-
|
273
|
-
def entry_attribute(label, attribute)
|
274
|
-
indexed_entry_attribute(label, 0, attribute)
|
275
|
-
end
|
276
|
-
|
277
|
-
def indexed_entry_attribute(label, index, attribute)
|
278
|
-
indexed_entry_attributes(label, index).fetch(attribute) do
|
279
|
-
raise "Unknown attribute #{ attribute } in #{ entry.attributes.keys.inspect }"
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
|
-
def indexed_entry_attributes(label, index)
|
284
|
-
indexed_entry(label, index).attributes
|
285
|
-
end
|
286
|
-
|
287
|
-
def indexed_voucher_entries(index)
|
288
|
-
indexed_entry("ver", index).entries
|
289
|
-
end
|
290
|
-
|
291
|
-
def indexed_entry(label, index)
|
292
|
-
sie_file.entries_with_label(label)[index] or raise "No entry with label #{ label.inspect } found!"
|
293
|
-
end
|
294
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "sie/parser/line_parser"
|
3
|
-
|
4
|
-
describe Sie::Parser::LineParser, "parse" do
|
5
|
-
it "parses lines from a sie file" do
|
6
|
-
parser = Sie::Parser::LineParser.new('#TRANS 2400 {"3" "5"} -200 20130101 "Foocorp expense"')
|
7
|
-
entry = parser.parse
|
8
|
-
expect(entry.label).to eq("trans")
|
9
|
-
expect(entry.attributes).to eq({
|
10
|
-
"kontonr" => "2400",
|
11
|
-
"belopp" => "-200",
|
12
|
-
"transdat" => "20130101",
|
13
|
-
"transtext" => "Foocorp expense",
|
14
|
-
"objektlista" => [{"dimensionsnr" => "3", "objektnr" => "5"}],
|
15
|
-
})
|
16
|
-
end
|
17
|
-
|
18
|
-
context "with unknown entry" do
|
19
|
-
let(:line) { "#MOMSKOD 2611 10"}
|
20
|
-
|
21
|
-
context "using a lenient parser" do
|
22
|
-
let(:parser) { Sie::Parser::LineParser.new(line, lenient: true) }
|
23
|
-
|
24
|
-
it "raises no error when encountering unknown entries" do
|
25
|
-
expect { parser.parse }.not_to raise_error
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
context "using a strict parser" do
|
30
|
-
let(:parser) { Sie::Parser::LineParser.new(line) }
|
31
|
-
|
32
|
-
it "raises error when encountering unknown entries" do
|
33
|
-
expect { parser.parse }.to raise_error(/Unknown entry type/)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,98 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "sie/parser/tokenizer"
|
3
|
-
|
4
|
-
describe Sie::Parser::Tokenizer do
|
5
|
-
it "tokenizes the given line" do
|
6
|
-
tokenizer = Sie::Parser::Tokenizer.new('#TRANS 2400 {} -200 20130101 "Foocorp expense"')
|
7
|
-
tokens = tokenizer.tokenize
|
8
|
-
|
9
|
-
expect(token_table_for(tokens)).to eq([
|
10
|
-
[ "EntryToken", "TRANS" ],
|
11
|
-
[ "StringToken", "2400" ],
|
12
|
-
[ "BeginArrayToken", "" ],
|
13
|
-
[ "EndArrayToken", "" ],
|
14
|
-
[ "StringToken", "-200" ],
|
15
|
-
[ "StringToken", "20130101" ],
|
16
|
-
[ "StringToken", "Foocorp expense" ]
|
17
|
-
])
|
18
|
-
end
|
19
|
-
|
20
|
-
it "can parse metadata arrays" do
|
21
|
-
tokenizer = Sie::Parser::Tokenizer.new('#TRANS 2400 { 1 "2" } -200 20130101 "Foocorp expense"')
|
22
|
-
tokens = tokenizer.tokenize
|
23
|
-
|
24
|
-
expect(token_table_for(tokens)).to eq([
|
25
|
-
[ "EntryToken", "TRANS" ],
|
26
|
-
[ "StringToken", "2400" ],
|
27
|
-
[ "BeginArrayToken", "" ],
|
28
|
-
[ "StringToken", "1" ],
|
29
|
-
[ "StringToken", "2" ],
|
30
|
-
[ "EndArrayToken", "" ],
|
31
|
-
[ "StringToken", "-200" ],
|
32
|
-
[ "StringToken", "20130101" ],
|
33
|
-
[ "StringToken", "Foocorp expense" ]
|
34
|
-
])
|
35
|
-
end
|
36
|
-
|
37
|
-
it "handles escaped quotes in quoted strings" do
|
38
|
-
tokenizer = Sie::Parser::Tokenizer.new('"String with \\" quote"')
|
39
|
-
tokens = tokenizer.tokenize
|
40
|
-
|
41
|
-
expect(token_table_for(tokens)).to eq([
|
42
|
-
[ "StringToken", 'String with " quote']
|
43
|
-
])
|
44
|
-
end
|
45
|
-
|
46
|
-
it "handles escaped quotes in non-quoted strings" do
|
47
|
-
tokenizer = Sie::Parser::Tokenizer.new('String_with_\\"_quote')
|
48
|
-
tokens = tokenizer.tokenize
|
49
|
-
|
50
|
-
expect(token_table_for(tokens)).to eq([
|
51
|
-
[ "StringToken", 'String_with_"_quote']
|
52
|
-
])
|
53
|
-
end
|
54
|
-
|
55
|
-
it "handles escaped backslash in strings" do
|
56
|
-
tokenizer = Sie::Parser::Tokenizer.new('"String with \\\\ backslash"')
|
57
|
-
tokens = tokenizer.tokenize
|
58
|
-
|
59
|
-
expect(token_table_for(tokens)).to eq([
|
60
|
-
[ "StringToken", 'String with \\ backslash']
|
61
|
-
])
|
62
|
-
end
|
63
|
-
|
64
|
-
it "has reasonable behavior for consecutive escape characters" do
|
65
|
-
tokenizer = Sie::Parser::Tokenizer.new('"\\\\\\"\\\\"')
|
66
|
-
tokens = tokenizer.tokenize
|
67
|
-
|
68
|
-
expect(token_table_for(tokens)).to eq([
|
69
|
-
[ "StringToken", '\\"\\']
|
70
|
-
])
|
71
|
-
end
|
72
|
-
|
73
|
-
it "handles tab character as field separator" do
|
74
|
-
tokenizer = Sie::Parser::Tokenizer.new("#TRANS\t2400")
|
75
|
-
tokens = tokenizer.tokenize
|
76
|
-
|
77
|
-
expect(token_table_for(tokens)).to eq([
|
78
|
-
[ "EntryToken", "TRANS"],
|
79
|
-
[ "StringToken", "2400"]
|
80
|
-
])
|
81
|
-
end
|
82
|
-
|
83
|
-
it "rejects control characters" do
|
84
|
-
codes_not_allowed = (0..8).to_a + (10..31).to_a + [127]
|
85
|
-
codes_not_allowed.each do |x|
|
86
|
-
tokenizer = Sie::Parser::Tokenizer.new([x].pack("C"))
|
87
|
-
expect{tokenizer.tokenize}.to raise_error /Unhandled character/
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
private
|
92
|
-
|
93
|
-
def token_table_for(tokens)
|
94
|
-
tokens.map { |token|
|
95
|
-
[ token.class.name.split("::").last, token.value ]
|
96
|
-
}
|
97
|
-
end
|
98
|
-
end
|
data/spec/unit/parser_spec.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "sie/parser"
|
3
|
-
|
4
|
-
describe Sie::Parser, "parse" do
|
5
|
-
it "parses sie data that includes arrays" do
|
6
|
-
data = <<-DATA
|
7
|
-
#VER "LF" 2222 20130101 "Foocorp expense"
|
8
|
-
{
|
9
|
-
#TRANS 2400 {} -200 20130101 "Foocorp expense"
|
10
|
-
#TRANS 4100 {} 180 20130101 "Widgets from foocorp"
|
11
|
-
#TRANS 2611 {} -20 20130101 "VAT"
|
12
|
-
}
|
13
|
-
DATA
|
14
|
-
|
15
|
-
parser = Sie::Parser.new
|
16
|
-
sie_file = parser.parse(data)
|
17
|
-
|
18
|
-
voucher_entry = sie_file.entries.first
|
19
|
-
expect(sie_file.entries.size).to eq(1)
|
20
|
-
expect(voucher_entry.attributes["verdatum"]).to eq("20130101")
|
21
|
-
expect(voucher_entry.entries.size).to eq(3)
|
22
|
-
expect(voucher_entry.entries.first.attributes["kontonr"]).to eq("2400")
|
23
|
-
end
|
24
|
-
|
25
|
-
it "handles leading whitespace" do
|
26
|
-
data = <<-DATA
|
27
|
-
#VER "LF" 2222 20130101 "Foocorp expense"
|
28
|
-
{
|
29
|
-
#TRANS 2400 {} -200 20130101 "Foocorp expense"
|
30
|
-
#TRANS 4100 {} 180 20130101 "Widgets from foocorp"
|
31
|
-
#TRANS 2611 {} -20 20130101 "VAT"
|
32
|
-
}
|
33
|
-
DATA
|
34
|
-
|
35
|
-
parser = Sie::Parser.new
|
36
|
-
sie_file = parser.parse(data)
|
37
|
-
|
38
|
-
voucher_entry = sie_file.entries.first
|
39
|
-
expect(sie_file.entries.size).to eq(1)
|
40
|
-
expect(voucher_entry.entries.size).to eq(3)
|
41
|
-
end
|
42
|
-
end
|