first commit
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
using Fitness_core_BE.Interfaces;
|
||||
using Fitness_core_BE.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Fitness_core_BE.Repos
|
||||
{
|
||||
public class PlatformBillingRepository : IPlatformBillingRepository
|
||||
{
|
||||
// Platform billing is central-bucket (HexaFitness's own revenue relationship with
|
||||
// each gym); AccessDevices (used only to check device-billing eligibility) is tenant.
|
||||
private readonly CentralDbContext _context;
|
||||
private readonly TenantDbContext _tenant;
|
||||
|
||||
public PlatformBillingRepository(CentralDbContext context, TenantDbContext tenant)
|
||||
{
|
||||
_context = context;
|
||||
_tenant = tenant;
|
||||
}
|
||||
|
||||
public Task<List<ClientPackage>> GetPricingPlansAsync(CancellationToken ct = default)
|
||||
{
|
||||
return _context.ClientPackages
|
||||
.AsNoTracking()
|
||||
.OrderByDescending(package => package.IsDefault)
|
||||
.ThenBy(package => package.PackageName)
|
||||
.ToListAsync(ct);
|
||||
}
|
||||
|
||||
public async Task<ClientPackage?> GetPackageByIdAsync(
|
||||
Guid packageId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return await _context.ClientPackages.FindAsync(new object[] { packageId }, ct);
|
||||
}
|
||||
|
||||
public async Task AddPackageAsync(
|
||||
ClientPackage package,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
await _context.ClientPackages.AddAsync(package, ct);
|
||||
}
|
||||
|
||||
public Task<List<ClientPackage>> GetOtherDefaultPackagesAsync(
|
||||
Guid exceptPackageId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return _context.ClientPackages
|
||||
.Where(package =>
|
||||
package.IsDefault &&
|
||||
package.ClientPackageId != exceptPackageId)
|
||||
.ToListAsync(ct);
|
||||
}
|
||||
|
||||
public Task<ClientPackage?> GetDefaultPackageAsync(CancellationToken ct = default)
|
||||
{
|
||||
return _context.ClientPackages
|
||||
.FirstOrDefaultAsync(package => package.IsDefault, ct);
|
||||
}
|
||||
|
||||
public async Task<ClientPackage?> GetActivePackageForClientAsync(
|
||||
Guid clientId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return await _context.ClientSubscriptions
|
||||
.AsNoTracking()
|
||||
.Where(subscription =>
|
||||
subscription.FKClientId == clientId &&
|
||||
subscription.IsActive)
|
||||
.OrderByDescending(subscription => subscription.OnboardDate)
|
||||
.Select(subscription => subscription.ClientPackage)
|
||||
.FirstOrDefaultAsync(ct);
|
||||
}
|
||||
|
||||
public Task<Client?> GetClientByIdAsync(
|
||||
Guid clientId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return _context.Client
|
||||
.FirstOrDefaultAsync(client => client.ClientId == clientId, ct);
|
||||
}
|
||||
|
||||
public Task<List<ClientSubscription>> GetActiveClientSubscriptionsAsync(
|
||||
Guid clientId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return _context.ClientSubscriptions
|
||||
.Where(subscription =>
|
||||
subscription.FKClientId == clientId &&
|
||||
subscription.IsActive)
|
||||
.ToListAsync(ct);
|
||||
}
|
||||
|
||||
public Task<ClientSubscription?> GetActiveClientSubscriptionAsync(
|
||||
Guid clientId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return _context.ClientSubscriptions
|
||||
.Where(subscription =>
|
||||
subscription.FKClientId == clientId &&
|
||||
subscription.IsActive)
|
||||
.OrderByDescending(subscription => subscription.OnboardDate)
|
||||
.FirstOrDefaultAsync(ct);
|
||||
}
|
||||
|
||||
public async Task AddClientSubscriptionAsync(
|
||||
ClientSubscription subscription,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
await _context.ClientSubscriptions.AddAsync(subscription, ct);
|
||||
}
|
||||
|
||||
public Task<List<ClientDeviceBilling>> GetActiveDeviceBillingsAsync(
|
||||
Guid clientId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return _context.ClientDeviceBillings
|
||||
.Where(billing =>
|
||||
billing.FKClientId == clientId &&
|
||||
billing.IsActive)
|
||||
.ToListAsync(ct);
|
||||
}
|
||||
|
||||
public Task<ClientDeviceBilling?> GetLatestActiveDeviceBillingAsync(
|
||||
Guid clientId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return _context.ClientDeviceBillings
|
||||
.Where(billing =>
|
||||
billing.FKClientId == clientId &&
|
||||
billing.IsActive)
|
||||
.OrderByDescending(billing => billing.AssignedAt)
|
||||
.FirstOrDefaultAsync(ct);
|
||||
}
|
||||
|
||||
public async Task AddDeviceBillingAsync(
|
||||
ClientDeviceBilling billing,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
await _context.ClientDeviceBillings.AddAsync(billing, ct);
|
||||
}
|
||||
|
||||
public Task<bool> HasActiveDeviceAsync(
|
||||
Guid clientId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return _tenant.AccessDevices.AnyAsync(device =>
|
||||
device.FKClientId == clientId &&
|
||||
device.IsActive, ct);
|
||||
}
|
||||
|
||||
public Task<List<Guid>> GetMonthlyBillingCandidatesAsync(
|
||||
DateTime startOfMonth,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return _context.Client
|
||||
.AsNoTracking()
|
||||
.Where(client =>
|
||||
_context.ClientCard.Any(card =>
|
||||
card.FK_ClientId == client.ClientId) &&
|
||||
!_context.ClientInvoices.Any(invoice =>
|
||||
invoice.ClientSubscription.FKClientId == client.ClientId &&
|
||||
invoice.ClientInvoiceDate >= startOfMonth))
|
||||
.Select(client => client.ClientId)
|
||||
.ToListAsync(ct);
|
||||
}
|
||||
|
||||
public Task<List<ClientInvoice>> GetInvoicesByStatusAsync(
|
||||
string status,
|
||||
bool newestFirst,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
var query = _context.ClientInvoices
|
||||
.AsNoTracking()
|
||||
.Include(invoice => invoice.ClientSubscription)
|
||||
.ThenInclude(subscription => subscription.Client)
|
||||
.ThenInclude(client => client.ClientBusinesses)
|
||||
.Where(invoice =>
|
||||
status == "Outstanding"
|
||||
? invoice.Status == "Pending" || invoice.Status == "Partial"
|
||||
: invoice.Status == status);
|
||||
|
||||
query = newestFirst
|
||||
? query.OrderByDescending(invoice => invoice.ClientInvoiceDate)
|
||||
: query.OrderBy(invoice => invoice.ClientInvoiceDate);
|
||||
|
||||
return query.ToListAsync(ct);
|
||||
}
|
||||
|
||||
public Task<ClientInvoice?> GetInvoiceWithClientAsync(
|
||||
Guid invoiceId,
|
||||
bool includeBusinesses,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
var query = _context.ClientInvoices
|
||||
.Include(invoice => invoice.ClientSubscription)
|
||||
.ThenInclude(subscription => subscription.Client)
|
||||
.AsQueryable();
|
||||
|
||||
if (includeBusinesses)
|
||||
{
|
||||
query = query.Include(invoice =>
|
||||
invoice.ClientSubscription.Client.ClientBusinesses);
|
||||
}
|
||||
|
||||
return query.FirstOrDefaultAsync(
|
||||
invoice => invoice.ClientInvoiceId == invoiceId, ct);
|
||||
}
|
||||
|
||||
public Task<ClientCard?> GetClientCardAsync(
|
||||
Guid clientId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
// The card billing charges: the active card marked primary. CardToken != null
|
||||
// excludes legacy rows created by ActivationService.ChargeAndActivateAsync before
|
||||
// real card onboarding existed — those were never confirmed by Payment-Service and
|
||||
// can't actually be charged, so they must never outrank (or stand in for) a real card.
|
||||
return _context.ClientCard
|
||||
.Where(card => card.FK_ClientId == clientId && card.IsActive && card.CardToken != null)
|
||||
.OrderByDescending(card => card.IsPrimary)
|
||||
.FirstOrDefaultAsync(ct);
|
||||
}
|
||||
|
||||
public Task<List<ClientCard>> GetClientCardsAsync(
|
||||
Guid clientId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return _context.ClientCard
|
||||
.Where(card => card.FK_ClientId == clientId && card.IsActive && card.CardToken != null)
|
||||
.OrderByDescending(card => card.IsPrimary)
|
||||
.ToListAsync(ct);
|
||||
}
|
||||
|
||||
public Task<ClientCard?> GetClientCardByTokenAsync(
|
||||
Guid clientId,
|
||||
string cardToken,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return _context.ClientCard
|
||||
.FirstOrDefaultAsync(card => card.FK_ClientId == clientId && card.CardToken == cardToken, ct);
|
||||
}
|
||||
|
||||
public async Task AddInvoiceAsync(
|
||||
ClientInvoice invoice,
|
||||
IReadOnlyCollection<ClientInvoiceItem> items,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
await _context.ClientInvoices.AddAsync(invoice, ct);
|
||||
await _context.ClientInvoiceItems.AddRangeAsync(items, ct);
|
||||
}
|
||||
|
||||
public Task<DevicePricingConfig?> GetDevicePricingConfigAsync(
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return _context.DevicePricingConfigs.FirstOrDefaultAsync(ct);
|
||||
}
|
||||
|
||||
public async Task AddDevicePricingConfigAsync(
|
||||
DevicePricingConfig config,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
await _context.DevicePricingConfigs.AddAsync(config, ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user