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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions EstateManagementUI.BlazorServer.Tests/Pages/HomePageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public void Home_RendersCorrectly()
this._mockMediator.Setup(m => m.Send(It.IsAny<Queries.GetMerchantKpiQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockMerchantKpi()));
this._mockMediator.Setup(m => m.Send(It.IsAny<Queries.GetTodaysSalesQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockTodaysSales()));
this._mockMediator.Setup(m => m.Send(It.IsAny<Queries.GetTodaysFailedSalesQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockTodaysSales()));
this._mockMediator.Setup(m => m.Send(It.IsAny<Queries.GetMerchantsQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockMerchants()));
this._mockMediator.Setup(m => m.Send(It.IsAny<Queries.GetRecentMerchantsQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockRecentMerchants()));

// Act
var cut = RenderComponent<Home>();
Expand All @@ -87,7 +87,7 @@ public void Home_HasCorrectPageTitle()
this._mockMediator.Setup(m => m.Send(It.IsAny<Queries.GetMerchantKpiQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockMerchantKpi()));
this._mockMediator.Setup(m => m.Send(It.IsAny<Queries.GetTodaysSalesQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockTodaysSales()));
this._mockMediator.Setup(m => m.Send(It.IsAny<Queries.GetTodaysFailedSalesQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockTodaysSales()));
this._mockMediator.Setup(m => m.Send(It.IsAny<Queries.GetMerchantsQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockMerchants()));
this._mockMediator.Setup(m => m.Send(It.IsAny<Queries.GetRecentMerchantsQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockRecentMerchants()));


// Act
Expand Down
7 changes: 4 additions & 3 deletions EstateManagementUI.BlazorServer/Components/Pages/Home.razor
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@
</div>
<div class="card-body">
<div class="space-y-3">
@foreach (var merchant in recentMerchants.Take(5))
@foreach (var merchant in recentMerchants)
{
<div class="flex items-center justify-between p-3 bg-gray-50 rounded hover:bg-gray-100 transition-colors">
<div class="flex items-center">
Expand All @@ -188,8 +188,9 @@
</svg>
</div>
<div>
<p class="text-gray-900 font-medium">@merchant.MerchantName</p>
<p class="text-sm text-gray-500">@merchant.MerchantReference</p>
<p class="text-gray-900 font-medium">@merchant.Name (@merchant.Reference)</p>
@* <p class="text-sm text-gray-500">@merchant.Reference</p> *@
<p class="text-sm text-gray-500">@merchant.CreatedDateTime.ToString("dd/MM/yyyy HH:mm")</p>
</div>
</div>
<a href="/merchants/@merchant.MerchantId" class="btn btn-sm btn-primary">View</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public partial class Home
private TodaysSalesModel? todaysSales;
private TodaysSalesModel? todaysFailedSales;
private List<ComparisonDateModel>? comparisonDates;
private List<MerchantModel>? recentMerchants;
private List<RecentMerchantsModel>? recentMerchants;
private string _selectedComparisonDate = DateTime.Now.AddDays(-7).ToString("yyyy-MM-dd");
private int changeEventCounter = 0;

Expand Down Expand Up @@ -115,7 +115,7 @@ private async Task<Result> LoadDashboardData(CorrelationId correlationId, Guid e
var kpiTask = Mediator.Send(new Queries.GetMerchantKpiQuery(correlationId, estateId));
var salesTask = Mediator.Send(new Queries.GetTodaysSalesQuery(correlationId, estateId, comparisonDateResult.Data));
var failedSalesTask = Mediator.Send(new Queries.GetTodaysFailedSalesQuery(correlationId, estateId, LOW_CREDIT_RESPONSE_CODE, comparisonDateResult.Data));
var merchantsTask = Mediator.Send(new Queries.GetMerchantsQuery(correlationId, estateId));
var merchantsTask = Mediator.Send(new Queries.GetRecentMerchantsQuery(correlationId, estateId));

await Task.WhenAll(kpiTask, salesTask, failedSalesTask, merchantsTask);

Expand Down
24 changes: 24 additions & 0 deletions EstateManagementUI.BlazorServer/Factories/ModelFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -296,5 +296,29 @@ public static List<FileImportLogModel> ConvertFrom(List<BusinessLogic.Models.Fil
models.ForEach(m => result.Add(ConvertFrom(m)));
return result;
}

public static List<RecentMerchantsModel>? ConvertFrom(List<BusinessLogic.Models.RecentMerchantsModel> models) {
List<RecentMerchantsModel> result = new List<RecentMerchantsModel>();
models.ForEach(m => result.Add(ConvertFrom(m)));
return result;
}

private static RecentMerchantsModel ConvertFrom(BusinessLogic.Models.RecentMerchantsModel model) {
RecentMerchantsModel result = new RecentMerchantsModel() {
CreatedDateTime = model.CreatedDateTime,
EstateReportingId = model.EstateReportingId,
LastSale = model.LastSale,
LastSaleDateTime = model.LastSaleDateTime,
LastStatement = model.LastStatement,
MerchantId = model.MerchantId,
MerchantReportingId = model.MerchantReportingId,
Name = model.Name,
PostCode = model.PostCode,
Reference = model.Reference,
Region = model.Region,
Town = model.Town
};
return result;
}
}
}
16 changes: 16 additions & 0 deletions EstateManagementUI.BlazorServer/Models/Models.cs
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,19 @@ public class TransactionDetailModel
public decimal NetAmount { get; set; }
public string? SettlementReference { get; set; }
}

