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,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