lipseys 5.0.1 → 6.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: 823c554eff146611688ad459e698e449625640f8
4
- data.tar.gz: 96a39a440393b8bebcb8a4b7872aeaf6a0cf893b
3
+ metadata.gz: 4403d00b0a7ca5e2b6754e739d85bae695e8c6ce
4
+ data.tar.gz: c8e997c51bc28411ea030341b77591a20e6f9b58
5
5
  SHA512:
6
- metadata.gz: 7a02161b0af4d5dc95f45b9f0a677b5ff7379ad20c5a59b5fd02ae5101adfa7c0b715d986eded166b27fc24e8a34f0c7c3f6e68da468f10aeb93755b77d40e10
7
- data.tar.gz: c1592da12a360a88b85daef78e24ddec07858a1e3688e12b7d30cd7dfc6873281b5dce54cadbcf490bd65287115053bab4ce1ab9b348e9af8c032ed02866f54f
6
+ metadata.gz: e5c1ad6a782c66656e2dafe7f4dedc0fecf2232e0c5425319d7b5ac0a775633ab4a9dcb4f9f7461a29407e713492e3c977fdf58ffabc4f46ad9649e02dbf2dd7
7
+ data.tar.gz: 5589846a2cbbee7b70eaa57831b42d385a09ba42950d1205162c42bb033070abadcb880b4d96daaf3821cb47154abe9c45c131ddc2fff2a30643774d2b5173fa
@@ -1,20 +1,38 @@
1
- require 'lipseys/version'
2
-
3
- require 'net/http'
4
- require 'nokogiri'
5
- require 'savon'
6
-
7
1
  require 'lipseys/base'
8
- require 'lipseys/soap_client'
2
+ require 'lipseys/version'
9
3
 
4
+ require 'lipseys/api'
10
5
  require 'lipseys/catalog'
6
+ require 'lipseys/client'
7
+ require 'lipseys/error'
11
8
  require 'lipseys/inventory'
12
- require 'lipseys/invoice'
9
+ require 'lipseys/items'
13
10
  require 'lipseys/order'
11
+ require 'lipseys/response'
14
12
  require 'lipseys/user'
15
- require 'lipseys/image'
16
- require 'lipseys/parser'
17
13
 
18
14
  module Lipseys
19
- class NotAuthenticated < StandardError; end
15
+
16
+ class << self
17
+ attr_accessor :config
18
+ end
19
+
20
+ def self.config
21
+ @config ||= Configuration.new
22
+ end
23
+
24
+ def self.configure
25
+ yield(config)
26
+ end
27
+
28
+ class Configuration
29
+ attr_accessor :proxy_address
30
+ attr_accessor :proxy_port
31
+
32
+ def initialize
33
+ @proxy_address ||= nil
34
+ @proxy_port ||= nil
35
+ end
36
+ end
37
+
20
38
  end
