cleaner(ish) code, support for rules
This commit is contained in:
parent
8b60f2b602
commit
e45c36e6e3
3 changed files with 87 additions and 42 deletions
3
Bank.cs
3
Bank.cs
|
@ -1,6 +1,7 @@
|
|||
namespace BunyMuny {
|
||||
public enum Bank {
|
||||
ME,
|
||||
NAB
|
||||
NAB,
|
||||
Other
|
||||
}
|
||||
}
|
||||
|
|
70
Program.cs
70
Program.cs
|
@ -2,51 +2,77 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.CommandLine.DragonFruit;
|
||||
using System.Text.Json.Serialization;
|
||||
using CsvHelper;
|
||||
using CsvHelper.Configuration.Attributes;
|
||||
|
||||
namespace BunyMuny {
|
||||
class Program {
|
||||
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="rules">The JSON file to use for rules when parsing statement descriptions</param>
|
||||
/// <param name="ruleFile">The JSON file to use for rules when parsing statement descriptions</param>
|
||||
/// <returns></returns>
|
||||
static int Main(string file = "test.csv", string rules = "rules.json") {
|
||||
Bank bank = Bank.ME;
|
||||
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);
|
||||
|
||||
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
|
||||
string header = csv.Parser.Context.RawRecord;
|
||||
if (header == null) {
|
||||
var header = csv.Parser.Context.RawRecord.Trim();
|
||||
switch (header) {
|
||||
case null:
|
||||
Console.WriteLine("File is empty 0uo");
|
||||
return 1;
|
||||
}
|
||||
else if (header == "Date,Description,Debits and credits,Balance") {
|
||||
case "Date,Description,Debits and credits,Balance":
|
||||
bank = Bank.ME;
|
||||
}
|
||||
else if (header == "Whatever NAB uses I guess") {
|
||||
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:
|
||||
double value = double.Parse(csv.GetField("Debits and credits").TrimStart().Replace("$", ""));
|
||||
var value = double.Parse(csv.GetField("Debits and credits").TrimStart().Replace("$", ""));
|
||||
var ruleValues = MatchAgainstRules(rules, csv.GetField("Description"));
|
||||
|
||||
statements.Add(new Statement() {
|
||||
Date = DateTime.ParseExact(csv.GetField("Date"), "dd/MM/yyyy", CultureInfo.InvariantCulture),
|
||||
Description = csv.GetField("Description"),
|
||||
Category = "Unknown",
|
||||
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;
|
||||
|
@ -56,10 +82,18 @@ namespace BunyMuny {
|
|||
foreach (var statement in statements) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
12
Statement.cs
12
Statement.cs
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace BunyMuny {
|
||||
public class Statement {
|
||||
|
@ -14,7 +15,16 @@ namespace BunyMuny {
|
|||
public string Category;
|
||||
|
||||
public override string ToString() {
|
||||
return $"${Math.Abs(Value)} {(Value < 0 ? "to" : "from")} {(Description)} on {Date.ToString("MMM d yyyy")}";
|
||||
// e.g.: Debit: $5.00 --> Lynnear Software (Personal) on Apr 2 2020
|
||||
return String.Format(
|
||||
"{0} ${1:0.##} {2} {3} ({4}) on {5:MMM d yyyy}",
|
||||
Value < 0 ? "Credit:" : "Debit: ",
|
||||
Math.Abs(Value),
|
||||
Value < 0 ? "-->" : "<--",
|
||||
Description,
|
||||
Category ?? "Unknown",
|
||||
Date
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue