solidus_advanced_pricing 0.3.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0feded43570200af31d61d2822614677e232d696b480196576c0651edafee278
4
- data.tar.gz: 20b1184e197fc387a095d5af68b7936fc894ccd213b6386a259bff8f0e77e6e5
3
+ metadata.gz: 35df8c1a684ddc6520796b75efe4f865cd2bee381230ad1a5323afe4207f3bd3
4
+ data.tar.gz: db971affc7d958d3e84c31fedc96be694723ea83f040b397ef752cc6917e8155
5
5
  SHA512:
6
- metadata.gz: c2a90ff27650243c41246a0dfa7b9cd1b6a672c73060dcf6abcaf007f101baefdf3d627c28301ac06e576b1a7bb1a4f9602135935a6cbe2327ea62918fa20d20
7
- data.tar.gz: 5b57c0ee2ef362b15e377db52ebd80c1624db43c3c94d69846e8e93bfacb7ce17864766f35cb9ee56c8113a424b3afb5a6d550be20b18872eefa6f8bd04ef595
6
+ metadata.gz: c62e682f06170ff5f6322f5a08ee020e88383a216fd3e955bb5cfba667b007711bb0396c2f9d7567df1b5cc827389bbee0c4f04c28d5ab8d928a81c00b2e6d87
7
+ data.tar.gz: 57bf9dfe07f8cf5849a15dd675efe63022a92032c9e431b2cbfa164d76a35f47dab71772ced385f8f451c5b7c153cca9e8ed696cbf63783556b9aea47a55062d
data/CHANGELOG.md CHANGED
@@ -4,6 +4,28 @@ All notable changes to this project are documented here. The format is based on
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to
5
5
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.3.1] - 2026-09-23
8
+
9
+ ### Fixed
10
+
11
+ - **Installing the gem without registering its price selector broke every
12
+ `variant.price = ...`**, product creation included, with
13
+ `NoMethodError: undefined method 'price_type_id' for an instance of
14
+ Spree::Variant::PricingOptions`. Core calls `default_price` on the way into
15
+ `price=`, and this gem's override reached for a typed fallback through
16
+ `pricing_options.with(price_type_id: :any)` — which only works on this gem's
17
+ own `PricingOptions`. A store that left
18
+ `Spree::Config.variant_price_selector_class` alone got core's, where `with`
19
+ falls through to ActiveSupport's `Object#with` and `public_send`s the key.
20
+ Present since 0.2.0, when the fallback was added.
21
+
22
+ The fallback is now skipped unless this gem's pricing options are in play.
23
+ Without the selector there are no typed prices to fall back to, so the right
24
+ answer is core's: nothing.
25
+ - `Spree::Variant#price_of_type` and `#base_price` now raise
26
+ `SolidusAdvancedPricing::SelectorNotRegistered`, naming the setting to change,
27
+ instead of a `NoMethodError` about `price_type_id`.
28
+
7
29
  ## [0.3.0] - 2026-09-23
8
30
 
9
31
  ### Added
@@ -113,6 +135,7 @@ Initial release.
113
135
  bucket. Without the role component a role-targeted price would be cached and served to
114
136
  guests.
115
137
 
138
+ [0.3.1]: https://github.com/fcpeuro/solidus_advanced_pricing/compare/v0.3.0...v0.3.1
116
139
  [0.3.0]: https://github.com/fcpeuro/solidus_advanced_pricing/compare/v0.2.0...v0.3.0
117
140
  [0.2.0]: https://github.com/fcpeuro/solidus_advanced_pricing/compare/v0.1.0...v0.2.0
118
141
  [0.1.0]: https://github.com/fcpeuro/solidus_advanced_pricing/releases/tag/v0.1.0
@@ -27,6 +27,8 @@ module SolidusAdvancedPricing
27
27
 
28
28
  # nil means the untyped base price. Accepts a PriceType, an id, or a code.
