Skip to content

Commit b38b507

Browse files
Merge pull request #813 from TransactionProcessing/task/#810_improve_code_coverage
Add tests and functionality for MerchantStatementDomainService
2 parents 2246036 + d56cd83 commit b38b507

File tree

3 files changed

+275
-19
lines changed

3 files changed

+275
-19
lines changed

TransactionProcessor.BusinessLogic.Tests/Services/MerchantDomainServiceTests.cs

Lines changed: 232 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Threading;
4-
using System.Threading.Tasks;
1+
using MessagingService.Client;
52
using Microsoft.Extensions.Configuration;
63
using Moq;
74
using Newtonsoft.Json;
@@ -15,6 +12,11 @@
1512
using Shared.Logger;
1613
using Shouldly;
1714
using SimpleResults;
15+
using System;
16+
using System.Collections.Generic;
17+
using System.Threading;
18+
using System.Threading.Tasks;
19+
using MessagingService.DataTransferObjects;
1820
using TransactionProcessor.Aggregates;
1921
using TransactionProcessor.BusinessLogic.Requests;
2022
using TransactionProcessor.BusinessLogic.Services;
@@ -1058,12 +1060,234 @@ public async Task MerchantDomainService_RemoveContractFromMerchant_ValidationFai
10581060
var result = await this.DomainService.RemoveContractFromMerchant(TestData.Commands.RemoveMerchantContractCommand, CancellationToken.None);
10591061
result.IsFailed.ShouldBeTrue();
10601062
}
1063+
}
1064+
1065+
public class MerchantStatementDomainServiceTests {
1066+
1067+
private Mock<IAggregateService> AggregateService;
1068+
private Mock<IStatementBuilder> StatementBuilder;
1069+
private Mock<IMessagingServiceClient> MessagingServiceClient;
1070+
private Mock<ISecurityServiceClient> SecurityServiceClient;
1071+
private MerchantStatementDomainService DomainService;
1072+
public MerchantStatementDomainServiceTests() {
1073+
this.AggregateService = new Mock<IAggregateService>();
1074+
this.StatementBuilder = new Mock<IStatementBuilder>();
1075+
this.MessagingServiceClient = new Mock<IMessagingServiceClient>();
1076+
this.SecurityServiceClient = new Mock<ISecurityServiceClient>();
1077+
this.DomainService = new MerchantStatementDomainService(this.AggregateService.Object, this.StatementBuilder.Object, this.MessagingServiceClient.Object, this.SecurityServiceClient.Object);
1078+
1079+
IConfigurationRoot configurationRoot =
1080+
new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build();
1081+
ConfigurationReader.Initialise(configurationRoot);
1082+
Logger.Initialise(new NullLogger());
1083+
}
1084+
1085+
[Fact]
1086+
public async Task MerchantStatementDomainService_AddTransactionToStatement_TransactionAddedToStatement() {
1087+
1088+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementForDateAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.EmptyMerchantStatementForDateAggregate));
1089+
this.AggregateService.Setup(a => a.Save<MerchantStatementForDateAggregate>(It.IsAny<MerchantStatementForDateAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success());
1090+
Result result = await this.DomainService.AddTransactionToStatement(TestData.Commands.AddTransactionToMerchantStatementCommand, CancellationToken.None);
1091+
result.IsSuccess.ShouldBeTrue();
1092+
}
1093+
1094+
[Fact]
1095+
public async Task MerchantStatementDomainService_AddTransactionToStatement_TransactionNotAuthorised_TransactionNotAddedToStatement()
1096+
{
1097+
1098+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementForDateAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.EmptyMerchantStatementForDateAggregate));
1099+
this.AggregateService.Setup(a => a.Save<MerchantStatementForDateAggregate>(It.IsAny<MerchantStatementForDateAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success());
1100+
Result result = await this.DomainService.AddTransactionToStatement(TestData.Commands.AddTransactionNotAuthorisedToMerchantStatementCommand, CancellationToken.None);
1101+
result.IsSuccess.ShouldBeTrue();
1102+
}
1103+
1104+
[Fact]
1105+
public async Task MerchantStatementDomainService_AddTransactionToStatement_TransactionHasNotAmount_TransactionNotAddedToStatement()
1106+
{
1107+
1108+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementForDateAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.EmptyMerchantStatementForDateAggregate));
1109+
this.AggregateService.Setup(a => a.Save<MerchantStatementForDateAggregate>(It.IsAny<MerchantStatementForDateAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success());
1110+
Result result = await this.DomainService.AddTransactionToStatement(TestData.Commands.AddTransactionWithNoAmountToMerchantStatementCommand, CancellationToken.None);
1111+
result.IsSuccess.ShouldBeTrue();
1112+
}
1113+
1114+
[Fact]
1115+
public async Task MerchantStatementDomainService_AddTransactionToStatement_SaveFailed_TransactionNotAddedToStatement()
1116+
{
1117+
1118+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementForDateAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.EmptyMerchantStatementForDateAggregate));
1119+
this.AggregateService.Setup(a => a.Save<MerchantStatementForDateAggregate>(It.IsAny<MerchantStatementForDateAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Failure);
1120+
Result result = await this.DomainService.AddTransactionToStatement(TestData.Commands.AddTransactionToMerchantStatementCommand, CancellationToken.None);
1121+
result.IsFailed.ShouldBeTrue();
1122+
}
1123+
1124+
[Fact]
1125+
public async Task MerchantStatementDomainService_AddSettledFeeToStatement_SettledFeeAddedToStatement()
1126+
{
1127+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementForDateAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.EmptyMerchantStatementForDateAggregate));
1128+
this.AggregateService.Setup(a => a.Save<MerchantStatementForDateAggregate>(It.IsAny<MerchantStatementForDateAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success());
1129+
Result result = await this.DomainService.AddSettledFeeToStatement(TestData.Commands.AddSettledFeeToMerchantStatementCommand, CancellationToken.None);
1130+
result.IsSuccess.ShouldBeTrue();
1131+
}
1132+
1133+
[Fact]
1134+
public async Task MerchantStatementDomainService_AddSettledFeeToStatement_SaveFailed_SettledFeeNotAddedToStatement()
1135+
{
1136+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementForDateAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.EmptyMerchantStatementForDateAggregate));
1137+
this.AggregateService.Setup(a => a.Save<MerchantStatementForDateAggregate>(It.IsAny<MerchantStatementForDateAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Failure);
1138+
Result result = await this.DomainService.AddSettledFeeToStatement(TestData.Commands.AddSettledFeeToMerchantStatementCommand, CancellationToken.None);
1139+
result.IsFailed.ShouldBeTrue();
1140+
}
1141+
1142+
1143+
[Fact]
1144+
public async Task MerchantStatementDomainService_RecordActivityDateOnMerchantStatement_SaveFailed_ActivityDateNotRecorded() {
1145+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.EmptyMerchantStatementAggregate));
1146+
this.AggregateService.Setup(a => a.Save<MerchantStatementAggregate>(It.IsAny<MerchantStatementAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success);
1147+
Result result = await this.DomainService.RecordActivityDateOnMerchantStatement(TestData.Commands.RecordActivityDateOnMerchantStatementCommand, CancellationToken.None);
1148+
result.IsSuccess.ShouldBeTrue();
1149+
}
1150+
1151+
[Fact]
1152+
public async Task MerchantStatementDomainService_RecordActivityDateOnMerchantStatement_ActivityDateRecorded()
1153+
{
1154+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.EmptyMerchantStatementAggregate));
1155+
this.AggregateService.Setup(a => a.Save<MerchantStatementAggregate>(It.IsAny<MerchantStatementAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Failure);
1156+
Result result = await this.DomainService.RecordActivityDateOnMerchantStatement(TestData.Commands.RecordActivityDateOnMerchantStatementCommand, CancellationToken.None);
1157+
result.IsFailed.ShouldBeTrue();
1158+
}
1159+
1160+
[Fact]
1161+
public async Task MerchantStatementDomainService_GenerateStatement_StatementIsGenerated()
1162+
{
1163+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.MerchantStatementAggregateWithActivityDates()));
1164+
this.AggregateService.Setup(a => a.Save<MerchantStatementAggregate>(It.IsAny<MerchantStatementAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success);
1165+
1166+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementForDateAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.MerchantStatementForDateAggregateWithTransactionAndFee()));
1167+
1168+
Result result = await this.DomainService.GenerateStatement(TestData.Commands.GenerateMerchantStatementCommand, CancellationToken.None);
1169+
result.IsSuccess.ShouldBeTrue();
1170+
}
1171+
1172+
[Fact]
1173+
public async Task MerchantStatementDomainService_GenerateStatement_GetStatementForDateFailed_StatementIsNotGenerated()
1174+
{
1175+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.MerchantStatementAggregateWithActivityDates()));
1176+
this.AggregateService.Setup(a => a.Save<MerchantStatementAggregate>(It.IsAny<MerchantStatementAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success);
1177+
1178+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementForDateAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Failure());
1179+
1180+
Result result = await this.DomainService.GenerateStatement(TestData.Commands.GenerateMerchantStatementCommand, CancellationToken.None);
1181+
result.IsFailed.ShouldBeTrue();
1182+
}
1183+
1184+
[Fact]
1185+
public async Task MerchantStatementDomainService_GenerateStatement_SaveFailed_StatementIsNotGenerated()
1186+
{
1187+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.MerchantStatementAggregateWithActivityDates()));
1188+
this.AggregateService.Setup(a => a.Save<MerchantStatementAggregate>(It.IsAny<MerchantStatementAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Failure);
1189+
1190+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementForDateAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.MerchantStatementForDateAggregateWithTransactionAndFee()));
1191+
1192+
Result result = await this.DomainService.GenerateStatement(TestData.Commands.GenerateMerchantStatementCommand, CancellationToken.None);
1193+
result.IsFailed.ShouldBeTrue();
1194+
}
1195+
1196+
[Fact]
1197+
public async Task MerchantStatementDomainService_BuildStatement_StatementIsBuilt()
1198+
{
1199+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.GeneratedMerchantStatementAggregate()));
1200+
this.AggregateService.Setup(a => a.Save<MerchantStatementAggregate>(It.IsAny<MerchantStatementAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success);
1201+
1202+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementForDateAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.MerchantStatementForDateAggregateWithTransactionAndFee()));
1203+
1204+
this.AggregateService.Setup(a => a.Get<MerchantAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.MerchantAggregateWithEverything(SettlementSchedule.Immediate)));
1205+
1206+
this.StatementBuilder.Setup(s => s.GetStatementHtml(It.IsAny<MerchantStatementAggregate>(), It.IsAny<Merchant>(), It.IsAny<CancellationToken>())).ReturnsAsync("<html></html>");
1207+
1208+
Result result = await this.DomainService.BuildStatement(TestData.Commands.BuildMerchantStatementCommand, CancellationToken.None);
1209+
result.IsSuccess.ShouldBeTrue();
1210+
}
1211+
1212+
[Fact]
1213+
public async Task MerchantStatementDomainService_BuildStatement_GetMerchantFailed_StatementIsNotBuilt()
1214+
{
1215+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.GeneratedMerchantStatementAggregate()));
1216+
this.AggregateService.Setup(a => a.Save<MerchantStatementAggregate>(It.IsAny<MerchantStatementAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success);
1217+
1218+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementForDateAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.MerchantStatementForDateAggregateWithTransactionAndFee()));
1219+
1220+
this.AggregateService.Setup(a => a.Get<MerchantAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Failure());
1221+
1222+
this.StatementBuilder.Setup(s => s.GetStatementHtml(It.IsAny<MerchantStatementAggregate>(), It.IsAny<Merchant>(), It.IsAny<CancellationToken>())).ReturnsAsync("<html></html>");
1223+
1224+
Result result = await this.DomainService.BuildStatement(TestData.Commands.BuildMerchantStatementCommand, CancellationToken.None);
1225+
result.IsFailed.ShouldBeTrue();
1226+
}
1227+
1228+
[Fact]
1229+
public async Task MerchantStatementDomainService_BuildStatement_SaveFailed_StatementIsNotBuilt()
1230+
{
1231+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.GeneratedMerchantStatementAggregate()));
1232+
this.AggregateService.Setup(a => a.Save<MerchantStatementAggregate>(It.IsAny<MerchantStatementAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Failure);
1233+
1234+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementForDateAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.MerchantStatementForDateAggregateWithTransactionAndFee()));
1235+
1236+
this.AggregateService.Setup(a => a.Get<MerchantAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.MerchantAggregateWithEverything(SettlementSchedule.Immediate)));
1237+
1238+
this.StatementBuilder.Setup(s => s.GetStatementHtml(It.IsAny<MerchantStatementAggregate>(), It.IsAny<Merchant>(), It.IsAny<CancellationToken>())).ReturnsAsync("<html></html>");
1239+
1240+
Result result = await this.DomainService.BuildStatement(TestData.Commands.BuildMerchantStatementCommand, CancellationToken.None);
1241+
result.IsFailed.ShouldBeTrue();
1242+
}
10611243

