Class: SpreeCmCommissioner::Guests::Finalize

Inherits:
Object
  • Object
show all
Includes:
Spree::ServiceModule::Base
Defined in:
app/services/spree_cm_commissioner/guests/finalize.rb

Constant Summary collapse

MAX_RETRY_ATTEMPTS =
5

Instance Method Summary collapse

Instance Method Details

#assign_bib(guest:, event:, variant:) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'app/services/spree_cm_commissioner/guests/finalize.rb', line 71

def assign_bib(guest:, event:, variant:)
  bib_prefix = variant.bib_prefix

  return false unless variant.bib_required?

  return false if guest.bib_prefix.present?
  return false if guest.event_id.blank?
  return false if event.nil? || guest.event_id != event.id

  guest.bib_prefix = bib_prefix

  # Use PostgreSQL advisory lock to ensure only one process assigns bibs at a time
  advisory_lock("event_#{event.id}_prefix_#{bib_prefix}") do
    last_bib_number = event.guests
                           .where(bib_prefix: bib_prefix)
                           .maximum(:bib_number) || 0

    guest.bib_number = last_bib_number + 1
    guest.bib_index = "#{event.id}-#{bib_prefix}-#{guest.bib_number}"

    guest.save!
    true
  end
end

#call(guest:, variant:, event: nil, user: nil) ⇒ Object

rubocop:disable Metrics/PerceivedComplexity,Metrics/MethodLength,Metrics/CyclomaticComplexity



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'app/services/spree_cm_commissioner/guests/finalize.rb', line 10

def call(guest:, variant:, event: nil, user: nil) # rubocop:disable Metrics/PerceivedComplexity,Metrics/MethodLength,Metrics/CyclomaticComplexity
  attempts = 0

  begin
    attempts += 1

    guest.user = user if user.present?

    bib_assigned = assign_bib(guest: guest, event: event, variant: variant)
    guest.save! unless bib_assigned

    success(guest)
  rescue ActiveRecord::RecordInvalid => e
    # Handle Rails-level validation error
    if e.record.errors[:bib_index].any? && attempts < MAX_RETRY_ATTEMPTS
      # Reload guest to get fresh data and retry
      if guest.persisted?
        guest.reload
      else
        # Clear bib values for new records so they get recalculated on retry
        guest.bib_prefix = nil
        guest.bib_number = nil
        guest.bib_index = nil
      end
      retry
    else
      # Return failure if not a bib_index error or exceeded max attempts
      failure(nil, e.message)
    end
  rescue ActiveRecord::RecordNotUnique => e
    # Handle database-level uniqueness constraint violation
    # Return failure if not a bib_index error or exceeded max attempts
    return failure(nil, e.message) unless e.message.include?('bib_index') && attempts < MAX_RETRY_ATTEMPTS

    # Reload guest to get fresh data and retry
    if guest.persisted?
      guest.reload
    else
      # Clear bib values for new records so they get recalculated on retry
      guest.bib_prefix = nil
      guest.bib_number = nil
      guest.bib_index = nil
    end
    retry
  rescue StandardError => e
    # Catch any unexpected errors from assign_bib or other operations
    return failure(nil, e.message) unless attempts < MAX_RETRY_ATTEMPTS

    # Reload guest to get fresh data and retry
    if guest.persisted?
      guest.reload
    else
      # Clear bib values for new records so they get recalculated on retry
      guest.bib_prefix = nil
      guest.bib_number = nil
      guest.bib_index = nil
    end
    retry
  end
end