public class RecentMerchantsModel
{
public DateTime CreatedDateTime { get; set; }
public Int32 EstateReportingId { get; set; }
public DateTime LastSale { get; set; }
public DateTime LastSaleDateTime { get; set; }
public DateTime LastStatement { get; set; }
public Guid MerchantId { get; set; }
public Int32 MerchantReportingId { get; set; }
public String Name { get; set; }
public String PostCode { get; set; }
public String Reference { get; set; }
public String Region { get; set; }
public String Town { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
[JsonProperty("date")]
public DateTime Date { get; set; }
[JsonProperty("description")]
public String Description { get; set; }

Check warning on line 12 in EstateManagmentUI.BusinessLogic/BackendAPI/DataTransferObjects/DataTransferObjects.cs

View workflow job for this annotation

GitHub Actions / Build and Unit Test

Non-nullable property 'Description' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
}

public class MerchantKpi
Expand Down Expand Up @@ -37,4 +37,36 @@
[JsonProperty("comparison_average_sales_value")]
public Decimal ComparisonAverageSalesValue { get; set; }
}

public class Merchant
{
#region Properties

[JsonProperty("created_date_time")]
public DateTime CreatedDateTime { get; set; }
[JsonProperty("estate_reporting_id")]
public Int32 EstateReportingId { get; set; }
[JsonProperty("last_sale")]
public DateTime LastSale { get; set; }
[JsonProperty("last_sale_date_time")]
public DateTime LastSaleDateTime { get; set; }
[JsonProperty("last_statement")]
public DateTime LastStatement { get; set; }
[JsonProperty("merchant_id")]
public Guid MerchantId { get; set; }
[JsonProperty("merchant_reporting_id")]
public Int32 MerchantReportingId { get; set; }
[JsonProperty("name")]
public String Name { get; set; }

Check warning on line 60 in EstateManagmentUI.BusinessLogic/BackendAPI/DataTransferObjects/DataTransferObjects.cs

View workflow job for this annotation

GitHub Actions / Build and Unit Test

Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
[JsonProperty("post_code")]
public String PostCode { get; set; }

Check warning on line 62 in EstateManagmentUI.BusinessLogic/BackendAPI/DataTransferObjects/DataTransferObjects.cs

View workflow job for this annotation

GitHub Actions / Build and Unit Test

Non-nullable property 'PostCode' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
[JsonProperty("reference")]
public String Reference { get; set; }

Check warning on line 64 in EstateManagmentUI.BusinessLogic/BackendAPI/DataTransferObjects/DataTransferObjects.cs

View workflow job for this annotation

GitHub Actions / Build and Unit Test

Non-nullable property 'Reference' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
[JsonProperty("region")]
public String Region { get; set; }

Check warning on line 66 in EstateManagmentUI.BusinessLogic/BackendAPI/DataTransferObjects/DataTransferObjects.cs

View workflow job for this annotation

GitHub Actions / Build and Unit Test

Non-nullable property 'Region' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
[JsonProperty("town")]
public String Town { get; set; }

Check warning on line 68 in EstateManagmentUI.BusinessLogic/BackendAPI/DataTransferObjects/DataTransferObjects.cs

View workflow job for this annotation

GitHub Actions / Build and Unit Test

Non-nullable property 'Town' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
Task<Result<List<ComparisonDate>>> GetComparisonDates(String accessToken, Guid estateId, CancellationToken cancellationToken);
Task<Result<MerchantKpi>> GetMerchantKpi(String accessToken, Guid estateId, CancellationToken cancellationToken);

Task<Result<List<Merchant>>> GetRecentMerchants(String accessToken,
Guid estateId,
CancellationToken cancellationToken);
Task<Result<TodaysSales>> GetTodaysSales(String accessToken,
Guid estateId,
Int32 merchantReportingId,
Expand Down Expand Up @@ -83,6 +86,31 @@
}
}

