efo_nelfo 0.0.7 → 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.
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