ManageIQ/manageiq-consumption

View on GitHub
app/models/manageiq/showback/envelope.rb

Summary

Maintainability
A
35 mins
Test Coverage
A
98%
module ManageIQ::Showback
  class Envelope < ApplicationRecord
    self.table_name = 'showback_envelopes'

    belongs_to :resource, :polymorphic => true

    monetize :accumulated_cost_subunits
    default_value_for :accumulated_cost, Money.new(0)

    before_save :check_envelope_state, :if => :state_changed?

    has_many :data_views,
             :dependent   => :destroy,
             :inverse_of  => :envelope,
             :foreign_key => :showback_envelope_id
    has_many :data_rollups,
             :through     => :data_views,
             :inverse_of  => :envelopes,
             :foreign_key => :showback_envelope_id

    validates :name,                  :presence => true
    validates :description,           :presence => true
    validates :resource,              :presence => true
    validates :start_time, :end_time, :presence => true
    validates :state,                 :presence => true, :inclusion => { :in => %w(OPEN PROCESSING CLOSED) }

    # Test that end_time happens later than start_time.
    validate  :start_time_before_end_time

    def start_time_before_end_time
      errors.add(:end_time, _('should happen after start_time')) unless end_time.to_i > start_time.to_i
    end

    def check_envelope_state
      case state_was
      when 'OPEN' then
        raise _("Envelope can't change state to CLOSED from OPEN") unless state != 'CLOSED'
        # s_time = (self.start_time + 1.months).beginning_of_month # This is never used
        s_time = end_time != start_time.end_of_month ? end_time : (start_time + 1.month).beginning_of_month
        e_time = s_time.end_of_month
        generate_envelope(s_time, e_time) unless ManageIQ::Showback::Envelope.exists?(:resource => resource, :start_time => s_time)
      when 'PROCESSING' then raise _("Envelope can't change state to OPEN from PROCESSING") unless state != 'OPEN'
      when 'CLOSED' then raise _("Envelope can't change state when it's CLOSED")
      end
    end

    def add_data_rollup(data_rollup)
      if data_rollup.kind_of?(ManageIQ::Showback::DataRollup)
        # verify that the event is not already there
        if data_rollups.include?(data_rollup)
          errors.add(:data_rollups, 'duplicate')
        else
          dataview = ManageIQ::Showback::DataView.new(:data_rollup => data_rollup, :envelope => self)
          dataview.save
        end
      else
        errors.add(:data_rollups, "Error Type #{data_rollup.type} is not ManageIQ::Showback::DataRollup")
      end
    end

    # Remove events from a envelope, no error is thrown

    def remove_data_rollup(data_rollup)
      if data_rollup.kind_of?(ManageIQ::Showback::DataRollup)
        if data_rollups.include?(data_rollup)
          data_rollups.delete(data_rollup)
        else
          errors.add(:data_rollups, "not found")
        end
      else
        errors.add(:data_rollups, "Error Type #{data_rollup.type} is not ManageIQ::Showback::DataRollup")
      end
    end

    def get_data_view(input)
      ch = find_data_view(input)
      if ch.nil?
        Money.new(0)
      else
        ch.cost
      end
    end

    def update_data_view(input, cost)
      ch = find_data_view(input)
      unless ch.nil?
        ch.cost = Money.new(cost)
        ch
      end
    end

    def add_data_view(input, cost)
      ch = find_data_view(input)
      # updates an existing dataviews
      if ch
        ch.cost = Money.new(cost)
      elsif input.class == ManageIQ::Showback::DataRollup # Or create a new one
        ch = data_views.new(:data_rollup => input,
                            :cost        => cost)
      else
        errors.add(:input, 'bad class')
        return
      end
      ch.save
      ch
    end

    def clear_data_view(input)
      ch = find_data_view(input)
      ch.cost = 0
      ch.save
    end

    def sum_of_data_views
      a = Money.new(0)
      data_views.each do |x|
        a += x.cost if x.cost
      end
      a
    end

    def clean_all_data_views
      data_views.each(&:clean_cost)
    end

    def calculate_data_view(input)
      ch = find_data_view(input)
      if ch.kind_of?(ManageIQ::Showback::DataView)
        ch.cost = ch.calculate_cost(find_price_plan) || Money.new(0)
        save
      elsif input.nil?
        errors.add(:data_view, 'not found')
        Money.new(0)
      else
        input.errors.add(:data_view, 'not found')
        Money.new(0)
      end
    end

    def calculate_all_data_views
      # plan = find_price_plan
      data_views.each do |x|
        calculate_data_view(x)
      end
    end

    def find_price_plan
      # TODO
      # For the demo: return one price plan, we will create the logic later
      # parent = resource
      # do
      # result = ManageIQ::Providers::Showback::Manager::PricePlan.where(resource: parent)
      # parent = parent.parent if !result
      # while !result || !parent
      # result || ManageIQ::Providers::Showback::Manager::PricePlan.where(resource = MiqEnterprise)
      ManageIQ::Showback::PricePlan.first
    end

    def find_data_view(input)
      if input.kind_of?(ManageIQ::Showback::DataRollup)
        data_views.find_by(:data_rollup => input, :envelope => self)
      elsif input.kind_of?(ManageIQ::Showback::DataView) && (input.envelope == self)
        input
      end
    end

    private

    def generate_envelope(s_time, e_time)
      envelope = ManageIQ::Showback::Envelope.create(:name        => name,
                                                        :description => description,
                                                        :resource    => resource,
                                                        :start_time  => s_time,
                                                        :end_time    => e_time,
                                                        :state       => 'OPEN')
      data_views.each do |data_view|
        ManageIQ::Showback::DataView.create(
          :stored_data   => {
            data_view.stored_data_last_key => data_view.stored_data_last
          },
          :data_rollup   => data_view.data_rollup,
          :envelope      => envelope,
          :cost_subunits => data_view.cost_subunits,
          :cost_currency => data_view.cost_currency
        )
      end
    end
  end
end