@@ -0,0 +1,121 @@
1
+ require 'net/http'
2
+
3
+ module Lipseys
4
+ module API
5
+
6
+ ROOT_API_URL = 'https://api.lipseys.com/api/integration'.freeze
7
+ USER_AGENT = "LipseysRubyGem/#{Lipseys::VERSION}".freeze
8
+
9
+ FILE_UPLOAD_ATTRS = {
10
+ permitted: %i( file_name file_type file_contents ).freeze,
11
+ reqired: %i( file_type file_contents ).freeze,
12
+ }
13
+
14
+ def get_request(endpoint, headers = {})
15
+ request = Net::HTTP::Get.new(request_url(endpoint))
16
+
17
+ submit_request(request, {}, headers)
18
+ end
19
+
20
+ def post_request(endpoint, data = {}, headers = {})
21
+ request = Net::HTTP::Post.new(request_url(endpoint))
22
+
23
+ submit_request(request, data, headers)
24
+ end
25
+
26
+ def post_file_request(endpoint, file_data, headers = {})
27
+ request = Net::HTTP::Post.new(request_url(endpoint))
28
+
29
+ submit_file_request(request, file_data, headers)
30
+ end
31
+
32
+ private
33
+
34
+ def submit_request(request, data, headers)
35
+ set_request_headers(request, headers)
36
+
37
+ request.body = data.is_a?(Hash) ? data.to_json : data
38
+
39
+ process_request(request)
40
+ end
41
+
42
+ def submit_file_request(request, file_data, headers)
43
+ boundary = ::SecureRandom.hex(15)
44
+
45
+ headers.merge!(content_type_header("multipart/form-data; boundary=#{boundary}"))
46
+
47
+ build_multipart_request_body(request, file_data, boundary)
48
+ set_request_headers(request, headers)
49
+ process_request(request)
50
+ end
51
+
52
+ def process_request(request)
53
+ uri = URI(request.path)
54
+
55
+ response = Net::HTTP.start(uri.host, uri.port, Lipseys.config.proxy_address, Lipseys.config.proxy_port, use_ssl: true) do |http|
56
+ http.request(request)
57
+ end
58
+
59
+ Lipseys::Response.new(response)
60
+ end
61
+
62
+ def build_multipart_request_body(request, file_data, boundary)
63
+ file_type = file_data[:file_type]
64
+ file_contents = file_data[:file_contents]
65
+ file_name = file_data[:file_name] || "ffl-document.#{file_type}"
66
+ content_type = "application/#{file_data[:file_type]}"
67
+
68
+ body = []
69
+ body << "--#{boundary}\r\n"
70
+ body << "Content-Disposition: form-data; name=\"file\"; filename=\"#{file_name}\"\r\n"
71
+ body << "Content-Type: #{content_type}\r\n"
72
+ body << "\r\n"
73
+ body << "#{file_contents}\r\n"
74
+ body << "--#{boundary}--\r\n"
75
+
76
+ request.body = body.join
77
+ end
78
+
79
+ def set_request_headers(request, headers)
80
+ request['User-Agent'] = USER_AGENT
81
+
82
+ headers.each { |header, value| request[header] = value }
83
+ end
84
+
85
+ def auth_header(token)
86
+ { 'Token' => token }
87
+ end
88
+
89
+ def content_type_header(type)
90
+ { 'Content-Type' => type }
91
+ end
92
+
93
+ def request_url(endpoint)
94
+ [ROOT_API_URL, endpoint].join('/')
95
+ end
96
+
97
+ def standardize_body_data(submitted_data, permitted_data_attrs)
98
+ _submitted_data = submitted_data.deep_transform_keys(&:to_sym)
99
+ permitted_data = {}
100
+
101
+ _submitted_data.each do |k1, v1|
102
+ if permitted_data_attrs.include?(k1)
103
+ if v1.is_a?(Array)
104
+ permitted_data[k1] = []
105
+
106
+ v1.each do |sub_data|
107
+ permitted_sub_data = {}
108
+ sub_data.each { |k2, v2| permitted_sub_data[k2] = v2 if permitted_data_attrs.include?(k2) }
109
+ permitted_data[k1] << permitted_sub_data
110
+ end
111
+ else
112
+ permitted_data[k1] = v1
113
+ end
114
+ end
115
+ end
116
+
117
+ permitted_data.deep_transform_keys { |k| k.to_s.camelize(:lower) }
118
+ end
119
+
120
+ end
121
+ end
@@ -3,70 +3,24 @@ module Lipseys
3
3
 
4
4
  protected
5
5
 
6
- # Wrapper to `self.requires!` that can be used as an instance method.
7
6
  def requires!(*args)
8
7
  self.class.requires!(*args)
9
8
  end
10
9
 
11
10
  def self.requires!(hash, *params)
11
+ hash_keys = hash.collect { |k, v| v.is_a?(Array) ? [k, v.collect(&:keys)] : k }.flatten
12
+
12
13
  params.each do |param|
13
14
  if param.is_a?(Array)
14
- raise ArgumentError.new("Missing required parameter: #{param.first}") unless hash.has_key?(param.first)
15
+ raise ArgumentError.new("Missing required parameter: #{param.first}") unless hash_keys.include?(param.first)
15
16
 
16
17
  valid_options = param[1..-1]
17
18
  raise ArgumentError.new("Parameter: #{param.first} must be one of: #{valid_options.join(', ')}") unless valid_options.include?(hash[param.first])
18
19
  else
19
- raise ArgumentError.new("Missing required parameter: #{param}") unless hash.has_key?(param)
20
+ raise ArgumentError.new("Missing required parameter: #{param}") unless hash_keys.include?(param)
20
21
  end
21
22
  end
22
23
  end
23
24
 
