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.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.bundle/config +2 -0
  3. data/.circleci/config.yml +41 -0
  4. data/.gem_release.yml +5 -0
  5. data/.github/stale.yml +17 -0
  6. data/.github_changelog_generator +2 -0
  7. data/.gitignore +20 -0
  8. data/.rspec +2 -0
  9. data/.rubocop.yml +14 -0
  10. data/.rubocop_todo.yml +40 -0
  11. data/CHANGELOG.md +2 -0
  12. data/Gemfile +33 -0
  13. data/LICENSE +26 -0
  14. data/README.md +208 -0
  15. data/Rakefile +6 -0
  16. data/app/assets/javascripts/spree/backend/solidus_backtracs.js +2 -0
  17. data/app/assets/javascripts/spree/frontend/solidus_backtracs.js +2 -0
  18. data/app/assets/stylesheets/spree/backend/solidus_backtracs.css +4 -0
  19. data/app/assets/stylesheets/spree/frontend/solidus_backtracs.css +4 -0
  20. data/app/controllers/spree/backtracs_controller.rb +46 -0
  21. data/app/decorators/models/solidus_backtracs/spree/shipment_decorator.rb +33 -0
  22. data/app/helpers/solidus_backtracs/export_helper.rb +52 -0
  23. data/app/jobs/solidus_backtracs/api/schedule_shipment_syncs_job.rb +28 -0
  24. data/app/jobs/solidus_backtracs/api/sync_shipment_job.rb +17 -0
  25. data/app/jobs/solidus_backtracs/api/sync_shipments_job.rb +41 -0
  26. data/app/queries/solidus_backtracs/shipment/between_query.rb +14 -0
  27. data/app/queries/solidus_backtracs/shipment/exportable_query.rb +24 -0
  28. data/app/queries/solidus_backtracs/shipment/pending_api_sync_query.rb +51 -0
  29. data/app/views/spree/backtracs/export.xml.builder +58 -0
  30. data/bin/console +17 -0
  31. data/bin/rails +7 -0
  32. data/bin/rails-engine +13 -0
  33. data/bin/rails-sandbox +16 -0
  34. data/bin/rake +7 -0
  35. data/bin/sandbox +86 -0
  36. data/bin/setup +8 -0
  37. data/config/locales/en.yml +5 -0
  38. data/config/routes.rb +6 -0
  39. data/db/migrate/20210220093010_add_backtracs_api_sync_fields.rb +8 -0
  40. data/lib/generators/solidus_backtracs/install/install_generator.rb +27 -0
  41. data/lib/generators/solidus_backtracs/install/templates/initializer.rb +91 -0
  42. data/lib/solidus_backtracs/api/batch_syncer.rb +45 -0
  43. data/lib/solidus_backtracs/api/client.rb +36 -0
  44. data/lib/solidus_backtracs/api/rate_limited_error.rb +23 -0
  45. data/lib/solidus_backtracs/api/request_error.rb +33 -0
  46. data/lib/solidus_backtracs/api/request_runner.rb +87 -0
  47. data/lib/solidus_backtracs/api/shipment_serializer.rb +103 -0
  48. data/lib/solidus_backtracs/api/threshold_verifier.rb +28 -0
  49. data/lib/solidus_backtracs/configuration.rb +62 -0
  50. data/lib/solidus_backtracs/engine.rb +19 -0
  51. data/lib/solidus_backtracs/errors.rb +23 -0
  52. data/lib/solidus_backtracs/shipment_notice.rb +58 -0
  53. data/lib/solidus_backtracs/testing_support/factories.rb +4 -0
  54. data/lib/solidus_backtracs/version.rb +5 -0
  55. data/lib/solidus_backtracs.rb +16 -0
  56. data/solidus_shipstation.gemspec +39 -0
  57. data/spec/controllers/spree/backtracs_controller_spec.rb +103 -0
  58. data/spec/fixtures/backtracs_xml_schema.xsd +171 -0
  59. data/spec/jobs/solidus_backtracs/api/schedule_shipment_syncs_job_spec.rb +32 -0
  60. data/spec/jobs/solidus_backtracs/api/sync_shipments_job_spec.rb +102 -0
  61. data/spec/lib/solidus_backtracs/api/batch_syncer_spec.rb +228 -0
  62. data/spec/lib/solidus_backtracs/api/client_spec.rb +120 -0
  63. data/spec/lib/solidus_backtracs/api/rate_limited_error_spec.rb +21 -0
  64. data/spec/lib/solidus_backtracs/api/request_error_spec.rb +20 -0
  65. data/spec/lib/solidus_backtracs/api/request_runner_spec.rb +65 -0
  66. data/spec/lib/solidus_backtracs/api/shipment_serializer_spec.rb +25 -0
  67. data/spec/lib/solidus_backtracs/api/threshold_verifier_spec.rb +61 -0
  68. data/spec/lib/solidus_backtracs/shipment_notice_spec.rb +111 -0
  69. data/spec/lib/solidus_backtracs_spec.rb +9 -0
  70. data/spec/models/spree/shipment_spec.rb +49 -0
  71. data/spec/queries/solidus_backtracs/shipment/between_query_spec.rb +53 -0
  72. data/spec/queries/solidus_backtracs/shipment/exportable_query_spec.rb +53 -0
  73. data/spec/queries/solidus_backtracs/shipment/pending_api_sync_query_spec.rb +37 -0
  74. data/spec/spec_helper.rb +31 -0
  75. data/spec/support/configuration_helper.rb +13 -0
  76. data/spec/support/controllers.rb +1 -0
  77. data/spec/support/webmock.rb +3 -0
  78. data/spec/support/xsd.rb +5 -0
  79. metadata +248 -0
