efo_nelfo 0.0.7 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 339fc7d74621d26713c98008d2060452753e3998
4
- data.tar.gz: 0020dbe4e5129c8890165cf01bae901bcd1373ee
3
+ metadata.gz: 5c4b4dce00c7c566c8cf0866f02cc7560a5bd3c4
4
+ data.tar.gz: 1e1bcc1e132c347c94d82ccc265bedc4cb8b4407
5
5
  SHA512:
6
- metadata.gz: 058e13eeccaaf4657c8f58711c3d278ef5190afb1a96b470ed3e38df8242e1b80ddc9ef8482be084012f2e758e1bf27e8270d044808e7c1761cb5b0de20ed873
7
- data.tar.gz: 2a755cf54f5d2481297513748eb14a944412364ecc2274ff4be40a75b2ed564fa522baff9753045fc27b1f566a7a5265c02e0b65819671796919b9c699579d09
6
+ metadata.gz: fe36c958173bbfc4ac87379b730d73c12721af0d0663f5bffdf527ac6b7aeffa2740eb78fa066764a62d60d89a23d3a933abf98f1d07f1496234fc6465a25cee
7
+ data.tar.gz: 96743647440ed7561e5b9df4670a50fa98e8e7a78c00cf9c452a25200c4f6e5880e5cf0adfd17c237d43f8a1455174a109ae4d591816817ea01270d4ab571298
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ /bin/
data/Guardfile CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  guard 'minitest' do
5
5
  watch(%r|^spec/(.*)_spec\.rb|)
6
- watch(%r|^lib/(.*)([^/]+)\.rb|) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
6
+ watch(%r{^lib/(.*)\.rb}) { "spec" }
7
+ #watch(%r|^lib/(.*)([^/]+)\.rb|) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
7
8
  watch(%r|^spec/spec_helper\.rb|) { "spec" }
8
9
  end
data/efo_nelfo.gemspec CHANGED
@@ -24,4 +24,5 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "guard-minitest"
25
25
  spec.add_development_dependency "rb-fsevent"
26
26
  spec.add_development_dependency "terminal-notifier-guard"
27
+ spec.add_development_dependency "turn"
27
28
  end
@@ -0,0 +1,44 @@
1
+ require 'forwardable'
2
+
3
+ module EfoNelfo
4
+
5
+ class Collection
6
+ include Enumerable
7
+ extend Forwardable
8
+
9
+ attr_reader :owner, :post_type
10
+
11
+ def_delegators :@list, :[], :each, :last, :size, :empty?
12
+
13
+ def initialize(owner, post_type)
14
+ @owner = owner
15
+ @post_type = post_type
16
+ @list = []
17
+ end
18
+
19
+ def <<(obj)
20
+ obj = post_type_class.new(obj) if obj.is_a? Hash
21
+ raise EfoNelfo::InvalidPostType if obj.nil? || (obj.is_a?(EfoNelfo::PostType) && obj.post_type != post_type)
22
+
23
+ # Set the index if the post has an index property
24
+ obj.index = size + 1 if obj.has_property?(:index)
25
+
26
+ @list << obj
27
+ end
28
+
29
+ def to_a
30
+ map(&:to_a).flatten(1)
31
+ end
32
+
33
+ private
34
+ attr_reader :list
35
+
36
+ def post_type_class
37
+ Kernel.const_get("EfoNelfo::V#{owner.class.version_from_class}::#{post_type}")
38
+ end
39
+
40
+
41
+ end
42
+
43
+ end
44
+
@@ -1,4 +1,6 @@
1
1
  module EfoNelfo
2
- class UnsupportedPostType < StandardError; end
3
- class DuplicateProperty < StandardError; end
2
+ InvalidPostType = Class.new(StandardError)
3
+ UnsupportedPostType = Class.new(StandardError)
4
+ DuplicateProperty = Class.new(StandardError)
5
+ UnknownPropertyOption = Class.new(StandardError)
4
6
  end