public async Task<Result<List<Merchant>>> GetRecentMerchants(String accessToken, Guid estateId, CancellationToken cancellationToken)
{
String requestUri = this.BuildRequestUrl("/api/merchants/recent");

try
{
List<(String headerName, String headerValue)> additionalHeaders = [
(EstateIdHeaderName, estateId.ToString())
];
Result<List<Merchant>> result = await this.SendHttpGetRequest<List<Merchant>>(requestUri, accessToken, additionalHeaders, cancellationToken);

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

return result;
}
catch (Exception ex)
{
// An exception has occurred, add some additional information to the message
Exception exception = new Exception($"Error getting recent merchants for estate {estateId}.", ex);

return Result.Failure(exception.Message);
}
}

public async Task<Result<TodaysSales>> GetTodaysSales(String accessToken, Guid estateId, Int32 merchantReportingId, Int32 operatorReportingId, DateTime comparisonDate, CancellationToken cancellationToken)
{
QueryStringBuilder builder = new QueryStringBuilder();
Expand Down Expand Up @@ -186,24 +214,24 @@
if (alwaysInclude)
return false;

Object? defaultValue = GetDefault(value.GetType());

Check warning on line 217 in EstateManagmentUI.BusinessLogic/BackendAPI/IEstateReportingApiClient.cs

View workflow job for this annotation

GitHub Actions / Build and Unit Test

Dereference of a possibly null reference.

if (defaultValue == null && value.GetType() == typeof(String))
{
defaultValue = String.Empty;
}
return defaultValue.Equals(value);

Check warning on line 223 in EstateManagmentUI.BusinessLogic/BackendAPI/IEstateReportingApiClient.cs

View workflow job for this annotation

GitHub Actions / Build and Unit Test

Dereference of a possibly null reference.
}

public static object GetDefault(Type t)
{
Func<object> f = GetDefault<object>;
return f.Method.GetGenericMethodDefinition().MakeGenericMethod(t).Invoke(null, null);

Check warning on line 229 in EstateManagmentUI.BusinessLogic/BackendAPI/IEstateReportingApiClient.cs

View workflow job for this annotation

GitHub Actions / Build and Unit Test

Possible null reference return.
}

private static T GetDefault<T>()
{
return default(T);

Check warning on line 234 in EstateManagmentUI.BusinessLogic/BackendAPI/IEstateReportingApiClient.cs

View workflow job for this annotation

GitHub Actions / Build and Unit Test

Possible null reference return.
}

