From 9c2932df8151d81e70a2444edc01c665d1f057b2 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Tue, 3 Nov 2026 21:12:05 +0000 Subject: [PATCH] support changes to transaction processor --- Directory.Packages.props | 14 +- .../MediatorTests.cs | 21 +- .../RequestHandlerTests.cs | 21 +- ...tionProcessorACLApplicationServiceTests.cs | 113 ++--------- .../BackendAPI/DataTransferObjects/Class1.cs | 180 +++++++++++++++++- .../BackendAPI/EstateReportingApiClient.cs | 2 + .../ReportingRequestHandler.cs | 1 - ...andler.cs => TransactionRequestHandler.cs} | 24 +-- .../Requests/TransactionCommands.cs | 21 +- ...ansactionProcessorACLApplicationService.cs | 27 +-- .../Services/ResponseFactory.cs | 23 ++- ...ansactionProcessorACLApplicationService.cs | 124 +++++------- .../Requests/TransactionRequestMessage.cs | 2 +- .../Responses/GetVoucherResponseMessage.cs | 2 +- ...MerchantDailyPerformanceSummaryResponse.cs | 2 +- .../Responses/MerchantResponse.cs | 2 +- .../MerchantTransactionMixSummaryResponse.cs | 6 +- .../Common/TransactionResponseAssertions.cs | 2 +- .../TransactionResponseAssertionsTests.cs | 2 +- .../Shared/ACLSteps.cs | 2 + .../Shared/ReqnrollExtensions.cs | 3 +- .../Shared/SharedSteps.cs | 1 + .../GetVoucherResponse.cs | 2 +- ...MerchantDailyPerformanceSummaryResponse.cs | 2 +- .../MerchantResponse.cs | 2 +- .../MerchantTransactionMixSummaryResponse.cs | 6 +- .../RedeemVoucherResponse.cs | 2 +- TransactionProcessorACL.Testing/TestData.cs | 32 ++-- .../Audit/AuditPipelineBehaviorTests.cs | 1 + .../General/ModelFactoryTests.cs | 2 +- .../Endpoints/TransactionEndpoints.cs | 3 +- .../Factories/ModelFactory.cs | 2 +- .../Handlers/ReportingHandlers.cs | 7 +- .../Handlers/TransactionHandlers.cs | 4 +- 34 files changed, 336 insertions(+), 324 deletions(-) rename TransactionProcessorACL.BusinessLogic/RequestHandlers/{ProcessLogonTransactionRequestHandler.cs => TransactionRequestHandler.cs} (76%) diff --git a/Directory.Packages.props b/Directory.Packages.props index ca4a42f..6e7f256 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -11,7 +11,7 @@ - + @@ -26,10 +26,10 @@ - + - + @@ -38,15 +38,15 @@ - - + + - - + + diff --git a/TransactionProcessorACL.BusinessLogic.Tests/MediatorTests.cs b/TransactionProcessorACL.BusinessLogic.Tests/MediatorTests.cs index 9576cbb..e2a599c 100644 --- a/TransactionProcessorACL.BusinessLogic.Tests/MediatorTests.cs +++ b/TransactionProcessorACL.BusinessLogic.Tests/MediatorTests.cs @@ -118,28 +118,13 @@ private void AddTestRegistrations(ServiceRegistry services, public class DummyTransactionProcessorACLApplicationService : ITransactionProcessorACLApplicationService { - public async Task> ProcessLogonTransaction(Guid estateId, - Guid merchantId, - DateTime transactionDateTime, - String transactionNumber, - String deviceIdentifier, + public async Task> ProcessLogonTransaction(TransactionCommands.ProcessLogonTransactionCommand command, CancellationToken cancellationToken) => Result.Success(new ProcessLogonTransactionResponse()); - public async Task> ProcessSaleTransaction((Guid estateId, Guid merchantId) merchantData, - DateTime transactionDateTime, - String transactionNumber, - String deviceIdentifier, - String customerEmailAddress, - (Guid operatorId, Guid contractId, Guid productId) productData, - Dictionary additionalRequestMetadata, + public async Task> ProcessSaleTransaction(TransactionCommands.ProcessSaleTransactionCommand command, CancellationToken cancellationToken) => Result.Success(new ProcessSaleTransactionResponse()); - public async Task> ProcessReconciliation(Guid estateId, - Guid merchantId, - DateTime transactionDateTime, - String deviceIdentifier, - Int32 transactionCount, - Decimal transactionValue, + public async Task> ProcessReconciliation(TransactionCommands.ProcessReconciliationCommand command, CancellationToken cancellationToken) => Result.Success(new ProcessReconciliationResponse()); public async Task> GetVoucher(Guid estateId, diff --git a/TransactionProcessorACL.BusinessLogic.Tests/RequestHandlerTests.cs b/TransactionProcessorACL.BusinessLogic.Tests/RequestHandlerTests.cs index 059a942..6d42e71 100644 --- a/TransactionProcessorACL.BusinessLogic.Tests/RequestHandlerTests.cs +++ b/TransactionProcessorACL.BusinessLogic.Tests/RequestHandlerTests.cs @@ -51,11 +51,7 @@ public async Task ProcessLogonTransactionRequestHandler_Handle_RequestIsHandled( { ITransactionProcessorACLApplicationServiceImposter applicationService = new ITransactionProcessorACLApplicationServiceImposter(); applicationService - .ProcessLogonTransaction(Arg.Any(), - Arg.Any(), - Arg.Any(), - Arg.Any(), - Arg.Any(), + .ProcessLogonTransaction(Arg.Any(), Arg.Any()).ReturnsAsync(TestData.ProcessLogonTransactionResponse); TransactionRequestHandler requestHandler = new TransactionRequestHandler(applicationService.Instance()); @@ -75,13 +71,7 @@ public async Task ProcessSaleTransactionRequestHandler_Handle_RequestIsHandled() { ITransactionProcessorACLApplicationServiceImposter applicationService = new ITransactionProcessorACLApplicationServiceImposter(); applicationService - .ProcessSaleTransaction(Arg<(Guid, Guid)>.Any(), - Arg.Any(), - Arg.Any(), - Arg.Any(), - Arg.Any(), - Arg<(Guid, Guid, Guid)>.Any(), - Arg>.Any(), + .ProcessSaleTransaction(Arg.Any(), Arg.Any()).ReturnsAsync(TestData.ProcessSaleTransactionResponse); TransactionRequestHandler requestHandler = new TransactionRequestHandler(applicationService.Instance()); @@ -100,12 +90,7 @@ public async Task ProcessReconciliationRequestHandler_Handle_RequestIsHandled() { ITransactionProcessorACLApplicationServiceImposter applicationService = new ITransactionProcessorACLApplicationServiceImposter(); applicationService - .ProcessReconciliation(Arg.Any(), - Arg.Any(), - Arg.Any(), - Arg.Any(), - Arg.Any(), - Arg.Any(), + .ProcessReconciliation(Arg.Any(), Arg.Any()).ReturnsAsync(TestData.ProcessReconciliationResponse); TransactionRequestHandler requestHandler = new TransactionRequestHandler(applicationService.Instance()); diff --git a/TransactionProcessorACL.BusinessLogic.Tests/TransactionProcessorACLApplicationServiceTests.cs b/TransactionProcessorACL.BusinessLogic.Tests/TransactionProcessorACLApplicationServiceTests.cs index 2034ffc..0725285 100644 --- a/TransactionProcessorACL.BusinessLogic.Tests/TransactionProcessorACLApplicationServiceTests.cs +++ b/TransactionProcessorACL.BusinessLogic.Tests/TransactionProcessorACLApplicationServiceTests.cs @@ -1,5 +1,7 @@ using System; using SimpleResults; +using TransactionProcessor.DataTransferObjects.Requests.Transaction; +using TransactionProcessor.DataTransferObjects.Requests.Voucher; namespace TransactionProcessorACL.BusinesssLogic.Tests { @@ -71,11 +73,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessLogonTransact .ReturnsAsync(TestData.ClientLogonTransactionResponse); securityServiceClient.GetToken(Arg.Any(), Arg.Any(), Arg.Any()).ReturnsAsync( Result.Success(TestData.TokenResponse)); - Result result = await applicationService.ProcessLogonTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, + Result result = await applicationService.ProcessLogonTransaction(TestData.ProcessLogonTransactionCommand, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); ProcessLogonTransactionResponse logonResponse = result.Data; @@ -94,11 +92,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessLogonTransact securityServiceClient.GetToken(Arg.Any(), Arg.Any(), Arg.Any()) .ReturnsAsync(Result.Success(TestData.TokenResponse)); - await applicationService.ProcessLogonTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, + await applicationService.ProcessLogonTransaction(TestData.ProcessLogonTransactionCommand, CancellationToken.None); capturedMessage.ShouldNotBeNull(); @@ -115,11 +109,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessLogonTransact { securityServiceClient.GetToken(Arg.Any(), Arg.Any(), Arg.Any()).ReturnsAsync(Result.Failure()); - Result result = await applicationService.ProcessLogonTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, + Result result = await applicationService.ProcessLogonTransaction(TestData.ProcessLogonTransactionCommand, CancellationToken.None); result.IsFailed.ShouldBeTrue(); @@ -131,11 +121,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessLogonTransact securityServiceClient.GetToken(Arg.Any(), Arg.Any(), Arg.Any()).ReturnsAsync(Result.Success(TestData.TokenResponse)); transactionProcessorClient.PerformTransaction(Arg.Any(), Arg.Any(), Arg.Any()) .ReturnsAsync(Result.Failure()); - Result result = await applicationService.ProcessLogonTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, + Result result = await applicationService.ProcessLogonTransaction(TestData.ProcessLogonTransactionCommand, CancellationToken.None); result.IsFailed.ShouldBeTrue(); @@ -148,11 +134,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessLogonTransact .Throws(new Exception("Error")); securityServiceClient.GetToken(Arg.Any(), Arg.Any(), Arg.Any()).ReturnsAsync(Result.Success(TestData.TokenResponse)); - Result result = await applicationService.ProcessLogonTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, + Result result = await applicationService.ProcessLogonTransaction(TestData.ProcessLogonTransactionCommand, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); ProcessLogonTransactionResponse logonResponse =result.Data; @@ -168,13 +150,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessSaleTransacti .ReturnsAsync(TestData.ClientSaleTransactionResponse); securityServiceClient.GetToken(Arg.Any(), Arg.Any(), Arg.Any()).ReturnsAsync(Result.Success(TestData.TokenResponse)); - Result result = await applicationService.ProcessSaleTransaction((TestData.EstateId, TestData.MerchantId), - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, - TestData.CustomerEmailAddress, - (TestData.OperatorId, TestData.ContractId, TestData.ProductId), - TestData.AdditionalRequestMetadata, + Result result = await applicationService.ProcessSaleTransaction(TestData.ProcessSaleTransactionCommand, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); @@ -192,13 +168,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessSaleTransacti .ReturnsAsync(TestData.ClientSaleTransactionResponse).Callback((accessToken, request, cancellationToken) => { capturedRequest = request; return Task.CompletedTask; }); securityServiceClient.GetToken(Arg.Any(), Arg.Any(), Arg.Any()).ReturnsAsync(Result.Success(TestData.TokenResponse)); - Result result = await applicationService.ProcessSaleTransaction((TestData.EstateId, TestData.MerchantId), - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, - TestData.CustomerEmailAddress, - (TestData.OperatorId, TestData.ContractId, TestData.ProductId), - TestData.AdditionalRequestMetadata, + Result result = await applicationService.ProcessSaleTransaction(TestData.ProcessSaleTransactionCommand, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); @@ -225,13 +195,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessSaleTransacti { securityServiceClient.GetToken(Arg.Any(), Arg.Any(), Arg.Any()).ReturnsAsync(Result.Failure()); - Result result = await applicationService.ProcessSaleTransaction((TestData.EstateId, TestData.MerchantId), - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, - TestData.CustomerEmailAddress, - (TestData.OperatorId, TestData.ContractId, TestData.ProductId), - TestData.AdditionalRequestMetadata, + Result result = await applicationService.ProcessSaleTransaction(TestData.ProcessSaleTransactionCommand, CancellationToken.None); result.IsFailed.ShouldBeTrue(); @@ -244,13 +208,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessSaleTransacti .ReturnsAsync(Result.Failure()); securityServiceClient.GetToken(Arg.Any(), Arg.Any(), Arg.Any()).ReturnsAsync(Result.Success(TestData.TokenResponse)); - Result result = await applicationService.ProcessSaleTransaction((TestData.EstateId, TestData.MerchantId), - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, - TestData.CustomerEmailAddress, - (TestData.OperatorId, TestData.ContractId, TestData.ProductId), - TestData.AdditionalRequestMetadata, + Result result = await applicationService.ProcessSaleTransaction(TestData.ProcessSaleTransactionCommand, CancellationToken.None); result.IsFailed.ShouldBeTrue(); @@ -263,13 +221,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessSaleTransacti .Throws(new Exception("Error")); securityServiceClient.GetToken(Arg.Any(), Arg.Any(), Arg.Any()).ReturnsAsync(Result.Success(TestData.TokenResponse)); - Result result = await applicationService.ProcessSaleTransaction((TestData.EstateId, TestData.MerchantId), - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, - TestData.CustomerEmailAddress, - (TestData.OperatorId, TestData.ContractId, TestData.ProductId), - TestData.AdditionalRequestMetadata, + Result result = await applicationService.ProcessSaleTransaction(TestData.ProcessSaleTransactionCommand, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); ProcessSaleTransactionResponse saleResponse = result.Data; @@ -285,12 +237,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessReconciliatio .ReturnsAsync(TestData.ClientReconciliationResponse); securityServiceClient.GetToken(Arg.Any(), Arg.Any(), Arg.Any()).ReturnsAsync(Result.Success(TestData.TokenResponse)); - Result result = await applicationService.ProcessReconciliation(TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.DeviceIdentifier, - TestData.ReconciliationTransactionCount, - TestData.ReconciliationTransactionValue, + Result result = await applicationService.ProcessReconciliation(TestData.ProcessReconciliationCommand, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); @@ -309,12 +256,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessReconciliatio .ReturnsAsync(TestData.ClientReconciliationResponse).Callback((_, message, _) => { capturedMessage = message; return Task.CompletedTask; }); securityServiceClient.GetToken(Arg.Any(), Arg.Any(), Arg.Any()).ReturnsAsync(Result.Success(TestData.TokenResponse)); - await applicationService.ProcessReconciliation(TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.DeviceIdentifier, - TestData.ReconciliationTransactionCount, - TestData.ReconciliationTransactionValue, + await applicationService.ProcessReconciliation(TestData.ProcessReconciliationCommand, CancellationToken.None); capturedMessage.ShouldNotBeNull(); @@ -332,12 +274,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessReconciliatio { securityServiceClient.GetToken(Arg.Any(), Arg.Any(), Arg.Any()).ReturnsAsync(Result.Failure()); - Result result = await applicationService.ProcessReconciliation(TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.DeviceIdentifier, - TestData.ReconciliationTransactionCount, - TestData.ReconciliationTransactionValue, + Result result = await applicationService.ProcessReconciliation(TestData.ProcessReconciliationCommand, CancellationToken.None); result.IsFailed.ShouldBeTrue(); @@ -350,12 +287,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessReconciliatio transactionProcessorClient.PerformTransaction(Arg.Any(), Arg.Any(), Arg.Any()) .ReturnsAsync(Result.Failure()); - Result result = await applicationService.ProcessReconciliation(TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.DeviceIdentifier, - TestData.ReconciliationTransactionCount, - TestData.ReconciliationTransactionValue, + Result result = await applicationService.ProcessReconciliation(TestData.ProcessReconciliationCommand, CancellationToken.None); result.IsFailed.ShouldBeTrue(); @@ -368,12 +300,7 @@ public async Task TransactionProcessorACLApplicationService_ProcessReconciliatio .Throws(new Exception("Error")); securityServiceClient.GetToken(Arg.Any(), Arg.Any(), Arg.Any()).ReturnsAsync(Result.Success(TestData.TokenResponse)); - Result result= await applicationService.ProcessReconciliation(TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.DeviceIdentifier, - TestData.ReconciliationTransactionCount, - TestData.ReconciliationTransactionValue, + Result result= await applicationService.ProcessReconciliation(TestData.ProcessReconciliationCommand, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); @@ -397,7 +324,7 @@ public async Task TransactionProcessorACLApplicationService_GetVoucher_VoucherRe voucherResponse.Data.VoucherCode.ShouldBe(TestData.GetVoucherResponse.VoucherCode); voucherResponse.Data.ContractId.ShouldBe(TestData.ContractId); voucherResponse.Data.EstateId.ShouldBe(TestData.EstateId); - voucherResponse.Data.ExpiryDate.ShouldBe(TestData.GetVoucherResponse.ExpiryDate); + voucherResponse.Data.ExpiryDate.ShouldBe(DateOnly.FromDateTime(TestData.GetVoucherResponse.ExpiryDate.DateTime)); voucherResponse.Data.Value.ShouldBe(TestData.GetVoucherResponse.Value); voucherResponse.Data.VoucherId.ShouldBe(TestData.GetVoucherResponse.VoucherId); } @@ -720,8 +647,8 @@ public async Task TransactionProcessorACLApplicationService_GetMerchantTransacti .GetMerchantTransactionMixSummary(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) .ReturnsAsync(Result.Success(new TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects.TransactionMixSummaryResponse { - FromDate = new DateTime(2026, 7, 1), - ToDate = new DateTime(2026, 7, 3), + FromDate = new DateOnly(2026, 7, 1), + ToDate = new DateOnly(2026, 7, 3), Breakdown = TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects.TransactionMixBreakdown.Product, Measure = TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects.TransactionMixMeasure.Count, Groups = diff --git a/TransactionProcessorACL.BusinessLogic/BackendAPI/DataTransferObjects/Class1.cs b/TransactionProcessorACL.BusinessLogic/BackendAPI/DataTransferObjects/Class1.cs index bd17f07..7d9f9bf 100644 --- a/TransactionProcessorACL.BusinessLogic/BackendAPI/DataTransferObjects/Class1.cs +++ b/TransactionProcessorACL.BusinessLogic/BackendAPI/DataTransferObjects/Class1.cs @@ -1,14 +1,13 @@ using System; using System.Collections.Generic; -using System.Text; using System.Text.Json.Serialization; namespace TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects { - public class TransactionMixSummaryResponse + /*public class TransactionMixSummaryResponse { - public DateTime FromDate { get; set; } - public DateTime ToDate { get; set; } + public DateOnly FromDate { get; set; } + public DateOnly ToDate { get; set; } public TransactionMixBreakdown Breakdown { get; set; } public TransactionMixMeasure Measure { get; set; } public int TotalCount { get; set; } @@ -28,7 +27,7 @@ public class TransactionMixSummaryGroup public class TransactionMixSummaryTransaction { public Guid Id { get; set; } - public DateTime DateTime { get; set; } + public DateTimeOffset DateTime { get; set; } public string? Merchant { get; set; } public Guid MerchantId { get; set; } public int MerchantReportingId { get; set; } @@ -110,3 +109,174 @@ public sealed class DrillDownTransaction public DateTime TransactionDateTime { get; set; } } } +*/ + +public sealed class MerchantDailyPerformanceSummaryResponse { + /// The metrics value. + public List Metrics { get; set; } = []; + + /// The drill down transactions value. + + public List DrillDownTransactions { get; set; } = []; +} + +public sealed class MetricItem { + /// The title value. + public string Title { get; set; } + + /// The value value. + + public Decimal Value { get; set; } + + /// The description value. + + public string Description { get; set; } + + /// The category value. + + public int Category { get; set; } + /// The type value. + public Int32 Type { get; set; } +} + +public sealed class DrillDownTransaction { + /// The reference value. + public string Reference { get; set; } + + /// The product value. + + public string Product { get; set; } + + /// The status value. + + public string Status { get; set; } + + /// The amount value. + + public Decimal Amount { get; set; } + + /// Date and time of the transaction. + + public DateTimeOffset TransactionDateTime { get; set; } +} + +public class MerchantDailyPerformanceSummaryRequest { + /// Numeric reporting identifier used to filter or identify a merchant. + public Int32 MerchantReportingId { get; set; } + /// Inclusive start date of the report period. + public DateOnly StartDate { get; set; } + /// Inclusive end date of the report period. + public DateOnly EndDate { get; set; } +} + +public class TransactionMixSummaryResponse { + /// The from date value. + public DateOnly FromDate { get; set; } + /// The to date value. + public DateOnly ToDate { get; set; } + /// Dimension used to group transactions. + public TransactionMixBreakdown Breakdown { get; set; } + /// Metric used to rank or compare transaction groups. + public TransactionMixMeasure Measure { get; set; } + /// The total count value. + public int TotalCount { get; set; } + /// Total monetary value represented by this result. + public decimal TotalValue { get; set; } + /// The groups value. + public List Groups { get; set; } = []; + /// The transactions value. + public List Transactions { get; set; } = []; + /// The pagination value. + public PaginationMetadata Pagination { get; set; } = new(); +} + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum TransactionMixBreakdown { + /// Group transactions by product. + Product, + /// Group transactions by transaction type. + TransactionType, + /// Group transactions by operator. + Operator, + /// Group transactions by transaction status. + Status +} + +/// API data model describing transaction mix measure information. +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum TransactionMixMeasure { + /// Compare groups by transaction count. + Count, + /// Compare groups by transaction value. + Value +} + +public class TransactionMixSummaryGroup { + /// The group key value. + public string? GroupKey { get; set; } + /// The group name value. + public string? GroupName { get; set; } + /// Number of transactions represented by this result. + public int TransactionCount { get; set; } + /// Total monetary value of the transactions represented by this result. + public decimal TransactionValue { get; set; } +} + +public class TransactionMixSummaryTransaction { + /// The id value. + public Guid Id { get; set; } + /// Date and time of the transaction. + public DateTimeOffset DateTime { get; set; } + /// The merchant value. + public string? Merchant { get; set; } + /// Unique identifier of the merchant. + public Guid MerchantId { get; set; } + /// Numeric reporting identifier used to filter or identify a merchant. + public int MerchantReportingId { get; set; } + /// The operator value. + public string? Operator { get; set; } + /// Unique identifier of the operator. + public Guid OperatorId { get; set; } + /// The operator reporting id value. + public int OperatorReportingId { get; set; } + /// The product value. + public string? Product { get; set; } + /// Unique identifier of the product. + public Guid ProductId { get; set; } + /// The product reporting id value. + public int ProductReportingId { get; set; } + /// The type value. + public string? Type { get; set; } + /// The status value. + public string? Status { get; set; } + /// The value value. + public decimal Value { get; set; } + /// The total fees value. + public decimal TotalFees { get; set; } + /// The settlement reference value. + public string? SettlementReference { get; set; } + /// The transaction number value. + public int TransactionNumber { get; set; } +} + +/// Request criteria for transaction mix summary. + +public class TransactionMixSummaryRequest { + /// Numeric reporting identifier used to filter or identify a merchant. + public int? MerchantReportingId { get; set; } + /// Inclusive start date of the report period. + public DateOnly StartDate { get; set; } + /// Inclusive end date of the report period. + public DateOnly EndDate { get; set; } + /// Dimension used to group transactions. + public TransactionMixBreakdown Breakdown { get; set; } + /// Metric used to rank or compare transaction groups. + public TransactionMixMeasure Measure { get; set; } + /// Maximum number of groups selected before pagination. + public int TopN { get; set; } = 5; + /// One-based page number to return. + public int PageNumber { get; set; } = 1; + /// Maximum number of items to include on a page. + public int PageSize { get; set; } = 50; +} +} \ No newline at end of file diff --git a/TransactionProcessorACL.BusinessLogic/BackendAPI/EstateReportingApiClient.cs b/TransactionProcessorACL.BusinessLogic/BackendAPI/EstateReportingApiClient.cs index 0db5112..7a5468b 100644 --- a/TransactionProcessorACL.BusinessLogic/BackendAPI/EstateReportingApiClient.cs +++ b/TransactionProcessorACL.BusinessLogic/BackendAPI/EstateReportingApiClient.cs @@ -115,3 +115,5 @@ private string BuildRequestUrl(string relativePath) return $"{baseAddress.TrimEnd('/')}{relativePath}"; } } + + diff --git a/TransactionProcessorACL.BusinessLogic/RequestHandlers/ReportingRequestHandler.cs b/TransactionProcessorACL.BusinessLogic/RequestHandlers/ReportingRequestHandler.cs index 35f7926..f15c0b1 100644 --- a/TransactionProcessorACL.BusinessLogic/RequestHandlers/ReportingRequestHandler.cs +++ b/TransactionProcessorACL.BusinessLogic/RequestHandlers/ReportingRequestHandler.cs @@ -4,7 +4,6 @@ using SimpleResults; using TransactionProcessorACL.BusinessLogic.Requests; using TransactionProcessorACL.BusinessLogic.Services; -using TransactionProcessorACL.DataTransferObjects.Requests; using TransactionProcessorACL.Models; namespace TransactionProcessorACL.BusinessLogic.RequestHandlers; diff --git a/TransactionProcessorACL.BusinessLogic/RequestHandlers/ProcessLogonTransactionRequestHandler.cs b/TransactionProcessorACL.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs similarity index 76% rename from TransactionProcessorACL.BusinessLogic/RequestHandlers/ProcessLogonTransactionRequestHandler.cs rename to TransactionProcessorACL.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs index 8193016..41e0138 100644 --- a/TransactionProcessorACL.BusinessLogic/RequestHandlers/ProcessLogonTransactionRequestHandler.cs +++ b/TransactionProcessorACL.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs @@ -42,37 +42,19 @@ public TransactionRequestHandler(ITransactionProcessorACLApplicationService appl public async Task> Handle(TransactionCommands.ProcessLogonTransactionCommand command, CancellationToken cancellationToken) { - return await this.ApplicationService.ProcessLogonTransaction(command.EstateId, - command.MerchantId, - command.TransactionDateTime, - command.TransactionNumber, - command.DeviceIdentifier, - cancellationToken); + return await this.ApplicationService.ProcessLogonTransaction(command, cancellationToken); } public async Task> Handle(TransactionCommands.ProcessReconciliationCommand command, CancellationToken cancellationToken) { - return await this.ApplicationService.ProcessReconciliation(command.EstateId, - command.MerchantId, - command.TransactionDateTime, - command.DeviceIdentifier, - command.TransactionCount, - command.TransactionValue, - cancellationToken); + return await this.ApplicationService.ProcessReconciliation(command, cancellationToken); } public async Task> Handle(TransactionCommands.ProcessSaleTransactionCommand command, CancellationToken cancellationToken) { - return await this.ApplicationService.ProcessSaleTransaction((command.EstateId, command.MerchantId), - command.TransactionDateTime, - command.TransactionNumber, - command.DeviceIdentifier, - command.CustomerEmailAddress, - (command.OperatorId, command.ContractId, command.ProductId), - command.AdditionalRequestMetadata, - cancellationToken); + return await this.ApplicationService.ProcessSaleTransaction(command, cancellationToken); } public async Task> Handle(TransactionCommands.ResendReceiptCommand command, diff --git a/TransactionProcessorACL.BusinessLogic/Requests/TransactionCommands.cs b/TransactionProcessorACL.BusinessLogic/Requests/TransactionCommands.cs index e772fc2..a4a0d9b 100644 --- a/TransactionProcessorACL.BusinessLogic/Requests/TransactionCommands.cs +++ b/TransactionProcessorACL.BusinessLogic/Requests/TransactionCommands.cs @@ -12,34 +12,33 @@ namespace TransactionProcessorACL.BusinessLogic.Requests; public record TransactionCommands { public record ProcessLogonTransactionCommand(Guid EstateId, Guid MerchantId, - DateTime TransactionDateTime, + DateTimeOffset TransactionDateTime, + DateTimeOffset HostDateTime, String TransactionNumber, - String DeviceIdentifier) - : IRequest>; + String DeviceIdentifier) : IRequest>; public record ProcessSaleTransactionCommand(Guid EstateId, Guid MerchantId, - DateTime TransactionDateTime, + DateTimeOffset TransactionDateTime, + DateTimeOffset HostDateTime, String TransactionNumber, String DeviceIdentifier, Guid OperatorId, String CustomerEmailAddress, Guid ContractId, Guid ProductId, - Dictionary AdditionalRequestMetadata) - : IRequest>; + Dictionary AdditionalRequestMetadata) : IRequest>; public record ProcessReconciliationCommand(Guid EstateId, Guid MerchantId, - DateTime TransactionDateTime, + DateTimeOffset TransactionDateTime, + DateTimeOffset HostDateTime, String DeviceIdentifier, Int32 TransactionCount, - Decimal TransactionValue) - : IRequest>; + Decimal TransactionValue) : IRequest>; public record ResendReceiptCommand(Guid EstateId, Guid MerchantId, String Reference, - String RecipientEmailAddress) - : IRequest>; + String RecipientEmailAddress) : IRequest>; } diff --git a/TransactionProcessorACL.BusinessLogic/Services/ITransactionProcessorACLApplicationService.cs b/TransactionProcessorACL.BusinessLogic/Services/ITransactionProcessorACLApplicationService.cs index 6713655..2ad40f8 100644 --- a/TransactionProcessorACL.BusinessLogic/Services/ITransactionProcessorACLApplicationService.cs +++ b/TransactionProcessorACL.BusinessLogic/Services/ITransactionProcessorACLApplicationService.cs @@ -1,42 +1,25 @@ using System; using System.Collections.Generic; -using System.Text; using SimpleResults; +using TransactionProcessorACL.BusinessLogic.Requests; namespace TransactionProcessorACL.BusinessLogic.Services { using System.Threading; using System.Threading.Tasks; - using Shared.General; using TransactionProcessorACL.DataTransferObjects.Requests; - using TransactionProcessor.DataTransferObjects; using TransactionProcessorACL.Models; using GetVoucherResponse = Models.GetVoucherResponse; using RedeemVoucherResponse = Models.RedeemVoucherResponse; public interface ITransactionProcessorACLApplicationService { - Task> ProcessLogonTransaction(Guid estateId, - Guid merchantId, - DateTime transactionDateTime, - String transactionNumber, - String deviceIdentifier, - CancellationToken cancellationToken); + Task> ProcessLogonTransaction(TransactionCommands.ProcessLogonTransactionCommand command, + CancellationToken cancellationToken); - Task> ProcessSaleTransaction((Guid estateId, Guid merchantId) merchantData, - DateTime transactionDateTime, - String transactionNumber, - String deviceIdentifier, - String customerEmailAddress, - (Guid operatorId, Guid contractId, Guid productId) productData, - Dictionary additionalRequestMetadata, CancellationToken cancellationToken); + Task> ProcessSaleTransaction(TransactionCommands.ProcessSaleTransactionCommand command, CancellationToken cancellationToken); - Task> ProcessReconciliation(Guid estateId, - Guid merchantId, - DateTime transactionDateTime, - String deviceIdentifier, - Int32 transactionCount, - Decimal transactionValue, + Task> ProcessReconciliation(TransactionCommands.ProcessReconciliationCommand command, CancellationToken cancellationToken); Task> GetVoucher(Guid estateId, diff --git a/TransactionProcessorACL.BusinessLogic/Services/ResponseFactory.cs b/TransactionProcessorACL.BusinessLogic/Services/ResponseFactory.cs index 74ba1a8..047781d 100644 --- a/TransactionProcessorACL.BusinessLogic/Services/ResponseFactory.cs +++ b/TransactionProcessorACL.BusinessLogic/Services/ResponseFactory.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; -using TransactionProcessor.DataTransferObjects.Requests.Merchant; using TransactionProcessorACL.Models; using ContractContactResponse = TransactionProcessor.DataTransferObjects.Responses.Contract.ContactResponse; using ModelContactResponse = TransactionProcessorACL.Models.ContactResponse; -using OpeningHoursResponse = TransactionProcessor.DataTransferObjects.Requests.Merchant.OpeningHoursResponse; +using OpeningHoursResponse = TransactionProcessor.DataTransferObjects.Responses.Merchant.OpeningHoursResponse; namespace TransactionProcessorACL.BusinessLogic.Services { @@ -19,7 +18,7 @@ public static MerchantResponse Build(TransactionProcessor.DataTransferObjects.Re MerchantName = merchant.MerchantName, EstateReportingId = merchant.EstateReportingId, MerchantReference = merchant.MerchantReference, - NextStatementDate = merchant.NextStatementDate, + NextStatementDate = DateOnly.FromDateTime(merchant.NextStatementDate.DateTime), SettlementSchedule = merchant.SettlementSchedule switch { TransactionProcessor.DataTransferObjects.Responses.Merchant.SettlementSchedule.Immediate => SettlementSchedule.Immediate, TransactionProcessor.DataTransferObjects.Responses.Merchant.SettlementSchedule.Weekly => SettlementSchedule.Weekly, @@ -146,15 +145,15 @@ public static MerchantScheduleResponse Build(TransactionProcessor.DataTransferOb return null; } - var response = new MerchantScheduleResponse - { - Year = resultData.Year, - Months = resultData.Months.Select(m => new MerchantScheduleMonthResponse - { - Month = m.Month, - ClosedDays = m.ClosedDays - }).ToList() ?? new List() - }; + MerchantScheduleResponse response = new MerchantScheduleResponse + { + Year = resultData.Year, + Months = resultData.Months.Select(m => new MerchantScheduleMonthResponse + { + Month = m.Month, + ClosedDays = m.ClosedDays + }).ToList() ?? new List() + }; return response; } diff --git a/TransactionProcessorACL.BusinessLogic/Services/TransactionProcessorACLApplicationService.cs b/TransactionProcessorACL.BusinessLogic/Services/TransactionProcessorACLApplicationService.cs index ab826f1..35ff5a4 100644 --- a/TransactionProcessorACL.BusinessLogic/Services/TransactionProcessorACLApplicationService.cs +++ b/TransactionProcessorACL.BusinessLogic/Services/TransactionProcessorACLApplicationService.cs @@ -4,7 +4,11 @@ using Shared.Results; using SimpleResults; using TransactionProcessor.DataTransferObjects.Requests.Merchant; +using TransactionProcessor.DataTransferObjects.Requests.Transaction; +using TransactionProcessor.DataTransferObjects.Requests.Voucher; using TransactionProcessor.DataTransferObjects.Responses.Contract; +using TransactionProcessor.DataTransferObjects.Responses.Transaction; +using TransactionProcessorACL.BusinessLogic.Requests; namespace TransactionProcessorACL.BusinessLogic.Services { @@ -41,11 +45,7 @@ public TransactionProcessorACLApplicationService(ITransactionProcessorClient tra this.EstateReportingApiClient = estateReportingApiClient; } - public async Task> ProcessLogonTransaction(Guid estateId, - Guid merchantId, - DateTime transactionDateTime, - String transactionNumber, - String deviceIdentifier, + public async Task> ProcessLogonTransaction(TransactionCommands.ProcessLogonTransactionCommand command, CancellationToken cancellationToken) { Result accessTokenResult = await this.GetAccessToken(cancellationToken); @@ -54,7 +54,7 @@ public async Task> ProcessLogonTransacti } TokenResponse accessToken = accessTokenResult.Data; - LogonTransactionRequest logonTransactionRequest = CreateLogonRequestMessage(estateId, merchantId, transactionDateTime, transactionNumber, deviceIdentifier); + LogonTransactionRequest logonTransactionRequest = CreateLogonRequestMessage(command); try { Result transactionResult = await this.TransactionProcessorClient.PerformTransaction(accessToken.AccessToken, logonTransactionRequest, cancellationToken); @@ -62,20 +62,14 @@ public async Task> ProcessLogonTransacti if (transactionResult.IsFailed) return ResultHelpers.CreateFailure(transactionResult); - return Result.Success(CreateProcessLogonTransactionResponse(estateId, merchantId, transactionResult.Data)); + return Result.Success(CreateProcessLogonTransactionResponse(command.EstateId, command.MerchantId, transactionResult.Data)); } catch (Exception ex) { - return Result.Success(CreateLogonErrorResponse(estateId, merchantId, ex)); + return Result.Success(CreateLogonErrorResponse(command.EstateId, command.MerchantId, ex)); } } - public async Task> ProcessSaleTransaction((Guid estateId, Guid merchantId) merchantData, - DateTime transactionDateTime, - String transactionNumber, - String deviceIdentifier, - String customerEmailAddress, - (Guid operatorId, Guid contractId, Guid productId) productData, - Dictionary additionalRequestMetadata, CancellationToken cancellationToken) + public async Task> ProcessSaleTransaction(TransactionCommands.ProcessSaleTransactionCommand command, CancellationToken cancellationToken) { Result accessTokenResult = await this.GetAccessToken(cancellationToken); if (accessTokenResult.IsFailed) { @@ -83,13 +77,7 @@ public async Task> ProcessSaleTransaction } TokenResponse accessToken = accessTokenResult.Data; - SaleTransactionRequest saleTransactionRequest = this.BuildSaleTransactionRequest(merchantData, - transactionNumber, - deviceIdentifier, - transactionDateTime, - productData, - customerEmailAddress, - additionalRequestMetadata); + SaleTransactionRequest saleTransactionRequest = this.BuildSaleTransactionRequest(command); ProcessSaleTransactionResponse response = null; @@ -100,11 +88,11 @@ public async Task> ProcessSaleTransaction if (transactionResult.IsFailed) return ResultHelpers.CreateFailure(transactionResult); - response = this.CreateSaleTransactionResponse(transactionResult.Data, merchantData.estateId, merchantData.merchantId); + response = this.CreateSaleTransactionResponse(transactionResult.Data, command.EstateId, command.MerchantId); } catch (Exception ex) { - response = this.CreateSaleTransactionErrorResponse(merchantData.estateId, merchantData.merchantId, ex); + response = this.CreateSaleTransactionErrorResponse(command.EstateId, command.MerchantId, ex); } return Result.Success(response); @@ -161,28 +149,23 @@ private static Int32 GetSecurityServiceTokenRetryCount() return DefaultSecurityServiceTokenRetryCount; } - private SaleTransactionRequest BuildSaleTransactionRequest((Guid estateId, Guid merchantId) merchantData, - String transactionNumber, - String deviceIdentifier, - DateTime transactionDateTime, - (Guid operatorId, Guid contractId, Guid productId) productData, - String customerEmailAddress, - Dictionary additionalRequestMetadata) + private SaleTransactionRequest BuildSaleTransactionRequest(TransactionCommands.ProcessSaleTransactionCommand command) { return new SaleTransactionRequest { - TransactionNumber = transactionNumber, - DeviceIdentifier = deviceIdentifier, - TransactionDateTime = transactionDateTime, + TransactionNumber = command.TransactionNumber, + DeviceIdentifier = command.DeviceIdentifier, + TransactionDateTime = command.TransactionDateTime, + HostDateTime = command.HostDateTime, TransactionType = "SALE", - OperatorId = productData.operatorId, - CustomerEmailAddress = customerEmailAddress, + OperatorId = command.OperatorId, + CustomerEmailAddress = command.CustomerEmailAddress, TransactionSource = 1, - ContractId = productData.contractId, - ProductId = productData.productId, - AdditionalTransactionMetadata = additionalRequestMetadata, - EstateId = merchantData.estateId, - MerchantId = merchantData.merchantId, + ContractId = command.ContractId, + ProductId = command.ProductId, + AdditionalTransactionMetadata = command.AdditionalRequestMetadata, + EstateId = command.EstateId, + MerchantId = command.MerchantId, }; } @@ -216,12 +199,7 @@ private ProcessSaleTransactionResponse CreateSaleTransactionErrorResponse(Guid e }; } - public async Task> ProcessReconciliation(Guid estateId, - Guid merchantId, - DateTime transactionDateTime, - String deviceIdentifier, - Int32 transactionCount, - Decimal transactionValue, + public async Task> ProcessReconciliation(TransactionCommands.ProcessReconciliationCommand command, CancellationToken cancellationToken) { Result accessTokenResult = await this.GetAccessToken(cancellationToken); @@ -230,12 +208,7 @@ public async Task> ProcessReconciliation(G } TokenResponse accessToken = accessTokenResult.Data; - ReconciliationRequest reconciliationRequest = CreateReconciliationRequestMessage(estateId, - merchantId, - transactionDateTime, - deviceIdentifier, - transactionCount, - transactionValue); + ReconciliationRequest reconciliationRequest = CreateReconciliationRequestMessage(command); try { @@ -247,7 +220,7 @@ public async Task> ProcessReconciliation(G } catch (Exception ex) { - return Result.Success(CreateReconciliationErrorResponse(estateId, merchantId, ex)); + return Result.Success(CreateReconciliationErrorResponse(command.EstateId, command.MerchantId, ex)); } } @@ -264,7 +237,7 @@ public async Task> GetVoucher(Guid estateId, TokenResponse accessToken = accessTokenResult.Data; try { - Result getVoucherResult = await this.TransactionProcessorClient.GetVoucherByCode(accessToken.AccessToken, estateId, voucherCode, cancellationToken); + Result getVoucherResult = await this.TransactionProcessorClient.GetVoucherByCode(accessToken.AccessToken, estateId, voucherCode, cancellationToken); if (getVoucherResult.IsFailed) { return ResultHelpers.CreateFailure(getVoucherResult); } @@ -814,14 +787,14 @@ private static ProcessReconciliationResponse CreateProcessReconciliationResponse private static GetVoucherResponse CreateGetVoucherSuccessResponse(Guid estateId, Guid contractId, - TransactionProcessor.DataTransferObjects.GetVoucherResponse getVoucherResponse) + TransactionProcessor.DataTransferObjects.Responses.Voucher.GetVoucherResponse getVoucherResponse) { return new GetVoucherResponse { ResponseCode = "0000", // Success ContractId = contractId, EstateId = estateId, - ExpiryDate = getVoucherResponse.ExpiryDate, + ExpiryDate = DateOnly.FromDateTime(getVoucherResponse.ExpiryDate.DateTime), Value = getVoucherResponse.Value, VoucherCode = getVoucherResponse.VoucherCode, VoucherId = getVoucherResponse.VoucherId, @@ -843,21 +816,17 @@ private static ProcessReconciliationResponse CreateReconciliationErrorResponse(G }; } - private static ReconciliationRequest CreateReconciliationRequestMessage(Guid estateId, - Guid merchantId, - DateTime transactionDateTime, - String deviceIdentifier, - Int32 transactionCount, - Decimal transactionValue) + private static ReconciliationRequest CreateReconciliationRequestMessage(TransactionCommands.ProcessReconciliationCommand command) { ReconciliationRequest reconciliationRequest = new ReconciliationRequest { - DeviceIdentifier = deviceIdentifier, - TransactionDateTime = transactionDateTime, - TransactionCount = transactionCount, - TransactionValue = transactionValue, - EstateId = estateId, - MerchantId = merchantId + DeviceIdentifier = command.DeviceIdentifier, + TransactionDateTime = command.TransactionDateTime, + HostDateTime = command.HostDateTime, + TransactionCount = command.TransactionCount, + TransactionValue = command.TransactionValue, + EstateId = command.EstateId, + MerchantId = command.MerchantId }; return reconciliationRequest; @@ -891,20 +860,17 @@ private static ProcessLogonTransactionResponse CreateLogonErrorResponse(Guid est }; } - private static LogonTransactionRequest CreateLogonRequestMessage(Guid estateId, - Guid merchantId, - DateTime transactionDateTime, - String transactionNumber, - String deviceIdentifier) + private static LogonTransactionRequest CreateLogonRequestMessage(TransactionCommands.ProcessLogonTransactionCommand command) { LogonTransactionRequest logonTransactionRequest = new LogonTransactionRequest { - TransactionNumber = transactionNumber, - DeviceIdentifier = deviceIdentifier, - TransactionDateTime = transactionDateTime, + TransactionNumber = command.TransactionNumber, + DeviceIdentifier = command.DeviceIdentifier, + TransactionDateTime = command.TransactionDateTime, + HostDateTime = command.HostDateTime, TransactionType = "LOGON", - EstateId = estateId, - MerchantId = merchantId + EstateId = command.EstateId, + MerchantId = command.MerchantId }; return logonTransactionRequest; diff --git a/TransactionProcessorACL.DataTransferObjects/Requests/TransactionRequestMessage.cs b/TransactionProcessorACL.DataTransferObjects/Requests/TransactionRequestMessage.cs index 8446eac..8aa8eeb 100644 --- a/TransactionProcessorACL.DataTransferObjects/Requests/TransactionRequestMessage.cs +++ b/TransactionProcessorACL.DataTransferObjects/Requests/TransactionRequestMessage.cs @@ -22,7 +22,7 @@ public class TransactionRequestMessage public String DeviceIdentifier { get; set; } [Description("Date and time when the transaction occurred.")] - public DateTime TransactionDateTime { get; set; } + public DateTimeOffset TransactionDateTime { get; set; } [Description("Client supplied transaction reference or number.")] public String TransactionNumber { get; set; } diff --git a/TransactionProcessorACL.DataTransferObjects/Responses/GetVoucherResponseMessage.cs b/TransactionProcessorACL.DataTransferObjects/Responses/GetVoucherResponseMessage.cs index 4337cf2..83efde1 100644 --- a/TransactionProcessorACL.DataTransferObjects/Responses/GetVoucherResponseMessage.cs +++ b/TransactionProcessorACL.DataTransferObjects/Responses/GetVoucherResponseMessage.cs @@ -20,7 +20,7 @@ public class GetVoucherResponseMessage{ public Guid EstateId{ get; set; } [Description("Voucher expiry date and time.")] - public DateTime ExpiryDate{ get; set; } + public DateOnly ExpiryDate{ get; set; } [Description("Original value of the voucher.")] public Decimal Value{ get; set; } diff --git a/TransactionProcessorACL.DataTransferObjects/Responses/MerchantDailyPerformanceSummaryResponse.cs b/TransactionProcessorACL.DataTransferObjects/Responses/MerchantDailyPerformanceSummaryResponse.cs index 7605f85..77bb5ce 100644 --- a/TransactionProcessorACL.DataTransferObjects/Responses/MerchantDailyPerformanceSummaryResponse.cs +++ b/TransactionProcessorACL.DataTransferObjects/Responses/MerchantDailyPerformanceSummaryResponse.cs @@ -44,6 +44,6 @@ public class DrillDownTransaction public decimal Amount { get; set; } [Description("Date and time when the transaction occurred.")] - public DateTime TransactionDateTime { get; set; } + public DateTimeOffset TransactionDateTime { get; set; } } } diff --git a/TransactionProcessorACL.DataTransferObjects/Responses/MerchantResponse.cs b/TransactionProcessorACL.DataTransferObjects/Responses/MerchantResponse.cs index 0e3f6ad..5dfdba6 100644 --- a/TransactionProcessorACL.DataTransferObjects/Responses/MerchantResponse.cs +++ b/TransactionProcessorACL.DataTransferObjects/Responses/MerchantResponse.cs @@ -35,7 +35,7 @@ public class MerchantResponse public string MerchantReference { get; set; } [Description("Date of the merchant's next statement.")] - public DateTime NextStatementDate { get; set; } + public DateOnly NextStatementDate { get; set; } [Description("Operators registered for the merchant.")] public List Operators { get; set; } diff --git a/TransactionProcessorACL.DataTransferObjects/Responses/MerchantTransactionMixSummaryResponse.cs b/TransactionProcessorACL.DataTransferObjects/Responses/MerchantTransactionMixSummaryResponse.cs index 9f8a8ca..7b42edc 100644 --- a/TransactionProcessorACL.DataTransferObjects/Responses/MerchantTransactionMixSummaryResponse.cs +++ b/TransactionProcessorACL.DataTransferObjects/Responses/MerchantTransactionMixSummaryResponse.cs @@ -8,10 +8,10 @@ namespace TransactionProcessorACL.DataTransferObjects.Responses; public class MerchantTransactionMixSummaryResponse { [Description("Start of the reporting period represented by the result.")] - public DateTime FromDate { get; set; } + public DateOnly FromDate { get; set; } [Description("End of the reporting period represented by the result.")] - public DateTime ToDate { get; set; } + public DateOnly ToDate { get; set; } [Description("Dimension used to group the results.")] public TransactionMixBreakdown Breakdown { get; set; } @@ -68,5 +68,5 @@ public class TransactionMixDrillDownTransaction public decimal Amount { get; set; } [Description("Date and time when the transaction occurred.")] - public DateTime TransactionDateTime { get; set; } + public DateTimeOffset TransactionDateTime { get; set; } } diff --git a/TransactionProcessorACL.IntegrationTests/Common/TransactionResponseAssertions.cs b/TransactionProcessorACL.IntegrationTests/Common/TransactionResponseAssertions.cs index 99dd558..c83e2ea 100644 --- a/TransactionProcessorACL.IntegrationTests/Common/TransactionResponseAssertions.cs +++ b/TransactionProcessorACL.IntegrationTests/Common/TransactionResponseAssertions.cs @@ -1,6 +1,6 @@ using Shouldly; using System; -using TransactionProcessor.DataTransferObjects; +using TransactionProcessor.DataTransferObjects.Responses.Transaction; namespace TransactionProcessor.IntegrationTests.Common; diff --git a/TransactionProcessorACL.IntegrationTests/Common/TransactionResponseAssertionsTests.cs b/TransactionProcessorACL.IntegrationTests/Common/TransactionResponseAssertionsTests.cs index 8e4c0c5..aa6c3b3 100644 --- a/TransactionProcessorACL.IntegrationTests/Common/TransactionResponseAssertionsTests.cs +++ b/TransactionProcessorACL.IntegrationTests/Common/TransactionResponseAssertionsTests.cs @@ -1,6 +1,6 @@ using NUnit.Framework; -using TransactionProcessor.DataTransferObjects; using System; +using TransactionProcessor.DataTransferObjects.Responses.Transaction; namespace TransactionProcessor.IntegrationTests.Common; diff --git a/TransactionProcessorACL.IntegrationTests/Shared/ACLSteps.cs b/TransactionProcessorACL.IntegrationTests/Shared/ACLSteps.cs index fe5a519..47396c5 100644 --- a/TransactionProcessorACL.IntegrationTests/Shared/ACLSteps.cs +++ b/TransactionProcessorACL.IntegrationTests/Shared/ACLSteps.cs @@ -1,5 +1,7 @@ using Shared.Serialisation; using SimpleResults; +using TransactionProcessor.DataTransferObjects.Responses.Transaction; +using TransactionProcessor.DataTransferObjects.Responses.Voucher; using TransactionProcessor.IntegrationTesting.Helpers; using TransactionProcessorACL.DataTransferObjects.Requests; diff --git a/TransactionProcessorACL.IntegrationTests/Shared/ReqnrollExtensions.cs b/TransactionProcessorACL.IntegrationTests/Shared/ReqnrollExtensions.cs index 64f9275..8c72990 100644 --- a/TransactionProcessorACL.IntegrationTests/Shared/ReqnrollExtensions.cs +++ b/TransactionProcessorACL.IntegrationTests/Shared/ReqnrollExtensions.cs @@ -1,4 +1,5 @@ -using TransactionProcessor.IntegrationTesting.Helpers; +using TransactionProcessor.DataTransferObjects.Requests.Transaction; +using TransactionProcessor.IntegrationTesting.Helpers; namespace TransactionProcessorACL.IntegrationTests.Shared; diff --git a/TransactionProcessorACL.IntegrationTests/Shared/SharedSteps.cs b/TransactionProcessorACL.IntegrationTests/Shared/SharedSteps.cs index a3b29d0..31203b6 100644 --- a/TransactionProcessorACL.IntegrationTests/Shared/SharedSteps.cs +++ b/TransactionProcessorACL.IntegrationTests/Shared/SharedSteps.cs @@ -4,6 +4,7 @@ using TransactionProcessor.DataTransferObjects.Requests.Estate; using TransactionProcessor.DataTransferObjects.Requests.Merchant; using TransactionProcessor.DataTransferObjects.Requests.Operator; +using TransactionProcessor.DataTransferObjects.Requests.Transaction; using TransactionProcessor.DataTransferObjects.Responses.Estate; using AssignOperatorRequest = TransactionProcessor.DataTransferObjects.Requests.Merchant.AssignOperatorRequest; diff --git a/TransactionProcessorACL.Models/GetVoucherResponse.cs b/TransactionProcessorACL.Models/GetVoucherResponse.cs index e4bee87..c8fbd2d 100644 --- a/TransactionProcessorACL.Models/GetVoucherResponse.cs +++ b/TransactionProcessorACL.Models/GetVoucherResponse.cs @@ -17,7 +17,7 @@ public class GetVoucherResponse public Guid EstateId { get; set; } - public DateTime ExpiryDate { get; set; } + public DateOnly ExpiryDate { get; set; } public Decimal Value { get; set; } diff --git a/TransactionProcessorACL.Models/MerchantDailyPerformanceSummaryResponse.cs b/TransactionProcessorACL.Models/MerchantDailyPerformanceSummaryResponse.cs index 014cb45..f7414a9 100644 --- a/TransactionProcessorACL.Models/MerchantDailyPerformanceSummaryResponse.cs +++ b/TransactionProcessorACL.Models/MerchantDailyPerformanceSummaryResponse.cs @@ -31,5 +31,5 @@ public class DrillDownTransaction public decimal Amount { get; set; } - public DateTime TransactionDateTime { get; set; } + public DateTimeOffset TransactionDateTime { get; set; } } diff --git a/TransactionProcessorACL.Models/MerchantResponse.cs b/TransactionProcessorACL.Models/MerchantResponse.cs index 7434b3c..2888c16 100644 --- a/TransactionProcessorACL.Models/MerchantResponse.cs +++ b/TransactionProcessorACL.Models/MerchantResponse.cs @@ -27,7 +27,7 @@ public class MerchantResponse public string MerchantReference { get; set; } - public DateTime NextStatementDate { get; set; } + public DateOnly NextStatementDate { get; set; } public List Operators { get; set; } diff --git a/TransactionProcessorACL.Models/MerchantTransactionMixSummaryResponse.cs b/TransactionProcessorACL.Models/MerchantTransactionMixSummaryResponse.cs index 88e76a7..1b6552c 100644 --- a/TransactionProcessorACL.Models/MerchantTransactionMixSummaryResponse.cs +++ b/TransactionProcessorACL.Models/MerchantTransactionMixSummaryResponse.cs @@ -5,9 +5,9 @@ namespace TransactionProcessorACL.Models; public class MerchantTransactionMixSummaryResponse { - public DateTime FromDate { get; set; } + public DateOnly FromDate { get; set; } - public DateTime ToDate { get; set; } + public DateOnly ToDate { get; set; } public TransactionMixBreakdown Breakdown { get; set; } @@ -47,7 +47,7 @@ public class TransactionMixDrillDownTransaction public decimal Amount { get; set; } - public DateTime TransactionDateTime { get; set; } + public DateTimeOffset TransactionDateTime { get; set; } } public enum TransactionMixBreakdown diff --git a/TransactionProcessorACL.Models/RedeemVoucherResponse.cs b/TransactionProcessorACL.Models/RedeemVoucherResponse.cs index 1670d01..1d719ad 100644 --- a/TransactionProcessorACL.Models/RedeemVoucherResponse.cs +++ b/TransactionProcessorACL.Models/RedeemVoucherResponse.cs @@ -17,7 +17,7 @@ public class RedeemVoucherResponse public Guid EstateId { get; set; } - public DateTime ExpiryDate { get; set; } + public DateOnly ExpiryDate { get; set; } public Decimal Balance { get; set; } diff --git a/TransactionProcessorACL.Testing/TestData.cs b/TransactionProcessorACL.Testing/TestData.cs index 03a6699..dc9e574 100644 --- a/TransactionProcessorACL.Testing/TestData.cs +++ b/TransactionProcessorACL.Testing/TestData.cs @@ -1,18 +1,16 @@ using SecurityService.DataTransferObjects; +using TransactionProcessor.DataTransferObjects.Responses.Transaction; namespace TransactionProcessorACL.Testing { using System; using System.Collections.Generic; using Models; - using TransactionProcessor.DataTransferObjects; using TransactionProcessorACL.BusinessLogic.Requests; using TransactionProcessorACL.Common; using TransactionProcessorACL.DataTransferObjects; using TransactionProcessorACL.DataTransferObjects.Requests; - using GetVoucherResponse = TransactionProcessor.DataTransferObjects.GetVoucherResponse; - using RedeemVoucherResponse = TransactionProcessor.DataTransferObjects.RedeemVoucherResponse; - + /// /// /// @@ -33,7 +31,8 @@ public class TestData /// /// The transaction date time /// - public static DateTime TransactionDateTime = DateTime.Now; + public static DateTimeOffset TransactionDateTime = DateTime.Now; + public static DateTimeOffset HostDateTime = DateTime.Now; /// /// The transaction number @@ -77,6 +76,7 @@ public class TestData new(TestData.EstateId, TestData.MerchantId, TestData.TransactionDateTime, + TestData.HostDateTime, TestData.TransactionNumber, TestData.DeviceIdentifier); @@ -148,6 +148,7 @@ public class TestData public static TransactionCommands.ProcessSaleTransactionCommand ProcessSaleTransactionCommand = new(TestData.EstateId, TestData.MerchantId, TestData.TransactionDateTime, + TestData.HostDateTime, TestData.TransactionNumber, TestData.DeviceIdentifier, TestData.OperatorId, @@ -163,6 +164,7 @@ public class TestData public static TransactionCommands.ProcessReconciliationCommand ProcessReconciliationCommand = new(TestData.EstateId, TestData.MerchantId, TestData.TransactionDateTime, + TestData.HostDateTime, TestData.DeviceIdentifier, TestData.ReconciliationTransactionCount, TestData.ReconciliationTransactionValue); @@ -175,7 +177,7 @@ public class TestData MerchantId = TestData.MerchantId }; - public static TransactionProcessor.DataTransferObjects.ReconciliationResponse ClientReconciliationResponse = new ReconciliationResponse + public static TransactionProcessor.DataTransferObjects.Responses.Transaction.ReconciliationResponse ClientReconciliationResponse = new ReconciliationResponse { ResponseMessage = TestData.ResponseMessage, ResponseCode = TestData.ResponseCode, @@ -252,7 +254,7 @@ public class TestData public static VoucherQueries.GetVoucherQuery GetVoucherQuery => new(TestData.EstateId, TestData.ContractId, TestData.VoucherCode); public static String VoucherCode = "1231231234"; - public static DateTime ExpiryDate = new DateTime(2021, 1, 11); + public static DateOnly ExpiryDate = new DateOnly(2021, 1, 11); public static Decimal Value = 20.00m; public static Guid VoucherId = Guid.Parse("C12665AC-1301-47AA-B292-281EC4DE9721"); public static Decimal Balance = 10.00m; @@ -282,13 +284,13 @@ public class TestData ResponseMessage = TestData.ResponseMessage }; - public static GetVoucherResponse GetVoucherResponse => - new GetVoucherResponse + public static TransactionProcessor.DataTransferObjects.Responses.Voucher.GetVoucherResponse GetVoucherResponse => + new() { VoucherCode = TestData.VoucherCode, Balance = TestData.Balance, - ExpiryDate = TestData.ExpiryDate, - GeneratedDateTime = TestData.GeneratedDateTime, + ExpiryDate = TestData.ExpiryDate.ToDateTime(TimeOnly.MinValue), + GeneratedDateTime = TestData.GeneratedDateTime.ToDateTime(TimeOnly.MinValue), IsGenerated = TestData.IsGenerated, IsIssued = TestData.IsIssued, IsRedeemed = TestData.IsRedeemed, @@ -299,15 +301,15 @@ public class TestData VoucherId = TestData.VoucherId }; - public static RedeemVoucherResponse RedeemVoucherResponse => - new RedeemVoucherResponse + public static TransactionProcessor.DataTransferObjects.Responses.Voucher.RedeemVoucherResponse RedeemVoucherResponse => + new () { VoucherCode = TestData.VoucherCode, RemainingBalance = TestData.Balance, - ExpiryDate = TestData.ExpiryDate + ExpiryDate = TestData.ExpiryDate.ToDateTime(TimeOnly.MinValue) }; - public static DateTime GeneratedDateTime = new DateTime(2020, 12, 11); + public static DateOnly GeneratedDateTime = new DateOnly(2020, 12, 11); public static Boolean IsGenerated = true; diff --git a/TransactionProcessorACL.Tests/Audit/AuditPipelineBehaviorTests.cs b/TransactionProcessorACL.Tests/Audit/AuditPipelineBehaviorTests.cs index 81f7971..517d962 100644 --- a/TransactionProcessorACL.Tests/Audit/AuditPipelineBehaviorTests.cs +++ b/TransactionProcessorACL.Tests/Audit/AuditPipelineBehaviorTests.cs @@ -39,6 +39,7 @@ public async Task Handle_WhenPipelineRuns_RecordsSingleAuditEventWithBusinessCon Guid.Parse("1C8354B7-B97A-46EA-9AD1-C43F33F7E3C3"), Guid.Parse("2C8354B7-B97A-46EA-9AD1-C43F33F7E3C4"), new System.DateTime(2026, 6, 30, 10, 15, 0), + new System.DateTime(2026, 6, 30, 10, 15, 0), "TX-0001", "device-01", Guid.Parse("5C8354B7-B97A-46EA-9AD1-C43F33F7E3C7"), diff --git a/TransactionProcessorACL.Tests/General/ModelFactoryTests.cs b/TransactionProcessorACL.Tests/General/ModelFactoryTests.cs index c8795ef..e30715d 100644 --- a/TransactionProcessorACL.Tests/General/ModelFactoryTests.cs +++ b/TransactionProcessorACL.Tests/General/ModelFactoryTests.cs @@ -123,7 +123,7 @@ public void ModelFactory_ConvertFrom_RedeemVoucherResponse_IsConverted() dto.VoucherCode.ShouldBe(model.VoucherCode); dto.EstateId.ShouldBe(model.EstateId); dto.Balance.ShouldBe(model.Balance); - dto.ExpiryDate.ShouldBe(model.ExpiryDate); + dto.ExpiryDate.ShouldBe(model.ExpiryDate.ToDateTime(TimeOnly.MinValue)); dto.ResponseMessage.ShouldBe(model.ResponseMessage); dto.ResponseCode.ShouldBe(model.ResponseCode); } diff --git a/TransactionProcessorACL/Endpoints/TransactionEndpoints.cs b/TransactionProcessorACL/Endpoints/TransactionEndpoints.cs index fa4d60f..f12fa20 100644 --- a/TransactionProcessorACL/Endpoints/TransactionEndpoints.cs +++ b/TransactionProcessorACL/Endpoints/TransactionEndpoints.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Shared.Authorisation; +using System; using TransactionProcessorACL.Handlers; namespace TransactionProcessorACL.Endpoints @@ -21,7 +22,7 @@ public static IEndpointRouteBuilder MapTransactionEndpoints(this IEndpointRouteB .RequireAuthorization(AuthorizationExtensions.PolicyNames.PasswordTokenOnlyPolicy); // POST /api/saletransactions - saleGroup.MapPost("", TransactionHandlers.PerformSaleTransaction) + saleGroup.MapPost(String.Empty, TransactionHandlers.PerformSaleTransaction) .WithName("ProcessSaleTransaction") .WithSummary("Process a sale transaction") .WithDescription("Submits a sale for the authenticated merchant. Estate and merchant identifiers are resolved from token claims. The request includes transaction details, contract, operator, product, and optional customer and metadata fields. Provide applicationVersion as a query parameter for minimum-version validation; the middleware also reads application_version from the JSON body.") diff --git a/TransactionProcessorACL/Factories/ModelFactory.cs b/TransactionProcessorACL/Factories/ModelFactory.cs index 6bbc0c2..cd8061c 100644 --- a/TransactionProcessorACL/Factories/ModelFactory.cs +++ b/TransactionProcessorACL/Factories/ModelFactory.cs @@ -282,7 +282,7 @@ public static RedeemVoucherResponseMessage ConvertFrom(RedeemVoucherResponse mod ResponseMessage = model.ResponseMessage, ContractId = model.ContractId, EstateId = model.EstateId, - ExpiryDate = model.ExpiryDate, + ExpiryDate = model.ExpiryDate.ToDateTime(TimeOnly.MinValue), ResponseCode = model.ResponseCode }; diff --git a/TransactionProcessorACL/Handlers/ReportingHandlers.cs b/TransactionProcessorACL/Handlers/ReportingHandlers.cs index 311cf23..254194b 100644 --- a/TransactionProcessorACL/Handlers/ReportingHandlers.cs +++ b/TransactionProcessorACL/Handlers/ReportingHandlers.cs @@ -9,10 +9,15 @@ using Shared.Logger; using Shared.Results.Web; using SimpleResults; +using TransactionProcessorACL.BusinessLogic.BackendAPI.DataTransferObjects; using TransactionProcessorACL.BusinessLogic.Requests; using TransactionProcessorACL.DataTransferObjects.Requests; -using ApiResponses = TransactionProcessorACL.DataTransferObjects.Responses; using TransactionProcessorACL.Models; +using ApiResponses = TransactionProcessorACL.DataTransferObjects.Responses; +using MerchantDailyPerformanceSummaryRequest = TransactionProcessorACL.DataTransferObjects.Requests.MerchantDailyPerformanceSummaryRequest; +using MerchantDailyPerformanceSummaryResponse = TransactionProcessorACL.Models.MerchantDailyPerformanceSummaryResponse; +using RecentActivityReceiptSearchRequest = TransactionProcessorACL.DataTransferObjects.Requests.RecentActivityReceiptSearchRequest; +using RecentActivityReceiptSearchResponse = TransactionProcessorACL.Models.RecentActivityReceiptSearchResponse; namespace TransactionProcessorACL.Handlers; diff --git a/TransactionProcessorACL/Handlers/TransactionHandlers.cs b/TransactionProcessorACL/Handlers/TransactionHandlers.cs index ace5750..094d152 100644 --- a/TransactionProcessorACL/Handlers/TransactionHandlers.cs +++ b/TransactionProcessorACL/Handlers/TransactionHandlers.cs @@ -127,7 +127,7 @@ public static async Task ResendReceipt(IMediator mediator, private static TransactionCommands.ProcessLogonTransactionCommand CreateLogonCommand(Guid estateId, Guid merchantId, LogonTransactionRequestMessage msg) { - return new TransactionCommands.ProcessLogonTransactionCommand(estateId, merchantId, msg.TransactionDateTime, msg.TransactionNumber, msg.DeviceIdentifier); + return new TransactionCommands.ProcessLogonTransactionCommand(estateId, merchantId, msg.TransactionDateTime, DateTimeOffset.UtcNow, msg.TransactionNumber, msg.DeviceIdentifier); } private static TransactionCommands.ProcessSaleTransactionCommand CreateSaleCommand(Guid estateId, Guid merchantId, SaleTransactionRequestMessage msg) @@ -136,6 +136,7 @@ private static TransactionCommands.ProcessSaleTransactionCommand CreateSaleComma estateId, merchantId, msg.TransactionDateTime, + DateTimeOffset.UtcNow, msg.TransactionNumber, msg.DeviceIdentifier, msg.OperatorId, @@ -151,6 +152,7 @@ private static TransactionCommands.ProcessReconciliationCommand CreateReconcilia estateId, merchantId, msg.TransactionDateTime, + DateTimeOffset.UtcNow, msg.DeviceIdentifier, msg.TransactionCount, msg.TransactionValue);