summaryrefslogtreecommitdiffstats
path: root/lib/balanced_batch.ml
blob: 5a64546df45431bc433b7517f46a1f1e39d414bd (about) (plain) (blame)
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
open Prelude

(* Degenerate transactions, which can be applied directly to account
   hierarchies (because we ideally want no unsafe operations on
   accounts) *)
module Make (K : Map_intf.Key) : sig
  type entry = {
    dc : Money.Debit_credit.t;
    commodity : Money.Commodity_id.t;
    amount : Money.Amount.t;
  }

  type t
  type error = Unbalanced

  val make : entry Map.Make(K).t -> (t, error) result
  val entries : t -> entry Map.Make(K).t
end = struct
  type entry = {
    dc : Money.Debit_credit.t;
    commodity : Money.Commodity_id.t;
    amount : Money.Amount.t;
  }

  type t = entry Map.Make(K).t
  type error = Unbalanced

  let is_balanced entries =
    Map.fold entries ~init:Money.Commodity_id.Map.empty
      ~f:(fun ~key:_ ~data comm_balances ->
        Map.update comm_balances data.commodity ~f:(fun ocomm_bal ->
            let comm_bal = Option.value ocomm_bal ~default:Money.Diff.(~$0) in
            match data.dc with
            | Money.Debit_credit.Debit -> Money.Diff.(comm_bal +% data.amount)
            | Money.Debit_credit.Credit -> Money.Diff.(comm_bal -% data.amount)))
    |> Map.for_all ~f:(fun comm_bal -> Money.Diff.(comm_bal = ~$0))

  let make entries =
    if not (is_balanced entries) then Error Unbalanced else Ok entries

  let entries entries = entries (* ambiguous? I disagree *)
end