24
- def content_for(xml_doc, field)
25
- node = xml_doc.css(field).first
26
- node.nil? ? nil : node.content.strip
27
- end
28
-
29
- def get_response_xml(api_url, params)
30
- uri = URI(api_url)
31
- uri.query = URI.encode_www_form(params_to_auth(params))
32
-
33
- response = Net::HTTP.get_response(uri)
34
- xml_doc = Nokogiri::XML(response.body)
35
-
36
- raise Lipseys::NotAuthenticated if not_authenticated?(xml_doc)
37
-
38
- xml_doc
39
- end
40
-
41
- def not_authenticated?(xml_doc)
42
- msg = content_for(xml_doc, 'CatalogError')
43
- msg =~ /Login failed/i || msg =~ /Credentials Not Valid/i
44
- end
45
-
46
- def stream_to_tempfile(api_url, params)
47
- tempfile = Tempfile.new
48
- uri = URI(api_url)
49
- uri.query = URI.encode_www_form(params_to_auth(params))
50
-
51
- Net::HTTP.get_response(uri) do |response|
52
- File.open(tempfile, 'w') do |file|
53
- response.read_body do |chunk|
54
- file.write(chunk.force_encoding('UTF-8'))
55
- end
56
- end
57
- end
58
-
59
- tempfile
60
- end
61
-
62
- private
63
-
64
- def params_to_auth(params)
65
- {
66
- email: params.fetch(:username),
67
- pass: params.fetch(:password),
68
- }
69
- end
70
-
71
25
  end
72
26
  end
@@ -1,87 +1,64 @@
1
1
  module Lipseys
2
2
  class Catalog < Base
3
3
 
4
- CHUNK_SIZE = 500
5
- API_URL = 'http://184.188.80.195/API/catalog.ashx'
6
- ITEMTYPES = %w(ACCESSORY FIREARM NFA OPTIC)
7
-
8
4
  def initialize(options = {})
9
5
  requires!(options, :username, :password)
10
6
 
11
- @options = options
7
+ @client = Lipseys::Client.new(username: options[:username], password: options[:password])
12
8
  end
13
9
 
14
10
  def self.all(options = {})
15
11
  requires!(options, :username, :password)
12
+
16
13
  new(options).all
17
14
  end
18
15
 
19
16
  def all
20
- inventory_tempfile = stream_to_tempfile(Lipseys::Inventory::API_URL, @options)
21
- catalog_tempfile = stream_to_tempfile(API_URL, @options)
22
- inventory = []
23
- items = []
24
-
25
- # Let's get the inventory and toss 'er into an array
26
- Lipseys::Parser.parse(inventory_tempfile, 'Item') do |node|
27
- inventory.push({
28
- item_identifier: content_for(node, 'ItemNo'),
29
- map_price: content_for(node, 'RetailMAP'),
30
- quantity: content_for(node, 'QtyOnHand'),
31
- price: content_for(node, 'Price')
32
- })
33
- end
34
-
35
- Lipseys::Parser.parse(catalog_tempfile, 'Item') do |node|
36
- item = map_hash(node)
37
- availability = inventory.select { |i| i[:item_identifier] == item[:item_identifier] }.first
38
-
39
- if availability
40
- item[:price] = availability[:price]
41
- item[:quantity] = availability[:quantity]
42
- item[:map_price] = availability[:map_price]
43
- end
44
-
45
- items << item
46
- end
47
-
48
- inventory_tempfile.unlink
49
- catalog_tempfile.unlink
50
-
51
- items
17
+ @client.items.catalog_feed[:data].map { |item| map_hash(item) }
52
18
  end
53
19
 
54
20
  private
55
21
 
