Class: SpreeCmCommissioner::ServiceFeeRule
- Inherits:
-
Base
- Object
- Base
- SpreeCmCommissioner::ServiceFeeRule
- Includes:
- Spree::AdjustmentSource, Spree::CalculatedAdjustments
- Defined in:
- app/models/spree_cm_commissioner/service_fee_rule.rb
Constant Summary collapse
- ALLOWED_RULEABLE_TYPES =
%w[Spree::Product Spree::Taxon Spree::Vendor].freeze
Class Method Summary collapse
-
.adjust(order, line_items) ⇒ Object
Deletes all service-fee adjustments on these line items, then recreates them from whichever rule currently resolves for each one.
-
.available_calculator_types ⇒ Object
Spree calculators only expose a fixed, hardcoded set of calculable model types (Rails.application.config.spree.calculators is a plain Struct — tax_rates, shipping_methods, promotion_actions_*).
-
.resolve_for(line_item:, currency:) ⇒ Object
Walks product -> event -> vendor -> global, returning the first active rule that matches the currency.
- .ruleables_for(line_item) ⇒ Object
- .vendor_for(line_item) ⇒ Object
Instance Method Summary collapse
-
#adjust(order, line_item) ⇒ Object
create_adjustment (from Spree::AdjustmentSource) is protected — callable with an explicit receiver only from inside another instance method of this class, not from the self.adjust class method above, where self is the class rather than an instance.
- #compute_amount(line_item) ⇒ Object
-
#fee_description ⇒ Object
A short, human-readable summary for admin listings, e.g.
- #ruleable_type_label ⇒ Object
- #scope_label ⇒ Object
Class Method Details
.adjust(order, line_items) ⇒ Object
Deletes all service-fee adjustments on these line items, then recreates them from whichever rule currently resolves for each one. Mirrors Spree::TaxRate.adjust: a plain destroy-then-create (not create_unique_adjustment, which only guards against duplicates and would leave a stale amount in place after a rule edit or a quantity change).
67 68 69 70 71 72 73 74 |
# File 'app/models/spree_cm_commissioner/service_fee_rule.rb', line 67 def self.adjust(order, line_items) Spree::Adjustment.where(adjustable: line_items).service_fee.destroy_all line_items.each do |line_item| rule = resolve_for(line_item: line_item, currency: order.currency) rule&.adjust(order, line_item) end end |
.available_calculator_types ⇒ Object
Spree calculators only expose a fixed, hardcoded set of calculable model types
(Rails.application.config.spree.calculators is a plain Struct — tax_rates,
shipping_methods, promotion_actions_*). There's no slot for a commissioner-owned
model, so — same as SpreeCmCommissioner::PricingAction — we expose our own list
instead of relying on the inherited calculators class method.
118 119 120 |
# File 'app/models/spree_cm_commissioner/service_fee_rule.rb', line 118 def self.available_calculator_types [SpreeCmCommissioner::Calculators::ServiceFeePercent, SpreeCmCommissioner::Calculators::ServiceFeeFlatAmount] end |
.resolve_for(line_item:, currency:) ⇒ Object
Walks product -> event -> vendor -> global, returning the first active rule that matches the currency. The product/event/vendor leg mirrors SpreeCmCommissioner::TicketTransfers::FeeCalculator's precedence.
"Global" means two different things depending on whether the vendor belongs to a tenant:
- No tenant (a base BookMe+ vendor): the true platform-wide default (tenant_id nil).
- Has a tenant: ONLY that tenant's own default (tenant_id: vendor.tenant_id) — deliberately does NOT fall back to the platform-wide default if the tenant hasn't set one. Each white-label tenant is expected to configure their own fee (or explicitly have none); a tenant silently inheriting BookMe+'s own fee because they forgot to configure one would be a surprising, not a sensible, default.
95 96 97 98 99 100 101 102 |
# File 'app/models/spree_cm_commissioner/service_fee_rule.rb', line 95 def self.resolve_for(line_item:, currency:) ruleables_for(line_item).each do |ruleable| rule = active_for(ruleable: ruleable, currency: currency).first return rule if rule.present? end active_for_tenant(tenant_id: vendor_for(line_item)&.tenant_id, currency: currency).first end |
.ruleables_for(line_item) ⇒ Object
104 105 106 |
# File 'app/models/spree_cm_commissioner/service_fee_rule.rb', line 104 def self.ruleables_for(line_item) [line_item.product, line_item.event, vendor_for(line_item)] end |
.vendor_for(line_item) ⇒ Object
108 109 110 111 |
# File 'app/models/spree_cm_commissioner/service_fee_rule.rb', line 108 def self.vendor_for(line_item) product = line_item.product product.respond_to?(:vendor) ? product.vendor : nil end |
Instance Method Details
#adjust(order, line_item) ⇒ Object
create_adjustment (from Spree::AdjustmentSource) is protected — callable with an explicit receiver only from inside another instance method of this class, not from the self.adjust class method above, where self is the class rather than an instance. This public wrapper is the same shape Spree::TaxRate#adjust uses for the identical reason.
80 81 82 |
# File 'app/models/spree_cm_commissioner/service_fee_rule.rb', line 80 def adjust(order, line_item) create_adjustment(order, line_item) end |
#compute_amount(line_item) ⇒ Object
122 123 124 |
# File 'app/models/spree_cm_commissioner/service_fee_rule.rb', line 122 def compute_amount(line_item) calculator&.compute(line_item) || 0 end |
#fee_description ⇒ Object
A short, human-readable summary for admin listings, e.g. "10%" or "$0.25" — so a rule's actual fee doesn't require opening it to see. Two calculator types (not one combined percent+flat calculator) means there's always exactly one number to show here.
129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'app/models/spree_cm_commissioner/service_fee_rule.rb', line 129 def fee_description case calculator when SpreeCmCommissioner::Calculators::ServiceFeePercent "#{calculator.preferred_percent.to_d.round(2).to_s('F')}%" when SpreeCmCommissioner::Calculators::ServiceFeeFlatAmount Spree::Money.new(calculator.preferred_flat_amount, currency: currency).to_s when nil Spree.t(:service_fee_rule_not_configured) else calculator.description end end |
#ruleable_type_label ⇒ Object
156 157 158 159 160 161 162 163 |
# File 'app/models/spree_cm_commissioner/service_fee_rule.rb', line 156 def ruleable_type_label case ruleable_type when 'Spree::Product' then Spree.t(:service_fee_rule_scope_product) when 'Spree::Taxon' then Spree.t(:service_fee_rule_scope_event) when 'Spree::Vendor' then Spree.t(:service_fee_rule_scope_vendor) else ruleable_type&.demodulize || Spree.t(:service_fee_rule_scope_global) end end |
#scope_label ⇒ Object
142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'app/models/spree_cm_commissioner/service_fee_rule.rb', line 142 def scope_label if ruleable.blank? # A tenant-scoped row is that tenant's own "global" — it never falls back to the # BookMe+-level one (see resolve_for), so it isn't really "global" in the broad sense; # labeled as its own Tenant scope rather than reusing the word "Global" for both. return Spree.t(:service_fee_rule_scope_tenant, name: tenant&.name || "##{tenant_id}") if tenant_id.present? return Spree.t(:service_fee_rule_scope_global) end label_value = ruleable.respond_to?(:name) ? ruleable.name.to_s : "##{ruleable_id}" "#{ruleable_type_label}: #{label_value}" end |