@@ -0,0 +1,70 @@
1
+ module EfoNelfo
2
+
3
+ module HasMany
4
+
5
+ def self.included(base)
6
+ base.send :extend, ClassMethods
7
+ end
8
+
9
+ def find_association(post_type)
10
+ send self.class.association(post_type) if has_association?(post_type)
11
+ end
12
+
13
+ def has_association?(post_type)
14
+ !self.class.association(post_type).nil?
15
+ end
16
+
17
+ def associations
18
+ self.class.associations
19
+ end
20
+
21
+ def add(post)
22
+ find_association(post) << post
23
+ end
24
+
25
+ def to_a
26
+ [ super ] + associations_array
27
+ end
28
+
29
+ protected
30
+
31
+ def associations_array
32
+ if associations
33
+ associations.keys.map { |name| find_association(name).to_a }.reject(&:empty?).flatten(1)
34
+ else
35
+ []
36
+ end
37
+ end
38
+
39
+ module ClassMethods
40
+
41
+ def has_many(name, options)
42
+ post_type = options[:post_type]
43
+
44
+ @associations ||= {}
45
+ @associations[post_type] = name
46
+
47
+ define_method name do
48
+ instance_variable_get("@#{name}") || instance_variable_set("@#{name}", EfoNelfo::Collection.new(self, post_type))
49
+ end
50
+
51
+ define_method "#{name}=" do |values|
52
+ instance_variable_set "@#{name}", EfoNelfo::Collection.new(self, post_type)
53
+ values.each { |item| instance_variable_get("@#{name}") << item } if values
54
+ end
55
+
56
+ end
57
+
58
+ def associations
59
+ @associations
60
+ end
61
+
62
+ def association(post_type)
63
+ type = post_type.is_a?(EfoNelfo::PostType) ? post_type.post_type : post_type.to_s.upcase
64
+ @associations[type]
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -0,0 +1,30 @@
1
+ module EfoNelfo
2
+ module PostHeadType
3
+ attr_accessor :source
4
+
5
+ def self.included(base)
6
+ base.send :property, :post_type, alias: :PostType, limit: 2, default: base.post_type
7
+ base.send :property, :format, alias: :Format, limit: 8, default: 'EFONELFO'
8
+ base.send :property, :version, alias: :Versjon, limit: 3, default: base.version
9
+ end
10
+
11
+ def add(post_type)
12
+ if has_association? post_type
13
+ find_association(post_type) << post_type
14
+ else
15
+ if lines.any?
16
+ lines.last.find_association(post_type) << post_type
17
+ end
18
+ end
19
+ end
20
+
21
+ def to_csv
22
+ CSV.generate EfoNelfo::Reader::CSV::CSV_OPTIONS do |csv|
23
+ to_a.each do |row|
24
+ csv << row unless row.empty?
25
+ end
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -2,48 +2,51 @@ module EfoNelfo
2
2
 
3
3
  class PostType
4
4
  include EfoNelfo::Property
5
-
6
- attr_reader :post_type
7
-
8
- @modules = []
5
+ include EfoNelfo::HasMany
9
6
 
10
7
  class << self
11
- def inherited(klass)
12
- @modules << klass
13
- end
14
8
 
15
- def for(type, version=nil)
16
- @modules.select { |mod| mod.can_parse?(type, version) }.first
9
+ def for(type, version)
10
+ klass = "EfoNelfo::V#{version_to_namespace(version)}::#{type}"
11
+ const_get(klass) rescue nil
17
12
  end
18
13
 
19
- def can_parse?(post_type, check_version=nil)
20
- if check_version
21
- self::POST_TYPES.keys.include?(post_type) && check_version == version
22
- else
23
- self::POST_TYPES.keys.include?(post_type)
24
- end
14
+ # Converts version to module version name
15
+ # Example: version_to_namespace("4.2") # => "42"
16
+ def version_to_namespace(version)
17
+ version.gsub('.', '')
25
18
  end
