Skip to contents

The `MainAccount` R6 class represents the top-level virtual account in a hierarchical financial structure. It receives all income and is responsible for distributing funds to its child accounts based on allocation rules.

This class is the core of the budgeting engine and manages:

  • Income reception and logging.

  • Transaction tracking via a structured data frame.

  • A list of linked child accounts.

  • Auto-generated UUID for identification.

  • A balance that reflects both manual and system transactions.

Details

The account includes the following core attributes:

uuid

A unique identifier for the account, auto-generated.

name

Human-readable name for the account.

balance

Current balance in the account.

transactions

A `data.frame` tracking transaction logs, including custom system transactions.

transaction_counter

Used internally to create unique transaction IDs.

child_accounts

A list containing attached child accounts.

total_allocation

Tracks the total allocation distributed to children.

path

Logical traversal path from the root (used to locate accounts hierarchically).

Hierarchy

This is the top-level class in a hierarchy that includes:

  • MainAccount: Root of the virtual budget system.

  • ChildAccount: Draws a portion of income from the MainAccount.

  • GrandChildAccount: Represents specific budget goals (e.g., rent, savings) and has due dates, frequency, and priority logic.

Public fields

uuid

Auto-generated unique identifier.

name

Account name.

balance

Current balance.

transactions

A `data.frame` of transaction logs.

transaction_counter

Counter used to generate unique transaction IDs.

child_accounts

List of child accounts.

total_allocation

Numeric. Sum of allocated funds to children.

path

Character vector representing the account's hierarchy path.

# some imports

Methods


Method new()

Constructor for the `MainAccount` class. Initializes a new main account with a unique identifier, user-defined name, zero balance, and an empty transaction data frame. Also sets the default account path to "main_account".

Usage

MainAccount$new(name, balance = 0)

Arguments

name

Character. The name of the main account. Used for identification in the app UI and reports.

balance

Numeric. Initial balance for the account.

Examples

\dontrun{
main_acc <- MainAccount$new(name = "My Main Account")
print(main_acc$uuid)
print(main_acc$balance)
print(main_acc$transactions)
}


Method generate_transaction_id()

Generates a unique system transaction ID by appending an incrementing counter to a fixed prefix ("sys"). The counter is then incremented for future calls.

Usage

MainAccount$generate_transaction_id()

Returns

A character string representing the generated transaction ID.

Examples

\dontrun{
  main_acc <- MainAccount$new(name = "Salary Pool")
  txn_id1 <- main_acc$generate_transaction_id()
  txn_id2 <- main_acc$generate_transaction_id()
  print(txn_id1)  # e.g., "sys1"
  print(txn_id2)  # e.g., "sys2"
}


Method is_duplicate_transaction()

Checks if a given transaction number already exists in the transaction log. This is used to prevent duplicate transaction entries.

Usage

MainAccount$is_duplicate_transaction(transaction_number)

Arguments

transaction_number

Character. The transaction ID to be checked.

Returns

Logical. TRUE if the transaction number exists, FALSE otherwise.

Examples

\dontrun{
  # Create a new main account
  main_acc <- MainAccount$new(name = "Salary Pool")

  # Manually add a transaction with ID "sys1"
  main_acc$transactions <- data.frame(
    Type = "Income",
    By = "User",
    TransactionID = "sys1",
    Channel = "Bank",
    Amount = 5000,
    Balance = 5000,
    amount_due = 0,
    overall_balance = 5000,
    Date = Sys.time(),
    stringsAsFactors = FALSE
  )

  # Check for duplicate
  main_acc$is_duplicate_transaction("sys1")  # Returns TRUE
  main_acc$is_duplicate_transaction("sys2")  # Returns FALSE
}


Method deposit()

Deposits a specified amount into the account and distributes it to child accounts based on allocation rules. This method also records the transaction in the internal ledger.

Usage

MainAccount$deposit(
  amount,
  transaction_number = NULL,
  by = "User",
  channel = NULL,
  date = Sys.time()
)

Arguments

amount

Numeric. The amount of money to deposit. Must be greater than zero.

transaction_number

Optional character. A unique identifier for this transaction. If not provided, the system generates one automatically.

by

Character. Identifier of the depositor (default is `"User"`).

channel

Character. The source of funds (e.g., `"ABSA"`, `"MPESA"`). Required.

date

POSIXct or character. The timestamp of the transaction (defaults to current time).

