1+ open Base
2+ open CalendarLib
3+ open Calendar
4+ open Accountid
5+ open Account_sig
6+ open Common
7+
8+ module Account : Account_sig = struct
9+ (* implementation of an account *)
10+
11+ (* hidden implementation for the base parts of an account *)
12+ type account_base = {
13+ no : Accountno .t ;
14+ name : Accountname .t ;
15+ date_of_open : CalendarLib.Calendar .t ;
16+ date_of_close : CalendarLib.Calendar .t option ;
17+ }
18+
19+ (* the abstract representation of the account *)
20+ type t = {
21+ base : account_base ;
22+ account_type : Common .account_type ;
23+ }
24+
25+ (* the concrete representations of account no and account name *)
26+ (* hidden as part of the account representation *)
27+ type account_no = Accountno .t
28+ type account_name = Accountname .t
29+
30+ let build_account_base no name date_of_open date_of_close =
31+ {
32+ no;
33+ name;
34+ date_of_open;
35+ date_of_close
36+ }
37+
38+ let validator_account_open_date =
39+ let open Tvalidator in
40+ TradingValidator. date_in_future " Cannot be in future"
41+
42+ let validate_base ~no ~name ~account_open_date ~account_close_date =
43+ let open Validator in
44+ let valid = build build_account_base
45+ |> keep no
46+ |> keep name
47+ |> validate account_open_date validator_account_open_date
48+ |> keep account_close_date in
49+ match valid with
50+ | Ok base -> Ok base
51+ | Error e -> Error e
52+
53+ let create_trading_account ~no ~name ~trading_currency ~account_open_date =
54+ let valid = validate_base ~no ~name ~account_open_date ~account_close_date: None in
55+ match valid with
56+ | Ok base -> Ok { base; account_type = Trading trading_currency }
57+ | Error e -> Error e
58+
59+ let create_settlement_account ~no ~name ~settlement_currency ~account_open_date =
60+ let valid = validate_base ~no ~name ~account_open_date ~account_close_date: None in
61+ match valid with
62+ | Ok base -> Ok { base; account_type = Settlement settlement_currency }
63+ | Error e -> Error e
64+
65+ let create_both_account ~no ~name ~trading_currency ~settlement_currency ~account_open_date =
66+ let valid = validate_base ~no ~name ~account_open_date ~account_close_date: None in
67+ match valid with
68+ | Ok base -> Ok { base; account_type = Both (trading_currency, settlement_currency) }
69+ | Error e -> Error e
70+
71+ let validate_close ~account : t ~date_of_close = match t.base.date_of_close with
72+ | Some _ -> Error " Account is already closed"
73+ | None -> match compare t.base.date_of_open date_of_close with
74+ | 0 -> Error " Account open and close date cannot be the same"
75+ | 1 -> Error " Account open date cannot be after close date"
76+ | _ -> Ok t
77+
78+ let close ~account : t ~date_of_close =
79+ let open Result in
80+ validate_close ~account: t ~date_of_close >> = fun _ ->
81+ Ok {
82+ t with base = {
83+ t.base with date_of_close = Some date_of_close
84+ }
85+ }
86+
87+ let get_account_type t = t.account_type
88+
89+ let get_account_no t = t.base.no
90+
91+ let get_account_name t = t.base.name
92+
93+ let get_trading_and_settlement_currency = function
94+ | { base = _ ; account_type = Trading trading_currency } -> (Some trading_currency, None )
95+ | { base = _ ; account_type = Settlement settlement_currency } -> (None , Some settlement_currency)
96+ | { base = _ ; account_type = Both (trading_currency , settlement_currency ) } -> (Some trading_currency, Some settlement_currency)
97+ end
0 commit comments