@@ -0,0 +1,20 @@
1
+ RSpec.describe SolidusBacktracs::Api::RequestError do
2
+ describe '.from_response' do
3
+ it 'extracts the status code, body and headers from the response' do
4
+ response = instance_double(
5
+ 'HTTParty::Response',
6
+ code: 500,
7
+ headers: { 'Key' => 'Value' },
8
+ body: '{ "message": "Internal Server Error" }',
9
+ )
10
+
11
+ error = described_class.from_response(response)
12
+
13
+ expect(error).to have_attributes(
14
+ response_code: 500,
15
+ response_headers: { 'Key' => 'Value' },
16
+ response_body: '{ "message": "Internal Server Error" }',
17
+ )
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,65 @@
1
+ RSpec.describe SolidusBacktracs::Api::RequestRunner do
2
+ #TODO
3
+ describe '.from_config' do
4
+ it 'builds a runner using credentials from the configuration' do
5
+ stub_configuration(api_key: 'user', api_secret: 'pass')
6
+
7
+ request_runner = described_class.from_config
8
+
9
+ expect(request_runner).to have_attributes(
10
+ username: 'user',
11
+ password: 'pass',
12
+ )
13
+ end
14
+ end
15
+
16
+ describe '#call' do
17
+ context 'when the response code is 2xx' do
18
+ it 'returns the parsed response' do
19
+ stub_request(:post, %r{bactracstest.andlor.com}).with(
20
+ basic_auth: %w[user pass],
21
+ headers: { 'Content-Type' => 'application/json', 'Accept' => 'application/json' },
22
+ body: '{"request_key":"request_value"}',
23
+ ).to_return(
24
+ headers: { 'Content-Type' => 'application/json' },
25
+ body: '{"response_key":"response_value"}',
26
+ )
27
+ request_runner = described_class.new(username: 'user', password: 'pass')
28
+
29
+ response = request_runner.call(:post, '/test', request_key: 'request_value')
30
+
31
+ expect(response).to eq('response_key' => 'response_value')
32
+ end
33
+ end
34
+
35
+ context 'when the response code is 429' do
36
+ it 'raises a RateLimitedError' do
37
+ stub_request(:post, %r{bactracstest.andlor.com}).to_return(
38
+ status: 429,
39
+ headers: { 'Content-Type' => 'application/json', 'X-Rate-Limit-Reset' => 20 },
40
+ body: '{"message":"Too Many Requests"}',
41
+ )
42
+ request_runner = described_class.new(username: 'user', password: 'pass')
43
+
44
+ expect {
45
+ request_runner.call(:post, '/test')
46
+ }.to raise_error(SolidusBacktracs::Api::RateLimitedError)
47
+ end
48
+ end
49
+
50
+ context 'when the response code is not 200 or 429' do
51
+ it 'raises a RequestError' do
52
+ stub_request(:post, %r{bactracstest.andlor.com}).to_return(
53
+ status: 500,
54
+ headers: { 'Content-Type' => 'application/json' },
55
+ body: '{"message":"Internal Server Error"}',
56
+ )
57
+ request_runner = described_class.new(username: 'user', password: 'pass')
58
+
59
+ expect {
60
+ request_runner.call(:post, '/test')
61
+ }.to raise_error(SolidusBacktracs::Api::RequestError)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,25 @@
1
+ RSpec.describe SolidusBacktracs::Api::ShipmentSerializer do
2
+ describe '#call' do
3
+ it 'serializes the shipment' do
4
+ shipment = create(:order_ready_to_ship).shipments.first
5
+
6
+ serializer = described_class.new(store_id: '12345678')
7
+ result = serializer.call(shipment)
8
+
9
+ expect(result).to be_instance_of(Hash)
10
+ end
11
+
12
+ it 'sets residential = false in address if company is given' do
13
+ order = create(:order_ready_to_ship,
14
+ bill_address: build(:address, company: 'ACME Co.'),
15
+ ship_address: build(:address, company: nil))
16
+ shipment = order.shipments.first
17
+
18
+ serializer = described_class.new(store_id: '12345678')
19
+ result = serializer.call(shipment)
20
+
21
+ expect(result[:billTo][:residential]).to be false
22
+ expect(result[:shipTo][:residential]).to be true
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,61 @@
1
+ RSpec.describe SolidusBacktracs::Api::ThresholdVerifier do
2
+ context "when the shipment's order was completed" do
3
+ context 'when the shipment was never synced with Backtracs yet' do
4
+ it 'returns true when the shipment was never synced with backtracs yet' do
5
+ stub_configuration(api_sync_threshold: 10.minutes)
6
+ shipment = create(:order_ready_to_ship).shipments.first
7
+
8
+ expect(described_class.call(shipment)).to eq(true)
9
+ end
10
+
11
+ it "returns false when the shipment's order was created too far in the past" do
12
+ stub_configuration(api_sync_threshold: 10.minutes)
13
+ shipment = create(:order_ready_to_ship).shipments.first.tap do |s|
14
+ s.order.update_columns(updated_at: 11.minutes.ago)
15
+ end
16
+
17
+ expect(described_class.call(shipment)).to eq(false)
18
+ end
19
+ end
20
+
21
+ context 'when the shipment was already synced with Backtracs' do
22
+ it 'returns true when the shipment is pending a Backtracs re-sync' do
23
+ stub_configuration(api_sync_threshold: 10.minutes)
24
+ shipment = create(:order_ready_to_ship).shipments.first.tap do |s|
25
+ s.order.update_columns(updated_at: 4.minutes.ago)
26
+ s.update_columns(backtracs_synced_at: 5.minutes.ago)
27
+ end
28
+
29
+ expect(described_class.call(shipment)).to eq(true)
30
+ end
31
+
32
+ it 'returns false when the shipment is up-to-date in Backtracs' do
33
+ stub_configuration(api_sync_threshold: 10.minutes)
34
+ shipment = create(:order_ready_to_ship).shipments.first.tap do |s|
35
+ s.order.update_columns(updated_at: 6.minutes.ago)
36
+ s.update_columns(backtracs_synced_at: 5.minutes.ago)
37
+ end
38
+
39
+ expect(described_class.call(shipment)).to eq(false)
40
+ end
41
+
42
+ it 'returns false when the order was updated too far in the past' do
43
+ stub_configuration(api_sync_threshold: 10.minutes)
44
+ shipment = create(:order_ready_to_ship).shipments.first.tap do |s|
45
+ s.order.update_columns(updated_at: 11.minutes.ago)
46
+ s.update_columns(backtracs_synced_at: 12.minutes.ago)
47
+ end
48
+
49
+ expect(described_class.call(shipment)).to eq(false)
50
+ end
51
+ end
52
+ end
53
+
54
+ context "when the shipment's order was not completed" do
55
+ it 'returns false' do
56
+ shipment = create(:shipment)
57
+
58
+ expect(described_class.call(shipment)).to eq(false)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe SolidusBacktracs::ShipmentNotice do
4
+ shared_examples 'ships or updates the shipment' do
5
+ context 'when the order was not shipped yet' do
6
+ # rubocop:disable RSpec/MultipleExpectations
7
+ it 'ships the order successfully' do
8
+ shipment_notice = build_shipment_notice(order.shipments.first, shipment_tracking: '1Z1231234')
9
+ shipment_notice.apply
10
+
11
+ order.reload
12
+ expect(order.shipments.first).to be_shipped
13
+ expect(order.shipments.first.shipped_at).not_to be_nil
14
+ expect(order.shipments.first.tracking).to eq('1Z1231234')
15
+ expect(order.cartons.first.tracking).to eq('1Z1231234')
16
+ end
17
+ # rubocop:enable RSpec/MultipleExpectations
18
+ end
19
+
20
+ context 'when the order was already shipped' do
21
+ it 'updates the tracking number on the shipment' do
22
+ order.shipments.first.ship!
23
+
24
+ shipment_notice = build_shipment_notice(order.shipments.first, shipment_tracking: '1Z1231234')
25
+ shipment_notice.apply
26
+
27
+ expect(order.reload.shipments.first.tracking).to eq('1Z1231234')
28
+ end
29
+ end
30
+ end
31
+
32
+ context 'when capture_at_notification is true' do
33
+ before { stub_configuration(capture_at_notification: true) }
34
+
35
+ context 'when the order is paid' do
36
+ let(:order) { create_order_ready_to_ship(paid: true) }
37
+
38
+ include_examples 'ships or updates the shipment'
39
+ end
40
+
41
+ context 'when the order is not paid' do
42
+ let(:order) { create_order_ready_to_ship(paid: false) }
43
+
44
+ context 'when the payment can be captured successfully' do
45
+ include_examples 'ships or updates the shipment'
46
+
47
+ it 'pays the order successfully' do
48
+ shipment_notice = build_shipment_notice(order.shipments.first, shipment_tracking: '1Z1231234')
49
+ shipment_notice.apply
50
+
51
+ order.reload
52
+ expect(order.payments).to all(be_completed)
53
+ expect(order.reload).to be_paid
54
+ end
55
+ end
56
+
57
+ context 'when the payment cannot be captured' do
58
+ it 'raises a PaymentError' do
59
+ allow_any_instance_of(Spree::Payment).to receive(:capture!).and_raise(Spree::Core::GatewayError)
60
+
61
+ shipment_notice = build_shipment_notice(order.shipments.first)
62
+
63
+ expect { shipment_notice.apply }.to raise_error(SolidusBacktracs::PaymentError) do |e|
64
+ expect(e.cause).to be_instance_of(Spree::Core::GatewayError)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ context 'when capture_at_notification is false' do
72
+ before { stub_configuration(capture_at_notification: false) }
73
+
74
+ context 'when the order is paid' do
75
+ let(:order) { create_order_ready_to_ship(paid: true) }
76
+
77
+ include_examples 'ships or updates the shipment'
78
+ end
79
+
80
+ context 'when the order is not paid' do
81
+ it 'raises an OrderNotPaidError' do
82
+ stub_configuration(capture_at_notification: false)
83
+ order = create_order_ready_to_ship(paid: false)
84
+
85
+ shipment_notice = build_shipment_notice(order.shipments.first)
86
+
87
+ expect { shipment_notice.apply }.to raise_error(SolidusBacktracs::OrderNotPaidError)
88
+ end
89
+ end
90
+ end
91
+
92
+ private
93
+
94
+ def create_order_ready_to_ship(paid: true)
95
+ order = create(:order_ready_to_ship)
96
+
97
+ unless paid
98
+ order.payments.update_all(state: 'pending')
99
+ order.recalculate
100
+ end
101
+
102
+ order
103
+ end
104
+
105
+ def build_shipment_notice(shipment, shipment_tracking: '1Z1231234')
106
+ SolidusBacktracs::ShipmentNotice.new(
107
+ shipment_number: shipment.number,
108
+ shipment_tracking: shipment_tracking,
109
+ )
110
+ end
111
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SolidusBacktracs do
4
+ describe 'VERSION' do
5
+ it 'is defined' do
6
+ expect(SolidusBacktracs::VERSION).to be_present
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Spree::Shipment do
4
+ describe '.between' do
5
+ it 'delegates to BetweenQuery' do
6
+ shipment = build_stubbed(:shipment)
7
+ allow(SolidusBacktracs::Shipment::BetweenQuery).to receive(:apply).with(
8
+ any_args,
9
+ from: Time.zone.yesterday,
10
+ to: Time.zone.today,
11
+ ).and_return([shipment])
12
+
13
+ result = Spree::Deprecation.silence do
14
+ described_class.between(Time.zone.yesterday, Time.zone.today)
15
+ end
16
+
17
+ expect(result).to eq([shipment])
18
+ end
19
+
20
+ it 'prints a deprecation warning' do
21
+ allow(Spree::Deprecation).to receive(:warn)
22
+
23
+ described_class.between(Time.zone.yesterday, Time.zone.today)
24
+
25
+ expect(Spree::Deprecation).to have_received(:warn).with(/Spree::Shipment\.between/)
26
+ end
27
+ end
28
+
29
+ describe '.exportable' do
30
+ it 'delegates to ExportableQuery' do
31
+ shipment = build_stubbed(:shipment)
32
+ allow(SolidusBacktracs::Shipment::ExportableQuery).to receive(:apply).and_return([shipment])
33
+
34
+ result = Spree::Deprecation.silence do
35
+ described_class.exportable
36
+ end
37
+
38
+ expect(result).to eq([shipment])
39
+ end
40
+
41
+ it 'prints a deprecation warning' do
42
+ allow(Spree::Deprecation).to receive(:warn)
43
+
44
+ described_class.exportable
45
+
46
+ expect(Spree::Deprecation).to have_received(:warn).with(/Spree::Shipment\.exportable/)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,53 @@
1
+ RSpec.describe SolidusBacktracs::Shipment::BetweenQuery do
2
+ describe '.apply' do
3
+ it 'returns shipments whose updated_at falls within the given time range' do
4
+ shipment = create(:shipment) { |s| s.update_column(:updated_at, Time.zone.now) }
5
+
6
+ result = described_class.apply(
7
+ Spree::Shipment.all,
8
+ from: Time.zone.yesterday,
9
+ to: Time.zone.tomorrow,
10
+ )
11
+
12
+ expect(result).to eq([shipment])
13
+ end
14
+
15
+ it "returns shipments whose order's updated_at falls within the given time range" do
16
+ order = create(:order) { |o| o.update_column(:updated_at, Time.zone.now) }
17
+ shipment = create(:shipment, order: order)
18
+
19
+ result = described_class.apply(
20
+ Spree::Shipment.all,
21
+ from: Time.zone.yesterday,
22
+ to: Time.zone.tomorrow,
23
+ )
24
+
25
+ expect(result).to eq([shipment])
26
+ end
27
+
28
+ it 'does not return shipments whose updated_at does not fall within the given time range' do
29
+ create(:shipment) { |s| s.update_column(:updated_at, Time.zone.now) }
30
+
31
+ result = described_class.apply(
32
+ Spree::Shipment.all,
33
+ from: Time.zone.tomorrow,
34
+ to: Time.zone.tomorrow + 1.day,
35
+ )
36
+
37
+ expect(result).to eq([])
38
+ end
39
+
40
+ it "does not return shipments whose order's updated_at falls within the given time range" do
41
+ order = create(:order) { |o| o.update_column(:updated_at, Time.zone.now) }
42
+ create(:shipment, order: order)
43
+
44
+ result = described_class.apply(
45
+ Spree::Shipment.all,
46
+ from: Time.zone.tomorrow,
47
+ to: Time.zone.tomorrow + 1.day,
48
+ )
49
+
50
+ expect(result).to eq([])
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,53 @@
1
+ RSpec.describe SolidusBacktracs::Shipment::ExportableQuery do
2
+ describe '.apply' do
3
+ context 'when capture_at_notification is false and export_canceled_shipments is false' do
4
+ it 'returns ready shipments from complete orders' do
5
+ stub_configuration(capture_at_notification: false, export_canceled_shipments: false)
6
+
7
+ ready_shipment = create(:order_ready_to_ship).shipments.first
8
+ create(:order_ready_to_ship) { |o| o.shipments.first.cancel! }
9
+ create(:shipped_order)
10
+
11
+ expect(described_class.apply(Spree::Shipment.all)).to eq([ready_shipment])
12
+ end
13
+ end
14
+
15
+ context 'when capture_at_notification is true and export_canceled_shipments is false' do
16
+ it 'returns non-canceled shipments from complete orders' do
17
+ stub_configuration(capture_at_notification: true, export_canceled_shipments: false)
18
+
19
+ ready_shipment = create(:order_ready_to_ship).shipments.first
20
+ shipped_shipment = create(:shipped_order).shipments.first
21
+ create(:order_ready_to_ship) { |o| o.shipments.first.cancel! }
22
+
23
+ expect(described_class.apply(Spree::Shipment.all)).to eq([ready_shipment, shipped_shipment])
24
+ end
25
+ end
26
+
27
+ context 'when capture_at_notification is false and export_canceled_shipments is true' do
28
+ it 'returns ready and canceled shipments from complete orders' do
29
+ stub_configuration(capture_at_notification: false, export_canceled_shipments: true)
30
+
31
+ ready_shipment = create(:order_ready_to_ship).shipments.first
32
+ canceled_shipment = create(:order_ready_to_ship).shipments.first
33
+ canceled_shipment.cancel!
34
+ create(:shipped_order)
35
+
36
+ expect(described_class.apply(Spree::Shipment.all)).to eq([ready_shipment, canceled_shipment])
37
+ end
38
+ end
39
+
40
+ context 'when capture_at_notification is true and export_canceled_shipments is true' do
41
+ it 'returns all shipments from complete orders' do
42
+ stub_configuration(capture_at_notification: true, export_canceled_shipments: true)
43
+
44
+ ready_shipment = create(:order_ready_to_ship).shipments.first
45
+ canceled_shipment = create(:order_ready_to_ship).shipments.first
46
+ canceled_shipment.cancel!
47
+ shipped_shipment = create(:shipped_order).shipments.first
48
+
49
+ expect(described_class.apply(Spree::Shipment.all)).to eq([ready_shipment, canceled_shipment, shipped_shipment])
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,37 @@
1
+ RSpec.describe SolidusBacktracs::Shipment::PendingApiSyncQuery do
2
+ describe '.apply' do
3
+ context 'when dealing with shipments that were never synced' do
4
+ it 'returns the shipments that are within the threshold' do
5
+ stub_configuration(api_sync_threshold: 10.minutes)
6
+ shipment = create(:order_ready_to_ship).shipments.first.tap do |s|
7
+ s.order.update_columns(updated_at: 9.minutes.ago)
8
+ end
9
+ create(:order_ready_to_ship).shipments.first.tap do |s|
10
+ s.order.update_columns(updated_at: 11.minutes.ago)
11
+ end
12
+
13
+ expect(described_class.apply(Spree::Shipment.all)).to match_array([shipment])
14
+ end
15
+ end
16
+
17
+ context 'when dealing with shipments that were already synced' do
18
+ it 'returns the shipments that are within the threshold and pending a re-sync' do
19
+ stub_configuration(api_sync_threshold: 10.minutes)
20
+ shipment = create(:order_ready_to_ship).shipments.first.tap do |s|
21
+ s.order.update_columns(updated_at: 7.minutes.ago)
22
+ s.update_columns(shipstation_synced_at: 8.minutes.ago)
23
+ end
24
+ create(:order_ready_to_ship).shipments.first.tap do |s|
25
+ s.order.update_columns(updated_at: 9.minutes.ago)
26
+ s.update_columns(shipstation_synced_at: 8.minutes.ago)
27
+ end
28
+ create(:order_ready_to_ship).shipments.first.tap do |s|
29
+ s.order.update_columns(updated_at: 11.minutes.ago)
30
+ s.update_columns(shipstation_synced_at: 10.minutes.ago)
31
+ end
32
+
33
+ expect(described_class.apply(Spree::Shipment.all)).to match_array([shipment])
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Configure Rails Environment
4
+ ENV['RAILS_ENV'] = 'test'
5
+
6
+ # Run Coverage report
7
+ require 'solidus_dev_support/rspec/coverage'
8
+
9
+ # Create the dummy app if it's still missing.
10
+ dummy_env = "#{__dir__}/dummy/config/environment.rb"
11
+ system 'bin/rake extension:test_app' unless File.exist? dummy_env
12
+ require dummy_env
13
+
14
+ # Requires factories and other useful helpers defined in spree_core.
15
+ require 'solidus_dev_support/rspec/feature_helper'
16
+
17
+ # Requires supporting ruby files with custom matchers and macros, etc,
18
+ # in spec/support/ and its subdirectories.
19
+ Dir["#{__dir__}/support/**/*.rb"].sort.each { |f| require f }
20
+
21
+ # Requires factories defined in lib/solidus_backtracs/testing_support/factories.rb
22
+ SolidusDevSupport::TestingSupport::Factories.load_for(SolidusBacktracs::Engine)
23
+
24
+ RSpec.configure do |config|
25
+ config.infer_spec_type_from_file_location!
26
+ config.use_transactional_fixtures = false
27
+
28
+ if Spree.solidus_gem_version < Gem::Version.new('2.11')
29
+ config.extend Spree::TestingSupport::AuthorizationHelpers::Request, type: :system
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ module ConfigurationHelper
2
+ def stub_configuration(options)
3
+ allow(SolidusBacktracs.configuration).to receive_messages(options)
4
+
5
+ if options[:capture_at_notification]
6
+ stub_spree_preferences(require_payment_to_ship: false)
7
+ end
8
+ end
9
+ end
10
+
11
+ RSpec.configure do |config|
12
+ config.include ConfigurationHelper
13
+ end
@@ -0,0 +1 @@
1
+ require 'rails-controller-testing'
@@ -0,0 +1,3 @@
1
+ require 'webmock/rspec'
2
+
3
+ WebMock.disable_net_connect!
@@ -0,0 +1,5 @@
1
+ require 'rspec/xsd'
2
+
3
+ RSpec.configure do |config|
4
+ config.include RSpec::XSD
5
+ end