Returns

No return value. The method updates the account balance, transaction log, and distributes funds to child accounts.

Examples

\dontrun{
  main_acc <- MainAccount$new(name = "Salary Pool")
  main_acc$deposit(
    amount = 1000,
    channel = "Bank Transfer"
  )
}


Method distribute_to_children()

Distributes a given amount from the an account to active child accounts based on their allocation weights and priorities. If the amount is too small (less than 0.10), it is routed entirely to the highest-priority child.

This method is automatically called after a deposit into a parent account. It performs internal withdrawals and instructs child accounts to deposit their corresponding shares.

Usage

MainAccount$distribute_to_children(amount, transaction, by = "System")

Arguments

amount

Numeric. Total amount available for distribution.

transaction

Character. The transaction ID associated with the distribution.

by

Character. Identifier of the actor performing the transfer (default is `"System"`).

Returns

No return value. This method updates balances and transaction logs in both the main account and all affected child accounts.

Examples

\dontrun{
  main_acc <- MainAccount$new(name = "Salary Pool")
  child1 <- ChildAccount$new(name = "Food Fund", allocation = 0.6)
  child2 <- ChildAccount$new(name = "Savings", allocation = 0.4)
  main_acc$add_child_account(child1)
  main_acc$add_child_account(child2)

  main_acc$deposit(amount = 1000, channel = "Bank")
  # This will trigger distribute_to_children internally.
}


Method add_child_account()

