Account Management, Part 2

Previously, I wrote about the utility classes needed for the application. I wrote about them first as they will be used in view models discussed in this post. Today, I will start discussing the domain and view models for the account data.

Account Types

The account type domain and view model will be used to manage the types of general ledger accounts. There are typically six types of general ledger accounts, Assets, Liabilities, Equity, Revenue, Expenses, and Other income accounts.

Asset general ledger accounts are used to track what the organization’s assets. This could be account receivables that have not yet been collected, investments, inventory, or cash. The normal balance for asset accounts would be debits, which mean that kind of transaction increases the value of the asset.

Liability general ledger accounts are used to track what an organization is obliged to pay someone else. These could be collected taxes not yet paid to the government, debt on a line of credit, unpaid expenses, or deposits placed by customers. The normal balance for liability accounts is credits, which means debits decrease the value of the account, or decrease what is owed by the organization.

Equity general ledger accounts are used to track investments made in the organization. These represent the amount invested and the growth of those accounts. A simple way of envisioning these accounts is to see them as a special type of liability, containing the value of the assets less the total liabilities. The normal balance for equity accounts is credits, which means that a debit represents a decrease in shareholder equity either through withdrawals or losses.

Revenue general ledger accounts are used to track monies paid to the organization. Depending on the type of organization, these could represent sales, donations, grants, rent payments. The normal balance for revenue accounts is credits, which means that a debit decreases the value of the revenue account.

Expense general ledger accounts are used to track expenses incurred by an organization. These represent salaries, utility bills, costs of services or good, and anything else for which the organization might be billed. Liabilities become expenses when they come due. An example of this is the quarterly payment of income taxes to the government. Taxes are a liability until they are to be paid to the government, then they become an expense. The normal balance for expense accounts is debits, meaning that a debit increases the value of the expense account.

Other income accounts are used to track income from non-day to day activities. These could represent a gain or loss in equity from the sale of an asset or interest collected on deposit or investment accounts. There is no documentation on what the normal balance would be for these types of accounts. However, since these represent income, I will treat them like revenue accounts. Therefore, the normal balance for the other income accounts is credits, just like revenue.

What does this all mean for building the domain and view models? This means we can now decide what data needs to be displayed and persisted.

The first step to building the account type models is to create an enumeration for the normal balance and another for the financial statement type.

The Normal Balance enumeration:

namespace Accounting.Core
{
    public enum NormalBalance : byte
    {
        D = 1,
        C = 2

    }
}

The Financial Statement Type enumeration:

namespace Accounting.Core
{
    public enum FinancialStatementType : byte
    {
        BalanceSheet = 1,
        IncomeStatement = 2,
        CashFlow = 3
    }
}

With the enumerations built, we can design the view model for the account type. We need to following information.

Field NameData TypeNotes
IdbyteIdentity
NameString30 characters
CodeString10 characters
NormalBalanceNormalBalanceUse enumeration
IsActiveString1 character
DescriptionString512 characters
StatementTypeFinancialStatementType
ReportingSequencebyteReporting sort order
HasTaxImplicationString1 character

The code for the view model looks like:

namespace Accounting.Core
{
    public class AccountTypeVM
    {
        public byte Id { get; set; }
        public string Name { get; set; }
        public String Code { get; set; }
        public NormalBalance NormalBalance { get; set; }
        public String IsActive { get; set; }
        public String Description { get; set; }
        public FinancialStatementType StatementType { get; set; }
        public byte ReportingSequence { get; set; }
        public String HasTaxImplications { get; set; }

        public override String ToString()
        {
            return Name;
        }

        public AccountTypeVM() : this(0, String.Empty, String.Empty, NormalBalance.D, 0, "N", String.Empty, FinancialStatementType.BalanceSheet, 0, "N")
        { }

        public AccountTypeVM(byte id, String name, String code, NormalBalance normalBalance, byte categoryId, String isActive, String description, FinancialStatementType statementType, byte reportingSequence, String hasTaxImplications)
        {
            Id = id;
            Name = name;
            Code = code;
            NormalBalance = normalBalance;
            CategoryId = categoryId;
            IsActive = isActive;
            Description = description;
            StatementType = statementType;
            ReportingSequence = reportingSequence;
            HasTaxImplications = hasTaxImplications;
        }
    }
}

The domain model will look like:

namespace Accounting.Core.Domain
{
    public class AMAccountType
    {
        public byte Id { get; set; }
        public string Name { get; set; }
        public String Code { get; set; }
        public NormalBalance NormalBalance { get; set; }
        public String IsActive { get; set; }
        public String Description { get; set; }
        public FinancialStatementType StatementType { get; set; }
        public byte ReportingSequence { get; set; }
        public String HasTaxImplications { get; set; }

        public List<AMAccount> Accounts { get; set; }

        public AMAccountType() : this(0, String.Empty, String.Empty, NormalBalance.D, String.Empty, "N", String.Empty, FinancialStatementType.BalanceSheet, 0, "N")
        { }

