solidus_backtracs 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7e943693a25b935abcf72d941f4f38c891761c3afae537f108e211041ccdc6e2
4
+ data.tar.gz: 87c9e1870799e0b007a8e2011a3460086b0aa9ccb39fa8a34bd1942bdf38e3ba
5
+ SHA512:
6
+ metadata.gz: c43355431c15e927961f74576d56e80bf7e56f6a14233bdf0ade847e833624c60cdf110c377952014e2007a0cb4d4138e8c5300e3e444a9d77f39c83effda44f
7
+ data.tar.gz: 95ce5f1c0d8d86a5a07eb884154caeecb9ca3c69a634594964d795aaa80439bb6a0bec00074dcf9151eeb16d02099fbea21a47fdcb560a9e98975e1f69892f1e
data/.bundle/config ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_JOBS: "12"
@@ -0,0 +1,41 @@
1
+ version: 2.1
2
+
3
+ orbs:
4
+ # Always take the latest version of the orb, this allows us to
5
+ # run specs against Solidus supported versions only without the need
6
+ # to change this configuration every time a Solidus version is released
7
+ # or goes EOL.
8
+ solidusio_extensions: solidusio/extensions@volatile
9
+
10
+ jobs:
11
+ run-specs-with-postgres:
12
+ executor: solidusio_extensions/postgres
13
+ steps:
14
+ - solidusio_extensions/run-tests
15
+ run-specs-with-mysql:
16
+ executor: solidusio_extensions/mysql
17
+ steps:
18
+ - solidusio_extensions/run-tests
19
+ lint-code:
20
+ executor: solidusio_extensions/sqlite-memory
21
+ steps:
22
+ - solidusio_extensions/lint-code
23
+
24
+ workflows:
25
+ "Run specs on supported Solidus versions":
26
+ jobs:
27
+ - run-specs-with-postgres
28
+ - run-specs-with-mysql
29
+ - lint-code
30
+
31
+ "Weekly run specs against master":
32
+ triggers:
33
+ - schedule:
34
+ cron: "0 0 * * 4" # every Thursday
35
+ filters:
36
+ branches:
37
+ only:
38
+ - master
39
+ jobs:
40
+ - run-specs-with-postgres
41
+ - run-specs-with-mysql
data/.gem_release.yml ADDED
@@ -0,0 +1,5 @@
1
+ bump:
2
+ recurse: false
3
+ file: 'lib/solidus_backtracs/version.rb'
4
+ message: Bump SolidusBacktracs to %{version}
5
+ tag: true
data/.github/stale.yml ADDED
@@ -0,0 +1,17 @@
1
+ # Number of days of inactivity before an issue becomes stale
2
+ daysUntilStale: 60
3
+ # Number of days of inactivity before a stale issue is closed
4
+ daysUntilClose: false
5
+ # Issues with these labels will never be considered stale
6
+ exemptLabels:
7
+ - pinned
8
+ - security
9
+ # Label to use when marking an issue as stale
10
+ staleLabel: stale
11
+ # Comment to post when marking an issue as stale. Set to `false` to disable
12
+ markComment: >
13
+ This issue has been automatically marked as stale because it has not had
14
+ recent activity. It might be closed if no further activity occurs. Thank you
15
+ for your contributions.
16
+ # Comment to post when closing a stale issue. Set to `false` to disable
17
+ closeComment: false
@@ -0,0 +1,2 @@
1
+ issues=false
2
+ exclude-labels=infrastructure
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ \#*
3
+ *~
4
+ .#*
5
+ .DS_Store
6
+ .idea
7
+ .project
8
+ .sass-cache
9
+ coverage
10
+ Gemfile.lock
11
+ tmp
12
+ nbproject
13
+ pkg
14
+ *.swp
15
+ spec/dummy
16
+ spec/examples.txt
17
+ /sandbox
18
+ .rvmrc
19
+ .ruby-version
20
+ .ruby-gemset
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,14 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ require:
4
+ - solidus_dev_support/rubocop
5
+
6
+ AllCops:
7
+ NewCops: disable
8
+ TargetRubyVersion: 2.5
9
+
10
+ Layout/LineLength:
11
+ Enabled: false
12
+
13
+ Rails/SkipsModelValidations:
14
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,40 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2020-09-22 09:09:44 UTC using RuboCop version 0.87.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ Lint/UselessAssignment:
11
+ Exclude:
12
+ - 'app/controllers/spree/backtracs_controller.rb'
13
+
14
+ # Offense count: 1
15
+ RSpec/AnyInstance:
16
+ Exclude:
17
+ - 'spec/lib/solidus_backtracs/shipment_notice_spec.rb'
18
+
19
+ # Offense count: 5
20
+ RSpec/MultipleExpectations:
21
+ Max: 2
22
+
23
+ # Offense count: 8
24
+ RSpec/NestedGroups:
25
+ Max: 5
26
+
27
+ # Offense count: 6
28
+ # Configuration parameters: ForbiddenMethods, AllowedMethods.
29
+ # ForbiddenMethods: decrement!, decrement_counter, increment!, increment_counter, insert, insert!, insert_all, insert_all!, toggle!, touch, touch_all, update_all, update_attribute, update_column, update_columns, update_counters, upsert, upsert_all
30
+ Rails/SkipsModelValidations:
31
+ Exclude:
32
+ - 'spec/lib/solidus_backtracs/shipment_notice_spec.rb'
33
+ - 'spec/models/spree/shipment_spec.rb'
34
+ - 'spec/support/shipment_helper.rb'
35
+
36
+ # Offense count: 1
37
+ # Configuration parameters: MinBodyLength.
38
+ Style/GuardClause:
39
+ Exclude:
40
+ - 'spec/support/configuration_helper.rb'
data/CHANGELOG.md ADDED
@@ -0,0 +1,2 @@
1
+ # Changelog
2
+
data/Gemfile ADDED
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
5
+
6
+ branch = ENV.fetch('SOLIDUS_BRANCH', 'master')
7
+ gem 'solidus', github: 'solidusio/solidus', branch: branch
8
+
9
+ # Needed to help Bundler figure out how to resolve dependencies,
10
+ # otherwise it takes forever to resolve them.
11
+ # See https://github.com/bundler/bundler/issues/6677
12
+ gem 'rails', '>0.a'
13
+
14
+ # Provides basic authentication functionality for testing parts of your engine
15
+ gem 'solidus_auth_devise'
16
+
17
+ case ENV['DB']
18
+ when 'mysql'
19
+ gem 'mysql2'
20
+ when 'postgresql'
21
+ gem 'pg'
22
+ else
23
+ gem 'sqlite3'
24
+ end
25
+
26
+ gemspec
27
+
28
+ # Use a local Gemfile to include development dependencies that might not be
29
+ # relevant for the project or for other contributors, e.g. pry-byebug.
30
+ #
31
+ # We use `send` instead of calling `eval_gemfile` to work around an issue with
32
+ # how Dependabot parses projects: https://github.com/dependabot/dependabot-core/issues/1658.
33
+ send(:eval_gemfile, 'Gemfile-local') if File.exist? 'Gemfile-local'
data/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2013 Boomer Digital
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ * Neither the name Solidus nor the names of its contributors may be used to
13
+ endorse or promote products derived from this software without specific
14
+ prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,208 @@
1
+ # Solidus ShipStation — Suvie fork
2
+
3
+ [![CircleCI](https://circleci.com/gh/solidusio-contrib/solidus_backtracs.svg?style=shield)](https://circleci.com/gh/solidusio-contrib/solidus_backtracs)
4
+ [![codecov](https://codecov.io/gh/solidusio-contrib/solidus_backtracs/branch/master/graph/badge.svg)](https://codecov.io/gh/solidusio-contrib/solidus_backtracs)
5
+
6
+ This gem integrates [ShipStation](http://www.backtracs.com) with [Solidus](http://solidus.io). It
7
+ enables ShipStation to pull shipments from the system and update tracking numbers.
8
+
9
+ This integration is a fork of [spree_backtracs](https://github.com/DynamoMTL/spree_backtracs)
10
+ that adds Solidus and Rails 4.2+ compatibility.
11
+
12
+ ## Installation
13
+
14
+ Add solidus_backtracs to your Gemfile:
15
+
16
+ ```ruby
17
+ gem 'solidus_backtracs', github: 'solidusio-contrib/solidus_backtracs'
18
+ ```
19
+
20
+ Bundle your dependencies and run the installation generator:
21
+
22
+ ```shell
23
+ bin/rails generate solidus_backtracs:install
24
+ ```
25
+
26
+ The installer will create a configuration initializer that you'll need to customize.
27
+
28
+ The installer will also create a migration, which is required by the API integration. If you are
29
+ going to use the XML integration, feel free to delete the migration file, as those columns won't be
30
+ used by the extension.
31
+
32
+ ## Usage
33
+
34
+ This extension can integrate with ShipStation in two ways.
35
+
36
+ ### XML integration
37
+
38
+ The [XML integration](https://help.backtracs.com/hc/en-us/articles/360025856192-Custom-Store-Development-Guide)
39
+ works by exposing a route in your Solidus application that generates an XML feed of all recently
40
+ created and updated shipments in your Solidus store.
41
+
42
+ #### XML integration: Configuration
43
+
44
+ In order to enable the XML integration, make sure to configure the relevant section of the
45
+ configuration initializer, and configure your ShipStation store accordingly:
46
+
47
+ - **Username**: the username defined in your configuration.
48
+ - **Password**: the password defined in your configuration.
49
+ - **URL to custom page**: `https://yourdomain.com/backtracs.xml`.
50
+
51
+ You can also configure your ShipStation store to pull the XML feed automatically on a recurring
52
+ basis, or manually by clicking the "Refresh stores" button.
53
+
54
+ There are five shipment states for an order (= shipment) in ShipStation. These states do not
55
+ necessarily align with Solidus, but you can configure ShipStation to create a mapping for your
56
+ specific needs. Here's the recommended mapping:
57
+
58
+ ShipStation description | ShipStation status | Solidus status
59
+ ------------------------|--------------------|---------------
60
+ Awaiting Payment | `unpaid` | `pending`
61
+ Awaiting Shipment | `paid` | `ready`
62
+ Shipped | `shipped` | `shipped`
63
+ Cancelled | `cancelled` | `cancelled`
64
+ On-Hold | `on-hold` | `pending`
65
+
66
+ Once you've configured the XML integration in your app and ShipStation, there's nothing else you
67
+ need to do. ShipStation will
68
+
69
+ #### XML integration: Usage
70
+
71
+ There's nothing you need to do. Once properly configured, the integration just works!
72
+
73
+ #### XML integration: Gotchas
74
+
75
+ There are a few gotchas you need to be aware of:
76
+
77
+ - If you change the shipping method of an order in ShipStation, the change will not be reflected in
78
+ Solidus and the tracking link might not work properly.
79
+ - When `backtracs_capture_at_notification` is enabled, any errors during payment capture will
80
+ prevent the update of the shipment's tracking number.
81
+
82
+ ### API integration
83
+
84
+ The [API integration](https://www.backtracs.com/docs/api/) works by calling the ShipStation API
85
+ to sync all of your shipments continuously.
86
+
87
+ Because ShipStation has very low rate limits (i.e., 40 reqs/minute at the time of writing), the
88
+ API integration does not send an API request for every single shipment update, as you would expect
89
+ from a traditional API integration.
90
+
91
+ Instead, a background job runs on a recurring basis and batches together all the shipments that need
92
+ to be created or updated in ShipStation. These shipments are then sent in groups of 100 (by default)
93
+ to ShipStation's [bulk order upsert endpoint](https://www.backtracs.com/docs/api/orders/create-update-multiple-orders/).
94
+
95
+ This allows us to work around ShipStation's rate limit and sync up to 4000 shipments/minute.
96
+
97
+ As you may imagine, this technique also comes at the expense of some additional complexity in the
98
+ implementation, but the extension abstracts it all away for you.
99
+
100
+ #### API integration: Configuration
101
+
102
+ In order to enable the API integration, make sure to configure the relevant section of the
103
+ configuration initializer. At the very least, the integration needs to know your API credentials
104
+ and store ID, but there are additional options you can configure — just look at the initializer!
105
+
106
+ #### API integration: Usage
107
+
108
+ Once you've configured the integration, you will also need to enqueue the `ScheduleShipmentSyncsJob`
109
+ on a recurring basis, to kick off the synchronization process. Because every app uses a different
110
+ background processing library, this is left up to the user.
111
+
112
+ Here's what an example with [sidekiq-scheduler](https://github.com/moove-it/sidekiq-scheduler) might
113
+ look like:
114
+
115
+ ```yaml
116
+ # config/sidekiq.yml
117
+ :schedule:
118
+ schedule_shipment_syncs:
119
+ every: ['1m', first_in: '0s']
120
+ class: 'SolidusBacktracs::Api::ScheduleShipmentSyncsJob'
121
+ ```
122
+
123
+ This will schedule the job to run every minute. This is generally a good starting point, but feel
124
+ free to adjust it as needed.
125
+
126
+ #### API integration: Gotchas
127
+
128
+ There's one possible problem you need to be aware of, when integrating via the API.
129
+
130
+ You should make sure the interval between your syncs is, on average, larger than your latency in
131
+ processing background jobs, or you are going to experience sync overlaps.
132
+
133
+ As an example, if it takes your Sidekiq process 10 seconds to execute a job from the time it's
134
+ scheduled, but you schedule a shipment sync every 5 seconds, your sync jobs will start overlapping,
135
+ making your latency even worse.
136
+
137
+ This is a problem that is faced by all recurring jobs. The solution is two-fold:
138
+
139
+ 1. Monitor the latency of your background processing queues. Seriously, do it.
140
+ 2. Make sure your sync interval is not too aggressive: unless you really need to, there's no point
141
+ in syncing your shipments more often than once a minute.
142
+
143
+ ## Development
144
+
145
+ ### Testing the extension
146
+
147
+ First bundle your dependencies, then run `bin/rake`. `bin/rake` will default to building the dummy
148
+ app if it does not exist, then it will run specs. The dummy app can be regenerated by using
149
+ `bin/rake extension:test_app`.
150
+
151
+ ```shell
152
+ bin/rake
153
+ ```
154
+
155
+ To run [Rubocop](https://github.com/bbatsov/rubocop) static code analysis run
156
+
157
+ ```shell
158
+ bundle exec rubocop
159
+ ```
160
+
161
+ When testing your application's integration with this extension you may use its factories.
162
+ Simply add this require statement to your `spec/spec_helper.rb`:
163
+
164
+ ```ruby
165
+ require 'solidus_backtracs/testing_support/factories'
166
+ ```
167
+
168
+ Or, if you are using `FactoryBot.definition_file_paths`, you can load Solidus core
169
+ factories along with this extension's factories using this statement:
170
+
171
+ ```ruby
172
+ SolidusDevSupport::TestingSupport::Factories.load_for(SolidusBacktracs::Engine)
173
+ ```
174
+
175
+ ### Running the sandbox
176
+
177
+ To run this extension in a sandboxed Solidus application, you can run `bin/sandbox`. The path for
178
+ the sandbox app is `./sandbox` and `bin/rails` will forward any Rails commands to
179
+ `sandbox/bin/rails`.
180
+
181
+ Here's an example:
182
+
183
+ ```
184
+ $ bin/rails server
185
+ => Booting Puma
186
+ => Rails 6.0.2.1 application starting in development
187
+ * Listening on tcp://127.0.0.1:3000
188
+ Use Ctrl-C to stop
189
+ ```
190
+
191
+ ### Updating the changelog
192
+
193
+ Before and after releases the changelog should be updated to reflect the up-to-date status of
194
+ the project:
195
+
196
+ ```shell
197
+ bin/rake changelog
198
+ git add CHANGELOG.md
199
+ git commit -m "Update the changelog"
200
+ ```
201
+
202
+ ### Releasing new versions
203
+
204
+ Please refer to the dedicated [page](https://github.com/solidusio/solidus/wiki/How-to-release-extensions) on Solidus wiki.
205
+
206
+ ## License
207
+
208
+ Copyright (c) 2013 Boomer Digital, released under the New BSD License.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solidus_dev_support/rake_tasks'
4
+ SolidusDevSupport::RakeTasks.install
5
+
6
+ task default: 'extension:specs'
@@ -0,0 +1,2 @@
1
+ // Placeholder manifest file.
2
+ // the installer will append this file to the app vendored assets here: vendor/assets/javascripts/spree/backend/all.js'
@@ -0,0 +1,2 @@
1
+ // Placeholder manifest file.
2
+ // the installer will append this file to the app vendored assets here: vendor/assets/javascripts/spree/frontend/all.js'
@@ -0,0 +1,4 @@
1
+ /*
2
+ Placeholder manifest file.
3
+ the installer will append this file to the app vendored assets here: 'vendor/assets/stylesheets/spree/backend/all.css'
4
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Placeholder manifest file.
3
+ the installer will append this file to the app vendored assets here: 'vendor/assets/stylesheets/spree/frontend/all.css'
4
+ */
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ class BacktracsController < Spree::BaseController
5
+ protect_from_forgery with: :null_session, only: :shipnotify
6
+
7
+ before_action :authenticate_backtracs
8
+
9
+ def export
10
+ @shipments = SolidusBacktracs::Shipment::ExportableQuery.apply(Spree::Shipment.all)
11
+ @shipments = SolidusBacktracs::Shipment::BetweenQuery.apply(
12
+ @shipments,
13
+ from: date_param(:start_date),
14
+ to: date_param(:end_date),
15
+ )
16
+ @shipments = @shipments.page(params[:page]).per(50)
17
+
18
+ respond_to do |format|
19
+ format.xml { render layout: false }
20
+ end
21
+ end
22
+
23
+ def shipnotify
24
+ shipment_notice_class = SolidusBacktracs.configuration.shipment_notice_class.constantize
25
+ shipment_notice_class.from_payload(params.to_unsafe_h).apply
26
+ head :ok
27
+ rescue SolidusBacktracs::Error => e
28
+ head :bad_request
29
+ end
30
+
31
+ private
32
+
33
+ def date_param(name)
34
+ return if params[name].blank?
35
+
36
+ Time.strptime("#{params[name]} UTC", '%m/%d/%Y %H:%M %Z')
37
+ end
38
+
39
+ def authenticate_backtracs
40
+ authenticate_or_request_with_http_basic do |username, password|
41
+ username == SolidusBacktracs.configuration.username &&
42
+ password == SolidusBacktracs.configuration.password
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusBacktracs
4
+ module Spree
5
+ module ShipmentDecorator
6
+ def self.prepended(base)
7
+ base.singleton_class.prepend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ def exportable
12
+ ::Spree::Deprecation.warn <<~DEPRECATION
13
+ `Spree::Shipment.exportable` is deprecated and will be removed in a future version
14
+ of solidus_backtracs. Please use `SolidusBacktracs::Shipment::ExportableQuery.apply`.
15
+ DEPRECATION
16
+
17
+ SolidusBacktracs::Shipment::ExportableQuery.apply(self)
18
+ end
19
+
20
+ def between(from, to)
21
+ ::Spree::Deprecation.warn <<~DEPRECATION
22
+ `Spree::Shipment.between` is deprecated and will be removed in a future version
23
+ of solidus_backtracs. Please use `SolidusBacktracs::Shipment::BetweenQuery.apply`.
24
+ DEPRECATION
25
+
26
+ SolidusBacktracs::Shipment::BetweenQuery.apply(self, from: from, to: to)
27
+ end
28
+ end
29
+
30
+ ::Spree::Shipment.prepend self
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'builder'
4
+
5
+ module SolidusBacktracs
6
+ module ExportHelper
7
+ DATE_FORMAT = '%m/%d/%Y %H:%M'
8
+ BACTRACS_DATE_FORMAT = '%Y-%m-%dT%H:%M:%S'
9
+
10
+ # rubocop:disable all
11
+ def self.address(xml, order, type)
12
+ name = "#{type.to_s.titleize}To"
13
+ address = order.send("#{type}_address")
14
+
15
+ xml.__send__(name) {
16
+ xml.Name address.respond_to?(:name) ? address.name : address.full_name
17
+ xml.Company address.company
18
+
19
+ if type == :ship
20
+ xml.Address1 address.address1
21
+ xml.Address2 address.address2
22
+ xml.City address.city
23
+ xml.State address.state ? address.state.abbr : address.state_name
24
+ xml.PostalCode address.zipcode
25
+ xml.Country address.country.iso
26
+ end
27
+
28
+ xml.Phone address.phone
29
+ }
30
+ end
31
+
32
+ def self.backtracs_address(xml, order, type)
33
+ name = "#{type.to_s.titleize}To"
34
+ address = order.send("#{type}_address")
35
+
36
+ xml.__send__(name) {
37
+ xml.CompanyName address.company ? address.company : address.name
38
+ xml.Contact address.name
39
+ xml.ContactEmail order.email
40
+ xml.Address1 address.address1
41
+ xml.Address2 address.address2
42
+ xml.City address.city
43
+ xml.State address.state ? address.state.abbr : address.state_name
44
+ xml.Zip address.zipcode
45
+ xml.Phone address.phone.present? ? address.phone : "000-000-0000"
46
+ xml.PhoneAlt address.phone.present? ? address.phone : "000-000-0000"
47
+ xml.Country address.country.iso
48
+ }
49
+ end
50
+ # rubocop:enable all
51
+ end
52
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusBacktracs
4
+ module Api
5
+ class ScheduleShipmentSyncsJob < ApplicationJob
6
+ queue_as :default
7
+
8
+ def perform
9
+ shipments = query_shipments
10
+
11
+ shipments.find_in_batches(batch_size: SolidusBacktracs.config.api_batch_size) do |batch|
12
+ SyncShipmentsJob.perform_later(batch.to_a)
13
+ end
14
+ rescue StandardError => e
15
+ SolidusBacktracs.config.error_handler.call(e, {})
16
+ end
17
+
18
+ def shippable_skus
19
+ SolidusBacktracs.config.shippable_skus.present? ? SolidusBacktracs.config.shippable_skus : Spree::Variant.pluck(:sku)
20
+ end
21
+
22
+ def query_shipments
23
+ shipments = SolidusBacktracs::Shipment::PendingApiSyncQuery.apply(::Spree::Shipment.joins(inventory_units: [:variant]).where("spree_variants.sku" => SolidusBacktracs.config.shippable_skus).where("spree_shipments.state" => :ready).where.not(shipstation_order_id: nil).distinct)
24
+ end
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusBacktracs
4
+ module Api
5
+ class SyncShipmentJob < ApplicationJob
6
+ queue_as :default
7
+
8
+ def perform(shipment_id: nil, error_handler: nil, shipment_serializer: nil, request_runner: nil)
9
+ shipment = ::Spree::Shipment.find(shipment_id)
10
+ request_runner.authenticated_call(method: :post, path: '/webservices/rma/rmaservice.asmx', serializer: shipment_serializer, shipment: shipment)
11
+ rescue StandardError => e
12
+ error_handler.call(e, shipment: shipment)
13
+ nil
14
+ end
15
+ end
16
+ end
17
+ end