fplib

package module
v0.0.0-...-5a0c4bc Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 12, 2024 License: AGPL-3.0 Imports: 11 Imported by: 0

README

finance-planner-lib

A Go library that processes a list of recurring bill definitions (transactions or TX in the code) and projects expenses into the future (results).

This library powers my Finance Planner applications.

Usage

This will be updated later.

Unit testing

The purpose of this library is to confidently calculate financial operations.

Unit test coverage is a big part of facilitating this, since it's large math and data structure manipulation.

To run unit tests, execute the following in your terminal:

# will open a browser tab with the code coverage
make test

Currently, unit testing code coverage is at 98.0%.

This project will not aim to hit 100% code coverage, since some of the error handling branches are not worth the effort of reproducing them in a unit test environment. The core business logic in this application is the priority, and the vast majority of it is tested.

TODOs and Limitations

Currently the library doesn't support weekday-specific recurrence patterns like First monday of every month. The underlying rrule library does support these patterns. In the future, this library will aim to provide an API that allows for more direct passthrough of all possible rrule options so that maximum flexibility is possible. Unfortunately, because this library was originally extracted from my other financial planning projects, the goal of specifically providing an rrule-like API was not in scope. However, to reiterate, future scope will move towards this direction.

Documentation

Index

Constants

View Source
const (
	WEEKLY                    string = "WEEKLY"
	MONTHLY                   string = "MONTHLY"
	YEARLY                    string = "YEARLY"
	New                       string = "New"
	None                      string = "none"
	Desc                      string = "Desc"
	Asc                       string = "Asc"
	DaysInMonth                      = 31
	HoursInDay                       = 24
	DefaultTransactionBalance        = 500
)

Variables

This section is empty.

Functions

func CalculateDailyRate

func CalculateDailyRate(amount int, days int) int

CalculateYearlyRate calculates the daily spending/income rate and returns an integer that represents a dollar amount ($100.00 = 10000).

Provide the number of days that the amount has accumulated over, and a rate will be returned.

func CalculateMonthlyRate

func CalculateMonthlyRate(amount int, days int) int

CalculateMonthlyRate calculates the monthly spending/income rate and returns an integer that represents a dollar amount ($100.00 = 10000).

Provide the number of days that the amount has accumulated over, and a rate will be returned.

func CalculateYearlyRate

func CalculateYearlyRate(amount int, days int) int

CalculateYearlyRate calculates the yearly spending/income rate and returns an integer that represents a dollar amount ($100.00 = 10000).

Provide the number of days that the amount has accumulated over, and a rate will be returned.

func FormatAsCurrency

func FormatAsCurrency(a int) string

FormatAsCurrency converts an integer to a USD-formatted string. Input is assumed to be based in pennies, i.e., hundredths of a dollar - 100 would return "$1.00".

func GetCSVString

func GetCSVString(input []string) string

GetCSVString produces a simple semi-colon-separated value string.

func GetDateFromStrSafe

func GetDateFromStrSafe(s string, t time.Time) time.Time

GetDateFromStrSafe converts a provided string, typically formatted like "YYYY-MM-DD" into a valid time.Time. If the provided string is not formatted in this manner, then the argument t is used as the resulting time.Time value instead, with its date being set to t.Year, t.Month, t.Day and its hours/minutes/seconds being set to zero.

func GetDateString

func GetDateString(y, m, d any) string

GetDateString formats a string as YYYY-MM-DD with zero-padding.

func GetDefaultEndDateString

func GetDefaultEndDateString(t time.Time) string

GetDefaultEndDateString returns a string corresponding to the current YYYY-MM-DD value plus 1 year in the future, but does not necessarily include 0-padded values.

func GetNextSort

func GetNextSort(current, next string) string

GetNextSort takes the current sort, which is typically something like OrderAsc, OrderDesc, or None, and attempts to do some basic string parsing to figure out what the next sort should be. The cycle is None -> Asc -> Des Note that if the `next` argument is a different column than the `current` argument (after stripping away Asc/Desc), the resulting sort will always be the `next` column with Asc ordering.

func GetNowDateString

func GetNowDateString(t time.Time) string

GetNowDateString returns a string corresponding to the current YYYY-MM-DD value.

func GetResultsCSVString

func GetResultsCSVString(results *[]Result) string

func GetStats

func GetStats(results []Result) string

GetStats spits out some quick calculations about the provided set of results. Calculations include, for example, yearly+monthly+daily income/expenses, as well as some other things. Users may want to copy this information to the clipboard.

func GetTXByID

func GetTXByID(txs *[]TX, id string) (int, error)

GetTXByID finds the index of a TX for the provided id, returning an error and -1 if not present.

func GetWeekdaysMap

func GetWeekdaysMap() map[int]bool

GetEmptyWeekdaysMap returns a map that can be used like this:

m := GetWeekdaysMap()

