summaryrefslogtreecommitdiffstats
path: root/lib/ledger.ml
blob: fd1b2a9e4ac32a306aafccc873dbba09030aaef7 (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
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
open Core

type account_type = Asset | Equity | Liability | Expense | Income

type tx_type =
  | Interest_tx
  | Online_banking_tx
  | Recurrent_direct_tx
  | Payment_terminal_tx
  | Cash_payment_tx
  | Atm_tx
  | Auto_save_rounding_tx
  | Batch_tx
  | Direct_debit_tx
  | Periodic_tx

type iban_tag = Account_tag | Counterparty_iban_tag [@@deriving compare]

type unit_tag = Filed_tag | GooglePay_tag | AutoRoundSavings_tag
[@@deriving compare]

type string_tag =
  | Desc_tag
  | User_tag
  | Counterparty_name_tag
  | Reference_tag
  | Mandate_id_tag
  | Creditor_id_tag
  | Other_party_tag
  | Transaction_tag
  | Terminal_tag
  | Card_seq_no_tag
  | Savings_account_tag
[@@deriving compare]

module Label = struct
  type 'a t =
    | Iban_label : iban_tag -> Iban.t t
    | String_label : string_tag -> string t
    | Timestamp_label : Time_ns.t t
    | Unit_label : unit_tag -> unit t

  let int_to_cmp x : ('a, 'a) Dmap.cmp =
    if x < 0 then Lt else if x > 0 then Gt else Eq

  let compare (type a1 a2) (v1 : a1 t) (v2 : a2 t) : (a1, a2) Dmap.cmp =
    match (v1, v2) with
    | Iban_label t1, Iban_label t2 -> int_to_cmp @@ [%compare: iban_tag] t1 t2
    | String_label t1, String_label t2 ->
        int_to_cmp @@ [%compare: string_tag] t1 t2
    | Timestamp_label, Timestamp_label -> Eq
    | Unit_label t1, Unit_label t2 -> int_to_cmp @@ [%compare: unit_tag] t1 t2
    | Iban_label _, _ -> Lt
    | String_label _, Iban_label _ -> Gt
    | String_label _, _ -> Lt
    | Timestamp_label, Unit_label _ -> Lt
    | Timestamp_label, _ -> Gt
    | Unit_label _, _ -> Gt
end

module Labels = Dmap.Make (Label)

module Money : sig
  type t

  val equal : t -> t -> bool
  val compare : t -> t -> int
  val of_z : Z.t -> t
  val to_z : t -> Z.t
  val ( + ) : t -> t -> t
  val ( - ) : t -> t -> t
end = struct
  type t = Z.t

  let equal = Z.equal
  let compare = Z.compare
  let of_z = Fn.id
  let to_z = Fn.id
  let ( + ) x y = Z.(x + y)
  let ( - ) x y = Z.(x - y)
end

type scalar = Amount of Money.t | Rate of Z.t [@@deriving equal, compare]
type account_id = string list
type commodity_id = string (* TODO: consider making this UUID *)

type account = {
  id : account_id;
  description : string list;
  commodity_id : commodity_id;
  balance : Money.t;
}

type bal_assert = { account : account_id; amount : Money.t; labels : Labels.t }

module Account_id_key = struct
  type t = account_id
  type comparator_witness
end

type tx = {
  cleared : Date.t option;
  commodity_id : commodity_id;
  debit : scalar Map.M(Account_id_key).t;
  credit : scalar Map.M(Account_id_key).t;
  labels : Labels.t;
}

type item = Tx_item of tx | Bal_assert_item of bal_assert
type ledger = Ledger of item list