diff --git a/EstateManagementUI.BlazorServer/Components/Pages/Merchants/New.razor b/EstateManagementUI.BlazorServer/Components/Pages/Merchants/New.razor index 6a859fb0..1ef7f590 100644 --- a/EstateManagementUI.BlazorServer/Components/Pages/Merchants/New.razor +++ b/EstateManagementUI.BlazorServer/Components/Pages/Merchants/New.razor @@ -29,6 +29,14 @@

@errorMessage

} + + @if (!string.IsNullOrWhiteSpace(successMessage)) + { +
+

Success

+

@successMessage

+
+ }
@@ -168,140 +176,4 @@
- - -@code { - private readonly New.CreateMerchantModel model = new(); - private bool isSaving = false; - private string? errorMessage; - - protected override async Task OnInitializedAsync() - { - await RequirePermission(PermissionSection.Merchant, PermissionFunction.Create); - } - - private async Task HandleSubmit() - { - isSaving = true; - errorMessage = null; - - try - { - var correlationId = new CorrelationId(Guid.NewGuid()); - var estateId = Guid.Parse("11111111-1111-1111-1111-111111111111"); - var accessToken = "stubbed-token"; - - // Create merchant - var createCommand = new Commands.CreateMerchantCommand( - correlationId, - accessToken, - estateId, - model.MerchantName!, - model.ContactName!, - model.EmailAddress! - ); - - var createResult = await Mediator.Send(createCommand); - - if (!createResult.IsSuccess) - { - errorMessage = createResult.Message ?? "Failed to create merchant"; - return; - } - - // Get the newly created merchant ID (in real implementation, this would be returned from the create command) - var merchantId = Guid.NewGuid(); - - // // Update address - // var addressCommand = new Commands.UpdateMerchantAddressCommand( - // correlationId, - // accessToken, - // estateId, - // merchantId, - // model.AddressLine1!, - // model.Town!, - // model.Region!, - // model.PostCode!, - // model.Country! - // ); - - // await Mediator.Send(addressCommand); - - // // Update contact (including phone) - // var contactCommand = new Commands.UpdateMerchantContactCommand( - // correlationId, - // accessToken, - // estateId, - // merchantId, - // model.ContactName!, - // model.EmailAddress!, - // model.PhoneNumber! - // ); - - // await Mediator.Send(contactCommand); - - // // Set settlement schedule - // var scheduleCommand = new Commands.SetMerchantSettlementScheduleCommand( - // correlationId, - // accessToken, - // estateId, - // merchantId, - // model.SettlementSchedule! - // ); - - // await Mediator.Send(scheduleCommand); - - // Navigate to merchant list - NavigationManager.NavigateTo($"/merchants"); - } - catch (Exception ex) - { - errorMessage = $"An error occurred: {ex.Message}"; - } - finally - { - isSaving = false; - } - } - - private void Cancel() - { - NavigationManager.NavigateTo("/merchants"); - } - - public class CreateMerchantModel - { - [Required(ErrorMessage = "Merchant name is required")] - public string? MerchantName { get; set; } - - [Required(ErrorMessage = "Settlement schedule is required")] - public string? SettlementSchedule { get; set; } - - [Required(ErrorMessage = "Address line 1 is required")] - public string? AddressLine1 { get; set; } - - public string? AddressLine2 { get; set; } - - [Required(ErrorMessage = "Town is required")] - public string? Town { get; set; } - - [Required(ErrorMessage = "Region is required")] - public string? Region { get; set; } - - [Required(ErrorMessage = "PostCode is required")] - public string? PostCode { get; set; } - - [Required(ErrorMessage = "Country is required")] - public string? Country { get; set; } - - [Required(ErrorMessage = "Contact name is required")] - public string? ContactName { get; set; } - - [Required(ErrorMessage = "Email address is required")] - [EmailAddress(ErrorMessage = "Invalid email address")] - public string? EmailAddress { get; set; } - - [Required(ErrorMessage = "Phone number is required")] - public string? PhoneNumber { get; set; } - } -} + \ No newline at end of file diff --git a/EstateManagementUI.BlazorServer/Components/Pages/Merchants/New.razor.cs b/EstateManagementUI.BlazorServer/Components/Pages/Merchants/New.razor.cs new file mode 100644 index 00000000..f95766fb --- /dev/null +++ b/EstateManagementUI.BlazorServer/Components/Pages/Merchants/New.razor.cs @@ -0,0 +1,115 @@ +using EstateManagementUI.BlazorServer.Permissions; +using EstateManagementUI.BusinessLogic.Requests; +using System.ComponentModel.DataAnnotations; + +namespace EstateManagementUI.BlazorServer.Components.Pages.Merchants +{ + public partial class New + { + private readonly New.CreateMerchantModel model = new(); + private bool isSaving = false; + private string? successMessage; + private string? errorMessage; + + protected override async Task OnAfterRenderAsync(bool firstRender) { + if (!firstRender) { + await base.OnAfterRenderAsync(firstRender); + return; + } + + await RequirePermission(PermissionSection.Merchant, PermissionFunction.Create); + } + + private async Task HandleSubmit() + { + isSaving = true; + errorMessage = null; + + try + { + var correlationId = new CorrelationId(Guid.NewGuid()); + var estateId = await this.GetEstateId(); + + var address = new MerchantCommands.MerchantAddress(Guid.Empty, model.AddressLine1, model.Town, model.Region, model.PostCode, model.Country); + var contact = new MerchantCommands.MerchantContact(Guid.Empty, model.ContactName, model.EmailAddress, model.PhoneNumber); + + // Get the newly created merchant ID + var merchantId = Guid.NewGuid(); + + // Create merchant + var createCommand = new MerchantCommands.CreateMerchantCommand( + correlationId, + estateId, merchantId, + this.model.MerchantName, + this.model.SettlementSchedule,address, contact); + + var createResult = await Mediator.Send(createCommand); + + if (!createResult.IsSuccess) + { + errorMessage = createResult.Message ?? "Failed to create merchant"; + return; + } + + // Show success message briefly before navigating away + successMessage = "Merchant created successfully."; + StateHasChanged(); + + // Small delay so user sees confirmation (adjust duration as needed) + await Task.Delay(2500); + + // Navigate to merchant list + NavigationManager.NavigateTo($"/merchants"); + } + catch (Exception ex) + { + errorMessage = $"An error occurred: {ex.Message}"; + } + finally + { + isSaving = false; + } + } + + private void Cancel() + { + NavigationManager.NavigateTo("/merchants"); + } + + public class CreateMerchantModel + { + [Required(ErrorMessage = "Merchant name is required")] + public string? MerchantName { get; set; } + + [Required(ErrorMessage = "Settlement schedule is required")] + public string? SettlementSchedule { get; set; } + + [Required(ErrorMessage = "Address line 1 is required")] + public string? AddressLine1 { get; set; } + + public string? AddressLine2 { get; set; } + + [Required(ErrorMessage = "Town is required")] + public string? Town { get; set; } + + [Required(ErrorMessage = "Region is required")] + public string? Region { get; set; } + + [Required(ErrorMessage = "PostCode is required")] + public string? PostCode { get; set; } + + [Required(ErrorMessage = "Country is required")] + public string? Country { get; set; } + + [Required(ErrorMessage = "Contact name is required")] + public string? ContactName { get; set; } + + [Required(ErrorMessage = "Email address is required")] + [EmailAddress(ErrorMessage = "Invalid email address")] + public string? EmailAddress { get; set; } + + [Required(ErrorMessage = "Phone number is required")] + public string? PhoneNumber { get; set; } + } + } +} diff --git a/EstateManagmentUI.BusinessLogic/Client/MerchantMethods.cs b/EstateManagmentUI.BusinessLogic/Client/MerchantMethods.cs index ac910242..e036f8f0 100644 --- a/EstateManagmentUI.BusinessLogic/Client/MerchantMethods.cs +++ b/EstateManagmentUI.BusinessLogic/Client/MerchantMethods.cs @@ -29,6 +29,7 @@ public partial interface IApiClient Task AddDeviceToMerchant(MerchantCommands.AddMerchantDeviceCommand request, CancellationToken cancellationToken); Task SwapMerchantDevice(MerchantCommands.SwapMerchantDeviceCommand request, CancellationToken cancellationToken); Task MakeMerchantDeposit(MerchantCommands.MakeMerchantDepositCommand request, CancellationToken cancellationToken); + Task CreateMerchant(MerchantCommands.CreateMerchantCommand request, CancellationToken cancellationToken); } public partial class ApiClient : IApiClient { @@ -122,6 +123,34 @@ public async Task MakeMerchantDeposit(MerchantCommands.MakeMerchantDepos return Result.Success(); } + public async Task CreateMerchant(MerchantCommands.CreateMerchantCommand request, + CancellationToken cancellationToken) { + var token = await this.GetToken(cancellationToken); + if (token.IsFailed) + return ResultHelpers.CreateFailure(token); + + SettlementSchedule settlementSchedule = Enum.Parse(request.SettlementSchedule); + CreateMerchantRequest apiRequest = new() { MerchantId = request.MerchantId, Name = request.Name,SettlementSchedule = settlementSchedule, Address = new Address { + AddressLine1 = request.MerchantAddress.AddressLine1, + Town = request.MerchantAddress.Town, + Country = request.MerchantAddress.Country, + PostalCode = request.MerchantAddress.PostalCode, + Region = request.MerchantAddress.Region + }, + Contact = new Contact { + ContactName = request.MerchantContact.ContactName, + EmailAddress = request.MerchantContact.ContactEmail, + PhoneNumber = request.MerchantContact.ContactPhone + } + }; + + var apiResult = await this.TransactionProcessorClient.CreateMerchant(token.Data, request.EstateId, apiRequest, cancellationToken); + if (apiResult.IsFailed) + return ResultHelpers.CreateFailure(apiResult); + + return Result.Success(); + } + public async Task RemoveOperatorFromMerchant(MerchantCommands.RemoveOperatorFromMerchantCommand request, CancellationToken cancellationToken) { var token = await this.GetToken(cancellationToken); diff --git a/EstateManagmentUI.BusinessLogic/RequestHandlers/DateRequestHandler.cs b/EstateManagmentUI.BusinessLogic/RequestHandlers/DateRequestHandler.cs index 9f7d0dad..e5197a7c 100644 --- a/EstateManagmentUI.BusinessLogic/RequestHandlers/DateRequestHandler.cs +++ b/EstateManagmentUI.BusinessLogic/RequestHandlers/DateRequestHandler.cs @@ -56,7 +56,7 @@ public class MerchantRequestHandler : IRequestHandler>, IRequestHandler, IRequestHandler, - IRequestHandler, + IRequestHandler, IRequestHandler, IRequestHandler, IRequestHandler, @@ -92,9 +92,9 @@ public async Task Handle(MerchantCommands.AddOperatorToMerchantCommand r return await this.ApiClient.AddOperatorToMerchant(request, cancellationToken); } - public async Task Handle(Commands.CreateMerchantCommand request, + public async Task Handle(MerchantCommands.CreateMerchantCommand request, CancellationToken cancellationToken) { - return Result.Success(); + return await this.ApiClient.CreateMerchant(request, cancellationToken); } public async Task Handle(MerchantCommands.MakeMerchantDepositCommand request, diff --git a/EstateManagmentUI.BusinessLogic/Requests/Requests.cs b/EstateManagmentUI.BusinessLogic/Requests/Requests.cs index 32959f4f..5af1092a 100644 --- a/EstateManagmentUI.BusinessLogic/Requests/Requests.cs +++ b/EstateManagmentUI.BusinessLogic/Requests/Requests.cs @@ -85,13 +85,13 @@ public record AssignContractToMerchantCommand(CorrelationId CorrelationId, Guid public record AddMerchantDeviceCommand(CorrelationId CorrelationId, Guid EstateId, Guid MerchantId, string DeviceIdentifier) : IRequest; public record SwapMerchantDeviceCommand(CorrelationId CorrelationId, Guid EstateId, Guid MerchantId, string OldDevice, string NewDevice) : IRequest; public record MakeMerchantDepositCommand(CorrelationId CorrelationId, Guid EstateId, Guid MerchantId, decimal Amount, DateTime Date, string Reference) : IRequest; + public record CreateMerchantCommand(CorrelationId CorrelationId, Guid EstateId, Guid MerchantId, string Name, String SettlementSchedule, MerchantAddress MerchantAddress, MerchantContact MerchantContact) : IRequest; } public static class Commands { public record CreateContractCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, string Description, Guid OperatorId) : IRequest; - public record CreateMerchantCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, string Name, string ContactName, string ContactEmail) : IRequest; public record CreateMerchantUserCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid MerchantId, string EmailAddress, string Password) : IRequest; public record CreateOperatorCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, string Name, bool RequireCustomMerchantNumber, bool RequireCustomTerminalNumber) : IRequest; diff --git a/EstateManagmentUI.BusinessLogic/Services/TestMediatorService.cs b/EstateManagmentUI.BusinessLogic/Services/TestMediatorService.cs index 62f44916..05fdb1ec 100644 --- a/EstateManagmentUI.BusinessLogic/Services/TestMediatorService.cs +++ b/EstateManagmentUI.BusinessLogic/Services/TestMediatorService.cs @@ -65,9 +65,9 @@ public Task Send(IRequest request, Cancellation Queries.GetMerchantSettlementHistoryQuery query => Task.FromResult((TResponse)(object)Result.Success(this.GetMockMerchantSettlementHistory(query))), Queries.GetSettlementSummaryQuery query => Task.FromResult((TResponse)(object)Result.Success(this.GetMockSettlementSummary(query))), Queries.GetTransactionDetailQuery q => Task.FromResult((TResponse)(object)Result.Success(this.GetMockTransactionDetails(q))), - + // Commands - execute against test data store - Commands.CreateMerchantCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteCreateMerchant(cmd)), + MerchantCommands.CreateMerchantCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteCreateMerchant(cmd)), MerchantCommands.UpdateMerchantCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteUpdateMerchant(cmd)), Commands.CreateOperatorCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteCreateOperator(cmd)), Commands.UpdateOperatorCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteUpdateOperator(cmd)), @@ -145,14 +145,14 @@ private Result GetContractResult(Guid estateId, Guid contractId) } // Command execution methods - private Result ExecuteCreateMerchant(Commands.CreateMerchantCommand cmd) + private Result ExecuteCreateMerchant(MerchantCommands.CreateMerchantCommand cmd) { var merchant = new MerchantModel { MerchantId = Guid.NewGuid(), MerchantName = cmd.Name, - ContactName = cmd.ContactName, - ContactEmailAddress = cmd.ContactEmail, + ContactName = cmd.MerchantContact.ContactName, + ContactEmailAddress = cmd.MerchantContact.ContactEmail, SettlementSchedule = "Immediate" }; this._testDataStore.AddMerchant(cmd.EstateId, merchant);