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);