DEV Community

Cover image for Starting a CLI Finance Tool
Ces-D
Ces-D

Posted on

Starting a CLI Finance Tool

Motivation

This is a finance tool project based heavily on beancount but with less features and way less complexity. After reviewing the beancount repo and documentation, I noticed that there are many more features available that I will use. In an attempt to create a new project with a new language, C#, this project was born.

Outline

This is a console application. As of right now the only major dependency is the System.CommandLine package. The commands code is written in namespace Controllers.Commands and the parsing and formatting of entries is written in namespace Controllers.VaultAccess.

Commands

Here is an example of one of my commands.

using System;
using System.CommandLine;
using System.CommandLine.Invocation;
using Controllers.VaultAccess;
using Config;

namespace Controllers.Commands
{

    public class NewCommand : Command
    {

        public NewCommand() : base("new", "Create a new vault entry")
        {
            AddArgument(DetailsArgument());
            AddOption(DateOption());
            AddOption(DirectiveOption());
            AddOption(ValueOption());
            Handler = CommandHandler.Create((DateTime date, string directiveType, string details, double currency) =>
            {
                JournalEntry entry = new JournalEntry(date, directiveType, details, currency);
                Console.WriteLine(entry.ToString());
            });
        }
Enter fullscreen mode Exit fullscreen mode

The logic is unfinished but clear. My command class inherits from System.CommandLine.Command and abstracts away all of its logic when initialized. Using this format I am able to encapsulate the Options and Arguments into their own private methods.

 private Argument<string> DetailsArgument()
        {
            Argument<string> details = new Argument<string>("details");
            details.Description = "The details of this journal entry";

            return details;
        }

        private Option<DateTime> DateOption()
        {
            Option<DateTime> date = new Option<DateTime>("--date");
            date.AddAlias("-d");
            date.Description = "Date of entry";
            date.SetDefaultValue(DateTime.Now);

            return date;
        }
Enter fullscreen mode Exit fullscreen mode

Journal Entry

Beancount is a very mature program and they have tested and perfected the input format for their entries. I am matching their input formats and created the JournalEntry class to handle the input, parsing, formatting, and output of the journal entry.
Here is an example of the format that I am expecting to output into my journal files
<Date> <Directive> <Details> <Value><Currency>
08/05/2021 open Liability:Food:Restaurant -35 USD

public class JournalEntry
    {
        private readonly int DATE_MAX_WIDTH = 13;
        private readonly int DIRECTIVE_MAX_WIDTH = 7;
        private readonly int DETAILS_MAX_WIDTH = 45;
        private DateTime entryDate { get; set; }
        private string directive { get; set; }
        private string details { get; set; }
        private double currency { get; set; }
        public JournalEntry(DateTime date, string dir, string det, double cur)
        {
            entryDate = date;
            directive = dir;
            details = det;
            currency = cur;
        }

        public override string ToString()
        {
            return string.Format("{0}{1}{2}{3}",
            entryDate.ToShortDateString().PadRight(DATE_MAX_WIDTH),
            directive.PadRight(DIRECTIVE_MAX_WIDTH),
            details.PadRight(DETAILS_MAX_WIDTH),
            currency);
        }
Enter fullscreen mode Exit fullscreen mode

Next Steps

The hardest feature that I have yet to implement are the accounting logic and maybe more importantly the parsing of each line in the journal to make the various accounting reports. I intend to add reports for all the open assets and liabilities, balances of accounts, and history of expenditures.
The benefit of this project is that it is not the first. I can copy over some of the logic from existing accounting tools and then build and better them.

Github Repo

Top comments (0)