public string BuildQueryString()
Expand Down
24 changes: 24 additions & 0 deletions EstateManagmentUI.BusinessLogic/Client/APIModelFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,28 @@ public static TodaysSalesModel ConvertFrom(TodaysSales apiResultData) {
};
return model;
}

public static List<RecentMerchantsModel> ConvertFrom(List<Merchant> apiResultData) {
List<RecentMerchantsModel> merchants = new();

foreach (Merchant merchant in apiResultData) {
merchants.Add(new RecentMerchantsModel
{
CreatedDateTime = merchant.CreatedDateTime,
EstateReportingId = merchant.EstateReportingId,
LastSale = merchant.LastSale,
LastSaleDateTime = merchant.LastSaleDateTime,
LastStatement = merchant.LastStatement,
MerchantId = merchant.MerchantId,
MerchantReportingId = merchant.MerchantReportingId,
Name = merchant.Name,
PostCode = merchant.PostCode,
Reference = merchant.Reference,
Region = merchant.Region,
Town = merchant.Town
});
}

return merchants;
}
}
20 changes: 19 additions & 1 deletion EstateManagmentUI.BusinessLogic/Client/MerchantMethods.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using EstateManagementUI.BusinessLogic.Models;
using EstateManagementUI.BusinessLogic.BackendAPI.DataTransferObjects;
using EstateManagementUI.BusinessLogic.Models;
using EstateManagementUI.BusinessLogic.Requests;
using SecurityService.DataTransferObjects.Responses;
using Shared.Results;
Expand All @@ -9,6 +10,7 @@ namespace EstateManagementUI.BusinessLogic.Client
public partial interface IApiClient
{
Task<Result<MerchantKpiModel>> GetMerchantKpi(Queries.GetMerchantKpiQuery request, CancellationToken cancellationToken);
Task<Result<List<RecentMerchantsModel>>> GetRecentMerchants(Queries.GetRecentMerchantsQuery request, CancellationToken cancellationToken);
}

public partial class ApiClient : IApiClient {
Expand All @@ -29,5 +31,21 @@ public async Task<Result<MerchantKpiModel>> GetMerchantKpi(Queries.GetMerchantKp

return Result.Success(merchantKpiModel);
}

public async Task<Result<List<RecentMerchantsModel>>> GetRecentMerchants(Queries.GetRecentMerchantsQuery request,
CancellationToken cancellationToken) {
Result<String> token = await this.GetToken(cancellationToken);
if (token.IsFailed)
return ResultHelpers.CreateFailure(token);

Result<List<Merchant>> apiResult = await this.EstateReportingApiClient.GetRecentMerchants(token.Data, request.EstateId, cancellationToken);

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

List<RecentMerchantsModel> recentMerchantsModels = APIModelFactory.ConvertFrom(apiResult.Data);

return Result.Success(recentMerchantsModels);
}
}
}
25 changes: 25 additions & 0 deletions EstateManagmentUI.BusinessLogic/Client/StubTestData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,31 @@ public static class StubTestData {
}
};

public static List<RecentMerchantsModel> GetMockRecentMerchants() => new()
{
new RecentMerchantsModel
{
MerchantId = Guid.Parse("22222222-2222-2222-2222-222222222222"),
Name = "Test Merchant 1",
Reference = "MERCH001",
CreatedDateTime = DateTime.Now
},
new RecentMerchantsModel
{
MerchantId = Guid.Parse("22222222-2222-2222-2222-222222222223"),
Name = "Test Merchant 2",
Reference = "MERCH002",
CreatedDateTime = DateTime.Now.AddDays(-1)
},
new RecentMerchantsModel
{
MerchantId = Guid.Parse("22222222-2222-2222-2222-222222222224"),
Name = "Test Merchant 3",
Reference = "MERCH003",
CreatedDateTime = DateTime.Now.AddDays(-5)
}
};