26
19
 
27
20
  # Extracts version number from class namespace.
28
21
  # Example: EfoNelfo::V41::Some::Class.version # => "4.1"
29
22
  def version
30
- (self.to_s.match(/::V(?<version>\d+)::/)[:version].to_f / 10).to_s
23
+ (version_from_class.to_f / 10).to_s
24
+ end
25
+
26
+ def version_from_class
27
+ self.to_s.match(/::V(?<version>\d+)::/)[:version]
28
+ end
29
+
30
+ def post_type
31
+ name.split(/::/).last
32
+ end
33
+
34
+ def from(hash)
35
+ self.for(hash[:post_type], hash[:version]).new(hash)
31
36
  end
32
37
 
33
38
  end
34
39
 
35
40
  def initialize(*args)
36
- initialize_attributes *args
37
- @post_type = self.class::POST_TYPES.keys.first
38
- @version = self.class.version
41
+ initialize_attributes(*args)
39
42
  end
40
43
 
41
- # This is for adding posttypes
42
- def add(something)
44
+ def post_type
45
+ self.class.post_type
43
46
  end
44
47
 
45
- def post_type_human
46
- self.class::POST_TYPES[post_type]
48
+ def version
49
+ self.class.version
47
50
  end
48
51
 
49
52
  end
@@ -1,12 +1,19 @@
1
1
  module EfoNelfo
2
2
 
3
3
  module Property
4
- include EfoNelfo::AttributeAssignment
5
4
 
6
5
  def self.included(base)
7
6
  base.send :extend, ClassMethods
8
7
  end
9
8
 
9
+ def initialize_attributes(*args)
10
+ if args && args.first.is_a?(Hash)
11
+ args.first.each do |attr, value|
12
+ send "#{attr}=", value
13
+ end
14
+ end
15
+ end
16
+
10
17
  def attributes
11
18
  @attributes ||= initialize_default_attributes
12
19
  end
@@ -15,6 +22,10 @@ module EfoNelfo
15
22
  self.class.properties
16
23
  end
17
24
 
25
+ def has_property?(property)
26
+ properties.include? property
27
+ end
28
+
18
29
  def to_a
19
30
  properties.keys.map { |prop| formatted_for_csv(prop) }
20
31
  end
@@ -76,6 +87,7 @@ module EfoNelfo
76
87
  # - alias Norwegian alias name for the attribute
77
88
  #
78
89
  def property(name, options={})
