-
This commit is contained in:
85
src/Apollinare.Domain/Entities/AppModule.cs
Normal file
85
src/Apollinare.Domain/Entities/AppModule.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
namespace Apollinare.Domain.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Rappresenta un modulo dell'applicazione (es. Magazzino, Acquisti, Vendite).
|
||||
/// I moduli possono essere attivati/disattivati per gestire licenze e funzionalità.
|
||||
/// </summary>
|
||||
public class AppModule : BaseEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// Codice univoco del modulo (es. "warehouse", "purchases", "sales")
|
||||
/// </summary>
|
||||
public required string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Nome visualizzato del modulo (es. "Magazzino", "Acquisti")
|
||||
/// </summary>
|
||||
public required string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Descrizione estesa delle funzionalità del modulo
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Nome dell'icona Material UI (es. "Warehouse", "ShoppingCart")
|
||||
/// </summary>
|
||||
public string? Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Prezzo base annuale del modulo in EUR
|
||||
/// </summary>
|
||||
public decimal BasePrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Moltiplicatore per abbonamento mensile (es. 1.2 = 20% in più rispetto all'annuale/12)
|
||||
/// </summary>
|
||||
public decimal MonthlyMultiplier { get; set; } = 1.2m;
|
||||
|
||||
/// <summary>
|
||||
/// Ordine di visualizzazione nel menu (più basso = prima)
|
||||
/// </summary>
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Se true, il modulo fa parte del core e non può essere disattivato
|
||||
/// </summary>
|
||||
public bool IsCore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Lista di codici modulo prerequisiti separati da virgola (es. "warehouse,purchases")
|
||||
/// </summary>
|
||||
public string? Dependencies { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Path base per le route frontend del modulo (es. "/warehouse")
|
||||
/// </summary>
|
||||
public string? RoutePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Se false, il modulo è nascosto e non disponibile per l'acquisto
|
||||
/// </summary>
|
||||
public bool IsAvailable { get; set; } = true;
|
||||
|
||||
// Navigation property
|
||||
public ModuleSubscription? Subscription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Restituisce la lista dei codici modulo prerequisiti
|
||||
/// </summary>
|
||||
public IEnumerable<string> GetDependencies()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Dependencies))
|
||||
return Enumerable.Empty<string>();
|
||||
|
||||
return Dependencies.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calcola il prezzo mensile basato su BasePrice e MonthlyMultiplier
|
||||
/// </summary>
|
||||
public decimal GetMonthlyPrice()
|
||||
{
|
||||
return Math.Round((BasePrice / 12) * MonthlyMultiplier, 2);
|
||||
}
|
||||
}
|
||||
108
src/Apollinare.Domain/Entities/ModuleSubscription.cs
Normal file
108
src/Apollinare.Domain/Entities/ModuleSubscription.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
namespace Apollinare.Domain.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Tipo di abbonamento per un modulo
|
||||
/// </summary>
|
||||
public enum SubscriptionType
|
||||
{
|
||||
/// <summary>Nessun abbonamento attivo</summary>
|
||||
None = 0,
|
||||
/// <summary>Abbonamento mensile</summary>
|
||||
Monthly = 1,
|
||||
/// <summary>Abbonamento annuale</summary>
|
||||
Annual = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rappresenta lo stato di abbonamento/attivazione di un modulo per questa istanza dell'applicazione.
|
||||
/// Ogni ModuleSubscription è collegata 1:1 con un AppModule.
|
||||
/// </summary>
|
||||
public class ModuleSubscription : BaseEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// ID del modulo associato
|
||||
/// </summary>
|
||||
public int ModuleId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Se true, il modulo è attualmente attivo e accessibile
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tipo di abbonamento corrente
|
||||
/// </summary>
|
||||
public SubscriptionType SubscriptionType { get; set; } = SubscriptionType.None;
|
||||
|
||||
/// <summary>
|
||||
/// Data di inizio dell'abbonamento corrente
|
||||
/// </summary>
|
||||
public DateTime? StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Data di scadenza dell'abbonamento (null = nessuna scadenza, es. licenza perpetua)
|
||||
/// </summary>
|
||||
public DateTime? EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Se true, l'abbonamento si rinnova automaticamente alla scadenza
|
||||
/// </summary>
|
||||
public bool AutoRenew { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Note aggiuntive sull'abbonamento (es. codice ordine, riferimento contratto)
|
||||
/// </summary>
|
||||
public string? Notes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Data dell'ultimo rinnovo effettuato
|
||||
/// </summary>
|
||||
public DateTime? LastRenewalDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Prezzo pagato per l'abbonamento corrente (può differire da BasePrice per sconti)
|
||||
/// </summary>
|
||||
public decimal? PaidPrice { get; set; }
|
||||
|
||||
// Navigation property
|
||||
public AppModule Module { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Verifica se l'abbonamento è attualmente valido (attivo e non scaduto)
|
||||
/// </summary>
|
||||
public bool IsValid()
|
||||
{
|
||||
if (!IsEnabled)
|
||||
return false;
|
||||
|
||||
// Se non c'è data di scadenza, è valido (licenza perpetua o core module)
|
||||
if (!EndDate.HasValue)
|
||||
return true;
|
||||
|
||||
return EndDate.Value >= DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calcola i giorni rimanenti alla scadenza (null se nessuna scadenza)
|
||||
/// </summary>
|
||||
public int? GetDaysRemaining()
|
||||
{
|
||||
if (!EndDate.HasValue)
|
||||
return null;
|
||||
|
||||
var remaining = (EndDate.Value - DateTime.UtcNow).Days;
|
||||
return remaining < 0 ? 0 : remaining;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifica se l'abbonamento sta per scadere (entro i prossimi N giorni)
|
||||
/// </summary>
|
||||
public bool IsExpiringSoon(int daysThreshold = 30)
|
||||
{
|
||||
if (!EndDate.HasValue)
|
||||
return false;
|
||||
|
||||
var daysRemaining = GetDaysRemaining();
|
||||
return daysRemaining.HasValue && daysRemaining.Value <= daysThreshold && daysRemaining.Value > 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user