using FastEndpoints;
using GB5Shared.DTO.Framework.Login;
using GB5Shared.DTO.Framework.ResponseStandard;
using GB5Shared.FastEndPoint;
using GB5Shared.Telemetry;
using PayRollBLL.SAP;
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using static GB5Shared.GB5Constant.Constant;
namespace PayRollSL.EndPoints.SAP
{
///
/// GET /SAP/PushITDeclarationToSap
/// Pushes IT Declaration data to the SAP HR OData API (infotypes 580–586).
///
/// HTTP 200 — every SAP infotype posting was accepted (IsSuccess = true for all results).
/// HTTP 400 — one or more postings were rejected or had no data to post.
/// HTTP 500 — unexpected server-side exception.
///
/// Pass Infotype = 0 to push all applicable infotypes in one call.
/// The Body array always contains one entry per infotype processed, with full detail
/// on what was sent and what SAP returned — even for failures.
///
public class PushITDeclarationToSap
: BaseEndpoint>
{
private readonly IITDeclarationSapBLL _bll;
public PushITDeclarationToSap(IITDeclarationSapBLL bll) => _bll = bll;
public override void Configure()
{
Get("/SAP/PushITDeclarationToSap");
AllowAnonymous();
}
public record PushITDeclarationToSapParameters(
[property: FromHeader] string Login,
[property: QueryParam] int DeclarationId,
[property: QueryParam] int EmployeeId,
[property: QueryParam] int PeriodId,
[property: QueryParam] int Infotype, // 0 = push all 580–586
[property: QueryParam] string? Date, // dd.MM.yyyy; defaults to today
[property: QueryParam] string? Remarks
);
protected override string? GetCacheKey(PushITDeclarationToSapParameters req, LoginDTO login) => null;
// HandleAsync is overridden directly so the HTTP status code accurately reflects the SAP outcome.
// The base-class HandleAsync always calls SendAsync without a status code (defaults to 200),
// which gives a misleading success signal even when SAP rejects the payload.
// This override sends 200 only when every infotype posting is confirmed successful by SAP.
public override async Task HandleAsync(PushITDeclarationToSapParameters req, CancellationToken ct)
{
using var activity = GB5ActivitySources.Endpoints.StartActivity(
nameof(PushITDeclarationToSap), ActivityKind.Server);
var login = GetLoginDTOFromRequest(req);
if (login != null)
login.RequestUrl =
$"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}{HttpContext.Request.Path}";
string date = string.IsNullOrWhiteSpace(req.Date)
? DateTime.Today.ToString("dd.MM.yyyy")
: req.Date;
try
{
var results = await _bll.PushToSapAsync(
req.DeclarationId,
req.EmployeeId,
req.PeriodId,
req.Infotype,
date,
req.Remarks ?? string.Empty,
login!,
ct);
bool allSucceeded = results.Count > 0 && results.All(r => r.IsSuccess);
if (allSucceeded)
{
activity?.SetTag("gb5.success", true);
activity?.SetTag("http.response.status_code", 200);
activity?.SetStatus(ActivityStatusCode.Ok);
var response = await GB5Shared.ResponseStandard.Response
.CreateSuccessResponse(results, CacheKeyLevel.NOT_REQUIRED, login!);
await Send.ResponseAsync(response, statusCode: 200, cancellation: ct);
}
else
{
string errorSummary = BuildErrorSummary(results);
activity?.SetTag("gb5.success", false);
activity?.SetTag("gb5.app.error", errorSummary);
activity?.SetTag("http.response.status_code", 400);
activity?.SetStatus(ActivityStatusCode.Error, errorSummary);
Logger.LogWarning(
"[PushITDeclarationToSap] SAP push completed with failures. {Summary}", errorSummary);
var response = new ResponseStandardDTO