Files
Core_Be/Repos/ProfitLossRepository.cs
T
HarithaRandunu 51f0021e27 feat: Enhance booking functionality with invoice management and dashboard summary
- Added customerId to guest booking requests for better identification.
- Implemented new endpoints for managing booking invoices and dashboard summaries.
- Created BookingInvoice and BookingDashboardSummary DTOs to support new features.
- Updated Booking and BookingInvoice models to include payment method and timestamps.
- Enhanced BookingService to handle invoice creation upon payment confirmation.
- Modified BookingRepository to support CRUD operations for BookingInvoice.
- Updated TenantDbContext to include BookingInvoice DbSet and relevant configurations.
- Improved error handling and validation for booking completion and payment processes.
2026-10-01 03:46:03 +05:30

149 lines
5.7 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);
// Paid facility bookings (guest/walk-in) -- a plain Booking read, not a
// PaymentTransaction, since Booking has no invoice at all (see BookingInvoice, kept
// deliberately separate from CustomerInvoice/PaymentTransaction's membership-only
// wiring). PaidAt is the recognition date, not BookedAt/CheckedOutAt.
var bookingPayments = await _context.Bookings
.AsNoTracking()
.Where(booking =>
booking.FKClientId == clientId &&
booking.PaymentStatus == "Paid" &&
booking.PaidAt != null &&
booking.PaidAt >= fromUtc &&
booking.PaidAt < toUtc)
.Select(booking => new LedgerEntryDto
{
EntryType = "Income",
Category = "Facility Bookings",
Description = booking.GuestName,
Amount = booking.AmountCharged,
EntryDate = booking.PaidAt!.Value,
IsManual = false
})
.ToListAsync(ct);
memberPayments.AddRange(platformInvoices);
memberPayments.AddRange(staffPayments);
memberPayments.AddRange(bookingPayments);
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);
}
}
}