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
+103
View File
@@ -0,0 +1,103 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IAccessDeviceRepo
{
Task<object> AddDeviceAsync(AccessDevice device);
Task<AccessDevice> RemoveDeviceAsync(Guid clientId);
Task<AccessDevice> GetDeviceByDId(Guid deviceId);
Task<AccessDevice?> GetDeviceByIdAsync(Guid deviceId, CancellationToken ct = default);
Task<AccessDevice?> GetDeviceByHardwareIdAsync(
Guid clientId,
string hardwareId,
CancellationToken ct = default);
Task<AccessDevice?> GetActiveDeviceForClientAsync(
Guid clientId,
Guid deviceId,
CancellationToken ct = default);
Task<List<AccessDevice>> GetAgentDevicesAsync(
Guid clientId,
Guid agentId,
IReadOnlyCollection<Guid> deviceIds,
CancellationToken ct = default);
Task<AccessDevice> GetDeviceByCId(Guid clientId);
Task<CustomerAccess> AddCustomerAccessAsync(CustomerAccess customerAccess);
Task<CustomerAccess> GetByIdAsync(int deviceUserId);
Task<CustomerAccess?> GetByDeviceAndUserIdAsync(Guid deviceId, int deviceUserId);
Task<CustomerAccess> GetByCusGuidAsync(Guid CusId);
Task<CustomerAccess> UpdateAsync(CustomerAccess customerAccess);
Task<List<AccessDevice>> GetDevicesByClientAsync(Guid clientId);
Task<bool> DeviceBelongsToClientAsync(Guid deviceId, Guid clientId);
Task<Customer?> GetCustomerByIdAsync(Guid customerId, CancellationToken ct = default);
Task<Staff?> GetStaffByIdAsync(Guid clientId, Guid staffId, CancellationToken ct = default);
/// <summary>
/// The other active customers sharing this customer's active group/couple
/// subscriptions at this gym (excludes the customer themselves). Empty for an
/// Individual plan, so callers can cascade unconditionally.
/// </summary>
Task<List<Guid>> GetCoMembersOnSharedSubscriptionsAsync(
Guid clientId,
Guid customerId,
CancellationToken ct = default);
Task<bool> IsActiveCustomerMemberAsync(
Guid clientId,
Guid customerId,
CancellationToken ct = default);
Task<Guid?> GetLatestActiveClientIdForCustomerAsync(
Guid customerId,
CancellationToken ct = default);
Task<AccessProfile?> GetAccessProfileAsync(
Guid clientId,
Guid userId,
CancellationToken ct = default);
Task<AccessProfile?> GetAccessStatusProfileAsync(
Guid clientId,
Guid userId,
CancellationToken ct = default);
Task<List<AccessProfile>> GetAccessProfilesByClientAsync(
Guid clientId,
CancellationToken ct = default);
Task AddAccessProfileAsync(AccessProfile profile, CancellationToken ct = default);
Task<AccessDeviceBinding?> GetBindingAsync(
long accessProfileId,
Guid deviceId,
CancellationToken ct = default);
Task<AccessDeviceBinding?> GetBindingByEmployeeNoAsync(
Guid deviceId,
string employeeNo,
CancellationToken ct = default);
Task<List<AccessDeviceBinding>> GetBindingsForDeviceAsync(
Guid deviceId,
CancellationToken ct = default);
Task AddBindingAsync(AccessDeviceBinding binding, CancellationToken ct = default);
Task<bool> IsDeviceEmployeeNoOccupiedAsync(
Guid deviceId,
string employeeNo,
Guid exceptUserId,
CancellationToken ct = default);
Task<List<UnlinkedDeviceEnrollment>> GetDuplicateUnlinkedEnrollmentsAsync(
Guid deviceId,
string employeeNo,
int deviceUserId,
CancellationToken ct = default);
Task<UnlinkedDeviceEnrollment?> GetUnlinkedEnrollmentByEmployeeNoAsync(
Guid deviceId,
string employeeNo,
CancellationToken ct = default);
Task AddUnlinkedEnrollmentAsync(
UnlinkedDeviceEnrollment enrollment,
CancellationToken ct = default);
Task<Guid?> GetCustomerIdForUserAtClientAsync(
Guid userId,
Guid clientId,
CancellationToken ct = default);
Task<bool> IsDeviceCommandableAsync(Guid deviceId, CancellationToken ct = default);
// Fingerprint-enrolled-directly-on-device reconciliation (req 3).
Task UpsertUnlinkedEnrollmentAsync(Guid deviceId, int deviceUserId, string? reportedName);
Task<List<UnlinkedDeviceEnrollment>> GetUnlinkedEnrollmentsByClientAsync(Guid clientId);
Task<UnlinkedDeviceEnrollment?> GetUnlinkedEnrollmentByIdAsync(Guid id);
Task<bool> CustomerAccessIdExistsAsync(int id);
}
}
+15
View File
@@ -0,0 +1,15 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IActivityLogRepository
{
Task AddActivityLogAsync(ActivityLog log, CancellationToken ct = default);
Task<List<ActivityLog>> GetActivityLogsAsync(
string searchTerm = null,
DateTime? startDate = null,
DateTime? endDate = null,
CancellationToken ct = default);
Task<string> GetUserNameAsync(Guid userId, CancellationToken ct = default);
}
}
@@ -0,0 +1,11 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IAdminClientDirectoryRepository
{
Task<(List<Client> Items, int Total)> ListAsync(string? search, int page, int pageSize, CancellationToken ct = default);
Task<Client?> GetByIdAsync(Guid clientId, CancellationToken ct = default);
Task<bool> ClientExistsAsync(Guid clientId, CancellationToken ct = default);
}
}
+15
View File
@@ -0,0 +1,15 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IAdminSuggestionRepository
{
Task<(List<WorkoutPlan> Workouts, List<MealPlan> Meals)> GetPublishedAsync(CancellationToken ct = default);
Task<WorkoutCategory?> FindWorkoutCategoryAsync(string name, CancellationToken ct = default);
Task<MealCategory?> FindMealCategoryAsync(string name, CancellationToken ct = default);
Task AddWorkoutCategoryAsync(WorkoutCategory category, CancellationToken ct = default);
Task AddMealCategoryAsync(MealCategory category, CancellationToken ct = default);
Task AddWorkoutAsync(WorkoutPlan plan, CancellationToken ct = default);
Task AddMealAsync(MealPlan plan, CancellationToken ct = default);
}
}
+13
View File
@@ -0,0 +1,13 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IAgentRepo
{
Task<Agent> AddAsync(Agent agent);
Task<Agent?> GetByApiKeyHashAsync(string apiKeyHash);
Task<Agent?> GetByIdAsync(Guid agentId);
Task<List<Agent>> GetByClientIdAsync(Guid clientId);
Task UpdateLastSeenAsync(Guid agentId, DateTime seenAt);
}
}
+18
View File
@@ -0,0 +1,18 @@
using Fitness_core_BE.DTOs.Attendance;
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IAttendanceRepository
{
Task<Attendance?> GetLatestAttendanceAsync(Guid clientId);
Task<HashSet<string>> GetAttendanceKeysAsync(Guid clientId, DateTime fromTime);
Task<HashSet<string>> GetSourceEventKeysAsync(
IReadOnlyCollection<string> candidateKeys,
CancellationToken ct = default);
Task AddAttendancesAsync(IEnumerable<Attendance> attendances);
Task<List<Attendance>> GetLatestPerPersonAsync(Guid clientId);
Task<List<AttendanceCountDTO>> GetAttendanceCountsAsync(Guid clientId, DateTime fromDate, DateTime toDate);
Task<List<TodayAttendanceDTO>> GetTodayAttendanceAsync(Guid clientId);
}
}
+17
View File
@@ -0,0 +1,17 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IBookingRepository
{
Task<Booking> CreateBooking(Booking booking);
Task<Booking?> GetBookingById(Guid bookingId);
// "Confirmed" only -- an OTP that's already been used/cancelled shouldn't check anyone in.
Task<Booking?> GetActiveBookingByOtp(string otpCode);
Task<List<Booking>> GetBookingsForSession(Guid facilitySessionId);
Task<List<Booking>> GetBookingsForCustomer(Guid customerId);
Task<bool> CustomerHasActiveBookingForSession(Guid facilitySessionId, Guid customerId);
}
}
+14
View File
@@ -0,0 +1,14 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IChatRepo
{
Task<Chat?> GetChatByIdAsync(Guid chatId);
Task<Chat?> GetChatBetweenUsersAsync(Guid userAId, Guid userBId);
Task CreateChatAsync(Chat chat);
Task AddMessageAsync(ChatMessages message);
Task<List<ChatMessages>> GetMessagesAsync(Guid chatId, int skip, int take);
Task<bool> IsUserInChatAsync(Guid chatId, Guid userId);
}
}
+13
View File
@@ -0,0 +1,13 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IClientInvoiceRepository
{
Task<ClientInvoice> CreateClientInvoiceFromSubscription(Guid subscriptionId);
Task<ClientInvoice?> GetClientInvoiceById(Guid clientInvoiceId);
Task<List<ClientInvoice>> GetClientInvoicesByClientId(Guid clientId);
Task<List<ClientInvoice>> GetClientInvoicesByUserId(Guid userId);
Task<ClientInvoice> UpdateClientInvoiceStatus(Guid clientInvoiceId, string status);
}
}
+70
View File
@@ -0,0 +1,70 @@
using Fitness_core_BE.Domain;
using Fitness_core_BE.DTOs.Customer;
using Fitness_core_BE.DTOs.CustomerPlan;
using Fitness_core_BE.DTOs.Meal;
using Fitness_core_BE.DTOs.Workout;
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IClientRepository
{
Task<List<Customer>> GetAllCustomers();
Task<Customer?> GetCustomerById(Guid customerId);
Task<List<Client>> GetAllClientsAsync(CancellationToken ct = default);
Task<Client?> GetClientByIdAsync(Guid clientId, CancellationToken ct = default);
Task<List<Customer>> GetClientListAsync(Guid clientId, CancellationToken ct = default);
Task <object> RegisterClientAsync(Client client, CancellationToken ct = default);
Task RegisterBussinessDetailAsync(ClientBusiness clientBusiness, CancellationToken ct = default);
// Tracked (unlike GetClientByIdAsync) so the caller can mutate & persist via UoW.
Task<ClientBusiness?> GetPrimaryBusinessByClientIdAsync(Guid clientId, CancellationToken ct = default);
Task<Client?> GetClientEntityByIdAsync(Guid clientId, CancellationToken ct = default);
Task<List<FollowedPlanDto>> GetFollowedWorkoutPlansAsync(Guid customerId, CancellationToken ct = default);
Task<List<FollowedPlanDto>> GetFollowedMealPlansAsync(Guid customerId, CancellationToken ct = default);
Task<CustomerHealth?> GetCustomerHealthAsync(Guid customerId, CancellationToken ct = default);
Task<List<MemberListRowDto>> GetCustomersByClientIdAsync(Guid clientId, CancellationToken ct = default);
Task<bool> CustomerBelongsToClientAsync(Guid customerId, Guid clientId, CancellationToken ct = default);
Task<List<CustomerPlan>> GetCustomerPlansByClientIdAsync(Guid clientId, CancellationToken ct = default);
// Workout Plan operations
Task<List<WorkoutPlanDto>> GetWorkoutPlansByClientIdAsync(Guid clientId, CancellationToken ct = default);
Task<WorkoutPlanDetailDto?> GetWorkoutPlanByIdForClientAsync(Guid workoutPlanId, Guid clientId, CancellationToken ct = default);
// Meal Plan operations
Task<List<MealPlanDto>> GetMealPlansByClientIdAsync(Guid clientId, CancellationToken ct = default);
Task<MealPlanDetailDto?> GetMealPlanByIdForClientAsync(Guid mealPlanId, Guid clientId, CancellationToken ct = default);
// Customer Plan operations
Task<CustomerPlanDto?> GetCustomerPlanByIdForClientAsync(Guid customerPlanId, Guid clientId, CancellationToken ct = default);
// Full entity (not the DTO above) — needed by CustomerSubscriptionFactory, which reads
// DurationMode/ValidTo/InstallmentCount/HasOnboardingFee that the DTO doesn't carry.
Task<CustomerPlan?> GetCustomerPlanEntityForClientAsync(Guid customerPlanId, Guid clientId, CancellationToken ct = default);
// Change-membership-plan / unassign-membership operations
Task<SubscriptionMember?> GetActiveMembershipForCustomerAsync(Guid customerId, CancellationToken ct = default);
// Deactivates a whole subscription and its members/subitems/installments.
Task DeactivateSubscriptionAsync(Guid subscriptionId, CancellationToken ct = default);
// Deactivates a single member's row within a (possibly still-active) subscription.
Task DeactivateSubscriptionMemberAsync(Guid subscriptionMemberId, CancellationToken ct = default);
// Any membership (assigned or not) for assign/unassign to act on.
Task<SubscriptionMember?> GetMembershipForCustomerAsync(Guid customerId, CancellationToken ct = default);
// Toggles IsPlanAssigned without touching IsActive, so the member stays listed.
Task SetMembershipPlanAssignedAsync(
Guid subscriptionId, bool assigned, bool wholeSubscription, Guid subscriptionMemberId,
CancellationToken ct = default);
// Deactivates oldMembership's subscription (if primary) or just their own row (if not),
// then persists newAggregate as the customer's new subscription.
Task ReplaceCustomerSubscriptionAsync(SubscriptionMember? oldMembership, CustomerSubscriptionAggregate newAggregate, CancellationToken ct = default);
// Client Package operations
Task<List<ClientPackage>> GetPackageListAsync(CancellationToken ct = default);
Task<ClientPackage?> GetPackageByIdAsync(Guid id, CancellationToken ct = default);
Task<List<ClientBusiness>> GetActiveGymsAsync(CancellationToken ct = default);
Task<List<CustomerCards>> GetCardsByClientIdAsync(Guid clientId, CancellationToken ct = default);
Task<List<CustomerCards>> GetCardsByCustomerForClientAsync(Guid customerId, Guid clientId, CancellationToken ct = default);
}
}
+21
View File
@@ -0,0 +1,21 @@
using Fitness_core_BE.DTOs.Stats;
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IClientStatRepository
{
Task<int> GetTotalCustomerCountAsync(Guid clientId, CancellationToken ct = default);
Task<int> GetMonthlyCustomerCountAsync(Guid clientId, CancellationToken ct = default);
Task<int> GetTotalWorkoutPlanCountAsync(Guid clientId, CancellationToken ct = default);
Task<int> GetTotalMealPlanCountAsync(Guid clientId, CancellationToken ct = default);
Task<int> GetLastMonthCustomerCountAsync(Guid clientId, CancellationToken ct = default);
Task<List<Attendance>> GetLastFiveAttendancesAsync(Guid clientId, CancellationToken ct = default);
Task<List<PaymentTransaction>> GetLastFivePaymentsAsync(Guid clientId, CancellationToken ct = default);
Task<decimal> GetLastMonthRevenueAsync(Guid clientId, CancellationToken ct = default);
Task<List<MonthlyRevenueStat>> GetMonthlyRevenueVariationAsync(Guid clientId, DateTime? from = null, DateTime? to = null, CancellationToken ct = default);
Task<decimal> GetTotalRevenueAsync(Guid clientId, CancellationToken ct = default);
Task<ClientStatSummaryDto> GetClientStatSummaryAsync(Guid clientId, DateTime? from = null, DateTime? to = null, CancellationToken ct = default);
Task<int> GetExpiringSoonCountAsync(Guid clientId, DateTime from, DateTime to, CancellationToken ct = default);
}
}
+53
View File
@@ -0,0 +1,53 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface ICustomerInvoiceRepository
{
// carriedOverBalance: unpaid amount rolled forward from a prior subscription period
// (renewal). includeOnboardingFee: false for renewals -- it's a one-time fee and would
// otherwise re-bill every cycle.
Task<CustomerInvoice> CreateCustomerInvoiceFromSubscription(
Guid subscriptionId, bool chargePayment = true, decimal carriedOverBalance = 0m, bool includeOnboardingFee = true);
// Guard-free sibling used only by the daily renewal sweep -- see the implementation for
// why CreateCustomerInvoiceFromSubscription's idempotency guard doesn't apply here.
Task<CustomerInvoice> CreateRenewalInvoiceAsync(
Guid subscriptionId, decimal carriedOverBalance, CancellationToken ct = default);
Task<CustomerInvoice?> GetInvoiceBySubscriptionIdAsync(Guid subscriptionId);
Task<CustomerInvoice?> GetCustomerInvoiceById(Guid customerInvoiceId);
Task<List<CustomerInvoice>> GetCustomerInvoicesByCustomerId(Guid customerId);
Task<List<CustomerInvoice>> GetCustomerInvoicesByClientId(Guid clientId);
Task<CustomerInvoice> UpdateCustomerInvoiceStatus(Guid customerInvoiceId, string status);
// Renewal-approval workflow.
Task<List<CustomerInvoice>> GetUnapprovedInvoicesByClientIdAsync(Guid clientId);
// True when this subscription has a renewal invoice awaiting approval -- used to tell a
// genuinely legacy "no invoice yet" subscription (safe to self-heal) apart from one whose
// only invoices are unapproved/RolledOver right now (not safe: creating a fresh invoice
// there would silently duplicate a renewal already in flight).
Task<bool> HasPendingApprovalInvoiceAsync(Guid subscriptionId);
Task<List<CustomerInvoice>> GetLatestApprovedInvoicePerCustomerAsync(Guid clientId);
Task RepointAndRecalculateInvoiceAsync(Guid customerInvoiceId, Guid newSubscriptionId, CancellationToken ct = default);
// Sum of each invoice's "Previous Balance" line item (0 if it has none) -- the portion of
// Amount that's carried-forward debt rather than this cycle's own charge. Batched so list
// endpoints (e.g. the approvals queue) don't issue one query per row.
Task<Dictionary<Guid, decimal>> GetCarriedForwardAmountsAsync(List<Guid> invoiceIds);
// A standalone charge on top of an existing subscription (e.g. an extra fee added
// mid-cycle), separate from the subscription's original CreateCustomerInvoiceFromSubscription
// invoice which is idempotent per subscription and won't pick up items added later.
Task<CustomerInvoice> CreateSupplementalInvoiceAsync(Guid subscriptionId, string itemName, string? itemDescription, decimal amount);
// Plan-change settlement: `amount` is the signed diff between what the new plan costs
// and what the customer already paid toward the old one (positive = they owe more,
// negative = they overpaid and get a credit). Nets out any of the customer's still-open
// Credit invoices first, same as every other invoice-creation path.
Task<CustomerInvoice> CreatePlanChangeInvoiceAsync(
Guid subscriptionId, string itemName, decimal amount, CancellationToken ct = default);
Task<decimal> GetApprovedPaymentTotalAsync(Guid invoiceId, CancellationToken ct = default);
}
}
@@ -0,0 +1,14 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface ICustomerNotificationRepository
{
Task CreateAsync(CustomerNotification notification, CancellationToken ct = default);
Task CreateManyAsync(IEnumerable<CustomerNotification> notifications, CancellationToken ct = default);
Task<List<CustomerNotification>> GetByCustomerIdAsync(Guid customerId, CancellationToken ct = default);
Task<CustomerNotification?> GetByIdAsync(Guid customerNotificationId, Guid customerId, CancellationToken ct = default);
Task<string?> GetCustomerPushTokenAsync(Guid customerId, CancellationToken ct = default);
Task<List<string>> GetCustomerPushTokensAsync(IEnumerable<Guid> customerIds, CancellationToken ct = default);
}
}
+18
View File
@@ -0,0 +1,18 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface ICustomerPlanRepository
{
Task<List<CustomerPlan>> GetAllCustomerPlans(bool includeInactive = false, Guid? clientId = null); Task<CustomerPlan?> GetCustomerPlanById(Guid customerPlanId);
Task<CustomerPlan> CreateCustomerPlan(CustomerPlan customerPlan);
Task<CustomerPlan> UpdateCustomerPlan(CustomerPlan customerPlan);
// Status-only toggle. Deliberately separate from UpdateCustomerPlan: reactivating a
// plan must not re-run the whole cross-field configuration validation, so an older
// plan whose config predates a rule can still be switched back on.
Task<CustomerPlan?> SetCustomerPlanActive(Guid customerPlanId, Guid clientId, bool isActive);
Task<bool> DeleteCustomerPlan(Guid customerPlanId, bool softDelete = true);
}
}
+76
View File
@@ -0,0 +1,76 @@
using Fitness_core_BE.DTOs.Meal;
using Fitness_core_BE.DTOs.Workout;
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface ICustomerRepository
{
Task<Customer?> GetCustomerById(Guid customerId);
// Central dedupe lookup: is this phone/email an existing Customer (active or not)?
// Matches on Customer's own PrimaryPH/SecondaryPH/Email as well as the linked User's
// PhoneNumber/Email, and deliberately does not filter by IsActive — an inactive
// customer's identity still counts as "already exists" so no duplicate central
// record gets created for the same person.
Task<Customer?> GetCustomerByIdentifier(string identifier);
Task<Customer> CreateCustomer(Customer customer);
Task<Customer?> UpdateCustomer(Guid customerId, Customer customer);
/// <summary>
/// Ensures this tenant DB has the TenantCustomerLink anchor row every tenant-side
/// FK (subscriptions, cards, attendance, ...) points at. Idempotent: refreshes the
/// cached display fields and re-activates the link when the row already exists, so
/// it is safe to call on both first-time creation and re-enrolment.
/// </summary>
Task EnsureTenantCustomerLink(Customer customer);
// Own-gym duplicate check: does THIS tenant already have an active customer whose
// cached phone/email matches? Scoped by construction (TenantDbContext is already this
// gym's own schema) -- no clientId parameter needed.
Task<TenantCustomerLink?> FindActiveLinkByIdentifierAsync(string identifier);
Task<bool> DeleteCustomer(Guid customerId);
// Client-initiated delete: deactivates only this customer's presence at the calling
// client's gym (subscriptions/members/plan assignments scoped to clientId). The shared
// central Customer record is never touched — the same person may be an active member
// at a different gym.
Task<bool> DeactivateCustomerForClient(Guid customerId, Guid clientId);
Task<List<ClientBusiness>> GetAllClentShopsAsync();
Task<Guid?> GetCustomerClientId(Guid customerId);
Task<MealPlan?> GetActiveMealPlanAsync(Guid? clientId = null, Guid? cusId = null);
Task<WorkoutPlan?> GetActiveWorkOutAsync(Guid? clientId = null, Guid? cusId = null);
Task<List<MealPlanDetailDto>> GetFollowedMealPlansByCustomerIdAsync(Guid customerId);
// All of the customer's own AI-generated meal plans (IsTemplate=false), regardless of
// whether they're currently followed — distinct from admin/client-authored templates.
Task<List<MealPlanDetailDto>> GetMyMealPlansByCustomerIdAsync(Guid customerId);
Task<MealPlanDetailDto?> GetMealPlanByIdForCustomerAsync(Guid mealPlanId);
Task<List<WorkoutPlanDetailDto>> GetFollowedWorkoutPlansByCustomerIdAsync(Guid customerId);
Task<List<WorkoutPlanDetailDto>> GetMyWorkoutPlansByCustomerIdAsync(Guid customerId);
Task<WorkoutPlanDetailDto?> GetWorkoutPlanByIdForCustomerAsync(Guid workoutPlanId, Guid customerId);
Task<object> FollowMealPlan(Guid customerId, Guid mealPlanId);
Task<object> FollowWorkoutPlan(Guid customerId, Guid workOutPlanId);
// Active (IsActive) CustomerWorkout join row for this customer + plan, regardless of
// whether it's the currently-followed one — used to scope per-exercise completion.
Task<CustomerWorkout?> GetActiveCustomerWorkoutAsync(Guid customerId, Guid workoutPlanId);
Task SetExerciseCompletionAsync(Guid customerWorkoutId, Guid workoutExerciseId, bool completed);
Task<object> GetClientBizDataAsync(Guid ClientBizId);
Task<CustomerHealth> GetCusHealthRec(Guid cusID);
Task<List<CustomerTarget>> GetCusProgressRec(Guid cusID);
Task<object> CreateCusHealthRecAsync(CustomerHealth customerHealth);
Task<object> UpdateCusHealthRecAsync(CustomerHealth NewcustomerHealth);
Task<object> CreateCustomerTargetAsync(CustomerTarget customerTarget);
Task<CustomerTarget?> GetLatestCustomerTargetAsync(Guid customerId);
Task<List<CustomerTarget>> GetCustomerTargetsAsync(Guid customerId);
Task<CustomerTarget> UpdateLatestCustomerTargetNutritionsAsync(Guid customerId, string predictedNutritionsJson);
Task<Dictionary<string, List<CustomerTarget>>> GetCustomerProgressGroupedByGoalAsync(Guid customerId);
Task<CusWeightLossProgress> UpdateWeeklyProgressAsync(Guid customerId, Guid customerTargetId, decimal weight, DateTime? recordedAt);
Task<List<CusWeightLossProgress>> GetWeeklyProgressForCustomerAsync(Guid customerId, Guid customerTargetId);
Task<bool> VerifyCustomer(Guid userId, string type, string identifire);
Task<bool> IsverifiedCus(Guid cusId);
Task<List<CustomerCards>> GetCardsByCustomerIdAsync(Guid customerId, CancellationToken ct = default);
Task<CustomerCards?> GetCardByIdAsync(Guid cardId, CancellationToken ct = default);
Task<CustomerCards> AddCardAsync(CustomerCards card, CancellationToken ct = default);
}
}
@@ -0,0 +1,53 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface ICustomerSubscriptionRepository
{
Task AddCustomerSubscriptionAsync(
CustomerSubscription subscription,
CustomerSubItem initialSubItem,
SubscriptionMember primaryMember,
IReadOnlyCollection<SubscriptionInstallment> installments,
CancellationToken ct = default);
Task<CustomerPlan?> GetPlanByIdAsync(Guid customerPlanId, CancellationToken ct = default);
Task<bool> IsActiveCustomerAsync(Guid customerId, CancellationToken ct = default);
Task<List<CustomerSubItem>> GetSubItemsAsync(
Guid subscriptionId,
bool activeOnly,
bool newestFirst,
CancellationToken ct = default);
Task AddSubItemAsync(CustomerSubItem subItem, CancellationToken ct = default);
Task<CustomerInvoice?> GetLatestInvoiceAsync(Guid subscriptionId, CancellationToken ct = default);
Task<decimal> GetApprovedPaymentTotalAsync(Guid invoiceId, CancellationToken ct = default);
Task<CustomerCards?> GetCardByIdAsync(Guid cardId, CancellationToken ct = default);
Task<CustomerSubscription?> GetCustomerSubscriptionById(Guid subscriptionId);
Task<List<CustomerSubscription>> GetCustomerSubscriptionsByCustomerId(Guid customerId);
Task<CustomerSubscription?> GetActiveSubscriptionByCustomerId(Guid customerId);
// Whether this customer is currently an active member (primary OR secondary/group) of
// ANY subscription at this gym. GetActiveSubscriptionByCustomerId only sees subscriptions
// where they're the primary -- this also catches a group co-member, so "one customer, one
// plan at a time" can be enforced everywhere a plan gets assigned, not just the primary
// path.
Task<bool> HasAnyActiveSubscriptionAsync(Guid customerId, CancellationToken ct = default);
Task<SubscriptionMember> AddSubscriptionMemberAsync(SubscriptionMember member);
Task<int> GetActiveMemberCountAsync(Guid subscriptionId);
Task<SubscriptionMember?> GetSubscriptionMemberAsync(Guid subscriptionMemberId);
Task<SubscriptionMember?> GetActiveSubscriptionMemberByCustomerAsync(Guid subscriptionId, Guid customerId);
Task<List<CustomerSubscription>> GetSubscriptionsForCustomerAsync(Guid customerId);
Task<List<SubscriptionInstallment>> GetInstallmentsAsync(Guid subscriptionId);
// Renewal-approval workflow (SubscriptionRenewalApprovalService.ApproveAsync): advances
// RenewalDate only -- ExpiryDate is never touched again after creation.
Task AdvanceRenewalDateAsync(Guid subscriptionId, DateTime newRenewalDate, CancellationToken ct = default);
// Removes the subscription's current-cycle installment rows before a fresh schedule is
// added for the newly-approved cycle. Hard delete, not soft-deactivate: a unique index on
// (FKSubscriptionId, InstallmentNo) means a soft-deactivated row would still collide with
// the new cycle's schedule restarting at InstallmentNo 1 on the same subscription.
Task DeactivatePriorInstallmentsAsync(Guid subscriptionId, CancellationToken ct = default);
Task AddInstallmentsAsync(IReadOnlyCollection<SubscriptionInstallment> installments, CancellationToken ct = default);
}
}
+36
View File
@@ -0,0 +1,36 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IDeviceCommandRepo
{
Task<DeviceCommand> AddAsync(DeviceCommand command);
Task<List<DeviceCommand>> GetPendingByClientAsync(Guid clientId);
Task<DeviceCommand?> GetByIdAsync(Guid commandId);
Task<bool> IsQueuedAsync(
Guid bindingId,
string commandType,
int desiredVersion,
CancellationToken ct = default);
Task<List<DeviceCommand>> GetPendingStateCommandsAsync(
Guid bindingId,
CancellationToken ct = default);
Task<List<DeviceCommand>> GetPendingFacePhotoCommandsAsync(
Guid bindingId,
CancellationToken ct = default);
Task<List<DeviceCommand>> GetExhaustedLeasesAsync(
Guid clientId,
DateTime now,
CancellationToken ct = default);
Task<List<DeviceCommand>> GetLeaseableCommandsAsync(
Guid clientId,
Guid agentId,
DateTime now,
int take,
CancellationToken ct = default);
Task<DeviceCommand?> GetForAgentResultAsync(
Guid commandId,
CancellationToken ct = default);
Task UpdateStatusAsync(DeviceCommand command, string status, string? resultJson = null, DateTime? processedAt = null);
}
}
+13
View File
@@ -0,0 +1,13 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IDocumentRepository
{
Task<UserDocument> UploadDocumentAsync(UserDocument userDocument);
Task<string> GetLastSequnce();
Task<List<UserDocument>> GetDocumentsByUserId(Guid userId);
Task<UserDocument?> GetDocumentById(int documentId);
Task<bool> RemoveDocument(int documentId);
}
}
+19
View File
@@ -0,0 +1,19 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IFacilityRepository
{
Task<List<Facility>> GetAllFacilities(Guid clientId, bool includeInactive = false);
Task<Facility?> GetFacilityById(Guid facilityId);
Task<Facility> CreateFacility(Facility facility);
Task<Facility> UpdateFacility(Facility facility);
Task<Facility?> SetFacilityActive(Guid facilityId, Guid clientId, bool isActive);
Task<FacilitySession> CreateFacilitySession(FacilitySession session);
Task<FacilitySession?> GetFacilitySessionById(Guid facilitySessionId);
Task<List<FacilitySession>> GetSessions(Guid clientId, Guid? facilityId, DateTime fromUtc, DateTime toUtc);
Task<int> GetActiveBookingCount(Guid facilitySessionId);
Task<FacilitySession?> CancelFacilitySession(Guid facilitySessionId, Guid clientId);
}
}
+28
View File
@@ -0,0 +1,28 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IFeedRepository
{
Task<FeedPost> GetFeedPostByIdAsync(Guid creatorId, Guid postId);
Task<List<FeedPost>> GetFeedListAsync(int skip, int take);
Task<bool> IsLikedAsync(Guid postId, Guid userId);
Task AddLikeAsync(Guid postId, Guid userId);
Task RemoveLikeAsync(Guid postId, Guid userId);
Task<object> CreateFeedAsync(FeedPost feedPost, CancellationToken ct = default);
Task<int> GetLikeCountAsync(Guid postId);
Task<List<FeedPost>> GetFeedByClientAsync(Guid clientId);
Task<(Guid? ClientId, List<FeedPost> Posts)> GetFeedForCustomerAsync(
Guid customerUserId,
int skip,
int take,
CancellationToken ct = default);
Task<object> DeletePostPostIdAsync(Guid creatorId, Guid postId);
// Resolves a feed poster's user id to the gym (Client) they own, then returns the ids of
// all customers with an active subscription at that gym — used to fan out a push
// notification to every member when the gym owner creates a post. Returns an empty list
// for staff-authored posts or any poster who isn't a Client owner.
Task<List<Guid>> GetActiveCustomerIdsByPosterUserIdAsync(Guid posterUserId, CancellationToken ct = default);
}
}
+20
View File
@@ -0,0 +1,20 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IGymRoleRepository
{
Task<List<GymRole>> GetRolesByClientId(Guid clientId);
Task<GymRole?> GetRoleById(Guid gymRoleId);
Task<GymRole> CreateRole(GymRole role);
Task<GymRole> UpdateRole(GymRole role);
Task DeleteRole(GymRole role);
Task ReplacePermissions(Guid gymRoleId, IEnumerable<string> navKeys);
Task<List<string>> GetPermissionKeys(Guid gymRoleId);
// Returns false if the staff member doesn't exist or doesn't belong to clientId (tenant isolation),
// or if gymRoleId is supplied but doesn't belong to clientId either.
Task<bool> AssignStaffRole(Guid staffId, Guid clientId, Guid? gymRoleId);
}
}
+34
View File
@@ -0,0 +1,34 @@
using Fitness_core_BE.Models;
using Fitness_core_BE.DTOs.Meal;
namespace Fitness_core_BE.Interfaces
{
public interface IMealRepository
{
// Meal Category operations
Task<List<MealCategoryDto>> GetMealCategoryListAsync(CancellationToken ct = default);
Task<bool> MealCategoryExistsAsync(Guid mealCategoryId, CancellationToken ct = default);
Task<MealCategory> CreateMealCategoryAsync(MealCategory mealCategory, CancellationToken ct = default);
// Meal Plan operations
Task<List<MealPlanDto>> GetMealPlanListAsync(string userType, Guid clientId, CancellationToken ct = default);
Task<MealPlanDetailDto?> GetMealPlanByIdAsync(Guid id, CancellationToken ct = default);
Task<List<MealPlanDetailDto>> GetMealPlansByCustomerIdAsync(Guid customerId, CancellationToken ct = default);
Task<MealPlan?> GetMealPlanEntityByIdAsync(Guid id, CancellationToken ct = default);
Task<MealPlan> CreateMealPlanAsync(MealPlan mealPlan, CancellationToken ct = default);
Task<MealPlan> UpdateMealPlanAsync(MealPlan mealPlan, CancellationToken ct = default);
Task DeleteMealPlanAsync(Guid id, CancellationToken ct = default);
// Meal Item operations
Task<List<MealDto>> GetMealsByMealPlanIdAsync(Guid mealPlanId, CancellationToken ct = default);
Task<Meal?> GetMealByIdAsync(Guid id, CancellationToken ct = default);
Task<Meal> CreateMealAsync(Meal mealItem, CancellationToken ct = default);
Task<Meal> UpdateMealAsync(Meal mealItem, CancellationToken ct = default);
Task DeleteMealAsync(Guid id, CancellationToken ct = default);
Task<CustomerMeal> AssignMealToCustomerAsync(CustomerMeal customerMeal, CancellationToken ct = default);
Task<bool> UnassignMealFromCustomerAsync(Guid customerMealId, CancellationToken ct = default);
Task<List<CustomerMealDto>> GetCustomerMealsByPlanIdAsync(Guid mealPlanId, CancellationToken ct = default);
Task<List<CustomerMealDto>> GetCustomerMealsByCustomerIdAsync(Guid customerId, CancellationToken ct = default);
}
}
+9
View File
@@ -0,0 +1,9 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface INavItemRepository
{
Task<List<NavItem>> GetActiveNavItemsOrdered();
}
}
+21
View File
@@ -0,0 +1,21 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IOverdueLockRepository
{
Task<List<Client>> GetClientsWithOverdueLockPolicyAsync(CancellationToken ct = default);
Task<List<Guid>> GetOverdueCustomerIdsAsync(
Guid clientId,
DateTime thresholdDate,
CancellationToken ct = default);
Task<Customer?> GetCustomerByIdAsync(Guid customerId, CancellationToken ct = default);
Task<bool> IsCustomerAccessDisabledAsync(
Guid clientId,
Guid userId,
CancellationToken ct = default);
Task<List<Guid>> GetCustomersLockedForOverdueAsync(
Guid clientId,
CancellationToken ct = default);
}
}
+11
View File
@@ -0,0 +1,11 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IPairingCodeRepo
{
Task<PairingCode> AddAsync(PairingCode pairingCode);
Task<PairingCode?> GetActiveByCodeAsync(string code);
Task MarkUsedAsync(PairingCode pairingCode);
}
}
+14
View File
@@ -0,0 +1,14 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IPaymentRepository
{
Task<PaymentTransaction> CreatePaymentAttemptAsync(PaymentTransaction attempt);
Task<PaymentTransaction?> GetPaymentByIdAsync(Guid attemptId);
Task<List<PaymentTransaction>> GetPaymentsByCustomerInvoiceIdAsync(Guid customerInvoiceId);
Task<List<PaymentTransaction>> GetPaymentsByClientInvoiceIdAsync(Guid clientInvoiceId);
Task<PaymentTransaction> UpdatePaymentAttemptAsync(PaymentTransaction attempt);
Task<decimal> GetApprovedPaidAmountAsync(Guid customerInvoiceId);
}
}
@@ -0,0 +1,19 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IPaymentsEnablementRepository
{
Task<ClientWallet?> GetWalletByClientIdAsync(Guid clientId, CancellationToken ct = default);
Task<List<WalletLedgerEntry>> GetLedgerAsync(Guid walletId, CancellationToken ct = default);
Task<ClientPayoutKyc?> GetKycByClientIdAsync(Guid clientId, CancellationToken ct = default);
Task<ClientPayoutKyc?> GetKycForUpdateAsync(Guid clientId, CancellationToken ct = default);
Task CreateKycAsync(ClientPayoutKyc kyc, CancellationToken ct = default);
Task<(List<ClientPayoutKyc> Items, int Total)> ListKycAsync(string? status, CancellationToken ct = default);
Task CreateWalletAsync(ClientWallet wallet, CancellationToken ct = default);
Task CreateClientCardAsync(ClientCard card, CancellationToken ct = default);
}
}
+25
View File
@@ -0,0 +1,25 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IPlaceRepo
{
Task<List<Place>> GetAllPlaces(Guid clientId, bool includeInactive = false);
Task<Place?> GetPlaceById(Guid placeId);
Task<Place> CreatePlace(Place place);
Task<Place> UpdatePlace(Place place);
Task<Place?> SetPlaceActive(Guid placeId, Guid clientId, bool isActive);
Task<AccessDevice?> GetDeviceByIdForClientAsync(Guid deviceId, Guid clientId);
Task<Dictionary<Guid, AccessDevice>> GetDevicesByPlaceIdsAsync(List<Guid> placeIds);
Task<bool> IsDeviceAssignedToAnotherPlaceAsync(Guid deviceId, Guid placeId);
Task AssignDeviceAsync(Guid placeId, Guid deviceId);
Task UnassignDeviceAsync(Guid placeId);
// CustomerPlan <-> Place (many-to-many). Replace-all semantics, like a tags field.
Task SetPlanPlacesAsync(Guid customerPlanId, List<Guid> placeIds);
Task<List<Guid>> GetPlaceIdsForPlanAsync(Guid customerPlanId);
Task<Dictionary<Guid, List<Guid>>> GetPlaceIdsByPlanIdsAsync(List<Guid> customerPlanIds);
Task<Dictionary<Guid, string>> GetPlaceNamesByIdsAsync(List<Guid> placeIds);
}
}
+66
View File
@@ -0,0 +1,66 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IPlatformBillingRepository
{
Task<List<ClientPackage>> GetPricingPlansAsync(CancellationToken ct = default);
Task<ClientPackage?> GetPackageByIdAsync(Guid packageId, CancellationToken ct = default);
Task AddPackageAsync(ClientPackage package, CancellationToken ct = default);
Task<List<ClientPackage>> GetOtherDefaultPackagesAsync(
Guid exceptPackageId,
CancellationToken ct = default);
Task<ClientPackage?> GetDefaultPackageAsync(CancellationToken ct = default);
Task<ClientPackage?> GetActivePackageForClientAsync(
Guid clientId,
CancellationToken ct = default);
Task<Client?> GetClientByIdAsync(Guid clientId, CancellationToken ct = default);
Task<List<ClientSubscription>> GetActiveClientSubscriptionsAsync(
Guid clientId,
CancellationToken ct = default);
Task<ClientSubscription?> GetActiveClientSubscriptionAsync(
Guid clientId,
CancellationToken ct = default);
Task AddClientSubscriptionAsync(
ClientSubscription subscription,
CancellationToken ct = default);
Task<List<ClientDeviceBilling>> GetActiveDeviceBillingsAsync(
Guid clientId,
CancellationToken ct = default);
Task<ClientDeviceBilling?> GetLatestActiveDeviceBillingAsync(
Guid clientId,
CancellationToken ct = default);
Task AddDeviceBillingAsync(
ClientDeviceBilling billing,
CancellationToken ct = default);
Task<bool> HasActiveDeviceAsync(Guid clientId, CancellationToken ct = default);
Task<List<Guid>> GetMonthlyBillingCandidatesAsync(
DateTime startOfMonth,
CancellationToken ct = default);
Task<List<ClientInvoice>> GetInvoicesByStatusAsync(
string status,
bool newestFirst,
CancellationToken ct = default);
Task<ClientInvoice?> GetInvoiceWithClientAsync(
Guid invoiceId,
bool includeBusinesses,
CancellationToken ct = default);
Task<ClientCard?> GetClientCardAsync(Guid clientId, CancellationToken ct = default);
Task<List<ClientCard>> GetClientCardsAsync(Guid clientId, CancellationToken ct = default);
Task<ClientCard?> GetClientCardByTokenAsync(Guid clientId, string cardToken, CancellationToken ct = default);
Task AddInvoiceAsync(
ClientInvoice invoice,
IReadOnlyCollection<ClientInvoiceItem> items,
CancellationToken ct = default);
Task<DevicePricingConfig?> GetDevicePricingConfigAsync(
CancellationToken ct = default);
Task AddDevicePricingConfigAsync(
DevicePricingConfig config,
CancellationToken ct = default);
}
}
+24
View File
@@ -0,0 +1,24 @@
using Fitness_core_BE.DTOs.Ledger;
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IProfitLossRepository
{
Task<List<LedgerEntryDto>> GetDerivedEntriesAsync(
Guid clientId,
DateTime fromUtc,
DateTime toUtc,
CancellationToken ct = default);
Task<List<LedgerEntry>> GetManualEntriesAsync(
Guid clientId,
DateTime fromUtc,
DateTime toUtc,
CancellationToken ct = default);
Task<LedgerEntry?> GetManualEntryByIdAsync(Guid id, CancellationToken ct = default);
Task AddManualEntryAsync(LedgerEntry entry, CancellationToken ct = default);
void RemoveManualEntry(LedgerEntry entry);
}
}
+20
View File
@@ -0,0 +1,20 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface IStaffRepository
{
Task<List<Staff>> GetAllStaff(bool includeInactive = false);
Task<Staff?> GetStaffById(Guid staffId);
Task<List<Staff>> GetStaffByClientId(Guid clientId, bool includeInactive = false);
Task<Staff> CreateStaff(Staff staff, User user);
Task<Staff> UpdateStaff(Staff staff);
Task<bool> DeleteStaff(Guid staffId, bool softDelete = true);
// Basic HRM/payroll (req 5).
Task<StaffPayRate?> GetActivePayRateAsync(Guid staffId);
Task<StaffPayRate> AddPayRateAsync(StaffPayRate rate);
Task<List<StaffPayment>> GetPaymentsAsync(Guid staffId);
Task<StaffPayment> AddPaymentAsync(StaffPayment payment);
}
}
+14
View File
@@ -0,0 +1,14 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface ITermsRepository
{
Task<ClientTerms?> GetActiveByClientIdAsync(Guid clientId);
Task<List<ClientTerms>> GetActiveForUpdateAsync(Guid clientId);
Task<int> GetLatestVersionAsync(Guid clientId);
Task AddTermsAsync(ClientTerms terms);
Task AddAcceptanceAsync(CustomerTermsAcceptance acceptance);
Task<CustomerTermsAcceptance?> GetAcceptanceAsync(Guid cusId, Guid clientId, int version);
}
}
+26
View File
@@ -0,0 +1,26 @@
using Fitness_core_BE.Models;
using Fitness_core_BE.DTOs.Ticket;
namespace Fitness_core_BE.Interfaces
{
public interface ITicketRepository
{
// Ticket operations
Task<Guid> GetTicketCatId(string type);
Task<List<TicketDto>> GetTicketListAsync(CancellationToken ct = default);
Task<List<TicketDto>> GetTicketByUserIdAsync(Guid userId, CancellationToken ct = default);
Task<TicketDetailDto?> GetByTicketIdAsync(Guid id, CancellationToken ct = default);
Task<Ticket> CreateTicketAsync(Ticket ticket, CancellationToken ct = default);
Task<Ticket> UpdateTicketAsync(TicketDetailDto ticket, CancellationToken ct = default);
Task<bool> DeleteAsync(Guid id, CancellationToken ct = default);
// Ticket category operations
Task<List<TicketCategory>> GetTicketCategoryListAsync(CancellationToken ct = default);
Task<TicketCategory?> GetTicketCategoryByIdAsync(Guid id, CancellationToken ct = default);
// Ticket message operations
Task<TicketMessage> SendMessageAsync(TicketMessage ticketMessage, CancellationToken ct = default);
Task<Ticket> SubmitTicketFeedbackAsync(Guid ticketId, int rating, string? feedback, CancellationToken ct = default);
Task UpdateTicketStatusAsync(Guid ticketId, Fitness_core_BE.Models.Enums.TicketStatusEnum statusCode);
}
}
+13
View File
@@ -0,0 +1,13 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces
{
public interface ITimeBankCardRepository
{
Task<TimeBankCard> CreateTimeBankCard(TimeBankCard card);
Task<TimeBankCard?> GetById(Guid timeBankCardId);
Task<TimeBankCard?> GetByRfidTagId(string rfidTagId);
Task<List<TimeBankCard>> GetByCustomerId(Guid customerId);
Task<TimeBankCardUsageLog> AddUsageLog(TimeBankCardUsageLog log);
}
}
+34
View File
@@ -0,0 +1,34 @@
using Fitness_core_BE.Models;
using Fitness_core_BE.DTOs.Workout;
namespace Fitness_core_BE.Interfaces
{
public interface IWorkoutRepository
{
// Workout Category operations
Task<List<WorkoutCategoryDto>> GetWorkoutCategoryListAsync(CancellationToken ct = default);
Task<bool> WorkoutCategoryExistsAsync(Guid workoutCategoryId, CancellationToken ct = default);
Task<WorkoutCategory> CreateWorkoutCategoryAsync(WorkoutCategory workoutCategory, CancellationToken ct = default);
// Workout Plan operations
Task<List<WorkoutPlanDto>> GetWorkoutPlanListAsync(string userType, Guid clientId, CancellationToken ct = default);
Task<WorkoutPlanDetailDto?> GetWorkoutPlanByIdAsync(Guid id, CancellationToken ct = default);
Task<List<WorkoutPlanDetailDto>> GetWorkoutPlansByCustomerIdAsync(Guid customerId, CancellationToken ct = default);
Task<WorkoutPlan?> GetWorkoutPlanEntityByIdAsync(Guid id, CancellationToken ct = default);
Task<WorkoutPlan> CreateWorkoutPlanAsync(WorkoutPlan workoutPlan, CancellationToken ct = default);
Task<WorkoutPlan> UpdateWorkoutPlanAsync(WorkoutPlan workoutPlan, CancellationToken ct = default);
Task<bool> DeleteWorkoutPlanAsync(Guid id, CancellationToken ct = default);
// Workout Item operations
Task<List<WorkoutItemDto>> GetWorkoutItemsByWorkoutPlanIdAsync(Guid workoutPlanId, CancellationToken ct = default);
Task<WorkoutItem?> GetWorkoutItemByIdAsync(Guid id, CancellationToken ct = default);
Task<WorkoutItem> CreateWorkoutItemAsync(WorkoutItem workoutItem, CancellationToken ct = default);
Task<WorkoutItem> UpdateWorkoutItemAsync(WorkoutItem workoutItem, CancellationToken ct = default);
Task DeleteWorkoutItemAsync(Guid id, CancellationToken ct = default);
Task<CustomerWorkout> AssignWorkoutToCustomerAsync(CustomerWorkout customerWorkout, CancellationToken ct = default);
Task<bool> UnassignWorkoutFromCustomerAsync(Guid customerWorkoutId, CancellationToken ct = default);
Task<List<CustomerWorkoutDto>> GetCustomerWorkoutsByPlanIdAsync(Guid workoutPlanId, CancellationToken ct = default);
Task<List<CustomerWorkoutDto>> GetCustomerWorkoutsByCustomerIdAsync(Guid customerId, CancellationToken ct = default);
}
}
@@ -0,0 +1,47 @@
using Fitness_core_BE.DTOs;
using Fitness_core_BE.DTOs.AccessDevice;
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IAccessDeviceService
{
Task<object> AddDevice(object payload);
Task<object> RemoveDevice(object payload);
Task<object> GeneratePairingCode(object payload);
Task<bool> WhiteListMember(Guid memberId);
Task<bool> BlackListMember(Guid memberId);
// Manual/auto lock (req 7) — wraps WhiteListMember/BlackListMember and mirrors the
// result onto Customer.IsLocked/LockReason/LockedAt.
Task<bool> LockCustomer(Guid customerId, string reason);
Task<bool> UnlockCustomer(Guid customerId);
Task<Customer> UpdateDeviceProfile(Customer customer);
Task<object> AddUser(CustomerAccess cusDevice);
// Dedup + persist attendance. Reused by the agent attendance ingestion endpoint.
Task<int> SaveAttendanceRecords(Guid clientId, List<AttendanceDTO> attendanceList);
// Fingerprint-enrolled-directly-on-device reconciliation (req 3).
Task<List<UnlinkedDeviceEnrollment>> GetUnlinkedFingerprintsAsync(Guid clientId);
Task<AccessProfile> LinkFingerprintAsync(Guid clientId, Guid customerId, Guid unlinkedEnrollmentId);
Task<AccessProfile> EnsureAccessProfileAsync(
Guid clientId, Guid userId, string personType, string displayName, bool queueProvisioning = true);
Task ProvisionProfilesToDeviceAsync(AccessDevice device);
Task<object> SetUserAccessAsync(Guid clientId, Guid userId, bool enabled, string? reason);
Task<object> SetCustomerAccessAsync(Guid clientId, Guid customerId, bool enabled, string? reason);
/// <summary>
/// Queues a face photo for enrolment into the gym's Hikvision terminals. The image
/// travels in the command payload only -- it is purged once a terminal confirms.
/// </summary>
Task<object> SetCustomerFacePhotoAsync(Guid clientId, Guid customerId, string base64Jpeg);
Task<object> SetStaffAccessAsync(Guid clientId, Guid staffId, bool enabled, string? reason);
Task<AccessProfile> LinkDevicePersonAsync(
Guid clientId, Guid userId, string personType, string displayName, Guid unlinkedEnrollmentId);
Task<AccessProfile> LinkStaffFingerprintAsync(
Guid clientId, Guid staffId, Guid unlinkedEnrollmentId);
Task<AccessStatusDto?> GetAccessStatusAsync(Guid clientId, Guid userId);
}
}
@@ -0,0 +1,10 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IActivityLogService
{
Task<object> LogActivity(object payload, HttpContext httpContext);
Task<object> GetActivityLogs(object payload, HttpContext httpContext);
}
}
@@ -0,0 +1,16 @@
using Fitness_core_BE.Models.IOs;
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IAdminClientDirectoryService
{
Task<PagedResult<ClientSummary>> ListAsync(ClientDirectoryQuery query);
Task<object> GetByIdAsync(Guid id);
Task<PairingCodeResult> GeneratePairingCodeAsync(Guid clientId);
Task<AdminClientDevicesResult> GetDevicesAsync(Guid clientId);
// Re-sends the "set your password" welcome email (with a fresh temp password + link)
// for a client whose account has no usable password yet.
Task ResendWelcomeEmailAsync(Guid clientId, HttpContext httpContext);
}
}
@@ -0,0 +1,11 @@
using Fitness_core_BE.Models.IOs;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IAdminSuggestionService
{
Task<object> ListAsync();
Task<object> CreateWorkoutAsync(AdminWorkoutSuggestionRequest request, HttpContext httpContext);
Task<object> CreateMealAsync(AdminMealSuggestionRequest request, HttpContext httpContext);
}
}
+21
View File
@@ -0,0 +1,21 @@
using Fitness_core_BE.DTOs.Agent;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IAgentService
{
// Bootstrap enrollment (no api-key auth). Returns { agentId, apiKey } once.
Task<object> EnrollAsync(EnrollRequest request);
// Agent-authenticated operations. clientId / agentId are resolved server-side
// from the authenticated agent, never from the request body.
Task<object> RegisterDeviceAsync(Guid clientId, Guid agentId, RegisterDeviceRequest request);
Task<object> ReconcileDeviceInventoryAsync(Guid clientId, Guid agentId, DeviceInventoryRequest request);
Task<object> IngestAttendanceAsync(Guid clientId, Guid agentId, AgentAttendanceRequest request);
Task<object> GetPendingCommandsAsync(Guid clientId, Guid agentId);
Task<object> SubmitCommandResultAsync(
Guid clientId, Guid agentId, Guid commandId, CommandResultRequest request);
Task<object> HeartbeatAsync(
Guid clientId, Guid agentId, AgentHeartbeatRequest request);
}
}
@@ -0,0 +1,9 @@
namespace Fitness_core_BE.Interfaces.Services
{
public interface IAttendanceService
{
Task<object> GetAllAttendanceRecords(object payload, HttpContext httpContext);
Task<object> GetAttendanceCounts(object payload, HttpContext httpContext);
Task<object> GetTodayAttendance(object payload, HttpContext httpContext);
}
}
+32
View File
@@ -0,0 +1,32 @@
using Fitness_core_BE.DTOs.Auth;
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IAuthService
{
Task<AuthResponse> SendOtp(object payload, HttpContext httpContext);
Task<AuthResponse> LoginUser(object payload, HttpContext httpContext);
Task<AuthResponse> RefreshToken(object payload, HttpContext httpContext);
Task<AuthResponse> VerifyOTP(object payload, HttpContext httpContext);
// Verifies an OTP and, on success, sets the caller's Customer channel flag
// (IsPrimaryPHVerfied / IsEmailVerfied / IsSecondaryPHVerfied).
Task<AuthResponse> VerifyOTPForCus(object payload, HttpContext httpContext);
Task<AuthResponse> IsAvailable(object payload, HttpContext httpContext);
Task<AuthResponse> GetUserDetails(object payload, HttpContext httpContext);
Task<AuthResponse> UpdateUser(object payload, HttpContext httpContext);
// Admin/service-initiated update of an arbitrary user's login credential by userId —
// unlike UpdateUser (which patches the caller's own profile from their JWT), this lets
// a client/staff edit patch the login record of the *customer* they're editing. Forwards
// to Auth's existing "adminUpdateUser" function.
Task<AuthResponse> AdminUpdateUser(object payload, HttpContext httpContext);
Task<AuthResponse> RegisterUser(object payload, HttpContext httpContext);
Task<AuthResponse> VerifyOtpForLogin(object payload, HttpContext httpContext);
Task<AuthResponse> ForgotPassword(object payload, HttpContext httpContext);
Task<AuthResponse> ResetPassword(object payload, HttpContext httpContext);
Task<AuthResponse> ResetPasswordWithToken(object payload, HttpContext httpContext);
Task<AuthResponse> VerifyPassword(object payload, HttpContext httpContext);
Task<AuthResponse> LogOut(object payload, HttpContext httpContext);
void SetAccessTokenCookie(HttpContext httpContext, string token);
}
}
+28
View File
@@ -0,0 +1,28 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IBookingService
{
/// <summary>Logged-in member books a session against their own plan's allowance.</summary>
Task<object> CreateMemberBooking(object payload, HttpContext httpContext);
/// <summary>No membership at all -- pay-per-session, identity proof is the returned OTP.</summary>
Task<object> CreateGuestBooking(object payload, HttpContext httpContext);
/// <summary>Renders the public, unauthenticated confirmation page a booking's ShareUrl
/// points to -- the "copy the link and share it" receipt. Returns null if not found, so
/// the controller can render a 404 page instead of a JSON error for a browser hit.</summary>
Task<object?> GetBookingView(object payload);
/// <summary>Staff records a guest booking's payment (cash/bank/at-venue) after the fact.</summary>
Task<object> MarkGuestBookingPaid(object payload, HttpContext httpContext);
/// <summary>Staff/door check-in: verifies the OTP and marks the booking checked in.</summary>
Task<object> CheckInBooking(object payload, HttpContext httpContext);
Task<object> CancelBooking(object payload, HttpContext httpContext);
Task<object> GetMyBookings(object payload, HttpContext httpContext);
Task<object> GetSessionBookings(object payload, HttpContext httpContext);
}
}
+7
View File
@@ -0,0 +1,7 @@
namespace Fitness_core_BE.Interfaces.Services
{
public interface IBootstrapService
{
Task<object> BootstrapClub(object payload);
}
}
+12
View File
@@ -0,0 +1,12 @@
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IChatService
{
Task<object> GetOrCreateChatAsync(object payload);
Task<object> SendMessageAsync(object payload);
Task<object> GetMessagesAsync(object payload);
Task<bool> CanUserAccessChatAsync(Guid chatId, Guid userId);
}
}
@@ -0,0 +1,14 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IClientInvoiceService
{
Task<object> CreateClientInvoiceFromSubscription(object payload, HttpContext httpContext);
Task<object> GetClientInvoiceById(object payload, HttpContext httpContext);
Task<object> GetClientInvoicesByClientId(object payload, HttpContext httpContext);
Task<object> GetClientInvoicesByUserId(object payload, HttpContext httpContext);
Task<object> UpdateClientInvoiceStatus(object payload, HttpContext httpContext);
Task<object> CalculateClientInvoiceTotal(object payload, HttpContext httpContext);
}
}
@@ -0,0 +1,33 @@
using Fitness_core_BE.DTOs.PlatformBilling;
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
// The gym owner's own card(s) on file for their HexaFitness platform subscription, and
// the transaction history behind those charges — backed by Payment-Service via
// IPaymentGatewayClient, scoped to the caller's own Client (see UserRoleHelper.GetClientId).
public interface IClientPaymentMethodService
{
Task<StartCardOnboardingResult> StartCardOnboardingAsync(
HttpContext httpContext,
StartCardOnboardingRequest request,
CancellationToken ct = default);
Task<CardOnboardingStatusResult> CompleteCardOnboardingAsync(
HttpContext httpContext,
string sessionId,
CancellationToken ct = default);
Task<List<ClientCardDto>> ListCardsAsync(HttpContext httpContext, CancellationToken ct = default);
Task RemoveCardAsync(HttpContext httpContext, string cardToken, CancellationToken ct = default);
Task<ClientCardDto> SetDefaultCardAsync(HttpContext httpContext, string cardToken, CancellationToken ct = default);
Task<TransactionHistoryResult> GetTransactionHistoryAsync(
HttpContext httpContext,
int page,
int pageSize,
CancellationToken ct = default);
}
}
+54
View File
@@ -0,0 +1,54 @@
using Microsoft.AspNetCore.Http;
using Fitness_core_BE.Models.IOs;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IClientService
{
Task<object> GetAllCustomers(object payload, HttpContext httpContext);
Task<object> GetClientList(object payload, HttpContext httpContext);
Task<object> GetClientById(object payload, HttpContext httpContext);
Task<object> UpdateGymProfile(
UpdateGymProfileRequest request, HttpContext httpContext);
// Gym-specific Terms & Conditions authoring (client portal).
Task<object> GetMyGymTerms(object payload, HttpContext httpContext);
Task<object> PublishGymTerms(object payload, HttpContext httpContext);
Task<object> UploadGymLogo(IFormFile logo, HttpContext httpContext);
Task<object> GetGymLogo(HttpContext httpContext);
Task<object> SendContactOtp(object payload, HttpContext httpContext);
Task<object> VerifyContactOtp(object payload, HttpContext httpContext);
Task<object> GetCustomerFullDetails(object payload, HttpContext httpContext);
Task<object> GetCustomerMedical(object payload, HttpContext httpContext);
Task<object> GetCustomerDetailsById(object payload, HttpContext httpContext);
Task<object> CreateCustomerWithPlans(object payload, HttpContext httpContext);
Task<object> UpdateCustomerByClient(object payload, HttpContext httpContext);
Task<object> GetCustomersByClientId(object payload, HttpContext httpContext);
// "Parent" path for a plan-less customer: starts a brand new subscription with them
// as primary. Mirrors CreateCustomerWithPlans' plan-assignment step, callable standalone
// for a customer who was created without a plan.
Task<object> AssignPlanToExistingCustomer(Guid customerId, object payload, HttpContext httpContext);
// Switches a customer with an existing Individual-scope subscription onto a different
// Individual-scope plan: deactivates the old subscription and starts a fresh one.
Task<object> ChangeCustomerMembershipPlan(Guid customerId, Guid newCustomerPlanId, HttpContext httpContext);
Task<object> UnassignCustomerMembership(Guid customerId, HttpContext httpContext);
Task<object> GetCustomerPlansByClientId(object payload, HttpContext httpContext);
Task<object> RegisterClient(object payload, HttpContext httpContext);
Task<object> GetPackageList(object payload, HttpContext httpContext);
Task<object> DeleteCustomerByClient(object payload, HttpContext httpContext);
Task<object> ClientLogOut(object payload, HttpContext httpContext);
Task<object> GetWorkoutPlansByClientId(object payload, HttpContext httpContext);
Task<object> GetWorkoutPlanById(object payload, HttpContext httpContext);
Task<object> GetMealPlansByClientId(object payload, HttpContext httpContext);
Task<object> GetMealPlanById(object payload, HttpContext httpContext);
Task<object> GetAllCustomerPlans(object payload, HttpContext httpContext);
Task<object> GetCustomerPlanById(object payload, HttpContext httpContext);
Task<object> GetCardDetails(object payload, HttpContext httpContext);
// Cards a specific member has saved with this gym (used to offer the auto-charge toggle).
Task<object> GetCustomerCards(object payload, HttpContext httpContext);
// Auto-lock-after-non-payment settings (req 7) — client-configurable.
Task<object> GetLockPolicy(HttpContext httpContext);
Task<object> UpdateLockPolicy(int? lockAfterDaysOverdue, HttpContext httpContext);
}
}
+17
View File
@@ -0,0 +1,17 @@
namespace Fitness_core_BE.Interfaces.Services
{
public interface IClientStatService
{
Task<object> GetTotalCustomerCount(object payload, HttpContext httpContext);
Task<object> GetMonthlyCustomerCount(object payload, HttpContext httpContext);
Task<object> GetTotalWorkoutPlanCount(object payload, HttpContext httpContext);
Task<object> GetTotalMealPlanCount(object payload, HttpContext httpContext);
Task<object> GetLastMonthCustomerCount(object payload, HttpContext httpContext);
Task<object> GetLastFiveAttendances(object payload, HttpContext httpContext);
Task<object> GetLastFivePayments(object payload, HttpContext httpContext);
Task<object> GetLastMonthRevenue(object payload, HttpContext httpContext);
Task<object> GetMonthlyRevenueVariation(object payload, HttpContext httpContext, DateTime? from = null, DateTime? to = null);
Task<object> GetTotalRevenue(object payload, HttpContext httpContext);
Task<object> GetClientStatSummary(object payload, HttpContext httpContext, DateTime? from = null, DateTime? to = null);
}
}
@@ -0,0 +1,14 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface ICustomerInvoiceService
{
Task<object> CreateCustomerInvoiceFromSubscription(object payload, HttpContext httpContext);
Task<object> GetCustomerInvoiceById(object payload, HttpContext httpContext);
Task<object> GetCustomerInvoicesByCustomerId(object payload, HttpContext httpContext);
Task<object> GetCustomerInvoicesByClientId(object payload, HttpContext httpContext);
Task<object> UpdateCustomerInvoiceStatus(object payload, HttpContext httpContext);
Task<object> CalculateCustomerInvoiceTotal(object payload, HttpContext httpContext);
}
}
@@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface ICustomerPlanService
{
Task<object> GetAllCustomerPlans(object payload, HttpContext httpContext);
Task<object> GetCustomerPlanById(object payload, HttpContext httpContext);
Task<object> CreateCustomerPlan(object payload, HttpContext httpContext);
Task<object> UpdateCustomerPlan(object payload, HttpContext httpContext);
/// <summary>Activates or deactivates a plan without touching its configuration.</summary>
Task<object> SetCustomerPlanStatus(object payload, HttpContext httpContext);
Task<object> DeleteCustomerPlan(object payload, HttpContext httpContext);
}
}
+65
View File
@@ -0,0 +1,65 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface ICustomerService
{
Task<object> CreateCustomer(object payload, HttpContext httpContext);
Task<object> CustomerExists(object payload, HttpContext httpContext);
// True when the caller's Customer has verified at least one channel (email/phone).
Task<bool> IsCustomerVerified(HttpContext httpContext);
Task<object> AssignPlansToCustomer(Guid customerId, object payload, HttpContext httpContext);
Task<object> UpdateCustomer(object payload, HttpContext httpContext);
Task<object> DeleteCustomer(object payload, HttpContext httpContext);
Task<object> GetCustomerMealPlan(object payload, HttpContext httpContext);
Task<object> GetCustomerMealPlanById(object payload, HttpContext httpContext);
Task<object> GetFollowedMealPlans(object payload, HttpContext httpContext);
Task<object> GetMyMealPlans(object payload, HttpContext httpContext);
Task<object> GetCustomerWorkOutPlan(object payload, HttpContext httpContext);
Task<object> GetCustomerWorkoutPlanById(object payload, HttpContext httpContext);
Task<object> GetFollowedWorkoutPlans(object payload, HttpContext httpContext);
Task<object> GetMyWorkoutPlans(object payload, HttpContext httpContext);
Task<object> FollowMealPlan(object payload, HttpContext httpContext);
Task<object> FollowWorkOutPlan(object payload, HttpContext httpContext);
Task<object> SetWorkoutExerciseCompletion(Guid workoutPlanId, Guid exerciseId, bool completed, HttpContext httpContext);
Task<object> GetClientDataById(object payload, HttpContext httpContext);
Task<object> GetClientGyms(object payload, HttpContext httpContext);
// QR gym onboarding: list a gym's membership plans, then join by picking one.
Task<object> GetGymPlans(object payload, HttpContext httpContext);
Task<object> JoinGym(object payload, HttpContext httpContext);
// Gym-specific Terms & Conditions: view the gym's active terms and record acceptance.
Task<object> GetGymTerms(object payload, HttpContext httpContext);
Task<object> AcceptGymTerms(object payload, HttpContext httpContext);
Task<byte[]?> GetGymTermsPdf(Guid clientId);
Task<object> CreateCusHealthRec(object payload, HttpContext httpContext);
Task<object> CreateCusProgressRec(object payload, HttpContext httpContext);
Task<object> UpdateCusHealthRec(object payload, HttpContext httpContext);
Task<object> UpdateCusProgressRec(object payload, HttpContext httpContext);
Task<object> UpdateCustomerTargetNutritions(object payload, HttpContext httpContext);
Task<object> GetCusBasicDetails(object payload, HttpContext httpContext);
Task<object> GetCusHealthDetails(object payload, HttpContext httpContext);
Task<object> GetCusProgressDetails(object payload, HttpContext httpContext);
Task<object> GetCustomerProgress(object payload, HttpContext httpContext);
Task<object> UpdateWeeklyProgress(object payload, HttpContext httpContext);
Task<object> GetWeeklyProgressForCustomer(object payload, HttpContext httpContext);
Task<object> CreateFeed(object payload, HttpContext httpContext);
Task<object> GetCardDetails(object payload, HttpContext httpContext);
// Member self-serve auto-deduct: save a card with explicit consent, then opt a
// subscription in/out of being auto-charged against that card.
Task<object> SaveCard(object payload, HttpContext httpContext);
Task<object> SetAutoCharge(Guid subscriptionId, object payload, HttpContext httpContext);
// Lets the mobile app find the caller's active subscription id to target SetAutoCharge.
Task<object> GetMySubscription(object payload, HttpContext httpContext);
Task<object> GetMyGym(object payload, HttpContext httpContext);
Task<object> UnfollowMyGym(object payload, HttpContext httpContext);
Task<object> MyPayment(object payload, HttpContext httpContext);
// In-app Notification tab: history of assignment/feed pushes sent to this customer.
Task<object> GetMyNotifications(object payload, HttpContext httpContext);
Task<object> MarkNotificationRead(Guid notificationId, HttpContext httpContext);
// Refreshes the stored Expo push token (called at login, since a token can rotate).
Task<object> UpdatePushToken(object payload, HttpContext httpContext);
// Links an already-uploaded document (POST /customer/documents) as this customer's
// profile picture.
Task<object> UpdateProfileImage(object payload, HttpContext httpContext);
}
}
@@ -0,0 +1,22 @@
using Fitness_core_BE.DTOs.CustomerSubscription;
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface ICustomerSubscriptionService
{
Task<object> CreateCustomerSubscription(object payload, HttpContext httpContext);
Task<object> GetCustomerSubscriptionById(object payload, HttpContext httpContext);
Task<object> GetCustomerSubscriptionsByCustomerId(object payload, HttpContext httpContext);
Task<object> GetActiveSubscriptionByCustomerId(object payload, HttpContext httpContext);
Task<object> GetSubscriptionSummary(object payload, HttpContext httpContext);
Task<object> AddMemberToSubscription(object payload, HttpContext httpContext);
Task<object> RemoveMemberFromSubscription(object payload, HttpContext httpContext);
Task<List<SubscriptionSummaryDto>> BuildSummariesForCustomerAsync(Guid customerId);
// Optional extra fees on a subscription (req 6 — e.g. coaching fee, once or recurring).
Task<List<CustomerSubItemDto>> GetExtraFeesAsync(Guid subscriptionId, HttpContext httpContext);
Task<object> AddExtraFeeAsync(Guid subscriptionId, AddExtraFeeRequest request, HttpContext httpContext);
}
}
+14
View File
@@ -0,0 +1,14 @@
using Fitness_core_BE.DTOs;
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IDocumentService
{
Task<object> UploadDocument(object payload, HttpContext httpContext);
Task<object> GetDocumentsByUserId(object payload, HttpContext httpContext);
Task<object> GetDocumentById(object payload, HttpContext httpContext);
Task<object> RemoveDocument(object payload, HttpContext httpContext);
Task<DocumentDownloadModel> GetFileBytesById(int documentId);
}
}
+16
View File
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IFacilityService
{
Task<object> GetAllFacilities(object payload, HttpContext httpContext);
Task<object> CreateFacility(object payload, HttpContext httpContext);
Task<object> UpdateFacility(object payload, HttpContext httpContext);
Task<object> SetFacilityStatus(object payload, HttpContext httpContext);
Task<object> CreateFacilitySession(object payload, HttpContext httpContext);
Task<object> GetSessions(object payload, HttpContext httpContext);
Task<object> CancelFacilitySession(object payload, HttpContext httpContext);
}
}
+17
View File
@@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IFeedService
{
Task<object> GetFeedPostById(object payload, HttpContext httpContext);
Task<object> GetFeedForCustomer(object payload, HttpContext httpContext);
Task<object> LikeAsync(object payload, HttpContext httpContext);
Task<object> IsLikedAsync(object payload, HttpContext httpContext);
Task<object> UnlikeAsync(object payload, HttpContext httpContext);
Task<object> CreateFeed(object payload, HttpContext httpContext);
Task<object> ShowFeedByClient(object payload, HttpContext httpContext);
Task<object> DeleteFeedByPostId(object payload, HttpContext httpContext);
}
}
+19
View File
@@ -0,0 +1,19 @@
using Fitness_core_BE.DTOs.Rbac;
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
// Owner-only role CRUD + staff-role assignment. Every method resolves the caller via
// UserRoleHelper.GetClientId directly and never consults IPermissionService/GymRolePermission —
// this is what makes role management immune to staff self-escalation: no nav-section
// permission can ever unlock these methods for a staff account.
public interface IGymRoleService
{
Task<List<GymRoleDto>> GetRolesAsync(HttpContext httpContext);
Task<GymRoleDto> CreateRoleAsync(CreateGymRoleRequest request, HttpContext httpContext);
Task<GymRoleDto> UpdateRoleAsync(Guid gymRoleId, UpdateGymRoleRequest request, HttpContext httpContext);
Task DeleteRoleAsync(Guid gymRoleId, HttpContext httpContext);
Task<GymRoleDto> SetRolePermissionsAsync(Guid gymRoleId, SetRolePermissionsRequest request, HttpContext httpContext);
Task AssignStaffRoleAsync(Guid staffId, AssignStaffRoleRequest request, HttpContext httpContext);
}
}
+21
View File
@@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IMealService
{
Task<object> GetMealCategoryList(object payload, HttpContext httpContext);
Task<object> CreateMealCategory(object payload, HttpContext httpContext);
Task<object> GetMealPlanList(object payload, HttpContext httpContext);
Task<object> GetMealPlanById(object payload, HttpContext httpContext);
Task<object> GetMealPlanByCustomerId(object payload, HttpContext httpContext);
Task<object> CreateMealPlan(object payload, HttpContext httpContext);
Task<object> CreateCustomerMealPlan(object payload, HttpContext httpContext);
Task<object> GetMealItemsByMealPlanId(object payload, HttpContext httpContext);
Task<object> CreateMealItem(object payload, HttpContext httpContext);
Task<object> UpdateMealPlan(object payload, HttpContext httpContext);
Task<object> DeleteMealPlan(object payload, HttpContext httpContext);
Task<object> AssignMealToCustomer(object payload, HttpContext httpContext);
Task<object> UnassignMealFromCustomer(object payload, HttpContext httpContext);
}
}
@@ -0,0 +1,9 @@
using Fitness_core_BE.DTOs.Rbac;
namespace Fitness_core_BE.Interfaces.Services
{
public interface INavigationService
{
Task<NavResponseDto> GetNavigationAsync(HttpContext httpContext);
}
}
@@ -0,0 +1,26 @@
using Fitness_core_BE.DTOs.PaymentGateways;
namespace Fitness_core_BE.Interfaces.Services
{
// Server-to-server client for Payment-Service's HMAC-signed, per-platform routes
// (Controllers/v1/CardsController.cs, PaymentsController.cs, RefundsController.cs there).
// Distinct from IPaymentServiceClient, which calls the X-Internal-Key admin/catalog surface.
// Every method here is scoped to one gym client and lazily provisions that client's
// Payment-Service Platform on first use (see PaymentGatewayClient.EnsureCredentialsAsync).
public interface IPaymentGatewayClient
{
Task<OnboardCardResult> OnboardCardAsync(Guid clientId, OnboardCardRequest request, CancellationToken ct = default);
Task<CardDetailsResult> GetCardDetailsAsync(Guid clientId, string cardToken, CancellationToken ct = default);
Task<IReadOnlyCollection<CardDetailsResult>> ListCardsAsync(Guid clientId, string customerId, CancellationToken ct = default);
Task DeactivateCardAsync(Guid clientId, string cardToken, CancellationToken ct = default);
Task<SetDefaultCardResult> SetDefaultCardAsync(Guid clientId, string cardToken, string customerId, CancellationToken ct = default);
/// <summary>Polls a hosted-page onboarding started earlier (CardToken is empty until
/// the gateway's webhook completes it — see Payment-Service's CardService).</summary>
Task<OnboardCardResult> GetOnboardingStatusAsync(Guid clientId, string gatewayName, string sessionId, CancellationToken ct = default);
Task<AttemptPaymentResult> AttemptPaymentAsync(Guid clientId, AttemptPaymentRequest request, CancellationToken ct = default);
Task<RefundPaymentResult> RefundPaymentAsync(Guid clientId, Guid paymentId, bool isVoid, CancellationToken ct = default);
Task<PaymentListResult> ListPaymentsAsync(Guid clientId, string? cardToken, int page, int pageSize, CancellationToken ct = default);
}
}
+24
View File
@@ -0,0 +1,24 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IPaymentService
{
Task<object> CreateCustomerPayment(object payload, HttpContext httpContext);
Task<object> CreateClientPayment(object payload, HttpContext httpContext);
Task<object> GetPaymentById(object payload, HttpContext httpContext);
Task<object> GetPaymentsByCustomerInvoice(object payload, HttpContext httpContext);
Task<object> GetPaymentsByClientInvoice(object payload, HttpContext httpContext);
Task<object> ApprovePayment(object payload, HttpContext httpContext);
Task<object> RecordSubscriptionPayment(object payload, HttpContext httpContext);
Task<object> GetSubscriptionPayments(object payload, HttpContext httpContext);
// "Charge now": owner-triggered attempt against the member's consented auto-charge card.
Task<object> AttemptAutoCharge(Guid customerInvoiceId, HttpContext httpContext);
// Emails/texts the member a link to pay the invoice online themselves.
Task<object> SendPaymentLink(Guid customerInvoiceId, HttpContext httpContext);
// Public pay-by-link surface (token proves authorization; no logged-in session).
Task<object> GetInvoiceByPaymentToken(string token);
Task<object> ChargeInvoiceByPaymentToken(string token, object payload);
}
}
@@ -0,0 +1,19 @@
using Fitness_core_BE.DTOs.PaymentGateways;
namespace Fitness_core_BE.Interfaces.Services
{
// Server-to-server client for Payment-Service's internal-key-protected admin
// routes (Controllers/v1/GatewaysController.cs, PlatformsController.cs there).
public interface IPaymentServiceClient
{
Task<List<GatewayDefinitionDto>> ListGatewaysAsync(CancellationToken cancellationToken = default);
Task<GatewayDefinitionDto> UpsertGatewayAsync(UpsertGatewayDefinitionRequest request, CancellationToken cancellationToken = default);
Task<GatewayDefinitionDto> SetGatewayEnabledAsync(Guid id, bool isEnabled, CancellationToken cancellationToken = default);
Task UpsertPlatformCredentialAsync(UpsertPlatformGatewayCredentialRequest request, CancellationToken cancellationToken = default);
// Mints (or returns) the Payment-Service Platform for a client; call once at
// client activation and store the returned PlatformId on Client.FKPaymentPlatformId.
Task<(Guid PlatformId, string ApiKey, string HmacSecret)> ProvisionPlatformAsync(
Guid clientId, string displayName, CancellationToken cancellationToken = default);
}
}
@@ -0,0 +1,20 @@
using Fitness_core_BE.DTOs.PaymentsEnablement;
using Fitness_core_BE.DTOs.PaymentGateways;
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IPaymentsEnablementService
{
Task<List<PaymentTrackOption>> GetTrackOptionsAsync();
Task<PaymentTrackSelectionResult> SelectTrackAsync(HttpContext httpContext, SelectPaymentTrackRequest request);
Task<List<GatewayDefinitionDto>> GetAvailableGatewaysAsync(CancellationToken ct = default);
Task<ClientPayoutKycDto> SubmitKycAsync(
HttpContext httpContext,
SubmitGatewayOnboardingRequest request,
CancellationToken ct = default);
Task<GatewayOnboardingStatusDto> GetKycStatusAsync(HttpContext httpContext);
Task<WalletDto> GetWalletAsync(HttpContext httpContext);
Task<PayoutScheduleDto> GetPayoutScheduleAsync(HttpContext httpContext);
}
}
@@ -0,0 +1,12 @@
using Fitness_core_BE.DTOs.PaymentsEnablement;
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IPayoutKycReviewService
{
Task<List<ClientPayoutKycDto>> ListAsync(string? status);
Task<ClientPayoutKycDto> GetByClientIdAsync(Guid clientId);
Task<ClientPayoutKycDto> ReviewAsync(Guid clientId, ReviewPayoutKycRequest request, HttpContext httpContext);
}
}
+13
View File
@@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public record PermissionContext(bool IsOwner, Guid? ClientId, Guid? StaffId, IReadOnlySet<string> AllowedNavKeys);
public interface IPermissionService
{
// Single shared source of truth for "what can this caller see/do" — used by both
// RequiresPermissionAttribute and NavController so they can never drift apart.
Task<PermissionContext> GetPermissionContextAsync(HttpContext httpContext);
}
}
+13
View File
@@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IPlaceService
{
Task<object> GetAllPlaces(object payload, HttpContext httpContext);
Task<object> CreatePlace(object payload, HttpContext httpContext);
Task<object> UpdatePlace(object payload, HttpContext httpContext);
Task<object> SetPlaceStatus(object payload, HttpContext httpContext);
Task<object> AssignDevice(object payload, HttpContext httpContext);
}
}
@@ -0,0 +1,28 @@
using Fitness_core_BE.DTOs.PlatformBilling;
using Fitness_core_BE.Models;
namespace Fitness_core_BE.Interfaces.Services
{
// Computes and generates the platform's own bill to a gym ("Client"): a per-active-member
// SaaS fee (with minimum/cap), device rental, and one-time setup fees. Distinct from
// CustomerInvoice/CustomerSubscription, which is the gym billing its own members.
public interface IPlatformBillingService
{
Task<List<PricingPlanDto>> GetPricingPlansAsync(CancellationToken ct = default);
Task<PricingPlanDto> UpsertPricingPlanAsync(UpsertPricingPlanRequest request, CancellationToken ct = default);
Task<DevicePricingDto> GetDevicePricingAsync(CancellationToken ct = default);
Task<DevicePricingDto> UpdateDevicePricingAsync(DevicePricingDto request, CancellationToken ct = default);
Task<Models.ClientInvoice> AssignPricingPlanAsync(Guid clientId, AssignPricingPlanRequest request, CancellationToken ct = default);
Task<PlatformFeeBreakdownDto> ComputeMonthlyFeeAsync(Guid clientId, CancellationToken ct = default);
Task<Models.ClientInvoice> GenerateMonthlyInvoiceAsync(Guid clientId, CancellationToken ct = default);
Task<Models.ClientInvoice> GenerateOnboardingInvoiceAsync(Guid clientId, CancellationToken ct = default);
Task<List<Models.ClientInvoice>> RunMonthlyBillingForAllClientsAsync(CancellationToken ct = default);
Task<SubscriptionChargeRunResult> RunAndChargeSubscriptionBillingAsync(CancellationToken ct = default);
Task<List<PendingPlatformInvoiceDto>> GetPendingInvoicesAsync(CancellationToken ct = default);
Task<List<PendingPlatformInvoiceDto>> GetCompletedInvoicesAsync(CancellationToken ct = default);
Task<PendingPlatformInvoiceDto> RecordClientInvoicePaymentAsync(Guid clientInvoiceId, decimal amount, CancellationToken ct = default);
Task<object> SendClientPaymentLinkAsync(Guid clientInvoiceId, CancellationToken ct = default);
}
}
+16
View File
@@ -0,0 +1,16 @@
using Fitness_core_BE.DTOs.Ledger;
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
// Basic P&L / ledger for the client portal. Derives income (approved member payments)
// and expenses (platform fees paid, staff payroll) from existing tables, and merges in
// manual ledger entries (LedgerEntry) for anything else (rent, utilities, misc income).
public interface IProfitLossService
{
Task<ProfitLossDto> GetProfitLossAsync(DateTime from, DateTime to, HttpContext httpContext);
Task<List<LedgerEntryDto>> GetManualEntriesAsync(DateTime from, DateTime to, HttpContext httpContext);
Task<LedgerEntryDto> AddManualEntryAsync(AddLedgerEntryRequest request, HttpContext httpContext);
Task DeleteManualEntryAsync(Guid id, HttpContext httpContext);
}
}
@@ -0,0 +1,25 @@
namespace Fitness_core_BE.Interfaces.Services
{
public interface IPushNotificationService
{
// Persists a CustomerNotification row (for the mobile Notification tab) and, if the
// customer has a registered Expo push token, sends a real push too. routeName/routeParams
// mirror the mobile app's PushNavigationData contract (pushNotification.ts) so tapping
// either the push or the in-app list item navigates the same way.
Task NotifyCustomerAsync(
Guid customerId,
string title,
string body,
string notificationType,
string? routeName = null,
object? routeParams = null);
Task NotifyCustomersAsync(
IEnumerable<Guid> customerIds,
string title,
string body,
string notificationType,
string? routeName = null,
object? routeParams = null);
}
}
+20
View File
@@ -0,0 +1,20 @@
using Fitness_core_BE.Models.Receipt;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IReceiptService
{
/// <summary>Gathers member/plan/gym/amount data for a member invoice.
/// When <paramref name="requireClientId"/> is set, throws if the invoice isn't that gym's.</summary>
Task<ReceiptModel> BuildForInvoiceAsync(Guid customerInvoiceId, decimal? paymentAmount = null, Guid? requireClientId = null);
/// <summary>Gathers gym/amount data for a platform (HexaFitness -> gym) invoice.
/// When <paramref name="requireClientId"/> is set, throws if the invoice isn't that gym's.</summary>
Task<ReceiptModel> BuildForClientInvoiceAsync(Guid clientInvoiceId, decimal? paymentAmount = null, Guid? requireClientId = null);
byte[] GeneratePdf(ReceiptModel model);
/// <summary>Best-effort: emails the receipt PDF and texts the member. Never throws.</summary>
Task SendReceiptAsync(ReceiptModel model);
}
}
+20
View File
@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IStaffService
{
Task<object> GetAllStaff(object payload, HttpContext httpContext);
Task<object> GetStaffById(object payload, HttpContext httpContext);
Task<object> GetStaffByClientId(object payload, HttpContext httpContext);
Task<object> CreateStaff(object payload, HttpContext httpContext);
Task<object> UpdateStaff(object payload, HttpContext httpContext);
Task<object> DeleteStaff(object payload, HttpContext httpContext);
// Basic HRM/payroll (req 5).
Task<object> GetPayRate(Guid staffId, HttpContext httpContext);
Task<object> UpsertPayRate(Guid staffId, string rateType, decimal amount, HttpContext httpContext);
Task<object> GetPayments(Guid staffId, HttpContext httpContext);
Task<object> RecordPayment(Guid staffId, decimal amount, string? note, HttpContext httpContext);
}
}
@@ -0,0 +1,14 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
// Staff-facing approval workflow for the unapproved (IsActive=false) invoices the daily
// SubscriptionRenewalJob sweep creates. See Services/SubscriptionRenewalApprovalService.cs.
public interface ISubscriptionRenewalApprovalService
{
Task<object> GetUnapprovedInvoicesAsync(HttpContext httpContext);
Task<object> ApproveAsync(Guid customerInvoiceId, HttpContext httpContext);
Task<object> ChangePlanAsync(Guid customerInvoiceId, Guid newCustomerPlanId, HttpContext httpContext);
Task<object> RejectAsync(Guid customerInvoiceId, HttpContext httpContext);
}
}
+11
View File
@@ -0,0 +1,11 @@
using Fitness_core_BE.Models.IOs;
namespace Fitness_core_BE.Interfaces.Services
{
/// <summary>Outbound notification channels (SMS + email) — mirrors Core-Hex-Auth's ThirdPartyService.</summary>
public interface IThirdPartyService
{
Task<OtpResponse> SendSmsAsync(string mobileNumber, string? otpCode = null, string? message = null);
Task SendEmailAsync(string toEmail, string subject, string htmlBody, byte[]? attachment = null, string? attachmentName = null);
}
}
+18
View File
@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface ITicketService
{
Task<object> GetTicketList(object payload, HttpContext httpContext);
Task<object> GetTicketByUserId(object payload, HttpContext httpContext);
Task<object> GetTicketById(object payload, HttpContext httpContext);
Task<object> GetTicketCategoryList(object payload, HttpContext httpContext);
Task<object> CreateTicket(object payload, HttpContext httpContext);
Task<object> UpdateTicket(object payload, HttpContext httpContext);
Task<object> SendMessage(object payload, HttpContext httpContext);
Task<object> SubmitTicketFeedback(object payload, HttpContext httpContext);
Task<object> CloseTicket(object payload, HttpContext httpContext);
Task<object> DeleteTicket(object payload, HttpContext httpContext);
}
}
@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface ITimeBankCardService
{
/// <summary>Staff issues/sells a card -- minutes purchased, optionally linked to a member.</summary>
Task<object> IssueCard(object payload, HttpContext httpContext);
/// <summary>The tap-in/tap-out swipe action: first swipe on a card starts its session
/// (no deduction), second swipe ends it and deducts the elapsed minutes. No login
/// required (called by the reader/agent, or by staff at a manual terminal).</summary>
Task<object> Swipe(object payload);
Task<object> GetBalance(object payload);
Task<object> GetMyCards(object payload, HttpContext httpContext);
}
}
+21
View File
@@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Http;
namespace Fitness_core_BE.Interfaces.Services
{
public interface IWorkoutService
{
Task<object> GetWorkoutCategoryList(object payload, HttpContext httpContext);
Task<object> CreateWorkoutCategory(object payload, HttpContext httpContext);
Task<object> GetWorkoutPlanList(object payload, HttpContext httpContext);
Task<object> GetWorkoutPlanById(object payload, HttpContext httpContext);
Task<object> GetWorkoutPlanByCustomerId(object payload, HttpContext httpContext);
Task<object> CreateWorkoutPlan(object payload, HttpContext httpContext);
Task<object> CreateCustomerWorkout(object payload, HttpContext httpContext);
Task<object> UpdateWorkoutPlan(object payload, HttpContext httpContext);
Task<object> DeleteWorkoutPlan(object payload, HttpContext httpContext);
Task<object> GetWorkoutItemsByWorkoutPlanId(object payload, HttpContext httpContext);
Task<object> CreateWorkoutItem(object payload, HttpContext httpContext);
Task<object> AssignWorkoutToCustomer(object payload, HttpContext httpContext);
Task<object> UnassignWorkoutFromCustomer(object payload, HttpContext httpContext);
}
}