56
- def map_hash(node)
57
- model = content_for(node, 'Model')
58
- mfg_number = content_for(node, 'MFGModelNo')
59
- name = "#{model} #{mfg_number}".lstrip.rstrip
60
-
22
+ def map_hash(item)
61
23
  {
62
- name: name,
63
- model: model,
64
- upc: content_for(node, 'UPC'),
65
- short_description: content_for(node, 'Desc2'),
66
- category: content_for(node, 'Type'),
67
- price: nil,
68
- weight: content_for(node, 'Weight'),
69
- item_identifier: content_for(node, 'ItemNo'),
70
- brand: content_for(node, 'MFG'),
71
- mfg_number: mfg_number,
24
+ name: [item[:model].try(:strip), item[:manufacturerModelNo].try(:strip)].compact.join(' '),
25
+ model: item[:model],
26
+ upc: item[:upc],
27
+ long_description: item[:description1],
28
+ short_description: item[:description2],
29
+ category: item[:type],
30
+ price: item[:price],
31
+ map_price: item[:retailMap],
32
+ msrp: item[:msrp],
33
+ quantity: item[:quantity],
34
+ weight: item[:weight],
35
+ item_identifier: item[:itemNo],
36
+ brand: item[:manufacturer],
37
+ mfg_number: item[:manufacturerModelNo],
72
38
  features: {
73
- caliber: content_for(node, 'Caliber'),
74
- action: content_for(node, 'Action'),
75
- barrel: content_for(node, 'Barrel'),
76
- capacity: content_for(node, 'Capacity'),
77
- finish: content_for(node, 'Finish'),
78
- length: content_for(node, 'Length'),
79
- receiver: content_for(node, 'Receiver'),
80
- safety: content_for(node, 'Safety'),
81
- sights: content_for(node, 'Sights'),
82
- magazine: content_for(node, 'Magazine'),
83
- chamber: content_for(node, 'Chamber')
84
- }
39
+ caliber: item[:caliberGauge],
40
+ action: item[:action],
41
+ barrel: item[:barrelLength],
42
+ capacity: item[:capacity],
43
+ finish: item[:finish],
44
+ length: item[:overallLength],
45
+ receiver: item[:receiver],
46
+ safety: item[:safety],
47
+ sights: item[:sights],
48
+ stock_frame_grips: item[:stockFrameGrips],
49
+ magazine: item[:magazine],
50
+ chamber: item[:chamber],
51
+ rate_of_twist: item[:rateOfTwist],
52
+ additional_feature_1: item[:additionalFeature1],
53
+ additional_feature_2: item[:additionalFeature2],
54
+ additional_feature_3: item[:additionalFeature3],
55
+ nfa_thread_pattern: item[:nfaThreadPattern],
56
+ nfa_attachment_method: item[:nfaAttachmentMethod],
57
+ nfa_baffle_type: item[:nfaBaffleType],
58
+ nfa_db_reduction: item[:nfaDbReduction],
59
+ nfa_form_3_caliber: item[:nfaForm3Caliber],
60
+ optic_magnification: item[:opticMagnification],
61
+ },
85
62
  }
86
63
  end
87
64
 
@@ -0,0 +1,40 @@
1
+ require 'lipseys/api'
2
+ require 'lipseys/items'
3
+ require 'lipseys/order'
4
+
5
+ module Lipseys
6
+ class Client < Base
7
+
8
+ include Lipseys::API
9
+
10
+ attr_accessor :access_token
11
+
12
+ def initialize(options = {})
13
+ requires!(options, :username, :password)
14
+ @options = options
15
+
16
+ authenticate!
17
+ end
18
+
19
+ def items
20
+ @items ||= Lipseys::Items.new(self)
21
+ end
22
+
23
+ def order
24
+ @order ||= Lipseys::Order.new(self)
25
+ end
26
+
27
+ private
28
+
29
+ def authenticate!
30
+ response = post_request(
31
+ 'authentication/login',
32
+ { email: @options[:username], password: @options[:password] },
33
+ content_type_header('application/json')
34
+ )
35
+
36
+ self.access_token = response[:token]
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,11 @@
1
+ module Lipseys
2
+ class Error < StandardError
3
+
4
+ class NoContent < Lipseys::Error; end
5
+ class NotAuthorized < Lipseys::Error; end
6
+ class NotFound < Lipseys::Error; end
7
+ class RequestError < Lipseys::Error; end
8
+ class TimeoutError < Lipseys::Error; end
9
+
10
+ end
11
+ end
@@ -1,62 +1,30 @@
1
1
  module Lipseys
2
2
  class Inventory < Base
3
3
 
4
- API_URL = 'http://184.188.80.195/API/pricequantitycatalog.ashx'
5
-
6
4
  def initialize(options = {})
7
5
  requires!(options, :username, :password)
8
6
 
9
- @options = options
7
+ @client = Lipseys::Client.new(username: options[:username], password: options[:password])
10
8
  end
11
9
 
12
10
  def self.all(options = {})
13
- new(options).all
14
- end
11
+ requires!(options, :username, :password)
15
12
 
16
- def self.quantity(options = {})
17
13
  new(options).all
18
14
  end
19
-
20
- def self.get_quantity_file(options = {})
21
- new(options).get_quantity_file
22
- end
15
+ class << self; alias_method :quantity, :all; end
23
16
 
24
17
  def all
25
- items = []
26
- tempfile = stream_to_tempfile(API_URL, @options)
27
-
28
- Lipseys::Parser.parse(tempfile, 'Item') do |node|
29
- _map_hash = map_hash(node)
30
-
31
- items << _map_hash unless _map_hash.nil?
32
- end
33
-
34
- tempfile.unlink
35
-
36
- items
37
- end
38
-
39
- def get_quantity_file
40
- quantity_tempfile = stream_to_tempfile(API_URL, @options)
41
- tempfile = Tempfile.new
42
-
43
- Lipseys::Parser.parse(quantity_tempfile, 'Item') do |node|
44
- tempfile.puts("#{content_for(node, 'ItemNo')},#{content_for(node, 'QtyOnHand')}")
45
- end
46
-
47
- quantity_tempfile.unlink
48
- tempfile.close
49
-
50
- tempfile.path
18
+ @client.items.pricing_quantity_feed[:data][:items].map { |item| map_hash(item) }
51
19
  end
