from typing import List, Sequence from .hospitality_tronc_allocation_types import TroncMember, TroncMethod, TroncShare from .money_allocate import allocate from .money_amount import Money, money def _whole(value: object) -> bool: return isinstance(value, int) and not isinstance(value, bool) def _weight_of(member: TroncMember, method: str) -> int: if method == "hours": return member.minutes_worked if method == "points": return member.points if method == "hours-and-points": return member.minutes_worked * member.points raise ValueError('unknown tronc method "%s"' % (method,)) def tronc_allocation(pool: Money, staff: Sequence[TroncMember], method: TroncMethod) -> List[TroncShare]: """Share a tips pool between staff in proportion to a weight. Time is in minutes so a 7.5-hour shift is exact. The pool is split with money.allocate, so the shares add up to the pool exactly: the leftover pennies go to the largest remainders, ties to whoever is listed first. """ if len(staff) == 0: raise ValueError("staff must have at least one member") if pool.minor < 0: raise ValueError("pool must not be negative, received %d" % (pool.minor,)) ids = set() for member in staff: if member.id == "": raise ValueError("every member needs an id") if member.id in ids: raise ValueError('staff id "%s" appears twice' % (member.id,)) ids.add(member.id) if not _whole(member.minutes_worked) or member.minutes_worked < 0: raise ValueError( 'minutesWorked must not be negative, received %s for "%s"' % (member.minutes_worked, member.id) ) if not _whole(member.points) or member.points < 0: raise ValueError('points must not be negative, received %s for "%s"' % (member.points, member.id)) weights = [_weight_of(member, method) for member in staff] if sum(weights) == 0: if pool.minor != 0: raise ValueError("nobody in the pool has any weight to share it by") return [TroncShare(id=member.id, weight=0, share=money(0, pool.currency)) for member in staff] shares = allocate(pool, weights) return [TroncShare(id=member.id, weight=weights[i], share=shares[i]) for i, member in enumerate(staff)]