RVR.Declarations.psm1

function Send-Declaration {
    <#
       .SYNOPSIS
        Send the declaration using Outlook.
 
       .DESCRIPTION
       Send the declaration using Outlook.
     
       .PARAMETER recipient
       The recipient to send the declaration to
 
       .PARAMETER subject
       The email message subject.
 
       .PARAMETER Transactions
       The transactions to include in the mail message
 
       .PARAMETER SumAmount
       The total amount of declarations (eur)
     
    #>


    [cmdletbinding()]
    param(
        $recipient = 'robertreems@gmail.com',
        $subject = 'Parkeerdeclaraties Robert van Reems',
        $Transactions,
        $SumAmount
    )

    begin {
        #Start Outlook process`
        try {
            $Outlook = New-Object -ComObject Outlook.Application -ErrorAction Stop

        }
        catch {
            throw "Failed to start Outlook with error: $_"
            exit
        }

        #Compile the Message body

        $Body = "Beste collega,
 
        Hierbij de declaraties van mijn parkeerkosten in Den Bosch Pettelaar park. Deze kosten zijn gemaakt voor mijn werkzaamheden bij de Volksbank.
 
        De transacties staan hieronder:
        $Transactions
 
        Het totaal bedrag komt neer op $SumAmount Euro
 
        Alvast bedankt voor het verwerken."


    }

    process {

        $Mail = $Outlook.CreateItem(0)

        $Mail.To = $recipient
        $Mail.Subject = $subject
        $Mail.Body = $body

        $Mail.Send()

    }

    end {
            # stop Outlook
            $Outlook.Quit()    
    }
}

function Get-BankTransaction {

    <#
       .SYNOPSIS
        The function that imports the CSV exported from the bank
 
       .DESCRIPTION
       The function that imports the CSV exported from the bank
     
       .PARAMETER Path
       Path to the CSV-file
     
    #>


    [cmdletbinding()]
    param (
        [ValidateScript( {
                if ( -Not ($_ | Test-Path) ) {
                    throw "File or folder does not exist"
                    exit
                }
                return $true
            })]
        [System.IO.FileInfo]$Path
    )
    
    # The predefined header for the CSV-file
    # TODO update columns
    $header = 'Date', 'Account', 'CounterAccount', 'ReadableOrgName', 'Kolom4', 'Kolom5', 'Kolom6', 'Currency', 'Kolom8', 'Currency2', 'Amount', 'Date2', 'Date3', 'Unknown', 'Unknown1', 'Unknown2', 'Unknown3', 'Description', 'Unknown4'
        
    $Transactions = [System.Collections.ArrayList]@()
    
    Write-Verbose "Importing $path"
    try {
        $Transactions += Import-Csv -Delimiter ';' -Path $Path -Header $header    
    }
    catch {
        throw "Failed to import CSV-file $Path with error: $_"
        exit
    }

    Write-Verbose "Imported transactions is: $($Transactions.count)"

    Write-Verbose 'Filtering the transactions'
    $FilteredTransactions = $Transactions.Where( { $_.Description -like '*PETTELR*' -and $_.Amount -eq '-4.00' })    
    
    return $FilteredTransactions
}

function Test-TransactionIsDeclared {
    <#
       .SYNOPSIS
       Tests if the transaction is allready declared or not.
     
       .DESCRIPTION
       Tests if the transaction is allready declared or not.
     
       .PARAMETER Transaction
       The transaction to test
     
       .PARAMETER Path
       Path to the database file (CSV) containing allready declared transactions
     
    #>


    [cmdletbinding()]
    [OutputType([boolean])] 

    param (
        [parameter()]
        [ValidateNotNull()]
        $Transaction, 
        
        [parameter()]
        [ValidateScript( {
                if ( -Not ($_ | Test-Path) ) {
                    throw "File or folder does not exist"
                    exit
                }
                return $true
            })]
        [System.IO.FileInfo]$Path
    )
    
    begin {
        
        # Import the CSV to $Declared CSV
        # I'm using script scope so the contents can be cached.

        # Check if cache exists
        if (-not $Script:DeclaredTransactions) {

            try {
                Write-Verbose "Importing Declared transactions file $path"
                $Script:DeclaredTransactions = Import-Csv $Path 
                
            }
            catch {
                throw "Failed to import declared transactions file $path with error $_ " 
                exit
            }
        }
    }

    process {
        # Check if there are declared transactions
        if ($Script:DeclaredTransactions.count -gt 1) {

            # If there are declared transactions check them.
            if ( $Script:DeclaredTransactions.Description.Contains($transaction.Description) ) {
                return $true
            }
            else {
                return $false
            }
        }
    }

    end {

    }
}

