1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
#!/usr/bin/env ruby -w
# encoding: UTF-8
#
# = ChargeSet.rb -- The TaskJuggler III Project Management Software
#
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
# by Chris Schlaeger <cs@taskjuggler.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
require 'taskjuggler/TjException'
class TaskJuggler
# A charge set describes how a given amount is distributed over a set of
# accounts. It stores the percentage share for each account. The accumulated
# percentages must always be 100% for a valid charge set. For consistency
# reasons, accounts must always be leaf accounts of the same top-level
# account. Percentage values must range from 0.0 to 1.0.
class ChargeSet
attr_reader :master
# Create a new ChargeSet object.
def initialize
@set = {}
@master = nil
end
# Add a new account to the set. Accounts and share rates must meet a number
# of requirements. This method does some error checking and raises a
# TjException in case of problems. It cannot check everything. Accounts can
# later be turned into group accounts or the total share sum may not be
# 100%. This needs to be checked at a later stage. Accounts may have a share
# of nil. This will be set in ChargeSet#complete later.
def addAccount(account, share)
unless account.leaf?
raise TjException.new,
"Account #{account.fullId} is a group account and cannot be used " +
"in a chargeset."
end
if @set.include?(account)
raise TjException.new,
"Account #{account.fullId} is already a member of the charge set."
end
if @master.nil?
@master = account.root
elsif @master != account.root
raise TjException.new,
"All members of this charge set must belong to the " +
"#{@master.fullId} account. #{account.fullId} belongs to " +
"#{account.root.fullId}."
end
if account.container?
raise TjException.new,
"#{account.fullId} is a group account. Only leaf accounts are " +
"allowed for a charge set."
end
if share && (share < 0.0 || share > 1.0)
raise TjException.new, "Charge set shares must be between 0 and 100%"
end
@set[account] = share
end
def each
@set.each do |account, share|
yield account, share
end
end
# Check for accounts that don't have a share yet and distribute the
# remainder to 100% evenly accross them.
def complete
# Calculate the current total share.
totalPercent = 0.0
undefined = 0
@set.each_value do |share|
if share
totalPercent += share
else
undefined += 1
end
end
# Must be less than 100%.
if totalPercent > 1.0
raise TjException.new,
"Total share of this set (#{totalPercent * 100}%) excedes 100%."
end
if undefined > 0
commonShare = (1.0 - totalPercent) / undefined
if commonShare <= 0
raise TjException.new,
"Total share is 100% but #{undefined} account(s) still exist."
end
@set.each do |account, share|
if share.nil?
@set[account] = commonShare
end
end
elsif totalPercent != 1.0
raise TjException.new,
"Total share of this set is #{totalPercent * 100} instead of 100%."
end
end
# Return the share percentage for a given Account _account_.
def share(account)
@set[account]
end
# Return the set as comma separated list of account ID + share pairs.
def to_s
str = '('
@set.each do |account, share|
str += ', ' unless str == '('
str += "#{account.fullId} #{share * 100}%"
end
str += ')'
end
end
end
|