117 lines
5.0 KiB
C#
117 lines
5.0 KiB
C#
using General_Ledger_Service.DTOs.Reports;
|
|
using General_Ledger_Service.Infra;
|
|
using General_Ledger_Service.Interfaces.Repositories;
|
|
using General_Ledger_Service.Models;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace General_Ledger_Service.Repositories
|
|
{
|
|
public class JournalEntryRepository(AppDBContext context) : IJournalEntryRepository
|
|
{
|
|
private readonly AppDBContext _context = context;
|
|
|
|
public async Task<JournalEntry?> GetJournalEntryByJournalNoAsync(string journalNo) =>
|
|
await _context.JournalEntries
|
|
.Include(j => j.Lines)
|
|
.FirstOrDefaultAsync(j => j.JournalNo == journalNo);
|
|
|
|
public async Task<JournalEntry?> GetJournalEntryBySourceReferenceAsync(string sourceModule, string reference) =>
|
|
await _context.JournalEntries
|
|
.Include(j => j.Lines)
|
|
.FirstOrDefaultAsync(j => j.SourceModule == sourceModule && j.Reference == reference);
|
|
|
|
public async Task<int> CountJournalEntriesForYearAsync(int year) =>
|
|
await _context.JournalEntries.CountAsync(j => j.JournalNo.StartsWith($"JV-{year}-"));
|
|
|
|
public Task<JournalEntry> AddJournalEntryAsync(JournalEntry entry) =>
|
|
RepositoryHelpers.AddAsync(_context.JournalEntries, entry);
|
|
|
|
public async Task AddJournalEntryLinesAsync(IEnumerable<JournalEntryLine> lines) =>
|
|
await _context.JournalEntryLines.AddRangeAsync(lines);
|
|
|
|
public async Task<List<GeneralLedgerLineDto>> GetGeneralLedgerLinesAsync(long accountId, DateOnly periodStart, DateOnly periodEnd)
|
|
{
|
|
var treeRows = await _context.Accounts.AsNoTracking()
|
|
.Select(a => new RecursiveTreeQueries.TreeRow
|
|
{
|
|
Id = a.AccountId,
|
|
Code = a.AccountCode,
|
|
Name = a.AccountName,
|
|
ParentId = a.ParentAccountId
|
|
})
|
|
.ToListAsync();
|
|
var accountIds = RecursiveTreeQueries.GetDescendantIds(treeRows, accountId).ToList();
|
|
|
|
var lines = _context.JournalEntryLines
|
|
.Where(l => l.Journal.IsPosted
|
|
&& accountIds.Contains(l.AccountId)
|
|
&& l.Journal.EntryDate >= periodStart
|
|
&& l.Journal.EntryDate <= periodEnd);
|
|
|
|
return await BuildGeneralLedgerLinesAsync(lines);
|
|
}
|
|
|
|
public async Task<List<GeneralLedgerLineDto>> GetGeneralLedgerLinesForAllAccountsAsync(DateOnly periodStart, DateOnly periodEnd)
|
|
{
|
|
var lines = _context.JournalEntryLines
|
|
.Where(l => l.Journal.IsPosted
|
|
&& l.Account.IsPostable
|
|
&& l.Journal.EntryDate >= periodStart
|
|
&& l.Journal.EntryDate <= periodEnd);
|
|
|
|
return await BuildGeneralLedgerLinesAsync(lines);
|
|
}
|
|
|
|
// Orders by account code, then entry date/journal (the running balance restarts for each
|
|
// account and accumulates in that same date/journal order), then fetches the rows and
|
|
// computes the running balance in memory.
|
|
private static async Task<List<GeneralLedgerLineDto>> BuildGeneralLedgerLinesAsync(IQueryable<JournalEntryLine> lines)
|
|
{
|
|
var rows = await lines
|
|
.OrderBy(l => l.Account.AccountCode)
|
|
.ThenBy(l => l.Journal.EntryDate)
|
|
.ThenBy(l => l.JournalId)
|
|
.ThenBy(l => l.LineId)
|
|
.Select(l => new
|
|
{
|
|
l.AccountId,
|
|
l.Journal.EntryDate,
|
|
l.Journal.JournalNo,
|
|
l.Account.AccountCode,
|
|
l.Account.AccountName,
|
|
l.Journal.Narration,
|
|
l.DebitAmount,
|
|
l.CreditAmount
|
|
})
|
|
.ToListAsync();
|
|
|
|
var runningBalances = new Dictionary<long, decimal>();
|
|
var result = new List<GeneralLedgerLineDto>(rows.Count);
|
|
|
|
foreach (var row in rows)
|
|
{
|
|
runningBalances.TryGetValue(row.AccountId, out var previous);
|
|
var running = previous + row.DebitAmount - row.CreditAmount;
|
|
runningBalances[row.AccountId] = running;
|
|
|
|
result.Add(new GeneralLedgerLineDto
|
|
{
|
|
EntryDate = row.EntryDate,
|
|
JournalNo = row.JournalNo,
|
|
AccountCode = row.AccountCode,
|
|
AccountName = row.AccountName,
|
|
Narration = row.Narration,
|
|
DebitAmount = row.DebitAmount,
|
|
CreditAmount = row.CreditAmount,
|
|
RunningBalance = running
|
|
});
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public Task<JournalCorrection> AddJournalCorrectionAsync(JournalCorrection correction) =>
|
|
RepositoryHelpers.AddAsync(_context.JournalCorrections, correction);
|
|
}
|
|
}
|