Skip to content

Commit 41f7f60

Browse files
Merge pull request #438 from TransactionProcessing/task/#437_incompletesettlement
Incomplete Settlement for immediate settlement merchants
2 parents ae03d87 + 238d578 commit 41f7f60

File tree

4 files changed

+132
-5
lines changed

4 files changed

+132
-5
lines changed

TransactionProcessor.BusinessLogic.Tests/Services/SettlementDomainServiceTests.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
using System.Threading;
55
using System.Threading.Tasks;
66
using BusinessLogic.Services;
7+
using EstateManagement.Client;
78
using Microsoft.Extensions.Configuration;
89
using Models;
910
using Moq;
11+
using SecurityService.Client;
1012
using SettlementAggregates;
1113
using Shared.DomainDrivenDesign.EventSourcing;
1214
using Shared.EventStore.Aggregate;
@@ -23,16 +25,23 @@ public class SettlementDomainServiceTests
2325

2426
private Mock<IAggregateRepository<SettlementAggregate, DomainEvent>> settlementAggregateRepository;
2527

28+
private Mock<ISecurityServiceClient> securityServiceClient;
29+
30+
private Mock<IEstateClient> estateClient;
31+
2632
private SettlementDomainService settlementDomainService;
2733

2834
public SettlementDomainServiceTests() {
2935
this.transactionAggregateRepository =
3036
new Mock<IAggregateRepository<TransactionAggregate, DomainEvent>>();
3137
this.settlementAggregateRepository =
3238
new Mock<IAggregateRepository<SettlementAggregate, DomainEvent>>();
39+
this.securityServiceClient = new Mock<ISecurityServiceClient>();
40+
this.estateClient = new Mock<IEstateClient>();
3341

3442
this.settlementDomainService =
35-
new SettlementDomainService(this.transactionAggregateRepository.Object, settlementAggregateRepository.Object);
43+
new SettlementDomainService(this.transactionAggregateRepository.Object, settlementAggregateRepository.Object,
44+
this.securityServiceClient.Object, this.estateClient.Object);
3645

3746
IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build();
3847
ConfigurationReader.Initialise(configurationRoot);
@@ -48,6 +57,11 @@ public async Task SettlementDomainService_ProcessSettlement_SettlementIsProcesse
4857
this.transactionAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
4958
.ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionAggregate);
5059

