first commit

This commit is contained in:
Dhananjaya99
2026-09-28 11:44:26 +05:30
parent 721743ae6b
commit bffc9b1686
424 changed files with 46474 additions and 0 deletions
+161
View File
@@ -0,0 +1,161 @@
using Fitness_core_BE.DTOs.Ledger;
using Fitness_core_BE.Exceptions;
using Fitness_core_BE.Helpers;
using Fitness_core_BE.Infra.UoW;
using Fitness_core_BE.Interfaces;
using Fitness_core_BE.Interfaces.Services;
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Services
{
public class ProfitLossService : IProfitLossService
{
private readonly IProfitLossRepository _repository;
private readonly UserRoleHelper _userRoleHelper;
private readonly IUnitOfWork _uow;
public ProfitLossService(
IProfitLossRepository repository,
UserRoleHelper userRoleHelper,
IUnitOfWork uow)
{
_repository = repository;
_userRoleHelper = userRoleHelper;
_uow = uow;
}
public async Task<ProfitLossDto> GetProfitLossAsync(DateTime from, DateTime to, HttpContext httpContext)
{
var clientId = await GetClientIdAsync(httpContext);
var (fromUtc, toUtc) = NormalizeRange(from, to);
var entries = await _repository.GetDerivedEntriesAsync(
clientId, fromUtc, toUtc);
// Manual entries.
var manualEntries = await GetManualEntriesRawAsync(clientId, fromUtc, toUtc);
entries.AddRange(manualEntries.Select(ToDto));
var totalIncome = entries.Where(e => e.EntryType == "Income").Sum(e => e.Amount);
var totalExpense = entries.Where(e => e.EntryType == "Expense").Sum(e => e.Amount);
return new ProfitLossDto
{
From = fromUtc,
To = toUtc,
TotalIncome = totalIncome,
TotalExpense = totalExpense,
NetProfit = totalIncome - totalExpense,
IncomeByCategory = entries.Where(e => e.EntryType == "Income")
.GroupBy(e => e.Category)
.Select(g => new CategoryTotalDto { Category = g.Key, Amount = g.Sum(e => e.Amount) })
.OrderByDescending(c => c.Amount)
.ToList(),
ExpenseByCategory = entries.Where(e => e.EntryType == "Expense")
.GroupBy(e => e.Category)
.Select(g => new CategoryTotalDto { Category = g.Key, Amount = g.Sum(e => e.Amount) })
.OrderByDescending(c => c.Amount)
.ToList(),
Entries = entries.OrderByDescending(e => e.EntryDate).ToList()
};
}
public async Task<List<LedgerEntryDto>> GetManualEntriesAsync(DateTime from, DateTime to, HttpContext httpContext)
{
var clientId = await GetClientIdAsync(httpContext);
var (fromUtc, toUtc) = NormalizeRange(from, to);
var entries = await GetManualEntriesRawAsync(clientId, fromUtc, toUtc);
return entries.Select(ToDto).OrderByDescending(e => e.EntryDate).ToList();
}
public async Task<LedgerEntryDto> AddManualEntryAsync(AddLedgerEntryRequest request, HttpContext httpContext)
{
var clientId = await GetClientIdAsync(httpContext);
if (request.EntryType != "Income" && request.EntryType != "Expense")
throw new ArgumentException("entryType must be 'Income' or 'Expense'.");
if (string.IsNullOrWhiteSpace(request.Category))
throw new ArgumentException("category is required.");
if (request.Amount <= 0)
throw new ArgumentException("amount must be greater than zero.");
await _uow.BeginAsync();
try
{
var entry = new LedgerEntry
{
Id = Guid.NewGuid(),
FKClientId = clientId,
EntryType = request.EntryType,
Category = request.Category,
Description = request.Description,
Amount = request.Amount,
EntryDate = request.EntryDate ?? DateTime.UtcNow,
CreatedAt = DateTime.UtcNow
};
await _repository.AddManualEntryAsync(entry);
await _uow.CommitAsync();
return ToDto(entry);
}
catch
{
await _uow.RollbackAsync();
throw;
}
}
public async Task DeleteManualEntryAsync(Guid id, HttpContext httpContext)
{
var clientId = await GetClientIdAsync(httpContext);
var entry = await _repository.GetManualEntryByIdAsync(id)
?? throw new NotFoundException("Ledger entry not found.");
if (entry.FKClientId != clientId)
throw new ForbiddenException("This ledger entry does not belong to your gym.");
await _uow.BeginAsync();
try
{
_repository.RemoveManualEntry(entry);
await _uow.CommitAsync();
}
catch
{
await _uow.RollbackAsync();
throw;
}
}
private async Task<List<LedgerEntry>> GetManualEntriesRawAsync(Guid clientId, DateTime fromUtc, DateTime toUtc)
{
return await _repository.GetManualEntriesAsync(clientId, fromUtc, toUtc);
}
private async Task<Guid> GetClientIdAsync(HttpContext httpContext)
{
var userId = DataExtractor.GetUserIdFromContext(httpContext);
return await _userRoleHelper.GetClientId(userId);
}
private static (DateTime From, DateTime To) NormalizeRange(DateTime from, DateTime to)
{
var fromUtc = DateTime.SpecifyKind(from.Date, DateTimeKind.Utc);
// Treat `to` as inclusive of the whole day.
var toUtc = DateTime.SpecifyKind(to.Date.AddDays(1), DateTimeKind.Utc);
return (fromUtc, toUtc);
}
private static LedgerEntryDto ToDto(LedgerEntry entry) => new()
{
Id = entry.Id,
EntryType = entry.EntryType,
Category = entry.Category,
Description = entry.Description,
Amount = entry.Amount,
EntryDate = entry.EntryDate,
IsManual = true
};
}
}