faturas_4docs/Compliance/Services/ValidationRules/FlagTariffValidationRule.cs

117 lines
4.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 FlagTariffValidationRule(IDistributorRepository distributorRepository) : IValidationRule
{
private readonly IDistributorRepository _distributorRepository = distributorRepository;
private const string RULE_NAME = "Flag Tariff Validation";
private const string FLAG_ERROR = "Flag tariff amount doesn't match the expected value for the current flag color";
private const string EXEMPT_ERROR = "Flag tariff charged to exempt consumer";
private const string COLOR_ERROR = "Invalid flag color applied";
private const decimal TOLERANCE = 0.01m;
private const decimal KWH_BLOCK = 100m; // Flag tariff is applied per 100 kWh
public int Priority => 4; // Run after tariff component validation
public async Task<ValidationResult> ValidateAsync(
BillComplianceRequest request,
DistributorInformation distributorInfo,
Client clientInfo)
{
var flagInfo = await _distributorRepository.GetFlagTariffInformationAsync(
request.DistributorName,
request.Month) ?? throw new InvalidOperationException("Flag tariff information not found");
var isValid = true;
var message = new StringBuilder();
// Check if consumer is exempt
if (flagInfo.ExemptGroups.Contains(request.ConsumerGroup.ToLower()))
{
if (request.FlagAmount != 0)
{
isValid = false;
message.AppendLine(EXEMPT_ERROR);
}
return new ValidationResult
{
IsValid = isValid,
RuleName = RULE_NAME,
Message = message.ToString().TrimEnd()
};
}
// Validate flag color
if (!IsValidFlagColor(request.AppliedFlag))
{
isValid = false;
message.AppendLine($"{COLOR_ERROR}. Found: {request.AppliedFlag}");
}
// Calculate expected flag amount
var expectedFlagAmount = CalculateFlagAmount(
request.ConsumptionAmount,
flagInfo.FlagColor,
flagInfo.FlagValue,
request.BillingDays,
flagInfo.ApplyPartialMonth,
flagInfo.ValidFromDay);
if (Math.Abs(request.FlagAmount - expectedFlagAmount) > TOLERANCE)
{
isValid = false;
message.AppendLine($"{FLAG_ERROR}. Expected: {expectedFlagAmount:F2}, Found: {request.FlagAmount:F2}");
}
return new ValidationResult
{
IsValid = isValid,
RuleName = RULE_NAME,
Message = message.ToString().TrimEnd()
};
}
private static bool IsValidFlagColor(string flagColor)
{
return flagColor.ToUpper() switch
{
"GREEN" => true,
"YELLOW" => true,
"RED1" => true,
"RED2" => true,
_ => false
};
}
private static decimal CalculateFlagAmount(
decimal consumption,
string flagColor,
decimal flagValue,
int billingDays,
bool applyPartialMonth,
int validFromDay)
{
if (flagColor.Equals("GREEN", StringComparison.CurrentCultureIgnoreCase)) return 0;
// Calculate number of 100 kWh blocks
var blocks = Math.Ceiling(consumption / KWH_BLOCK);
// If partial month application is enabled, prorate the flag value
if (applyPartialMonth)
{
var applicableDays = billingDays - (validFromDay - 1);
if (applicableDays < billingDays)
{
return blocks * flagValue * (applicableDays / (decimal)billingDays);
}
}
return blocks * flagValue;
}
}
}