10621244
[Fact]
1063-
public void Test1() {
1064-
var domainEvent = JsonConvert.DeserializeObject<SettlementDomainEvents.MerchantFeeSettledEvent>("{\r\n \"transactionId\": \"a4702780-03a3-4f9d-8ed0-5b5c88f276ba\",\r\n \"estateId\": \"435613ac-a468-47a3-ac4f-649d89764c22\",\r\n \"merchantId\": \"8bc8434d-41f9-4cc3-83bc-e73f20c02e1d\",\r\n \"calculatedValue\": 0.5,\r\n \"feeId\": \"957939ba-7bec-48b6-adb8-0277faf752ba\",\r\n \"feeValue\": 0.5,\r\n \"feeCalculatedDateTime\": \"2025-01-01T09:17:40\",\r\n \"settledDateTime\": \"2025-01-01T00:00:00\",\r\n \"settlementId\": \"0a4f96f9-0e58-9b43-2f0b-4bdca9367a3f\",\r\n \"transactionDateTime\": \"2025-01-01T09:17:40\",\t\t\t\r\n \"eventId\": \"435613ac-a468-47a3-ac4f-649d89764c22\"\r\n}");
1245+
public async Task MerchantStatementDomainService_EmailStatement_StatementIsEmailed()
1246+
{
1247+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.BuiltMerchantStatementAggregate()));
1248+
this.AggregateService.Setup(a => a.Save<MerchantStatementAggregate>(It.IsAny<MerchantStatementAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success);
10651249

1066-
var statementDate = MerchantStatementDomainService.CalculateStatementDate(domainEvent.FeeCalculatedDateTime);
1067-
statementDate.ShouldBe(new DateTime(2025,2,1));
1250+
this.AggregateService.Setup(a => a.Get<MerchantAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.MerchantAggregateWithEverything(SettlementSchedule.Immediate)));
1251+
1252+
this.MessagingServiceClient.Setup(m => m.SendEmail(It.IsAny<String>(), It.IsAny<SendEmailRequest>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success);
1253+
1254+
this.SecurityServiceClient.Setup(m => m.GetToken(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.TokenResponse()));
1255+
1256+
Result result = await this.DomainService.EmailStatement(TestData.Commands.EmailMerchantStatementCommand, CancellationToken.None);
1257+
result.IsSuccess.ShouldBeTrue();
10681258
}
1259+
1260+
[Fact]
1261+
public async Task MerchantStatementDomainService_EmailStatement_MerchantNotFound_StatementIsNotEmailed()
1262+
{
1263+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.BuiltMerchantStatementAggregate()));
1264+
this.AggregateService.Setup(a => a.Save<MerchantStatementAggregate>(It.IsAny<MerchantStatementAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success);
1265+
1266+
this.AggregateService.Setup(a => a.Get<MerchantAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Failure());
1267+
1268+
this.MessagingServiceClient.Setup(m => m.SendEmail(It.IsAny<String>(), It.IsAny<SendEmailRequest>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success);
1269+
1270+
this.SecurityServiceClient.Setup(m => m.GetToken(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.TokenResponse()));
1271+
1272+
Result result = await this.DomainService.EmailStatement(TestData.Commands.EmailMerchantStatementCommand, CancellationToken.None);
1273+
result.IsFailed.ShouldBeTrue();
1274+
}
1275+
1276+
[Fact]
1277+
public async Task MerchantStatementDomainService_EmailStatement_GetTokenFailed_StatementIsNotEmailed()
1278+
{
1279+
this.AggregateService.Setup(a => a.GetLatest<MerchantStatementAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.BuiltMerchantStatementAggregate()));
1280+
this.AggregateService.Setup(a => a.Save<MerchantStatementAggregate>(It.IsAny<MerchantStatementAggregate>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success);
1281+
1282+
this.AggregateService.Setup(a => a.Get<MerchantAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.Aggregates.MerchantAggregateWithEverything(SettlementSchedule.Immediate)));
1283+
1284+
this.MessagingServiceClient.Setup(m => m.SendEmail(It.IsAny<String>(), It.IsAny<SendEmailRequest>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success);
1285+
1286+
this.SecurityServiceClient.Setup(m => m.GetToken(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Failure());
1287+
1288+
Result result = await this.DomainService.EmailStatement(TestData.Commands.EmailMerchantStatementCommand, CancellationToken.None);
1289+
result.IsFailed.ShouldBeTrue();
1290+
}
1291+
1292+
10691293
}

0 commit comments

Comments
 (0)