public static MerchantModel GetMockMerchant() => new()
{
MerchantId = Guid.Parse("22222222-2222-2222-2222-222222222222"),
Expand Down
17 changes: 17 additions & 0 deletions EstateManagmentUI.BusinessLogic/Models/Models.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class MerchantModel
public string? ContactName { get; set; }
public string? ContactEmailAddress { get; set; }
public string? ContactPhoneNumber { get; set; }
public DateTime CreatedDateTime { get; set; }
}

// Operator Models
Expand Down Expand Up @@ -253,3 +254,19 @@ public class TransactionDetailModel
public decimal NetAmount { get; set; }
public string? SettlementReference { get; set; }
}

public class RecentMerchantsModel
{
public DateTime CreatedDateTime { get; set; }
public Int32 EstateReportingId { get; set; }
public DateTime LastSale { get; set; }
public DateTime LastSaleDateTime { get; set; }
public DateTime LastStatement { get; set; }
public Guid MerchantId { get; set; }
public Int32 MerchantReportingId { get; set; }
public String Name { get; set; }
public String PostCode { get; set; }
public String Reference { get; set; }
public String Region { get; set; }
public String Town { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ public class MerchantRequestHandler : IRequestHandler<Queries.GetMerchantsQuery,
IRequestHandler<Commands.UpdateMerchantAddressCommand, Result>,
IRequestHandler<Commands.UpdateMerchantCommand, Result>,
IRequestHandler<Commands.UpdateMerchantContactCommand, Result>,
IRequestHandler<Commands.AssignContractToMerchantCommand, Result>
IRequestHandler<Commands.AssignContractToMerchantCommand, Result>,
IRequestHandler<Queries.GetRecentMerchantsQuery, Result<List<RecentMerchantsModel>>>
{
private readonly IApiClient ApiClient;

Expand Down Expand Up @@ -136,6 +137,11 @@ public async Task<Result> Handle(Commands.AssignContractToMerchantCommand reques
CancellationToken cancellationToken) {
return Result.Success();
}

public async Task<Result<List<RecentMerchantsModel>>> Handle(Queries.GetRecentMerchantsQuery request,
CancellationToken cancellationToken) {
return await this.ApiClient.GetRecentMerchants(request, cancellationToken);
}
}

public class ContractRequestHandler : IRequestHandler<Queries.GetContractsQuery, Result<List<ContractModel>>>,
Expand Down
1 change: 1 addition & 0 deletions EstateManagmentUI.BusinessLogic/Requests/Requests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public static class Queries
{
public record GetEstateQuery(CorrelationId CorrelationId, string AccessToken, Guid EstateId) : IRequest<Result<EstateModel>>;
public record GetMerchantsQuery(CorrelationId CorrelationId, Guid EstateId) : IRequest<Result<List<MerchantModel>>>;
public record GetRecentMerchantsQuery(CorrelationId CorrelationId, Guid EstateId) : IRequest<Result<List<RecentMerchantsModel>>>;
public record GetOperatorsQuery(CorrelationId CorrelationId, string AccessToken, Guid EstateId) : IRequest<Result<List<OperatorModel>>>;
public record GetContractsQuery(CorrelationId CorrelationId, string AccessToken, Guid EstateId) : IRequest<Result<List<ContractModel>>>;
public record GetOperatorQuery(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid OperatorId) : IRequest<Result<OperatorModel>>;
Expand Down
1 change: 1 addition & 0 deletions EstateManagmentUI.BusinessLogic/Services/ITestDataStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public interface ITestDataStore

// Merchant Management
List<MerchantModel> GetMerchants(Guid estateId);
List<RecentMerchantsModel> GetRecentMerchants(Guid estateId);
MerchantModel? GetMerchant(Guid estateId, Guid merchantId);
void AddMerchant(Guid estateId, MerchantModel merchant);
void UpdateMerchant(Guid estateId, MerchantModel merchant);
Expand Down
Loading