spree_stock_locking 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 38d75dfae6efd34b4f0e73396551513fd1acd3d78fbc339eeb50e9d92bc0fc5d
4
+ data.tar.gz: 5d0710ceeb52b457763f6ba3f1f0f017e0997ef592df372fc1408acef6ce24f1
5
+ SHA512:
6
+ metadata.gz: 48e9c07428b3c2854fca7aa4d6d49bdc152570bb60338c411c638acb0127f07d11d42dccd51b07ffb046cf88f89653eef8a26513af1f8128fa8036820545646f
7
+ data.tar.gz: f4f8af7445d5cdec07d9e0a76a530b2f1b4575b6317a504b86805cc605a0d732e1c0df517801d6721aedab16681c92b37a43c6b56f60303b798d2688586679e6
@@ -0,0 +1,49 @@
1
+ name: ci
2
+
3
+ on: push
4
+
5
+ jobs:
6
+ ci:
7
+ runs-on: ubuntu-latest
8
+ timeout-minutes: 30
9
+ env:
10
+ DATABASE_HOST: 0.0.0.0
11
+ DATABASE_PASSWORD: mysql123
12
+ RAILS_ENV: test
13
+ REDIS_URL: redis://0.0.0.0:6379
14
+ TZ: Asia/Tokyo
15
+
16
+ services:
17
+ mysql:
18
+ image: mysql:8.0.23
19
+ options: --health-cmd "mysqladmin ping -h localhost" --health-interval 20s --health-timeout 10s --health-retries 10
20
+ env:
21
+ MYSQL_ROOT_PASSWORD: ${{ env.DATABASE_PASSWORD }}
22
+ ports:
23
+ - 3306:3306
24
+ redis:
25
+ image: redis:6.2-alpine
26
+ options: --health-cmd "redis-cli -h localhost ping" --health-interval 10s --health-timeout 5s --health-retries 15
27
+ ports:
28
+ - 6379:6379
29
+ webdriver_chrome:
30
+ image: selenium/standalone-chrome:95.0
31
+ ports:
32
+ - 4444:4444
33
+ options: "--shm-size 2g"
34
+
35
+ steps:
36
+ - uses: actions/checkout@v2
37
+ - uses: ruby/setup-ruby@v1
38
+ with:
39
+ bundler-cache: true
40
+ ruby-version: 3.0.3
41
+
42
+ - name: Exec tests 👚
43
+ env:
44
+ DB_HOST: 127.0.0.1
45
+ DB_PASSWORD: ${{ env.DATABASE_PASSWORD }}
46
+ DB_USERNAME: root
47
+ run: |
48
+ bundle exec rake test_app
49
+ bundle exec rake spec
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ \#*
2
+ *~
3
+ .#*
4
+ .DS_Store
5
+ .idea
6
+ .localeapp/locales
7
+ .project
8
+ .vscode
9
+ coverage
10
+ default
11
+ Gemfile.lock
12
+ tmp
13
+ nbproject
14
+ pkg
15
+ *.sw?
16
+ spec/dummy
17
+ .rvmrc
18
+ .sass-cache
19
+ public/spree
20
+ .ruby-version
21
+ .ruby-gemset
22
+ *.gem
23
+ */*.gem
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ -r spec_helper
3
+ -f documentation
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) do |repo_name|
4
+ repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?('/')
5
+ "https://github.com/#{repo_name}.git"
6
+ end
7
+
8
+ gem 'spree' # , github: 'spree/spree', branch: 'main'
9
+ # gem 'spree_backend', github: 'spree/spree', branch: 'main'
10
+ gem 'rails-controller-testing'
11
+
12
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2021 ROUTE06, Inc.
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 Spree 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,54 @@
1
+ # SpreeStockLocking
2
+
3
+ A [Spree](https://github.com/spree/spree) extension that implements stock movement locking with Redis::Lock.
4
+
5
+ ## Installation
6
+
7
+ 1. Add this extension to your Gemfile with this line:
8
+
9
+ ```ruby
10
+ gem 'spree_stock_locking'
11
+ ```
12
+
13
+ 2. Install the gem using Bundler
14
+
15
+ ```ruby
16
+ bundle install
17
+ ```
18
+
19
+ 3. Copy & run migrations
20
+
21
+ ```ruby
22
+ bundle exec rails g spree_stock_locking:install
23
+ ```
24
+
25
+ 4. Restart your server
26
+
27
+ If your server was running, restart it so that it can find the assets properly.
28
+
29
+ ## Testing
30
+
31
+ First bundle your dependencies, then run `rake`. `rake` will default to building the dummy app if it does not exist, then it will run specs. The dummy app can be regenerated by using `rake test_app`.
32
+
33
+ ```shell
34
+ bundle update
35
+ bundle exec rake
36
+ ```
37
+
38
+ When testing your applications integration with this extension you may use it's factories.
39
+ Simply add this require statement to your spec_helper:
40
+
41
+ ```ruby
42
+ require 'spree_stock_locking/factories'
43
+ ```
44
+
45
+ ## Releasing
46
+
47
+ ```shell
48
+ bundle exec gem bump -p -t
49
+ bundle exec gem release
50
+ ```
51
+
52
+ For more options please see [gem-release REAMDE](https://github.com/svenfuchs/gem-release)
53
+
54
+ Copyright (c) 2021 ROUTE06, Inc., released under the New BSD License
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ require 'spree/testing_support/extension_rake'
6
+
7
+ RSpec::Core::RakeTask.new
8
+
9
+ task :default do
10
+ if Dir['spec/dummy'].empty?
11
+ Rake::Task[:test_app].invoke
12
+ Dir.chdir('../../')
13
+ end
14
+ Rake::Task[:spec].invoke
15
+ end
16
+
17
+ desc 'Generates a dummy app for testing'
18
+ task :test_app do
19
+ ENV['LIB_NAME'] = 'spree_stock_locking'
20
+ Rake::Task['extension:test_app'].invoke
21
+ end
data/app/.gitkeep ADDED
File without changes
File without changes
@@ -0,0 +1,42 @@
1
+ # @see https://github.com/spree/spree/blob/759a342d8c223f38f6544b880eb475db3c6f879c/backend/app/controllers/spree/admin/stock_items_controller.rb
2
+ module SpreeStockLocking::Admin::StockItemsControllerDecorator
3
+ def self.prepended(base)
4
+ base.around_action(:lock_with_variant_ids_for_request_params, only: [:create])
5
+ base.around_action(:lock_with_variant_ids_for_stock_item, only: [:update, :destroy])
6
+ end
7
+
8
+ private
9
+
10
+ # @param variant_ids [Array] Get a lock with each variant
11
+ def lock_with_variant_ids(variant_ids, &block)
12
+ variant_id = variant_ids.shift
13
+ if variant_id
14
+ identifier = "variant_id:#{variant_id}"
15
+ # Since the lock mechanism of redis-objects uses blocks,
16
+ # use recursion to handle multiple variant_ids.
17
+ Redis::Lock.new(identifier, expiration: 15, timeout: 10).lock do
18
+ lock_with_variant_ids(variant_ids, &block)
19
+ end
20
+ else
21
+ yield
22
+ end
23
+ end
24
+
25
+ def lock_with_variant_ids_for_stock_item
26
+ variant_ids = [stock_item.variant_id]
27
+ lock_with_variant_ids(variant_ids) do
28
+ yield
29
+ end
30
+ rescue Redis::Lock::LockTimeout
31
+ end
32
+
33
+ def lock_with_variant_ids_for_request_params
34
+ variant_ids = [::Spree::Variant.find(params[:variant_id]).id]
35
+ lock_with_variant_ids(variant_ids) do
36
+ yield
37
+ end
38
+ rescue Redis::Lock::LockTimeout
39
+ end
40
+ end
41
+
42
+ Spree::Admin::StockItemsController.prepend(SpreeStockLocking::Admin::StockItemsControllerDecorator) unless Spree::Admin::StockItemsController.included_modules.include?(SpreeStockLocking::Admin::StockItemsControllerDecorator)
@@ -0,0 +1,44 @@
1
+ # @see https://github.com/spree/spree/blob/759a342d8c223f38f6544b880eb475db3c6f879c/api/app/controllers/spree/api/v2/storefront/checkout_controller.rb
2
+ module SpreeStockLocking
3
+ module Api
4
+ module V2
5
+ module Storefront
6
+ module CheckoutControllerDecorator
7
+ def self.prepended(base)
8
+ base.around_action(:lock_with_variants_ids_for_complete, only: [:next, :advance, :complete])
9
+ end
10
+
11
+ private
12
+
13
+ def lock_with_variants_ids_for_complete
14
+ if spree_current_order.confirm?
15
+ variant_ids = spree_current_order.line_items.pluck(:variant_id)
16
+
17
+ lock_with_variants_ids(variant_ids) do
18
+ yield
19
+ end
20
+ else
21
+ yield
22
+ end
23
+ rescue Redis::Lock::LockTimeout
24
+ end
25
+
26
+ def lock_with_variants_ids(variant_ids, &block)
27
+ variant_id = variant_ids.shift
28
+
29
+ if variant_id
30
+ identifier = "variant_id:#{variant_id}"
31
+ Redis::Lock.new(identifier, expiration: 15, timeout: 10).lock do
32
+ lock_with_variants_ids(variant_ids, &block)
33
+ end
34
+ else
35
+ yield
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ Spree::Api::V2::Storefront::CheckoutController.prepend(SpreeStockLocking::Api::V2::Storefront::CheckoutControllerDecorator) unless Spree::Api::V2::Storefront::CheckoutController.included_modules.include?(SpreeStockLocking::Api::V2::Storefront::CheckoutControllerDecorator)
File without changes
@@ -0,0 +1,13 @@
1
+ module SpreeStockLocking
2
+ class Configuration < Spree::Preferences::Configuration
3
+
4
+ # Some example preferences are shown below, for more information visit:
5
+ # https://dev-docs.spreecommerce.org/internals/preferences
6
+
7
+ preference :enabled, :boolean, default: true
8
+ # preference :dark_chocolate, :boolean, default: true
9
+ # preference :color, :string, default: 'Red'
10
+ # preference :favorite_number, :integer
11
+ # preference :supported_locales, :array, default: [:en]
12
+ end
13
+ end
File without changes
File without changes
data/bin/rails ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" from the root of your extension
3
+
4
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
5
+ ENGINE_PATH = File.expand_path('../../lib/spree_stock_locking/engine', __FILE__)
6
+
7
+ require 'rails/all'
8
+ require 'rails/engine/commands'
@@ -0,0 +1,5 @@
1
+ # Sample localization file for English. Add more files in this directory for other locales.
2
+ # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3
+
4
+ en:
5
+ hello: "Hello world"
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Spree::Core::Engine.add_routes do
2
+ # Add your extension routes here
3
+ end
@@ -0,0 +1,20 @@
1
+ module SpreeStockLocking
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ class_option :migrate, type: :boolean, default: true
5
+
6
+ def add_migrations
7
+ run 'bundle exec rake railties:install:migrations FROM=spree_stock_locking'
8
+ end
9
+
10
+ def run_migrations
11
+ run_migrations = options[:migrate] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]'))
12
+ if run_migrations
13
+ run 'bundle exec rails db:migrate'
14
+ else
15
+ puts 'Skipping rails db:migrate, don\'t forget to run it!'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ module SpreeStockLocking
2
+ class Engine < Rails::Engine
3
+ require 'spree/core'
4
+ isolate_namespace Spree
5
+ engine_name 'spree_stock_locking'
6
+
7
+ # use rspec for tests
8
+ config.generators do |g|
9
+ g.test_framework :rspec
10
+ end
11
+
12
+ initializer 'spree_stock_locking.environment', before: :load_config_initializers do |_app|
13
+ SpreeStockLocking::Config = SpreeStockLocking::Configuration.new
14
+ end
15
+
16
+ def self.activate
17
+ Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
18
+ Rails.configuration.cache_classes ? require(c) : load(c)
19
+ end
20
+ end
21
+
22
+ config.to_prepare(&method(:activate).to_proc)
23
+ end
24
+ end
@@ -0,0 +1,6 @@
1
+ FactoryBot.define do
2
+ # Define your Spree extensions Factories within this file to enable applications, and other extensions to use and override them.
3
+ #
4
+ # Example adding this to your spec_helper will load these Factories for use:
5
+ # require 'spree_stock_locking/factories'
6
+ end
@@ -0,0 +1,11 @@
1
+ module SpreeStockLocking
2
+ VERSION = '0.0.1'.freeze
3
+
4
+ module_function
5
+
6
+ # Returns the version of the currently loaded SpreeStockLocking as a
7
+ # <tt>Gem::Version</tt>.
8
+ def version
9
+ Gem::Version.new VERSION
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ require 'spree_core'
2
+ require 'spree_extension'
3
+ require 'spree_backend'
4
+ require 'spree_auth_devise'
5
+ require 'spree_stock_locking/engine'
6
+ require 'spree_stock_locking/version'
7
+
8
+ require 'redis-objects'
@@ -0,0 +1,33 @@
1
+ # encoding: UTF-8
2
+ lib = File.expand_path('../lib/', __FILE__)
3
+ $LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'spree_stock_locking/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.platform = Gem::Platform::RUBY
9
+ s.name = 'spree_stock_locking'
10
+ s.version = SpreeStockLocking.version
11
+ s.summary = 'A Spree extension that implements stock movement locking with Redis::Lock'
12
+ s.description = ''
13
+ s.required_ruby_version = '>= 2.5'
14
+
15
+ s.author = 'ROUTE06'
16
+ s.email = 'development+rubygems@route06.co.jp'
17
+ s.homepage = 'https://github.com/route06/spree_stock_locking'
18
+ s.license = 'BSD-3-Clause'
19
+
20
+ s.files = `git ls-files`.split("\n").reject { |f| f.match(/^spec/) && !f.match(/^spec\/fixtures/) }
21
+ s.require_path = 'lib'
22
+ s.requirements << 'none'
23
+
24
+ s.add_dependency 'spree', '>= 4.3.0'
25
+ s.add_dependency 'spree_auth_devise'
26
+ s.add_dependency 'spree_backend'
27
+ s.add_dependency 'spree_extension'
28
+
29
+ s.add_dependency 'redis-objects'
30
+
31
+ s.add_development_dependency 'actionmailer' # needed for running rspec
32
+ s.add_development_dependency 'spree_dev_tools'
33
+ end
metadata ADDED
@@ -0,0 +1,165 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spree_stock_locking
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - ROUTE06
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-12-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: spree
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.3.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 4.3.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: spree_auth_devise
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: spree_backend
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: spree_extension
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: redis-objects
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: actionmailer
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: spree_dev_tools
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: ''
112
+ email: development+rubygems@route06.co.jp
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - ".github/workflows/ci.yml"
118
+ - ".gitignore"
119
+ - ".rspec"
120
+ - Gemfile
121
+ - LICENSE
122
+ - README.md
123
+ - Rakefile
124
+ - app/.gitkeep
125
+ - app/controllers/.gitkeep
126
+ - app/controllers/spree_stock_locking/admin/stock_items_controller_decorator.rb
127
+ - app/controllers/spree_stock_locking/api/v2/storefront/checkout_controller_decorator.rb
128
+ - app/models/.gitkeep
129
+ - app/models/spree_stock_locking/configuration.rb
130
+ - app/serializers/.gitkeep
131
+ - app/services/.gitkeep
132
+ - bin/rails
133
+ - config/locales/en.yml
134
+ - config/routes.rb
135
+ - lib/generators/spree_stock_locking/install/install_generator.rb
136
+ - lib/spree_stock_locking.rb
137
+ - lib/spree_stock_locking/engine.rb
138
+ - lib/spree_stock_locking/factories.rb
139
+ - lib/spree_stock_locking/version.rb
140
+ - spree_stock_locking.gemspec
141
+ homepage: https://github.com/route06/spree_stock_locking
142
+ licenses:
143
+ - BSD-3-Clause
144
+ metadata: {}
145
+ post_install_message:
146
+ rdoc_options: []
147
+ require_paths:
148
+ - lib
149
+ required_ruby_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '2.5'
154
+ required_rubygems_version: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ requirements:
160
+ - none
161
+ rubygems_version: 3.2.32
162
+ signing_key:
163
+ specification_version: 4
164
+ summary: A Spree extension that implements stock movement locking with Redis::Lock
165
+ test_files: []