125 lines
4.5 KiB
C#
125 lines
4.5 KiB
C#
using Fitness_core_BE.DTOs.Ledger;
|
|
using Fitness_core_BE.Interfaces;
|
|
using Fitness_core_BE.Models;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace Fitness_core_BE.Repos
|
|
{
|
|
public class ProfitLossRepository : IProfitLossRepository
|
|
{
|
|
// Every method here is already scoped to a single caller-owned clientId (resolved
|
|
// from the ambient tenant), so no cross-tenant fan-out is needed. PaymentTransactions
|
|
// (member-payment rows), StaffPayments and LedgerEntries are tenant-bucket;
|
|
// ClientInvoices (platform billing) is central.
|
|
private readonly TenantDbContext _context;
|
|
private readonly CentralDbContext _central;
|
|
|
|
public ProfitLossRepository(TenantDbContext context, CentralDbContext central)
|
|
{
|
|
_context = context;
|
|
_central = central;
|
|
}
|
|
|
|
public async Task<List<LedgerEntryDto>> GetDerivedEntriesAsync(
|
|
Guid clientId,
|
|
DateTime fromUtc,
|
|
DateTime toUtc,
|
|
CancellationToken ct = default)
|
|
{
|
|
var memberPayments = await _context.PaymentTransactions
|
|
.AsNoTracking()
|
|
.Where(payment =>
|
|
payment.FK_ClientId == clientId &&
|
|
payment.FK_CustomerInvoiceId != null &&
|
|
payment.IsApproved == true &&
|
|
payment.IsActive == true &&
|
|
payment.PayDate != null &&
|
|
payment.PayDate >= fromUtc &&
|
|
payment.PayDate < toUtc)
|
|
.Select(payment => new LedgerEntryDto
|
|
{
|
|
EntryType = "Income",
|
|
Category = "Member Payments",
|
|
Description = payment.PayNote,
|
|
Amount = payment.PayAmount,
|
|
EntryDate = payment.PayDate!.Value,
|
|
IsManual = false
|
|
})
|
|
.ToListAsync(ct);
|
|
|
|
var platformInvoices = await _central.ClientInvoices
|
|
.AsNoTracking()
|
|
.Where(invoice =>
|
|
invoice.ClientSubscription.FKClientId == clientId &&
|
|
invoice.PaidAmount > 0 &&
|
|
invoice.ClientInvoiceDate >= fromUtc &&
|
|
invoice.ClientInvoiceDate < toUtc)
|
|
.Select(invoice => new LedgerEntryDto
|
|
{
|
|
EntryType = "Expense",
|
|
Category = "Platform Fees",
|
|
Description = "HexaFitness platform invoice",
|
|
Amount = invoice.PaidAmount,
|
|
EntryDate = invoice.ClientInvoiceDate,
|
|
IsManual = false
|
|
})
|
|
.ToListAsync(ct);
|
|
|
|
var staffPayments = await _context.StaffPayments
|
|
.AsNoTracking()
|
|
.Where(payment =>
|
|
payment.Staff.FKClientId == clientId &&
|
|
payment.PaidAt >= fromUtc &&
|
|
payment.PaidAt < toUtc)
|
|
.Select(payment => new LedgerEntryDto
|
|
{
|
|
EntryType = "Expense",
|
|
Category = "Staff Payroll",
|
|
Description = payment.Note,
|
|
Amount = payment.Amount,
|
|
EntryDate = payment.PaidAt,
|
|
IsManual = false
|
|
})
|
|
.ToListAsync(ct);
|
|
|
|
memberPayments.AddRange(platformInvoices);
|
|
memberPayments.AddRange(staffPayments);
|
|
return memberPayments;
|
|
}
|
|
|
|
public Task<List<LedgerEntry>> GetManualEntriesAsync(
|
|
Guid clientId,
|
|
DateTime fromUtc,
|
|
DateTime toUtc,
|
|
CancellationToken ct = default)
|
|
{
|
|
return _context.LedgerEntries
|
|
.AsNoTracking()
|
|
.Where(entry =>
|
|
entry.FKClientId == clientId &&
|
|
entry.EntryDate >= fromUtc &&
|
|
entry.EntryDate < toUtc)
|
|
.ToListAsync(ct);
|
|
}
|
|
|
|
public Task<LedgerEntry?> GetManualEntryByIdAsync(
|
|
Guid id,
|
|
CancellationToken ct = default)
|
|
{
|
|
return _context.LedgerEntries.FirstOrDefaultAsync(entry => entry.Id == id, ct);
|
|
}
|
|
|
|
public async Task AddManualEntryAsync(
|
|
LedgerEntry entry,
|
|
CancellationToken ct = default)
|
|
{
|
|
await _context.LedgerEntries.AddAsync(entry, ct);
|
|
}
|
|
|
|
public void RemoveManualEntry(LedgerEntry entry)
|
|
{
|
|
_context.LedgerEntries.Remove(entry);
|
|
}
|
|
}
|
|
}
|