        public AMAccountType(byte id, String name, String code, NormalBalance normalBalance, String category, String isActive, String description, FinancialStatementType statementType, byte reportingSequence, String hasTaxImplications)
        {
            Id = id;
            Name = name;
            Code = code;
            NormalBalance = normalBalance;
            Category = category;
            IsActive = isActive;
            Description = description;
            StatementType = statementType;
            ReportingSequence = reportingSequence;
            HasTaxImplications = hasTaxImplications;

            Accounts = new List<AMAccount>();
        }
    }
}

These models may change as we continue developing the application. I suspect we will find that additional fields may be needed as we start to create reports.

General Ledger Accounts

In double entry accounting, the general ledger records all financial transaction. The transactions are organized by general ledger account. This facilitates quick reconciliation of the accounts and eases reporting.

In this application, the general ledger account definitions will have the following fields:

Field NameData TypeNotes
IdlongIdentity
AccountNumberString10 characters
AccountNameString30 characters
AccountTypeIdbyte
AccountTypeString30 characters
HasSubaccountsString1 character
IsSubaccountString1 character
ParentAccountIdlongNullable
NormalBalanceNormalBalanceUse enumeration
IsActiveString1 character
IsPostingAccountString1 character
OpeningBalancedoubleCalculated
CurrentBalancedoubleCalculated
FiscalYearOpeningdoubleCalculated

No balances will be recorded in the database for the general ledger accounts. However, the balances defined above will be calculated for the view model.

The view model will look like:

namespace Accounting.Core.Models
{
    public class AccountVM
    {
        public long Id { get; set; }
        public String AccountNumber { get; set; }
        public String Name { get; set; }
        public AccountTypeVM AccountType { get; set; }
        public String HasSubAccounts { get; set; }
        public String IsSubAccount { get; set; }
        public AccountVM? ParentAccount { get; set; }
        public NormalBalance NormalBalance { get; set; }
        public String IsActive { get; set; }
        public String IsPostingAccount { get; set; }
        public double OpeningBalance { get; set; }
        public double CurrentBalance { get; set; }
        public double FiscalYearOpeningBalance { get; set; }

        public List<AccountVM> SubAccounts { get; set; }

        public String AccountTypeAsString
        {
            get
            {
                return AccountType.Name;
            }
        }

        public AccountVM() : this(0, String.Empty, String.Empty, new AccountTypeVM(), "N", "N", null, NormalBalance.D, "Y", "Y")
        { }

        public AccountVM(long id, String name, String accountNumber, AccountTypeVM accountType, String hasSubAccounts, String isSubAccount, AccountVM? parentAccount, NormalBalance normalBalance, String isActive, String isPostingAccount)
        {
            Id = id;
            Name = name;
            AccountNumber = accountNumber;
            AccountType = accountType;
            HasSubAccounts = hasSubAccounts;
            IsSubAccount = isSubAccount;
            ParentAccount = parentAccount;
            NormalBalance = normalBalance;
            IsActive = isActive;
            IsPostingAccount = isPostingAccount;

            OpeningBalance = 0.00; //To be calculated in a service
            CurrentBalance = 0.00; //To be calculated in a service
            FiscalYearOpeningBalance = 0.00; //To be calculated in a service

            SubAccounts = new List<AccountVM>();
        }
    }
}

The domain model looks like:

using Accounting.Core.Models;

namespace Accounting.Core.Domain
{
    public class AMAccount : IAuditable
    {
        public long Id { get; set; }
        public String Name { get; set; }
        public String AccountNumber { get; set; }
        public byte AccountTypeId { get; set; }
        public String HasSubAccounts { get; set; }
        public String IsSubAccount { get; set; }
        public long? ParentAccountId { get; set; }
        public NormalBalance NormalBalance { get; set; }
        public String IsActive { get; set; }
        public String IsPostingAccount { get; set; }
        public DateTime Created { get; set; }
        public DateTime Modified { get; set; }
        public string CreatedBy { get; set; }
        public string ModifiedBy { get; set; }

        public AMAccountType AccountType { get; set; }
        public AMAccount? ParentAccount { get; set; }
        public List<AMAccount> SubAccounts { get; set; }

        public AMAccount() : this(0, String.Empty, String.Empty, 0, "N", "N", null, NormalBalance.D, "Y", "Y")
        { }

        public AMAccount(long id, String name, String accountNumber, byte accountTypeId, String hasSubAccounts, String isSubAccount, long? parentAccountId, NormalBalance normalBalance, String isActive, String isPostingAccount)
        {
            Id = id;
            Name = name;
            AccountNumber = accountNumber;
            AccountTypeId = accountTypeId;
            HasSubAccounts = hasSubAccounts;
            IsSubAccount = isSubAccount;
            ParentAccountId = parentAccountId;
            NormalBalance = normalBalance;
            IsActive = isActive;
            IsPostingAccount = isPostingAccount;

            Created = DateTime.Now;
            Modified = DateTime.Now;
            CreatedBy = String.Empty;
            ModifiedBy = String.Empty;

            AccountType = new AMAccountType();
            SubAccounts = new List<AMAccount>();
        }
    }
}

While I haven’t covered a whole lot today, I’m going to call this a post. If you like where I’m going with this, please subscribe to the blog. You will get an email when I publish a post. Also, if you like a post I made, please click the “Like” button below.

I’ll see you next week.

Der alter Knacker!

Leave a comment