90
+
79
91
  options = {
80
92
  type: :string,
81
93
  required: false,
@@ -83,6 +95,11 @@ module EfoNelfo
83
95
 
84
96
  name = name.to_sym
85
97
 
98
+ # ensure all options are valid
99
+ valid_options = [:type, :required, :limit, :read_only, :alias, :default]
100
+ invalid_options = options.keys - valid_options
101
+ raise EfoNelfo::UnknownPropertyOption.new("Invalid option for #{name}: #{invalid_options.join(',')}") if invalid_options.any?
102
+
86
103
  # Store property info in @properties
87
104
  raise EfoNelfo::DuplicateProperty if properties.has_key?(name)
88
105
  properties[name] = options
@@ -33,7 +33,7 @@ module EfoNelfo
33
33
  # Read rest of the file and add them to the head
34
34
  csv.each do |row|
35
35
  # Find the correct posttype module for given posttype and version
36
- klass = EfoNelfo::PostType.for row[0]
36
+ klass = EfoNelfo::PostType.for row[0], head.version
37
37
  next if klass.nil?
38
38
 
39
39
  line = initialize_object_with_properties klass, row
@@ -1,19 +1,9 @@
1
- # encoding: utf-8
2
1
  module EfoNelfo
3
2
  module V40
4
- class Order < EfoNelfo::PostType
5
- POST_TYPES = {
6
- 'BH' => 'Bestilling Hodepost',
7
- 'IH' => 'Forespørsel Hodepost'
8
- }
9
-
10
- attr_reader :lines
11
- attr_accessor :source
3
+ class BH < EfoNelfo::PostType
4
+ include PostHeadType
12
5
 
13
6
  # It's important to list the property in the same order as specified in the specs
14
- property :post_type, alias: :PostType, limit: 2, default: 'BH'
15
- property :format, alias: :Format, limit: 8, default: 'EFONELFO'
16
- property :version, alias: :Versjon, limit: 3, default: version
17
7
  property :seller_id, alias: :SelgersId, limit: 14
18
8
  property :buyer_id, alias: :KjøpersId, limit: 14, required: true
19
9
  property :order_number, alias: :BestNr, limit: 10, required: true
@@ -60,40 +50,18 @@ module EfoNelfo
60
50
  property :seller_office, alias: :SPostSted, limit: 35
61
51
  property :seller_country, alias: :SLandK, limit: 2
62
52
 
63
- def initialize(*args)
64
- @lines = EfoNelfo::Array.new
65
- super
66
- end
53
+ has_many :lines, post_type: "BL"
67
54
 
68
- def add(post_type)
69
- case
70
- when post_type.is_a?(Order::Line)
71
- add_order_line(post_type)
72
- when post_type.is_a?(Order::Text)
73
- add_text_to_order_line(post_type)
74
- when post_type.is_a?(Hash)
75
- add_order_line(EfoNelfo::V40::Order::Line.new(post_type))
76
- end
77
- end
78
-
79
- def lines=(values)
80
- @lines = EfoNelfo::Array.new
81
- values.each do |item|
82
- add item
83
- end
84
- end
85
-
86
- def to_a
87
- [ super ] + lines.to_a
88
- end
89
-
90
- def to_csv
91
- CSV.generate EfoNelfo::Reader::CSV::CSV_OPTIONS do |csv|
92
- to_a.each do |row|
93
- csv << row unless row.empty?
94
- end
95
- end
96
- end
55
+ # def add(post_type)
56
+ # case
57
+ # when post_type.is_a?(BL)
58
+ # add_order_line(post_type)
59
+ # when post_type.is_a?(BT)
60
+ # add_text_to_order_line(post_type)
61
+ # when post_type.is_a?(Hash)
62
+ # add_order_line(EfoNelfo::V40::BL.new(post_type))
63
+ # end
64
+ # end
97
65
 
98
66
  private
99
67
 
@@ -0,0 +1,30 @@
1
+ module EfoNelfo
2
+ module V40
3
+ class BL < EfoNelfo::PostType
4
+
5
+ # It's important to list the property in the same order as specified in the specs
6
+ property :post_type, alias: :PostType, limit: 2, default: post_type, required: true
7
+ property :index, alias: :LinjeNr, limit: 4, type: :integer
8
+ property :order_number, alias: :BestNr, limit: 10, required: true
9
+ property :item_type, alias: :VareMrk, limit: 1, required: true, type: :integer
10
+ property :item_number, alias: :VareNr, limit: 14, required: true
11
+ property :item_name, alias: :VaBetg, limit: 30, required: true
12
+ property :item_description, alias: :VaBetg2, limit: 30
13
+ property :item_count, alias: :Ant, limit: 9, required: true, type: :integer
14
+ property :price_unit, alias: :PrisEnhet, limit: 3, required: true
15
+ property :buyer_item_number, alias: :KVareNr, limit: 25
16
+ property :delivery_date, alias: :LevDato, type: :date
17
+ property :buyer_ref, alias: :KjøpersRef, limit: 25
18
+ property :splitable, alias: :DelLev, type: :boolean, default: true
19
+ property :replacable, alias: :AltKode, type: :boolean, default: true
20
+
21
+ has_many :text, post_type: "BT"
22
+
23
+ def format_item_count
24
+ item_count ? item_count * 100 : nil
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ module EfoNelfo
2
+ module V40
3
+ class BT < EfoNelfo::PostType
4
+
5
+ # It's important to list the property in the same order as specified in the specs
6
+ property :post_type, alias: :PostType, limit: 2, default: post_type, required: true
7
+ property :text, alias: :FriTekst, limit: 30
8
+
9
+ def to_s
10
+ text
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module EfoNelfo
2
+ module V40
3
+ class VA < PostType
4
+ property :post_type, alias: :PostType, limit: 2, required: true, default: post_type
5
+ property :product_type, alias: :VareMrk, limit: 1, type: :integer, required: true
6
+ property :product_number, alias: :VareNr, limit: 14, required: true
7
+ property :type, alias: :VaType, limit: 1, required: true
8
+ property :sales_package, alias: :SalgsPakning, limit: 9, type: :integer
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ module EfoNelfo
2
+ module V40
3
+ class VH < EfoNelfo::PostType
4
+ include PostHeadType
5
+
6
+ property :seller_id, alias: :SelgersId, limit: 14, required: true
7
+ property :buyer_id, alias: :KjøpersId, limit: 14
8
+ property :customer_id, alias: :KundeNr, limit: 10
9
+ property :from_date, alias: :FraDato, limit: 8, type: :date
10
+ property :to_date, alias: :TilDato, limit: 8, type: :date
11
+ property :currency, alias: :Valuta, limit: 3, required: true
12
+ property :contract_id, alias: :AvtaleId, limit: 10
13
+ property :seller_name, alias: :SFirmaNavn, limit: 35, required: true
14
+ property :seller_address1, alias: :SAdr1, limit: 35
15
+ property :seller_address2, alias: :SAdr2, limit: 35
16
+ property :seller_zip, alias: :SPostNr, limit: 9, required: true
17
+ property :seller_office, alias: :SPostSted, limit: 35, required: true
18
+ property :seller_country, alias: :SLandK, limit: 2
19
+ property :price_type, alias: :PrisType, limit: 1
20
+
21
+ has_many :lines, post_type: 'VL'
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,34 @@
1
+ module EfoNelfo
2
+ module V40
3
+ class VL < EfoNelfo::PostType
4
+ property :post_type, alias: :PostType, limit: 2, default: post_type, required: true
5
+ property :product_type, alias: :VareMrk, limit: 1, type: :integer, required: true
6
+ property :product_number, alias: :VareNr, limit: 14, required: true
7
+ property :name, alias: :VaBetg, limit: 30, required: true
8
+ property :description, alias: :VaBetg2, limit: 30
9
+ property :unit, alias: :MåleEnhet, limit: 1, type: :integer, required: true
10
+ property :price_unit, alias: :PrisEnhet, limit: 3, required: true
11
+ property :price_unit_desc, alias: :PrisEnhetTxt, limit: 8
12
+ property :price, alias: :Pris, limit: 10, type: :integer, required: true
13
+ property :amount, alias: :Mengde, limit: 9, type: :integer, required: true
14
+ property :price_date, alias: :PrisDato, limit: 8, type: :date, required: true
15
+ property :status, alias: :Status, limit: 1, type: :integer, required: true
16
+ property :block_number, alias: :BlokkNummer, limit: 6, type: :integer
17
+ property :discount_group, alias: :RabattGruppe, limit: 14
18
+ property :fabrication, alias: :Fabrikat, limit: 10
19
+ property :type, alias: :Type, limit: 10
20
+ property :stocked, alias: :Lagerført, type: :boolean
21
+ property :sales_package, alias: :SalgsPakning, limit: 9, type: :integer
22
+ property :discount, alias: :Rabatt, limit: 4, type: :integer
23
+ property :price_type, alias: :Pristype, limit: 1
24
+
25
+ has_many :info, post_type: "VX"
26
+ has_many :alternatives, post_type: "VA"
27
+
28
+ def nrf_id
29
+ product_type == 4 ? product_number : nil
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ module EfoNelfo
2
+ module V40
3
+ class VX < EfoNelfo::PostType
4
+ property :post_type, alias: :PostType, limit: 2, default: post_type
5
+ property :field, alias: :FeltId, limit: 10, required: true
6
+ property :value, alias: :Verdi, limit: 70, required: true
7
+ end
8
+ end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module EfoNelfo
2
- VERSION = "0.0.7"
2
+ VERSION = "1.0.0"
3
3
  end
data/lib/efo_nelfo.rb CHANGED
@@ -3,15 +3,20 @@
3
3
  # Common stuff
4
4
  require 'efo_nelfo/version'
5
5
  require 'efo_nelfo/errors'
6
- require 'efo_nelfo/array'
7
- require 'efo_nelfo/attribute_assignment'
8
6
  require 'efo_nelfo/property'
7
+ require 'efo_nelfo/collection'
8
+ require 'efo_nelfo/has_many'
9
9
  require 'efo_nelfo/post_type'
10
+ require 'efo_nelfo/post_head_type'
10
11
 
11
12
  # EfoNelfo v4.0 modules
12
- require 'efo_nelfo/v40/order/order'
13
- require 'efo_nelfo/v40/order/line'
14
- require 'efo_nelfo/v40/order/text'
13
+ require 'efo_nelfo/v40/bh'
14
+ require 'efo_nelfo/v40/bl'
15
+ require 'efo_nelfo/v40/bt'
16
+ require 'efo_nelfo/v40/vh'
17
+ require 'efo_nelfo/v40/vl'
18
+ require 'efo_nelfo/v40/vx'
19
+ require 'efo_nelfo/v40/va'
15
20
 
16
21
  # Reader modules (import)
17
22
  require 'efo_nelfo/reader/csv'
@@ -30,6 +35,4 @@ module EfoNelfo
30
35
 
31
36
  end
32
37
 
33
-
34
38
  end
35
-
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ describe EfoNelfo::Collection do
4
+ Owner = Class.new do
5
+ def self.version_from_class
6
+ '21'
7
+ end
8
+ end
9
+
10
+ let(:owner) { Owner.new }
11
+ let(:array) { EfoNelfo::Collection.new owner, "BT" }
12
+
13
+ it "accepts owner and post_type arguments" do
14
+ array.owner.must_equal owner
15
+ array.post_type.must_equal "BT"
16
+ end
17
+
18
+ describe "<<" do
19
+ module EfoNelfo
20
+ module V21
21
+ class MyType < EfoNelfo::PostType
22
+ property :whatever
23
+ property :version
24
+ end
25
+
26
+ class BT < EfoNelfo::PostType
27
+ property :post_type
28
+ property :whatever
29
+ property :version
30
+ end
31
+ end
32
+ end
33
+
34
+ describe "passing a hash" do
35
+ let(:hash) {
36
+ { post_type: "BT", version: "2.1", whatever: 'blah' }
37
+ }
38
+
39
+ it "accepts a valid hash" do
40
+ array << hash
41
+ array.size.must_equal 1
42
+ end
43
+
44
+ it "converts the hash into a post type" do
45
+ array << hash
46
+ array[0].must_be_instance_of EfoNelfo::V21::BT
47
+ array[0].whatever.must_equal 'blah'
48
+ end
49
+
50
+ end
51
+
52
+ describe "passing a PostType object" do
53
+ let(:obj) { EfoNelfo::V21::MyType.new }
54
+
55
+ it "accepts a valid posttype" do
56
+ def obj.post_type; 'BT'; end
57
+ array << obj
58
+ array.must_include obj
59
+ end
60
+
61
+ it "raises an error if the object being added is of wrong type" do
62
+ def obj.post_type; 'BH'; end
63
+ lambda { array << obj }.must_raise(EfoNelfo::InvalidPostType)
64
+ end
65
+ end
66
+ end
67
+
68
+ end