The first part of the accounting application to be designed is the Account Management module. This module allows the users to establish general ledger accounts for documenting and recording all an organization’s financial transactions. This module will be rather straight forward. We won’t be adding security until a later series of posts.
That said, we will design this module to make implementing the security easier.
User Stories
For this module, we will implement the following user stories.
- As an application user, I need to add an account type so that I can categorize general ledger accounts.
- As an application user, I need to review the settings for an account type so that I can ensure that the information is correct.
- As an application user, I need to edit account types so that I can ensure that the information is correct.
- As a system, I need to ensure that there are no general ledger accounts associated with an account type so that I can protect data integrity.
- As an application user, I need to mark an account type as inactive so that no new general ledger accounts can be assigned that account type.
- As a system, I need to mark all general ledger accounts and associated subaccounts inactive when the parent account type is marked as inactive so that no new financial transactions can be recorded against an account type that is no longer used.
- As an application user, I need to delete an account type so that I can properly maintain the chart of accounts.
- As an application user, I need to add general ledger accounts to the system so that I can properly maintain the chart of accounts.
- As an application user, I need to display general ledger account information so that I can review the information for correctness.
- As an application user, I need to edit general ledger accounts so that I can ensure that the information is correct.
- As a system, I need to ensure that there are no transactions associated with a general ledger account so that I can protect data integrity.
- As an application user, I need to be able to mark a general ledger account as inactive so that no new financial transactions can be recorded against accounts that are no longer used.
- As a system, I need to mark associated subaccounts inactive when a general ledger account is marked inactive so that financial transactions are no longer recorded against subaccounts that are no longer used.
- As an application user, I need to delete a general ledger account so that I can properly maintain the chart of accounts.
- As an application user, I need to flag top-level general ledger accounts to have subaccounts so that I can create properly maintain the chart of accounts with subaccounts.
- As an application user, I need to add subaccounts to a general ledger account so that I can properly maintain the chart of accounts.
I’m going to pause listing the user stories for a bit. I can hear some of you saying, “Whoa! What are these subaccounts?” In a general ledger, some accounts need to have subaccounts, or accounts that can be used to further detail the purpose of the financial transactions.
A good example of this would be a fraternal organization’s “community projects” general ledger account. Subaccounts would be established to better track donations and what was spent on veteran’s projects versus children’s projects versus fraternal activities. An organization could even have separate sub-accounts for each activity.
Now, back to the user stories.
- As an application user, I need to display subaccount information so that I can review the information for correctness.
- As an application user, I need to edit subaccounts so that I can ensure that the information is correct.
- As a system, I need to ensure that there are no transactions associated with a subaccount so that I can protect data integrity.
- As an application user, I need to mark a subaccount inactive so that no new financial transactions can be recorded against subaccounts that are no longer used.
- As an application user, I need to delete a subaccount so that I can properly maintain the chart of accounts.
One thing to notices is that all of these user stories follow the four basic operations of persistent storage, Create – Retrieve – Update – Disable/Delete, also knows by the acronym CRUD. Normally, the “D” in CRUD just means Delete. However, data integrity requires that sometimes a database record needs to be disabled (marked inactive) instead of deleted. Because of that, the user stories reflect both.
Entity Design
To persist and alter the data, this application will use two tiers of entity models, domain models and view models. The domain models will be used by the database system for retrieving and writing the data. They, along with configuration models, etc., tell the object-relational model system (ORM) how the data is structured and related to other data.
In the case of this application, Entity Framework is the ORM that will be used. The programming language will be C# and the integrated development environment will be Visual Studio Community. However, this design could easily be implemented in nearly any other language/ORM combination.
Additional view models not used for persistence will also be created. These models are used for controlling the display of certain user interface elements as well as other purposes.
Database Organization
Before actually discussing the entities used for the application, I want to discuss how the database objects will be organized. Because other potential, target databases, such as MariaDB and Oracle, do not support schemas for organization, all tables will target the default schema in the example target database, Microsoft SQL Server Express. Instead of using schemas to organize the tables, database views, and other objects, this application will use a set of module prefixes for the table and view names, “AM” in the case of this module, Account Management. This will allow a small amount of organization of the database objects.
Utility Models
Before starting on the actual models needed to persist and display the account information, let’s discuss a few utility models we’ll need. The first is a pair of models we’ll use on all views with select boxes, to populate those. We’ll call the primary model SelectInformation. There will also be an additional model, SelectOption, with all of the information needed for the Option tag. This model will also be used for the retrieving data for automatic completion calls. By designing these models properly up front, we can use this model for both static select boxes and those using an automatic completion function.
The other model mentioned will actually be an interface instead of a traditional model class. The interface will be used by the system to add some basic audit information to each row in a data set as it is added to the database or u. We will take advantage of Entity Framework to populate these fields once we get to that part of the project. We’ll call this interface IAuditable.
SelectInformation and SelectOption models
These two models will be used to populate Select boxes in the user interface with a helper class extending the Html helper C# class. We’re designing it now because it will be used by the view model for the general ledger accounts.
Looking at the w3 school site for the HTML Select tag, we see that there are a few attributes that should be added, a list of options, and a label associated with the Select. The attributes are autofocus, disabled, form, id, multiple, name, required, and size. Additionally, we will add a style and a class attribute to the SelectInformation model to allow the form to be styled. We will also add a List of option models. The Option tag models will have the attributes disabled, label, selected, and value.
The actual models should look like:
namespace Accounting.Core
{
public class SelectOption
{
public String Text { get; set; } // Option text
public bool Disabled { get; set; } // Option is disabled
public String Label { get; set; } // Option shortened label
public bool Selected { get; set; } // Option is selected
public String Value { get; set; } // Option value on submit
public SelectOption() : this(String.Empty, false, String.Empty, false, String.Empty)
{ }
public SelectOption(String text, bool selected, String value) : this(text, false, String.Empty, selected, value)
{ }
public SelectOption(String text, bool disabled, String label, bool selected, String value)
{
Text = text;
Disabled = disabled;
Label = label;
Selected = selected;
Value = value;
}
}
}
namespace Accounting.Core
{
public class SelectInformation
{
public bool AutoFocus { get; set; }
public bool Disabled { get; set; }
public String Form { get; set; }
public String Id { get; set; }
public bool Multiple { get; set; }
public String Name { get; set; }
public bool Required { get; set; }
public int Size { get; set; }
public String Label { get; set; }
public String Class { get; set; }
public String Style { get; set; }
public List<SelectOption> Options { get; set; }
public String SizeAsString
{
get
{
return Size.ToString();
}
}
public SelectInformation(bool autofocus, bool disabled, String form, String id, bool multiple, String name, bool required, int size, String label, List<SelectOption> options)
{
AutoFocus = autofocus;
Disabled = disabled;
Form = form;
Id = id;
Multiple = multiple;
Name = name;
Required = required;
Size = size;
Label = label;
Class = String.Empty;
Style = String.Empty;
Options = options;
}
public SelectInformation(bool disabled, String id, bool multiple, String name, bool required, int size, String label) : this(false, disabled, String.Empty, id, multiple, name, required, size, label, new List<SelectOption>())
{ }
public SelectInformation(String id, String name, bool required, String label) : this(false, false, String.Empty, id, false, name, required, -1, label, new List<SelectOption>())
{ }
}
}
IAuditable Interface
This interface will be used to add basic audit information to domain classes. These fields will be Created, Modified, CreatedBy, and ModifiedBy. This will be the date and time when the record was created and most recently modified and the account name of the user who did either. We will extend the Entity Framework SaveChanges function to populate these fields.
The interface should look like this:
namespace Accounting.Core
{
public interface IAuditable
{
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
public String CreatedBy { get; set; }
public String ModifiedBy { get; set; }
}
}
I’m going to end this post here. We will pick up on the Domain and View models for the General Ledger accounts next week. We might also get into scaffolding the first controller and associated service or services next week. After that, I’ll create the database and hook the application to it.
I’ll see you next week!
Der alter Knacker!