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
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public async Task EstateManagementManager_GetMerchants_MerchantListIsReturned()
this.EstateManagementRepository.Setup(e => e.GetMerchants(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(new List<Merchant>
{
TestData
.MerchantModelWithAddressesContactsDevicesAndOperators
.MerchantModelWithAddressesContactsDevicesAndOperators()
});

List<Merchant> merchantList = await this.EstateManagementManager.GetMerchants(TestData.EstateId, CancellationToken.None);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,20 @@ public void MerchantRequestHandler_SetMerchantSettlementScheduleRequest_IsHandle
});

}

[Fact]
public void MerchantRequestHandler_SwapMerchantDeviceRequest_IsHandled()
{
Mock<IMerchantDomainService> merchantDomainService = new Mock<IMerchantDomainService>();
MerchantRequestHandler handler = new MerchantRequestHandler(merchantDomainService.Object);

SwapMerchantDeviceRequest request = TestData.SwapMerchantDeviceRequest;

Should.NotThrow(async () =>
{
await handler.Handle(request, CancellationToken.None);
});

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -596,5 +596,80 @@ await domainService.SetMerchantSettlementSchedule(TestData.EstateId,
CancellationToken.None);
});
}

[Fact]
public async Task MerchantDomainService_SwapMerchantDevice_MerchantDeviceSwapped()
{
Mock<IAggregateRepository<EstateAggregate, DomainEventRecord.DomainEvent>> estateAggregateRepository = new Mock<IAggregateRepository<EstateAggregate, DomainEventRecord.DomainEvent>>();
estateAggregateRepository.Setup(e => e.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(TestData.CreatedEstateAggregate);

Mock<IAggregateRepository<MerchantAggregate, DomainEventRecord.DomainEvent>> merchantAggregateRepository = new Mock<IAggregateRepository<MerchantAggregate, DomainEventRecord.DomainEvent>>();
merchantAggregateRepository.Setup(m => m.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(TestData.MerchantAggregateWithDevice);
merchantAggregateRepository.Setup(m => m.SaveChanges(It.IsAny<MerchantAggregate>(), It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);

Mock<ISecurityServiceClient> securityServiceClient = new Mock<ISecurityServiceClient>();

MerchantDomainService domainService = new MerchantDomainService(estateAggregateRepository.Object, merchantAggregateRepository.Object, securityServiceClient.Object);

Should.NotThrow(async () =>
{
await domainService.SwapMerchantDevice(TestData.EstateId,
TestData.MerchantId,
TestData.DeviceId,
TestData.DeviceIdentifier,
TestData.NewDeviceIdentifier,
CancellationToken.None);
});
}

[Fact]
public async Task MerchantDomainService_SwapMerchantDevice_MerchantNotCreated_ErrorThrown()
{
Mock<IAggregateRepository<EstateAggregate, DomainEventRecord.DomainEvent>> estateAggregateRepository = new Mock<IAggregateRepository<EstateAggregate, DomainEventRecord.DomainEvent>>();
estateAggregateRepository.Setup(e => e.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(TestData.CreatedEstateAggregate);

Mock<IAggregateRepository<MerchantAggregate, DomainEventRecord.DomainEvent>> merchantAggregateRepository = new Mock<IAggregateRepository<MerchantAggregate, DomainEventRecord.DomainEvent>>();
merchantAggregateRepository.Setup(m => m.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(new MerchantAggregate());
merchantAggregateRepository.Setup(m => m.SaveChanges(It.IsAny<MerchantAggregate>(), It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);

Mock<ISecurityServiceClient> securityServiceClient = new Mock<ISecurityServiceClient>();

MerchantDomainService domainService = new MerchantDomainService(estateAggregateRepository.Object, merchantAggregateRepository.Object, securityServiceClient.Object);

Should.Throw<InvalidOperationException>(async () =>
{
await domainService.SwapMerchantDevice(TestData.EstateId,
TestData.MerchantId,
TestData.DeviceId,
TestData.DeviceIdentifier,
TestData.NewDeviceIdentifier,
CancellationToken.None);
});
}

[Fact]
public async Task MerchantDomainService_SwapMerchantDevice_EstateNotCreated_ErrorThrown()
{
Mock<IAggregateRepository<EstateAggregate, DomainEventRecord.DomainEvent>> estateAggregateRepository = new Mock<IAggregateRepository<EstateAggregate, DomainEventRecord.DomainEvent>>();
estateAggregateRepository.Setup(e => e.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(new EstateAggregate());

Mock<IAggregateRepository<MerchantAggregate, DomainEventRecord.DomainEvent>> merchantAggregateRepository = new Mock<IAggregateRepository<MerchantAggregate, DomainEventRecord.DomainEvent>>();
merchantAggregateRepository.Setup(m => m.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(TestData.MerchantAggregateWithDevice);
merchantAggregateRepository.Setup(m => m.SaveChanges(It.IsAny<MerchantAggregate>(), It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);

Mock<ISecurityServiceClient> securityServiceClient = new Mock<ISecurityServiceClient>();

MerchantDomainService domainService = new MerchantDomainService(estateAggregateRepository.Object, merchantAggregateRepository.Object, securityServiceClient.Object);

Should.Throw<InvalidOperationException>(async () =>
{
await domainService.SwapMerchantDevice(TestData.EstateId,
TestData.MerchantId,
TestData.DeviceId,
TestData.DeviceIdentifier,
TestData.NewDeviceIdentifier,
CancellationToken.None);
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public class MerchantRequestHandler : IRequestHandler<CreateMerchantRequest, Str
IRequestHandler<CreateMerchantUserRequest, Guid>,
IRequestHandler<AddMerchantDeviceRequest, String>,
IRequestHandler<MakeMerchantDepositRequest, Guid>,
IRequestHandler<SetMerchantSettlementScheduleRequest,String>
IRequestHandler<SetMerchantSettlementScheduleRequest,String>,
IRequestHandler<SwapMerchantDeviceRequest, String>
{
#region Fields

Expand Down Expand Up @@ -161,5 +162,12 @@ public async Task<String> Handle(SetMerchantSettlementScheduleRequest request,

return String.Empty;
}

public async Task<string> Handle(SwapMerchantDeviceRequest request, CancellationToken cancellationToken)
{
await this.MerchantDomainService.SwapMerchantDevice(request.EstateId, request.MerchantId, request.DeviceId, request.OriginalDeviceIdentifier, request.NewDeviceIdentifier,cancellationToken);

return string.Empty;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System;
using MediatR;

namespace EstateManagement.BusinessLogic.Requests
{
public class SwapMerchantDeviceRequest : IRequest<string>
{
#region Constructors

/// <summary>
/// Initializes a new instance of the <see cref="AssignOperatorToMerchantRequest" /> class.
/// </summary>
/// <param name="estateId">The estate identifier.</param>
/// <param name="merchantId">The merchant identifier.</param>
/// <param name="deviceId">The device identifier.</param>
/// <param name="deviceIdentifier">The device identifier.</param>
private SwapMerchantDeviceRequest(Guid estateId,
Guid merchantId,
Guid deviceId,
String originalDeviceIdentifier,
String newDeviceIdentifier)
{
this.EstateId = estateId;
this.MerchantId = merchantId;
this.DeviceId = deviceId;
this.OriginalDeviceIdentifier = originalDeviceIdentifier;
this.NewDeviceIdentifier = newDeviceIdentifier;
}

#endregion

#region Properties

/// <summary>
/// The device identifier
/// </summary>
public String OriginalDeviceIdentifier { get; }

/// <summary>
/// The device identifier
/// </summary>
public String NewDeviceIdentifier { get; }

public Guid DeviceId { get; }

/// <summary>
/// The estate identifier
/// </summary>
public Guid EstateId { get; }

/// <summary>
/// The merchant identifier
/// </summary>
public Guid MerchantId { get; }

#endregion

#region Methods

/// <summary>
/// Creates the specified estate identifier.
/// </summary>
/// <param name="estateId">The estate identifier.</param>
/// <param name="merchantId">The merchant identifier.</param>
/// <param name="deviceId">The device identifier.</param>
/// <param name="deviceIdentifier">The device identifier.</param>
/// <returns></returns>
public static SwapMerchantDeviceRequest Create(Guid estateId,
Guid merchantId,
Guid deviceId,
String originalDeviceIdentifier,
String newDeviceIdentifier)
{
return new SwapMerchantDeviceRequest(estateId, merchantId, deviceId,originalDeviceIdentifier, newDeviceIdentifier);
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ Task AddDeviceToMerchant(Guid estateId,
String deviceIdentifier,
CancellationToken cancellationToken);

Task SwapMerchantDevice(Guid estateId,
Guid merchantId,
Guid deviceId,
String originalDeviceIdentifier,
String newDeviceIdentifier,
CancellationToken cancellationToken);

/// <summary>
/// Makes the merchant deposit.
/// </summary>
Expand Down
23 changes: 23 additions & 0 deletions EstateManagement.BusinessLogic/Services/MerchantDomainService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,29 @@ public async Task AddDeviceToMerchant(Guid estateId,
await this.MerchantAggregateRepository.SaveChanges(merchantAggregate, cancellationToken);
}

public async Task SwapMerchantDevice(Guid estateId, Guid merchantId, Guid deviceId, string originalDeviceIdentifier,
string newDeviceIdentifier, CancellationToken cancellationToken)
{
MerchantAggregate merchantAggregate = await this.MerchantAggregateRepository.GetLatestVersion(merchantId, cancellationToken);

// Check merchant has been created
if (merchantAggregate.IsCreated == false)
{
throw new InvalidOperationException($"Merchant Id {merchantId} has not been created");
}

// Estate Id is a valid estate
EstateAggregate estateAggregate = await this.EstateAggregateRepository.GetLatestVersion(estateId, cancellationToken);
if (estateAggregate.IsCreated == false)
{
throw new InvalidOperationException($"Estate Id {estateId} has not been created");
}

merchantAggregate.SwapDevice(deviceId, originalDeviceIdentifier, newDeviceIdentifier);

await this.MerchantAggregateRepository.SaveChanges(merchantAggregate, cancellationToken);
}

/// <summary>
/// Makes the merchant deposit.
/// </summary>
Expand Down
39 changes: 39 additions & 0 deletions EstateManagement.Client/EstateClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,45 @@ public async Task<AddMerchantDeviceResponse> AddDeviceToMerchant(String accessTo
return response;
}

public async Task<SwapMerchantDeviceResponse> SwapDeviceForMerchant(String accessToken,
Guid estateId,
Guid merchantId,
SwapMerchantDeviceRequest swapMerchantDeviceRequest,
CancellationToken cancellationToken)
{
SwapMerchantDeviceResponse response = null;

String requestUri = this.BuildRequestUrl($"/api/estates/{estateId}/merchants/{merchantId}/devices");

try
{
String requestSerialised = JsonConvert.SerializeObject(swapMerchantDeviceRequest);

StringContent httpContent = new StringContent(requestSerialised, Encoding.UTF8, "application/json");

// Add the access token to the client headers
this.HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

// Make the Http Call here
HttpResponseMessage httpResponse = await this.HttpClient.PatchAsync(requestUri, httpContent, cancellationToken);

// Process the response
String content = await this.HandleResponse(httpResponse, cancellationToken);

// call was successful so now deserialise the body to the response object
response = JsonConvert.DeserializeObject<SwapMerchantDeviceResponse>(content);
}
catch (Exception ex)
{
// An exception has occurred, add some additional information to the message
Exception exception = new Exception($"Error swapping device for merchant Id {merchantId} in estate {estateId}.", ex);

throw exception;
}

return response;
}

/// <summary>
/// Adds the product to contract.
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions EstateManagement.Client/IEstateClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ Task<AddMerchantDeviceResponse> AddDeviceToMerchant(String accessToken,
AddMerchantDeviceRequest request,
CancellationToken cancellationToken);

Task<SwapMerchantDeviceResponse> SwapDeviceForMerchant(String accessToken,
Guid estateId,
Guid merchantId,
SwapMerchantDeviceRequest request,
CancellationToken cancellationToken);

/// <summary>
/// Adds the product to contract.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using Newtonsoft.Json;

namespace EstateManagement.DataTransferObjects.Requests
{
public class SwapMerchantDeviceRequest
{
[JsonProperty("original_device_identifier")]
public String OriginalDeviceIdentifier { get; set; }

/// <summary>
/// Gets or sets the device identifier.
/// </summary>
/// <value>
/// The device identifier.
/// </value>
[JsonProperty("new_device_identifier")]
public String NewDeviceIdentifier { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json;

namespace EstateManagement.DataTransferObjects.Responses
{
[ExcludeFromCodeCoverage]
public class SwapMerchantDeviceResponse
{
#region Properties

/// <summary>
/// Gets or sets the estate identifier.
/// </summary>
/// <value>
/// The estate identifier.
/// </value>
[JsonProperty("estate_id")]
public Guid EstateId { get; set; }

/// <summary>
/// Gets or sets the merchant identifier.
/// </summary>
/// <value>
/// The merchant identifier.
/// </value>
[JsonProperty("merchant_id")]
public Guid MerchantId { get; set; }

/// <summary>
/// Gets or sets the device identifier.
/// </summary>
/// <value>
/// The device identifier.
/// </value>
[JsonProperty("device_id")]
public Guid DeviceId { get; set; }

#endregion
}
}
Loading