class Budget class Phase < ActiveRecord::Base PHASE_KINDS = %w(drafting informing accepting reviewing selecting valuating publishing_prices balloting reviewing_ballots finished).freeze PUBLISHED_PRICES_PHASES = %w(publishing_prices balloting reviewing_ballots finished).freeze SUMMARY_MAX_LENGTH = 1000 DESCRIPTION_MAX_LENGTH = 2000 belongs_to :budget belongs_to :next_phase, class_name: 'Budget::Phase', foreign_key: :next_phase_id has_one :prev_phase, class_name: 'Budget::Phase', foreign_key: :next_phase_id validates :budget, presence: true validates :kind, presence: true, uniqueness: { scope: :budget }, inclusion: { in: PHASE_KINDS } validates :summary, length: { maximum: SUMMARY_MAX_LENGTH } validates :description, length: { maximum: DESCRIPTION_MAX_LENGTH } validate :invalid_dates_range? validate :prev_phase_dates_valid? validate :next_phase_dates_valid? before_validation :sanitize_description after_save :adjust_date_ranges after_save :touch_budget scope :enabled, -> { where(enabled: true) } scope :published, -> { enabled.where.not(kind: 'drafting') } scope :drafting, -> { find_by_kind('drafting') } scope :informing, -> { find_by_kind('informing') } scope :accepting, -> { find_by_kind('accepting')} scope :reviewing, -> { find_by_kind('reviewing')} scope :selecting, -> { find_by_kind('selecting')} scope :valuating, -> { find_by_kind('valuating')} scope :publishing_prices, -> { find_by_kind('publishing_prices')} scope :balloting, -> { find_by_kind('balloting')} scope :reviewing_ballots, -> { find_by_kind('reviewing_ballots')} scope :finished, -> { find_by_kind('finished')} def next_enabled_phase next_phase&.enabled? ? next_phase : next_phase&.next_enabled_phase end def prev_enabled_phase prev_phase&.enabled? ? prev_phase : prev_phase&.prev_enabled_phase end def invalid_dates_range? if starts_at.present? && ends_at.present? && starts_at >= ends_at errors.add(:starts_at, I18n.t('budgets.phases.errors.dates_range_invalid')) end end private def adjust_date_ranges if enabled? next_enabled_phase&.update_column(:starts_at, ends_at) prev_enabled_phase&.update_column(:ends_at, starts_at) elsif enabled_changed? next_enabled_phase&.update_column(:starts_at, starts_at) end end def touch_budget budget.touch end def prev_phase_dates_valid? if enabled? && starts_at.present? && prev_enabled_phase.present? prev_enabled_phase.assign_attributes(ends_at: starts_at) if prev_enabled_phase.invalid_dates_range? phase_name = I18n.t("budgets.phase.#{prev_enabled_phase.kind}") error = I18n.t('budgets.phases.errors.prev_phase_dates_invalid', phase_name: phase_name) errors.add(:starts_at, error) end end end def next_phase_dates_valid? if enabled? && ends_at.present? && next_enabled_phase.present? next_enabled_phase.assign_attributes(starts_at: ends_at) if next_enabled_phase.invalid_dates_range? phase_name = I18n.t("budgets.phase.#{next_enabled_phase.kind}") error = I18n.t('budgets.phases.errors.next_phase_dates_invalid', phase_name: phase_name) errors.add(:ends_at, error) end end end def sanitize_description self.description = WYSIWYGSanitizer.new.sanitize(description) end end end