faturas_4docs/Compliance/Services/ValidationRules/AdditionalChargeValidationRule.cs

115 lines
4.7 KiB
C#

using System;
using System.Threading.Tasks;
using System.Text;
using System.Linq;
using Compliance.Domain.Models;
using Compliance.DTOs;
using Compliance.Infrastructure.Repositories;
namespace Compliance.Services.ValidationRules
{
public class AdditionalChargeValidationRule(IDistributorRepository distributorRepository) : IValidationRule
{
private readonly IDistributorRepository _distributorRepository = distributorRepository;
private const string RULE_NAME = "Additional Charge Validation";
private const string AMOUNT_ERROR = "Additional charge amount doesn't match the expected value";
private const string MISSING_CHARGE_ERROR = "Mandatory charge not applied";
private const string INVALID_CHARGE_ERROR = "Invalid charge type applied";
private const string JUSTIFICATION_ERROR = "Missing justification for additional charge";
private const string TOTAL_ERROR = "Total additional charges exceed maximum allowed percentage";
private const decimal TOLERANCE = 0.01m;
public int Priority => 8; // Run after subsidy validation
public async Task<ValidationResult> ValidateAsync(
BillComplianceRequest request,
DistributorInformation distributorInfo,
Client clientInfo)
{
var chargeInfo = await _distributorRepository.GetAdditionalChargeInformationAsync(
request.DistributorName,
request.Month) ?? throw new InvalidOperationException("Additional charge information not found");
var isValid = true;
var message = new StringBuilder();
// Validate mandatory charges
foreach (var mandatoryCharge in chargeInfo.MandatoryCharges)
{
if (!request.AdditionalCharges.Any(c => c.Type.Equals(mandatoryCharge, StringComparison.OrdinalIgnoreCase)))
{
isValid = false;
message.AppendLine($"{MISSING_CHARGE_ERROR}: {mandatoryCharge}");
}
}
// Calculate bill base for percentage validation
var billBase = CalculateBillBase(request);
var totalCharges = 0m;
// Validate each charge
foreach (var charge in request.AdditionalCharges)
{
// Validate charge type
if (!chargeInfo.ChargeRates.ContainsKey(charge.Type.ToLower()))
{
isValid = false;
message.AppendLine($"{INVALID_CHARGE_ERROR}: {charge.Type}");
continue;
}
// Check for exemptions
if (chargeInfo.ConsumerGroupExemptions.Contains($"{charge.Type.ToLower()}:{request.ConsumerGroup.ToLower()}"))
{
if (charge.Amount != 0)
{
isValid = false;
message.AppendLine($"Consumer group exempt from charge: {charge.Type}");
}
continue;
}
// Validate justification
if (chargeInfo.RequireJustification && string.IsNullOrWhiteSpace(charge.Justification))
{
isValid = false;
message.AppendLine($"{JUSTIFICATION_ERROR}: {charge.Type}");
}
// Validate amount
var expectedAmount = billBase * (chargeInfo.ChargeRates[charge.Type.ToLower()] / 100m);
if (Math.Abs(charge.Amount - expectedAmount) > TOLERANCE)
{
isValid = false;
message.AppendLine($"{AMOUNT_ERROR} for {charge.Type}. Expected: {expectedAmount:F2}, Found: {charge.Amount:F2}");
}
totalCharges += charge.Amount;
}
// Validate total charges percentage
var maxAllowed = billBase * (chargeInfo.MaximumTotalPercentage / 100m);
if (totalCharges > maxAllowed)
{
isValid = false;
message.AppendLine($"{TOTAL_ERROR}. Maximum: {maxAllowed:F2}, Total: {totalCharges:F2}");
}
return new ValidationResult
{
IsValid = isValid,
RuleName = RULE_NAME,
Message = message.ToString().TrimEnd()
};
}
private static decimal CalculateBillBase(BillComplianceRequest request)
{
return request.TUSDAmount +
request.TEAmount +
request.PowerFactorAdjustment +
request.FlagAmount +
request.ICMSAmount +
request.MunicipalTaxAmount;
}
}
}