sapoci 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ # 0.1.4, release 2011-07-14
2
+
3
+ * Add various before_type_cast methods
4
+
5
+ # 0.1.3, release 2011-07-14
6
+
7
+ * Ignore whitespace on numeric fields
8
+
9
+ # 0.1.2, release 2011-07-05
10
+
11
+ * Use Nokogiri 1.5.0
12
+
13
+ # 0.1.1, release 2011-04-30
14
+
15
+ * Removed version from sources and put it into gemspec only
16
+
17
+ # 0.1.0, released 2011-04-29
18
+
19
+ * Added a gemspec
20
+ * Initial release on GitHub
21
+
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2007-2011 Oliver Eilhard
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
@@ -0,0 +1,14 @@
1
+ # SAP-OCI
2
+
3
+ ## Description
4
+
5
+ Ruby library and Rails plugin for punchout via SAP OCI protocol.
6
+
7
+ ## Installation
8
+
9
+ $ gem install sapoci
10
+
11
+ ## License
12
+
13
+ Released under the MIT License. See the LICENSE file for further
14
+ details.
@@ -0,0 +1,16 @@
1
+ # Copyright (C) 2010 Oliver Eilhard
2
+ #
3
+ # This SAP OCI library is freely distributable under
4
+ # the terms of an MIT-style license.
5
+ # See COPYING or http://www.opensource.org/licenses/mit-license.php.
6
+
7
+ # This library is for parsing and emitting shopping cart data and
8
+ # behavior in SAP OCI style.
9
+
10
+ module SAPOCI
11
+ VERSION_40 = "4.0"
12
+
13
+ autoload :CoreExt, 'sapoci/core_ext.rb'
14
+ autoload :Document, 'sapoci/document.rb'
15
+ autoload :Item, 'sapoci/item.rb'
16
+ end
@@ -0,0 +1,2 @@
1
+ require 'sapoci/core_ext/try.rb'
2
+ require 'sapoci/core_ext/blank.rb'
@@ -0,0 +1,59 @@
1
+ class Object #:nodoc:
2
+ unless respond_to?(:blank?)
3
+ def blank?
4
+ respond_to?(:empty?) ? empty? : !self
5
+ end
6
+ end
7
+ end
8
+
9
+ class NilClass #:nodoc:
10
+ unless respond_to?(:blank?)
11
+ def blank?
12
+ true
13
+ end
14
+ end
15
+ end
16
+
17
+ class FalseClass #:nodoc:
18
+ unless respond_to?(:blank?)
19
+ def blank?
20
+ true
21
+ end
22
+ end
23
+ end
24
+
25
+ class TrueClass #:nodoc:
26
+ unless respond_to?(:blank?)
27
+ def blank?
28
+ false
29
+ end
30
+ end
31
+ end
32
+
33
+ class Array #:nodoc:
34
+ unless respond_to?(:blank?)
35
+ alias_method :blank?, :empty?
36
+ end
37
+ end
38
+
39
+ class Hash #:nodoc:
40
+ unless respond_to?(:blank?)
41
+ alias_method :blank?, :empty?
42
+ end
43
+ end
44
+
45
+ class String #:nodoc:
46
+ unless respond_to?(:blank?)
47
+ def blank?
48
+ self !~ /\S/
49
+ end
50
+ end
51
+ end
52
+
53
+ class Numeric #:nodoc:
54
+ unless respond_to?(:blank?)
55
+ def blank?
56
+ false
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,11 @@
1
+ class Object
2
+ alias_method(:try, :__send__) unless respond_to?(:try)
3
+ end
4
+
5
+ class NilClass
6
+ unless respond_to?(:try)
7
+ def try(*args)
8
+ nil
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,116 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems' unless RUBY_VERSION >= '1.9'
4
+ require 'nokogiri'
5
+ require 'sapoci/core_ext'
6
+
7
+ module SAPOCI
8
+ # SAPOCI::Document is for parsing and emitting SAP OCI compliant
9
+ # data.
10
+ #
11
+ # Open a +Document+ by feeding it a string:
12
+ #
13
+ # doc = SAPOCI::Document.from_html("<html>...</html>")
14
+ #
15
+ # Open a +Document+ by parsing a Rails-/Rack compatible +Hash+:
16
+ #
17
+ # doc = SAPOCI::Document.from_params({ "NEW_ITEM-DESCRIPTION"=>{"1"=>"Standard Visitenkarte deutsch 200 St."} })
18
+ #
19
+ class Document
20
+ def initialize(items)
21
+ @items = items
22
+ end
23
+
24
+ # Create a new document from a HTML string.
25
+ def self.from_html(html)
26
+ html_doc = Nokogiri::HTML(html)
27
+ doc = Document.new(parse_html(html_doc))
28
+ yield doc if block_given?
29
+ doc
30
+ end
31
+
32
+ # Create a new document from a Rails-/Rack-compatible
33
+ # params hash.
34
+ def self.from_params(params)
35
+ doc = Document.new(parse_params(params))
36
+ yield doc if block_given?
37
+ doc
38
+ end
39
+
40
+ # All +Item+ instances.
41
+ attr_reader :items
42
+
43
+ # Returns all +items+ as HTML hidden field tags.
44
+ def to_html(options = {})
45
+ html = []
46
+ self.items.each do |item|
47
+ html << item.to_html(options)
48
+ end
49
+ html.join
50
+ end
51
+
52
+ private
53
+
54
+ # Parses a Nokogiri HTML document and returns
55
+ # +Item+ instances in an array.
56
+ def self.parse_html(doc)
57
+ items = {}
58
+ doc.xpath("//input[starts-with(@name, 'NEW_ITEM-')]").each do |item_node|
59
+ name = item_node.attribute("name")
60
+ if /NEW_ITEM-(\w+)\[(\d+)\]/.match(name)
61
+ property = $1
62
+ index = $2.to_i - 1
63
+ value = item_node.attribute("value").value
64
+ items[index] = Item.new(index) unless items[index]
65
+ items[index].send((property+'=').downcase.to_sym, value)
66
+ end
67
+ end
68
+ items.inject([]) { |memo, (key, value)| memo << value }.sort_by(&:index)
69
+ end
70
+
71
+ # Parses a Rails-/Rack-compatible params hash and returns
72
+ # +Item+ instances in an array.
73
+ def self.parse_params(params)
74
+ items = {}
75
+ (params || {}).each do |oci_name, oci_values|
76
+ if oci_name =~ /NEW_ITEM-/
77
+ # Parse anything but NEW_ITEM-LONGTEXT (which is special, see below)
78
+ oci_values.each do |index, value|
79
+ index = index.to_i - 1 rescue next
80
+ property = /NEW_ITEM-(\w+)/.match(oci_name)[1]
81
+ next if property =~ /LONGTEXT/
82
+ method = (property+'=').downcase.to_sym
83
+ items[index] = Item.new(index) unless items[index]
84
+ items[index].send(method, value) if items[index].respond_to?(method)
85
+ end if oci_values && oci_values.respond_to?(:each)
86
+
87
+ # LONGTEXT is a special case because it doesn't follow the conventions
88
+ # Format is:
89
+ # NEW_ITEM-LONTEXT_n:132[]
90
+ # But shops use other (invalid) formats as well (and we're ready to accept them):
91
+ # NEW_ITEM-LONGTEXT_n:132[n]
92
+ # NEW_ITEM_LONGTEXT_n:132
93
+ #
94
+ if /NEW_ITEM-LONGTEXT_(\d+):132/.match(oci_name)
95
+ index = $1.to_i - 1
96
+ if oci_values.is_a?(Array)
97
+ # NEW_ITEM-LONGTEXT_1:132[]
98
+ items[index] = Item.new(index) unless items[index]
99
+ items[index].longtext = oci_values.first
100
+ elsif oci_values.is_a?(String)
101
+ # NEW_ITEM-LONGTEXT_1:132 <= invalid but parsed!
102
+ items[index] = Item.new(index) unless items[index]
103
+ items[index].longtext = oci_values
104
+ elsif oci_values.is_a?(Hash)
105
+ # NEW_ITEM-LONGTEXT_1:132[1] <= invalid but parsed!
106
+ items[index] = Item.new(index) unless items[index]
107
+ items[index].longtext = oci_values.first.last
108
+ end
109
+ end if oci_values
110
+ end # oci_name =~ /NEW_ITEM-/
111
+ end
112
+ items.inject([]) { |memo, (key, value)| memo << value }.sort_by(&:index)
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,139 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems' unless RUBY_VERSION >= '1.9'
4
+ require 'nokogiri'
5
+ require 'sapoci/core_ext'
6
+ require 'bigdecimal'
7
+
8
+ module SAPOCI
9
+ class Item
10
+
11
+ attr_reader :index
12
+ attr_accessor :description
13
+ attr_accessor :matnr
14
+ attr_accessor :quantity
15
+ attr_accessor :unit
16
+ attr_accessor :price
17
+ attr_accessor :currency
18
+ attr_accessor :priceunit
19
+ attr_accessor :leadtime
20
+ attr_accessor :longtext
21
+ attr_accessor :vendor
22
+ attr_accessor :vendormat
23
+ attr_accessor :manufactcode
24
+ attr_accessor :manufactmat
25
+ attr_accessor :matgroup
26
+ attr_accessor :service
27
+ attr_accessor :contract
28
+ attr_accessor :contract_item
29
+ attr_accessor :ext_quote_id
30
+ attr_accessor :ext_quote_item
31
+ attr_accessor :ext_product_id
32
+ attr_accessor :attachment
33
+ attr_accessor :attachment_title
34
+ attr_accessor :attachment_purpose
35
+ attr_accessor :ext_schema_type
36
+ attr_accessor :ext_category_id
37
+ attr_accessor :ext_category
38
+ attr_accessor :sld_sys_name
39
+ attr_accessor :cust_field1
40
+ attr_accessor :cust_field2
41
+ attr_accessor :cust_field3
42
+ attr_accessor :cust_field4
43
+ attr_accessor :cust_field5
44
+
45
+ # Initializes the item.
46
+ def initialize(index)
47
+ @index = index
48
+ end
49
+
50
+ def quantity
51
+ BigDecimal.new("0#{@quantity.to_s.strip}")
52
+ end
53
+
54
+ def quantity_before_type_cast
55
+ @quantity
56
+ end
57
+
58
+ def price
59
+ BigDecimal.new("0#{@price.to_s.strip}")
60
+ end
61
+
62
+ def price_before_type_cast
63
+ @price
64
+ end
65
+
66
+ def priceunit
67
+ BigDecimal.new("0#{@priceunit.to_s.strip}")
68
+ end
69
+
70
+ def priceunit_before_type_cast
71
+ @priceunit
72
+ end
73
+
74
+ def leadtime
75
+ @leadtime.to_i if @leadtime
76
+ end
77
+
78
+ def leadtime_before_type_cast
79
+ @leadtime
80
+ end
81
+
82
+ def service?
83
+ self.service == "X"
84
+ end
85
+
86
+ # Returns the item properties as HTML hidden field tags.
87
+ def to_html(options = {})
88
+ html = []
89
+ html << hidden_field_tag("DESCRIPTION", self.description) unless self.description.blank?
90
+ html << hidden_field_tag("MATNR", self.matnr) unless self.matnr.blank?
91
+ html << hidden_field_tag("QUANTITY", "%015.3f" % self.quantity)
92
+ html << hidden_field_tag("UNIT", self.unit) unless self.unit.blank?
93
+ html << hidden_field_tag("PRICE", "%015.3f" % self.price)
94
+ html << hidden_field_tag("CURRENCY", self.currency) unless self.currency.blank?
95
+ html << hidden_field_tag("PRICEUNIT", self.priceunit.to_i) if self.priceunit.to_i > 0
96
+ html << hidden_field_tag("LEADTIME", "%05d" % self.leadtime) if self.leadtime.to_i > 0
97
+ html << hidden_field_tag("VENDOR", self.vendor) unless self.vendor.blank?
98
+ html << hidden_field_tag("VENDORMAT", self.vendormat) unless self.vendormat.blank?
99
+ html << hidden_field_tag("MANUFACTCODE", self.manufactcode) unless self.manufactcode.blank?
100
+ html << hidden_field_tag("MANUFACTMAT", self.manufactmat) unless self.manufactmat.blank?
101
+ html << hidden_field_tag("MATGROUP", self.matgroup) unless self.matgroup.blank?
102
+ html << hidden_field_tag("SERVICE", "X") if self.service?
103
+ html << hidden_field_tag("CONTRACT", self.contract) unless self.contract.blank?
104
+ html << hidden_field_tag("CONTRACT_ITEM", self.contract_item) unless self.contract_item.blank?
105
+ html << hidden_field_tag("EXT_QUOTE_ID", self.ext_quote_id) unless self.ext_quote_id.blank?
106
+ html << hidden_field_tag("EXT_QUOTE_ITEM", self.ext_quote_item) unless self.ext_quote_item.blank?
107
+ html << hidden_field_tag("EXT_PRODUCT_ID", self.ext_product_id) unless self.ext_product_id.blank?
108
+ html << hidden_field_tag("ATTACHMENT", self.attachment) unless self.attachment.blank?
109
+ html << hidden_field_tag("ATTACHMENT_TITLE", self.attachment_title) unless self.attachment_title.blank?
110
+ html << hidden_field_tag("ATTACHMENT_PURPOSE", self.attachment_purpose) unless self.attachment_purpose.blank?
111
+ html << hidden_field_tag("EXT_SCHEMA_TYPE", self.ext_schema_type) unless self.ext_schema_type.blank?
112
+ html << hidden_field_tag("EXT_CATEGORY_ID", self.ext_category_id) unless self.ext_category_id.blank?
113
+ html << hidden_field_tag("EXT_CATEGORY", self.ext_category) unless self.ext_category.blank?
114
+ html << hidden_field_tag("SLD_SYS_NAME", self.sld_sys_name) unless self.sld_sys_name.blank?
115
+ html << hidden_field_tag("CUST_FIELD1", self.cust_field1) unless self.cust_field1.blank?
116
+ html << hidden_field_tag("CUST_FIELD2", self.cust_field2) unless self.cust_field2.blank?
117
+ html << hidden_field_tag("CUST_FIELD3", self.cust_field3) unless self.cust_field3.blank?
118
+ html << hidden_field_tag("CUST_FIELD4", self.cust_field4) unless self.cust_field4.blank?
119
+ html << hidden_field_tag("CUST_FIELD5", self.cust_field5) unless self.cust_field5.blank?
120
+ html << "<input type=\"hidden\" name=\"NEW_ITEM-LONGTEXT_#{index + 1}:132[]\" value=\"#{escape_html(self.longtext)}\" />" unless self.longtext.blank?
121
+ html.join
122
+ end
123
+
124
+ private
125
+
126
+ def hidden_field_tag(name, value, options = {})
127
+ "<input type=\"hidden\" name=\"NEW_ITEM-#{name}[#{index + 1}]\" value=\"#{escape_html(value)}\" />"
128
+ end
129
+
130
+ ESCAPE_HTML = { "&" => "&amp;", "<" => "&lt;", ">" => "&gt;", "'" => "&#39;", '"' => "&quot;", }
131
+ ESCAPE_HTML_PATTERN = Regexp.union(ESCAPE_HTML.keys)
132
+
133
+ # Shamelessly borrowed from Rack::Utils.escape_html(s)
134
+ def escape_html(s)
135
+ s.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] }
136
+ end
137
+
138
+ end
139
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sapoci
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Oliver Eilhard
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-18 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &70261606168780 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70261606168780
25
+ - !ruby/object:Gem::Dependency
26
+ name: rdoc
27
+ requirement: &70261606168260 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '2.5'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70261606168260
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &70261606167780 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 0.9.2
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70261606167780
47
+ - !ruby/object:Gem::Dependency
48
+ name: nokogiri
49
+ requirement: &70261606166980 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.5.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70261606166980
58
+ description: Ruby library and Rails plugin for punchout via SAP OCI protocol.
59
+ email:
60
+ - oliver.eilhard@gmail.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files:
64
+ - CHANGELOG.md
65
+ - LICENSE
66
+ - README.md
67
+ files:
68
+ - lib/sapoci.rb
69
+ - lib/sapoci/core_ext.rb
70
+ - lib/sapoci/core_ext/blank.rb
71
+ - lib/sapoci/core_ext/try.rb
72
+ - lib/sapoci/document.rb
73
+ - lib/sapoci/item.rb
74
+ - CHANGELOG.md
75
+ - LICENSE
76
+ - README.md
77
+ homepage: http://github.com/meplato/sapoci
78
+ licenses: []
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --charset=UTF-8
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: 1.3.6
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 1.8.7
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: Ruby library and Rails plugin for punchout via SAP OCI protocol.
102
+ test_files: []