main
 1using System.Collections.Generic;
 2
 3namespace solidware.financials.service.domain.payroll
 4{
 5    public class Grant
 6    {
 7        Date issued_on;
 8        History<UnitPrice> price_history = new History<UnitPrice>();
 9        Units units = Units.Empty;
10        List<Vest> expirations = new List<Vest>();
11
12        static public Grant New(Money purchase_amount, UnitPrice price, Fraction portion, Frequency frequency)
13        {
14            var grant = new Grant
15                        {
16                            issued_on = Calendar.today(),
17                        };
18            grant.change_unit_price_to(price);
19            grant.purchase(purchase_amount);
20            grant.apply_vesting_frequency(portion, frequency);
21            return grant;
22        }
23
24        Grant() {}
25
26        public virtual void change_unit_price_to(UnitPrice new_price)
27        {
28            price_history.record(new_price);
29        }
30
31        public virtual bool was_issued_on(Date date)
32        {
33            return issued_on.Equals(date);
34        }
35
36        public virtual Money balance()
37        {
38            return balance(Calendar.today());
39        }
40
41        public virtual Money balance(Date on_date)
42        {
43            return unit_price(on_date).total_value_of(units_remaining(on_date));
44        }
45
46        Units units_remaining(Date on_date)
47        {
48            var remaining = Units.Empty;
49            foreach (var expiration in expirations)
50            {
51                remaining = remaining.combined_with(expiration.unvested_units(units, on_date));
52            }
53            return remaining;
54        }
55
56        void purchase(Money amount)
57        {
58            units = units.combined_with(current_unit_price().purchase_units(amount));
59        }
60
61        UnitPrice current_unit_price()
62        {
63            return unit_price(Calendar.today());
64        }
65
66        UnitPrice unit_price(Date on_date)
67        {
68            return price_history.recorded(on_date);
69        }
70
71        void apply_vesting_frequency(Fraction portion, Frequency frequency)
72        {
73            var next_date = issued_on.minus_days(1);
74            portion.each(x =>
75            {
76                next_date = frequency.next(next_date);
77                expirations.Add(new Vest(portion, next_date));
78            });
79        }
80    }
81}