lsv-plus 1.0.0

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.
@@ -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