Adds a `ChildAccount` object to the list of child accounts of the account. It checks for valid allocation percentages (must not exceed 100 hierarchical path references, and updates total allocation.

Usage

MainAccount$add_child_account(child_account)

Arguments

child_account

An object of class `ChildAccount`or `GrandChildAccount`, representing the account to be added as a subordinate of the current main account.

Details

If the child's allocation is zero, it will be automatically marked as inactive. The method also updates the logical `path` of the child and attaches a `parent` reference to maintain the hierarchy.

Returns

None. This method modifies the object in-place.

Examples

\dontrun{
  main_acc <- MainAccount$new(name = "Master")
  child_acc <- ChildAccount$new(name = "Savings", allocation = 0.4)
  main_acc$add_child_account(child_acc)
}


Method set_child_allocation()

Updates the allocation percentage for a specified child account. Ensures that the total allocation across all children does not exceed 100

Usage

MainAccount$set_child_allocation(child_account_name, new_allocation)

Arguments

child_account_name

Character. The name of the child account whose allocation is to be updated.

new_allocation

Numeric. The new allocation proportion (between 0 and 1).

Details

If the allocation is set to zero, the child account is marked as inactive. The function automatically updates the total allocation tracker.

Returns

None. This method modifies the object in-place.

Examples

\dontrun{
  main_acc <- MainAccount$new("Main")
  child <- ChildAccount$new(name = "Emergency", allocation = 0.2)
  main_acc$add_child_account(child)
  main_acc$set_child_allocation("Emergency", 0.3)
}


Method withdraw()

Withdraws a specified amount from the account and logs the transaction. A transaction number is generated automatically if not provided. Withdrawals require a valid channel and sufficient balance.

Usage

MainAccount$withdraw(
  amount,
  transaction_number = NULL,
  by = "User",
  channel = NULL,
  date = Sys.time()
)

Arguments

amount

Numeric. The amount to withdraw. Must be greater than zero and #' not exceed the current balance.

transaction_number

Optional character. Custom transaction ID. If NULL, a system-generated ID will be used.

by

Character. The entity initiating the withdrawal. Default is `"User"`.

channel

Character. The withdrawal channel (e.g., "Bank Transfer"). Required.

date

POSIXct. Timestamp for the transaction. Defaults to `Sys.time()`.

Returns

None. Modifies the object's internal state by reducing the balance and appending a new transaction to the log.

Examples

\dontrun{
  main_acc <- MainAccount$new("Primary Pool")
  main_acc$deposit(amount = 1000, channel = "Mobile", by = "User")
  main_acc$withdraw(amount = 200, channel = "ATM", by = "User")
}


Method get_balance()

Returns the current balance of the account and prints it to the console.

Usage

MainAccount$get_balance()

Returns

Numeric. The current account balance.

Examples

\dontrun{
  main_acc <- MainAccount$new("Primary Pool")
  main_acc$deposit(amount = 500, channel = "Bank Transfer")
  main_acc$get_balance()
}


Method get_transactions()

Retrieves and displays the transaction history for the account. If no transactions are found, a message is printed. Otherwise, the transaction log is displayed in the console.

This method is inherited by child and grandchild account classes.

Usage

MainAccount$get_transactions()

Returns

A data frame containing the account's transaction history.

Examples

\dontrun{
  acc <- MainAccount$new("Main Budget")
  acc$deposit(500, channel = "M-Pesa")
  acc$get_transactions()
}


Method list_child_accounts()

Lists all direct child accounts attached to this account. If no child accounts are found, a message is printed.

This method is inherited by both `ChildAccount` and `GrandChildAccount`, allowing recursive visibility into nested account structures.

Usage

MainAccount$list_child_accounts()

Returns

Invisibly returns a character vector of child account names.

Examples

\dontrun{
  main_acc <- MainAccount$new("Main Budget")
  child <- ChildAccount$new("Bills", allocation = 0.5)
  main_acc$add_child_account(child)
  main_acc$list_child_accounts()
}
# Recursively find all accounts by name


Method find_account()

Recursively searches the current account, its children, and its parent chain to collect **all** accounts with a given name. This version differs from the original by not stopping at the first match—it returns a list of **all** matches instead.

It avoids infinite recursion by tracking visited account paths.

Usage

MainAccount$find_account(target_name, visited_paths = NULL, matches = NULL)

Arguments

target_name

Character. The name of the account(s) to locate.

visited_paths

(Internal use only) Tracks visited paths to avoid cycles.

matches

(Internal use only) A list to accumulate matches during recursion.

Returns

A list of account objects matching the given name. If no matches are found, returns an empty list.

Examples

\dontrun{
  main <- MainAccount$new("Main")
  savings1 <- ChildAccount$new("Savings", allocation = 0.5)
  savings2 <- ChildAccount$new("Savings", allocation = 0.3)
  main$add_child_account(savings1)
  main$add_child_account(savings2)
  found <- main$find_account("Savings")
  length(found)  # 2
  found[[1]]$uuid
}


Method find_account_by_uuid()

Recursively searches for an account by its unique UUID. The method traverses downward through all child accounts and upward to the parent, if needed, while preventing circular recursion by tracking visited paths. This is especially useful when account names are not unique but UUIDs are.

Usage

MainAccount$find_account_by_uuid(target_uuid, visited_paths = NULL)

Arguments

target_uuid

Character. The UUID of the account to find.

visited_paths

Internal use only. A list used to track visited paths and prevent infinite loops in cyclic or nested account structures.

Returns

Returns the account object whose UUID matches the target, or NULL if no match is found.

Examples

\dontrun{
  main_acc <- MainAccount$new("Root")
  groceries <- ChildAccount$new("Groceries", allocation = 0.3)
  main_acc$add_child_account(groceries)
  found <- main_acc$find_account_by_uuid(groceries$uuid)
  if (!is.null(found)) cat("Found UUID:", found$uuid)
}
# Move balance to another account (by UUID)


Method move_balance()

Moves a specified amount from the current account to another account identified by its **UUID**. This is intended for internal transfers within the account tree. It reuses `withdraw()` and `deposit()` logic and logs the transfer using the "Internal Transfer" channel.

The target account is resolved using `find_account_by_uuid()`, not by name. This ensures unambiguous targeting even when accounts share the same name.

Usage

MainAccount$move_balance(target_account_uuid, amount)

Arguments

target_account_uuid

Character. The UUID of the account to which the funds will be moved.

amount

Numeric. The amount to transfer. Must be less than or equal to the current account's balance.

Returns

No return value. Side effects include balance updates and transaction logs for both the source and target accounts.

Examples

\dontrun{
  main_acc <- MainAccount$new("Main")
  savings <- ChildAccount$new("Savings", allocation = 0.5)
  emergency <- ChildAccount$new("Emergency", allocation = 0.5)
  main_acc$add_child_account(savings)
  main_acc$add_child_account(emergency)

  # Initial deposit
  main_acc$deposit(1000, channel = "Bank")

  # Move 200 to savings using UUID
  main_acc$move_balance(savings$uuid, 200)
}


Method list_all_accounts()

Recursively lists the names of all accounts in the hierarchy, both upward (towards ancestors) and downward (towards descendants), starting from the current account. This method avoids revisiting any account by tracking visited paths, preventing infinite loops in case of circular references.

Usage

MainAccount$list_all_accounts(visited_paths = NULL)

Arguments

visited_paths

Optional list. Used internally for recursion to avoid revisiting accounts. Should generally be left as `NULL` by the user.

Returns

A character vector of account names found across the full reachable tree (both children and ancestors) from the current account.

Examples

\dontrun{
  main_acc <- MainAccount$new("Main")
  savings <- ChildAccount$new("Savings", allocation = 0.4)
  emergency <- ChildAccount$new("Emergency", allocation = 0.6)

  main_acc$add_child_account(savings)
  main_acc$add_child_account(emergency)

  # List all accounts from the root
  main_acc$list_all_accounts()
  # Output: "Main" "Savings" "Emergency"

  # List all accounts from a child node (will include parents)
  savings$list_all_accounts()
  # Output: "Savings" "Main" "Emergency"
}


Method compute_total_balance()

Recursively computes the total balance held by the current account and all of its child accounts. This method includes the balance of the account on which it's called and traverses down the tree to sum balances of all active descendants.

Usage

MainAccount$compute_total_balance()

Returns

Numeric. The total aggregated balance of this account and its entire descendant subtree.

Examples

\dontrun{
  main_acc <- MainAccount$new("Main")
  child1 <- ChildAccount$new("Child1", allocation = 0.5)
  child2 <- ChildAccount$new("Child2", allocation = 0.5)

  main_acc$add_child_account(child1)
  main_acc$add_child_account(child2)

  main_acc$deposit(100, channel = "Bank", transaction_number = "txn1")
  # This distributes 100 into child1 and child2 based on allocation

  # Check total balance recursively
  total <- main_acc$compute_total_balance()
  print(total)
  # Should return 100 (main + children)
}


Method compute_total_due()

Recursively computes the total amount due for the current account and all of its descendant child accounts. If `amount_due` is not defined in an account, it defaults to zero.

This is useful for aggregating outstanding dues across the entire hierarchical account structure (e.g., main → child → grandchild).

Usage

MainAccount$compute_total_due()

Returns

Numeric. The total due amount for this account and all its descendants.

Examples

\dontrun{
  main_acc <- MainAccount$new("Main")
  child1 <- ChildAccount$new("Child1", allocation = 0.6)
  child2 <- ChildAccount$new("Child2", allocation = 0.4)

  main_acc$add_child_account(child1)
  main_acc$add_child_account(child2)

  # Manually set dues
  main_acc$amount_due <- 50
  child1$amount_due <- 20
  child2$amount_due <- 30

  total_due <- main_acc$compute_total_due()
  print(total_due)
  # Should return 100 (50 + 20 + 30)
}


Method compute_total_due_within_n_days()

Recursively computes the total amount due for the current account and all child accounts where the due date is within the next n days from the current system time.

This method is useful for identifying upcoming payments or obligations in a multi-account hierarchy and prioritizing them based on urgency.

Usage

MainAccount$compute_total_due_within_n_days(n)

Arguments

n

Integer. The number of days from today within which dues should be considered. Dues without a due date are ignored.

Returns

Numeric. The total due amount within the next n days across the account hierarchy.

Examples

\dontrun{
  main_acc <- MainAccount$new("Main")
  child1 <- ChildAccount$new("Child1", allocation = 0.6)
  child2 <- ChildAccount$new("Child2", allocation = 0.4)

  main_acc$add_child_account(child1)
  main_acc$add_child_account(child2)

  # Assign dues and due dates
  main_acc$amount_due <- 100
  main_acc$due_date <- Sys.time() + 2 * 24 * 60 * 60  # Due in 2 days

  child1$amount_due <- 50
  child1$due_date <- Sys.time() + 5 * 24 * 60 * 60    # Due in 5 days

  child2$amount_due <- 70
  child2$due_date <- Sys.time() + 10 * 24 * 60 * 60   # Due in 10 days

  # Compute total dues within next 7 days
  total_due_7_days <- main_acc$compute_total_due_within_n_days(7)
  print(total_due_7_days)
  # Should return 100 + 50 = 150
}


Method spending()

Recursively computes the total spending (i.e., user-initiated withdrawals) for the current account and all child accounts within a specified date range.

Spending is defined as withdrawals made by the user (`By == "User"`), excluding system-initiated or internal transfers. The function includes both the current account and all of its descendants in the calculation.

Usage

MainAccount$spending(daterange = c(Sys.Date() - 365000, Sys.Date()))

Arguments

daterange

A Date or POSIXct vector of length 2. The start and end dates for the period over which to compute spending. Defaults to the entire timeline.

Returns

Numeric. The total spending amount over the specified date range.

Examples

\dontrun{
  main_acc <- MainAccount$new("Main")
  child1 <- ChildAccount$new("Child1", allocation = 0.5)
  child2 <- ChildAccount$new("Child2", allocation = 0.5)

  main_acc$add_child_account(child1)
  main_acc$add_child_account(child2)

  # Simulate some deposits and withdrawals
  main_acc$deposit(500, "T1", By = "User", channel = "Cash")
  main_acc$withdraw(200, By = "User", channel = "Spending",
  date = Sys.time() - 10)
  child1$deposit(300, "T2", By = "User", channel = "Mobile")
  child1$withdraw(100, By = "User", channel = "Shopping",
  date = Sys.time() - 5)

  # Get total user spending in last 30 days
  main_acc$spending(c(Sys.Date() - 30, Sys.Date()))
  # Should return 200 + 100 = 300
}


Method total_income()

Recursively computes the total income (i.e., user-initiated deposits) for the current account and all of its child accounts within a specified date range.

This function sums up all "Deposit" transactions where the `By` field is set to `"User"`. It includes both the current account and all of its descendants in the income calculation.

Usage

MainAccount$total_income(daterange = c(Sys.Date() - 365000, Sys.Date()))

Arguments

daterange

A vector of two Dates or POSIXct objects specifying the start and end dates for the income calculation. Defaults to the entire timeline.

Returns

A numeric value representing the total income across all relevant accounts within the specified date range.

Examples

\dontrun{
  main_acc <- MainAccount$new("Main")
  child1 <- ChildAccount$new("Child1", allocation = 0.5)
  child2 <- ChildAccount$new("Child2", allocation = 0.5)

  main_acc$add_child_account(child1)
  main_acc$add_child_account(child2)

  # Simulate some deposits
  main_acc$deposit(500, "TX01", By = "User", channel = "Cash",
  date = Sys.time() - 7)
  child1$deposit(300, "TX02", By = "User", channel = "Mobile",
  date = Sys.time() - 3)

  # Get total income in last 10 days
  main_acc$total_income(c(Sys.Date() - 10, Sys.Date()))
  # Should return 500 + 300 = 800
}


Method allocated_amount()

Calculates the total allocated amount to this account and its child accounts over a specified date range.

This includes **all deposits** (from both `"User"` and `"System"`) into the current account, **plus** all **user-initiated** deposits into child and deeper-level descendant accounts. It provides insight into how much funding (regardless of origin) has been allocated directly or indirectly to this node in the account tree.

Usage

MainAccount$allocated_amount(daterange = c(Sys.Date() - 365000, Sys.Date()))

Arguments

daterange

A vector of two `Date` or `POSIXct` objects specifying the start and end dates for the deposit aggregation. Defaults to a very wide range.

Returns

A numeric value representing the total allocated amount across the account and its descendants within the specified date range.

Examples

\dontrun{
  main_acc <- MainAccount$new("Main")
  child1 <- ChildAccount$new("Child1", allocation = 0.5)
  child2 <- ChildAccount$new("Child2", allocation = 0.5)

  main_acc$add_child_account(child1)
  main_acc$add_child_account(child2)

  main_acc$deposit(1000, "TX001", By = "System", channel = "Bank",
  date = Sys.time() - 5)
  child1$deposit(300, "TX002", By = "User", channel = "Mobile",
  date = Sys.time() - 3)
  child2$deposit(200, "TX003", By = "User", channel = "Cash",
  date = Sys.time() - 2)

  # Get total allocated amount within last 7 days
  main_acc$allocated_amount(c(Sys.Date() - 7, Sys.Date()))
  # Expected output: 1000 (System) + 300 + 200 = 1500
}


Method income_utilization()

Computes the **income utilization ratio** over a specified date range.

This is calculated as the ratio of total user withdrawals (`spending`) to the total allocated income (`allocated_amount`). It measures how effectively funds are being used relative to the total amount deposited (both by user and system).

A value close to 1 indicates high utilization (most funds spent), while a valueclose to 0 indicates low spending relative to funds received.

Usage

MainAccount$income_utilization(daterange = c(Sys.Date() - 365000, Sys.Date()))

Arguments

daterange

A vector of two `Date` or `POSIXct` values defining the date range for the calculation. Defaults to a large historical window.

Returns

A numeric value (between 0 and potentially >1) representing the income utilization ratio. If no income has been allocated, a small epsilon is added to the denominator to avoid division by zero.

Examples

\dontrun{
  account <- MainAccount$new("Parent")
  account$deposit(1000, "TX001", By = "System", channel = "Bank")
  account$withdraw(200, By = "User", channel = "Mobile")

  account$income_utilization()
  # Expected output: 200 / 1000 = 0.2
}


Method walking_amount()

Computes the **latest recorded amount** (either `amount_due` or `balance`) from the `Track_dues_and_balance` tracker for the current account and all its child accounts within a specified date range.

It retrieves the latest entry in the given date range, and recursively sums the values for all child accounts.

Usage

MainAccount$walking_amount(
  amt_type = "amount_due",
  daterange = c(Sys.Date() - 365000, Sys.Date())
)

Arguments

amt_type

A string specifying the metric to return: - `"amount_due"`: Return the last tracked `Amount_due`. - `"Balance"`: Return the last tracked `Balance`.

daterange

A vector of two dates (of class `Date` or `POSIXct`) specifying the time window. Default: wide historical range.

Returns

A numeric value representing the sum of either latest `Amount_due` or `Balance` from this account and all its children.

Examples

\dontrun{
account$walking_amount("amount_due", c(Sys.Date() - 30,
Sys.Date()))
account$walking_amount("Balance", c(Sys.Date() - 7, Sys.Date()))
}


Method clone()

The objects of this class are cloneable with this method.

Usage

MainAccount$clone(deep = FALSE)

Arguments

deep

Whether to make a deep clone.

Examples

library(R6)
library(uuid)
library(tidyverse)
# Create a main account

acc <- MainAccount$new(name = "Salary Pool", balance = 1000)

# Generate a system transaction ID
acc$generate_transaction_id()
#> [1] "sys1"

# Check for duplicate transaction ID
acc$is_duplicate_transaction("sys1")
#> [1] FALSE

# Inspect balance
acc$balance
#> [1] 1000

# Inspect UUID
acc$uuid
#> [1] "acc3e98c72b-7231-45f7-882c-74d134b0f853"


## ------------------------------------------------
## Method `MainAccount$new`
## ------------------------------------------------

if (FALSE) { # \dontrun{
main_acc <- MainAccount$new(name = "My Main Account")
print(main_acc$uuid)
print(main_acc$balance)
print(main_acc$transactions)
} # }

## ------------------------------------------------
## Method `MainAccount$generate_transaction_id`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new(name = "Salary Pool")
  txn_id1 <- main_acc$generate_transaction_id()
  txn_id2 <- main_acc$generate_transaction_id()
  print(txn_id1)  # e.g., "sys1"
  print(txn_id2)  # e.g., "sys2"
} # }

