newgistics 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +25 -0
  3. data/.env.sample +2 -0
  4. data/.gitignore +15 -0
  5. data/.rspec +2 -0
  6. data/.ruby-version +1 -0
  7. data/.simplecov +4 -0
  8. data/.travis.yml +5 -0
  9. data/CODE_OF_CONDUCT.md +74 -0
  10. data/Gemfile +6 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +187 -0
  13. data/Rakefile +6 -0
  14. data/bin/console +16 -0
  15. data/bin/setup +8 -0
  16. data/lib/newgistics.rb +68 -0
  17. data/lib/newgistics/api.rb +26 -0
  18. data/lib/newgistics/configuration.rb +23 -0
  19. data/lib/newgistics/customer.rb +20 -0
  20. data/lib/newgistics/default_logger.rb +11 -0
  21. data/lib/newgistics/errors.rb +4 -0
  22. data/lib/newgistics/fee.rb +9 -0
  23. data/lib/newgistics/inbound_return.rb +29 -0
  24. data/lib/newgistics/inventory.rb +22 -0
  25. data/lib/newgistics/item.rb +19 -0
  26. data/lib/newgistics/order.rb +32 -0
  27. data/lib/newgistics/product.rb +30 -0
  28. data/lib/newgistics/query.rb +43 -0
  29. data/lib/newgistics/requests/cancel_shipment.rb +70 -0
  30. data/lib/newgistics/requests/post_inbound_return.rb +76 -0
  31. data/lib/newgistics/requests/post_shipment.rb +121 -0
  32. data/lib/newgistics/requests/search.rb +21 -0
  33. data/lib/newgistics/requests/update_shipment_contents.rb +74 -0
  34. data/lib/newgistics/response_handlers/cancel_shipment.rb +25 -0
  35. data/lib/newgistics/response_handlers/post_errors.rb +40 -0
  36. data/lib/newgistics/response_handlers/post_inbound_return.rb +25 -0
  37. data/lib/newgistics/response_handlers/post_shipment.rb +25 -0
  38. data/lib/newgistics/response_handlers/search.rb +57 -0
  39. data/lib/newgistics/response_handlers/update_shipment_contents.rb +25 -0
  40. data/lib/newgistics/return.rb +40 -0
  41. data/lib/newgistics/shipment.rb +79 -0
  42. data/lib/newgistics/shipment_cancellation.rb +24 -0
  43. data/lib/newgistics/shipment_update.rb +24 -0
  44. data/lib/newgistics/string_helper.rb +13 -0
  45. data/lib/newgistics/time_zone.rb +31 -0
  46. data/lib/newgistics/timestamp.rb +31 -0
  47. data/lib/newgistics/version.rb +3 -0
  48. data/lib/newgistics/warehouse.rb +14 -0
  49. data/lib/newgistics/xml_marshaller.rb +72 -0
  50. data/newgistics.gemspec +37 -0
  51. metadata +263 -0
