Skip to content

Commit 69ecb71

Browse files
author
Yelena Shahparonyan
committed
adding commission validation
1 parent ada9a1d commit 69ecb71

File tree

4 files changed

+160
-34
lines changed

4 files changed

+160
-34
lines changed

src/SharedKernel/SharedKernel.csproj

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<PackageReadmeFile>Readme.md</PackageReadmeFile>
99
<Authors>Pandatech</Authors>
1010
<Copyright>MIT</Copyright>
11-
<Version>1.8.2</Version>
11+
<Version>1.8.3</Version>
1212
<PackageId>Pandatech.SharedKernel</PackageId>
1313
<Title>Pandatech Shared Kernel Library</Title>
1414
<PackageTags>Pandatech, shared kernel, library, OpenAPI, Swagger, utilities, scalar</PackageTags>
@@ -18,46 +18,47 @@
1818
</PropertyGroup>
1919

2020
<ItemGroup>
21-
<None Include="..\..\pandatech.png" Pack="true" PackagePath="\"/>
22-
<None Include="..\..\Readme.md" Pack="true" PackagePath="\"/>
21+
<None Include="..\..\pandatech.png" Pack="true" PackagePath="\" />
22+
<None Include="..\..\Readme.md" Pack="true" PackagePath="\" />
2323
</ItemGroup>
2424

2525
<ItemGroup>
26-
<EmbeddedResource Include="OpenApi\UiAssets\**\*"/>
26+
<EmbeddedResource Include="OpenApi\UiAssets\**\*" />
2727
</ItemGroup>
2828

2929
<ItemGroup>
30-
<PackageReference Include="AspNetCore.HealthChecks.Prometheus.Metrics" Version="9.0.0"/>
31-
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="9.0.0"/>
32-
<PackageReference Include="Elastic.CommonSchema.Serilog" Version="9.0.0"/>
33-
<PackageReference Include="FluentDateTime" Version="3.0.0"/>
34-
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="12.0.0"/>
35-
<PackageReference Include="HtmlSanitizer" Version="9.0.886"/>
36-
<PackageReference Include="MediatR" Version="[12.5.0]"/>
37-
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.8"/>
38-
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.8"/>
39-
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="9.0.8"/>
40-
<PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="9.0.8"/>
41-
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.8.0"/>
42-
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0"/>
43-
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.8.0-rc.1"/>
44-
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0"/>
45-
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0"/>
46-
<PackageReference Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" Version="1.0.0-beta.12"/>
47-
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0"/>
48-
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0"/>
30+
<PackageReference Include="AspNetCore.HealthChecks.Prometheus.Metrics" Version="9.0.0" />
31+
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="9.0.0" />
32+
<PackageReference Include="Elastic.CommonSchema.Serilog" Version="9.0.0" />
33+
<PackageReference Include="FluentDateTime" Version="3.0.0" />
34+
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="12.0.0" />
35+
<PackageReference Include="HtmlSanitizer" Version="9.0.886" />
36+
<PackageReference Include="MediatR" Version="[12.5.0]" />
37+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.8" />
38+
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.8" />
39+
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="9.0.8" />
40+
<PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="9.0.8" />
41+
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.8.0" />
42+
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
43+
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.8.0-rc.1" />
44+
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
45+
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
46+
<PackageReference Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" Version="1.0.0-beta.12" />
47+
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
48+
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" />
49+
<PackageReference Include="Pandatech.CommissionCalculator" Version="4.0.1" />
4950
<PackageReference Include="Pandatech.Crypto" Version="6.1.1" />
50-
<PackageReference Include="Pandatech.DistributedCache" Version="4.0.9"/>
51-
<PackageReference Include="PandaTech.FileExporter" Version="4.1.2"/>
52-
<PackageReference Include="PandaTech.FluentImporter" Version="3.0.9"/>
53-
<PackageReference Include="Pandatech.FluentMinimalApiMapper" Version="2.0.4"/>
54-
<PackageReference Include="Pandatech.PandaVaultClient" Version="4.0.6"/>
55-
<PackageReference Include="Pandatech.ResponseCrafter" Version="5.2.2"/>
51+
<PackageReference Include="Pandatech.DistributedCache" Version="4.0.9" />
52+
<PackageReference Include="PandaTech.FileExporter" Version="4.1.2" />
53+
<PackageReference Include="PandaTech.FluentImporter" Version="3.0.9" />
54+
<PackageReference Include="Pandatech.FluentMinimalApiMapper" Version="2.0.4" />
55+
<PackageReference Include="Pandatech.PandaVaultClient" Version="4.0.6" />
56+
<PackageReference Include="Pandatech.ResponseCrafter" Version="5.2.2" />
5657
<PackageReference Include="Scalar.AspNetCore" Version="2.8.5" />
57-
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0"/>
58-
<PackageReference Include="Serilog.Sinks.Async" Version="2.1.0"/>
59-
<PackageReference Include="Serilog.Sinks.Grafana.Loki" Version="8.3.1"/>
60-
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="9.0.4"/>
58+
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
59+
<PackageReference Include="Serilog.Sinks.Async" Version="2.1.0" />
60+
<PackageReference Include="Serilog.Sinks.Grafana.Loki" Version="8.3.1" />
61+
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="9.0.4" />
6162
</ItemGroup>
6263