## ------------------------------------------------
## Method `MainAccount$is_duplicate_transaction`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  # Create a new main account
  main_acc <- MainAccount$new(name = "Salary Pool")

  # Manually add a transaction with ID "sys1"
  main_acc$transactions <- data.frame(
    Type = "Income",
    By = "User",
    TransactionID = "sys1",
    Channel = "Bank",
    Amount = 5000,
    Balance = 5000,
    amount_due = 0,
    overall_balance = 5000,
    Date = Sys.time(),
    stringsAsFactors = FALSE
  )

  # Check for duplicate
  main_acc$is_duplicate_transaction("sys1")  # Returns TRUE
  main_acc$is_duplicate_transaction("sys2")  # Returns FALSE
} # }

## ------------------------------------------------
## Method `MainAccount$deposit`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new(name = "Salary Pool")
  main_acc$deposit(
    amount = 1000,
    channel = "Bank Transfer"
  )
} # }


## ------------------------------------------------
## Method `MainAccount$distribute_to_children`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new(name = "Salary Pool")
  child1 <- ChildAccount$new(name = "Food Fund", allocation = 0.6)
  child2 <- ChildAccount$new(name = "Savings", allocation = 0.4)
  main_acc$add_child_account(child1)
  main_acc$add_child_account(child2)

  main_acc$deposit(amount = 1000, channel = "Bank")
  # This will trigger distribute_to_children internally.
} # }


