Public/Get-ProjectedTransactions.ps1

function Get-ProjectedTransactions {
    <#
    .SYNOPSIS
        Generates projected transactions based on billers and earnings.
 
    .DESCRIPTION
        Creates a list of projected transactions for a specified date range based on
        configured billers and earnings. Calculates running balance for each transaction.
 
    .PARAMETER StartDate
        The start date for the projection period.
 
    .PARAMETER EndDate
        The end date for the projection period.
 
    .PARAMETER AccountId
        Optional account ID to associate with transactions.
 
    .PARAMETER InitialBalance
        The starting balance for the projection. Defaults to 0.
 
    .PARAMETER Budget
        Optional budget name to target. Uses active budget if not specified.
 
    .PARAMETER DataPath
        Optional custom path for data storage. Overrides budget-based paths.
 
    .EXAMPLE
        Get-ProjectedTransactions -StartDate "2025-01-01" -EndDate "2025-03-31"
 
    .EXAMPLE
        Get-ProjectedTransactions -StartDate (Get-Date) -EndDate (Get-Date).AddMonths(6) -InitialBalance 1000
 
    .EXAMPLE
        Get-ProjectedTransactions -StartDate "2025-01-01" -EndDate "2025-12-31" -Budget "japan-holiday-2026"
 
    .OUTPUTS
        Array of Transaction objects
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [datetime]$StartDate,

        [Parameter(Mandatory)]
        [datetime]$EndDate,

        [Parameter()]
        [string]$AccountId,

        [Parameter()]
        [decimal]$InitialBalance = 0,

        [Parameter()]
        [string]$Budget,

        [Parameter()]
        [string]$DataPath
    )

    $resolvedPath = Resolve-DataPath -DataPath $DataPath -Budget $Budget
    if (-not $resolvedPath) { return @() }

    # Get all billers and earnings
    $billers = Read-EntityData -EntityType 'Biller' -DataPath $resolvedPath
    $earnings = Read-EntityData -EntityType 'Earning' -DataPath $resolvedPath

    # Create transaction list
    $transactions = [System.Collections.ArrayList]::new()

    # Process earnings (positive transactions)
    foreach ($earning in $earnings) {
        $currentDate = Get-NextOccurrence -StartDate $earning.StartDate -Frequency $earning.Frequency -FromDate $StartDate

        while ($currentDate -le $EndDate) {
            $transaction = [Transaction]@{
                Date = $currentDate
                Name = $earning.Name
                Amount = $earning.Amount
                Balance = 0  # Will calculate later
                Type = 'Earning'
                AccountId = $AccountId
            }
            $transactions.Add($transaction) | Out-Null

            # Get next occurrence
            switch ($earning.Frequency) {
                'Daily' { $currentDate = $currentDate.AddDays(1) }
                'Weekly' { $currentDate = $currentDate.AddDays(7) }
                'BiWeekly' { $currentDate = $currentDate.AddDays(14) }
                'Monthly' { $currentDate = $currentDate.AddMonths(1) }
                'Bimonthly' { $currentDate = $currentDate.AddMonths(2) }
                'Quarterly' { $currentDate = $currentDate.AddMonths(3) }
                'Yearly' { $currentDate = $currentDate.AddYears(1) }
            }
        }
    }

    # Process billers (negative transactions)
    foreach ($biller in $billers) {
        $currentDate = Get-NextOccurrence -StartDate $biller.StartDate -Frequency $biller.Frequency -FromDate $StartDate

        while ($currentDate -le $EndDate) {
            $transaction = [Transaction]@{
                Date      = $currentDate
                Name      = $biller.Name
                Amount    = -$biller.Amount  # Negative for expenses
                Balance   = 0  # Will calculate later
                Type      = 'Biller'
                AccountId = $AccountId
            }
            $transactions.Add($transaction) | Out-Null

            # Get next occurrence
            switch ($biller.Frequency) {
                'Daily' { $currentDate = $currentDate.AddDays(1) }
                'Weekly' { $currentDate = $currentDate.AddDays(7) }
                'BiWeekly' { $currentDate = $currentDate.AddDays(14) }
                'Monthly' { $currentDate = $currentDate.AddMonths(1) }
                'Bimonthly' { $currentDate = $currentDate.AddMonths(2) }
                'Quarterly' { $currentDate = $currentDate.AddMonths(3) }
                'Yearly' { $currentDate = $currentDate.AddYears(1) }
            }
        }
    }

    # Sort transactions by date
    $sortedTransactions = $transactions | Sort-Object -Property Date

    # Add initial balance as the first entry
    $initialTransaction = [Transaction]@{
        Date      = $StartDate
        Name      = 'Initial Balance'
        Amount    = 0
        Balance   = $InitialBalance
        Type      = 'Balance'
        AccountId = $AccountId
    }

    # Create final list with initial balance first
    $finalTransactions = [System.Collections.ArrayList]::new()
    $finalTransactions.Add($initialTransaction) | Out-Null

    # Calculate running balance for remaining transactions
    $runningBalance = $InitialBalance
    foreach ($transaction in $sortedTransactions) {
        $runningBalance += $transaction.Amount
        $transaction.Balance = $runningBalance
        $finalTransactions.Add($transaction) | Out-Null
    }

    return $finalTransactions
}