Implement pricing management functionality and update related components
CI / Backend (build + test) (push) Successful in 1m19s
CI / Frontend (lint + typecheck + build) (push) Successful in 32s

- Added new endpoints for managing global pricing settings, including retrieval and updates for `PricePerConfigPerQuarter` and `PricePerConfigPerYear`.
- Updated `RoleService` and related commands to remove pricing fields from role management, ensuring a clear separation between role configurations and global pricing.
- Enhanced the `FactoryResetCommandHandler` to include seeding of pricing settings during a factory reset.
- Modified frontend components to support new pricing settings, including forms for creating and updating pricing information.
- Updated API documentation to reflect changes in pricing management endpoints and their expected request/response formats.
- Adjusted tests to ensure proper coverage for new pricing functionalities and their integration with existing role management features.
This commit is contained in:
Leonid Pershin
2026-07-18 19:34:29 +03:00
parent 285d8180c8
commit ae379f8e0f
54 changed files with 2516 additions and 268 deletions
@@ -8,6 +8,7 @@ using PnvPanel.Domain.Inbounds;
using PnvPanel.Domain.Instructions;
using PnvPanel.Domain.News;
using PnvPanel.Domain.Nodes;
using PnvPanel.Domain.Pricing;
using PnvPanel.Domain.Support;
using PnvPanel.Domain.Telegram;
@@ -45,6 +46,8 @@ public interface IAppDbContext
DbSet<InstructionTab> InstructionTabs { get; }
DbSet<PricingSettings> PricingSettings { get; }
/// <summary>Нужен для advisory-lock при проверке квоты конфигов (см. CreateVpnConfigCommandHandler).</summary>
DatabaseFacade Database { get; }
@@ -0,0 +1,10 @@
namespace PnvPanel.Application.Common.Interfaces;
/// <summary>
/// Сидинг дефолтной (пустой) строки глобальных настроек цены. Идемпотентно — не трогает таблицу, если
/// в ней уже есть строка (используется и при старте, и после полного сброса панели).
/// </summary>
public interface IPricingSettingsSeeder
{
Task SeedIfEmptyAsync(CancellationToken cancellationToken);
}
@@ -2,15 +2,7 @@ using PnvPanel.Application.Common.Models;
namespace PnvPanel.Application.Common.Interfaces;
public sealed record RoleDto(
Guid Id,
string Name,
int MaxConfigs,
int MaxIpLimit,
bool IsSystem,
int? PricePerConfigPerQuarter = null,
int? PricePerConfigPerYear = null
);
public sealed record RoleDto(Guid Id, string Name, int MaxConfigs, int MaxIpLimit, bool IsSystem);
public interface IRoleService
{
@@ -18,8 +10,6 @@ public interface IRoleService
string name,
int maxConfigs,
int maxIpLimit,
int? pricePerConfigPerQuarter,
int? pricePerConfigPerYear,
CancellationToken cancellationToken
);
@@ -27,8 +17,6 @@ public interface IRoleService
Guid roleId,
int maxConfigs,
int maxIpLimit,
int? pricePerConfigPerQuarter,
int? pricePerConfigPerYear,
CancellationToken cancellationToken
);