## ------------------------------------------------
## Method `MainAccount$add_child_account`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new(name = "Master")
  child_acc <- ChildAccount$new(name = "Savings", allocation = 0.4)
  main_acc$add_child_account(child_acc)
} # }

## ------------------------------------------------
## Method `MainAccount$set_child_allocation`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new("Main")
  child <- ChildAccount$new(name = "Emergency", allocation = 0.2)
  main_acc$add_child_account(child)
  main_acc$set_child_allocation("Emergency", 0.3)
} # }

## ------------------------------------------------
## Method `MainAccount$withdraw`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new("Primary Pool")
  main_acc$deposit(amount = 1000, channel = "Mobile", by = "User")
  main_acc$withdraw(amount = 200, channel = "ATM", by = "User")
} # }

## ------------------------------------------------
## Method `MainAccount$get_balance`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new("Primary Pool")
  main_acc$deposit(amount = 500, channel = "Bank Transfer")
  main_acc$get_balance()
} # }

## ------------------------------------------------
## Method `MainAccount$get_transactions`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  acc <- MainAccount$new("Main Budget")
  acc$deposit(500, channel = "M-Pesa")
  acc$get_transactions()
} # }

## ------------------------------------------------
## Method `MainAccount$list_child_accounts`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new("Main Budget")
  child <- ChildAccount$new("Bills", allocation = 0.5)
  main_acc$add_child_account(child)
  main_acc$list_child_accounts()
} # }
# Recursively find all accounts by name


