#!/usr/bin/env bash
# docker-finance | modern accounting for the power-user
#
# Copyright (C) 2021-2024 Aaron Fiore (Founder, Evergreen Crypto LLC)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
# "Libraries"
#
[ -z "$DOCKER_FINANCE_CONTAINER_REPO" ] && exit 1
source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/lib_utils.bash" || exit 1
#
# Execute
#
if [ $UID -lt 1000 ]; then
lib_utils::die_fatal "Do not run as root or system user!"
fi
# IMPORTANT: keep umask for security
umask go-rwx
# Top-level caller
global_basename="$(basename $0)"
declare -rx global_basename
# Dependencies
if [ -z "$EDITOR" ]; then
lib_utils::die_fatal "Shell EDITOR is not set, export EDITOR in your shell"
fi
# Globals (argument delimiters)
# NOTE: argument parsing will use this unified format
[ -z "$global_arg_delim_1" ] && declare -rx global_arg_delim_1="/"
[ -z "$global_arg_delim_2" ] && declare -rx global_arg_delim_2="="
[ -z "$global_arg_delim_3" ] && declare -rx global_arg_delim_3=","
# "Constructor" for finance environment
function lib_finance::finance()
{
# Ensure profile/subprofile
[[ ! $1 =~ $global_arg_delim_1 ]] && return 2
IFS="$global_arg_delim_1" read -ra _profile <<<"$1"
declare -grx global_parent_profile="${_profile[0]}"
declare -grx global_child_profile="${_profile[1]}"
# Subcommand
declare -grx global_arg_subcommand="$2"
# Globals (convenience)
declare -grx global_usage="$global_basename ${global_parent_profile}${global_arg_delim_1}${global_child_profile} $global_arg_subcommand"
# Globals (implementation)
[ -z "$DOCKER_FINANCE_CONTAINER_FLOW" ] && lib_utils::die_fatal
declare -grx global_child_profile_flow="${DOCKER_FINANCE_CONTAINER_FLOW}/profiles/${global_parent_profile}/${global_child_profile}"
if [ ! -d "$global_child_profile_flow" ]; then
lib_utils::die_fatal "Profiles '${global_parent_profile}${global_arg_delim_1}${global_child_profile}' do not exist!"
fi
declare -grx global_child_profile_journal="${global_child_profile_flow}/all-years.journal"
declare -grx global_hledger_cmd=("/usr/bin/hledger" "-f" "$global_child_profile_journal")
# Globals (configuration)
declare -grx global_conf_fetch="${global_child_profile_flow}/docker-finance.d/fetch/fetch.yaml"
declare -grx global_conf_hledger="${global_child_profile_flow}/docker-finance.d/hledger/hledger.conf"
declare -grx global_conf_meta="${global_child_profile_flow}/docker-finance.d/meta/meta.csv"
declare -grx global_conf_shell="${global_child_profile_flow}/docker-finance.d/shell/subprofile.bash"
# Implementation "libraries" (requires previously set globals)
source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/lib_edit.bash" || exit 1
source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/lib_fetch.bash" || exit 1
source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/lib_ledger.bash" || exit 1
source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/lib_meta.bash" || exit 1
source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/lib_plugins.bash" || exit 1
source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/lib_reports.bash" || exit 1
source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/lib_taxes.bash" || exit 1
source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/lib_times.bash" || exit 1
}
#
# Library implementation facades
#
# The "all" command which fetches, imports, generates taxes and reports for given year
function lib_finance::all()
{
time lib_finance::__all "$@"
lib_utils::catch $?
}
function lib_finance::__all()
{
local _arg="$1"
local _usage="
\e[32mDescription:\e[0m
The 'all' command which fetches and imports accounts, and then generates taxes and reports
\e[32mUsage:\e[0m
$ $global_usage year${global_arg_delim_2}
\e[32mExamples:\e[0m
\e[37;2m# Fetch, import, generates taxes and reports for year 2023\e[0m
$ $global_usage year${global_arg_delim_2}2023
"
if [ "$#" -gt 1 ]; then
lib_utils::die_usage "$_usage"
fi
# Get/Set year
if [ ! -z "$_arg" ]; then
if [[ ! "$_arg" =~ ^year[s]?${global_arg_delim_2} ]]; then
lib_utils::die_usage "$_usage"
fi
# Parse key for value
local _key="${_arg%${global_arg_delim_2}*}"
local _len="$((${#_key} + 1))"
if [[ "$_key" =~ ^year[s]?$ ]]; then
local _arg_year="${_arg:${_len}}"
if [ -z "$_arg_year" ]; then
lib_utils::die_usage "$_usage"
fi
fi
else
_arg_year="$(date +%Y)"
fi
# Execute
lib_utils::print_custom "\n\t\e[1mFetching 'all' for year ${_arg_year}\e[0m\n"
(lib_finance::fetch year${global_arg_delim_2}"${_arg_year}" all=all) \
&& (lib_finance::import year${global_arg_delim_2}"${_arg_year}") \
&& (lib_finance::taxes year${global_arg_delim_2}"${_arg_year}" all=all) \
&& (lib_finance::reports year${global_arg_delim_2}"${_arg_year}" all=all)
[ $? -eq 0 ] \
&& lib_utils::print_custom "\n\t\e[1mFetching 'all' for year ${_arg_year} completed successfully!\e[0m\n"
return $?
}
function lib_finance::meta()
{
lib_meta::meta "$@"
lib_utils::catch $?
}
function lib_finance::fetch()
{
lib_fetch::fetch "$@"
lib_utils::catch $?
}
function lib_finance::import()
{
lib_ledger::ledger-import "$@"
lib_utils::catch $?
}
function lib_finance::ledger()
{
lib_ledger::ledger-cli "$@"
lib_utils::catch $?
}
function lib_finance::ledger-ui()
{
lib_ledger::ledger-ui "$@"
lib_utils::catch $?
}
function lib_finance::ledger-vui()
{
lib_ledger::ledger-vui "$@"
lib_utils::catch $?
}
function lib_finance::ledger-web()
{
lib_ledger::ledger-web "$@"
lib_utils::catch $?
}
function lib_finance::plugins()
{
lib_plugins::plugins "$@"
lib_utils::catch $?
}
function lib_finance::reports()
{
lib_reports::reports "$@"
lib_utils::catch $?
}
function lib_finance::root()
{
# NOTE: will automatically load rootlogon.C
pushd "${DOCKER_FINANCE_CONTAINER_REPO}/src/root/macro" 1>/dev/null \
&& root -l
lib_utils::catch $?
}
function lib_finance::taxes()
{
lib_taxes::taxes "$@"
lib_utils::catch $?
}
function lib_finance::times()
{
lib_times::times "$@"
lib_utils::catch $?
}
function lib_finance::edit()
{
lib_edit::edit "$@"
lib_utils::catch $?
}
# vim: sw=2 sts=2 si ai et