function Get-ToDeclareTransaction {

    <#
       .SYNOPSIS
       This returnes the transactions that have yet to be declared.
     
       .DESCRIPTION
       This returnes the transactions that have yet to be declared.
     
       .PARAMETER BankTransactionsPath
       The path to the Bank transactions CSV file
 
       .PARAMETER DeclaredTransactionsPath
        Path to the database file (CSV) containing allready declared transactions
     
    #>

    
    [cmdletbinding()]
    param(
        [ValidateScript( {
                if ( -Not ($_ | Test-Path) ) {
                    throw "File or folder does not exist"
                    exit
                }
                return $true
            })]
        [System.IO.FileInfo]$BankTransactionsPath,

        $DeclaredTransactionsPath
    )

    begin {
        # Get the Bank transactions from CSV
        Write-Verbose "Importing bank transactions $BankTransactionsPath"
        $BankTransactions = Get-BankTransaction -ErrorAction Stop -Path $BankTransactionsPath
    }

    process {
        # Loop through each transaction and check if it's allready declared
        $ToDeclareTransactions = @()
        foreach ($transaction in $BankTransactions) {
            if (Test-TransactionIsDeclared -Path $DeclaredTransactionsPath -Transaction $transaction ) {
                # The transaction is allready declared
                Write-Verbose "$($transaction.description) is allready declared."
            }
            else {
                Write-Verbose "$($transaction.description) is not yet declared."
                $ToDeclareTransactions += $transaction
            }
        }
    }

    end {
        $ToDeclareTransactions
    }
}

function New-Declaration {

    <#
       .SYNOPSIS
        Creates a new declaration email containing all the not yet declared transactions.
     
       .DESCRIPTION
        This function takes a CSV file from the SNS-bank to search for new transactions that have to be declared. If
        new declarations are found it sends them using Outlook.
     
       .PARAMETER BankTransactionsPath
       The path to the CSV-file exported from the bank.
 
       .PARAMETER DeclaredTransactionsPath
       Path to the database file (CSV) containing allready declared transactions.
       You should allways use the same file.
 
       .PARAMETER Recipient
       The recipient of the e-mail message.
     
       .EXAMPLE
       Use .\test-transactions.csv as input and send the declaration.
        
       PS> New-Declaration -BankTransactionsPath .\test-transactions.csv -recipient xxx@xmail.com
     
    #>

    
    [cmdletbinding(SupportsShouldProcess=$True)]

    param(
        [parameter(Mandatory)]
        [ValidateScript( {
                if ( -Not ($_ | Test-Path) ) {
                    throw "File or folder does not exist"
                    exit
                }
                return $true
            })]
        [System.IO.FileInfo]$BankTransactionsPath,
        
        [System.IO.FileInfo]$DeclaredTransactionsPath = ( ([Environment]::GetFolderPath("MyDocuments") ) + '\MyDeclarations.csv'),
        $Recipient = 'robertreems@gmail.com'
        
    )

    Begin {
        Write-Verbose 'Starting New-Declaration'

        # Create new DeclaredTransactions CSV if it doesn't exist
        if (-not (Test-Path $DeclaredTransactionsPath) ) {
            Write-Verbose 'Create new Declared transactions file'

            New-Item $DeclaredTransactionsPath -Force | Out-Null
        }
    }

    Process {
        # Get the transactions that should be declared
        $ToDeclareTransactions = @()
        $ToDeclareTransactions += Get-ToDeclareTransaction -BankTransactionsPath $BankTransactionsPath -DeclaredTransactionsPath $DeclaredTransactionsPath

        $sum = 0
        foreach ($transaction in $ToDeclareTransactions) {
            $sum = $sum + [int]$transaction.Amount
        }

        # Since $sum is a negative interger I'll have to convert it to positive
        $sum = -$sum 

        # utilise whatif
        If ($PSCmdlet.ShouldProcess("Sending message")) { 

            # If new transactions are found send the mail and update the $DeclaredTransactionsPath.
            if($ToDeclareTransactions.count -gt 0){
                Write-Verbose "Sum of transactions (euro): $sum"

                Send-Declaration -Transactions ($ToDeclareTransactions | Format-Table date, Amount, Description | Out-String) -SumAmount $sum -recipient $recipient 

                # TODO update $DeclaredTransactions
                try {
                    Write-Verbose "Writing new transactions to $DeclaredTransactionsPath"


                    $ToDeclareTransactions | Export-Csv -Path $DeclaredTransactionsPath -Append -ErrorAction Stop -Force
                } 
                catch {
                    throw "Failed to update $DeclaredTransactionsPath with error: $_ "
                    Exit 
                }
            }
        }
    }

    End {
        # empty cache
        $Script:DeclaredTransactions = $null

        Write-Verbose 'Ending normally'
    }
}