## ------------------------------------------------
## Method `MainAccount$find_account`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main <- MainAccount$new("Main")
  savings1 <- ChildAccount$new("Savings", allocation = 0.5)
  savings2 <- ChildAccount$new("Savings", allocation = 0.3)
  main$add_child_account(savings1)
  main$add_child_account(savings2)
  found <- main$find_account("Savings")
  length(found)  # 2
  found[[1]]$uuid
} # }

## ------------------------------------------------
## Method `MainAccount$find_account_by_uuid`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new("Root")
  groceries <- ChildAccount$new("Groceries", allocation = 0.3)
  main_acc$add_child_account(groceries)
  found <- main_acc$find_account_by_uuid(groceries$uuid)
  if (!is.null(found)) cat("Found UUID:", found$uuid)
} # }
# Move balance to another account (by UUID)


## ------------------------------------------------
## Method `MainAccount$move_balance`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new("Main")
  savings <- ChildAccount$new("Savings", allocation = 0.5)
  emergency <- ChildAccount$new("Emergency", allocation = 0.5)
  main_acc$add_child_account(savings)
  main_acc$add_child_account(emergency)

  # Initial deposit
  main_acc$deposit(1000, channel = "Bank")

  # Move 200 to savings using UUID
  main_acc$move_balance(savings$uuid, 200)
} # }

