54 lines
3.5 KiB
C#
54 lines
3.5 KiB
C#
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);
|
|
}
|
|
}
|