60+
this.securityServiceClient.Setup(s => s.GetToken(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>())).ReturnsAsync(TestData.TokenResponse);
61+
62+
this.estateClient.Setup(e => e.GetMerchant(It.IsAny<String>(), It.IsAny<Guid>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
63+
.ReturnsAsync(TestData.GetMerchantResponseWithOperator1);
64+
5165
ProcessSettlementResponse response = await settlementDomainService.ProcessSettlement(TestData.SettlementDate,
5266
TestData.EstateId,
5367
TestData.MerchantId,
@@ -82,6 +96,11 @@ public async Task SettlementDomainService_ProcessSettlement_SettlementAggregateN
8296
settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
8397
.ReturnsAsync(TestData.GetCreatedSettlementAggregate);
8498

99+
this.securityServiceClient.Setup(s => s.GetToken(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>())).ReturnsAsync(TestData.TokenResponse);
100+
101+
this.estateClient.Setup(e => e.GetMerchant(It.IsAny<String>(), It.IsAny<Guid>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
102+
.ReturnsAsync(TestData.GetMerchantResponseWithOperator1);
103+
85104
ProcessSettlementResponse response = await settlementDomainService.ProcessSettlement(TestData.SettlementDate,
86105
TestData.EstateId,
87106
TestData.MerchantId,
@@ -99,6 +118,11 @@ public async Task SettlementDomainService_ProcessSettlement_AddSettledFeeThrownE
99118
settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
100119
.ReturnsAsync(TestData.GetSettlementAggregateWithPendingMerchantFees(10));
101120

121+
this.securityServiceClient.Setup(s => s.GetToken(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>())).ReturnsAsync(TestData.TokenResponse);
122+
123+
this.estateClient.Setup(e => e.GetMerchant(It.IsAny<String>(), It.IsAny<Guid>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
124+
.ReturnsAsync(TestData.GetMerchantResponseWithOperator1);
125+
102126
ProcessSettlementResponse response = await settlementDomainService.ProcessSettlement(TestData.SettlementDate,
103127
TestData.EstateId,
104128
TestData.MerchantId,
@@ -110,4 +134,4 @@ public async Task SettlementDomainService_ProcessSettlement_AddSettledFeeThrownE
110134
response.NumberOfFeesSuccessfullySettled.ShouldBe(0);
111135
}
112136
}
113-
}
137+
}

TransactionProcessor.BusinessLogic/Services/SettlementDomainService.cs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,21 @@
22
{
33
using System;
44
using System.Collections.Generic;
5+
using System.Diagnostics.CodeAnalysis;
56
using System.Linq;
67
using System.Threading;
78
using System.Threading.Tasks;
89
using Common;
10+
using EstateManagement.Client;
11+
using EstateManagement.DataTransferObjects;
12+
using EstateManagement.DataTransferObjects.Responses;
913
using Models;
14+
using SecurityService.Client;
15+
using SecurityService.DataTransferObjects.Responses;
1016
using SettlementAggregates;
1117
using Shared.DomainDrivenDesign.EventSourcing;
1218
using Shared.EventStore.Aggregate;
19+
using Shared.General;
1320
using Shared.Logger;
1421
using TransactionAggregate;
1522

@@ -18,6 +25,10 @@ public class SettlementDomainService : ISettlementDomainService
1825
private readonly IAggregateRepository<TransactionAggregate, DomainEvent> TransactionAggregateRepository;
1926
private readonly IAggregateRepository<SettlementAggregate, DomainEvent> SettlementAggregateRepository;
2027

28+
private readonly ISecurityServiceClient SecurityServiceClient;
29+
30+
private readonly IEstateClient EstateClient;
31+
2132
public async Task<ProcessSettlementResponse> ProcessSettlement(DateTime settlementDate,
2233
Guid estateId,
2334
Guid merchantId,
@@ -36,6 +47,21 @@ public async Task<ProcessSettlementResponse> ProcessSettlement(DateTime settleme
3647
return response;
3748
}
3849

50+
this.TokenResponse = await this.GetToken(cancellationToken);
51+
52+
MerchantResponse merchant = await this.EstateClient.GetMerchant(this.TokenResponse.AccessToken,
53+
estateId,
54+
merchantId,
55+
cancellationToken);
56+
57+
if (merchant.SettlementSchedule == SettlementSchedule.Immediate){
58+
// Mark the settlement as completed
59+
settlementAggregate.StartProcessing(DateTime.Now);
60+
settlementAggregate.ManuallyComplete();
61+
await this.SettlementAggregateRepository.SaveChanges(settlementAggregate, cancellationToken);
62+
return response;
63+
}
64+
3965
List<(Guid transactionId, Guid merchantId, CalculatedFee calculatedFee)> feesToBeSettled = settlementAggregate.GetFeesToBeSettled();
4066
response.NumberOfFeesPendingSettlement = feesToBeSettled.Count;
4167

@@ -71,10 +97,43 @@ public async Task<ProcessSettlementResponse> ProcessSettlement(DateTime settleme
7197
}
7298

7399
public SettlementDomainService(IAggregateRepository<TransactionAggregate, DomainEvent> transactionAggregateRepository,
74-
IAggregateRepository<SettlementAggregate, DomainEvent> settlementAggregateRepository)
100+
IAggregateRepository<SettlementAggregate, DomainEvent> settlementAggregateRepository,
101+
ISecurityServiceClient securityServiceClient,
102+
IEstateClient estateClient)
75103
{
76104
this.TransactionAggregateRepository = transactionAggregateRepository;
77105
this.SettlementAggregateRepository = settlementAggregateRepository;
106+
this.SecurityServiceClient = securityServiceClient;
107+
this.EstateClient = estateClient;
108+
}
109+
110+
private TokenResponse TokenResponse;
111+
112+
[ExcludeFromCodeCoverage]
113+
private async Task<TokenResponse> GetToken(CancellationToken cancellationToken)
114+
{
115+
// Get a token to talk to the estate service
116+
String clientId = ConfigurationReader.GetValue("AppSettings", "ClientId");
117+
String clientSecret = ConfigurationReader.GetValue("AppSettings", "ClientSecret");
118+
Logger.LogInformation($"Client Id is {clientId}");
119+
Logger.LogInformation($"Client Secret is {clientSecret}");
120+
121+
if (this.TokenResponse == null)
122+
{
123+
TokenResponse token = await this.SecurityServiceClient.GetToken(clientId, clientSecret, cancellationToken);
124+
Logger.LogInformation($"Token is {token.AccessToken}");
125+
return token;
126+
}
127+
128+
if (this.TokenResponse.Expires.UtcDateTime.Subtract(DateTime.UtcNow) < TimeSpan.FromMinutes(2))
129+
{
130+
Logger.LogInformation($"Token is about to expire at {this.TokenResponse.Expires.DateTime:O}");
131+
TokenResponse token = await this.SecurityServiceClient.GetToken(clientId, clientSecret, cancellationToken);
132+
Logger.LogInformation($"Token is {token.AccessToken}");
133+
return token;
134+
}
135+
136+
return this.TokenResponse;
78137
}
79138
}
80139
}

TransactionProcessor.SettlementAggregates.Tests/SettlementAggregateTests.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ public void SettlementAggregate_StartProcessing_CalledTwice_ProcessingStarted(){
209209
aggregate.StartProcessing(TestData.SettlementProcessingStartedDateTimeSecondCall);
210210

211211
aggregate.ProcessingStarted.ShouldBeTrue();
212-
aggregate.ProcessingStartedDateTime.ShouldBe(TestData.SettlementProcessingStartedDateTimeSecondCall);
212+
aggregate.ProcessingStartedDateTime.ShouldBe(TestData.SettlementProcessingStartedDateTimeSecondCall);
213213
}
214214

215215
[Fact]
@@ -221,5 +221,38 @@ public void SettlementAggregate_StartProcessing_SettlementNotCreated_ErrorThron(
221221
aggregate.StartProcessing(TestData.SettlementProcessingStartedDateTime);
222222
});
223223
}
224+
225+
[Fact]
226+
public void SettlementAggregate_ManuallyComplete_SettlementCompleted()
227+
{
228+
SettlementAggregate aggregate = SettlementAggregate.Create(TestData.SettlementAggregateId);
229+
aggregate.Create(TestData.EstateId, TestData.MerchantId, TestData.SettlementDate);
230+
aggregate.StartProcessing(TestData.SettlementProcessingStartedDateTime);
231+
aggregate.ManuallyComplete();
232+
233+
aggregate.SettlementComplete.ShouldBeTrue();
234+
}
235+
236+
[Fact]
237+
public void SettlementAggregate_ManuallyComplete_CalledTwice_SettlementCompleted()
238+
{
239+
SettlementAggregate aggregate = SettlementAggregate.Create(TestData.SettlementAggregateId);
240+
aggregate.Create(TestData.EstateId, TestData.MerchantId, TestData.SettlementDate);
241+
aggregate.StartProcessing(TestData.SettlementProcessingStartedDateTime);
242+
aggregate.ManuallyComplete();
243+
aggregate.ManuallyComplete();
244+
245+
aggregate.SettlementComplete.ShouldBeTrue();
246+
}
247+
248+
[Fact]
249+
public void SettlementAggregate_ManuallyComplete_SettlementNotCreated_ErrorThron()
250+
{
251+
SettlementAggregate aggregate = SettlementAggregate.Create(TestData.SettlementAggregateId);
252+
253+
Should.Throw<InvalidOperationException>(() => {
254+
aggregate.ManuallyComplete();
255+
});
256+
}
224257
}
225258
}

