faturas_4docs/Compliance/Services/ValidationRules/PublicLightingValidationRule.cs

82 lines
3.2 KiB
C#

using System;
using System.Threading.Tasks;
using System.Text;
using Compliance.Domain.Models;
using Compliance.DTOs;
using Compliance.Infrastructure.Repositories;
using System.Linq;
using System.Collections.Generic;
namespace Compliance.Services.ValidationRules
{
public class PublicLightingValidationRule(IDistributorRepository distributorRepository) : IValidationRule
{
private readonly IDistributorRepository _distributorRepository = distributorRepository;
private const string RULE_NAME = "Public Lighting Validation";
private const string AMOUNT_ERROR = "Public lighting charge doesn't match the expected value";
private const string EXEMPT_ERROR = "Public lighting charge applied to exempt consumer";
private const decimal TOLERANCE = 0.01m;
public int Priority => 8;
public async Task<ValidationResult> ValidateAsync(
BillComplianceRequest request,
DistributorInformation distributorInfo,
Client clientInfo)
{
var lightingInfo = await _distributorRepository.GetPublicLightingInformationAsync(
request.DistributorName,
request.Municipality,
request.Month) ?? throw new InvalidOperationException("Public lighting information not found");
var isValid = true;
var message = new StringBuilder();
// Check municipal legislation compliance
if (!lightingInfo.HasValidMunicipalLaw)
{
if (request.PublicLightingAmount > 0)
{
isValid = false;
message.AppendLine(EXEMPT_ERROR);
}
return new ValidationResult
{
IsValid = isValid,
RuleName = RULE_NAME,
Message = message.ToString()
};
}
// Validate charge calculation method
var expectedCharge = lightingInfo.CalculationType switch
{
"Fixed" => lightingInfo.FixedAmount,
"Percentage" => request.ConsumptionAmount * (lightingInfo.Percentage / 100m),
"ConsumptionRange" => CalculateRangeBasedCharge(request.ConsumptionAmount, lightingInfo.Ranges),
_ => 0m
};
if (Math.Abs(request.PublicLightingAmount - expectedCharge) > TOLERANCE)
{
isValid = false;
message.AppendLine($"{AMOUNT_ERROR}. Expected: {expectedCharge:F2}, Found: {request.PublicLightingAmount:F2}");
}
return new ValidationResult
{
IsValid = isValid,
RuleName = RULE_NAME,
Message = message.ToString().TrimEnd()
};
}
private decimal CalculateRangeBasedCharge(decimal consumption, IEnumerable<SubsidyInformation.ConsumptionRange> ranges)
{
var applicableRange = ranges.FirstOrDefault(r =>
consumption >= r.MinConsumption &&
consumption <= (r.MaxConsumption ?? decimal.MaxValue));
return applicableRange?.Amount ?? 0m;
}
}
}