52
20
 
53
21
  private
54
22
 
55
- def map_hash(node)
23
+ def map_hash(item)
56
24
  {
57
- item_identifier: content_for(node, 'ItemNo'),
58
- quantity: content_for(node, 'QtyOnHand'),
59
- price: content_for(node, 'Price')
25
+ item_identifier: item[:itemNumber],
26
+ quantity: item[:quantity],
27
+ price: item[:price],
60
28
  }
61
29
  end
62
30
 
@@ -0,0 +1,54 @@
1
+ require 'lipseys/api'
2
+
3
+ module Lipseys
4
+ class Items < Base
5
+
6
+ include Lipseys::API
7
+
8
+ ENDPOINTS = {
9
+ catalog_feed: "items/catalogfeed".freeze,
10
+ pricing_quantity_feed: "items/pricingquantityfeed".freeze,
11
+ validate_item: "items/validateitem".freeze,
12
+ catalog_feed_item: "items/catalogfeed/item".freeze,
13
+ }
14
+
15
+ def initialize(client)
16
+ @client = client
17
+ end
18
+
19
+ def catalog_feed
20
+ endpoint = ENDPOINTS[:catalog_feed]
21
+
22
+ get_request(endpoint, auth_header(@client.access_token))
23
+ end
24
+
25
+ def pricing_quantity_feed
26
+ endpoint = ENDPOINTS[:pricing_quantity_feed]
27
+
28
+ get_request(endpoint, auth_header(@client.access_token))
29
+ end
30
+
31
+ # `identifier` can be Item #, Mfg Model #, or UPC
32
+ def validate_item(identifier)
33
+ endpoint = ENDPOINTS[:validate_item]
34
+ headers = [
35
+ *auth_header(@client.access_token),
36
+ *content_type_header('application/json'),
37
+ ].to_h
38
+
39
+ post_request(endpoint, "'#{identifier}'", headers)
40
+ end
41
+
42
+ # `identifier` can be Item #, Mfg Model #, or UPC
43
+ def catalog_feed_item(identifier)
44
+ endpoint = ENDPOINTS[:catalog_feed_item]
45
+ headers = [
46
+ *auth_header(@client.access_token),
47
+ *content_type_header('application/json'),
48
+ ].to_h
49
+
50
+ post_request(endpoint, "'#{identifier}'", headers)
51
+ end
52
+
53
+ end
54
+ end
@@ -1,74 +1,55 @@
1
- module Lipseys
2
- # Required options when submitting an order:
3
- #
4
- # * `:email` and `:password`
5
- # * `:item_number` OR `:upc`
6
- # * `:quantity`
7
- # * `:purchase_order`
8
- #
9
- # Optional order params:
10
- #
11
- # * `:notify_by_email` (boolean)
12
- # * `:note`
13
- class Order < SoapClient
14
-
15
- def initialize(options = {})
16
- requires!(options, :username, :password, :quantity, :purchase_order)
17
- @email = options[:username]
18
- @password = options[:password]
19
- @quantity = options[:quantity]
20
-
21
- @notify_by_email = (options[:notify_by_email] == true ? 'Y' : nil)
22
- @purchase_order = options[:purchase_order]
23
- @note = options[:note]
24
-
25
- @item_number_or_upc = options[:item_number] || options[:upc]
26
- raise ArgumentError.new("Either :item_number or :upc must be given") if @item_number_or_upc.nil?
27
- end
28
-
1
+ require 'lipseys/api'
29
2
 
