From 9def02fbe0b6aff50966da66474d25a6782a2a2b Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 15 Sep 2026 15:35:11 +0000 Subject: [PATCH] Fix members#new 500 when pricing hits a nil amount MembershipPricing#add called round_to_five_cents on nil when the registration form asked for activity participations but no delivery cycle could be resolved. Treat missing price parts as zero and skip activity/extra math without a cycle or delivery count. Co-authored-by: Thibaud Guillaume-Gentil --- app/models/membership_pricing.rb | 32 +++++++++++++++++++---- test/models/membership_pricing_test.rb | 35 ++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/app/models/membership_pricing.rb b/app/models/membership_pricing.rb index 9ada3153a..d5278a0b5 100644 --- a/app/models/membership_pricing.rb +++ b/app/models/membership_pricing.rb @@ -62,15 +62,25 @@ def baskets_price_extras comp_prices = [ 0, 0 ] complements_prices.each { |p| - comp_prices = comp_prices.zip(p.map(&:round_to_five_cents)).map(&:sum) + comp_prices = comp_prices.zip(rounded_prices(p)).map(&:sum) } [ - deliveries_counts.min * calculate_price_extra(extra, basket_size, comp_prices.min / deliveries_counts.min, deliveries_counts.min), - deliveries_counts.max * calculate_price_extra(extra, basket_size, comp_prices.max / deliveries_counts.max, deliveries_counts.max) + extra_total(deliveries_counts.min, extra, comp_prices.min), + extra_total(deliveries_counts.max, extra, comp_prices.max) ] end + def extra_total(deliveries_count, extra, complements_price) + return 0 unless deliveries_count&.positive? + + deliveries_count * calculate_price_extra( + extra, + basket_size, + complements_price / deliveries_count, + deliveries_count) + end + def calculate_price_extra(extra, basket_size, complements_price, deliveries_count) return 0 if extra.to_f.zero? return 0 unless basket_size @@ -96,10 +106,13 @@ def complement_prices(complement_id, quantity) complement = BasketComplement.find_by(id: complement_id) return [ 0, 0 ] unless complement return [ 0, 0 ] if quantity.zero? + return [ 0, 0 ] unless delivery_cycles.any? deliveries_counts = delivery_cycles.map { |dc| dc.billable_deliveries_count_for_basket_complement(complement) }.uniq + return [ 0, 0 ] if deliveries_counts.empty? || deliveries_counts.any?(&:nil?) + [ deliveries_counts.min * complement.price * quantity, deliveries_counts.max * complement.price * quantity @@ -109,8 +122,11 @@ def complement_prices(complement_id, quantity) def activity_participations_prices return [ 0, 0 ] unless @params[:activity_participations_demanded_annually] return [ 0, 0 ] unless basket_size + return [ 0, 0 ] unless delivery_cycles.any? + + fy = Delivery.last&.fiscal_year + return [ 0, 0 ] unless fy - fy = Delivery.last.fiscal_year counts = delivery_cycles.map { |dc| m = Membership.new( started_on: fy.beginning_of_year, @@ -126,6 +142,8 @@ def activity_participations_prices demanded = ActivityParticipationDemanded.new(m).count -1 * (demanded - default) * Current.org.activity_price } + return [ 0, 0 ] if counts.empty? || counts.any?(&:nil?) + [ counts.min, counts.max ] end @@ -185,6 +203,10 @@ def depot def add(prices) @min, @max = - [ @min, @max ].zip(prices.map(&:round_to_five_cents)).map(&:sum) + [ @min, @max ].zip(rounded_prices(prices)).map(&:sum) + end + + def rounded_prices(prices) + Array(prices).map { |price| (price || 0).round_to_five_cents } end end diff --git a/test/models/membership_pricing_test.rb b/test/models/membership_pricing_test.rb index 7d268c240..d43ceb5b8 100644 --- a/test/models/membership_pricing_test.rb +++ b/test/models/membership_pricing_test.rb @@ -357,6 +357,41 @@ def pricing(params = {}) assert_equal [ 140 + (2 + 1) * 50 ], pricing.prices end + test "does not raise when activity participations are set but no delivery cycles apply" do + org( + activity_participations_form_min: 0, + activity_participations_form_max: 10, + activity_price: 50) + + depot = depots(:farm) + depot.delivery_cycles.clear + + pricing = pricing( + waiting_basket_size_id: small_id, + waiting_depot_id: depot.id, + waiting_delivery_cycle_id: "", + waiting_basket_price_extra: "1.0", + waiting_activity_participations_demanded_annually: "10") + + assert_equal [ 0 ], pricing.prices + assert_not pricing.present? + end + + test "does not raise when activity participations are set without depot or cycle" do + org( + activity_participations_form_min: 0, + activity_participations_form_max: 10, + activity_price: 50) + DeliveryCycle.visible.each { |cycle| cycle.update!(depots: []) } + + pricing = pricing( + waiting_basket_size_id: small_id, + waiting_delivery_cycle_id: "", + waiting_activity_participations_demanded_annually: "10") + + assert_equal [ 0 ], pricing.prices + end + test "basket size with availability restrictions reduces deliveries count" do # Small basket is 10 price, mondays has 10 deliveries = 100 pricing = pricing(