if m[rrule.MO.Day()] { /* do something * / }

It is meant to be more efficient than repeatedly using tx.HasWeekday() to determine if a weekday is present in a given TX.

func ParseDollarAmount

func ParseDollarAmount(input string, assumePositive bool) int64

ParseDollarAmount takes an input currency-formatted string, such as $100.00, and returns an integer corresponding to the underlying value, such as 10000. Generally in this application, values are assumed to be negative (i.e. recurring bills), so if assumePositive is set to true, the returned value will be positive, but otherwise it will default to negative.

func ParseYearMonthDateString

func ParseYearMonthDateString(input string) (int, int, int)

ParseYearMonthDateString takes an input value such as 2020-01-01 and returns three integer values - year, month, day. Returns 0, 0, 0 if invalid input is received.

func RemoveTXByID

func RemoveTXByID(txs *[]TX, id string)

RemoveTXByID manipulates an input TX slice by removing a TX with the provided id.

Types

type PreCalculatedResult

type PreCalculatedResult struct {
	Date                  time.Time
	DayTransactionNames   []string
	DayTransactionAmounts []int
}

type Result

type Result struct {
	Record                   int
	Date                     time.Time
	Balance                  int
	CumulativeIncome         int
	CumulativeExpenses       int
	DayExpenses              int
	DayIncome                int
	DayNet                   int
	DayTransactionNames      string
	DiffFromStart            int
	DayTransactionNamesSlice []string
	ID                       string
	CreatedAt                string
	UpdatedAt                string
}

A result is a csv/table output row as shown in a results page.

func GetResults

func GetResults(tx []TX, startDate time.Time, endDate time.Time, startBalance int, statusHook func(status string)) ([]Result, error)

type TX

type TX struct {
	// Order  int    `yaml:"order"`  // manual ordering
	Amount int    `yaml:"amount"` // in cents; 500 = $5.00
	Active bool   `yaml:"active"`
	Name   string `yaml:"name"`
	Note   string `yaml:"note"`
	// for examples of rrules:
	// https://github.com/teambition/rrule-go/blob/f71921a2b0a18e6e73c74dea155f3a549d71006d/rrule.go#L91
	// https://github.com/teambition/rrule-go/blob/master/rruleset_test.go
	// https://labix.org/python-dateutil/#head-88ab2bc809145fcf75c074817911575616ce7caf
	RRule string `yaml:"rrule"`

	// The frequency of recurrence, such as MONTHLY/YEARLY/DAILY.
	Frequency string `yaml:"frequency"`
	// The interval of recurrence. A value of 1 means that this occurs every
	// 1 month/year/day. A value of 6 means that this occurs every 6th month/year/day.
	Interval    int          `yaml:"interval"`
	Weekdays    map[int]bool `yaml:"weekdays"` // monday starts on 0
	StartsDay   int          `yaml:"startsDay"`
	StartsMonth int          `yaml:"startsMonth"`
	StartsYear  int          `yaml:"startsYear"`
	EndsDay     int          `yaml:"endsDay"`
	EndsMonth   int          `yaml:"endsMonth"`
	EndsYear    int          `yaml:"endsYear"`
	ID          string       `yaml:"id"`
	CreatedAt   time.Time    `yaml:"createdAt"`
	UpdatedAt   time.Time    `yaml:"updatedAt"`
	Selected    bool         `yaml:"selected"` // when activated in the transactions table
}

func GetNewTX

func GetNewTX(t time.Time) TX

GetNewTX returns an empty transaction with sensible defaults based on the provided time t (which is typically time.Now()).

func RemoveTXAtIndex

func RemoveTXAtIndex(txs []TX, i int) []TX

RemoveTXAtIndex is a quick helper function to remove a transaction from a slice. There are more generic ways to do this, and it's fairly trivial, but it's nice to have a dedicated helper function for it.

func (*TX) GetEndsDateString

func (tx *TX) GetEndsDateString() string

GetEndsDateString returns a formatted date string for the transaction's end date.

func (*TX) GetStartDateString

func (tx *TX) GetStartDateString() string

GetStartDateString returns a formatted date string for the transaction's start date.

func (*TX) GetWeekdaysCheckedMap

func (tx *TX) GetWeekdaysCheckedMap(checked, unchecked string) map[int]string

GetWeekdaysCheckedMap returns a map that can be used like this:

checkedGlyph := "X" uncheckedGlyph := " " m := GetWeekdaysCheckedMap(checkedGlyph)

log.Println("occurs on mondays: %v", m[rrule.MO.Day()])

It is meant to be more efficient than repeatedly using tx.HasWeekday() to determine if a weekday is present in a given TX.

type TXStats

type TXStats struct {
	DailySpending   int
	DailyIncome     int
	DailyNet        int
	MonthlySpending int
	MonthlyIncome   int
	MonthlyNet      int
	YearlySpending  int
	YearlyIncome    int
	YearlyNet       int
}

func CalculateStats

func CalculateStats(results []Result) TXStats

func (*TXStats) GetStats

func (s *TXStats) GetStats() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL