BunyMuny/Program.cs

104 lines
2.9 KiB
C#

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 {
/// <summary>
/// BunyMuny parses the CSV output of various bank statement listings and converts it to something more human readable with nice visualisations.
/// </summary>
/// <param name="file">The CSV file to read</param>
/// <param name="ruleFile">The JSON file to use for rules when parsing statement descriptions</param>
/// <returns></returns>
private static int Main(string file = "test.csv", string ruleFile = "rules.json") {
var bank = Bank.Other;
var statements = new List<Statement>();
List<Rule> rules;
using (var ruleStreamReader = new StreamReader(ruleFile)) {
var jsonOptions = new JsonSerializerOptions();
jsonOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
jsonOptions.WriteIndented = true;
rules = JsonSerializer.Deserialize<List<Rule>>(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<Rule> rules, string value) {
foreach (var rule in rules) {
if (rule.Check(value)) {
return (rule.Category, rule.Description);
}
}
return (null, null);
}
}
}