accountability 0.2.1 → 0.2.2
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 +4 -4
- data/README.md +32 -2
- data/app/controllers/accountability/billing_configurations_controller.rb +3 -0
- data/app/controllers/accountability/order_groups_controller.rb +9 -4
- data/app/controllers/accountability_controller.rb +4 -0
- data/app/models/accountability/billing_configuration.rb +8 -1
- data/app/models/accountability/inventory.rb +40 -7
- data/app/models/accountability/order_group.rb +5 -2
- data/app/models/accountability/order_item.rb +12 -2
- data/app/models/accountability/price_override.rb +8 -0
- data/app/models/accountability/product.rb +1 -0
- data/app/models/concerns/accountability/active_merchant_interface/stripe_interface.rb +2 -0
- data/config/locales/en.yml +2 -0
- data/lib/accountability/configuration.rb +1 -1
- data/lib/accountability/extensions/acts_as_offerable.rb +5 -0
- data/lib/accountability/types/billing_configuration_types.rb +8 -0
- data/lib/accountability/version.rb +1 -1
- data/lib/generators/accountability/install_generator.rb +4 -4
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25f8546f25aae663976cd6cd712b38b444a385a9b5b609bf9f0fa0f1f62e0bb0
|
4
|
+
data.tar.gz: 278fb73d9c9d2f9d3a5c7ed609514b82cceb9db892508cb5bda6464b8e959607
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4bfd0bf5a59e3a8804a96739d416f9dbbb6ade1a56d6bdc821a207eafc58fe783086511001f40262b9c7175e30f8a17078a23af4e1ea1f79d18a1558650b1ab3
|
7
|
+
data.tar.gz: 869170f02d04650f64beefa7cc616189420575ceb497ba7ae97b3970f635ce29c1c555bc66bc1157831cfc02f9dc6c4bf97c99b3097c8a1ae2da5b883f2363e6
|
data/README.md
CHANGED
@@ -102,6 +102,19 @@ config.tax_rate = 9.53
|
|
102
102
|
|
103
103
|
Note that products can be marked as tax exempt.
|
104
104
|
|
105
|
+
#### Country Whitelist
|
106
|
+
To limit which countries your application accepts credit cards from, you can define a whitelist.
|
107
|
+
|
108
|
+
The whitelist must be an array of [two-character ISO country codes](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements).
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
config.country_whitelist = %w[US CA MX]
|
112
|
+
```
|
113
|
+
|
114
|
+
When a `country_whitelist` is specified, the BillingConfiguration's country field will be validated for inclusion.
|
115
|
+
|
116
|
+
The first country listed in the whitelist will be used as the default value for all new BillingConfiguration records.
|
117
|
+
|
105
118
|
#### Debugger tools
|
106
119
|
To print helpful session information in the views such as the currently tracked billable entity, enable the dev tools.
|
107
120
|
|
@@ -142,7 +155,24 @@ end
|
|
142
155
|
#### Dynamic Pricing
|
143
156
|
AKA traits
|
144
157
|
|
158
|
+
## Contributing
|
159
|
+
The only current contribution guideline is that we ask contributors to include detailed commit descriptions and avoid pushing merge commits.
|
160
|
+
|
161
|
+
### Versioning
|
162
|
+
The version number listed in `lib/accountability/version.rb` is the version being actively developed.
|
163
|
+
|
164
|
+
It is formatted `MAJOR.MINOR.TINY`:
|
165
|
+
- MAJOR - Will be set to `1` once ready for public use, at which point we will switch to semantic versioning.
|
166
|
+
- MINOR - Is bumped prior to implementing breaking changes.
|
167
|
+
- TINY - Is bumped after implementing new features or other meaningful changes.
|
168
|
+
|
169
|
+
Rebuild the gem after updating the `version.rb` file.
|
170
|
+
```bash
|
171
|
+
gem build accountability.gemspec
|
172
|
+
```
|
173
|
+
|
145
174
|
## TODO
|
146
175
|
- [ ] Finish implementing multi-tenanting features
|
147
|
-
- [ ]
|
148
|
-
- [ ]
|
176
|
+
- [ ] Update views to support full E-commerce functionality out of the box
|
177
|
+
- [ ] Add test coverage
|
178
|
+
- [ ] Add test helpers
|
@@ -53,6 +53,9 @@ module Accountability
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def updated_billing_elements
|
56
|
+
return unless partial_exists? 'configurations', within: 'accountability/accounts/billing_configurations'
|
57
|
+
return unless partial_exists? 'payment_form', within: 'accountability/accounts'
|
58
|
+
|
56
59
|
configurations_partial = 'accountability/accounts/billing_configurations/configurations'
|
57
60
|
payment_form_partial = 'accountability/accounts/payment_form'
|
58
61
|
|
@@ -16,12 +16,15 @@ module Accountability
|
|
16
16
|
def edit; end
|
17
17
|
|
18
18
|
def create
|
19
|
-
@order_group = OrderGroup.new(order_group_params)
|
19
|
+
@order_group = params[:order_group].present? ? OrderGroup.new(order_group_params) : OrderGroup.new
|
20
|
+
source_scope = params.to_unsafe_h[:source_scope]&.symbolize_keys
|
20
21
|
|
21
22
|
if @order_group.save
|
22
|
-
|
23
|
+
@order_group.add_item!(params[:product_id], source_scope: source_scope) if params[:product_id].present?
|
24
|
+
|
25
|
+
redirect_to accountability_order_group_path(@order_group), notice: 'Successfully created new order_group'
|
23
26
|
else
|
24
|
-
|
27
|
+
redirect_back fallback_location: root_path, alert: 'Failed to create cart'
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
@@ -43,7 +46,9 @@ module Accountability
|
|
43
46
|
|
44
47
|
def add_item
|
45
48
|
product = Product.find(params[:product_id])
|
46
|
-
|
49
|
+
source_scope = params.to_unsafe_h[:source_scope]&.symbolize_keys
|
50
|
+
|
51
|
+
if @order_group.add_item! product, source_scope: source_scope
|
47
52
|
redirect_to accountability_order_group_path(current_order_group), notice: 'Successfully added to cart'
|
48
53
|
else
|
49
54
|
redirect_back fallback_location: accountability_order_groups_path, alert: 'Failed to add to cart'
|
@@ -44,4 +44,8 @@ class AccountabilityController < ApplicationController
|
|
44
44
|
order_group_id = session[:current_order_group_id]
|
45
45
|
Accountability::OrderGroup.find_by(id: order_group_id)
|
46
46
|
end
|
47
|
+
|
48
|
+
def partial_exists?(partial_name, within:)
|
49
|
+
helpers.lookup_context.template_exists?(partial_name, within, true)
|
50
|
+
end
|
47
51
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Accountability
|
2
2
|
class BillingConfiguration < ApplicationRecord
|
3
3
|
include Accountability::ActiveMerchantInterface
|
4
|
-
after_initialize :set_provider, if: :new_record?
|
4
|
+
after_initialize :set_provider, :set_default_country, if: :new_record?
|
5
5
|
|
6
6
|
belongs_to :account
|
7
7
|
has_many :payments, dependent: :restrict_with_error
|
@@ -37,5 +37,12 @@ module Accountability
|
|
37
37
|
def set_provider
|
38
38
|
self.provider = Configuration.payment_gateway[:provider]
|
39
39
|
end
|
40
|
+
|
41
|
+
def set_default_country
|
42
|
+
return unless self.billing_address.present?
|
43
|
+
return unless Configuration.country_whitelist.present?
|
44
|
+
|
45
|
+
self.billing_address.country = Configuration.country_whitelist.first
|
46
|
+
end
|
40
47
|
end
|
41
48
|
end
|
@@ -8,7 +8,7 @@ require 'forwardable'
|
|
8
8
|
#
|
9
9
|
# Usage:
|
10
10
|
# inventory = Inventory.new(product)
|
11
|
-
# inventory.
|
11
|
+
# inventory.available.count
|
12
12
|
|
13
13
|
module Accountability
|
14
14
|
class Inventory
|
@@ -25,10 +25,14 @@ module Accountability
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def collection
|
28
|
-
|
29
|
-
|
28
|
+
source_records.map { |record| InventoryItem.new(record: record, product: product, inventory: self) }
|
29
|
+
end
|
30
30
|
|
31
|
-
|
31
|
+
def source_records
|
32
|
+
records = source_class.where(**source_scope).includes(:price_overrides)
|
33
|
+
records = records.public_send(offerable_template.whitelist) if scope_availability?
|
34
|
+
records = records.order(@order_params) if @order_params.present?
|
35
|
+
records
|
32
36
|
end
|
33
37
|
|
34
38
|
def available
|
@@ -37,18 +41,47 @@ module Accountability
|
|
37
41
|
self
|
38
42
|
end
|
39
43
|
|
44
|
+
def order(order_params)
|
45
|
+
@order_params = order_params
|
46
|
+
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def available_source_ids
|
51
|
+
return @available_source_ids if @available_source_ids.present?
|
52
|
+
|
53
|
+
@available_source_ids = Inventory.new(product, available_only: true).source_records.ids
|
54
|
+
end
|
55
|
+
|
40
56
|
private
|
41
57
|
|
42
58
|
class InventoryItem
|
43
|
-
attr_accessor :record, :product
|
59
|
+
attr_accessor :record, :product, :inventory
|
44
60
|
|
45
|
-
def initialize(record:, product:)
|
61
|
+
def initialize(record:, product:, inventory:)
|
46
62
|
@record = record
|
47
63
|
@product = product
|
64
|
+
@inventory = inventory
|
65
|
+
|
66
|
+
# Expose source record through offerable's name
|
67
|
+
record_alias = product.offerable_category.to_sym
|
68
|
+
alias :"#{record_alias}" record
|
48
69
|
end
|
49
70
|
|
50
71
|
def price
|
51
|
-
|
72
|
+
# Iterating pre-loaded content is faster with Ruby than an N+1 in SQL
|
73
|
+
price_override = record.price_overrides.find { |override| override.product_id == product.id }
|
74
|
+
price_override&.price || product.price
|
75
|
+
end
|
76
|
+
|
77
|
+
def available?
|
78
|
+
return @available unless @available.nil?
|
79
|
+
|
80
|
+
@available = inventory.available_source_ids.include? record.id
|
81
|
+
end
|
82
|
+
|
83
|
+
def unavailable?
|
84
|
+
!available?
|
52
85
|
end
|
53
86
|
end
|
54
87
|
|
@@ -29,8 +29,11 @@ module Accountability
|
|
29
29
|
order_items.each(&:accrue_credit!)
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
# The `product` parameter accepts Product, String, and Integer objects
|
33
|
+
def add_item!(product, source_scope: nil)
|
34
|
+
product = Product.find(product) unless product.is_a? Product
|
35
|
+
|
36
|
+
order_items.create! product: product, source_scope: source_scope.presence
|
34
37
|
end
|
35
38
|
|
36
39
|
def unassigned?
|
@@ -51,7 +51,15 @@ class Accountability::OrderItem < ApplicationRecord
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def default_price
|
54
|
-
product.price
|
54
|
+
price_override&.price || product.price
|
55
|
+
end
|
56
|
+
|
57
|
+
def price_override
|
58
|
+
return @price_override unless @price_override.nil?
|
59
|
+
return unless source_records.one?
|
60
|
+
|
61
|
+
# Memoize as `false` if nil to avoid re-running query
|
62
|
+
@price_override = product.price_overrides.find_by(offerable_source: source_records) || false
|
55
63
|
end
|
56
64
|
|
57
65
|
def trigger_callback(trigger)
|
@@ -76,9 +84,11 @@ class Accountability::OrderItem < ApplicationRecord
|
|
76
84
|
end
|
77
85
|
|
78
86
|
def source_records
|
87
|
+
return @source_records unless @source_records.nil?
|
88
|
+
|
79
89
|
return [] if source_scope.empty?
|
80
90
|
return [] if product.source_class.nil?
|
81
91
|
|
82
|
-
product.source_class.where(**source_scope)
|
92
|
+
@source_records = product.source_class.where(**source_scope)
|
83
93
|
end
|
84
94
|
end
|
@@ -13,6 +13,7 @@ module Accountability
|
|
13
13
|
|
14
14
|
has_and_belongs_to_many :coupons
|
15
15
|
has_many :order_items, dependent: :restrict_with_error
|
16
|
+
has_many :price_overrides, dependent: :destroy
|
16
17
|
has_many :credits, through: :order_items, inverse_of: :product
|
17
18
|
|
18
19
|
serialize :source_scope, Hash
|
data/config/locales/en.yml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Accountability
|
2
2
|
class Configuration
|
3
3
|
class << self
|
4
|
-
attr_accessor :logo_path, :payment_gateway, :dev_tools_enabled
|
4
|
+
attr_accessor :logo_path, :payment_gateway, :dev_tools_enabled, :country_whitelist
|
5
5
|
attr_writer :tax_rate, :admin_checker, :billable_identifier, :billable_name_column
|
6
6
|
|
7
7
|
def tax_rate
|
@@ -14,6 +14,11 @@ module Accountability
|
|
14
14
|
end
|
15
15
|
|
16
16
|
self.acts_as = acts_as.dup << :offerable
|
17
|
+
|
18
|
+
if reflections['price_overrides'].blank?
|
19
|
+
has_many :price_overrides, class_name: 'Accountability::PriceOverride',
|
20
|
+
as: :offerable_source, dependent: :destroy
|
21
|
+
end
|
17
22
|
end
|
18
23
|
|
19
24
|
alias_method :acts_as_offerable, :has_offerable
|
@@ -14,6 +14,14 @@ module Accountability
|
|
14
14
|
|
15
15
|
validates :address_1, :city, :state, :country, presence: true
|
16
16
|
validates :zip, numericality: { only_integer: true }
|
17
|
+
validate :validate_country_whitelisted
|
18
|
+
|
19
|
+
def validate_country_whitelisted
|
20
|
+
return unless Configuration.country_whitelist.present?
|
21
|
+
return if country.blank?
|
22
|
+
|
23
|
+
errors.add(:country, :not_permitted) unless Configuration.country_whitelist.include? country
|
24
|
+
end
|
17
25
|
end
|
18
26
|
|
19
27
|
class BillingAddressType < ActiveModel::Type::Value
|
@@ -9,10 +9,10 @@ module Accountability
|
|
9
9
|
include ActiveRecord::Generators::Migration
|
10
10
|
source_root File.join(__dir__, 'templates')
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
def create_initializer_file
|
13
|
+
initializer_content = "Accountability.configure { |_config| }"
|
14
|
+
create_file "config/initializers/accountability.rb", initializer_content
|
15
|
+
end
|
16
16
|
|
17
17
|
def copy_migration
|
18
18
|
# Note: migration.rb is always up-to-date
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: accountability
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Stowers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-03-
|
11
|
+
date: 2020-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: active_accountability_merchant
|
@@ -116,6 +116,7 @@ files:
|
|
116
116
|
- app/models/accountability/order_group.rb
|
117
117
|
- app/models/accountability/order_item.rb
|
118
118
|
- app/models/accountability/payment.rb
|
119
|
+
- app/models/accountability/price_override.rb
|
119
120
|
- app/models/accountability/product.rb
|
120
121
|
- app/models/accountability/statement.rb
|
121
122
|
- app/models/accountability/transactions.rb
|