私が開発している会計システムの DDD アプローチに従っています。
2 つの部分があります (以下のドメインを参照)。
- トランザクションの作成: トランザクション (AccountingTransaction) は、現金が元帳からクライアントのアカウントに、またはその逆に、またはある元帳から別の元帳に移動されるときに、親 (集約ルート) として作成されます。つまり、Transaction(AccountingTransaction) は複数の LedgerTransaction または CashTransaction を持つことができます。
- アカウントの照合 : 各元帳の貸方と借方を毎日照合する必要があります。
これは私のドメインがどのように見えるかです:
- AccountingTransaction は集約ルートです。
- LedgerTransaction と CashTransaction は、AccountingTransaction の子エンティティです。
- AccountingTransaction には、CashTransactions と LedgerTransactions のリストがあります。
- Ledger は集約ルートです。
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; }
}
したがって、最初の部分 (トランザクションの作成) は非常にうまく機能し、元帳勘定の調整にどのようにアプローチするべきかについて悩んでいます。
問題:アカウントを調整するには、特定の日に、ReconciledOn (ドメイン クラスを参照) が null である特定の Ledger に属するすべての Ledger トランザクションを取得する必要があります。次に、すべての借方と貸方の合計が 0 であることを確認する必要があります。そうでない場合は、エラーを報告する必要があります。一致する借方と貸方が異なる集約ルート (AccountingTransaction) に属することも可能です。これは、集約ルート (AccountingTransaction) の外で Ledger トランザクションを取得する必要があることも意味します。これは DDD に反しており、おそらく LedgerTransactions テーブルに対して直接書き込み操作を実行します。
これにどのようにアプローチすればよいかアドバイスしてください。ドメインクラスに欠陥はありますか?
私はあなたの助けに感謝します。
ありがとうございました!