## ------------------------------------------------
## Method `MainAccount$list_all_accounts`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new("Main")
  savings <- ChildAccount$new("Savings", allocation = 0.4)
  emergency <- ChildAccount$new("Emergency", allocation = 0.6)

  main_acc$add_child_account(savings)
  main_acc$add_child_account(emergency)

  # List all accounts from the root
  main_acc$list_all_accounts()
  # Output: "Main" "Savings" "Emergency"

  # List all accounts from a child node (will include parents)
  savings$list_all_accounts()
  # Output: "Savings" "Main" "Emergency"
} # }

## ------------------------------------------------
## Method `MainAccount$compute_total_balance`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new("Main")
  child1 <- ChildAccount$new("Child1", allocation = 0.5)
  child2 <- ChildAccount$new("Child2", allocation = 0.5)

  main_acc$add_child_account(child1)
  main_acc$add_child_account(child2)

  main_acc$deposit(100, channel = "Bank", transaction_number = "txn1")
  # This distributes 100 into child1 and child2 based on allocation

  # Check total balance recursively
  total <- main_acc$compute_total_balance()
  print(total)
  # Should return 100 (main + children)
} # }

## ------------------------------------------------
## Method `MainAccount$compute_total_due`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new("Main")
  child1 <- ChildAccount$new("Child1", allocation = 0.6)
  child2 <- ChildAccount$new("Child2", allocation = 0.4)

  main_acc$add_child_account(child1)
  main_acc$add_child_account(child2)

  # Manually set dues
  main_acc$amount_due <- 50
  child1$amount_due <- 20
  child2$amount_due <- 30

  total_due <- main_acc$compute_total_due()
  print(total_due)
  # Should return 100 (50 + 20 + 30)
} # }