30
- def self.submit!(*args)
31
- new(*args).submit!
32
- end
33
-
34
- def submit!
35
- response = soap_client.call(:submit_order, message: build_order_data)
36
-
37
- raise Lipseys::NotAuthenticated if not_authenticated?(response)
38
-
39
- order_result = response.body[:submit_order_response][:submit_order_result]
40
-
41
- {
42
- order_number: order_result[:order_no],
43
- new_order: (order_result[:new_order] == 'Y'),
44
- success: (order_result[:success] == 'Y'),
45
- description: order_result[:return_desc],
46
- quantity_received: Integer(order_result[:qty_received]),
47
- }
48
- rescue Savon::Error => e
49
- { success: false, description: e.to_s }
3
+ module Lipseys
4
+ class Order < Base
5
+
6
+ include Lipseys::API
7
+
8
+ SUBMIT_TO_STORE_ATTRS = {
9
+ permitted: %i( po_number disable_email items item_no quantity note ).freeze,
10
+ required: %i( items item_no quantity ).freeze
11
+ }
12
+
13
+ SUBMIT_TO_DROP_SHIP_ATTRS = {
14
+ permitted: %i(
15
+ warehouse po_number billing_name billing_address_line_1 billing_address_line_2 billing_address_city
16
+ billing_address_state billing_address_zip shipping_name shipping_address_line_1 shipping_address_line_2
17
+ shipping_address_city shipping_address_state shipping_address_zip message_for_sales_exec disable_email
18
+ items item_no quantity note overnight
19
+ ).freeze,
20
+ required: %i(
21
+ po_number billing_name billing_address_line_1 billing_address_city billing_address_state billing_address_zip
22
+ shipping_name shipping_address_line_1 shipping_address_city shipping_address_state shipping_address_zip
23
+ items item_no quantity
24
+ ).freeze
25
+ }
26
+
27
+ ENDPOINTS = {
28
+ submit_to_store: "order/apiorder".freeze,
29
+ submit_to_drop_ship: "order/dropship".freeze,
30
+ }
31
+
32
+ def initialize(client)
33
+ @client = client
50
34
  end
51
35
 
52
- private
36
+ def submit_to_store(order_data)
37
+ requires!(order_data, *SUBMIT_TO_STORE_ATTRS[:required])
53
38
 
54
- def build_order_data
55
- order_data = {
56
- EmailAddress: @email,
57
- Password: @password,
58
- LipseysItemNumberOrUPC: @item_number_or_upc,
59
- Qty: @quantity
60
- }
39
+ endpoint = ENDPOINTS[:submit_to_store]
40
+ headers = [
41
+ *auth_header(@client.access_token),
42
+ *content_type_header('application/json'),
43
+ ].to_h
61
44
 
62
- order_data[:NotifyByEmail] = @notify_by_email unless @notify_by_email.nil?
63
- order_data[:PONumber] = @purchase_order unless @purchase_order.nil?
64
- order_data[:Note] = @note unless @note.nil?
45
+ order_data = standardize_body_data(order_data, SUBMIT_TO_STORE_ATTRS[:permitted])
65
46
 
66
- { OrderData: order_data }
47
+ post_request(endpoint, order_data, headers)
67
48
  end
68
49
 
69
- def not_authenticated?(response)
70
- order_result = response.body[:submit_order_response][:submit_order_result]
71
- order_result[:success] == 'N' && order_result[:return_desc] =~ /Credentials Not Valid/i
50
+ def submit_to_drop_ship(order_data)
51
+ # NOTE: Will build this out as time permits.
52
+ false
72
53
  end
73
54
 
74
55
  end
@@ -0,0 +1,45 @@
1
+ module Lipseys
2
+ class Response
3
+
4
+ def initialize(response)
5
+ @response = response
6
+
7
+ case @response
8
+ when Net::HTTPUnauthorized
9
+ Lipseys::Error::NotAuthorized.new(@response.body)
10
+ when Net::HTTPNotFound
11
+ Lipseys::Error::NotFound.new(@response.body)
12
+ when Net::HTTPNoContent
13
+ Lipseys::Error::NoContent.new(@response.body)
14
+ when Net::HTTPOK, Net::HTTPSuccess
15
+ _data = (JSON.parse(@response.body) if @response.body.present?)
16
+
17
+ @data = case
18
+ when _data.is_a?(Hash)
19
+ _data.deep_symbolize_keys
20
+ when _data.is_a?(Array)
21
+ _data.map(&:deep_symbolize_keys)
22
+ end
23
+ else
24
+ raise Lipseys::Error::RequestError.new(@response.body)
25
+ end
26
+ end
27
+
28
+ def [](key)
29
+ @data[key]
30
+ end
31
+
32
+ def body
33
+ @data
34
+ end
35
+
36
+ def fetch(key)
37
+ @data.fetch(key)
38
+ end
39
+
40
+ def success?
41
+ !!self[:success] && self[:errors].empty?
42
+ end
43
+
44
+ end
45
+ end
@@ -1,29 +1,14 @@
1
1
  module Lipseys
