faturas_4docs/Compliance/Services/ValidationRules/ReadingImpedimentValidationRule.cs

126 lines
5.2 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 ReadingImpedimentValidationRule(IDistributorRepository distributorRepository) : IValidationRule
{
private readonly IDistributorRepository _distributorRepository = distributorRepository;
private const string RULE_NAME = "Reading Impediment Validation";
// Art. 231 - Impediment documentation requirements
private const int MAX_DAYS_WITHOUT_NOTIFICATION = 15;
private const int MAX_CONSECUTIVE_IMPEDIMENTS = 3;
private const string NOTIFICATION_ERROR = "Customer must be notified within 15 days of impediment";
private const string CONSECUTIVE_ERROR = "Maximum consecutive impediments exceeded";
private const string DOCUMENTATION_ERROR = "Insufficient impediment documentation";
private const string RESOLUTION_ERROR = "No resolution attempts documented";
private const string EVIDENCE_ERROR = "Photo evidence required for access impediment";
public int Priority => 1; // High priority as it affects reading validation
public async Task<ValidationResult> ValidateAsync(
BillComplianceRequest request,
DistributorInformation distributorInfo,
Client clientInfo)
{
if (!request.HasReadingImpediment)
return ValidationResult.Success(RULE_NAME);
var impedimentInfo = await _distributorRepository.GetReadingImpedimentInfoAsync(
request.SmartCode,
request.CurrentReadingDate) ?? throw new InvalidOperationException("Impediment information not found");
var errors = new List<string>();
ValidateImpedimentDocumentation(impedimentInfo, errors);
ValidateCustomerNotification(impedimentInfo, errors);
ValidateConsecutiveImpediments(impedimentInfo, errors);
ValidateResolutionAttempts(impedimentInfo, errors);
ValidateAlternativeReading(request, impedimentInfo, errors);
return errors.Count == 0
? ValidationResult.Success(RULE_NAME)
: ValidationResult.Failure(RULE_NAME, errors);
}
private static void ValidateImpedimentDocumentation(ReadingImpedimentInfo info, List<string> errors)
{
if (string.IsNullOrEmpty(info.ImpedimentCode) ||
string.IsNullOrEmpty(info.Description) ||
info.ReportDate == default ||
string.IsNullOrEmpty(info.ReportedBy))
{
errors.Add(DOCUMENTATION_ERROR);
}
// Art. 231 §1 - Photo evidence requirement
if (info.ImpedimentCode.Contains("ACCESS", StringComparison.OrdinalIgnoreCase) &&
info.PhotoEvidence.Count == 0)
{
errors.Add(EVIDENCE_ERROR);
}
}
private static void ValidateCustomerNotification(ReadingImpedimentInfo info, List<string> errors)
{
if (info.RequiresCustomerAction)
{
if (!info.CustomerNotificationDate.HasValue)
{
errors.Add(NOTIFICATION_ERROR);
}
else
{
var notificationDelay = (info.CustomerNotificationDate.Value - info.ReportDate).Days;
if (notificationDelay > MAX_DAYS_WITHOUT_NOTIFICATION)
{
errors.Add($"{NOTIFICATION_ERROR}. Actual delay: {notificationDelay} days");
}
}
}
}
private static void ValidateConsecutiveImpediments(ReadingImpedimentInfo info, List<string> errors)
{
if (info.ConsecutiveOccurrences > MAX_CONSECUTIVE_IMPEDIMENTS)
{
errors.Add($"{CONSECUTIVE_ERROR}. Current consecutive: {info.ConsecutiveOccurrences}");
}
}
private static void ValidateResolutionAttempts(ReadingImpedimentInfo info, List<string> errors)
{
if (info.ConsecutiveOccurrences > 1 &&
string.IsNullOrEmpty(info.ResolutionAttempts))
{
errors.Add(RESOLUTION_ERROR);
}
}
private static void ValidateAlternativeReading(
BillComplianceRequest request,
ReadingImpedimentInfo info,
List<string> errors)
{
// Art. 232 - Alternative reading methods
if (string.IsNullOrEmpty(info.AlternativeReadingMethod))
{
errors.Add("Alternative reading method must be documented");
}
else if (info.AlternativeReadingMethod.Equals("ESTIMATION",
StringComparison.OrdinalIgnoreCase))
{
// Ensure estimation is properly justified
if (string.IsNullOrEmpty(request.EstimationJustification))
{
errors.Add("Estimation justification required for impediment-based reading");
}
}
}
}
}