在另一种方法中包括验证方法

时间:2013-02-01 06:05:55

标签: ruby-on-rails ruby ruby-on-rails-3

我有一个验证方法,必须验证在另一个方法中分配的值,如何让它在验证之前识别这些值? pay_must_be_same_to_amount方法需要create_items_from_readings方法中的一些值

class Invoice < ActiveRecord::Base
  attr_accessible :approved_by, :due_date, :invoice_date, :reading_ids, :terms, :customer_id, :customer, :status, :reference_no, :payment_method, :amount, :payment_date

  has_many :invoice_items, :dependent => :destroy
  belongs_to :customer, :inverse_of => :invoices

  validate :pay_must_be_same_to_amount

  def create_item_from_readings
    item = invoice_items.new
    item.rate = customer.unit_cost

    readings_in_this_period = customer.unbilled_readings.where('date_of_reading <= ?',  invoice_date).order(:date_of_reading)
    return nil if readings_in_this_period.empty?

    self.reading_ids = readings_in_this_period.collect(&:id).join(',')

    total_units = 0
    readings_in_this_period.each do |reading|
      total_units = total_units + reading.units_used1 + reading.units_used2 + reading.units_used3
    end

    item.amount = total_units * customer.unit_cost * customer.ct_ratio
    item.tax_amount = (item.amount * Settings.vat) if customer.pays_vat

    invoice_from_reading = readings_in_this_period.first.previous_reading
    invoice_from_reading ||= readings_in_this_period.first
    invoice_to_reading = readings_in_this_period.last


  #Select Item description based on Phase type
    if customer.phase_type == 'Single Phase'
      item.description = "Electricity used from #{invoice_from_reading.date_of_reading.strftime('%d/%m/%Y')} with readings #{invoice_from_reading.reading1} to #{invoice_to_reading.date_of_reading.strftime('%d/%m/%Y')} with   reading #{invoice_to_reading.reading1} - #{total_units.to_i} total units"
    else
      item.description = "Electricity used from #{invoice_from_reading.date_of_reading.strftime('%d/%m/%Y')} with readings, R1: #{invoice_from_reading.reading1}, R2: #{invoice_from_reading.reading2}, R3: #{invoice_from_reading.reading3} to #{invoice_to_reading.date_of_reading.strftime('%d/%m/%Y')} with  readings, R1: #{invoice_to_reading.reading1}, R2:#{invoice_to_reading.reading2}, R3: # {invoice_to_reading.reading3}- #{total_units.to_i} total units"
    end
  end 
end

并且验证方法如下,需要将上面的item.amount与类Invoice中的金额进行比较

 def pay_must_be_same_to_amount
  if item.amount < self.amount && item.amount != self.amount
    self.errors.add :amount, 'The payment amount should be equal to amount on invoice' 
  end
 end
end

2 个答案:

答案 0 :(得分:0)

一些评论:create_item_from_readings太复杂了。我不知道它应该做什么,但如果你运行它,我相信它会返回一个字符串(上一个if语句中的两个之一)。

如果您需要做的就是将item.amount与发票amount属性进行比较,那很简单。您几乎可以在编写时使用验证方法,并根据需要使用其他一些方法。

def item_amount
  total_units * customer.unit_cost * customer.ct_ratio
end

def total_units
  readings_in_this_period.inject(0) {|total,r| total + r.units_used1 + r.units_used2 + r.units_used3 }
end

def pay_must_be_same_to_amount
  if item_amount != amount
    errors.add :amount, 'The payment amount should be equal to amount on invoice'
  end
end

这两种补充方法的代码只是用较长方法修改的代码。

一个好的实践规则是,如果一个方法长于一行,并且你无法通过浏览它来判断它是什么,它太长了(这不是总是为真,但是考虑到复杂的方法,这是值得的。)

答案 1 :(得分:0)

问题的解决方案是

def pay_must_be_same_to_amount
 sum = 0
 self.invoice_items.each do |invoice_item|
  sum = sum + invoice_item.amount
end
 if sum != self.amount
  self.errors.add :amount, 'The payment amount should be equal to amount on invoice' 
 end
end
相关问题