backend phase 13 & frontend phase 6
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Asp.Versioning;
|
||||
using Baya.Application.Features.Payouts.Commands.ExecutePayoutBatch;
|
||||
using Baya.Application.Features.Payouts.Commands.GeneratePayoutBatch;
|
||||
using Baya.Application.Features.Payouts.Commands.MarkPayoutFailed;
|
||||
using Baya.Application.Features.Payouts.Commands.RetryFailedPayout;
|
||||
using Baya.Application.Features.Payouts.Queries.ComputeEligibleEarnings;
|
||||
using Baya.Application.Features.Payouts.Queries.GetBatchDetail;
|
||||
using Baya.Application.Features.Payouts.Queries.ListPayoutBatches;
|
||||
using Baya.Application.Models.Common;
|
||||
using Baya.Application.Models.Payouts;
|
||||
using Baya.Infrastructure.Identity.Identity.PermissionManager;
|
||||
using Baya.WebFramework.Attributes;
|
||||
using Baya.WebFramework.BaseController;
|
||||
using Baya.WebFramework.ServiceConfiguration;
|
||||
using Mediator;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
|
||||
namespace Baya.Web.Api.Controllers.V1;
|
||||
|
||||
/// <summary>
|
||||
/// Admin payout console: preview eligible earnings, open a draft batch, submit it to the (mocked) PAYA/SATNA
|
||||
/// rail, retry a failed payout, mark a reconciled bank rejection, and read batches. Generating and processing a
|
||||
/// batch move real (mocked) money and are rate-limited as money endpoints. One payout per booking is guaranteed by
|
||||
/// the <c>nurse_payout_booking_links.booking_id</c> UNIQUE; processing is the one irreversible step.
|
||||
/// </summary>
|
||||
[ApiVersion("1")]
|
||||
[ApiController]
|
||||
[Route("api/v{version:apiVersion}/admin_payouts")]
|
||||
[Authorize(ConstantPolicies.DynamicPermission)]
|
||||
[EnableRateLimiting(RateLimitingServiceExtension.SensitivePolicy)]
|
||||
[Display(Description = "Admin payout batches: eligible preview, generate, process, retry, mark-failed, read")]
|
||||
public sealed class AdminPayoutsController(ISender sender) : BaseController
|
||||
{
|
||||
[HttpGet("eligible")]
|
||||
[ProducesOkApiResponseType<PagedResult<EligibleNurseEarningsDto>>]
|
||||
public async Task<IActionResult> Eligible([FromQuery] ComputeEligibleEarningsQuery query, CancellationToken cancellationToken)
|
||||
=> OperationResult(await sender.Send(query, cancellationToken));
|
||||
|
||||
[HttpPost("batches")]
|
||||
[ProducesOkApiResponseType<GeneratePayoutBatchResult>]
|
||||
public async Task<IActionResult> Generate(GeneratePayoutBatchCommand command, CancellationToken cancellationToken)
|
||||
=> OperationResult(await sender.Send(command, cancellationToken));
|
||||
|
||||
[HttpPost("batches/{id}/process")]
|
||||
[ProducesOkApiResponseType<ExecutePayoutBatchResult>]
|
||||
public async Task<IActionResult> Process(long id, CancellationToken cancellationToken)
|
||||
=> OperationResult(await sender.Send(new ExecutePayoutBatchCommand(id), cancellationToken));
|
||||
|
||||
[HttpGet("batches/{id}")]
|
||||
[ProducesOkApiResponseType<PayoutBatchDetailDto>]
|
||||
public async Task<IActionResult> Get(long id, [FromQuery] int page = 1, [FromQuery] int pageSize = 50, CancellationToken cancellationToken = default)
|
||||
=> OperationResult(await sender.Send(new GetBatchDetailQuery(id, page, pageSize), cancellationToken));
|
||||
|
||||
[HttpGet("batches")]
|
||||
[ProducesOkApiResponseType<PagedResult<PayoutBatchDto>>]
|
||||
public async Task<IActionResult> List([FromQuery] ListPayoutBatchesQuery query, CancellationToken cancellationToken)
|
||||
=> OperationResult(await sender.Send(query, cancellationToken));
|
||||
|
||||
[HttpPost("{payoutId}/retry")]
|
||||
[ProducesOkApiResponseType<bool>]
|
||||
public async Task<IActionResult> Retry(long payoutId, CancellationToken cancellationToken)
|
||||
=> OperationResult(await sender.Send(new RetryFailedPayoutCommand(payoutId), cancellationToken));
|
||||
|
||||
[HttpPost("{payoutId}/mark_failed")]
|
||||
[ProducesOkApiResponseType<bool>]
|
||||
public async Task<IActionResult> MarkFailed(long payoutId, MarkPayoutFailedBody body, CancellationToken cancellationToken)
|
||||
=> OperationResult(await sender.Send(new MarkPayoutFailedCommand(payoutId, body.FailureReason), cancellationToken));
|
||||
|
||||
/// <summary>The mark-failed body (the payout id comes from the route).</summary>
|
||||
public record MarkPayoutFailedBody(string FailureReason);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Asp.Versioning;
|
||||
using Baya.Application.Features.Payouts.Queries.GetNursePayoutHistory;
|
||||
using Baya.Application.Models.Common;
|
||||
using Baya.Application.Models.Payouts;
|
||||
using Baya.WebFramework.Attributes;
|
||||
using Baya.WebFramework.BaseController;
|
||||
using Mediator;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Baya.Web.Api.Controllers.V1;
|
||||
|
||||
/// <summary>The signed-in nurse's own payout history — tenancy-scoped to <c>ICurrentUser</c> (a nurse can never
|
||||
/// read another nurse's payouts). Feeds f12's earnings screen: status, net, masked IBAN + transfer reference, and
|
||||
/// any clawback applied.</summary>
|
||||
[ApiVersion("1")]
|
||||
[ApiController]
|
||||
[Route("api/v{version:apiVersion}/nurse_payouts")]
|
||||
[Authorize]
|
||||
[Display(Description = "The signed-in nurse's payout history")]
|
||||
public sealed class NursePayoutsController(ISender sender) : BaseController
|
||||
{
|
||||
[HttpGet("history")]
|
||||
[ProducesOkApiResponseType<PagedResult<NursePayoutHistoryDto>>]
|
||||
public async Task<IActionResult> History([FromQuery] GetNursePayoutHistoryQuery query, CancellationToken cancellationToken)
|
||||
=> OperationResult(await sender.Send(query, cancellationToken));
|
||||
}
|
||||
Reference in New Issue
Block a user