voormedia/rails-erd

View on GitHub
examples/applications/spree/models/calculator/vat.rb

Summary

Maintainability
A
3 hrs
Test Coverage
class Calculator::Vat < Calculator

  def self.description
    I18n.t("vat")
  end

  def self.register
    super
    TaxRate.register_calculator(self)
  end

  # list the vat rates for the default country
  def self.default_rates
    origin = Country.find(Spree::Config[:default_country_id])
    calcs = Calculator::Vat.find(:all, :include => {:calculable => :zone}).select {
      |vat| vat.calculable.zone.country_list.include?(origin)
    }
    calcs.collect { |calc| calc.calculable }
  end

  def self.calculate_tax(order, rates=default_rates)
    return 0 if rates.empty?
    # note: there is a bug with associations in rails 2.1 model caching so we're using this hack
    # (see https://rails.lighthouseapp.com/projects/8994/tickets/785-caching-models-fails-in-development)
    cache_hack = rates.first.respond_to?(:tax_category_id)

    taxable_totals = {}
    order.line_items.each do |line_item|
      next unless tax_category = line_item.variant.product.tax_category
      next unless rate = rates.find { | vat_rate | vat_rate.tax_category_id == tax_category.id } if cache_hack
      next unless rate = rates.find { | vat_rate | vat_rate.tax_category == tax_category } unless cache_hack
      taxable_totals[tax_category] ||= 0
      taxable_totals[tax_category] += line_item.price * rate.amount * line_item.quantity
    end

    return 0 if taxable_totals.empty?
    tax = 0
    taxable_totals.values.each do |total|
      tax += total
    end
    tax
  end

  # TODO: Refactor this method after integrating #54 to use default address
  def self.calculate_tax_on(product_or_variant)
    vat_rates = default_rates

    return 0 if vat_rates.nil?
    return 0 unless tax_category = product_or_variant.is_a?(Product) ? product_or_variant.tax_category : product_or_variant.product.tax_category
    return 0 unless rate = vat_rates.find { | vat_rate | vat_rate.tax_category_id == tax_category.id }

    (product_or_variant.is_a?(Product) ? product_or_variant.price : product_or_variant.price) * rate.amount
  end

  # computes vat for line_items associated with order, and tax rate
  def compute(order)
    rate = self.calculable
    line_items = order.line_items.select { |i| i.product.tax_category == rate.tax_category }
    line_items.inject(0) {|sum, line_item|
      sum += (line_item.price * rate.amount * line_item.quantity)
    }
  end
end