using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Text.Json; using System.CommandLine.DragonFruit; using System.Linq; using System.Text.Json.Serialization; using CsvHelper; namespace BunyMuny { internal class Program { /// /// BunyMuny parses the CSV output of various bank statement listings and converts it to something more human readable with nice visualisations. /// /// The CSV file to read /// The JSON file to use for rules when parsing statement descriptions /// private static int Main(string file = "test.csv", string ruleFile = "rules.json") { var bank = Bank.Other; var statements = new List(); List rules; using (var ruleStreamReader = new StreamReader(ruleFile)) { var jsonOptions = new JsonSerializerOptions(); jsonOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)); jsonOptions.WriteIndented = true; rules = JsonSerializer.Deserialize>(ruleStreamReader.ReadToEnd(), jsonOptions); } using var sr = new StreamReader(file); using var csv = new CsvReader(sr, CultureInfo.InvariantCulture); csv.Read(); csv.ReadHeader(); // get the first line of the CSV file (the header) as a string var header = csv.Parser.Context.RawRecord.Trim(); switch (header) { case null: Console.WriteLine("File is empty 0uo"); return 1; case "Date,Description,Debits and credits,Balance": bank = Bank.ME; break; case "Whatever NAB uses I guess": bank = Bank.NAB; break; default: Console.WriteLine($"Unknown header: [{header}]"); break; } while (csv.Read()) { switch (bank) { case Bank.ME: var value = double.Parse(csv.GetField("Debits and credits").TrimStart().Replace("$", "")); // SHOW PET THIS var ruleValues = MatchAgainstRules(rules, csv.GetField("Description")); statements.Add(new Statement() { Date = DateTime.ParseExact(csv.GetField("Date"), "dd/MM/yyyy", CultureInfo.InvariantCulture), OriginalDescription = csv.GetField("Description"), Description = ruleValues.Description, Category = ruleValues.Category, Value = value }); break; case Bank.NAB: Console.WriteLine("Unimplemented"); return 1; case Bank.Other: Console.WriteLine("Unknown bank!"); return 1; default: Console.WriteLine(":("); return 1; } } foreach (var statement in statements. Where(s => s.Category != null). OrderBy(s => s.Date)) { Console.WriteLine(statement); } return 0; } private static (string Category, string Description) MatchAgainstRules(List rules, string value) { foreach (var rule in rules) { if (rule.Check(value)) { return (rule.Category, rule.Description); } } return (null, null); } } }