diff --git a/spec/files/bioromeo/bioromeo_flawless.csv b/spec/files/bioromeo/bioromeo_flawless.csv
new file mode 100644
index 0000000..950d3dd
--- /dev/null
+++ b/spec/files/bioromeo/bioromeo_flawless.csv
@@ -0,0 +1,12 @@
+,,,,,,
+,Bestelling plaatsen via info@bioromeo.nl,,,,,
+,Op maandag bestellen.,,,,,
+,Uitleveren. ,,,,,
+Zwijnsweg 5,Prijzen blablabla,,,,,
+8307 PP Ens,"En nog meer wat €0,- kosten",,,,,
+skal 012345,bla in overleg,,,,,
+Vragen: bel iemand 01-23456789,,,,,,
+,,,,,,
+Artnr.,Product,Skal,Demeter, Prijs per eenh. , Prijs per colli ,Bestelling,opm.
+,"Aardappels ""nieuwe oogst""",,,,,,
+1,Wilde aardappels - 5kg,1234,123456, € 1.00 , € 5.00 ,,Kopervrij
diff --git a/spec/files/bnn/bnn_bad_encoding.BNN b/spec/files/bnn/bnn_bad_encoding.BNN
new file mode 100644
index 0000000..0b7cb14
--- /dev/null
+++ b/spec/files/bnn/bnn_bad_encoding.BNN
@@ -0,0 +1,3 @@
+BNN;3;0;Naturkost Nord, Hamburg;T;Angebot Nr. 0922;EUR;20220905;20221001;20220825;837;1
+64721;A;;;4280001958081;4280001958203;Greek Dressing - Kräuter Mix;Oregano, Basilikum und Minze;;;med;;GR;C%;DE-ÖKO-001;120;1302;10;55;;1;6 x35g;6;35g;1;N;930190;99260;;1,41;;;;1;;;4,49;2,89;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;28,571;;
+;;99
\ No newline at end of file
diff --git a/spec/files/bnn/bnn_flawless.BNN b/spec/files/bnn/bnn_flawless.BNN
new file mode 100644
index 0000000..1c5ac61
--- /dev/null
+++ b/spec/files/bnn/bnn_flawless.BNN
@@ -0,0 +1,3 @@
+BNN;3;0;Naturkost Nord, Hamburg;T;Angebot Nr. 0922;EUR;20220905;20221001;20220825;837;1
+64721;X;;;4280001958081;4280001958203;Greek Dressing - Kr„uter Mix;Oregano, Basilikum und Minze;;;med;;GR;C%;DE-™KO-001;120;1302;10;55;;1;6 x35g;6;35g;1;N;930190;99260;;1,41;;;;1;;;4,49;2,89;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;28,571;;
+;;99
\ No newline at end of file
diff --git a/spec/files/bnn/bnn_flawless_category.BNN b/spec/files/bnn/bnn_flawless_category.BNN
new file mode 100644
index 0000000..6f09dbf
--- /dev/null
+++ b/spec/files/bnn/bnn_flawless_category.BNN
@@ -0,0 +1,3 @@
+BNN;3;0;Naturkost Nord, Hamburg;T;Angebot Nr. 0922;EUR;20220905;20221001;20220825;837;1
+64721;A;;;4280001958081;4280001958203;Greek Dressing - Kr„uter Mix;Oregano, Basilikum und Minze;;;med;;GR;C%;DE-™KO-001;120;4000;10;55;;1;6 x35g;6;35g;1;N;930190;99260;;1,41;;;;1;;;4,49;2,89;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;28,571;;
+;;99
\ No newline at end of file
diff --git a/spec/files/bnn/bnn_flawless_special.BNN b/spec/files/bnn/bnn_flawless_special.BNN
new file mode 100644
index 0000000..0f285f6
--- /dev/null
+++ b/spec/files/bnn/bnn_flawless_special.BNN
@@ -0,0 +1,3 @@
+BNN;3;0;Naturkost Nord, Hamburg;T;Angebot Nr. 0922;EUR;20220905;20221001;20220825;837;1
+64721;A;;;4280001958081;4280001958203;Greek Dressing - Kr„uter Mix;Oregano, Basilikum und Minze;;;med;;GR;C%;DE-™KO-001;120;1302;10;55;;1;6 x35g;6;35g;1;N;930190;99260;;1,41;;;;1;;;4,49;2,89;J;;2;3;;;;;;;;;;;;;;;;;;;A;;20230101;20230201;;Kg;28,571;;
+;;99
diff --git a/spec/files/bnn/bnn_missing_entries.BNN b/spec/files/bnn/bnn_missing_entries.BNN
new file mode 100644
index 0000000..6c8dafe
--- /dev/null
+++ b/spec/files/bnn/bnn_missing_entries.BNN
@@ -0,0 +1,3 @@
+BNN;3;0;Naturkost Nord, Hamburg;T;Angebot Nr. 0922;EUR;20220905;20221001;20220825;837;1
+64721;A;;;4280001958081;4280001958203;Greek Dressing - Kr„uter Mix;Oregano, Basilikum und Minze;;;HDE;;GR;C%;DE-™KO-001;120;1100;10;55;;1;6 x35g;6;35g;1;N;;99260;;1,41;;;;1;;;4,49;2,89;J;;;;;;;;;;;;;;;;;;;;;;A;;;;;Kg;28,571;;
+;;99
diff --git a/spec/files/bnn/bnn_missing_order_number.BNN b/spec/files/bnn/bnn_missing_order_number.BNN
new file mode 100644
index 0000000..aadcb9b
--- /dev/null
+++ b/spec/files/bnn/bnn_missing_order_number.BNN
@@ -0,0 +1,3 @@
+BNN;3;0;Naturkost Nord, Hamburg;T;Angebot Nr. 0922;EUR;20220905;20221001;20220825;837;1
+;A;;;4280001958081;4280001958203;Greek Dressing - Kr„uter Mix;Oregano, Basilikum und Minze;;;HDE;;GR;C%;DE-™KO-001;120;1100;10;55;;1;6 x35g;6;35g;1;N;;99260;;1,41;;;;1;;;4,49;2,89;J;;;;;;;;;;;;;;;;;;;;;;A;;;;;Kg;28,571;;
+;;99
diff --git a/spec/files/bnn/fusion.rb b/spec/files/bnn/fusion.rb
new file mode 100644
index 0000000..2f0d579
--- /dev/null
+++ b/spec/files/bnn/fusion.rb
@@ -0,0 +1,66 @@
+event_ids = [25, 6, 10, 9, 18, 12, 20, 21, 23, 30, 11, 29, 28, 19]
+# events = Event.where("starting_at >= ?", Date.parse("2016-01-01"))
+events = Event.where(id: event_ids).chronological
+puts events.pluck(:name)
+
+# Fusion 2016
+# at.tension#7
+# Fusion 2018
+# Fusion 2019
+# at.tension#8
+# Fusion 2020
+# Fusion 2021 RED
+# Fusion 2021 BLACK
+# Plan:et C - alpha
+# Plan:et C - beta
+# be.tween #1
+# Plan:et C - gamma
+# Fusion 2022
+# at.tension#9
+
+bookings = Booking.where(event: events)
+ap bookings.count
+
+sums = {}
+sums[:quellensteuer] = {}
+sums[:doitsch] = {}
+sums[:quellensteuer][:guest_tickets] = 0
+sums[:quellensteuer][:artist_tickets] = 0
+sums[:doitsch][:guest_tickets] = 0
+sums[:doitsch][:artist_tickets] = 0
+
+events.each do |event|
+ bookings = Booking.where(event: event)
+ sums = {}
+ sums[:quellensteuer] = {}
+ sums[:doitsch] = {}
+ sums[:quellensteuer][:guest_tickets] = 0
+ sums[:quellensteuer][:artist_tickets] = 0
+ sums[:doitsch][:guest_tickets] = 0
+ sums[:doitsch][:artist_tickets] = 0
+ bookings.each do |booking|
+ ti = booking.task_instance("Quellensteuer")
+ #ap "============================================="
+ #ap "Booking #{booking.id} - #{booking.artist.name}"
+ has_quellensteuer = (ti.present? && (ti.is_state?("teilweise gemeldet") || ti.is_state?("komplett gemeldet")))
+ cat = has_quellensteuer ? :quellensteuer : :doitsch
+ booking.admissions.each do |adm|
+ # ap "Admission ##{adm.id}"
+ if adm.canceled?
+ # ap "cancelled"
+ next
+ end
+ # Nur die eingecheckten (Gäste)
+ # Alle angelegten, nicht stornierten (Artists)
+ if adm.guest_admission?
+ if adm.checked_in? # Guest & Checked in
+ sums[cat][:guest_tickets] += 1
+ end
+ else # Artist
+ sums[cat][:artist_tickets] += 1
+ end
+ end
+ end
+ ap event.name
+ ap sums
+end
diff --git a/spec/files/custom_codes.yml b/spec/files/custom_codes.yml
new file mode 100644
index 0000000..5e9020f
--- /dev/null
+++ b/spec/files/custom_codes.yml
@@ -0,0 +1,8 @@
+# BNN Codes
+category:
+ "4000": "Schuhe"
+additional:
+ "additional": "value"
+indeling:
+ 11: Test Indeling
+ 111: Test Subindeling
\ No newline at end of file
diff --git a/spec/files/foodsoft/foodsoft_flawless.csv b/spec/files/foodsoft/foodsoft_flawless.csv
new file mode 100644
index 0000000..a9a94c2
--- /dev/null
+++ b/spec/files/foodsoft/foodsoft_flawless.csv
@@ -0,0 +1,3 @@
+status;number;name;note;manufacturer;origin;unit ;clear price;tax;deposit;unit quantity;scale quantity;scale price;category
+;1;product;bio;someone;eu;1 kg;1.23;6;0;10;;;coolstuff
+;12;other product;bio;someone;eu;2 kg;3.45;6;0;10;;;coolstuff
\ No newline at end of file
diff --git a/spec/files/foodsoft/foodsoft_generate_order_number.csv b/spec/files/foodsoft/foodsoft_generate_order_number.csv
new file mode 100644
index 0000000..a50dde3
--- /dev/null
+++ b/spec/files/foodsoft/foodsoft_generate_order_number.csv
@@ -0,0 +1,3 @@
+status;number;name;note;manufacturer;origin;unit ;clear price;tax;deposit;unit quantity;scale quantity;scale price;category
+;;product;bio;someone;eu;1 kg;1.23;6;0;10;;;coolstuff
+;;other product;bio;someone;eu;2 kg;3.45;6;0;10;;;coolstuff
\ No newline at end of file
diff --git a/spec/files/foodsoft/foodsoft_missing_entries.csv b/spec/files/foodsoft/foodsoft_missing_entries.csv
new file mode 100644
index 0000000..560c11a
--- /dev/null
+++ b/spec/files/foodsoft/foodsoft_missing_entries.csv
@@ -0,0 +1,2 @@
+status;number;name;note;manufacturer;origin;unit ;clear price;tax;deposit;unit quantity;scale quantity;scale price;category
+;12;product;bio;;eu;1 kg;1.23;;0;10;;;coolstuff
\ No newline at end of file
diff --git a/spec/files/odin/odin_flawless.xml b/spec/files/odin/odin_flawless.xml
new file mode 100644
index 0000000..5b5a28f
--- /dev/null
+++ b/spec/files/odin/odin_flawless.xml
@@ -0,0 +1,75 @@
+
+
+
+1039
+1.08
+Estafette Associatie C.V.
+Geldermalsen
+
+
+8719325207668
+nucli rose
+Nucli rose
+
+0
+0
+0
+750
+g
+Stuk
+0
+NELEMAN
+Biologisch
+
+
+ES
+
+21
+1017515
+0109
+6
+Actief
+druiven*
+0
+0
+2
+2
+0
+0
+0
+2
+2
+0
+2
+0
+2
+0
+2
+2
+2
+2
+1
+0
+2
+0
+2
+2
+
+
+
+0
+0
+0
+0
+1
+
+2
+0
+
+adviesprijs
+2022-08-18
+4.52
+7.95
+
+
+
\ No newline at end of file
diff --git a/spec/files/odin/odin_flawless_custom_category.xml b/spec/files/odin/odin_flawless_custom_category.xml
new file mode 100644
index 0000000..460da24
--- /dev/null
+++ b/spec/files/odin/odin_flawless_custom_category.xml
@@ -0,0 +1,77 @@
+
+
+
+1039
+1.08
+Estafette Associatie C.V.
+Geldermalsen
+
+
+8719325207668
+nucli rose
+Nucli rose
+
+0
+0
+0
+750
+g
+Stuk
+0
+NELEMAN
+Biologisch
+
+
+ES
+
+21
+1017515
+0109
+11
+111
+6
+Actief
+druiven*
+0
+0
+2
+2
+0
+0
+0
+2
+2
+0
+2
+0
+2
+0
+2
+2
+2
+2
+1
+0
+2
+0
+2
+2
+
+
+
+0
+0
+0
+0
+1
+
+2
+0
+
+adviesprijs
+2022-08-18
+4.52
+7.95
+
+
+
\ No newline at end of file
diff --git a/spec/files/odin/odin_missing_entries.xml b/spec/files/odin/odin_missing_entries.xml
new file mode 100644
index 0000000..5089b91
--- /dev/null
+++ b/spec/files/odin/odin_missing_entries.xml
@@ -0,0 +1,75 @@
+
+
+
+1039
+1.08
+Estafette Associatie C.V.
+Geldermalsen
+
+
+8719325207668
+nucli rose
+Nucli rose
+
+0
+0
+0
+750
+
+Stuk
+0
+
+Biologisch
+
+
+ES
+
+21
+1017515
+0109
+6
+Non Actief
+druiven*
+0
+0
+2
+2
+0
+0
+0
+2
+2
+0
+2
+0
+2
+0
+2
+2
+2
+2
+1
+0
+2
+0
+2
+2
+
+
+
+0
+0
+0
+0
+1
+
+2
+0
+
+adviesprijs
+2022-08-18
+4.52
+7.95
+
+
+
\ No newline at end of file
diff --git a/spec/files/odin/odin_missing_order_number.xml b/spec/files/odin/odin_missing_order_number.xml
new file mode 100644
index 0000000..d43a943
--- /dev/null
+++ b/spec/files/odin/odin_missing_order_number.xml
@@ -0,0 +1,75 @@
+
+
+
+1039
+1.08
+Estafette Associatie C.V.
+Geldermalsen
+
+
+8719325207668
+nucli rose
+Nucli rose
+
+0
+0
+0
+750
+g
+Stuk
+0
+NELEMAN
+Biologisch
+
+
+ES
+
+21
+1017515
+
+6
+Actief
+druiven*
+0
+0
+2
+2
+0
+0
+0
+2
+2
+0
+2
+0
+2
+0
+2
+2
+2
+2
+1
+0
+2
+0
+2
+2
+
+
+
+0
+0
+0
+0
+1
+
+2
+0
+
+adviesprijs
+2022-08-18
+4.52
+7.95
+
+
+
\ No newline at end of file
diff --git a/spec/lib/bioromeo/foodsoft_article_import_bioromeo_spec.rb b/spec/lib/bioromeo/foodsoft_article_import_bioromeo_spec.rb
new file mode 100644
index 0000000..63bd522
--- /dev/null
+++ b/spec/lib/bioromeo/foodsoft_article_import_bioromeo_spec.rb
@@ -0,0 +1,24 @@
+require 'spec_helper'
+require_relative '../../../lib/foodsoft_article_import'
+
+describe FoodsoftArticleImport do
+
+ files_path = File.expand_path '../../files', __dir__
+ bioromeo_files_path = File.join(files_path, 'bioromeo')
+
+ dummy_article = {:order_number=>"1", :name => "Wilde aardappels",:article_category => "Aardappels \"nieuwe oogst\"", :deposit => 0, :manufacturer => nil, :origin => "Noordoostpolder, NL", :price => 5.0, :tax => 6, :unit => "5kg", :unit_quantity => 1, :note => "Skal 1234; 123456; Demeter 123456; (Kopervrij)"}
+
+
+ empty = {}
+
+ context "bioromeo" do
+ it 'parses file correctly with type parameter bioromeo' do
+ FoodsoftArticleImport.parse(File.open(File.join(bioromeo_files_path, 'bioromeo_flawless.csv')), type: 'bioromeo') do |new_attrs, status, line|
+ if new_attrs==nil
+ next
+ end
+ expect(new_attrs).to eq dummy_article
+ end
+ end
+ end
+end
diff --git a/spec/lib/bnn/foodsoft_article_import_bnn_spec.rb b/spec/lib/bnn/foodsoft_article_import_bnn_spec.rb
new file mode 100644
index 0000000..54e666d
--- /dev/null
+++ b/spec/lib/bnn/foodsoft_article_import_bnn_spec.rb
@@ -0,0 +1,71 @@
+require 'spec_helper'
+require_relative '../../../lib/foodsoft_article_import'
+
+describe FoodsoftArticleImport do
+
+ files_path = File.expand_path '../../files', __dir__
+ bnn_files_path = File.join(files_path, 'bnn')
+
+ dummy_article = { name: 'Greek Dressing - Kräuter Mix', order_number: '64721', note: 'Oregano, Basilikum und Minze',
+ manufacturer: 'Medousa, Griechenland Importe', origin: 'GR', article_category: 'Kräutermischungen', unit: '35g', price: '2,89', tax: 7.0, unit_quantity: '6'}
+
+ article = dummy_article.merge({scale_price: "3", scale_quantity: "2", deposit: 0.08})
+ article_special = article.merge(note: 'Sonderpreis: 2,89 von 20230101 bis 20230201')
+
+ article_2 = dummy_article.merge({manufacturer: nil, article_category: nil})
+
+ article_custom_code = article.merge(article_category: "Schuhe")
+
+ empty = {}
+
+ context 'bnn' do
+ it 'parses bnn file correctly without type parameter' do
+ FoodsoftArticleImport.parse(File.open(File.join(bnn_files_path, 'bnn_flawless.BNN'))) do |new_attrs, status, line|
+ expect(new_attrs).to eq article
+ expect(status).to eq :outlisted
+ end
+ end
+ it 'parses file correctly with type parameter' do
+ FoodsoftArticleImport.parse(File.open(File.join(bnn_files_path, 'bnn_flawless.BNN')), type: 'bnn') do |new_attrs, status, line|
+ expect(new_attrs).to eq article
+ expect(status).to eq :outlisted
+ end
+ end
+ it 'raises error wenn wrong type (except dnb_xml) specified' do
+ expect{FoodsoftArticleImport.parse(File.open(File.join(bnn_files_path, 'bnn_flawless.BNN')),type: 'foodsoft')}.to raise_error(RuntimeError)
+ expect{FoodsoftArticleImport.parse(File.open(File.join(bnn_files_path, 'bnn_flawless.BNN')),type: 'bioromeo')}.to raise_error(RuntimeError)
+
+ expect(FoodsoftArticleImport.parse(File.open(File.join(bnn_files_path, 'bnn_flawless.BNN')),type: 'dnb_xml')).to eq []
+ end
+ it 'parses article with special correctly' do
+ FoodsoftArticleImport.parse(File.open(File.join(bnn_files_path, 'bnn_flawless_special.BNN')), type: 'bnn') do |new_attrs, status, line|
+ expect(new_attrs).to eq article_special
+ expect(status).to eq :special
+ end
+ end
+ it 'parses missing entries correctly' do
+ FoodsoftArticleImport.parse(File.open(File.join(bnn_files_path, 'bnn_missing_entries.BNN')), type: 'bnn') do |new_attrs, status, line|
+ expect(new_attrs).to eq article_2
+ expect(status).to eq nil
+ end
+ end
+ it 'skips rows without order_number' do
+ FoodsoftArticleImport.parse(File.open(File.join(bnn_files_path, 'bnn_missing_order_number.BNN')), type: 'bnn') do |new_attrs, status, line|
+ expect(new_attrs).to eq empty
+ end
+ end
+ it 'joins custom_codes file' do
+ custom_file_path = File.join(files_path, 'custom_codes.yml').to_s
+ FoodsoftArticleImport.parse(File.open(File.join(bnn_files_path, 'bnn_flawless_category.BNN')), custom_file_path: custom_file_path, type: 'bnn') do |new_attrs, status, line|
+ expect(new_attrs).to eq article_custom_code
+ end
+ end
+ it 'parses file with different encoding' do
+ #the bnn file is loaded with encoding ibm850. If file is not ibm850 encoded, some characters might look weird
+ FoodsoftArticleImport.parse(File.open(File.join(bnn_files_path, 'bnn_bad_encoding.BNN')), type: 'bnn') do |new_attrs, status, line|
+ expect(new_attrs[:order_number]).to eq("64721")
+ expect(new_attrs[:name]).to eq("Greek Dressing - Kräuter Mix")
+ end
+ end
+ end
+end
diff --git a/spec/lib/foodsoft/foodsoft_article_import_foodsoft_spec.rb b/spec/lib/foodsoft/foodsoft_article_import_foodsoft_spec.rb
new file mode 100644
index 0000000..24d1c27
--- /dev/null
+++ b/spec/lib/foodsoft/foodsoft_article_import_foodsoft_spec.rb
@@ -0,0 +1,57 @@
+require 'spec_helper'
+require_relative '../../../lib/foodsoft_article_import'
+
+describe FoodsoftArticleImport do
+
+ files_path = File.expand_path '../../files', __dir__
+ foodsoft_files_path = File.join(files_path, 'foodsoft')
+
+ dummy_article = {:order_number=>"1", :name=>"product", :note=>"bio", :manufacturer=>"someone", :origin=>"eu", :unit=>"1 kg", :price=>"1.23", :tax=>"6", :unit_quantity=>"10", :scale_quantity=>nil, :scale_price=>nil, :article_category=>"coolstuff", :deposit=>"0"}
+
+
+ dummy_article_2 = {:order_number=>"12", :name=>"other product", :note=>"bio", :manufacturer=>"someone", :origin=>"eu", :unit=>"2 kg", :price=>"3.45", :tax=>"6", :unit_quantity=>"10", :scale_quantity=>nil, :scale_price=>nil, :article_category=>"coolstuff", :deposit=>"0"}
+
+ articles=[dummy_article, dummy_article_2]
+
+ dummy_article_3 = dummy_article.merge({ order_number: ":d8df298"})
+ dummy_article_4 = dummy_article_2.merge({ order_number: ":1f37e39"})
+ articles_number_generated= [dummy_article_3, dummy_article_4]
+ empty = {}
+
+ context "foodsoft" do
+ it 'parses file correctly with type parameter foodsoft' do
+ count =0
+ FoodsoftArticleImport.parse(File.open(File.join(foodsoft_files_path, 'foodsoft_flawless.csv')), type: 'foodsoft') do |new_attrs, status, line|
+ expect(new_attrs).to eq articles[count]
+ expect(status).to eq nil
+ count+=1
+ end
+ end
+ it 'raises error wenn wrong type specified' do
+ expect{FoodsoftArticleImport.parse(File.open(File.join(foodsoft_files_path, 'foodsoft_flawless.csv')),type: 'bioromeo')}.to raise_error(Roo::HeaderRowNotFoundError)
+ expect(FoodsoftArticleImport.parse(File.open(File.join(foodsoft_files_path, 'foodsoft_flawless.csv')),type: 'odin')).to eq []
+
+ expect(FoodsoftArticleImport.parse(File.open(File.join(foodsoft_files_path, 'foodsoft_flawless.csv')),type: 'bnn')).to eq []
+ end
+ it 'parses missing entries correctly' do
+ FoodsoftArticleImport.parse(File.open(File.join(foodsoft_files_path, 'foodsoft_missing_entries.csv')), type: 'foodsoft') do |new_attrs, status, line|
+ expect(status).to eq 'Error: unit, price and tax must be entered'
+ expect(new_attrs[:unit]).to eq "1 kg"
+ expect(new_attrs[:manufacturer]).to eq nil
+ end
+ end
+ it 'generates order numbers for articles without order number' do
+ count=0
+ FoodsoftArticleImport.parse(File.open(File.join(foodsoft_files_path, 'foodsoft_generate_order_number.csv')), type: 'foodsoft') do |new_attrs, status, line|
+ expect(new_attrs).to eq articles_number_generated[count]
+ count+=1
+ end
+ end
+ xit 'joins custom_codes file' do
+ custom_file_path = File.join(files_path, 'custom_codes.yml').to_s
+ FoodsoftArticleImport.parse(File.open(File.join(foodsoft_files_path, 'foodsoft_flawless_custom_category.csv')), custom_file_path: custom_file_path, type: 'foodsoft') do |new_attrs, status, line|
+ expect(new_attrs[:article_category]).to eq "Test Indeling - Test Subindeling"
+ end
+ end
+ end
+end
diff --git a/spec/lib/odin/foodsoft_article_import_odin_spec.rb b/spec/lib/odin/foodsoft_article_import_odin_spec.rb
new file mode 100644
index 0000000..bdac2ae
--- /dev/null
+++ b/spec/lib/odin/foodsoft_article_import_odin_spec.rb
@@ -0,0 +1,67 @@
+require 'spec_helper'
+require_relative '../../../lib/foodsoft_article_import'
+
+describe FoodsoftArticleImport do
+
+ files_path = File.expand_path '../../files', __dir__
+ odin_files_path = File.join(files_path, 'odin')
+
+ dummy_article = {:order_number=>"0109", :name=>"nucli rose", :note=>"Biologisch", :manufacturer=>"NELEMAN", :origin=>"ES", :unit=>"750gr", :price=>"4.52", :unit_quantity=>"6", :tax=>"21", :deposit=>"0", :article_category=>""}
+
+
+ empty = {}
+
+ context "odin/dnb_xml" do
+ it 'parses file correctly with type parameter dnb_xml' do
+ FoodsoftArticleImport.parse(File.open(File.join(odin_files_path, 'odin_flawless.xml')), type: 'dnb_xml') do |new_attrs, status, line|
+ expect(new_attrs).to eq dummy_article
+ expect(status).to eq nil
+ end
+ end
+ it 'parses file correctly with type parameter odin' do
+ FoodsoftArticleImport.parse(File.open(File.join(odin_files_path, 'odin_flawless.xml')), type: 'odin') do |new_attrs, status, line|
+ expect(new_attrs).to eq dummy_article
+ expect(status).to eq nil
+ end
+ end
+ it 'raises error wenn wrong type specified' do
+ expect{FoodsoftArticleImport.parse(File.open(File.join(odin_files_path, 'odin_flawless.xml')),type: 'foodsoft')}.to raise_error(RuntimeError)
+ expect{FoodsoftArticleImport.parse(File.open(File.join(odin_files_path, 'odin_flawless.xml')),type: 'bioromeo')}.to raise_error(RuntimeError)
+
+ expect{FoodsoftArticleImport.parse(File.open(File.join(odin_files_path, 'odin_flawless.xml')),type: 'bnn')}.to raise_error(CSV::MalformedCSVError)
+ end
+ it 'parses missing entries correctly' do
+ FoodsoftArticleImport.parse(File.open(File.join(odin_files_path, 'odin_missing_entries.xml')), type: 'odin') do |new_attrs, status, line|
+ expect(status).to eq :outlisted
+ expect(new_attrs[:unit]).to eq "750st"
+ expect(new_attrs[:manufacturer]).to eq ""
+ end
+ end
+ it 'skips rows without order_number' do
+ FoodsoftArticleImport.parse(File.open(File.join(odin_files_path, 'odin_missing_order_number.xml')), type: 'odin') do |new_attrs, status, line|
+ expect(new_attrs).to eq empty
+ end
+ end
+ it 'joins custom_codes file' do
+ custom_file_path = File.join(files_path, 'custom_codes.yml').to_s
+ FoodsoftArticleImport.parse(File.open(File.join(odin_files_path, 'odin_flawless_custom_category.xml')), custom_file_path: custom_file_path, type: 'odin') do |new_attrs, status, line|
+ expect(new_attrs[:article_category]).to eq "Test Indeling - Test Subindeling"
+ end
+ end
+
+ xit 'parses dummy_article with special correctly' do
+ #TODO: find out whether there are special prices for odin files
+ FoodsoftArticleImport.parse(File.open(File.join(odin_files_path, 'bnn_flawless_special.BNN')), type: 'bnn') do |new_attrs, status, line|
+ expect(new_attrs.manufacturer).to eq nil
+ expect(new_attrs.unit).to eq "750st"
+ end
+ end
+ xit 'parses file with different encoding' do
+ #the bnn file is loaded with encoding ibm850. If file is not ibm850 encoded, some characters might look weird
+ FoodsoftArticleImport.parse(File.open(File.join(odin_files_path, 'bnn_bad_encoding.BNN')), type: 'bnn') do |new_attrs, status, line|
+ expect(new_attrs[:order_number]).to eq("64721")
+ expect(new_attrs[:name]).to eq("Greek Dressing - Kräuter Mix")
+ end
+ end
+ end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..03990c4
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,100 @@
+require 'simplecov'
+SimpleCov.start
+# This file was generated by the `rspec --init` command. Conventionally, all
+# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
+# The generated `.rspec` file contains `--require spec_helper` which will cause
+# this file to always be loaded, without a need to explicitly require it in any
+# files.
+#
+# Given that it is always loaded, you are encouraged to keep this file as
+# light-weight as possible. Requiring heavyweight dependencies from this file
+# will add to the boot time of your test suite on EVERY test run, even for an
+# individual file that may not need all of that loaded. Instead, consider making
+# a separate helper file that requires the additional dependencies and performs
+# the additional setup, and require it from the spec files that actually need
+# it.
+#
+# See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
+RSpec.configure do |config|
+ # rspec-expectations config goes here. You can use an alternate
+ # assertion/expectation library such as wrong or the stdlib/minitest
+ # assertions if you prefer.
+ config.expect_with :rspec do |expectations|
+ # This option will default to `true` in RSpec 4. It makes the `description`
+ # and `failure_message` of custom matchers include text for helper methods
+ # defined using `chain`, e.g.:
+ # be_bigger_than(2).and_smaller_than(4).description
+ # # => "be bigger than 2 and smaller than 4"
+ # ...rather than:
+ # # => "be bigger than 2"
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
+ end
+
+ # rspec-mocks config goes here. You can use an alternate test double
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
+ config.mock_with :rspec do |mocks|
+ # Prevents you from mocking or stubbing a method that does not exist on
+ # a real object. This is generally recommended, and will default to
+ # `true` in RSpec 4.
+ mocks.verify_partial_doubles = true
+ end
+
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
+ # have no way to turn it off -- the option exists only for backwards
+ # compatibility in RSpec 3). It causes shared context metadata to be
+ # inherited by the metadata hash of host groups and examples, rather than
+ # triggering implicit auto-inclusion in groups with matching metadata.
+ config.shared_context_metadata_behavior = :apply_to_host_groups
+
+# The settings below are suggested to provide a good initial experience
+# with RSpec, but feel free to customize to your heart's content.
+=begin
+ # This allows you to limit a spec run to individual examples or groups
+ # you care about by tagging them with `:focus` metadata. When nothing
+ # is tagged with `:focus`, all examples get run. RSpec also provides
+ # aliases for `it`, `describe`, and `context` that include `:focus`
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
+ config.filter_run_when_matching :focus
+
+ # Allows RSpec to persist some state between runs in order to support
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
+ # you configure your source control system to ignore this file.
+ config.example_status_persistence_file_path = "spec/examples.txt"
+
+ # Limits the available syntax to the non-monkey patched syntax that is
+ # recommended. For more details, see:
+ # https://relishapp.com/rspec/rspec-core/docs/configuration/zero-monkey-patching-mode
+ config.disable_monkey_patching!
+
+ # This setting enables warnings. It's recommended, but in some cases may
+ # be too noisy due to issues in dependencies.
+ config.warnings = true
+
+ # Many RSpec users commonly either run the entire suite or an individual
+ # file, and it's useful to allow more verbose output when running an
+ # individual spec file.
+ if config.files_to_run.one?
+ # Use the documentation formatter for detailed output,
+ # unless a formatter has already been configured
+ # (e.g. via a command-line flag).
+ config.default_formatter = "doc"
+ end
+
+ # Print the 10 slowest examples and example groups at the
+ # end of the spec run, to help surface which specs are running
+ # particularly slow.
+ config.profile_examples = 10
+
+ # Run specs in random order to surface order dependencies. If you find an
+ # order dependency and want to debug it, you can fix the order by providing
+ # the seed, which is printed after each run.
+ # --seed 1234
+ config.order = :random
+
+ # Seed global randomization in this process using the `--seed` CLI option.
+ # Setting this allows you to use `--seed` to deterministically reproduce
+ # test failures related to randomization by passing the same `--seed` value
+ # as the one that triggered the failure.
+ Kernel.srand config.seed
+=end
+end