Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions TransactionProcessorACL.BusinessLogic.Tests/MediatorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public MediatorTests()
this.Requests.Add(TestData.GetMerchantScheduleQuery);
this.Requests.Add(TestData.GetMerchantDailyPerformanceSummaryQuery);
this.Requests.Add(TestData.GetMerchantTransactionMixSummaryQuery);
this.Requests.Add(TestData.GetRecentActivityReceiptSearchQuery);
}

[Fact]
Expand Down Expand Up @@ -177,5 +178,12 @@ public async Task<Result<MerchantTransactionMixSummaryResponse>> GetMerchantTran
{
return Result.Success(new MerchantTransactionMixSummaryResponse());
}

public async Task<Result<RecentActivityReceiptSearchResponse>> GetRecentActivityReceiptSearch(Guid estateId,
RecentActivityReceiptSearchRequest request,
CancellationToken cancellationToken)
{
return Result.Success(new RecentActivityReceiptSearchResponse());
}
}
}
29 changes: 29 additions & 0 deletions TransactionProcessorACL.BusinessLogic.Tests/RequestHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,35 @@ public async Task ReportingRequestHandler_GetMerchantDailyPerformanceSummaryQuer
result.Data.ShouldNotBeNull();
}

[Fact]
public async Task ReportingRequestHandler_GetRecentActivityReceiptSearchQuery_Handle_RequestIsHandled()
{
Mock<ITransactionProcessorACLApplicationService> applicationService = new Mock<ITransactionProcessorACLApplicationService>();
applicationService
.Setup(a => a.GetRecentActivityReceiptSearch(It.IsAny<Guid>(),
It.IsAny<RecentActivityReceiptSearchRequest>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(new RecentActivityReceiptSearchResponse());

ReportingRequestHandler requestHandler = new ReportingRequestHandler(applicationService.Object);

ReportingQueries.GetRecentActivityReceiptSearchQuery query = new(
TestData.EstateId,
new RecentActivityReceiptSearchRequest
{
MerchantReportingId = 12345,
ReportDate = new DateTime(2026, 7, 8),
SearchText = "abc",
PageNumber = 2,
PageSize = 5
});

Result<RecentActivityReceiptSearchResponse> result = await requestHandler.Handle(query, CancellationToken.None);

result.IsSuccess.ShouldBeTrue();
result.Data.ShouldNotBeNull();
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -699,5 +699,86 @@ public async Task TransactionProcessorACLApplicationService_GetMerchantTransacti
capturedRequest.MerchantReportingId.ShouldBe(12345);
//capturedRequest.Breakdown.ShouldBe(RequestTransactionMixBreakdown.Product);
}

[Fact]
public async Task TransactionProcessorACLApplicationService_GetRecentActivityReceiptSearch_ReturnedFromEstateReportingClient()
{
TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects.RecentActivityReceiptSearchRequest capturedRequest = null;
estateReportingApiClient
.Setup(v => v.GetRecentActivityReceiptSearch(It.IsAny<String>(), It.IsAny<Guid>(), It.IsAny<TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects.RecentActivityReceiptSearchRequest>(), It.IsAny<CancellationToken>()))
.Callback<String, Guid, TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects.RecentActivityReceiptSearchRequest, CancellationToken>((_, _, request, _) => capturedRequest = request)
.ReturnsAsync(Result.Success(new TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects.RecentActivityReceiptSearchResponse
{
ReportDate = new DateTime(2026, 7, 8),
PageNumber = 2,
PageSize = 5,
TotalCount = 1,
Items =
[
new TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects.RecentActivityReceiptSearchItem
{
Reference = "REF-1",
TransactionType = "SALE",
Product = "Product 1",
Operator = "Operator 1",
Status = "Completed",
Amount = 42.75M,
TransactionDateTime = new DateTime(2026, 7, 8, 10, 30, 0),
ReceiptReference = "RCPT-1"
}
]
}));
securityServiceClient.Setup(s => s.GetToken(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.TokenResponse));

Result<RecentActivityReceiptSearchResponse> result = await applicationService.GetRecentActivityReceiptSearch(
TestData.EstateId,
new RecentActivityReceiptSearchRequest
{
MerchantReportingId = 12345,
ReportDate = new DateTime(2026, 7, 8),
SearchText = "abc",
PageNumber = 2,
PageSize = 5
},
CancellationToken.None);

result.IsSuccess.ShouldBeTrue();
result.Data.ShouldNotBeNull();
result.Data.Items.Count.ShouldBe(1);
result.Data.Items[0].ReceiptReference.ShouldBe("RCPT-1");
capturedRequest.ShouldNotBeNull();
capturedRequest.MerchantReportingId.ShouldBe(12345);
capturedRequest.ReportDate.ShouldBe(new DateTime(2026, 7, 8));
capturedRequest.SearchText.ShouldBe("abc");
capturedRequest.PageNumber.ShouldBe(2);
capturedRequest.PageSize.ShouldBe(5);
}

[Fact]
public async Task TransactionProcessorACLApplicationService_GetRecentActivityReceiptSearch_BlankSearchTextIsNotForwarded()
{
TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects.RecentActivityReceiptSearchRequest capturedRequest = null;
estateReportingApiClient
.Setup(v => v.GetRecentActivityReceiptSearch(It.IsAny<String>(), It.IsAny<Guid>(), It.IsAny<TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects.RecentActivityReceiptSearchRequest>(), It.IsAny<CancellationToken>()))
.Callback<String, Guid, TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects.RecentActivityReceiptSearchRequest, CancellationToken>((_, _, request, _) => capturedRequest = request)
.ReturnsAsync(Result.Success(new TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects.RecentActivityReceiptSearchResponse()));
securityServiceClient.Setup(s => s.GetToken(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.TokenResponse));

Result<RecentActivityReceiptSearchResponse> result = await applicationService.GetRecentActivityReceiptSearch(
TestData.EstateId,
new RecentActivityReceiptSearchRequest
{
MerchantReportingId = 12345,
ReportDate = new DateTime(2026, 7, 8),
SearchText = " ",
PageNumber = 1,
PageSize = 5
},
CancellationToken.None);

result.IsSuccess.ShouldBeTrue();
capturedRequest.ShouldNotBeNull();
capturedRequest.SearchText.ShouldBeNull();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;

namespace TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects;

public class RecentActivityReceiptSearchRequest
{
public string? ApplicationVersion { get; set; }

public int? MerchantReportingId { get; set; }

public DateTime ReportDate { get; set; }

public string? SearchText { get; set; }

public int PageNumber { get; set; } = 1;

public int PageSize { get; set; } = 5;
}

public class RecentActivityReceiptSearchResponse
{
public DateTime ReportDate { get; set; }

public int PageNumber { get; set; }

public int PageSize { get; set; }

public int TotalCount { get; set; }

public List<RecentActivityReceiptSearchItem> Items { get; set; } = [];
}

public class RecentActivityReceiptSearchItem
{
public string? Reference { get; set; }

public string? TransactionType { get; set; }

public string? Product { get; set; }

public string? Operator { get; set; }

public string? Status { get; set; }

public decimal Amount { get; set; }

public DateTime TransactionDateTime { get; set; }

public string? ReceiptReference { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,35 @@ public async Task<Result<TransactionMixSummaryResponse>> GetMerchantTransactionM
}
}

public async Task<Result<RecentActivityReceiptSearchResponse>> GetRecentActivityReceiptSearch(String accessToken,
Guid estateId,
RecentActivityReceiptSearchRequest request,
CancellationToken cancellationToken)
{
string requestUri = this.BuildRequestUrl("/api/transactions/recentactivityreceiptreport");

try
{
List<(string headerName, string headerValue)> additionalHeaders =
[
(EstateIdHeaderName, estateId.ToString())
];

Result<RecentActivityReceiptSearchResponse> result =
await this.Post<RecentActivityReceiptSearchRequest, RecentActivityReceiptSearchResponse>(requestUri, request, accessToken, additionalHeaders, cancellationToken);

if (result.IsFailed)
return ResultHelpers.CreateFailure(result);

return result;
}
catch (Exception ex)
{
Exception exception = new($"Error getting recent activity receipt search for estate {estateId}.", ex);
return Result.Failure(exception.Message);
}
}

private string BuildRequestUrl(string relativePath)
{
string baseAddress = this.BaseAddressResolver("EstateReportingApi");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,9 @@ Task<Result<TransactionMixSummaryResponse>> GetMerchantTransactionMixSummary(Str
Guid estateId,
TransactionMixSummaryRequest request,
CancellationToken cancellationToken);

Task<Result<RecentActivityReceiptSearchResponse>> GetRecentActivityReceiptSearch(String accessToken,
Guid estateId,
RecentActivityReceiptSearchRequest request,
CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ namespace TransactionProcessorACL.BusinessLogic.RequestHandlers;

public class ReportingRequestHandler :
IRequestHandler<ReportingQueries.GetMerchantDailyPerformanceSummaryQuery, Result<MerchantDailyPerformanceSummaryResponse>>,
IRequestHandler<ReportingQueries.GetMerchantTransactionMixSummaryQuery, Result<MerchantTransactionMixSummaryResponse>>
IRequestHandler<ReportingQueries.GetMerchantTransactionMixSummaryQuery, Result<MerchantTransactionMixSummaryResponse>>,
IRequestHandler<ReportingQueries.GetRecentActivityReceiptSearchQuery, Result<RecentActivityReceiptSearchResponse>>
{
private readonly ITransactionProcessorACLApplicationService ApplicationService;

Expand All @@ -31,4 +32,10 @@ public async Task<Result<MerchantTransactionMixSummaryResponse>> Handle(Reportin
{
return await this.ApplicationService.GetMerchantTransactionMixSummary(request.EstateId, request.Request, cancellationToken);
}

public async Task<Result<RecentActivityReceiptSearchResponse>> Handle(ReportingQueries.GetRecentActivityReceiptSearchQuery request,
CancellationToken cancellationToken)
{
return await this.ApplicationService.GetRecentActivityReceiptSearch(request.EstateId, request.Request, cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ public record GetMerchantDailyPerformanceSummaryQuery(Guid EstateId,
public record GetMerchantTransactionMixSummaryQuery(Guid EstateId,
MerchantTransactionMixSummaryRequest Request)
: IRequest<Result<MerchantTransactionMixSummaryResponse>>;

public record GetRecentActivityReceiptSearchQuery(Guid EstateId,
RecentActivityReceiptSearchRequest Request)
: IRequest<Result<RecentActivityReceiptSearchResponse>>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,9 @@ Task<Result<MerchantDailyPerformanceSummaryResponse>> GetMerchantDailyPerformanc
Task<Result<MerchantTransactionMixSummaryResponse>> GetMerchantTransactionMixSummary(Guid estateId,
MerchantTransactionMixSummaryRequest request,
CancellationToken cancellationToken);

Task<Result<RecentActivityReceiptSearchResponse>> GetRecentActivityReceiptSearch(Guid estateId,
RecentActivityReceiptSearchRequest request,
CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,52 @@ public async Task<Result<MerchantTransactionMixSummaryResponse>> GetMerchantTran
return response;
}

public async Task<Result<RecentActivityReceiptSearchResponse>> GetRecentActivityReceiptSearch(Guid estateId,
RecentActivityReceiptSearchRequest request,
CancellationToken cancellationToken)
{
Result<TokenResponse> accessTokenResult = await this.GetAccessToken(cancellationToken);
if (accessTokenResult.IsFailed) {
return ResultHelpers.CreateFailure(accessTokenResult);
}

var apiRequest = new BackendAPI.DataTransferObjects.RecentActivityReceiptSearchRequest
{
MerchantReportingId = request.MerchantReportingId,
ReportDate = request.ReportDate.Date,
SearchText = string.IsNullOrWhiteSpace(request.SearchText) ? null : request.SearchText.Trim(),
PageNumber = request.PageNumber,
PageSize = request.PageSize
};

TokenResponse accessToken = accessTokenResult.Data;
var apiResponse = await this.EstateReportingApiClient.GetRecentActivityReceiptSearch(accessToken.AccessToken, estateId, apiRequest, cancellationToken);

if (apiResponse.IsFailed)
return ResultHelpers.CreateFailure(apiResponse);

RecentActivityReceiptSearchResponse response = new()
{
ReportDate = apiResponse.Data.ReportDate,
PageNumber = apiResponse.Data.PageNumber,
PageSize = apiResponse.Data.PageSize,
TotalCount = apiResponse.Data.TotalCount,
Items = apiResponse.Data.Items.Select(i => new RecentActivityReceiptSearchItem
{
Amount = i.Amount,
Operator = i.Operator,
Product = i.Product,
Reference = i.Reference,
ReceiptReference = i.ReceiptReference,
Status = i.Status,
TransactionDateTime = i.TransactionDateTime,
TransactionType = i.TransactionType
}).ToList()
};

return response;
}

private static ProcessReconciliationResponse CreateProcessReconciliationResponse(ReconciliationResponse reconciliationResponse)
{
return new ProcessReconciliationResponse
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Diagnostics.CodeAnalysis;

namespace TransactionProcessorACL.DataTransferObjects.Requests;

[ExcludeFromCodeCoverage]
public class RecentActivityReceiptSearchRequest
{
public string ApplicationVersion { get; set; }

public int MerchantReportingId { get; set; }

public DateTime ReportDate { get; set; }

public string? SearchText { get; set; }

public int PageNumber { get; set; } = 1;

public int PageSize { get; set; } = 5;
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,6 @@ public async Task StartSystem()
DockerServices.SqlServer | DockerServices.TestHost | DockerServices.TransactionProcessor |
DockerServices.TransactionProcessorAcl | DockerServices.EstateReporting;

if (this.ScenarioContext.ScenarioInfo.Tags.Any(tag => tag.Equals("reporting", StringComparison.OrdinalIgnoreCase)))
{
dockerServices |= DockerServices.EstateReporting;
}

this.TestingContext.DockerHelper = new DockerHelper();
this.TestingContext.DockerHelper.Logger = logger;
this.TestingContext.Logger = logger;
Expand Down
Loading
Loading