6364
</Project>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using CommissionCalculator.DTO;
2+
using FluentValidation;
3+
using FluentValidation.Validators;
4+
using SharedKernel.ValidatorAndMediatR.Validators.Files;
5+
6+
namespace SharedKernel.ValidatorAndMediatR.Validators;
7+
public sealed class CommissionRuleValidator<T> : PropertyValidator<T, CommissionRule?>
8+
{
9+
public override string Name => "CommissionRuleValidator";
10+
11+
public override bool IsValid(ValidationContext<T> context, CommissionRule? rule)
12+
{
13+
if (rule == null || rule.CommissionRangeConfigs.Count == 0)
14+
{
15+
context.AddFailure("The ranges list cannot be null or empty.");
16+
return false;
17+
}
18+
19+
if (rule.CommissionRangeConfigs.Any(
20+
r => r is { Type: CommissionType.Percentage, CommissionAmount: < -10 or > 10 }))
21+
{
22+
context.AddFailure(
23+
"For 'Percentage' CommissionType, the CommissionAmount should be between -10 and 10. Commissions over 1000% are not allowed.");
24+
return false;
25+
}
26+
27+
if (rule.CommissionRangeConfigs.Count == 1)
28+
{
29+
if (rule.CommissionRangeConfigs[0].RangeStart != 0 || rule.CommissionRangeConfigs[0].RangeEnd != 0)
30+
{
31+
context.AddFailure("In case of one range, both 'From' and 'To' should be 0.");
32+
return false;
33+
}
34+
35+
if (rule.CommissionRangeConfigs[0].MaxCommission != 0 && rule.CommissionRangeConfigs[0].MaxCommission <
36+
rule.CommissionRangeConfigs[0].MinCommission)
37+
{
38+
context.AddFailure("MaxCommission should be greater than or equal to MinCommission.");
39+
return false;
40+
}
41+
42+
return true; //check
43+
}
44+
else
45+
{
46+
var rangeValidator = new CommissionRangeValidator<T>();
47+
var rangeValidatorResult = rangeValidator.IsValid(context, rule);
48+
49+
return true && rangeValidatorResult;
50+
}
51+
}
52+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using CommissionCalculator.DTO;
2+
using FluentValidation;
3+
using FluentValidation.Validators;
4+
5+
namespace SharedKernel.ValidatorAndMediatR.Validators.Files;
6+
public sealed class CommissionRangeValidator<T> : PropertyValidator<T, CommissionRule?>
7+
{
8+
public override string Name => "CommissionRangeValidator";
9+
10+
public override bool IsValid(ValidationContext<T> context, CommissionRule? rule)
11+
{
12+
var startRule = rule!.CommissionRangeConfigs.FirstOrDefault(r => r is { RangeStart: 0, RangeEnd: > 0 });
13+
if (startRule == null)
14+
{
15+
context.AddFailure("There should be at least one rule where From = 0.");
16+
return false;
17+
}
18+
19+
if (startRule.MaxCommission != 0 && startRule.MaxCommission < startRule.MinCommission)
20+
{
21+
context.AddFailure("MaxCommission should be greater than or equal to MinCommission.");
22+
return false;
23+
}
24+
25+
var verifiedRules = 1;
26+
27+
var lastTo = startRule.RangeEnd;
28+
29+
while (true)
30+
{
31+
var nextRule = rule.CommissionRangeConfigs.FirstOrDefault(r => r.RangeStart == lastTo);
32+
if (nextRule is null && lastTo != 0)
33+
{
34+
context.AddFailure($"Gap detected. No rule found for 'From = {lastTo}'.");
35+
return false;
36+
}
37+
38+
if (nextRule is not null && nextRule.RangeStart == nextRule.RangeEnd)
39+
{
40+
context.AddFailure("Invalid rule. 'From' and 'To' cannot be equal.");
41+
return false;
42+
}
43+
44+
if (nextRule is not null && nextRule.MaxCommission != 0 && nextRule.MaxCommission < nextRule.MinCommission)
45+
{
46+
context.AddFailure("MaxCommission should be greater than or equal to MinCommission.");
47+
return false;
48+
}
49+
50+
if (lastTo == 0)
51+
{
52+
break;
53+
}
54+
55+
verifiedRules++;
56+
57+
lastTo = nextRule!.RangeEnd;
58+
}
59+
60+
if (verifiedRules != rule.CommissionRangeConfigs.Count)
61+
{
62+
context.AddFailure("There is some nested or gap ranges in the rules.");
63+
return false;
64+
}
65+
66+
return true; //check
67+
}
68+
}

src/SharedKernel/ValidatorAndMediatR/Validators/ValidatorExtensions.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using FluentValidation;
1+
using CommissionCalculator.DTO;
2+
using FluentValidation;
23
using Microsoft.AspNetCore.Http;
34
using SharedKernel.Helpers;
45
using SharedKernel.ValidatorAndMediatR.Validators.Files;
@@ -80,4 +81,8 @@ public static IRuleBuilderOptions<T, string> IsXssSanitized<T>(this IRuleBuilder
8081
{
8182
return rb.SetValidator(new FilesMaxCountValidator<T>(maxCount));
8283
}
84+
public static IRuleBuilderOptions<T, CommissionRule?> ValidateCommissionRule<T>(this IRuleBuilder<T, CommissionRule?> rule)
85+
{
86+
return rule.SetValidator(new CommissionRuleValidator<T>());
87+
}
8388
}

0 commit comments

Comments
 (0)