Reputation: 951
I am following the DDD approach for the accounting system I am developing.
There are two parts(see domain below):
This is how my domain looks like:
public class AccountingTransaction : AggregateRoot
{
public string AccountingTransactionId { get; private set; }
public TransactionStatus TransactionStatus { get; private set; } //enum
private List<CashTransaction> _cashTransactions = new List<CashTransaction>();
public IReadOnlyList<CashTransaction> CashTransactions => new ReadOnlyCollection<CashTransaction>(_cashTransactions);
private List<LedgerTransaction> _ledgerTransactions = new List<LedgerTransaction>();
public IReadOnlyList<LedgerTransaction> LedgerTransactions => new ReadOnlyCollection<LedgerTransaction>(_ledgerTransactions);
private AccountingTransaction(string transactionId, List<CashTransaction> cashTransactions, List<LedgerTransaction> ledgerTransactions, TransactionStatus transactionStatus)
{
//Code omitted for brevity
}
public static IResult<AccountingTransaction> CreateTransaction(string transactionId, List<CashTransaction> cashTransactions, List<LedgerTransaction> ledgerTransactions, List<ClientAccount> clientAccounts, List<Ledger> ledgerAccounts)
{
//Factory method
//Maintain invaraint and creates a new transaction
}
public IResult CancelTransaction(string username)
{
}
}
public class LedgerTransaction
{
public int Id { get; private set; }
public string LedgerAccountId { get; private set; }
public string TransactionId { get; private set; }
public string EntryDescription { get; private set; }
public DateTime? ReconciledOn { get; private set; }
public TransactionAmount TransactionAmount { get; private set; } //Value object
private LedgerTransaction(int id, TransactionAmount transactionAmount,
string transactionId,
string entryDescription,
string batchId,
string ledgerAccountId)
{
//Code omitted for brevity
}
internal static IResult<LedgerTransaction> CreateTransaction(/*List of arguments*/)
{
//Factory method
//Code omitted for brevity
}
}
public class CashTransaction
{
public int Id { get; private set; }
public string ClientAccountId { get; private set; }
public string TransactionId { get; private set; }
public TransactionAmount TransactionAmount { get; private set; }//Value object
public string EntryDescription { get; private set; }
private CashTransaction(int id,
TransactionAmount transactionAmount,
string transactionId,
string entryDescription,
string clientAccountId)
{
Id = id;
TransactionAmount = transactionAmount;
TransactionId = transactionId;
EntryDescription = entryDescription;
ClientAccountId = clientAccountId;
}
internal static IResult<CashTransaction> CreateTransaction(/*List of arguments*/)
{
//Factory method
//Code omitted for brevity
}
}
public class Ledger : AggregateRoot
{
public string AccountId { get; private set; }
public string Name { get; private set; }
public LedgerType LedgerType { get; set; }
public Currency Currency { get; private set; }
}
So the first part(create transaction) works pretty well, and I am stuck on how I should approach the Ledger accounts reconciliation.
Problem: To reconcile accounts, for a given day, I need to fetch all ledger transactions belonging to a particular Ledger where ReconciledOn(see domain class) is null. Then I need to make sure that all debits and credits sum is 0 - if not, I need to report the error. It is also possible that matching debit and credits belong to the different aggregate roots (AccountingTransaction). This also means I need to fetch Ledger transactions outside of the aggregate root(AccountingTransaction), which is against DDD, and then probably do a write operation directly on the LedgerTransactions table.
Please advise how should I approach this. Is there a flaw in the domain classes?
I appreciate your help.
Thank you!
Upvotes: 1
Views: 860
Reputation: 1660
The domain looks good at first glance. A couple of options here:
Fetch all AccountingTransaction
s that have unreconciled ledger transactions and pass them all to do the reconciliation service. This would require you to put some domain logic to the repository (the knowledge of what an unreconciled transaction is), but that should be fine.
Make LedgerTransaction
its own aggregate root.
Upvotes: 1
Reputation: 20541
That conflict suggests that LedgerTransaction wants to be an aggregate root.
Upvotes: 0