@@ -0,0 +1,26 @@
1
+ module Newgistics
2
+ class Api
3
+ def get(request, response_handler)
4
+ response = connection.get(request.path, request.body)
5
+ response_handler.handle(response)
6
+ end
7
+
8
+ def post(request, response_handler)
9
+ response = connection.post(request.path, request.body)
10
+ response_handler.handle(response)
11
+ end
12
+
13
+ private
14
+
15
+ def connection
16
+ @connection ||= Faraday.new(url: api_base_url) do |faraday|
17
+ faraday.response :logger, Newgistics.logger, bodies: true
18
+ faraday.adapter Faraday.default_adapter
19
+ end
20
+ end
21
+
22
+ def api_base_url
23
+ Newgistics.configuration.api_base_url
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ module Newgistics
2
+ class Configuration
3
+ attr_reader :time_zone, :local_time_zone
4
+ attr_accessor :api_key, :api_base_url
5
+
6
+ def initialize
7
+ self.time_zone = "America/Denver"
8
+ self.local_time_zone = "UTC"
9
+ end
10
+
11
+ def api_base_url
12
+ @api_base_url ||= "https://apistaging.newgisticsfulfillment.com"
13
+ end
14
+
15
+ def time_zone=(name)
16
+ @time_zone = TimeZone.new(name)
17
+ end
18
+
19
+ def local_time_zone=(name)
20
+ @local_time_zone = TimeZone.new(name)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ module Newgistics
2
+ class Customer
3
+ include Virtus.model
4
+
5
+ attribute :company, String
6
+ attribute :first_name, String
7
+ attribute :last_name, String
8
+ attribute :email, String
9
+
10
+ attribute :address1, String
11
+ attribute :address2, String
12
+ attribute :city, String
13
+ attribute :state, String
14
+ attribute :country, String
15
+ attribute :phone, String
16
+ attribute :fax, String
17
+ attribute :zip, String
18
+ attribute :is_residential, Boolean
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ require 'logger'
2
+
3
+ module Newgistics
4
+ class DefaultLogger
5
+ def self.build
6
+ Logger.new(STDOUT).tap do |logger|
7
+ logger.level = Logger::INFO
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ module Newgistics
2
+ class QueryError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,9 @@
1
+ module Newgistics
2
+ class Fee
3
+ include Virtus.model
4
+
5
+ attribute :type, String
6
+ attribute :amount, Float
7
+ attribute :notes, String
8
+ end
9
+ end
@@ -0,0 +1,29 @@
1
+ module Newgistics
2
+ class InboundReturn
3
+ include Virtus.model
4
+
5
+ attribute :id, String
6
+ attribute :shipment_id, String
7
+ attribute :order_id, String
8
+ attribute :rma, String
9
+ attribute :comments, String
10
+ attribute :items, Array[Item]
11
+
12
+ attribute :errors, Array[String], default: []
13
+ attribute :warnings, Array[String], default: []
14
+
15
+ def self.where(conditions)
16
+ Query.build(
17
+ endpoint: '/inbound_returns.aspx',
18
+ element_selector: 'InboundReturns InboundReturn',
19
+ model_class: self
20
+ ).where(conditions)
21
+ end
22
+
23
+ def save
24
+ Requests::PostInboundReturn.new(self).perform
25
+
26
+ errors.empty?
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ module Newgistics
2
+ class Inventory
3
+ include Virtus.model
4
+
5
+ attribute :manifest_id, String
6
+ attribute :manifest_po, String
7
+ attribute :shipment_id, String
8
+ attribute :order_id, String
9
+ attribute :timestamp, Timestamp
10
+ attribute :sku, String
11
+ attribute :quantity, Integer
12
+ attribute :notes, String
13
+
14
+ def self.where(conditions)
15
+ Query.build(
16
+ endpoint: '/inventory_details.aspx',
17
+ element_selector: 'inventories inventory',
18
+ model_class: self
19
+ ).where(conditions)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ module Newgistics
2
+ class Item
3
+ include Virtus.model
4
+
5
+ attribute :id, String
6
+
7
+ attribute :sku, String
8
+ attribute :qty, Integer
9
+ attribute :is_gift_wrapped, Boolean
10
+ attribute :custom_fields, Hash
11
+
12
+ attribute :qty_returned, Integer
13
+ attribute :return_reason, String
14
+ attribute :qty_returned_to_stock, Integer
15
+ attribute :return_timestamp, Timestamp
16
+
17
+ attribute :reason, String
18
+ end
19
+ end
@@ -0,0 +1,32 @@
1
+ module Newgistics
2
+ class Order
3
+ include Virtus.model
4
+
5
+ attribute :id, String
6
+ attribute :warehouse_id, String
7
+ attribute :customer, Customer
8
+ attribute :drop_ship_info, Hash
9
+ attribute :order_date, Date
10
+ attribute :ship_method, String
11
+ attribute :info_line, String
12
+ attribute :requires_signature, Boolean
13
+ attribute :is_insured, Boolean
14
+ attribute :insured_value, Float
15
+ attribute :add_gift_wrap, Boolean
16
+ attribute :gift_message, String
17
+ attribute :hold_for_all_inventory, Boolean
18
+ attribute :custom_fields, Hash
19
+ attribute :allow_duplicate, Boolean
20
+ attribute :items, Array[Item]
21
+
22
+ attribute :errors, Array[String], default: []
23
+ attribute :warnings, Array[String], default: []
24
+ attribute :shipment_id, String
25
+
26
+ def save
27
+ Requests::PostShipment.new(self).perform
28
+
29
+ errors.empty?
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,30 @@
1
+ module Newgistics
2
+ class Product
3
+ include Virtus.model
4
+
5
+ attribute :id, String
6
+ attribute :sku, String
7
+
8
+ attribute :putaway_quantity, Integer
9
+ attribute :quarantine_quantity, Integer
10
+ attribute :damaged_quantity, Integer
11
+ attribute :expired_quantity, Integer
12
+ attribute :recalled_quantity, Integer
13
+ attribute :current_quantity, Integer
14
+ attribute :kitting_quantity, Integer
15
+ attribute :pending_quantity, Integer
16
+ attribute :available_quantity, Integer
17
+
18
+ def self.all
19
+ where({}).all
20
+ end
21
+
22
+ def self.where(conditions)
23
+ Query.build(
24
+ endpoint: '/inventory.aspx',
25
+ element_selector: 'products product',
26
+ model_class: self
27
+ ).where(conditions)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,43 @@
1
+ module Newgistics
2
+ class Query
3
+ include Enumerable
4
+
5
+ attr_reader :request, :response_handler, :conditions
6
+
7
+ def initialize(request, response_handler)
8
+ @request = request
9
+ @response_handler = response_handler
10
+ @conditions = {}
11
+ end
12
+
13
+ def self.build(endpoint:, element_selector:, model_class:)
14
+ request = Requests::Search.new(endpoint)
15
+ response_handler = ResponseHandlers::Search.new(
16
+ element_selector: element_selector,
17
+ model_class: model_class
18
+ )
19
+
20
+ new(request, response_handler)
21
+ end
22
+
23
+ def where(conditions)
24
+ @conditions.merge!(conditions)
25
+ self
26
+ end
27
+
28
+ def all
29
+ results.to_a
30
+ end
31
+
32
+ def each
33
+ results.each { |result| yield(result) }
34
+ end
35
+
36
+ private
37
+
38
+ def results
39
+ request.params = conditions
40
+ Newgistics.api.get(request, response_handler)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,70 @@
1
+ module Newgistics
2
+ module Requests
3
+ class CancelShipment
4
+ attr_reader :shipment_cancellation, :response_handler
5
+
6
+ def initialize(shipment_cancellation, response_handler: nil)
7
+ @shipment_cancellation = shipment_cancellation
8
+ @response_handler = response_handler || default_response_handler
9
+ end
10
+
11
+ def path
12
+ "/cancel_shipment.aspx?#{URI.encode_www_form(mandatory_params.merge(optional_params))}"
13
+ end
14
+
15
+ def body
16
+ xml_builder.to_xml
17
+ end
18
+
19
+ def perform
20
+ Newgistics.api.post(self, response_handler)
21
+ end
22
+
23
+ private
24
+
25
+ def default_response_handler
26
+ ResponseHandlers::CancelShipment.new(shipment_cancellation)
27
+ end
28
+
29
+ def xml_builder
30
+ Nokogiri::XML::Builder.new do |xml|
31
+ shipment_cancellation_xml(xml)
32
+ end
33
+ end
34
+
35
+ def shipment_cancellation_xml(xml)
36
+ xml.cancelShipment(mandatory_params) do
37
+ cancel_if_in_process(xml)
38
+ cancel_if_backorder(xml)
39
+ end
40
+ end
41
+
42
+ def api_key
43
+ Newgistics.configuration.api_key
44
+ end
45
+
46
+ def mandatory_params
47
+ {
48
+ apiKey: api_key,
49
+ shipmentID: shipment_cancellation.shipment_id,
50
+ orderID: shipment_cancellation.order_id
51
+ }.reject { |_k, v| v.nil? || v.empty? }
52
+ end
53
+
54
+ def cancel_if_in_process(xml)
55
+ xml.cancelIfInProcess shipment_cancellation.cancel_if_in_process
56
+ end
57
+
58
+ def cancel_if_backorder(xml)
59
+ xml.cancelIfBackorder shipment_cancellation.cancel_if_backorder
60
+ end
61
+
62
+ def optional_params
63
+ {
64
+ cancelIfInProcess: shipment_cancellation.cancel_if_in_process,
65
+ cancelIfBackorder: shipment_cancellation.cancel_if_backorder
66
+ }.reject { |_k, v| v.nil? }
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,76 @@
1
+ module Newgistics
2
+ module Requests
3
+ class PostInboundReturn
4
+ attr_reader :inbound_return, :response_handler
5
+
6
+ def initialize(inbound_return, response_handler: nil)
7
+ @inbound_return = inbound_return
8
+ @response_handler = response_handler || default_response_handler
9
+ end
10
+
11
+ def path
12
+ '/post_inbound_returns.aspx'
13
+ end
14
+
15
+ def body
16
+ xml_builder.to_xml
17
+ end
18
+
19
+ def perform
20
+ Newgistics.api.post(self, response_handler)
21
+ end
22
+
23
+ private
24
+
25
+ def default_response_handler
26
+ ResponseHandlers::PostInboundReturn.new(inbound_return)
27
+ end
28
+
29
+ def xml_builder
30
+ Nokogiri::XML::Builder.new do |xml|
31
+ returns_xml(xml)
32
+ end
33
+ end
34
+
35
+ def returns_xml(xml)
36
+ xml.Returns(apiKey: api_key) do
37
+ return_xml(inbound_return, xml)
38
+ end
39
+ end
40
+
41
+ def api_key
42
+ Newgistics.configuration.api_key
43
+ end
44
+
45
+ def return_xml(inbound_return, xml)
46
+ xml.Return(return_attributes(inbound_return)) do
47
+ xml.RMA inbound_return.rma
48
+ xml.Comments inbound_return.comments
49
+
50
+ items_xml(inbound_return.items, xml)
51
+ end
52
+ end
53
+
54
+ def return_attributes(inbound_return)
55
+ {
56
+ id: inbound_return.shipment_id,
57
+ orderID: inbound_return.order_id
58
+ }.reject { |_k, v| v.nil? || v.empty? }
59
+ end
60
+
61
+ def items_xml(items, xml)
62
+ xml.Items do
63
+ items.each { |item| item_xml(item, xml) }
64
+ end
65
+ end
66
+
67
+ def item_xml(item, xml)
68
+ xml.Item do
69
+ xml.SKU item.sku
70
+ xml.Qty item.qty
71
+ xml.Reason item.reason
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,121 @@
1
+ module Newgistics
2
+ module Requests
3
+ class PostShipment
4
+ attr_reader :order, :response_handler
5
+
6
+ def initialize(order, response_handler: nil)
7
+ @order = order
8
+ @response_handler = response_handler || default_response_handler
9
+ end
10
+
11
+ def path
12
+ '/post_shipments.aspx'
13
+ end
14
+
15
+ def body
16
+ xml_builder.to_xml
17
+ end
18
+
19
+ def perform
20
+ Newgistics.api.post(self, response_handler)
21
+ end
22
+
23
+ private
24
+
25
+ def default_response_handler
26
+ ResponseHandlers::PostShipment.new(order)
27
+ end
28
+
29
+ def xml_builder
30
+ Nokogiri::XML::Builder.new do |xml|
31
+ orders_xml(xml)
32
+ end
33
+ end
34
+
35
+ def orders_xml(xml)
36
+ xml.Orders(apiKey: api_key) do
37
+ order_xml(order, xml)
38
+ end
39
+ end
40
+
41
+ def api_key
42
+ Newgistics.configuration.api_key
43
+ end
44
+
45
+ def order_xml(order, xml)
46
+ xml.Order(orderID: order.id) do
47
+ xml.Warehouse(warehouseid: order.warehouse_id)
48
+ xml.ShipMethod order.ship_method
49
+ xml.InfoLine order.info_line
50
+ xml.RequiresSignature order.requires_signature
51
+ xml.IsInsured order.is_insured
52
+ xml.InsuredValue order.insured_value
53
+ xml.AddGiftWrap order.add_gift_wrap
54
+ xml.GiftMessage order.gift_message
55
+ xml.HoldForAllInventory order.hold_for_all_inventory
56
+ xml.AllowDuplicate order.allow_duplicate
57
+
58
+ order_date_xml(order, xml)
59
+ customer_xml(order.customer, xml)
60
+ drop_ship_info_xml(order, xml)
61
+ custom_fields_xml(order, xml)
62
+ items_xml(order.items, xml)
63
+ end
64
+ end
65
+
66
+ def order_date_xml(order, xml)
67
+ unless order.order_date.nil?
68
+ xml.OrderDate order.order_date.strftime('%m/%d/%Y')
69
+ end
70
+ end
71
+
72
+ def drop_ship_info_xml(object, xml)
73
+ xml.DropShipInfo do
74
+ object.drop_ship_info.each do |key, value|
75
+ xml.send StringHelper.camelize(key), value
76
+ end
77
+ end
78
+ end
79
+
80
+ def custom_fields_xml(object, xml)
81
+ xml.CustomFields do
82
+ object.custom_fields.each do |key, value|
83
+ xml.send StringHelper.camelize(key), value
84
+ end
85
+ end
86
+ end
87
+
88
+ def items_xml(items, xml)
89
+ xml.Items do
90
+ items.each { |item| item_xml(item, xml) }
91
+ end
92
+ end
93
+
94
+ def item_xml(item, xml)
95
+ xml.Item do
96
+ xml.SKU item.sku
97
+ xml.Qty item.qty
98
+ xml.IsGiftWrapped item.is_gift_wrapped
99
+ custom_fields_xml(item, xml)
100
+ end
101
+ end
102
+
103
+ def customer_xml(customer, xml)
104
+ xml.CustomerInfo do
105
+ xml.Company customer.company
106
+ xml.FirstName customer.first_name
107
+ xml.LastName customer.last_name
108
+ xml.Address1 customer.address1
109
+ xml.Address2 customer.address2
110
+ xml.City customer.city
111
+ xml.State customer.state
112
+ xml.Zip customer.zip
113
+ xml.Country customer.country
114
+ xml.Email customer.email
115
+ xml.Phone customer.phone
116
+ xml.IsResidential customer.is_residential
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end