newgistics 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +25 -0
- data/.env.sample +2 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.simplecov +4 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +187 -0
- data/Rakefile +6 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/lib/newgistics.rb +68 -0
- data/lib/newgistics/api.rb +26 -0
- data/lib/newgistics/configuration.rb +23 -0
- data/lib/newgistics/customer.rb +20 -0
- data/lib/newgistics/default_logger.rb +11 -0
- data/lib/newgistics/errors.rb +4 -0
- data/lib/newgistics/fee.rb +9 -0
- data/lib/newgistics/inbound_return.rb +29 -0
- data/lib/newgistics/inventory.rb +22 -0
- data/lib/newgistics/item.rb +19 -0
- data/lib/newgistics/order.rb +32 -0
- data/lib/newgistics/product.rb +30 -0
- data/lib/newgistics/query.rb +43 -0
- data/lib/newgistics/requests/cancel_shipment.rb +70 -0
- data/lib/newgistics/requests/post_inbound_return.rb +76 -0
- data/lib/newgistics/requests/post_shipment.rb +121 -0
- data/lib/newgistics/requests/search.rb +21 -0
- data/lib/newgistics/requests/update_shipment_contents.rb +74 -0
- data/lib/newgistics/response_handlers/cancel_shipment.rb +25 -0
- data/lib/newgistics/response_handlers/post_errors.rb +40 -0
- data/lib/newgistics/response_handlers/post_inbound_return.rb +25 -0
- data/lib/newgistics/response_handlers/post_shipment.rb +25 -0
- data/lib/newgistics/response_handlers/search.rb +57 -0
- data/lib/newgistics/response_handlers/update_shipment_contents.rb +25 -0
- data/lib/newgistics/return.rb +40 -0
- data/lib/newgistics/shipment.rb +79 -0
- data/lib/newgistics/shipment_cancellation.rb +24 -0
- data/lib/newgistics/shipment_update.rb +24 -0
- data/lib/newgistics/string_helper.rb +13 -0
- data/lib/newgistics/time_zone.rb +31 -0
- data/lib/newgistics/timestamp.rb +31 -0
- data/lib/newgistics/version.rb +3 -0
- data/lib/newgistics/warehouse.rb +14 -0
- data/lib/newgistics/xml_marshaller.rb +72 -0
- data/newgistics.gemspec +37 -0
- metadata +263 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
module Newgistics
|
2
|
+
module Requests
|
3
|
+
class Search
|
4
|
+
attr_reader :path, :params
|
5
|
+
|
6
|
+
def initialize(path)
|
7
|
+
@path = path
|
8
|
+
end
|
9
|
+
|
10
|
+
def params=(params)
|
11
|
+
@params = params.merge(key: Newgistics.configuration.api_key)
|
12
|
+
end
|
13
|
+
|
14
|
+
def body
|
15
|
+
params.
|
16
|
+
map { |k,v| [StringHelper.camelize(k, upcase_first: false), v] }.
|
17
|
+
to_h
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Newgistics
|
2
|
+
module Requests
|
3
|
+
class UpdateShipmentContents
|
4
|
+
attr_reader :shipment_update, :response_handler
|
5
|
+
|
6
|
+
def initialize(shipment_update, response_handler: nil)
|
7
|
+
@shipment_update = shipment_update
|
8
|
+
@response_handler = response_handler || default_response_handler
|
9
|
+
end
|
10
|
+
|
11
|
+
def path
|
12
|
+
'/update_shipment_contents.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::UpdateShipmentContents.new(shipment_update)
|
27
|
+
end
|
28
|
+
|
29
|
+
def xml_builder
|
30
|
+
Nokogiri::XML::Builder.new do |xml|
|
31
|
+
shipment_update_xml(xml)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def shipment_update_xml(xml)
|
36
|
+
xml.Shipment(shipment_update_attributes) do
|
37
|
+
add_items_xml(shipment_update.add_items, xml)
|
38
|
+
remove_items_xml(shipment_update.remove_items, xml)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def api_key
|
43
|
+
Newgistics.configuration.api_key
|
44
|
+
end
|
45
|
+
|
46
|
+
def shipment_update_attributes
|
47
|
+
{
|
48
|
+
apiKey: api_key,
|
49
|
+
id: shipment_update.id,
|
50
|
+
orderID: shipment_update.order_id
|
51
|
+
}.reject { |_k, v| v.nil? || v.empty? }
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_items_xml(items, xml)
|
55
|
+
xml.AddItems do
|
56
|
+
items.each { |item| item_xml(item, xml) }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def remove_items_xml(items, xml)
|
61
|
+
xml.RemoveItems do
|
62
|
+
items.each { |item| item_xml(item, xml) }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def item_xml(item, xml)
|
67
|
+
xml.Item do
|
68
|
+
xml.SKU item.sku
|
69
|
+
xml.Qty item.qty
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Newgistics
|
2
|
+
module ResponseHandlers
|
3
|
+
class CancelShipment
|
4
|
+
attr_reader :shipment
|
5
|
+
|
6
|
+
def initialize(shipment)
|
7
|
+
@shipment = shipment
|
8
|
+
end
|
9
|
+
|
10
|
+
def handle(response)
|
11
|
+
PostErrors.new(shipment).handle(response)
|
12
|
+
if shipment.errors.empty?
|
13
|
+
handle_successful_response(response)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def handle_successful_response(response)
|
20
|
+
xml = Nokogiri::XML(response.body)
|
21
|
+
shipment.success = xml.at_css('success').text
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Newgistics
|
2
|
+
module ResponseHandlers
|
3
|
+
class PostErrors
|
4
|
+
attr_reader :model
|
5
|
+
|
6
|
+
def initialize(model)
|
7
|
+
@model = model
|
8
|
+
end
|
9
|
+
|
10
|
+
def handle(response)
|
11
|
+
if response.success?
|
12
|
+
handle_successful_response(response)
|
13
|
+
else
|
14
|
+
handle_failed_response(response)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def handle_successful_response(response)
|
21
|
+
xml = Nokogiri::XML(response.body)
|
22
|
+
model.errors = error_nodes(xml).map(&:text)
|
23
|
+
model.warnings = warning_nodes(xml).map(&:text)
|
24
|
+
end
|
25
|
+
|
26
|
+
def handle_failed_response(response)
|
27
|
+
message = "API Error: #{response.status}"
|
28
|
+
model.errors << message
|
29
|
+
end
|
30
|
+
|
31
|
+
def error_nodes(xml)
|
32
|
+
xml.css('errors error') + xml.css('Errors Error')
|
33
|
+
end
|
34
|
+
|
35
|
+
def warning_nodes(xml)
|
36
|
+
xml.css('warnings warning') + xml.css('Warnings warning')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Newgistics
|
2
|
+
module ResponseHandlers
|
3
|
+
class PostInboundReturn
|
4
|
+
attr_reader :inbound_return
|
5
|
+
|
6
|
+
def initialize(inbound_return)
|
7
|
+
@inbound_return = inbound_return
|
8
|
+
end
|
9
|
+
|
10
|
+
def handle(response)
|
11
|
+
PostErrors.new(inbound_return).handle(response)
|
12
|
+
if inbound_return.errors.empty?
|
13
|
+
handle_successful_response(response)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def handle_successful_response(response)
|
20
|
+
xml = Nokogiri::XML(response.body)
|
21
|
+
inbound_return.id = xml.css('Return').first['ID']
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Newgistics
|
2
|
+
module ResponseHandlers
|
3
|
+
class PostShipment
|
4
|
+
attr_reader :order
|
5
|
+
|
6
|
+
def initialize(order)
|
7
|
+
@order = order
|
8
|
+
end
|
9
|
+
|
10
|
+
def handle(response)
|
11
|
+
PostErrors.new(order).handle(response)
|
12
|
+
if order.errors.empty?
|
13
|
+
handle_successful_response(response)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def handle_successful_response(response)
|
20
|
+
xml = Nokogiri::XML(response.body)
|
21
|
+
order.shipment_id = xml.css('shipment').first['id']
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Newgistics
|
2
|
+
module ResponseHandlers
|
3
|
+
class Search
|
4
|
+
attr_reader :element_selector, :model_class
|
5
|
+
|
6
|
+
def initialize(element_selector:, model_class:)
|
7
|
+
@element_selector = element_selector
|
8
|
+
@model_class = model_class
|
9
|
+
end
|
10
|
+
|
11
|
+
def handle(response)
|
12
|
+
if response.success?
|
13
|
+
handle_successful_response(response)
|
14
|
+
else
|
15
|
+
handle_failed_response(response)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def handle_successful_response(response)
|
22
|
+
xml = Nokogiri::XML(response.body)
|
23
|
+
errors = error_nodes(xml).map(&:text)
|
24
|
+
|
25
|
+
if errors.empty?
|
26
|
+
build_models(xml)
|
27
|
+
else
|
28
|
+
raise_error(errors.join(', '))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def error_nodes(xml)
|
33
|
+
xml.css('errors error') + xml.css('Errors Error')
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_models(xml)
|
37
|
+
xml.css(element_selector).map do |model_xml|
|
38
|
+
build_model(model_xml)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_model(model_xml)
|
43
|
+
model_class.new.tap do |model|
|
44
|
+
XmlMarshaller.new.assign_attributes(model, model_xml)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def handle_failed_response(response)
|
49
|
+
raise_error "API Error: #{response.status}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def raise_error(message)
|
53
|
+
raise QueryError.new(message)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Newgistics
|
2
|
+
module ResponseHandlers
|
3
|
+
class UpdateShipmentContents
|
4
|
+
attr_reader :shipment
|
5
|
+
|
6
|
+
def initialize(shipment)
|
7
|
+
@shipment = shipment
|
8
|
+
end
|
9
|
+
|
10
|
+
def handle(response)
|
11
|
+
PostErrors.new(shipment).handle(response)
|
12
|
+
if shipment.errors.empty?
|
13
|
+
handle_successful_response(response)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def handle_successful_response(response)
|
20
|
+
xml = Nokogiri::XML(response.body)
|
21
|
+
shipment.success = xml.at_css('success').text
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Newgistics
|
2
|
+
class Return
|
3
|
+
include Virtus.model
|
4
|
+
|
5
|
+
attribute :warehouse_id, String
|
6
|
+
attribute :shipment_id, String
|
7
|
+
attribute :order_id, String
|
8
|
+
|
9
|
+
attribute :status, String
|
10
|
+
attribute :name, String
|
11
|
+
attribute :company, String
|
12
|
+
attribute :address1, String
|
13
|
+
attribute :address2, String
|
14
|
+
attribute :city, String
|
15
|
+
attribute :state, String
|
16
|
+
attribute :postal_code, String
|
17
|
+
attribute :country, String
|
18
|
+
attribute :email, String
|
19
|
+
attribute :phone, String
|
20
|
+
attribute :carrier, String
|
21
|
+
attribute :tracking_number, String
|
22
|
+
attribute :postage_due, Float
|
23
|
+
attribute :rma_present, Boolean
|
24
|
+
attribute :rma_number, String
|
25
|
+
attribute :reason, String
|
26
|
+
attribute :condition, String
|
27
|
+
attribute :notes, String
|
28
|
+
attribute :is_archived, Boolean
|
29
|
+
attribute :timestamp, Timestamp
|
30
|
+
attribute :items, Array[Item]
|
31
|
+
|
32
|
+
def self.where(conditions)
|
33
|
+
Query.build(
|
34
|
+
endpoint: '/returns.aspx',
|
35
|
+
element_selector: 'Returns Return',
|
36
|
+
model_class: self
|
37
|
+
).where(conditions)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Newgistics
|
2
|
+
class Shipment
|
3
|
+
include Virtus.model
|
4
|
+
|
5
|
+
attribute :id, String
|
6
|
+
attribute :client_name, String
|
7
|
+
attribute :order_id, String
|
8
|
+
attribute :purchase_order, String
|
9
|
+
attribute :name, String
|
10
|
+
attribute :last_name, String
|
11
|
+
attribute :first_name, String
|
12
|
+
attribute :company, String
|
13
|
+
attribute :address1, String
|
14
|
+
attribute :address2, String
|
15
|
+
attribute :city, String
|
16
|
+
attribute :state, String
|
17
|
+
attribute :postal_code, String
|
18
|
+
attribute :country, String
|
19
|
+
attribute :email, String
|
20
|
+
attribute :phone, String
|
21
|
+
attribute :order_timestamp, Timestamp
|
22
|
+
attribute :received_timestamp, Timestamp
|
23
|
+
attribute :shipment_status, String
|
24
|
+
attribute :order_type, String
|
25
|
+
attribute :shipped_date, Timestamp
|
26
|
+
attribute :expected_delivery_date, Timestamp
|
27
|
+
attribute :delivered_timestamp, Timestamp
|
28
|
+
attribute :warehouse, Warehouse
|
29
|
+
attribute :ship_method, String
|
30
|
+
attribute :ship_method_code, String
|
31
|
+
attribute :tracking, String
|
32
|
+
attribute :tracking_url, String
|
33
|
+
attribute :items, Array[Item]
|
34
|
+
attribute :custom_fields, Hash
|
35
|
+
attribute :weight, Float
|
36
|
+
attribute :postage, Float
|
37
|
+
attribute :fees, Array[Fee]
|
38
|
+
|
39
|
+
def backordered?
|
40
|
+
shipment_status == 'BACKORDER'
|
41
|
+
end
|
42
|
+
|
43
|
+
def canceled?
|
44
|
+
shipment_status == 'CANCELED'
|
45
|
+
end
|
46
|
+
|
47
|
+
def on_hold?
|
48
|
+
%w(ONHOLD BADSKUHOLD BADADDRESS CNFHOLD INVHOLD).include? shipment_status
|
49
|
+
end
|
50
|
+
|
51
|
+
def received?
|
52
|
+
shipment_status == 'RECEIVED'
|
53
|
+
end
|
54
|
+
|
55
|
+
def printed?
|
56
|
+
shipment_status == 'PRINTED'
|
57
|
+
end
|
58
|
+
|
59
|
+
def shipped?
|
60
|
+
shipment_status == 'SHIPPED'
|
61
|
+
end
|
62
|
+
|
63
|
+
def returned?
|
64
|
+
shipment_status == 'RETURNED'
|
65
|
+
end
|
66
|
+
|
67
|
+
def verified?
|
68
|
+
shipment_status == 'VERIFIED'
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.where(conditions)
|
72
|
+
Query.build(
|
73
|
+
endpoint: '/shipments.aspx',
|
74
|
+
element_selector: 'Shipments Shipment',
|
75
|
+
model_class: self
|
76
|
+
).where(conditions)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Newgistics
|
2
|
+
class ShipmentCancellation
|
3
|
+
include Virtus.model
|
4
|
+
|
5
|
+
attribute :shipment_id, String
|
6
|
+
attribute :order_id, String
|
7
|
+
attribute :cancel_if_in_process, Boolean
|
8
|
+
attribute :cancel_if_backorder, Boolean
|
9
|
+
attribute :success, Boolean
|
10
|
+
|
11
|
+
attribute :errors, Array[String], default: []
|
12
|
+
attribute :warnings, Array[String], default: []
|
13
|
+
|
14
|
+
def success?
|
15
|
+
!!success
|
16
|
+
end
|
17
|
+
|
18
|
+
def save
|
19
|
+
Requests::CancelShipment.new(self).perform
|
20
|
+
|
21
|
+
errors.empty? && success?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|