newgistics 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.
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