package tiny_appkits
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Application engines from scratch: a spreadsheet, rich text, paint, draw, CAD, editors and more
Install
dune-project
Dependency
Authors
Maintainers
Sources
0.3.6.tar.gz
md5=7c636383d146d30ac6f2fa234a6253c8
sha512=c79f3823c5f8f57e5038eb640d487c61168b84aa07c61999d6622ef9fd0c890e2b03b4c6a7cdbbe9352a49e25dda00ac7bb14693cee8e3d7beeed251351a2af0
doc/src/tiny_appkits.appkit_money/Reconcile.ml.html
Source file Reconcile.ml
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(* Claude Code * * Copyright (C) 2026 Yoann Padioleau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * (LGPL) as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. *) (* See Reconcile.mli *) type hint = | Missing of Ledger.txn list | Extra of Ledger.txn | Wrong_sign of Ledger.txn | Transposed of Ledger.txn * Money.cents | Nine let sum_of status txns = List.fold_left (fun s (t : Ledger.txn) -> if List.mem t.status status then s + t.amount else s) 0 txns let opening txns = sum_of [ Ledger.Reconciled ] txns let cleared txns = sum_of [ Ledger.Reconciled; Ledger.Cleared ] txns let difference ~statement txns = statement - cleared txns (* the amounts [a] becomes with two neighbouring digits swapped *) let swaps (a : Money.cents) : Money.cents list = let s = string_of_int (abs a) in List.filter_map (fun i -> if s.[i] = s.[i + 1] then None else let b = Bytes.of_string s in Bytes.set b i s.[i + 1]; Bytes.set b (i + 1) s.[i]; let v = int_of_string (Bytes.to_string b) in Some (if a < 0 then -v else v)) (List.init (max 0 (String.length s - 1)) Fun.id) (* up to three of [items] whose amounts add up to [target], the fewest first *) let subset (items : Ledger.txn list) (target : Money.cents) : Ledger.txn list option = let rec pick k start sum chosen = if k = 0 then if sum = target then Some (List.rev chosen) else None else let rec from = function | [] -> None | (t : Ledger.txn) :: rest -> ( match pick (k - 1) rest (sum + t.amount) (t :: chosen) with Some c -> Some c | None -> from rest) in from start in List.fold_left (fun found k -> match found with Some _ -> found | None -> pick k items 0 []) None [ 1; 2; 3 ] let hints ~statement (txns : Ledger.txn list) : hint list = let diff = difference ~statement txns in if diff = 0 then [] else let open_ = List.filter (fun (t : Ledger.txn) -> t.status = Ledger.Open) txns in let ticked = List.filter (fun (t : Ledger.txn) -> t.status = Ledger.Cleared) txns in let missing = match subset open_ diff with Some ts -> [ Missing ts ] | None -> [] in let extra = List.filter_map (fun (t : Ledger.txn) -> if t.amount = -diff then Some (Extra t) else None) ticked in let sign = List.filter_map (fun (t : Ledger.txn) -> if 2 * t.amount = -diff then Some (Wrong_sign t) else None) ticked in let transposed = List.concat_map (fun (t : Ledger.txn) -> List.filter_map (fun a -> if a - t.amount = diff then Some (Transposed (t, a)) else None) (swaps t.amount)) ticked in let nine = if transposed = [] && diff mod 9 = 0 then [ Nine ] else [] in missing @ extra @ sign @ transposed @ nine let finish (txns : Ledger.txn list) : Ledger.txn list = List.map (fun (t : Ledger.txn) -> if t.status = Ledger.Cleared then { t with status = Ledger.Reconciled } else t) txns
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>