solidus_backtracs 2.2.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.
- checksums.yaml +7 -0
- data/.bundle/config +2 -0
- data/.circleci/config.yml +41 -0
- data/.gem_release.yml +5 -0
- data/.github/stale.yml +17 -0
- data/.github_changelog_generator +2 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/.rubocop.yml +14 -0
- data/.rubocop_todo.yml +40 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile +33 -0
- data/LICENSE +26 -0
- data/README.md +208 -0
- data/Rakefile +6 -0
- data/app/assets/javascripts/spree/backend/solidus_backtracs.js +2 -0
- data/app/assets/javascripts/spree/frontend/solidus_backtracs.js +2 -0
- data/app/assets/stylesheets/spree/backend/solidus_backtracs.css +4 -0
- data/app/assets/stylesheets/spree/frontend/solidus_backtracs.css +4 -0
- data/app/controllers/spree/backtracs_controller.rb +46 -0
- data/app/decorators/models/solidus_backtracs/spree/shipment_decorator.rb +33 -0
- data/app/helpers/solidus_backtracs/export_helper.rb +52 -0
- data/app/jobs/solidus_backtracs/api/schedule_shipment_syncs_job.rb +28 -0
- data/app/jobs/solidus_backtracs/api/sync_shipment_job.rb +17 -0
- data/app/jobs/solidus_backtracs/api/sync_shipments_job.rb +41 -0
- data/app/queries/solidus_backtracs/shipment/between_query.rb +14 -0
- data/app/queries/solidus_backtracs/shipment/exportable_query.rb +24 -0
- data/app/queries/solidus_backtracs/shipment/pending_api_sync_query.rb +51 -0
- data/app/views/spree/backtracs/export.xml.builder +58 -0
- data/bin/console +17 -0
- data/bin/rails +7 -0
- data/bin/rails-engine +13 -0
- data/bin/rails-sandbox +16 -0
- data/bin/rake +7 -0
- data/bin/sandbox +86 -0
- data/bin/setup +8 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +6 -0
- data/db/migrate/20210220093010_add_backtracs_api_sync_fields.rb +8 -0
- data/lib/generators/solidus_backtracs/install/install_generator.rb +27 -0
- data/lib/generators/solidus_backtracs/install/templates/initializer.rb +91 -0
- data/lib/solidus_backtracs/api/batch_syncer.rb +45 -0
- data/lib/solidus_backtracs/api/client.rb +36 -0
- data/lib/solidus_backtracs/api/rate_limited_error.rb +23 -0
- data/lib/solidus_backtracs/api/request_error.rb +33 -0
- data/lib/solidus_backtracs/api/request_runner.rb +87 -0
- data/lib/solidus_backtracs/api/shipment_serializer.rb +103 -0
- data/lib/solidus_backtracs/api/threshold_verifier.rb +28 -0
- data/lib/solidus_backtracs/configuration.rb +62 -0
- data/lib/solidus_backtracs/engine.rb +19 -0
- data/lib/solidus_backtracs/errors.rb +23 -0
- data/lib/solidus_backtracs/shipment_notice.rb +58 -0
- data/lib/solidus_backtracs/testing_support/factories.rb +4 -0
- data/lib/solidus_backtracs/version.rb +5 -0
- data/lib/solidus_backtracs.rb +16 -0
- data/solidus_shipstation.gemspec +39 -0
- data/spec/controllers/spree/backtracs_controller_spec.rb +103 -0
- data/spec/fixtures/backtracs_xml_schema.xsd +171 -0
- data/spec/jobs/solidus_backtracs/api/schedule_shipment_syncs_job_spec.rb +32 -0
- data/spec/jobs/solidus_backtracs/api/sync_shipments_job_spec.rb +102 -0
- data/spec/lib/solidus_backtracs/api/batch_syncer_spec.rb +228 -0
- data/spec/lib/solidus_backtracs/api/client_spec.rb +120 -0
- data/spec/lib/solidus_backtracs/api/rate_limited_error_spec.rb +21 -0
- data/spec/lib/solidus_backtracs/api/request_error_spec.rb +20 -0
- data/spec/lib/solidus_backtracs/api/request_runner_spec.rb +65 -0
- data/spec/lib/solidus_backtracs/api/shipment_serializer_spec.rb +25 -0
- data/spec/lib/solidus_backtracs/api/threshold_verifier_spec.rb +61 -0
- data/spec/lib/solidus_backtracs/shipment_notice_spec.rb +111 -0
- data/spec/lib/solidus_backtracs_spec.rb +9 -0
- data/spec/models/spree/shipment_spec.rb +49 -0
- data/spec/queries/solidus_backtracs/shipment/between_query_spec.rb +53 -0
- data/spec/queries/solidus_backtracs/shipment/exportable_query_spec.rb +53 -0
- data/spec/queries/solidus_backtracs/shipment/pending_api_sync_query_spec.rb +37 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/support/configuration_helper.rb +13 -0
- data/spec/support/controllers.rb +1 -0
- data/spec/support/webmock.rb +3 -0
- data/spec/support/xsd.rb +5 -0
- metadata +248 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "uri"
|
3
|
+
require "net/http"
|
4
|
+
|
5
|
+
module SolidusBacktracs
|
6
|
+
module Api
|
7
|
+
class RequestRunner
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@username = SolidusBacktracs.configuration.authentication_username
|
11
|
+
@password = SolidusBacktracs.configuration.authentication_password
|
12
|
+
@api_base = SolidusBacktracs.configuration.api_base
|
13
|
+
end
|
14
|
+
|
15
|
+
def authenticated_call(method: nil, path: nil, serializer: nil, shipment: nil)
|
16
|
+
unless @username.present? || @password.present? || @api_base.present?
|
17
|
+
raise "Credentials not defined for Authentication"
|
18
|
+
end
|
19
|
+
|
20
|
+
Rails.cache.fetch("backtracks_cache_key", expires_in: 1.hour) do
|
21
|
+
@response = self.call(method: :get, path: "/webservices/user/Authentication.asmx/Login?sUserName=#{@username}&sPassword=#{@password}")
|
22
|
+
end
|
23
|
+
|
24
|
+
authenticted = parse_authentication_response(@response, "Result")
|
25
|
+
|
26
|
+
if authenticted == 'false'
|
27
|
+
raise RequestError.from_response(@response)
|
28
|
+
else
|
29
|
+
sguid = parse_authentication_response(@response, "Message")
|
30
|
+
params = serializer.call(shipment, sguid)
|
31
|
+
|
32
|
+
rma_response = call(method: :post, path: path, params: params)
|
33
|
+
sync_shipment(shipment, rma_response)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(method: nil, path: nil, params: {})
|
38
|
+
doc = {}
|
39
|
+
if params.present?
|
40
|
+
doc = Nokogiri::XML(params.to_s)
|
41
|
+
end
|
42
|
+
response = HTTParty.send(
|
43
|
+
method,
|
44
|
+
URI.join(@api_base, path),
|
45
|
+
body: doc.to_xml,
|
46
|
+
http_proxyaddr: SolidusBacktracs.configuration.proxy_address,
|
47
|
+
http_proxyport: SolidusBacktracs.configuration.proxy_port,
|
48
|
+
http_proxyuser: SolidusBacktracs.configuration.proxy_username,
|
49
|
+
http_proxypass: SolidusBacktracs.configuration.proxy_password,
|
50
|
+
headers: {
|
51
|
+
'Content-Type' => 'text/xml',
|
52
|
+
},
|
53
|
+
)
|
54
|
+
|
55
|
+
case response.code.to_s
|
56
|
+
when /2\d{2}/
|
57
|
+
response
|
58
|
+
when '429'
|
59
|
+
raise RateLimitedError.from_response(response)
|
60
|
+
else
|
61
|
+
raise RequestError.from_response(response)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse_authentication_response(response, type)
|
66
|
+
response.dig("AuthenticationResponse", type)
|
67
|
+
end
|
68
|
+
|
69
|
+
def sync_shipment(shipment, response)
|
70
|
+
result = response.dig("Envelope", "Body", "CreateNewResponse", "CreateNewResult", "Result")
|
71
|
+
if result == 'true'
|
72
|
+
shipment.update_column(:backtracs_synced_at, Time.zone.now)
|
73
|
+
|
74
|
+
::Spree::Event.fire(
|
75
|
+
'solidus_backtracs.api.sync_completed',
|
76
|
+
shipment: shipment
|
77
|
+
)
|
78
|
+
else
|
79
|
+
::Spree::Event.fire(
|
80
|
+
'solidus_backtracs.api.sync_failed',
|
81
|
+
shipment: shipment
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBacktracs
|
4
|
+
module Api
|
5
|
+
class ShipmentSerializer
|
6
|
+
|
7
|
+
def initialize(shipment:)
|
8
|
+
@shipment = shipment
|
9
|
+
@config = SolidusBacktracs.config
|
10
|
+
@property_id = ::Spree::Property.find_by(name: SolidusBacktracs.config.default_property_name)&.id
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(sguid: nil)
|
14
|
+
order = @shipment.order
|
15
|
+
user = @shipment.user
|
16
|
+
|
17
|
+
xml = Builder::XmlMarkup.new
|
18
|
+
xml.instruct!(:xml, :encoding => "UTF-8")
|
19
|
+
|
20
|
+
xml.soap(:Envelope, {"xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance", "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema", "xmlns:soap" => "http://schemas.xmlsoap.org/soap/envelope/"}) do
|
21
|
+
xml.soap :Body do
|
22
|
+
xml.CreateNew({"xmlns" => "http://bactracs.andlor.com/rmaservice"}) do
|
23
|
+
xml.sGuid sguid
|
24
|
+
xml.NewRMA {
|
25
|
+
xml.RMANumber @shipment.number
|
26
|
+
xml.RMATypeName @config.default_rma_type
|
27
|
+
xml.RMASubTypeName
|
28
|
+
xml.CustomerRef
|
29
|
+
xml.InboundShippingPriority
|
30
|
+
xml.InboundTrackingNumber @shipment.tracking
|
31
|
+
|
32
|
+
xml.Ship {
|
33
|
+
xml.Carrier @config.default_carrier
|
34
|
+
xml.ShipMethod @config.default_ship_method
|
35
|
+
xml.ShipDate @shipment.created_at.strftime(SolidusBacktracs::ExportHelper::BACTRACS_DATE_FORMAT)
|
36
|
+
xml.TrackingNumber @shipment.tracking
|
37
|
+
xml.SerialNumber @shipment.number
|
38
|
+
xml.Ud1
|
39
|
+
}
|
40
|
+
xml.Customer {
|
41
|
+
SolidusBacktracs::ExportHelper.backtracs_address(xml, order, :ship)
|
42
|
+
SolidusBacktracs::ExportHelper.backtracs_address(xml, order, :bill)
|
43
|
+
}
|
44
|
+
xml.Rep {
|
45
|
+
xml.Code
|
46
|
+
xml.Name user.full_name
|
47
|
+
xml.Email user.email
|
48
|
+
}
|
49
|
+
|
50
|
+
xml.RMALines {
|
51
|
+
@shipment.line_items.each do |line|
|
52
|
+
product = line.product
|
53
|
+
if product.respond_to?(:assembly?) && product.assembly?
|
54
|
+
product.parts.each do |part|
|
55
|
+
next unless part.product.product_properties.where(property_id: @property_id).present?
|
56
|
+
line_items_xml(xml: xml, line_item: line, variant: part, order: order)
|
57
|
+
end
|
58
|
+
else
|
59
|
+
line_items_xml(xml: xml, line_item: line, variant: line.variant, order: order)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
}
|
63
|
+
xml.OrderDate order.completed_at.strftime(SolidusBacktracs::ExportHelper::BACTRACS_DATE_FORMAT)
|
64
|
+
xml.CreateDate @shipment.created_at.strftime(SolidusBacktracs::ExportHelper::BACTRACS_DATE_FORMAT)
|
65
|
+
xml.Status @config.default_status
|
66
|
+
xml.RMAId @shipment.id
|
67
|
+
xml.ClientGuid
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
xml
|
73
|
+
end
|
74
|
+
|
75
|
+
def line_items_xml(xml: nil, line_item: nil, variant: nil, order: nil)
|
76
|
+
shipment_notice = @shipment.shipment_notice
|
77
|
+
xml.RMALine {
|
78
|
+
xml.DFItem find_sku_variant(variant)
|
79
|
+
xml.DFModelNum find_sku_variant(variant)
|
80
|
+
xml.DFCategory
|
81
|
+
xml.DFCategoryDescription
|
82
|
+
xml.DFQuantity line_item.quantity
|
83
|
+
xml.DFUnitPrice line_item.price
|
84
|
+
xml.DFSerialNumbers
|
85
|
+
xml.Ud1s
|
86
|
+
xml.CurrentWarranties
|
87
|
+
xml.DFComments
|
88
|
+
xml.DFStatus @shipment.state
|
89
|
+
xml.PurchaseDate order.completed_at.strftime(SolidusBacktracs::ExportHelper::BACTRACS_DATE_FORMAT)
|
90
|
+
xml.ServiceProvider shipment_notice&.service
|
91
|
+
xml.WarrantyRepair
|
92
|
+
xml.RMALineTest
|
93
|
+
xml.InboundShipWeight variant.weight.to_f
|
94
|
+
xml.RPLocation @config.default_rp_location
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
def find_sku_variant(variant)
|
99
|
+
@config.sku_map[variant.sku].present? ? @config.sku_map[variant.sku] : variant.sku
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBacktracs
|
4
|
+
module Api
|
5
|
+
class ThresholdVerifier
|
6
|
+
class << self
|
7
|
+
def call(shipment)
|
8
|
+
return false unless shipment.order.completed?
|
9
|
+
|
10
|
+
!!(shipment_requires_creation?(shipment) || shipment_requires_update?(shipment))
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def shipment_requires_creation?(shipment)
|
16
|
+
shipment.backtracs_synced_at.nil? &&
|
17
|
+
Time.zone.now - shipment.order.updated_at < SolidusBacktracs.config.api_sync_threshold
|
18
|
+
end
|
19
|
+
|
20
|
+
def shipment_requires_update?(shipment)
|
21
|
+
shipment.backtracs_synced_at &&
|
22
|
+
shipment.backtracs_synced_at < shipment.order.updated_at &&
|
23
|
+
Time.zone.now - shipment.order.updated_at < SolidusBacktracs.config.api_sync_threshold
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBacktracs
|
4
|
+
class Configuration
|
5
|
+
attr_accessor(
|
6
|
+
:webhook_username,
|
7
|
+
:webhook_password,
|
8
|
+
:weight_units,
|
9
|
+
:ssl_encrypted,
|
10
|
+
:capture_at_notification,
|
11
|
+
:export_canceled_shipments,
|
12
|
+
:api_batch_size,
|
13
|
+
:api_sync_threshold,
|
14
|
+
:api_shipment_serializer,
|
15
|
+
:api_key,
|
16
|
+
:api_secret,
|
17
|
+
:api_shipment_matcher,
|
18
|
+
:error_handler,
|
19
|
+
:shipment_notice_class,
|
20
|
+
:authentication_username,
|
21
|
+
:authentication_password,
|
22
|
+
:api_base,
|
23
|
+
:proxy_address,
|
24
|
+
:proxy_port,
|
25
|
+
:proxy_username,
|
26
|
+
:proxy_password,
|
27
|
+
:default_carrier,
|
28
|
+
:default_ship_method,
|
29
|
+
:default_rp_location,
|
30
|
+
:default_status,
|
31
|
+
:default_property_name,
|
32
|
+
:sku_map,
|
33
|
+
:default_rma_type,
|
34
|
+
:shippable_skus
|
35
|
+
)
|
36
|
+
|
37
|
+
def initialize
|
38
|
+
@api_batch_size = 100
|
39
|
+
@api_sync_threshold = 7.days
|
40
|
+
@error_handler = ->(_error, _extra = {}) {
|
41
|
+
Rails.logger.error "#{error.inspect} (#{extra.inspect})"
|
42
|
+
}
|
43
|
+
@api_shipment_matcher = proc do |backtracs_order, shipments|
|
44
|
+
shipments.find { |shipment| shipment.number == backtracs_order['orderNumber'] }
|
45
|
+
end
|
46
|
+
|
47
|
+
@shipment_notice_class = 'SolidusBacktracs::ShipmentNotice'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class << self
|
52
|
+
def configuration
|
53
|
+
@configuration ||= Configuration.new
|
54
|
+
end
|
55
|
+
|
56
|
+
alias config configuration
|
57
|
+
|
58
|
+
def configure
|
59
|
+
yield configuration
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'solidus_core'
|
4
|
+
require 'solidus_support'
|
5
|
+
|
6
|
+
module SolidusBacktracs
|
7
|
+
class Engine < Rails::Engine
|
8
|
+
include SolidusSupport::EngineExtensions
|
9
|
+
|
10
|
+
isolate_namespace ::Spree
|
11
|
+
|
12
|
+
engine_name 'solidus_backtracs'
|
13
|
+
|
14
|
+
# use rspec for tests
|
15
|
+
config.generators do |g|
|
16
|
+
g.test_framework :rspec
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBacktracs
|
4
|
+
class Error < StandardError; end
|
5
|
+
|
6
|
+
class OrderNotPaidError < Error
|
7
|
+
def initialize(order, *args)
|
8
|
+
super("Order #{order.number} is not paid and capture_at_notification is false", *args)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class ShipmentNotFoundError < Error
|
13
|
+
def initialize(shipment_number, *args)
|
14
|
+
super("Could not find shipment with number #{shipment_number}", *args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class PaymentError < Error
|
19
|
+
def initialize(payment, *args)
|
20
|
+
super("Could not process payment #{payment.id}", *args)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBacktracs
|
4
|
+
class ShipmentNotice
|
5
|
+
attr_reader :shipment_number, :shipment_tracking
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def from_payload(params)
|
9
|
+
new(
|
10
|
+
shipment_number: params[:order_number],
|
11
|
+
shipment_tracking: params[:tracking_number],
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(shipment_number:, shipment_tracking:)
|
17
|
+
@shipment_number = shipment_number
|
18
|
+
@shipment_tracking = shipment_tracking
|
19
|
+
end
|
20
|
+
|
21
|
+
def apply
|
22
|
+
unless shipment
|
23
|
+
raise ShipmentNotFoundError, shipment
|
24
|
+
end
|
25
|
+
|
26
|
+
process_payment
|
27
|
+
ship_shipment
|
28
|
+
|
29
|
+
shipment
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def shipment
|
35
|
+
@shipment ||= ::Spree::Shipment.find_by(number: shipment_number)
|
36
|
+
end
|
37
|
+
|
38
|
+
def process_payment
|
39
|
+
return if shipment.order.paid?
|
40
|
+
|
41
|
+
unless SolidusBacktracs.configuration.capture_at_notification
|
42
|
+
raise OrderNotPaidError, shipment.order
|
43
|
+
end
|
44
|
+
|
45
|
+
shipment.order.payments.pending.each do |payment|
|
46
|
+
payment.capture!
|
47
|
+
rescue ::Spree::Core::GatewayError
|
48
|
+
raise PaymentError, payment
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def ship_shipment
|
53
|
+
shipment.update!(tracking: shipment_tracking)
|
54
|
+
shipment.ship! if shipment.can_ship?
|
55
|
+
shipment.order.recalculate
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'httparty'
|
4
|
+
|
5
|
+
require 'solidus_backtracs/api/batch_syncer'
|
6
|
+
require 'solidus_backtracs/api/request_runner'
|
7
|
+
require 'solidus_backtracs/api/client'
|
8
|
+
require 'solidus_backtracs/api/request_error'
|
9
|
+
require 'solidus_backtracs/api/rate_limited_error'
|
10
|
+
require 'solidus_backtracs/api/shipment_serializer'
|
11
|
+
require 'solidus_backtracs/api/threshold_verifier'
|
12
|
+
require 'solidus_backtracs/configuration'
|
13
|
+
require 'solidus_backtracs/errors'
|
14
|
+
require 'solidus_backtracs/shipment_notice'
|
15
|
+
require 'solidus_backtracs/version'
|
16
|
+
require 'solidus_backtracs/engine'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/solidus_backtracs/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'solidus_backtracs'
|
7
|
+
spec.version = SolidusBacktracs::VERSION
|
8
|
+
spec.authors = ['Stephen Puiszis']
|
9
|
+
spec.email = 'steve@tablexi.com'
|
10
|
+
|
11
|
+
spec.summary = 'A Solidus extension for integrating the Backtracs API.'
|
12
|
+
spec.homepage = 'https://github.com/solidusio-contrib/solidus_backtracs'
|
13
|
+
spec.license = 'BSD-3-Clause'
|
14
|
+
|
15
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
16
|
+
spec.metadata['source_code_uri'] = 'https://github.com/solidusio-contrib/solidus_backtracs'
|
17
|
+
spec.metadata['changelog_uri'] = 'https://github.com/solidusio-contrib/solidus_backtracs/blob/master/CHANGELOG.md'
|
18
|
+
|
19
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.5')
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
files = Dir.chdir(__dir__) { `git ls-files -z`.split("\x0") }
|
24
|
+
|
25
|
+
spec.files = files.grep_v(%r{^(test|spec|features)/})
|
26
|
+
spec.test_files = files.grep(%r{^(test|spec|features)/})
|
27
|
+
spec.bindir = "exe"
|
28
|
+
spec.executables = files.grep(%r{^exe/}) { |f| File.basename(f) }
|
29
|
+
spec.require_paths = ["lib"]
|
30
|
+
|
31
|
+
spec.add_dependency 'httparty', '~> 0.18'
|
32
|
+
spec.add_dependency 'solidus_core', ['>= 2.0.0', '< 4']
|
33
|
+
spec.add_dependency 'solidus_support', '~> 0.5'
|
34
|
+
|
35
|
+
spec.add_development_dependency 'rails-controller-testing'
|
36
|
+
spec.add_development_dependency 'rspec-xsd'
|
37
|
+
spec.add_development_dependency 'solidus_dev_support', '~> 2.5'
|
38
|
+
spec.add_development_dependency 'webmock'
|
39
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Spree::BacktracsController do
|
4
|
+
render_views
|
5
|
+
|
6
|
+
describe '#export' do
|
7
|
+
context 'when the authentication is invalid' do
|
8
|
+
it 'returns an error error' do
|
9
|
+
get :export, params: { format: 'xml' }
|
10
|
+
|
11
|
+
expect(response.status).to eq(401)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when the authentication is valid' do
|
16
|
+
it 'responds with 200 OK' do
|
17
|
+
stub_backtracs_auth
|
18
|
+
create(:order_ready_to_ship)
|
19
|
+
|
20
|
+
get :export,
|
21
|
+
params: {
|
22
|
+
start_date: 1.day.ago.strftime('%m/%d/%Y %H:%M'),
|
23
|
+
end_date: 1.day.from_now.strftime('%m/%d/%Y %H:%M'),
|
24
|
+
format: 'xml'
|
25
|
+
}
|
26
|
+
|
27
|
+
expect(response.status).to eq(200)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'generates Backtracs-compliant XML' do
|
31
|
+
stub_backtracs_auth
|
32
|
+
create(:order_ready_to_ship)
|
33
|
+
|
34
|
+
get :export, params: {
|
35
|
+
start_date: 1.day.ago.strftime('%m/%d/%Y %H:%M'),
|
36
|
+
end_date: 1.day.from_now.strftime('%m/%d/%Y %H:%M'),
|
37
|
+
format: 'xml'
|
38
|
+
}
|
39
|
+
|
40
|
+
expect(response.body).to pass_validation('spec/fixtures/backtracs_xml_schema.xsd')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#shipnotify' do
|
46
|
+
context 'when the authentication is valid' do
|
47
|
+
context 'when the shipment can be found' do
|
48
|
+
it 'responds with 200 OK' do
|
49
|
+
stub_backtracs_auth
|
50
|
+
shipment = create(:order_ready_to_ship).shipments.first
|
51
|
+
|
52
|
+
post :shipnotify, params: {
|
53
|
+
order_number: shipment.number,
|
54
|
+
tracking_number: '123456',
|
55
|
+
format: 'xml',
|
56
|
+
}
|
57
|
+
shipment.reload
|
58
|
+
|
59
|
+
expect(response.status).to eq(200)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'updates the shipment' do
|
63
|
+
stub_backtracs_auth
|
64
|
+
shipment = create(:order_ready_to_ship).shipments.first
|
65
|
+
|
66
|
+
post :shipnotify, params: {
|
67
|
+
order_number: shipment.number,
|
68
|
+
tracking_number: '123456',
|
69
|
+
format: 'xml',
|
70
|
+
}
|
71
|
+
shipment.reload
|
72
|
+
|
73
|
+
expect(shipment).to have_attributes(
|
74
|
+
tracking: '123456',
|
75
|
+
state: 'shipped',
|
76
|
+
shipped_at: an_instance_of(ActiveSupport::TimeWithZone),
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'when the shipment cannot be found' do
|
82
|
+
it 'responds with 400 Bad Request' do
|
83
|
+
stub_backtracs_auth
|
84
|
+
shipment = create(:order_ready_to_ship).shipments.first
|
85
|
+
|
86
|
+
post :shipnotify, params: {
|
87
|
+
order_number: 'ABC123',
|
88
|
+
tracking_number: '123456',
|
89
|
+
format: 'xml',
|
90
|
+
}
|
91
|
+
shipment.reload
|
92
|
+
|
93
|
+
expect(response.status).to eq(400)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def stub_backtracs_auth(username = 'mario', password = 'lemieux')
|
100
|
+
stub_configuration(username: username, password: password)
|
101
|
+
request.headers['Authorization'] = ActionController::HttpAuthentication::Basic.encode_credentials(username, password)
|
102
|
+
end
|
103
|
+
end
|