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 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 CreateRenewalInvoiceAsync( Guid subscriptionId, decimal carriedOverBalance, CancellationToken ct = default); Task GetInvoiceBySubscriptionIdAsync(Guid subscriptionId); Task GetCustomerInvoiceById(Guid customerInvoiceId); Task> GetCustomerInvoicesByCustomerId(Guid customerId); Task> GetCustomerInvoicesByClientId(Guid clientId); Task UpdateCustomerInvoiceStatus(Guid customerInvoiceId, string status); // Renewal-approval workflow. Task> 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 HasPendingApprovalInvoiceAsync(Guid subscriptionId); Task> 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> GetCarriedForwardAmountsAsync(List 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 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 CreatePlanChangeInvoiceAsync( Guid subscriptionId, string itemName, decimal amount, CancellationToken ct = default); Task GetApprovedPaymentTotalAsync(Guid invoiceId, CancellationToken ct = default); } }