#!/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=("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_subscript="${global_child_profile_flow}/docker-finance.d/shell/subscript.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_hledger.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_hledger::hledger-import "$@" lib_utils::catch $? } function lib_finance::hledger() { lib_hledger::hledger-cli "$@" lib_utils::catch $? } function lib_finance::hledger-ui() { lib_hledger::hledger-ui "$@" lib_utils::catch $? } function lib_finance::hledger-vui() { lib_hledger::hledger-vui "$@" lib_utils::catch $? } function lib_finance::hledger-web() { lib_hledger::hledger-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() { # TODO: lib_root, add extendable arguments lib_utils::deps_check "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