我已经构建了一个跟踪图书销售情况的应用程序,并且希望能够计算作者版税。

现在,我按订单跟踪销售情况。每个订单都有_many :line_items。当保存一个新的订单项时,我会计算给定产品的总销售额,所以我有一个总销售额。

每个作者都有多个基于他们的契约(Contract)的版税规则。例如,销售 0 到 5000 份,他们得到 10%。 5001 到 10,000,他们得到 20%。起初,我正在计算每个订单项的作者份额。它运行良好,但后来我意识到我的应用程序正在根据总销售额选择要应用的版税规则。如果我发布了一个大订单,那么作者的版税可能会以整个订单项的高版税率计算,而实际上,应根据较低和高的版税率计算版税(例如,一行项目插入总销售额通过版税规则断点)。

所以我的问题是如何最好地解决这个问题。我已经探索过使用范围,但这对我来说有点新,代码变得有点复杂。这是我用来将给定契约(Contract)的所有版税规则提取到数组中的公认笨重的代码:

  def royalty_rate
    @product = Product.find_by_id(product_id)
    @total_sold = @product.total_sold
    @rules = Contract.find_by_product_id(@product).royalties
    ... where next?
  end

@rules 对每个版税规则都有 :lower 和 :upper,所以对于这个产品,第一个 :lower 将为 0, :upper 将为 5000,然后第二个 :lower 将为 5001,第二个 :upper 将为 10,000,很快。

对此的任何帮助或想法将不胜感激。这实际上是我获得一个可以玩的完整版本的最后一步。

我使用下面的这段代码根据 total_sold 的值挑选出一个特定的规则,但同样,这具有采用累积销售额并选择最高版税率而不是拆分它们的效果。
    @rules = @contract.royalties.where("lower <= :total_sold AND upper >= :total_sold", {:total_sold => @total_sold}).limit(1)

提前致谢。

最佳答案

听起来您需要为每个作者单独存储版税计算规则——或者您可能有多个方案并且每个作者都与其中一个相关联?

对于第一种情况,可能是这样的:

class Author
  has_many :royalty_rules
end

class RoyaltyRule
  belongs_to :author
  # columns :lower, :upper, :rate
end

因此,当添加作者时,您可以为每一层的 RoyalRule 模型添加行。那么你需要一种计算版税的方法
class Author
  def royalty(product)
    product = Product.find_by_id(product.id)
    units = product.total_sold
    amount = 0
    royalty_rules.each do |rule|
      case units
      when 0
      when Range.new(rule.lower,rule.upper)
        # reached the last applicable rule -- add the part falling within the tier
        amount += (units - rule.lower + 1) * rule.rate
        break
      else
        # add the full amount for the tier
        amount += (rule.upper - rule.lower + 1) * rule.rate
      end
    end
    amount
  end
end

以及一些要测试的规范:
describe Author do
  before(:each) do
    @author = Author.new
    @tier1 = mock('tier1',:lower=>1,:upper=>5000,:rate=>0.10)
    @tier2 = mock('tier2',:lower=>5001,:upper=>10000,:rate=>0.20)
    @tier3 = mock('tier3',:lower=>10001,:upper=>15000,:rate=>0.30)
    @author.stub(:royalty_rules) { [@tier1,@tier2,@tier3] }
  end

  it "should work for one tier" do
    product = mock('product',:total_sold=>1000)
    @author.royalty(product).should == 100
  end

  it "should work for two tiers" do
    product = mock('product',:total_sold=>8000)
    @author.royalty(product).should == (5000 * 0.10) + (3000 * 0.20)
  end

  it "should work for three tiers" do
    product = mock('product',:total_sold=>14000)
    @author.royalty(product).should == (5000 * 0.10) + (5000 * 0.20) + (4000 * 0.30)
  end

  # edge cases
  it "should be zero when units is zero" do
    product = mock('product',:total_sold=>0)
    @author.royalty(product).should == 0
  end

  it "should be 500 when units is 5000" do
    product = mock('product',:total_sold=>5000)
    @author.royalty(product).should == 500
  end

  it "should be 500.2 when units is 5001" do
    product = mock('product',:total_sold=>5001)
    @author.royalty(product).should == 500.2
  end
end

注意:Author.royalty_rules 需要返回从低到高排序的层。此外,为了更容易计算,最低层从 1 开始而不是 0。

关于ruby-on-rails - 根据 Rails 3 中的范围计算版税,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4719942/

10-12 07:34