spree_core 5.6.0.rc4 → 5.6.0.rc5
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/app/models/spree/order_routing_rule.rb +43 -0
- data/app/models/spree/permission_sets/configuration_management.rb +2 -1
- data/config/locales/en.yml +10 -0
- data/db/migrate/20260721000001_add_unique_type_index_to_spree_order_routing_rules.rb +7 -0
- data/db/sample_data/wholesale.rb +13 -1
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/testing_support/factories/order_routing_rule_factory.rb +14 -0
- metadata +6 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1b3d64f54fca96fb946e3ee9b49d80648677ce7f5c36d0d6bb10769bf8c98df9
|
|
4
|
+
data.tar.gz: 82a353e9cad247a2be8f909d569ab286f323a63fe04b1ef5676d66c72001fdf7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ee39b451ea0e40f7ea1b0811ae858b7a58580952c943b3356a642acf3b04dc5a461c2ae8864db916a14f1dcbe4b46428b924e852fdb21e271d071e3917388561
|
|
7
|
+
data.tar.gz: a90ca190815ef4e7ba9fec0cfe9bce1902b4c00eb35c1cd27c64e2edbe20980d69353826c612b4534cea402723a0cb5db8e9f2da4aea5023d5e51e05764c2175
|
|
@@ -29,7 +29,15 @@ module Spree
|
|
|
29
29
|
|
|
30
30
|
attribute :active, :boolean, default: true
|
|
31
31
|
|
|
32
|
+
# acts_as_list only assigns bottom positions in before_create — too late
|
|
33
|
+
# for the presence validation below, so API creates without an explicit
|
|
34
|
+
# position would 422. Default to the end of the channel's list instead.
|
|
35
|
+
before_validation :set_position_to_end, on: :create, if: -> { position.blank? && channel.present? }
|
|
36
|
+
|
|
32
37
|
validates :type, :channel, presence: true
|
|
38
|
+
# One instance of each rule kind per channel — a duplicate signal would
|
|
39
|
+
# either be a no-op or fight itself in the reducer walk.
|
|
40
|
+
validates :type, uniqueness: { scope: [:channel_id, *spree_base_uniqueness_scope] }
|
|
33
41
|
validates :position, presence: true, numericality: { only_integer: true }
|
|
34
42
|
validate :channel_belongs_to_store
|
|
35
43
|
|
|
@@ -43,6 +51,25 @@ module Spree
|
|
|
43
51
|
|
|
44
52
|
validate :type_must_be_registered
|
|
45
53
|
|
|
54
|
+
# @return [String] localized display name for the rule kind, used by admin pickers
|
|
55
|
+
def self.human_name
|
|
56
|
+
Spree.t("order_routing_rule_types.#{api_type}.name", default: api_type.titleize)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @return [String] localized description for the rule kind
|
|
60
|
+
def self.human_description
|
|
61
|
+
Spree.t("order_routing_rule_types.#{api_type}.description", default: '')
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Feeds the `description` field of `subclasses_with_preference_schema`
|
|
65
|
+
# (the `/types` discovery payload), which only reads `.description`.
|
|
66
|
+
def self.description
|
|
67
|
+
human_description
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def human_name = self.class.human_name
|
|
71
|
+
def human_description = self.class.human_description
|
|
72
|
+
|
|
46
73
|
# Subclasses override. Returns an Array<LocationRanking> — one per location,
|
|
47
74
|
# with rank=nil to abstain.
|
|
48
75
|
#
|
|
@@ -53,8 +80,24 @@ module Spree
|
|
|
53
80
|
raise NotImplementedError, "#{self.class} must implement #rank(order, locations)"
|
|
54
81
|
end
|
|
55
82
|
|
|
83
|
+
# Routes Spree::PreferenceSchema's subclass discovery
|
|
84
|
+
# (`subclasses_with_preference_schema`, `find_by_api_type`) to the
|
|
85
|
+
# order-routing rule registry.
|
|
86
|
+
module ClassMethods
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
def registered_subclasses
|
|
90
|
+
Spree.order_routing.rules
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
extend ClassMethods
|
|
94
|
+
|
|
56
95
|
private
|
|
57
96
|
|
|
97
|
+
def set_position_to_end
|
|
98
|
+
self.position = bottom_position_in_list + 1
|
|
99
|
+
end
|
|
100
|
+
|
|
58
101
|
# The +type+ presence validation already covers blank; here we only reject
|
|
59
102
|
# a present-but-unregistered STI type so arbitrary class names can't be
|
|
60
103
|
# persisted via the +type+ column.
|
|
@@ -45,8 +45,9 @@ module Spree
|
|
|
45
45
|
can :manage, Spree::ReimbursementType
|
|
46
46
|
can :manage, Spree::ReturnReason
|
|
47
47
|
|
|
48
|
-
# Channels
|
|
48
|
+
# Channels + per-channel order routing rules
|
|
49
49
|
can :manage, Spree::Channel
|
|
50
|
+
can :manage, Spree::OrderRoutingRule
|
|
50
51
|
|
|
51
52
|
# Restrictions on immutable types
|
|
52
53
|
cannot [:edit, :update], Spree::RefundReason, mutable: false
|
data/config/locales/en.yml
CHANGED
|
@@ -1190,6 +1190,16 @@ en:
|
|
|
1190
1190
|
strategies:
|
|
1191
1191
|
legacy: Legacy
|
|
1192
1192
|
rules: Rules (ordered)
|
|
1193
|
+
order_routing_rule_types:
|
|
1194
|
+
default_location:
|
|
1195
|
+
description: Prefer the stock location marked as default
|
|
1196
|
+
name: Default location
|
|
1197
|
+
minimize_splits:
|
|
1198
|
+
description: Prefer the location that can fulfill the most items on its own, avoiding split shipments
|
|
1199
|
+
name: Minimize splits
|
|
1200
|
+
preferred_location:
|
|
1201
|
+
description: Fulfill from the location pinned on the order, when one is set
|
|
1202
|
+
name: Preferred location
|
|
1193
1203
|
order_summary: Order Summary
|
|
1194
1204
|
order_total: Order Total
|
|
1195
1205
|
orders: Orders
|
data/db/sample_data/wholesale.rb
CHANGED
|
@@ -20,7 +20,19 @@ end
|
|
|
20
20
|
wholesale_group.add_customers([buyer.id])
|
|
21
21
|
|
|
22
22
|
price_list = store.price_lists.find_or_create_by!(name: 'Wholesale') do |list|
|
|
23
|
-
list.description = 'Wholesale pricing for approved B2B buyers (40% off retail)'
|
|
23
|
+
list.description = 'Wholesale pricing for approved B2B buyers (40% off retail) on orders of 10+ per item'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Case-pack minimum: the trade price applies only when a buyer orders at least
|
|
27
|
+
# WHOLESALE_MIN_QUANTITY of a single item (VolumeRule matches per line item, not
|
|
28
|
+
# per order). Below the threshold the buyer falls back to the retail price — no
|
|
29
|
+
# hard checkout block. This is what makes the demo feel like real wholesale.
|
|
30
|
+
wholesale_min_quantity = 10
|
|
31
|
+
|
|
32
|
+
unless price_list.price_rules.any? { |rule| rule.is_a?(Spree::PriceRules::VolumeRule) }
|
|
33
|
+
volume_rule = Spree::PriceRules::VolumeRule.new(price_list: price_list)
|
|
34
|
+
volume_rule.preferred_min_quantity = wholesale_min_quantity
|
|
35
|
+
volume_rule.save!
|
|
24
36
|
end
|
|
25
37
|
|
|
26
38
|
unless price_list.price_rules.any? { |rule| rule.is_a?(Spree::PriceRules::CustomerGroupRule) }
|
data/lib/spree/core/version.rb
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
FactoryBot.define do
|
|
2
|
+
# STI base can't be persisted (type must be a registered subclass), so the
|
|
3
|
+
# factory defaults to DefaultLocation. Channels seed all built-in kinds on
|
|
4
|
+
# create and `type` is unique per channel, so the factory clears the seeded
|
|
5
|
+
# list — specs get a pristine channel whose only rule is the one built here.
|
|
6
|
+
# Position defaults to the end of the channel's list via the model callback.
|
|
7
|
+
factory :order_routing_rule, class: Spree::OrderRouting::Rules::DefaultLocation do
|
|
8
|
+
channel { association(:channel).tap { |c| c.order_routing_rules.delete_all } }
|
|
9
|
+
store { channel.store }
|
|
10
|
+
|
|
11
|
+
factory :preferred_location_routing_rule, class: Spree::OrderRouting::Rules::PreferredLocation
|
|
12
|
+
factory :minimize_splits_routing_rule, class: Spree::OrderRouting::Rules::MinimizeSplits
|
|
13
|
+
end
|
|
14
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: spree_core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.6.0.
|
|
4
|
+
version: 5.6.0.rc5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sean Schofield
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2026-07-
|
|
13
|
+
date: 2026-07-22 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: i18n-tasks
|
|
@@ -1604,6 +1604,7 @@ files:
|
|
|
1604
1604
|
- db/migrate/20260710000001_add_import_id_status_index_to_spree_import_rows.rb
|
|
1605
1605
|
- db/migrate/20260711000001_add_preferences_to_spree_exports.rb
|
|
1606
1606
|
- db/migrate/20260719000001_add_channel_id_to_spree_api_keys.rb
|
|
1607
|
+
- db/migrate/20260721000001_add_unique_type_index_to_spree_order_routing_rules.rb
|
|
1607
1608
|
- db/sample_data/channels.rb
|
|
1608
1609
|
- db/sample_data/customers.csv
|
|
1609
1610
|
- db/sample_data/markets.rb
|
|
@@ -1748,6 +1749,7 @@ files:
|
|
|
1748
1749
|
- lib/spree/testing_support/factories/options_factory.rb
|
|
1749
1750
|
- lib/spree/testing_support/factories/order_factory.rb
|
|
1750
1751
|
- lib/spree/testing_support/factories/order_promotion_factory.rb
|
|
1752
|
+
- lib/spree/testing_support/factories/order_routing_rule_factory.rb
|
|
1751
1753
|
- lib/spree/testing_support/factories/payment_capture_event_factory.rb
|
|
1752
1754
|
- lib/spree/testing_support/factories/payment_factory.rb
|
|
1753
1755
|
- lib/spree/testing_support/factories/payment_method_factory.rb
|
|
@@ -1865,9 +1867,9 @@ licenses:
|
|
|
1865
1867
|
- BSD-3-Clause
|
|
1866
1868
|
metadata:
|
|
1867
1869
|
bug_tracker_uri: https://github.com/spree/spree/issues
|
|
1868
|
-
changelog_uri: https://github.com/spree/spree/releases/tag/v5.6.0.
|
|
1870
|
+
changelog_uri: https://github.com/spree/spree/releases/tag/v5.6.0.rc5
|
|
1869
1871
|
documentation_uri: https://docs.spreecommerce.org/
|
|
1870
|
-
source_code_uri: https://github.com/spree/spree/tree/v5.6.0.
|
|
1872
|
+
source_code_uri: https://github.com/spree/spree/tree/v5.6.0.rc5
|
|
1871
1873
|
post_install_message:
|
|
1872
1874
|
rdoc_options: []
|
|
1873
1875
|
require_paths:
|