faturas_4docs/Compliance/Services/ValidationRules/MeasurementSystemValidationRule.cs

123 lines
5.0 KiB
C#

using System;
using System.Threading.Tasks;
using System.Text;
using Compliance.Domain.Models;
using Compliance.DTOs;
using Compliance.Infrastructure.Repositories;
namespace Compliance.Services.ValidationRules
{
public class MeasurementSystemValidationRule(IDistributorRepository distributorRepository) : IValidationRule
{
private readonly IDistributorRepository _distributorRepository = distributorRepository;
private const string RULE_NAME = "Measurement System Validation";
// Art. 238 - Maximum calibration periods
private const int MAX_CALIBRATION_YEARS_REGULAR = 10;
private const int MAX_CALIBRATION_YEARS_ELECTRONIC = 5;
private const int MAX_CALIBRATION_YEARS_SMART = 3;
// Art. 239 - Accuracy requirements
private const decimal MAX_ERROR_PERCENTAGE = 2.5m;
private const decimal SMART_METER_ERROR_PERCENTAGE = 1.0m;
public int Priority => 1; // High priority as measurements affect other validations
public async Task<ValidationResult> ValidateAsync(
BillComplianceRequest request,
DistributorInformation distributorInfo,
Client clientInfo)
{
var measurementInfo = await _distributorRepository.GetMeasurementSystemInfoAsync(
request.MeterNumber) ?? throw new InvalidOperationException("Measurement system info not found");
var errors = new List<string>();
ValidateCalibration(measurementInfo, errors);
ValidateAccuracy(measurementInfo, errors);
ValidateSmartMeterRequirements(measurementInfo, errors);
ValidateSeals(measurementInfo, errors);
ValidateLocation(measurementInfo, errors);
return errors.Count == 0
? ValidationResult.Success(RULE_NAME)
: ValidationResult.Failure(RULE_NAME, errors);
}
private static void ValidateCalibration(MeasurementSystemInfo info, List<string> errors)
{
var maxYears = info.IsSmartMeter ? MAX_CALIBRATION_YEARS_SMART :
info.MeterType.Contains("Electronic", StringComparison.OrdinalIgnoreCase)
? MAX_CALIBRATION_YEARS_ELECTRONIC
: MAX_CALIBRATION_YEARS_REGULAR;
var calibrationAge = (DateTime.Now - info.LastCalibrationDate).TotalDays / 365.25;
if (calibrationAge > maxYears)
{
errors.Add($"Meter calibration expired. Last calibration: {info.LastCalibrationDate:d}. " +
$"Maximum period for {info.MeterType}: {maxYears} years");
}
// Validate component calibrations
foreach (var component in info.ComponentCalibrations)
{
var componentAge = (DateTime.Now - component.Value).TotalDays / 365.25;
if (componentAge > maxYears)
{
errors.Add($"Component {component.Key} calibration expired. " +
$"Last calibration: {component.Value:d}");
}
}
}
private static void ValidateAccuracy(MeasurementSystemInfo info, List<string> errors)
{
var maxError = info.IsSmartMeter ? SMART_METER_ERROR_PERCENTAGE : MAX_ERROR_PERCENTAGE;
if (info.MaximumError > maxError)
{
errors.Add($"Meter accuracy ({info.MaximumError}%) exceeds maximum allowed error " +
$"({maxError}%) for {(info.IsSmartMeter ? "smart" : "regular")} meters");
}
}
private static void ValidateSmartMeterRequirements(MeasurementSystemInfo info, List<string> errors)
{
if (!info.IsSmartMeter) return;
var requiredProtocols = new[] { "DLMS/COSEM", "ANSI C12.19" };
foreach (var protocol in requiredProtocols)
{
if (!info.CommunicationProtocols.Contains(protocol))
{
errors.Add($"Smart meter missing required protocol: {protocol}");
}
}
}
private static void ValidateSeals(MeasurementSystemInfo info, List<string> errors)
{
if (!info.HasSeal)
{
errors.Add("Meter missing required security seal");
}
else if (string.IsNullOrEmpty(info.SealNumber))
{
errors.Add("Security seal number not documented");
}
}
private static void ValidateLocation(MeasurementSystemInfo info, List<string> errors)
{
if (string.IsNullOrEmpty(info.Location))
{
errors.Add("Meter location not documented");
}
else if (!info.Location.Contains("accessible", StringComparison.OrdinalIgnoreCase))
{
errors.Add("Meter must be installed in an accessible location");
}
}
}
}