29
29
  def price_of_type(price_type, pricing_options = ::Spree::Config.default_pricing_options)
30
+ SolidusAdvancedPricing.assert_advanced_pricing_options!(pricing_options)
31
+
30
32
  price_selector.price_for_options(
31
33
  pricing_options.with(price_type_id: SolidusAdvancedPricing.resolve_price_type_id(price_type))
32
34
  )
@@ -41,9 +43,22 @@ module SolidusAdvancedPricing
41
43
  # A MAP-restricted variant may carry no untyped price at all; fall back so
42
44
  # variant.price is never blank when some price exists.
43
45
  def default_price
44
- super || price_selector.price_for_options(
45
- ::Spree::Config.default_pricing_options.with(price_type_id: :any)
46
- )
46
+ super || typed_fallback_price
47
+ end
48
+
49
+ private
50
+
51
+ # Core calls default_price on the way into `price=`, so this runs in stores
52
+ # that installed the gem and never registered its selector. Those get core's
53
+ # PricingOptions, which has no price_type_id, and `with` would raise rather
54
+ # than fall back -- breaking every `variant.price = ...`, product creation
55
+ # included. Without the selector there are no typed prices to fall back to
56
+ # anyway, so the right answer is core's: nothing.
57
+ def typed_fallback_price
58
+ pricing_options = ::Spree::Config.default_pricing_options
59
+ return unless SolidusAdvancedPricing.advanced_pricing_options?(pricing_options)
60
+
61
+ price_selector.price_for_options(pricing_options.with(price_type_id: :any))
47
62
  end
48
63
 
49
64
  ::Spree::Variant.prepend self
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusAdvancedPricing
4
- VERSION = "0.3.0"
4
+ VERSION = "0.3.1"
5
5
  end
@@ -5,6 +5,38 @@ require "solidus_advanced_pricing/version"
5
5
  require "solidus_advanced_pricing/engine"
6
6
 
7
7
  module SolidusAdvancedPricing
8
+ # Raised when an advanced-pricing lookup is attempted in a store that never
9
+ # registered this gem's price selector.
10
+ class SelectorNotRegistered < StandardError
11
+ def initialize(message = nil)
12
+ super(message || <<~MESSAGE.strip)
13
+ SolidusAdvancedPricing::PriceSelector is not registered, so pricing options
14
+ carry no price type and this lookup cannot be answered. Set
15
+
16
+ Spree::Config.variant_price_selector_class = "SolidusAdvancedPricing::PriceSelector"
17
+
18
+ (the install generator writes this into config/initializers/solidus_advanced_pricing.rb).
19
+ MESSAGE
20
+ end
21
+ end
22
+
23
+ # Whether this gem's PricingOptions -- and therefore its selector -- is in play.
24
+ # A store can install the gem and leave Spree::Config.variant_price_selector_class
25
+ # alone; everything then has to behave exactly as core does.
26
+ #
27
+ # Tested by class, not by `respond_to?(:price_type_id)`: price_type_id is not a
28
+ # reader on either class, it lives in desired_attributes. What actually differs
29
+ # is that this gem's PricingOptions overrides `with` to merge arbitrary
30
+ # attributes, where core's falls through to ActiveSupport's Object#with, which
31
+ # public_sends every key it is given.
32
+ def self.advanced_pricing_options?(pricing_options = ::Spree::Config.default_pricing_options)
33
+ pricing_options.is_a?(SolidusAdvancedPricing::PricingOptions)
34
+ end
35
+
36
+ def self.assert_advanced_pricing_options!(pricing_options = ::Spree::Config.default_pricing_options)
37
+ raise SelectorNotRegistered unless advanced_pricing_options?(pricing_options)
38
+ end
39
+
8
40
  # nil stays nil (the base price); a PriceType or id passes through; a code resolves.
9
41
  def self.resolve_price_type_id(price_type)
10
42
  case price_type
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solidus_advanced_pricing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrick McMorran