using EntitlementBLL.Auth; using EntitlementBLL.Interfaces; using EntitlementSL.Common; using FastEndpoints; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Framework.ResponseStandard; using GB5Shared.FastEndPoint; using ErrorResponse = GB5Shared.Resource.Response.ErrorResponse; using static GB5Shared.GB5Constant.Constant; namespace EntitlementSL.Endpoints.ChangeRequest; // Client-facing, capability-gated: a plan change is a commercial/financial decision, so beyond the // base ClientAdmin tier this also requires the COMMERCIAL_ADMIN capability grant (checked against // the JWT's Capabilities claim — no DB round-trip). Submitting a request never mutates the // subscription itself — that only happens once a GOODBOOKS_ADMIN approves it via // ChangeRequestBLL.ApproveChangeRequestAsync. public class RequestChangePlan : BaseEndpoint> { private const string ClientJwtSchemeName = "ClientJwtBearer"; private readonly IChangeRequestBLL _ChangeRequestBLL; public RequestChangePlan(IChangeRequestBLL changeRequestBLL) => _ChangeRequestBLL = changeRequestBLL; public override void Configure() { Post("/lic/ChangeRequest.svc/RequestChangePlan"); AuthSchemes(ClientJwtSchemeName); Roles(ClientRoleCodes.ClientAdmin); } public record Body(int SubscriptionId, int NewPlanId); public record Params( [property: FromHeader] string Login, [property: FromBody] Body RequestBody ); protected override string? GetCacheKey(Params req, LoginDTO loginDTO) => null; protected override async Task> ExecuteAsync(Params req, LoginDTO loginDTO, CancellationToken ct) { var caller = ClientCallerContext.FromClaims(HttpContext.User.Claims); if (caller.Role != ClientRoleCodes.ClientAdmin || caller.ClientId <= 0) return await GB5Shared.ResponseStandard.Response.CreateErrorResponse( ErrorResponse.AccessDeniedMessage, CacheKeyLevel.NOT_REQUIRED, loginDTO, statusCode: 403); if (!caller.HasCapability(EntitlementClientCapabilityCodes.CommercialAdmin)) return await GB5Shared.ResponseStandard.Response.CreateErrorResponse( ErrorResponse.AccessDeniedMessage, CacheKeyLevel.NOT_REQUIRED, loginDTO, statusCode: 403); var changeRequestId = await _ChangeRequestBLL.SubmitChangePlanRequestAsync( caller.ClientId, req.RequestBody.SubscriptionId, req.RequestBody.NewPlanId, caller.ClientUserId, ct); return await GB5Shared.ResponseStandard.Response.CreateSuccessResponse( $"Change request submitted. ChangeRequestId={changeRequestId}", CacheKeyLevel.NOT_REQUIRED, loginDTO); } }