first commit
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Fitness_core_BE.Models;
|
||||
|
||||
namespace Fitness_core_BE.Interfaces
|
||||
{
|
||||
public interface INavItemRepository
|
||||
{
|
||||
Task<List<NavItem>> GetActiveNavItemsOrdered();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Fitness_core_BE.Interfaces.Services
|
||||
{
|
||||
public interface IBootstrapService
|
||||
{
|
||||
Task<object> BootstrapClub(object payload);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user