lsv-plus 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ require 'lsv_plus/formatting_helper'
2
+
3
+ module LSVplus
4
+ class TotalRecordFormatter
5
+ TYPE = '890'
6
+ VERSION = '0'
7
+
8
+ attr_reader :file
9
+
10
+ def self.call(file)
11
+ new(file).call
12
+ end
13
+
14
+ def initialize(file)
15
+ @file = file
16
+ end
17
+
18
+ def call
19
+ [TYPE, VERSION, creation_date, creator_identification, record_number, currency, total_amount].join('')
20
+ end
21
+
22
+ def creation_date
23
+ LSVplus::FormattingHelper.date file.creation_date
24
+ end
25
+
26
+ def creator_identification
27
+ file.creator_identification
28
+ end
29
+
30
+ def record_number
31
+ LSVplus::FormattingHelper.index file.records.length
32
+ end
33
+
34
+ def currency
35
+ file.currency
36
+ end
37
+
38
+ def total_amount
39
+ LSVplus::FormattingHelper.amount file.total
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ module LSVplus
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'lsv_plus/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'lsv-plus'
8
+ spec.version = LSVplus::VERSION
9
+ spec.authors = ['Raffael Schmid']
10
+ spec.email = ['raffael.schmid@welltravel.com']
11
+ spec.summary = 'Gem to create LSV+ files'
12
+ spec.homepage = 'https://github.com/wtag/lsv-plus'
13
+ spec.license = 'MIT'
14
+ spec.description = 'Create a LSV+ file which can be uploaded to your bank.'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
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_development_dependency 'rake', '~> 10.4'
22
+ spec.add_development_dependency 'rspec', '~> 3.4'
23
+ spec.add_development_dependency 'rspec_junit_formatter', '~> 0.2'
24
+ spec.add_development_dependency 'coveralls', '~> 0.8'
25
+ end
@@ -0,0 +1,98 @@
1
+ require 'lsv_plus/file'
2
+
3
+ RSpec.describe LSVplus::File do
4
+ let(:attributes) do
5
+ {
6
+ creator_identification: 'YOLO1',
7
+ currency: 'CHF',
8
+ processing_type: 'P',
9
+ creation_date: Date.new(2016, 1, 5),
10
+ lsv_identification: 'YOLO1',
11
+ }
12
+ end
13
+ let(:instance) { one_time_instance }
14
+
15
+ def one_time_instance
16
+ LSVplus::File.new(attributes)
17
+ end
18
+
19
+ describe 'validations' do
20
+ describe '#creator_identification' do
21
+ it 'it has to be all uppercase' do
22
+ attributes[:creator_identification] = 'yolo1'
23
+ expect { one_time_instance }.to raise_error(LSVplus::File::InvalidCreatorIdentification)
24
+ end
25
+
26
+ it 'has to be exactly 5 characters long' do
27
+ attributes[:creator_identification] = 'ASD1'
28
+ expect { one_time_instance }.to raise_error(LSVplus::File::InvalidCreatorIdentification)
29
+ attributes[:creator_identification] = 'ASDASD'
30
+ expect { one_time_instance }.to raise_error(LSVplus::File::InvalidCreatorIdentification)
31
+ attributes[:creator_identification] = 'ASD12'
32
+ expect { one_time_instance }.to_not raise_error
33
+ end
34
+ end
35
+
36
+ describe '#lsv_identification' do
37
+ it 'has to be all uppercase' do
38
+ attributes[:lsv_identification] = 'yolo1'
39
+ expect { one_time_instance }.to raise_error(LSVplus::File::InvalidLSVIdentification)
40
+ end
41
+
42
+ it 'has to be exactly 5 characters long' do
43
+ attributes[:lsv_identification] = 'ASD1'
44
+ expect { one_time_instance }.to raise_error(LSVplus::File::InvalidLSVIdentification)
45
+ attributes[:lsv_identification] = 'ASDASD'
46
+ expect { one_time_instance }.to raise_error(LSVplus::File::InvalidLSVIdentification)
47
+ attributes[:lsv_identification] = 'ASD12'
48
+ expect { one_time_instance }.to_not raise_error
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '#add_record' do
54
+ it 'adds a record to #records' do
55
+ expect { instance.add_record('a') }.to change { instance.records }.from([]).to(%w(a))
56
+ end
57
+ end
58
+
59
+ describe '#to_s' do
60
+ it 'concatenates the records and the total record' do
61
+ expect(instance).to receive(:records_as_string).and_return('records').ordered
62
+ expect(instance).to receive(:total_record).and_return('total_record').ordered
63
+ expect(instance.to_s).to eq('recordstotal_record')
64
+ end
65
+ end
66
+
67
+ describe '#records_as_string' do
68
+ it 'calls RecordFormatter for each record' do
69
+ expect(LSVplus::RecordFormatter).to receive(:call).with(instance, 'record1', 1).once
70
+ expect(LSVplus::RecordFormatter).to receive(:call).with(instance, 'record2', 2).once
71
+ instance.add_record 'record1'
72
+ instance.add_record 'record2'
73
+ instance.records_as_string
74
+ end
75
+
76
+ it 'concatenates the records' do
77
+ expect(LSVplus::RecordFormatter).to receive(:call).and_return('a', 'b').twice
78
+ instance.add_record 'record1'
79
+ instance.add_record 'record2'
80
+ expect(instance.records_as_string).to eq('ab')
81
+ end
82
+ end
83
+
84
+ describe '#total_record' do
85
+ it 'calls TotalRecordFormatter' do
86
+ expect(LSVplus::TotalRecordFormatter).to receive(:call).with(instance)
87
+ instance.total_record
88
+ end
89
+ end
90
+
91
+ describe '#total' do
92
+ it 'sums record.amount' do
93
+ instance.add_record OpenStruct.new(amount: BigDecimal.new('0.9'))
94
+ instance.add_record OpenStruct.new(amount: 99)
95
+ expect(instance.total).to eq(BigDecimal.new('99.9'))
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,51 @@
1
+ require 'lsv_plus/formatting_helper'
2
+
3
+ RSpec.describe LSVplus::FormattingHelper do
4
+ describe '.date' do
5
+ let(:value) { Date.new(2016, 1, 31) }
6
+
7
+ subject { described_class.date value }
8
+
9
+ it { is_expected.to eq('20160131') }
10
+ end
11
+
12
+ describe '.index' do
13
+ let(:value) { 1 }
14
+
15
+ subject { described_class.index value }
16
+
17
+ it { is_expected.to eq('0000001') }
18
+ end
19
+
20
+ describe '.amount' do
21
+ let(:value) { 133 }
22
+
23
+ subject { described_class.amount value }
24
+
25
+ it { is_expected.to eq('000000133,00') }
26
+ end
27
+
28
+ describe '.multiline' do
29
+ let(:value) { ['Somewhere', 'else'] }
30
+
31
+ subject { described_class.multiline value }
32
+
33
+ it { is_expected.to eq('Somewhere else ') }
34
+ end
35
+
36
+ describe '.account' do
37
+ let(:value) { 'asd-1.233' }
38
+
39
+ subject { described_class.account value }
40
+
41
+ it { is_expected.to eq('asd-1.233 ') }
42
+ end
43
+
44
+ describe '.clearing_number' do
45
+ let(:value) { '233' }
46
+
47
+ subject { described_class.clearing_number value }
48
+
49
+ it { is_expected.to eq('233 ') }
50
+ end
51
+ end
@@ -0,0 +1,97 @@
1
+ require 'bigdecimal'
2
+ require 'lsv-plus'
3
+
4
+ RSpec.describe 'Simple LSV+ file' do
5
+ let(:record_type) { '875' }
6
+ let(:version) { '0' }
7
+ let(:processing_type) { 'P' }
8
+ let(:processing_date) { '20160115' }
9
+ let(:creditor_bank_clearing_number) { '1337 ' }
10
+ let(:creation_date) { '20160105' }
11
+ let(:debitor_bank_clearing_number) { '42 ' }
12
+ let(:creator_identification) { 'YOLO1' }
13
+ let(:record_number) { '0000001' }
14
+ let(:lsv_identification) { 'YOLO1' }
15
+ let(:currency) { 'CHF' }
16
+ let(:amount) { '000001337,42' }
17
+ let(:creditor_iban) { 'CH9300762011623852957 ' }
18
+ let(:creditor_address) do
19
+ 'Fancy AG '\
20
+ 'Funnystreet 42 '\
21
+ ' '\
22
+ ' '
23
+ end
24
+ let(:debitor_account) { '123.456-78XY ' }
25
+ let(:debitor_address) do
26
+ 'Debit AG '\
27
+ 'Other Street 1337 '\
28
+ 'Somewhere City '\
29
+ ' '
30
+ end
31
+ let(:message) do
32
+ 'Invoice 133 via BDD '\
33
+ ' '\
34
+ ' '\
35
+ ' '
36
+ end
37
+ let(:reference_type) { 'A' }
38
+ let(:reference) { '200002000000004443332000061' }
39
+ let(:esr_member_id) { '133742 ' }
40
+ let(:record_string) do
41
+ [
42
+ record_type, version, processing_type, processing_date,
43
+ creditor_bank_clearing_number, creation_date, debitor_bank_clearing_number,
44
+ creator_identification, record_number, lsv_identification,
45
+ currency, amount,
46
+ creditor_iban, creditor_address,
47
+ debitor_account, debitor_address,
48
+ message, reference_type, reference, esr_member_id
49
+ ].join('')
50
+ end
51
+
52
+ let(:total_record_type) { '890' }
53
+ let(:total_record_version) { '0' }
54
+ let(:total_amount) { '000001337,42' }
55
+ let(:total_record) do
56
+ [
57
+ total_record_type, total_record_version,
58
+ creation_date, creator_identification, record_number, currency, total_amount
59
+ ].join('')
60
+ end
61
+ let(:valid_output) do
62
+ [record_string, total_record].join('')
63
+ end
64
+
65
+ let(:file_attributes) do
66
+ {
67
+ creator_identification: creator_identification,
68
+ currency: currency,
69
+ processing_type: 'P',
70
+ creation_date: Date.new(2016, 1, 5),
71
+ lsv_identification: 'YOLO1',
72
+ }
73
+ end
74
+
75
+ let(:record_attributes) do
76
+ {
77
+ processing_date: Date.new(2016, 1, 15),
78
+ creditor_bank_clearing_number: 1337,
79
+ amount: BigDecimal.new('1337.42'),
80
+ debitor_bank_clearing_number: 42,
81
+ creditor_iban: 'CH9300762011623852957',
82
+ creditor_address: ['Fancy AG', 'Funnystreet 42'],
83
+ debitor_account: '123.456-78XY',
84
+ debitor_address: ['Debit AG', 'Other Street 1337', 'Somewhere City'],
85
+ message: ['Invoice 133 via BDD'],
86
+ reference_type: 'A',
87
+ reference: '200002000000004443332000061',
88
+ esr_member_id: '133742',
89
+ }
90
+ end
91
+
92
+ it 'returns a valid LSV+ file' do
93
+ file = LSVplus::File.new(file_attributes)
94
+ file.add_record LSVplus::Record.new(record_attributes)
95
+ expect(file.to_s).to eq(valid_output)
96
+ end
97
+ end
@@ -0,0 +1,313 @@
1
+ require 'lsv_plus/record_formatter'
2
+
3
+ RSpec.describe LSVplus::RecordFormatter do
4
+ let(:file) do
5
+ LSVplus::File.new(
6
+ creator_identification: 'YOLO1',
7
+ currency: 'CHF',
8
+ processing_type: 'P',
9
+ creation_date: Date.new(2016, 1, 5),
10
+ lsv_identification: 'YOLO1',
11
+ )
12
+ end
13
+ let(:record) do
14
+ LSVplus::Record.new(
15
+ processing_date: Date.new(2016, 1, 15),
16
+ creditor_bank_clearing_number: 1337,
17
+ amount: BigDecimal.new('1337.42'),
18
+ debitor_bank_clearing_number: 42,
19
+ creditor_iban: 'CH9300762011623852957',
20
+ creditor_address: ['Fancy AG', 'Funnystreet 42'],
21
+ debitor_account: '123.456-78XY',
22
+ debitor_address: ['Debit AG', 'Other Street 1337', 'Somewhere City'],
23
+ message: ['Invoice 133 via BDD'],
24
+ reference_type: 'A',
25
+ reference: '200002000000004443332000061',
26
+ esr_member_id: '133742',
27
+ )
28
+ end
29
+ let(:index) { 1 }
30
+ let(:instance) { LSVplus::RecordFormatter.new(file, record, index) }
31
+
32
+ describe '.call' do
33
+ let(:record_formatter_double) { instance_double(LSVplus::RecordFormatter) }
34
+
35
+ it 'initializes a new instance and calls `#call`' do
36
+ expect(LSVplus::RecordFormatter).
37
+ to receive(:new).with(record, file, index).and_return(record_formatter_double)
38
+ expect(record_formatter_double).to receive(:call)
39
+ LSVplus::RecordFormatter.call(record, file, index)
40
+ end
41
+ end
42
+
43
+ describe '#call' do
44
+ it 'returns all the formatted fields as string' do
45
+ %i(type version processing_type processing_date
46
+ creditor_bank_clearing_number creation_date debitor_bank_clearing_number
47
+ creator_identification record_number lsv_identification
48
+ currency amount
49
+ creditor_iban creditor_address
50
+ debitor_account debitor_address
51
+ message reference_type reference esr_member_id).each do |meth|
52
+ expect(instance).to receive(meth).with(no_args).and_call_original.ordered
53
+ end
54
+ expect(instance.call).to be_a(String)
55
+ end
56
+ end
57
+
58
+ describe '#type' do
59
+ it 'calls record.type' do
60
+ expect(record).to receive(:type).and_return('value')
61
+ expect(instance.type).to eq('value')
62
+ end
63
+ end
64
+
65
+ describe '#version' do
66
+ it 'calls record.version' do
67
+ expect(record).to receive(:version).and_return('value')
68
+ expect(instance.version).to eq('value')
69
+ end
70
+ end
71
+
72
+ describe '#processing_type' do
73
+ it 'calls file.processing_type' do
74
+ expect(file).to receive(:processing_type).and_return('value')
75
+ expect(instance.processing_type).to eq('value')
76
+ end
77
+ end
78
+
79
+ describe '#processing_date' do
80
+ let(:value) { Date.today }
81
+ before do
82
+ allow(record).to receive(:processing_date).and_return(value)
83
+ end
84
+
85
+ it 'calls record.processing_date' do
86
+ expect(record).to receive(:processing_date).and_return(value)
87
+ instance.processing_date
88
+ end
89
+
90
+ it 'uses LSVplus::FormattingHelper to format it' do
91
+ expect(LSVplus::FormattingHelper).to receive(:date).with(value).and_return('value')
92
+ expect(instance.processing_date).to eq('value')
93
+ end
94
+ end
95
+
96
+ describe '#creditor_bank_clearing_number' do
97
+ let(:value) { Date.today }
98
+ before do
99
+ allow(record).to receive(:creditor_bank_clearing_number).and_return(value)
100
+ end
101
+
102
+ it 'calls record.creditor_bank_clearing_number' do
103
+ expect(record).to receive(:creditor_bank_clearing_number).and_return(value)
104
+ instance.creditor_bank_clearing_number
105
+ end
106
+
107
+ it 'uses LSVplus::FormattingHelper to format it' do
108
+ expect(LSVplus::FormattingHelper).to receive(:clearing_number).with(value).and_return('value')
109
+ expect(instance.creditor_bank_clearing_number).to eq('value')
110
+ end
111
+ end
112
+
113
+ describe '#creation_date' do
114
+ let(:value) { Date.today }
115
+ before do
116
+ allow(file).to receive(:creation_date).and_return(value)
117
+ end
118
+
119
+ it 'calls file.creation_date' do
120
+ expect(file).to receive(:creation_date).and_return(value)
121
+ instance.creation_date
122
+ end
123
+
124
+ it 'uses LSVplus::FormattingHelper to format it' do
125
+ expect(LSVplus::FormattingHelper).to receive(:date).with(value).and_return('value')
126
+ expect(instance.creation_date).to eq('value')
127
+ end
128
+ end
129
+
130
+ describe '#debitor_bank_clearing_number' do
131
+ let(:value) { Date.today }
132
+ before do
133
+ allow(record).to receive(:debitor_bank_clearing_number).and_return(value)
134
+ end
135
+
136
+ it 'calls record.debitor_bank_clearing_number' do
137
+ expect(record).to receive(:debitor_bank_clearing_number).and_return(value)
138
+ instance.debitor_bank_clearing_number
139
+ end
140
+
141
+ it 'uses LSVplus::FormattingHelper to format it' do
142
+ expect(LSVplus::FormattingHelper).to receive(:clearing_number).with(value).and_return('value')
143
+ expect(instance.debitor_bank_clearing_number).to eq('value')
144
+ end
145
+ end
146
+
147
+ describe '#creator_identification' do
148
+ it 'calls file.creator_identification' do
149
+ expect(file).to receive(:creator_identification).and_return('value')
150
+ expect(instance.creator_identification).to eq('value')
151
+ end
152
+ end
153
+
154
+ describe '#record_number' do
155
+ it 'uses LSVplus::FormattingHelper to format it' do
156
+ expect(LSVplus::FormattingHelper).to receive(:index).with(index).and_return('value')
157
+ expect(instance.record_number).to eq('value')
158
+ end
159
+ end
160
+
161
+ describe '#lsv_identification' do
162
+ it 'calls file.lsv_identification' do
163
+ expect(file).to receive(:lsv_identification).and_return('value')
164
+ expect(instance.lsv_identification).to eq('value')
165
+ end
166
+ end
167
+
168
+ describe '#currency' do
169
+ it 'calls file.currency' do
170
+ expect(file).to receive(:currency).and_return('value')
171
+ expect(instance.currency).to eq('value')
172
+ end
173
+ end
174
+
175
+ describe '#amount' do
176
+ let(:value) { 1234 }
177
+ before do
178
+ allow(record).to receive(:amount).and_return(value)
179
+ end
180
+
181
+ it 'calls record.amount' do
182
+ expect(record).to receive(:amount).and_return(value)
183
+ instance.amount
184
+ end
185
+
186
+ it 'uses LSVplus::FormattingHelper to format it' do
187
+ expect(LSVplus::FormattingHelper).to receive(:amount).with(value).and_return('value')
188
+ expect(instance.amount).to eq('value')
189
+ end
190
+ end
191
+
192
+ describe '#creditor_iban' do
193
+ let(:value) { 1234 }
194
+ before do
195
+ allow(record).to receive(:creditor_iban).and_return(value)
196
+ end
197
+
198
+ it 'calls record.creditor_iban' do
199
+ expect(record).to receive(:creditor_iban).and_return(value)
200
+ instance.creditor_iban
201
+ end
202
+
203
+ it 'uses LSVplus::FormattingHelper to format it' do
204
+ expect(LSVplus::FormattingHelper).to receive(:account).with(value).and_return('value')
205
+ expect(instance.creditor_iban).to eq('value')
206
+ end
207
+ end
208
+
209
+ describe '#creditor_address' do
210
+ let(:value) { 1234 }
211
+ before do
212
+ allow(record).to receive(:creditor_address).and_return(value)
213
+ end
214
+
215
+ it 'calls record.creditor_address' do
216
+ expect(record).to receive(:creditor_address).and_return(value)
217
+ instance.creditor_address
218
+ end
219
+
220
+ it 'uses LSVplus::FormattingHelper to format it' do
221
+ expect(LSVplus::FormattingHelper).to receive(:multiline).with(value).and_return('value')
222
+ expect(instance.creditor_address).to eq('value')
223
+ end
224
+ end
225
+
226
+ describe '#debitor_account' do
227
+ let(:value) { 1234 }
228
+ before do
229
+ allow(record).to receive(:debitor_account).and_return(value)
230
+ end
231
+
232
+ it 'calls record.debitor_account' do
233
+ expect(record).to receive(:debitor_account).and_return(value)
234
+ instance.debitor_account
235
+ end
236
+
237
+ it 'uses LSVplus::FormattingHelper to format it' do
238
+ expect(LSVplus::FormattingHelper).to receive(:account).with(value).and_return('value')
239
+ expect(instance.debitor_account).to eq('value')
240
+ end
241
+ end
242
+
243
+ describe '#debitor_address' do
244
+ let(:value) { 1234 }
245
+ before do
246
+ allow(record).to receive(:debitor_address).and_return(value)
247
+ end
248
+
249
+ it 'calls record.debitor_address' do
250
+ expect(record).to receive(:debitor_address).and_return(value)
251
+ instance.debitor_address
252
+ end
253
+
254
+ it 'uses LSVplus::FormattingHelper to format it' do
255
+ expect(LSVplus::FormattingHelper).to receive(:multiline).with(value).and_return('value')
256
+ expect(instance.debitor_address).to eq('value')
257
+ end
258
+ end
259
+
260
+ describe '#message' do
261
+ let(:value) { 1234 }
262
+ before do
263
+ allow(record).to receive(:message).and_return(value)
264
+ end
265
+
266
+ it 'calls record.message' do
267
+ expect(record).to receive(:message).and_return(value)
268
+ instance.message
269
+ end
270
+
271
+ it 'uses LSVplus::FormattingHelper to format it' do
272
+ expect(LSVplus::FormattingHelper).to receive(:multiline).with(value).and_return('value')
273
+ expect(instance.message).to eq('value')
274
+ end
275
+ end
276
+
277
+ describe '#reference_type' do
278
+ it 'calls record.reference_type' do
279
+ expect(record).to receive(:reference_type).and_return('value')
280
+ expect(instance.reference_type).to eq('value')
281
+ end
282
+ end
283
+
284
+ describe '#reference' do
285
+ before do
286
+ allow(record).to receive(:reference).and_return('value')
287
+ end
288
+
289
+ it 'calls record.reference' do
290
+ expect(record).to receive(:reference).and_return('1' * 27)
291
+ expect(instance.reference).to eq('1' * 27)
292
+ end
293
+
294
+ it 'fills up the missing chars with spaces' do
295
+ expect(instance.reference).to eq('value ')
296
+ end
297
+ end
298
+
299
+ describe '#esr_member_id' do
300
+ before do
301
+ allow(record).to receive(:esr_member_id).and_return('value')
302
+ end
303
+
304
+ it 'calls record.esr_member_id' do
305
+ expect(record).to receive(:esr_member_id).and_return('1' * 9)
306
+ expect(instance.esr_member_id).to eq('1' * 9)
307
+ end
308
+
309
+ it 'fills up the missing chars with spaces' do
310
+ expect(instance.esr_member_id).to eq('value ')
311
+ end
312
+ end
313
+ end