## ------------------------------------------------
## Method `MainAccount$compute_total_due_within_n_days`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new("Main")
  child1 <- ChildAccount$new("Child1", allocation = 0.6)
  child2 <- ChildAccount$new("Child2", allocation = 0.4)

  main_acc$add_child_account(child1)
  main_acc$add_child_account(child2)

  # Assign dues and due dates
  main_acc$amount_due <- 100
  main_acc$due_date <- Sys.time() + 2 * 24 * 60 * 60  # Due in 2 days

  child1$amount_due <- 50
  child1$due_date <- Sys.time() + 5 * 24 * 60 * 60    # Due in 5 days

  child2$amount_due <- 70
  child2$due_date <- Sys.time() + 10 * 24 * 60 * 60   # Due in 10 days

  # Compute total dues within next 7 days
  total_due_7_days <- main_acc$compute_total_due_within_n_days(7)
  print(total_due_7_days)
  # Should return 100 + 50 = 150
} # }

## ------------------------------------------------
## Method `MainAccount$spending`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new("Main")
  child1 <- ChildAccount$new("Child1", allocation = 0.5)
  child2 <- ChildAccount$new("Child2", allocation = 0.5)

  main_acc$add_child_account(child1)
  main_acc$add_child_account(child2)

  # Simulate some deposits and withdrawals
  main_acc$deposit(500, "T1", By = "User", channel = "Cash")
  main_acc$withdraw(200, By = "User", channel = "Spending",
  date = Sys.time() - 10)
  child1$deposit(300, "T2", By = "User", channel = "Mobile")
  child1$withdraw(100, By = "User", channel = "Shopping",
  date = Sys.time() - 5)

  # Get total user spending in last 30 days
  main_acc$spending(c(Sys.Date() - 30, Sys.Date()))
  # Should return 200 + 100 = 300
} # }

## ------------------------------------------------
## Method `MainAccount$total_income`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new("Main")
  child1 <- ChildAccount$new("Child1", allocation = 0.5)
  child2 <- ChildAccount$new("Child2", allocation = 0.5)

  main_acc$add_child_account(child1)
  main_acc$add_child_account(child2)

  # Simulate some deposits
  main_acc$deposit(500, "TX01", By = "User", channel = "Cash",
  date = Sys.time() - 7)
  child1$deposit(300, "TX02", By = "User", channel = "Mobile",
  date = Sys.time() - 3)

  # Get total income in last 10 days
  main_acc$total_income(c(Sys.Date() - 10, Sys.Date()))
  # Should return 500 + 300 = 800
} # }

## ------------------------------------------------
## Method `MainAccount$allocated_amount`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  main_acc <- MainAccount$new("Main")
  child1 <- ChildAccount$new("Child1", allocation = 0.5)
  child2 <- ChildAccount$new("Child2", allocation = 0.5)

  main_acc$add_child_account(child1)
  main_acc$add_child_account(child2)

  main_acc$deposit(1000, "TX001", By = "System", channel = "Bank",
  date = Sys.time() - 5)
  child1$deposit(300, "TX002", By = "User", channel = "Mobile",
  date = Sys.time() - 3)
  child2$deposit(200, "TX003", By = "User", channel = "Cash",
  date = Sys.time() - 2)

  # Get total allocated amount within last 7 days
  main_acc$allocated_amount(c(Sys.Date() - 7, Sys.Date()))
  # Expected output: 1000 (System) + 300 + 200 = 1500
} # }

## ------------------------------------------------
## Method `MainAccount$income_utilization`
## ------------------------------------------------

if (FALSE) { # \dontrun{
  account <- MainAccount$new("Parent")
  account$deposit(1000, "TX001", By = "System", channel = "Bank")
  account$withdraw(200, By = "User", channel = "Mobile")

  account$income_utilization()
  # Expected output: 200 / 1000 = 0.2
} # }

## ------------------------------------------------
## Method `MainAccount$walking_amount`
## ------------------------------------------------

if (FALSE) { # \dontrun{
account$walking_amount("amount_due", c(Sys.Date() - 30,
Sys.Date()))
account$walking_amount("Balance", c(Sys.Date() - 7, Sys.Date()))
} # }