TransactionProcessor.SettlementAggregates/SettlementAggregate.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ public static void StartProcessing(this SettlementAggregate aggregate, DateTime
2222
aggregate.ApplyAndAppend(startedEvent);
2323
}
2424

25+
public static void ManuallyComplete(this SettlementAggregate aggregate){
26+
27+
aggregate.CheckHasBeenCreated();
28+
29+
if (aggregate.SettlementComplete)
30+
return;
31+
32+
SettlementCompletedEvent pendingSettlementCompletedEvent = new SettlementCompletedEvent(aggregate.AggregateId, aggregate.EstateId);
33+
aggregate.ApplyAndAppend(pendingSettlementCompletedEvent);
34+
}
35+
2536
public static void MarkFeeAsSettled(this SettlementAggregate aggregate, Guid merchantId, Guid transactionId, Guid feeId)
2637
{
2738
(Guid transactionId, Guid merchantId, CalculatedFee calculatedFee) pendingFee = SettlementAggregateExtensions.GetPendingFee(aggregate, merchantId, transactionId, feeId);
@@ -182,7 +193,7 @@ private static void CheckHasNotAlreadyBeenCreated(this SettlementAggregate aggre
182193
throw new InvalidOperationException($"Pending Settlement already created for this date {aggregate.SettlementDate}");
183194
}
184195
}
185-
196+
186197
public static void PlayEvent(this SettlementAggregate aggregate, MerchantFeeSettledEvent domainEvent)
187198
{
188199
// Add to the settled fees list

0 commit comments

Comments
 (0)