diff --git a/TransactionProcessorACL.BusinessLogic.Tests/MediatorTests.cs b/TransactionProcessorACL.BusinessLogic.Tests/MediatorTests.cs index 03a6e83..d322901 100644 --- a/TransactionProcessorACL.BusinessLogic.Tests/MediatorTests.cs +++ b/TransactionProcessorACL.BusinessLogic.Tests/MediatorTests.cs @@ -33,6 +33,7 @@ public MediatorTests() this.Requests.Add(TestData.VersionCheckCommand); this.Requests.Add(TestData.GetVoucherQuery); this.Requests.Add(TestData.RedeemVoucherCommand); + this.Requests.Add(TestData.GetMerchantContractsQuery); } [Fact] @@ -142,5 +143,11 @@ public async Task RedeemVoucher(Guid estateId, { return new RedeemVoucherResponse(); } + + public async Task>> GetMerchantContracts(Guid estateId, + Guid merchantId, + CancellationToken cancellationToken) { + return Result.Success(new List()); + } } } diff --git a/TransactionProcessorACL.BusinessLogic/RequestHandlers/VoucherRequestHandler.cs b/TransactionProcessorACL.BusinessLogic/RequestHandlers/VoucherRequestHandler.cs index c3957c9..eea634b 100644 --- a/TransactionProcessorACL.BusinessLogic/RequestHandlers/VoucherRequestHandler.cs +++ b/TransactionProcessorACL.BusinessLogic/RequestHandlers/VoucherRequestHandler.cs @@ -50,4 +50,21 @@ public async Task> Handle(VoucherCommands.RedeemVo #endregion } + + public class MerchantRequestHandler : IRequestHandler>> { + #region Fields + + private readonly ITransactionProcessorACLApplicationService ApplicationService; + + #endregion + + public MerchantRequestHandler(ITransactionProcessorACLApplicationService applicationService) { + this.ApplicationService = applicationService; + } + + public async Task>> Handle(MerchantQueries.GetMerchantContractsQuery request, + CancellationToken cancellationToken) { + return await this.ApplicationService.GetMerchantContracts(request.EstateId, request.MerchantId, cancellationToken); + } + } } diff --git a/TransactionProcessorACL.BusinessLogic/Requests/TransactionCommands.cs b/TransactionProcessorACL.BusinessLogic/Requests/TransactionCommands.cs index d18e2bf..21ca24c 100644 --- a/TransactionProcessorACL.BusinessLogic/Requests/TransactionCommands.cs +++ b/TransactionProcessorACL.BusinessLogic/Requests/TransactionCommands.cs @@ -35,4 +35,10 @@ public record ProcessReconciliationCommand(Guid EstateId, Int32 TransactionCount, Decimal TransactionValue) : IRequest>; +} + +[ExcludeFromCodeCoverage] +public record MerchantQueries { + public record GetMerchantContractsQuery(Guid EstateId,Guid MerchantId) : IRequest>>; + } \ No newline at end of file diff --git a/TransactionProcessorACL.BusinessLogic/Services/ITransactionProcessorACLApplicationService.cs b/TransactionProcessorACL.BusinessLogic/Services/ITransactionProcessorACLApplicationService.cs index b4062c5..48a066d 100644 --- a/TransactionProcessorACL.BusinessLogic/Services/ITransactionProcessorACLApplicationService.cs +++ b/TransactionProcessorACL.BusinessLogic/Services/ITransactionProcessorACLApplicationService.cs @@ -51,5 +51,9 @@ Task RedeemVoucher(Guid estateId, Guid contractId, String voucherCode, CancellationToken cancellationToken); + + Task>> GetMerchantContracts(Guid estateId, + Guid merchantId, + CancellationToken cancellationToken); } } diff --git a/TransactionProcessorACL.BusinessLogic/Services/TransactionProcessorACLApplicationService.cs b/TransactionProcessorACL.BusinessLogic/Services/TransactionProcessorACLApplicationService.cs index 61ea6a5..2e805f2 100644 --- a/TransactionProcessorACL.BusinessLogic/Services/TransactionProcessorACLApplicationService.cs +++ b/TransactionProcessorACL.BusinessLogic/Services/TransactionProcessorACLApplicationService.cs @@ -1,4 +1,5 @@ using SimpleResults; +using TransactionProcessor.DataTransferObjects.Responses.Contract; namespace TransactionProcessorACL.BusinessLogic.Services { @@ -476,6 +477,79 @@ public async Task RedeemVoucher(Guid estateId, return response; } + public async Task>> GetMerchantContracts(Guid estateId, + Guid merchantId, + CancellationToken cancellationToken) { + // Get a client token to call the Transaction Processor + String clientId = ConfigurationReader.GetValue("AppSettings", "ClientId"); + String clientSecret = ConfigurationReader.GetValue("AppSettings", "ClientSecret"); + + TokenResponse accessToken = await this.SecurityServiceClient.GetToken(clientId, clientSecret, cancellationToken); + + ProcessLogonTransactionResponse response = null; + + Result> result = await this.TransactionProcessorClient.GetMerchantContracts(accessToken.AccessToken, estateId, merchantId, cancellationToken); + + if (result.IsFailed) + return Result.Failure($"Error getting merchant contracts {result.Message}"); + + List models = new(); + + foreach (TransactionProcessor.DataTransferObjects.Responses.Contract.ContractResponse contractResponse in result.Data) { + var contractModel = new ContractResponse { + ContractId = contractResponse.ContractId, + ContractReportingId = contractResponse.ContractReportingId, + Description = contractResponse.Description, + EstateId = contractResponse.EstateId, + EstateReportingId = contractResponse.EstateReportingId, + OperatorId = contractResponse.OperatorId, + OperatorName = contractResponse.OperatorName, + Products = new() + }; + + foreach (TransactionProcessor.DataTransferObjects.Responses.Contract.ContractProduct contractResponseProduct in contractResponse.Products) { + var productModel = new ContractProduct { + Value = contractResponseProduct.Value, + DisplayText = contractResponseProduct.DisplayText, + Name = contractResponseProduct.Name, + ProductId = contractResponseProduct.ProductId, + ProductReportingId = contractResponseProduct.ProductReportingId, + ProductType = contractResponseProduct.ProductType switch { + TransactionProcessor.DataTransferObjects.Responses.Contract.ProductType.BillPayment => ProductType.BillPayment, + TransactionProcessor.DataTransferObjects.Responses.Contract.ProductType.MobileTopup => ProductType.MobileTopup, + TransactionProcessor.DataTransferObjects.Responses.Contract.ProductType.Voucher => ProductType.Voucher, + _ => ProductType.NotSet + }, + TransactionFees = new() + }; + + foreach (TransactionProcessor.DataTransferObjects.Responses.Contract.ContractProductTransactionFee contractProductTransactionFee in contractResponseProduct.TransactionFees) { + var transactionFeeModel = new ContractProductTransactionFee { + Value = contractProductTransactionFee.Value, + Description = contractProductTransactionFee.Description, + CalculationType = contractProductTransactionFee.CalculationType switch { + TransactionProcessor.DataTransferObjects.Responses.Contract.CalculationType.Fixed => CalculationType.Fixed, + _ => CalculationType.Percentage, + }, + FeeType = contractProductTransactionFee.FeeType switch { + TransactionProcessor.DataTransferObjects.Responses.Contract.FeeType.Merchant => FeeType.Merchant, + _ => FeeType.ServiceProvider, + }, + TransactionFeeId = contractProductTransactionFee.TransactionFeeId, + TransactionFeeReportingId = contractProductTransactionFee.TransactionFeeReportingId + }; + productModel.TransactionFees.Add(transactionFeeModel); + } + + contractModel.Products.Add(productModel); + } + + models.Add(contractModel); + } + + return Result.Success(models); + } + #endregion } } \ No newline at end of file diff --git a/TransactionProcessorACL.DataTransferObjects/Responses/ContractResponse.cs b/TransactionProcessorACL.DataTransferObjects/Responses/ContractResponse.cs new file mode 100644 index 0000000..f53a40e --- /dev/null +++ b/TransactionProcessorACL.DataTransferObjects/Responses/ContractResponse.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace TransactionProcessorACL.DataTransferObjects.Responses { + public class ContractResponse + { + [JsonProperty("contract_id")] + public Guid ContractId { get; set; } + + [JsonProperty("contract_reporting_id")] + public int ContractReportingId { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("estate_id")] + public Guid EstateId { get; set; } + + [JsonProperty("estate_reporting_id")] + public int EstateReportingId { get; set; } + + [JsonProperty("operator_id")] + public Guid OperatorId { get; set; } + + [JsonProperty("operator_name")] + public string OperatorName { get; set; } + + [JsonProperty("products")] + public List Products { get; set; } + } + + public class ContractProduct + { + public string DisplayText { get; set; } + + public string Name { get; set; } + + public Guid ProductId { get; set; } + + public int ProductReportingId { get; set; } + + public List TransactionFees { get; set; } + + public Decimal? Value { get; set; } + + public ProductType ProductType { get; set; } + } + + public class ContractProductTransactionFee + { + public CalculationType CalculationType { get; set; } + + public FeeType FeeType { get; set; } + + public string Description { get; set; } + + public Guid TransactionFeeId { get; set; } + + public int TransactionFeeReportingId { get; set; } + + public Decimal Value { get; set; } + } + + public enum FeeType + { + Merchant, + ServiceProvider, + } + + public enum CalculationType + { + Fixed, + Percentage, + } + + public enum ProductType + { + NotSet, + MobileTopup, + Voucher, + BillPayment, + } +} \ No newline at end of file diff --git a/TransactionProcessorACL.DataTransferObjects/Responses/GetVoucherResponseMessage.cs b/TransactionProcessorACL.DataTransferObjects/Responses/GetVoucherResponseMessage.cs index 6a04942..6a3a624 100644 --- a/TransactionProcessorACL.DataTransferObjects/Responses/GetVoucherResponseMessage.cs +++ b/TransactionProcessorACL.DataTransferObjects/Responses/GetVoucherResponseMessage.cs @@ -1,7 +1,7 @@ namespace TransactionProcessorACL.DataTransferObjects.Responses{ + using Newtonsoft.Json; using System; using System.Diagnostics.CodeAnalysis; - using Newtonsoft.Json; [ExcludeFromCodeCoverage] public class GetVoucherResponseMessage{ diff --git a/TransactionProcessorACL.IntegrationTests/Shared/SharedSteps.cs b/TransactionProcessorACL.IntegrationTests/Shared/SharedSteps.cs index f0ffaf5..69427e7 100644 --- a/TransactionProcessorACL.IntegrationTests/Shared/SharedSteps.cs +++ b/TransactionProcessorACL.IntegrationTests/Shared/SharedSteps.cs @@ -132,8 +132,8 @@ public async Task GivenIAmLoggedInAsWithPasswordForMerchantForEstateWithClient(S public async Task GivenICreateAContractWithTheFollowingValues(DataTable table){ var estates = this.TestingContext.Estates.Select(e => e.EstateDetails).ToList(); List<(EstateDetails, CreateContractRequest)> requests = table.Rows.ToCreateContractRequests(estates); - List responses = await this.TransactionProcessorSteps.GivenICreateAContractWithTheFollowingValues(this.TestingContext.AccessToken, requests); - foreach (ContractResponse contractResponse in responses) + List responses = await this.TransactionProcessorSteps.GivenICreateAContractWithTheFollowingValues(this.TestingContext.AccessToken, requests); + foreach (TransactionProcessor.DataTransferObjects.Responses.Contract.ContractResponse contractResponse in responses) { var estate = this.TestingContext.Estates.Single(e => e.EstateDetails.EstateId == contractResponse.EstateId); estate.EstateDetails.AddContract(contractResponse.ContractId, contractResponse.Description, contractResponse.OperatorId); diff --git a/TransactionProcessorACL.Models/ContractResponse.cs b/TransactionProcessorACL.Models/ContractResponse.cs new file mode 100644 index 0000000..5827e16 --- /dev/null +++ b/TransactionProcessorACL.Models/ContractResponse.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; + +namespace TransactionProcessorACL.Models { + public class ContractResponse + { + public Guid ContractId { get; set; } + public int ContractReportingId { get; set; } + + public string Description { get; set; } + + public Guid EstateId { get; set; } + + public int EstateReportingId { get; set; } + + public Guid OperatorId { get; set; } + + public string OperatorName { get; set; } + + public List Products { get; set; } + } + + public class ContractProduct + { + public string DisplayText { get; set; } + + public string Name { get; set; } + + public Guid ProductId { get; set; } + + public int ProductReportingId { get; set; } + + public List TransactionFees { get; set; } + + public Decimal? Value { get; set; } + + public ProductType ProductType { get; set; } + } + + public class ContractProductTransactionFee + { + public CalculationType CalculationType { get; set; } + + public FeeType FeeType { get; set; } + + public string Description { get; set; } + + public Guid TransactionFeeId { get; set; } + + public int TransactionFeeReportingId { get; set; } + + public Decimal Value { get; set; } + } + + public enum FeeType + { + Merchant, + ServiceProvider, + } + + public enum CalculationType + { + Fixed, + Percentage, + } + + public enum ProductType + { + NotSet, + MobileTopup, + Voucher, + BillPayment, + } +} \ No newline at end of file diff --git a/TransactionProcessorACL.Testing/TestData.cs b/TransactionProcessorACL.Testing/TestData.cs index 044d49b..b8c62b4 100644 --- a/TransactionProcessorACL.Testing/TestData.cs +++ b/TransactionProcessorACL.Testing/TestData.cs @@ -239,6 +239,8 @@ public class TestData public static VersionCheckCommands.VersionCheckCommand VersionCheckCommand = new(TestData.ApplicationVersion); public static VoucherCommands.RedeemVoucherCommand RedeemVoucherCommand => new(TestData.EstateId, TestData.ContractId, TestData.VoucherCode); + public static MerchantQueries.GetMerchantContractsQuery GetMerchantContractsQuery => new(EstateId,MerchantId); + public static VoucherQueries.GetVoucherQuery GetVoucherQuery => new(TestData.EstateId, TestData.ContractId, TestData.VoucherCode); public static String VoucherCode = "1231231234"; diff --git a/TransactionProcessorACL/Bootstrapper/MediatorRegistry.cs b/TransactionProcessorACL/Bootstrapper/MediatorRegistry.cs index 20cb01d..2fb4cda 100644 --- a/TransactionProcessorACL/Bootstrapper/MediatorRegistry.cs +++ b/TransactionProcessorACL/Bootstrapper/MediatorRegistry.cs @@ -1,4 +1,5 @@ -using SimpleResults; +using System.Collections.Generic; +using SimpleResults; namespace TransactionProcessorACL.Bootstrapper { @@ -34,6 +35,8 @@ public MediatorRegistry() this.AddSingleton>, VoucherRequestHandler>(); this.AddSingleton>, VoucherRequestHandler>(); + + this.AddSingleton>>, MerchantRequestHandler>(); } #endregion diff --git a/TransactionProcessorACL/Common/ClaimsHelper.cs b/TransactionProcessorACL/Common/ClaimsHelper.cs index 688c1e0..e1dacfe 100644 --- a/TransactionProcessorACL/Common/ClaimsHelper.cs +++ b/TransactionProcessorACL/Common/ClaimsHelper.cs @@ -9,8 +9,8 @@ namespace TransactionProcessorACL.Common using System.Security.Claims; using Shared.Exceptions; - [ExcludeFromCodeCoverage] - public class ClaimsHelper + //[ExcludeFromCodeCoverage] + /*public class ClaimsHelper { #region Methods @@ -111,5 +111,5 @@ public static Boolean IsUserRolesValid(ClaimsPrincipal user, String[] allowedRol } #endregion - } + }*/ } diff --git a/TransactionProcessorACL/Controllers/MerchantController.cs b/TransactionProcessorACL/Controllers/MerchantController.cs new file mode 100644 index 0000000..d91684c --- /dev/null +++ b/TransactionProcessorACL/Controllers/MerchantController.cs @@ -0,0 +1,149 @@ +using Humanizer; +using MediatR; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; +using Shared.General; +using Shared.Results; +using SimpleResults; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using System.Threading.Tasks; +using TransactionProcessorACL.BusinessLogic.Requests; +using TransactionProcessorACL.Factories; +using TransactionProcessorACL.Models; +using static TransactionProcessorACL.BusinessLogic.Requests.VersionCheckCommands; + +namespace TransactionProcessorACL.Controllers +{ + [ExcludeFromCodeCoverage] + [Route(MerchantController.ControllerRoute)] + [ApiController] + [Authorize] + public class MerchantController : ControllerBase + { + #region Fields + + /// + /// The mediator + /// + private readonly IMediator Mediator; + + /// + /// The model factory + /// + private readonly IModelFactory ModelFactory; + + #endregion + + public MerchantController(IMediator mediator, + IModelFactory modelFactory) + { + this.Mediator = mediator; + this.ModelFactory = modelFactory; + } + + [HttpGet] + [Route("contracts")] + public async Task GetMerchantContracts([FromQuery] String applicationVersion, + CancellationToken cancellationToken) { + if (ClaimsHelper.IsPasswordToken(this.User) == false) { + return this.Forbid(); + } + + // Do the software version check + VersionCheckCommand versionCheckCommand = new(applicationVersion); + Result versionCheckResult = await this.Mediator.Send(versionCheckCommand, cancellationToken); + if (versionCheckResult.IsFailed) + return this.StatusCode(505); + + Result<(Guid estateId, Guid merchantId)> claimsResult = TransactionController.GetRequiredClaims(this.User); + if (claimsResult.IsFailed) + return this.Forbid(); + + MerchantQueries.GetMerchantContractsQuery query = new(claimsResult.Data.estateId, claimsResult.Data.merchantId); + Result> result = await this.Mediator.Send(query, cancellationToken); + + if (result.IsFailed) + return ResultHelpers.CreateFailure(result).ToActionResultX(); + + List responses = new(); + // Now need to convert to the DTO type for returning to the caller + foreach (ContractResponse contractModel in result.Data) + { + DataTransferObjects.Responses.ContractResponse contractResponse = new() { + ContractId = contractModel.ContractId, + ContractReportingId = contractModel.ContractReportingId, + Description = contractModel.Description, + EstateId = contractModel.EstateId, + EstateReportingId = contractModel.EstateReportingId, + OperatorId = contractModel.OperatorId, + OperatorName = contractModel.OperatorName, + Products = new() + }; + + foreach (ContractProduct contractModelProduct in contractModel.Products) + { + DataTransferObjects.Responses.ContractProduct productResponse = new() { + Value = contractModelProduct.Value, + DisplayText = contractModelProduct.DisplayText, + Name = contractModelProduct.Name, + ProductId = contractModelProduct.ProductId, + ProductReportingId = contractModelProduct.ProductReportingId, + ProductType = contractModelProduct.ProductType switch + { + ProductType.BillPayment => DataTransferObjects.Responses.ProductType.BillPayment, + ProductType.MobileTopup => DataTransferObjects.Responses.ProductType.MobileTopup, + ProductType.Voucher => DataTransferObjects.Responses.ProductType.Voucher, + _ => DataTransferObjects.Responses.ProductType.NotSet + }, + TransactionFees = new() + }; + + foreach (ContractProductTransactionFee contractProductTransactionFeeModel in contractModelProduct.TransactionFees) + { + DataTransferObjects.Responses.ContractProductTransactionFee transactionFeeModel = new() { + Value = contractProductTransactionFeeModel.Value, + Description = contractProductTransactionFeeModel.Description, + CalculationType = contractProductTransactionFeeModel.CalculationType switch + { + CalculationType.Fixed => DataTransferObjects.Responses.CalculationType.Fixed, + _ => DataTransferObjects.Responses.CalculationType.Percentage, + }, + FeeType = contractProductTransactionFeeModel.FeeType switch + { + FeeType.Merchant => DataTransferObjects.Responses.FeeType.Merchant, + _ => DataTransferObjects.Responses.FeeType.ServiceProvider, + }, + TransactionFeeId = contractProductTransactionFeeModel.TransactionFeeId, + TransactionFeeReportingId = contractProductTransactionFeeModel.TransactionFeeReportingId + }; + productResponse.TransactionFees.Add(transactionFeeModel); + } + + contractResponse.Products.Add(productResponse); + } + + responses.Add(contractResponse); + } + + return Result.Success(responses).ToActionResultX(); + } + + #region Others + + /// + /// The controller name + /// + public const String ControllerName = "merchants"; + + /// + /// The controller route + /// + private const String ControllerRoute = "api/" + MerchantController.ControllerName; + + #endregion + } +} diff --git a/TransactionProcessorACL/Controllers/TransactionController.cs b/TransactionProcessorACL/Controllers/TransactionController.cs index 088e311..954e748 100644 --- a/TransactionProcessorACL/Controllers/TransactionController.cs +++ b/TransactionProcessorACL/Controllers/TransactionController.cs @@ -1,4 +1,6 @@ -using Shared.Results; +using System.Security.Claims; +using Shared.General; +using Shared.Results; using SimpleResults; namespace TransactionProcessorACL.Controllers @@ -92,11 +94,15 @@ public async Task PerformTransaction([FromBody] TransactionReques if (versionCheckResult.IsFailed) return this.StatusCode(505); - // Now do the transaction - TransactionResponseMessage dto = null; - switch (transactionRequest){ + Result<(Guid estateId, Guid merchantId)> claimsResult = TransactionController.GetRequiredClaims(this.User); + if (claimsResult.IsFailed) + return this.Forbid(); + + TransactionResponseMessage dto = new TransactionResponseMessage(); + switch (transactionRequest) + { case SaleTransactionRequestMessage msg: - TransactionCommands.ProcessSaleTransactionCommand saleCommand = this.CreateCommandFromRequest(msg); + TransactionCommands.ProcessSaleTransactionCommand saleCommand = this.CreateCommandFromRequest(claimsResult.Data.estateId, claimsResult.Data.merchantId, msg); Result saleResponse = await this.Mediator.Send(saleCommand, cancellationToken); // TODO: Handle the result if (saleResponse.IsFailed) @@ -104,14 +110,14 @@ public async Task PerformTransaction([FromBody] TransactionReques dto = this.ModelFactory.ConvertFrom(saleResponse); break; case LogonTransactionRequestMessage msg: - TransactionCommands.ProcessLogonTransactionCommand logonCommand= this.CreateCommandFromRequest(msg); + TransactionCommands.ProcessLogonTransactionCommand logonCommand= this.CreateCommandFromRequest(claimsResult.Data.estateId, claimsResult.Data.merchantId, msg); Result logonResponse = await this.Mediator.Send(logonCommand, cancellationToken); if (logonResponse.IsFailed) return logonResponse.ToActionResultX(); dto = this.ModelFactory.ConvertFrom(logonResponse); break; - case ReconciliationRequestMessage msg: - TransactionCommands.ProcessReconciliationCommand reconciliationCommand = this.CreateCommandFromRequest(msg); + case ReconciliationRequestMessage msg: + TransactionCommands.ProcessReconciliationCommand reconciliationCommand = this.CreateCommandFromRequest(claimsResult.Data.estateId, claimsResult.Data.merchantId, msg); Result reconciliationResponse = await this.Mediator.Send(reconciliationCommand, cancellationToken); if (reconciliationResponse.IsFailed) return reconciliationResponse.ToActionResultX(); @@ -128,18 +134,26 @@ public async Task PerformTransaction([FromBody] TransactionReques /// /// The logon transaction request message. /// - private TransactionCommands.ProcessLogonTransactionCommand CreateCommandFromRequest(LogonTransactionRequestMessage logonTransactionRequestMessage) + private TransactionCommands.ProcessLogonTransactionCommand CreateCommandFromRequest(Guid estateId, Guid merchantId, LogonTransactionRequestMessage logonTransactionRequestMessage) { - Guid estateId = Guid.Parse(ClaimsHelper.GetUserClaim(this.User, "estateId").Value); - Guid merchantId = Guid.Parse(ClaimsHelper.GetUserClaim(this.User, "merchantId").Value); + TransactionCommands.ProcessLogonTransactionCommand command = new(estateId, merchantId, logonTransactionRequestMessage.TransactionDateTime, logonTransactionRequestMessage.TransactionNumber, logonTransactionRequestMessage.DeviceIdentifier); - TransactionCommands.ProcessLogonTransactionCommand command = new(estateId, - merchantId, - logonTransactionRequestMessage.TransactionDateTime, - logonTransactionRequestMessage.TransactionNumber, - logonTransactionRequestMessage.DeviceIdentifier); + return Result.Success(command); + } - return command; + public static Result<(Guid estateId, Guid merchantId)> GetRequiredClaims(ClaimsPrincipal user) { + Result estateIdResult = ClaimsHelper.GetUserClaim(user, "estateId"); + if (estateIdResult.IsFailed) + return Result.Failure("No Claim found for Estate Id"); + + Result merchantIdResult = ClaimsHelper.GetUserClaim(user, "merchantId"); + if (merchantIdResult.IsFailed) + return Result.Failure("No Claim found for Merchant Id"); + + // Ok we have the required claims + Guid estateId = Guid.Parse(estateIdResult.Data.Value); + Guid merchantId = Guid.Parse(merchantIdResult.Data.Value); + return Result.Success((estateId, merchantId)); } /// @@ -147,13 +161,10 @@ private TransactionCommands.ProcessLogonTransactionCommand CreateCommandFromReq /// /// The sale transaction request message. /// - private TransactionCommands.ProcessSaleTransactionCommand CreateCommandFromRequest(SaleTransactionRequestMessage saleTransactionRequestMessage) + private TransactionCommands.ProcessSaleTransactionCommand CreateCommandFromRequest(Guid estateId, Guid merchantId, SaleTransactionRequestMessage saleTransactionRequestMessage) { - Guid estateId = Guid.Parse(ClaimsHelper.GetUserClaim(this.User, "estateId").Value); - Guid merchantId = Guid.Parse(ClaimsHelper.GetUserClaim(this.User, "merchantId").Value); - TransactionCommands.ProcessSaleTransactionCommand command = new(estateId, - merchantId, + TransactionCommands.ProcessSaleTransactionCommand command = new(estateId, merchantId, saleTransactionRequestMessage.TransactionDateTime, saleTransactionRequestMessage.TransactionNumber, saleTransactionRequestMessage.DeviceIdentifier, @@ -171,13 +182,9 @@ private TransactionCommands.ProcessSaleTransactionCommand CreateCommandFromReque /// /// The reconciliation request message. /// - private TransactionCommands.ProcessReconciliationCommand CreateCommandFromRequest(ReconciliationRequestMessage reconciliationRequestMessage) + private TransactionCommands.ProcessReconciliationCommand CreateCommandFromRequest(Guid estateId, Guid merchantId, ReconciliationRequestMessage reconciliationRequestMessage) { - Guid estateId = Guid.Parse(ClaimsHelper.GetUserClaim(this.User, "estateId").Value); - Guid merchantId = Guid.Parse(ClaimsHelper.GetUserClaim(this.User, "merchantId").Value); - - TransactionCommands.ProcessReconciliationCommand command = new(estateId, - merchantId, + TransactionCommands.ProcessReconciliationCommand command = new(estateId, merchantId, reconciliationRequestMessage.TransactionDateTime, reconciliationRequestMessage.DeviceIdentifier, reconciliationRequestMessage.TransactionCount,