2
- class User < SoapClient
3
-
4
- API_URL = 'http://184.188.80.195/API/validate.asmx?WSDL'
2
+ class User < Base
5
3
 
6
4
  def initialize(options = {})
7
5
  requires!(options, :username, :password)
8
- @options = options
9
- end
10
6
 
11
- def authenticated?
12
- validate[:success]
7
+ @client = Lipseys::Client.new(username: options[:username], password: options[:password])
13
8
  end
14
9
 
15
- def validate
16
- body = { Credentials: { EmailAddress: @options[:username], Password: @options[:password] } }
17
- response = soap_client(API_URL).call(:validate_dealer, message: body)
18
-
19
- result = response.body[:validate_dealer_response][:validate_dealer_result]
20
-
21
- {
22
- success: (result[:success] == 'Y'),
23
- description: result[:return_desc],
24
- }
25
- rescue Savon::Error => e
26
- { success: false, description: e.to_s }
10
+ def authenticated?
11
+ @client.access_token.present?
27
12
  end
28
13
 
29
14
  end
@@ -1,3 +1,3 @@
1
1
  module Lipseys
2
- VERSION = '5.0.1'.freeze
2
+ VERSION = '6.0.0'.freeze
3
3
  end
@@ -6,8 +6,8 @@ require 'lipseys/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "lipseys"
8
8
  spec.version = Lipseys::VERSION
9
- spec.authors = ["Dale Campbell"]
10
- spec.email = ["oshuma@gmail.com"]
9
+ spec.authors = ["Jeffrey Dill"]
10
+ spec.email = ["jeffdill2@gmail.com"]
11
11
 
