diff --git a/.ocamlformat b/.ocamlformat index e69de29..5dab0e3 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -0,0 +1 @@ +profile = conventional \ No newline at end of file diff --git a/compta.ml b/compta.ml index a76d6c1..6755ebd 100644 --- a/compta.ml +++ b/compta.ml @@ -1,79 +1,22 @@ -let optstring = function Some s -> s | None -> "" - -type mvt = { - year : int; - month : int; - day : int; - category : string; - subcategory : string; - amount : float; - account : string; - payee : string; - notes : string; -} - -let mvt year month day category subcategory amount account payee notes = - { - year = truncate year; - month = truncate month; - day = truncate day; - category; - subcategory = optstring subcategory; - amount; - account; - payee; - notes = optstring notes; - } - -let after y m d l = - Printf.sprintf "%04d-%02d-%02d" l.year l.month l.day - > Printf.sprintf "%04d-%02d-%02d" y m d - -let until y m d l = - Printf.sprintf "%04d-%02d-%02d" l.year l.month l.day - <= Printf.sprintf "%04d-%02d-%02d" y m d - -let is_account_caisse m = m.account = "CAISSE" - -let is_account_courant m = m.account = "COURANT" - -let any_account _ = true - -let mvts fn = - Sqlite3_utils.( - with_db fn (fun db -> - exec db - "select Year, Month, Day, Category, Subcategory, Amount, \ - AccountName, Payee, Notes from alldata" - ~ty: - Ty. - ( nil, - p3 float float float - @>> p2 text (nullable text) - @>> p1 float - @>> p3 text text (nullable text), - mvt ) - ~f:Cursor.to_list)) - |> Rresult.R.get_ok - -let solde ~cpt_filter ~at:(y, m, d) mvts = +let solde ?(mvt_predicate = Mvt.any) ~at:(y, m, d) mvts = mvts - |> List.filter (until y m d) - |> List.filter cpt_filter - |> List.map (fun m -> m.amount) + |> List.filter (Mvt.until y m d) + |> List.filter mvt_predicate + |> List.rev_map (fun m -> m.Mvt.amount) |> List.fold_left ( +. ) 0. -let balance ~cpt_filter ~from ~until mvts = - solde ~cpt_filter ~at:until mvts -. solde ~cpt_filter ~at:from mvts +let balance ?(mvt_predicate = Mvt.any) ~from ~until mvts = + solde ~mvt_predicate ~at:until mvts -. solde ~mvt_predicate ~at:from mvts -let bilan ~cpt_filter ~from:(fy, fm, fd) ~until:(uy, um, ud) mvts () = +let bilan ?(mvt_predicate = Mvt.any) ~from:(fy, fm, fd) ~until:(uy, um, ud) mvts + () = let t = Hashtbl.create 164 in mvts - |> List.filter (after fy fm fd) - |> List.filter (until uy um ud) - |> List.filter cpt_filter + |> List.filter (Mvt.after fy fm fd) + |> List.filter (Mvt.until uy um ud) + |> List.filter mvt_predicate |> List.iter (fun mvt -> - let i = mvt.category ^ ":" ^ mvt.subcategory in + let i = mvt.Mvt.category ^ ":" ^ mvt.Mvt.subcategory in match Hashtbl.find_opt t i with | None -> Hashtbl.add t i mvt.amount | Some a -> Hashtbl.replace t i (mvt.amount +. a)); @@ -89,22 +32,22 @@ let bilan ~cpt_filter ~from:(fy, fm, fd) ~until:(uy, um, ud) mvts () = let main ~from:((yf, mf, df) as from) ~until:((yu, mu, du) as until) () = let ops = - mvts "/home/matt/Téléchargements/NOVEMBRE2.mmb_update_2019-11-12.mmb" + Mvt.mvts "/home/matt/Téléchargements/MAI2021.mmb_update_2021-05-06.mmb" in - let caisse_dbt = solde ~cpt_filter:is_account_caisse ~at:from ops - and caisse_fin = solde ~cpt_filter:is_account_caisse ~at:until ops - and courant_dbt = solde ~cpt_filter:is_account_courant ~at:from ops - and courant_fin = solde ~cpt_filter:is_account_courant ~at:until ops in + let caisse_dbt = solde ~mvt_predicate:Mvt.is_account_caisse ~at:from ops + and caisse_fin = solde ~mvt_predicate:Mvt.is_account_caisse ~at:until ops + and courant_dbt = solde ~mvt_predicate:Mvt.is_account_courant ~at:from ops + and courant_fin = solde ~mvt_predicate:Mvt.is_account_courant ~at:until ops in Printf.printf "%04d-%02d-%02d\n" yf mf df; Printf.printf "CAISSE : %.2f\n" caisse_dbt; Printf.printf "COURANT : %.2f\n" courant_dbt; - bilan ~cpt_filter:any_account ~from ~until ops (); + bilan ~mvt_predicate:Mvt.any ~from ~until ops (); Printf.printf "%04d-%02d-%02d\n" yu mu du; Printf.printf "CAISSE : %.2f\n" caisse_fin; Printf.printf "COURANT : %.2f\n" courant_fin -let () = main ~from:(2018, 11, 25) ~until:(2019, 10, 31) () +let () = main ~from:(2020, 11, 1) ~until:(2021, 5, 31) () diff --git a/cotisations.ml b/cotisations.ml new file mode 100644 index 0000000..8375d26 --- /dev/null +++ b/cotisations.ml @@ -0,0 +1,42 @@ +let solde ?(mvt_predicate = Mvt.any) ~at:(y, m, d) mvts = + mvts + |> List.filter (Mvt.until y m d) + |> List.filter mvt_predicate + |> List.rev_map (fun m -> m.Mvt.amount) + |> List.fold_left ( +. ) 0. + +let balance ?(mvt_predicate = Mvt.any) ~from ~until mvts = + solde ~mvt_predicate ~at:until mvts -. solde ~mvt_predicate ~at:from mvts + +let bilan ?(mvt_predicate = Mvt.any) ~from:(fy, fm, fd) ~until:(uy, um, ud) mvts + () = + let t = Hashtbl.create 164 in + mvts + |> List.filter (Mvt.after fy fm fd) + |> List.filter (Mvt.until uy um ud) + |> List.filter mvt_predicate + |> List.iter (fun mvt -> + let i = mvt.Mvt.category ^ ":" ^ mvt.Mvt.subcategory in + match Hashtbl.find_opt t i with + | None -> Hashtbl.add t i mvt.amount + | Some a -> Hashtbl.replace t i (mvt.amount +. a)); + + Hashtbl.iter + (fun cat mont -> if mont < 0. then Printf.printf "%50s\t%04.02f\n" cat mont) + t; + + Hashtbl.iter + (fun cat mont -> + if mont >= 0. then Printf.printf "%50s\t%04.02f\n" cat mont) + t + +let main ~from:(yf, mf, df) ~until:(yu, mu, du) () = + Mvt.mvts "/home/matt/Téléchargements/MAI2021.mmb_update_2021-05-06.mmb" + |> List.filter (Mvt.after yf mf df) + |> List.filter (Mvt.until yu mu du) + |> List.filter (fun m -> m.Mvt.category = "COTISATIONS RULLY LOISIRS") + |> List.iter (fun m -> + Printf.printf "%04d-%02d-%02d %70s %45s\n" m.Mvt.year m.month m.day + m.payee m.subcategory) + +let () = main ~from:(2020, 11, 1) ~until:(2021, 5, 31) () diff --git a/dune b/dune index cb6ddec..32b59af 100644 --- a/dune +++ b/dune @@ -1,3 +1,3 @@ -(executable - (name compta) +(executables + (names compta livre cotisations) (libraries rresult sqlite3_utils)) diff --git a/livre.ml b/livre.ml new file mode 100644 index 0000000..ef9b1ff --- /dev/null +++ b/livre.ml @@ -0,0 +1,42 @@ +let solde ?(mvt_predicate = Mvt.any) ~at:(y, m, d) mvts = + mvts + |> List.filter (Mvt.until y m d) + |> List.filter mvt_predicate + |> List.rev_map (fun m -> m.Mvt.amount) + |> List.fold_left ( +. ) 0. + +let balance ?(mvt_predicate = Mvt.any) ~from ~until mvts = + solde ~mvt_predicate ~at:until mvts -. solde ~mvt_predicate ~at:from mvts + +let bilan ?(mvt_predicate = Mvt.any) ~from:(fy, fm, fd) ~until:(uy, um, ud) mvts + () = + let t = Hashtbl.create 164 in + mvts + |> List.filter (Mvt.after fy fm fd) + |> List.filter (Mvt.until uy um ud) + |> List.filter mvt_predicate + |> List.iter (fun mvt -> + let i = mvt.Mvt.category ^ ":" ^ mvt.Mvt.subcategory in + match Hashtbl.find_opt t i with + | None -> Hashtbl.add t i mvt.amount + | Some a -> Hashtbl.replace t i (mvt.amount +. a)); + + Hashtbl.iter + (fun cat mont -> if mont < 0. then Printf.printf "%50s\t%04.02f\n" cat mont) + t; + + Hashtbl.iter + (fun cat mont -> + if mont >= 0. then Printf.printf "%50s\t%04.02f\n" cat mont) + t + +let main ~from:(yf, mf, df) ~until:(yu, mu, du) () = + Mvt.mvts "/home/matt/Téléchargements/MAI2021.mmb_update_2021-05-06.mmb" + |> List.filter (Mvt.after yf mf df) + |> List.filter (Mvt.until yu mu du) + |> List.iter (fun m -> + Printf.printf "%04d-%02d-%02d: % 6.2f - %7s - %70s - %32s - %45s\n" + m.Mvt.year m.month m.day m.amount m.account m.payee m.category + m.subcategory) + +let () = main ~from:(2020, 11, 1) ~until:(2021, 5, 31) () diff --git a/mvt.ml b/mvt.ml new file mode 100644 index 0000000..ac412d7 --- /dev/null +++ b/mvt.ml @@ -0,0 +1,64 @@ +let optstring = function Some s -> s | None -> "" + +type t = { + year : int; + month : int; + day : int; + category : string; + subcategory : string; + amount : float; + account : string; + payee : string; + notes : string; +} + +type predicate = t -> bool + +let create ~year ~month ~day ~category ?subcategory ~amount ~account ~payee + ?notes () = + { + year = truncate year; + month = truncate month; + day = truncate day; + category; + subcategory = optstring subcategory; + amount; + account; + payee; + notes = optstring notes; + } + +let mvt year month day category subcategory amount account payee notes = + create ~year ~month ~day ~category ?subcategory ~amount ~account ~payee ?notes + () + +let after y m d l = + Printf.sprintf "%04d-%02d-%02d" l.year l.month l.day + > Printf.sprintf "%04d-%02d-%02d" y m d + +let until y m d l = + Printf.sprintf "%04d-%02d-%02d" l.year l.month l.day + <= Printf.sprintf "%04d-%02d-%02d" y m d + +let is_account_caisse : predicate = fun m -> m.account = "CAISSE" + +let is_account_courant : predicate = fun m -> m.account = "COURANT" + +let any : predicate = fun _ -> true + +let mvts fn = + Sqlite3_utils.( + with_db fn (fun db -> + exec db + "select Year, Month, Day, Category, Subcategory, Amount, \ + AccountName, Payee, Notes from alldata" + ~ty: + Ty. + ( nil, + p3 float float float + @>> p2 text (nullable text) + @>> p1 float + @>> p3 text text (nullable text), + mvt ) + ~f:Cursor.to_list)) + |> Rresult.R.get_ok diff --git a/mvt.mli b/mvt.mli new file mode 100644 index 0000000..55318fd --- /dev/null +++ b/mvt.mli @@ -0,0 +1,50 @@ +type t = { + year : int; + month : int; + day : int; + category : string; + subcategory : string; + amount : float; + account : string; + payee : string; + notes : string; +} + +val create : + year:float -> + month:float -> + day:float -> + category:string -> + ?subcategory:string -> + amount:float -> + account:string -> + payee:string -> + ?notes:string -> + unit -> + t + +val mvt : + float -> + float -> + float -> + string -> + string option -> + float -> + string -> + string -> + string option -> + t + +type predicate = t -> bool + +val is_account_caisse : predicate + +val is_account_courant : predicate + +val any : predicate + +val after : int -> int -> int -> predicate + +val until : int -> int -> int -> predicate + +val mvts : string -> t list