82 lines
3.2 KiB
C#
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;
|
|
}
|
|
}
|
|
} |