12
12
  spec.summary = %q{Ruby library for Lipsey's API.}
13
13
  spec.description = %q{}
@@ -17,16 +17,14 @@ Gem::Specification.new do |spec|
17
17
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
18
  f.match(%r{^(test|spec|features)/})
19
19
  end
20
+
20
21
  spec.bindir = "exe"
21
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
23
  spec.require_paths = ["lib"]
23
24
 
24
- spec.add_dependency "nokogiri", "~> 1.6"
25
- spec.add_dependency "savon", "~> 2.11.1"
26
-
27
25
  spec.add_development_dependency "activesupport", "~> 5"
28
26
  spec.add_development_dependency "bundler", "~> 1.12"
29
- spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "rake", ">= 12.3.3"
30
28
  spec.add_development_dependency "rspec", "~> 3.0"
31
29
  spec.add_development_dependency "webmock", "~> 2.3"
32
30
  end
metadata CHANGED
@@ -1,43 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lipseys
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.1
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
- - Dale Campbell
7
+ - Jeffrey Dill
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-09-16 00:00:00.000000000 Z
11
+ date: 2020-03-31 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: nokogiri
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.6'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.6'
27
- - !ruby/object:Gem::Dependency
28
- name: savon
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: 2.11.1
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: 2.11.1
41
13
  - !ruby/object:Gem::Dependency
42
14
  name: activesupport
43
15
  requirement: !ruby/object:Gem::Requirement
@@ -70,16 +42,16 @@ dependencies:
70
42
  name: rake
71
43
  requirement: !ruby/object:Gem::Requirement
72
44
  requirements:
73
- - - "~>"
45
+ - - ">="
74
46
  - !ruby/object:Gem::Version
75
- version: '10.0'
47
+ version: 12.3.3
76
48
  type: :development
77
49
  prerelease: false
78
50
  version_requirements: !ruby/object:Gem::Requirement
79
51
  requirements:
80
- - - "~>"
52
+ - - ">="
81
53
  - !ruby/object:Gem::Version
82
- version: '10.0'
54
+ version: 12.3.3
83
55
  - !ruby/object:Gem::Dependency
84
56
  name: rspec
85
57
  requirement: !ruby/object:Gem::Requirement
@@ -110,7 +82,7 @@ dependencies:
110
82
  version: '2.3'
111
83
  description: ''
112
84
  email:
113
- - oshuma@gmail.com
85
+ - jeffdill2@gmail.com
114
86
  executables: []
115
87
  extensions: []
116
88
  extra_rdoc_files: []
@@ -127,14 +99,16 @@ files:
127
99
  - bin/console
128
100
  - bin/setup
129
101
  - lib/lipseys.rb
102
+ - lib/lipseys/api.rb
130
103
  - lib/lipseys/base.rb
131
104
  - lib/lipseys/catalog.rb
105
+ - lib/lipseys/client.rb
106
+ - lib/lipseys/error.rb
132
107
  - lib/lipseys/image.rb
133
108
  - lib/lipseys/inventory.rb
134
- - lib/lipseys/invoice.rb
109
+ - lib/lipseys/items.rb
135
110
  - lib/lipseys/order.rb
136
- - lib/lipseys/parser.rb
137
- - lib/lipseys/soap_client.rb
111
+ - lib/lipseys/response.rb
138
112
  - lib/lipseys/user.rb
139
113
  - lib/lipseys/version.rb
140
114
  - lipseys.gemspec
@@ -158,7 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
132
  version: '0'
159
133
  requirements: []
160
134
  rubyforge_project:
161
- rubygems_version: 2.6.14
135
+ rubygems_version: 2.6.14.1
162
136
  signing_key:
163
137
  specification_version: 4
164
138
  summary: Ruby library for Lipsey's API.
@@ -1,83 +0,0 @@
1
- module Lipseys
2
- # In addition to the `:email` and `:password` options, finding invoices requires
3
- # either an `:order_number` **OR** a `:purchase_order`.
4
- #
5
- # The response structure will look like this:
6
- #
7
- # {
8
- # invoices_found: 1,
9
- # description: "1 Invoice(s) found.",
10
- # invoices: {
11
- # invoice_detail: {
12
- # invoice_no: "...",
13
- # ship_to_location: "...",
14
- # tracking_no: "...",
15
- # line_items: {
16
- # item_detail: {
17
- # item_no: "...",
18
- # upc: "...",
19
- # qty: "...",
20
- # serialized_item: "...",
21
- # serial_numbers: {
22
- # string: "..."
23
- # }
24
- # }
25
- # }
26
- # }
27
- # }
28
- # }
29
- class Invoice < SoapClient
30
-
31
- def initialize(options = {})
32
- requires!(options, :username, :password)
33
- @email = options[:username]
34
- @password = options[:password]
35
-
36
- @order_number = options[:order_number]
37
- @purchase_order = options[:purchase_order]
38
- raise ArgumentError.new("Either :order_number or :purchase_order is required") if @order_number.nil? && @purchase_order.nil?
39
- end
40
-
41
-
42
- def self.all(*args)
43
- new(*args).all
44
- end
45
-
46
- def all
47
- response = soap_client.call(:get_invoices, message: build_inquiry_data)
48
-
49
- raise Lipseys::NotAuthenticated if not_authenticated?(response)
50
-
51
- invoice_result = response.body[:get_invoices_response][:get_invoices_result]
52
-
53
- {
54
- invoices_found: Integer(invoice_result[:invoices_found]),
55
- description: invoice_result[:return_desc],
56
-
57
- invoices: invoice_result[:invoices]
58
- }
59
- rescue Savon::Error => e
60
- { success: false, description: e.to_s }
61
- end
62
-
63
- private
64
-
65
- def build_inquiry_data
66
- inquiry_data = {
67
- EmailAddress: @email,
68
- Password: @password
69
- }
70
-
71
- inquiry_data[:OrderNo] = @order_number unless @order_number.nil?
72
- inquiry_data[:PONumber] = @purchase_order unless @purchase_order.nil?
73
-
74
- { InquiryData: inquiry_data }
75
- end
76
-
77
- def not_authenticated?(response)
78
- invoice_result = response.body[:get_invoices_response][:get_invoices_result]
79
- invoice_result[:return_desc] =~ /Credentials Not Valid/i
80
- end
81
-
82
- end
83
- end
@@ -1,25 +0,0 @@
1
- module Lipseys
2
- class Parser
3
-
4
- attr_reader :file
5
-
6
- def initialize(file)
7
- @file = file
8
- end
9
-
10
- def self.parse(file, node_name, &block)
11
- new(file).parse(node_name, &block)
12
- end
13
-
14
- def parse(node_name, &block)
15
- File.open(@file) do |file|
16
- Nokogiri::XML::Reader.from_io(file).each do |node|
17
- if node.name == node_name and node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT
18
- yield(Nokogiri::XML(node.outer_xml))
19
- end
20
- end
21
- end
22
- end
23
-
24
- end
25
- end
@@ -1,13 +0,0 @@
1
- module Lipseys
2
- class SoapClient < Base
3
-
4
- API_URL = 'http://184.188.80.195/webservice/LipseyAPI.asmx?WSDL'
5
-
6
- protected
7
-
8
- def soap_client(api_url = API_URL)
9
- @soap_client ||= Savon.client(wsdl: api_url, convert_request_keys_to: :none)
10
- end
11
-
12
- end
13
- end