0

我有一个验证方法必须验证在另一种方法中分配的值,我怎样才能让它在验证之前识别这些值?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
4

2 回答 2

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

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

一个好的实践规则是,如果一个方法长于一行,并且您无法通过浏览它来判断它的用途,那么它就太长了(这并不总是正确的,但对于复杂的方法值得考虑)。

于 2013-02-01T06:25:17.457 回答
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
于 2013-02-01T16:46:55.360 回答