private static ChangeOfChargesMessage GetValidChangeOfChargesMessage()
        {
            var message = new ChangeOfChargesMessage
            {
                ChargeTypeMRid      = "chargeTypeMRid",
                CorrelationId       = "correlationId",
                LastUpdatedBy       = "lastUpdatedBy",
                Type                = KnownChargeType,
                ChargeTypeOwnerMRid = KnownChargeOwner,
                MktActivityRecord   = new MktActivityRecord
                {
                    ChargeType = new Ingestion.Domain.ChangeOfCharges.ChargeType
                    {
                        VATPayer = KnownVatPayer, Name = "shortDescription", Description = "longDescription",
                    },
                },
                Period = new ChargeTypePeriod
                {
                    Resolution = KnownResolutionType, Points = new List <Point>
                    {
                        new Point {
                            Position = 1, PriceAmount = 1m, Time = SystemClock.Instance.GetCurrentInstant(),
                        },
                    },
                },
            };

            return(message);
        }
예제 #2
0
 private async Task <MarketParticipant?> GetChargeTypeOwnerMRidAsync(ChangeOfChargesMessage chargeMessage)
 {
     return(string.IsNullOrWhiteSpace(chargeMessage.ChargeTypeOwnerMRid)
         ? throw new ArgumentException($"Fails as {nameof(chargeMessage.ChargeTypeOwnerMRid)} is invalid")
         : await _chargesDatabaseContext.MarketParticipant.SingleOrDefaultAsync(type =>
                                                                                type.MRid == chargeMessage.ChargeTypeOwnerMRid));
 }
        private void HandleValidationRule(
            ChangeOfChargesMessage changeOfChargesMessage,
            IValidationRule validationRule,
            HubRequestValidationResult validationResult)
        {
            const string unknownServerError = "Unknown server error";

            try
            {
                if (_ruleConfigurations == null)
                {
                    validationResult.Add(new ValidationError("VR900", unknownServerError));
                    _logger.LogError($"{nameof(_ruleConfigurations)} was null");
                    return;
                }

                var ruleValidationResult = validationRule.Validate(changeOfChargesMessage, _ruleConfigurations);

                if (ruleValidationResult.ValidatedSuccessfully is false)
                {
                    validationResult.Add(ruleValidationResult.ValidationError);
                }
            }
            catch (RuleNotFoundException ruleNotFoundException)
            {
                validationResult.Add(new ValidationError("VRXYZ", unknownServerError));
                _logger.LogError(ruleNotFoundException, "Rule configuration could not be found");
            }
            catch (RuleCouldNotBeMappedException ruleCouldNotBeMappedException)
            {
                validationResult.Add(new ValidationError("VRXYZ", unknownServerError));
                _logger.LogError(ruleCouldNotBeMappedException, "Rule value could not be mapped");
            }
        }
예제 #4
0
 private async Task <VatPayerType?> GetVatPayerTypeAsync(ChangeOfChargesMessage chargeMessage)
 {
     return(string.IsNullOrWhiteSpace(chargeMessage.MktActivityRecord?.ChargeType?.VATPayer)
         ? throw new ArgumentException($"Fails as {nameof(chargeMessage.MktActivityRecord.ChargeType.VATPayer)} is invalid")
         : await _chargesDatabaseContext.VatPayerType.SingleOrDefaultAsync(type =>
                                                                           type.Name == chargeMessage.MktActivityRecord.ChargeType.VATPayer));
 }
        public async Task ValidateAsync_HappyFlow_ShouldNotAddAnyValidationResults(
            [Frozen] Mock <IEnumerable <IValidationRule> > validationRules,
            [Frozen] Mock <IRuleConfigurationRepository> ruleConfigurationRepository,
            [Frozen] Mock <ILogger <ChangeOfChargesDomainValidator> > logger)
        {
            // Arrange
            SetupValidationRulesCollection(validationRules);

            ruleConfigurationRepository.Setup(x => x.GetRuleConfigurationsAsync())
            .ReturnsAsync(new List <ValidationRuleConfiguration>
            {
                new ValidationRuleConfiguration(ValidationRuleNames.StartOfValidIntervalFromNowInDays, "30"),
                new ValidationRuleConfiguration(ValidationRuleNames.EndOfValidIntervalFromNowInDays, "1000"),
            });

            var sut = new ChangeOfChargesDomainValidator(
                validationRules.Object,
                ruleConfigurationRepository.Object,
                logger.Object);

            var changeOfChargesMessage = new ChangeOfChargesMessage
            {
                MktActivityRecord = new MktActivityRecord
                {
                    ValidityStartDate = SystemClock.Instance.GetCurrentInstant()
                                        .Plus(Duration.FromDays(500)),
                },
            };

            // Act
            var validationResult = await sut.ValidateAsync(changeOfChargesMessage);

            // Assert
            validationResult.Errors.Should().BeEmpty();
        }
 private ChargeChangeNotificationDocument CreateDocument(string receiverMRid, ChangeOfChargesMessage message)
 {
     return(new ChargeChangeNotificationDocument
     {
         Recipient = receiverMRid,
         EffectuationDate = message.MktActivityRecord !.ValidityStartDate,
         Content = CreateDocumentContent(receiverMRid, message),
     });
예제 #7
0
        public async Task AcceptAsync_WhenCalled_ShouldVerifyThatLoggerIsCalledWithSuccesfulMessage(
            [Frozen] Mock <ILogger <ChangeOfChargesCommandHandler> > logger,
            ChangeOfChargesMessage message,
            ChangeOfChargesCommandHandlerTestable sut)
        {
            await sut.CallAcceptAsync(message).ConfigureAwait(false);

            logger.VerifyLoggerWasCalled($"{nameof(ChangeOfChargesMessage)} have parsed validation", LogLevel.Information);
        }
 public IEnumerable <ChargeChangeNotificationDocument> Create(
     IEnumerable <MarketParticipant> energySuppliers,
     ChangeOfChargesMessage message)
 {
     foreach (var energySupplier in energySuppliers)
     {
         yield return(CreateDocument(energySupplier !.MRid !, message));
     }
 }
        private async Task <ChangeOfChargesMessageResult> HandleTransactionsAsync([NotNull] ChangeOfChargesMessage message)
        {
            foreach (ChangeOfChargesTransaction transaction in message.Transactions)
            {
                await _changeOfChargesTransactionHandler.HandleAsync(transaction).ConfigureAwait(false);
            }

            return(ChangeOfChargesMessageResult.CreateSuccess());
        }
예제 #10
0
        public async Task RejectAsync_WhenCalled_ShouldSendEventToReportQueue(
            [Frozen] Mock <IValidationReportQueueDispatcher> validationReportQueueDispatcher,
            ChangeOfChargesMessage message,
            [NotNull] ChangeOfChargesCommandHandlerTestable sut)
        {
            await sut.CallRejectAsync(message);

            validationReportQueueDispatcher
            .Verify(mock => mock.DispatchAsync(It.IsAny <IHubMessage>()), Times.Once);
        }
예제 #11
0
        public async Task NotifyAboutChangeOfChargesAsync([NotNull] ChangeOfChargesMessage changeOfChargesMessage)
        {
            if (changeOfChargesMessage == null)
            {
                throw new ArgumentNullException(nameof(changeOfChargesMessage));
            }

            var energySuppliers = _marketParticipantRepository.GetEnergySuppliers();
            var documents       = _postOfficeDocumentFactory.Create(energySuppliers, changeOfChargesMessage);
            await _postOfficeClient.SendAsync(documents);
        }
        public async Task <HubRequestValidationResult> ValidateAsync(ChangeOfChargesMessage changeOfChargesMessage)
        {
            _ruleConfigurations ??= await _ruleConfigurationRepository.GetRuleConfigurationsAsync();

            var validationResult = new HubRequestValidationResult(changeOfChargesMessage.Transaction.MRID);

            foreach (var validationRule in _validationRules)
            {
                HandleValidationRule(changeOfChargesMessage, validationRule, validationResult);
            }

            return(validationResult);
        }
        public async Task <HubRequestValidationResult> ValidateAsync(ChangeOfChargesMessage changeOfChargesMessage)
        {
            var result = await _inputValidationRuleEngine.ValidateAsync(changeOfChargesMessage).ConfigureAwait(false);

            var hubRequestValidationResult = new HubRequestValidationResult(changeOfChargesMessage.Transaction.MRID);

            foreach (var error in result)
            {
                hubRequestValidationResult.Add(new ValidationError(error.RuleNumber, error.Message));
            }

            return(hubRequestValidationResult);
        }
예제 #14
0
        public void Validate_WhenCalledWithTooLateDate_ShouldReturnFalse(int changeOfChargesStartDay, StartDateVr209ValidationRule sut)
        {
            var ruleConfigurations = GetValidationRuleConfigurationCollection();

            var messageWithLowStartDate = new ChangeOfChargesMessage
            {
                MktActivityRecord = new MktActivityRecord
                {
                    ValidityStartDate = SystemClock.Instance.GetCurrentInstant().Plus(Duration.FromDays(changeOfChargesStartDay)),
                },
            };

            var result = sut.Validate(messageWithLowStartDate, ruleConfigurations);

            result.Should().NotBeNull();
            result.ValidationError !.Code.Should().Be("VR209");
        }
예제 #15
0
        public void Validate_WhenCalledWithValidDate_ShouldReturnTrue(
            int changeOfChargesStartDay,
            StartDateVr209ValidationRule sut)
        {
            var ruleConfigurations = GetValidationRuleConfigurationCollection();

            var messageWithLowStartDate = new ChangeOfChargesMessage
            {
                MktActivityRecord = new MktActivityRecord
                {
                    ValidityStartDate = SystemClock.Instance.GetCurrentInstant().Plus(Duration.FromDays(changeOfChargesStartDay)),
                },
            };

            var result = sut.Validate(messageWithLowStartDate, ruleConfigurations);

            result.ValidatedSuccessfully.Should().BeTrue();
        }
예제 #16
0
        public ValidationStatus Validate(ChangeOfChargesMessage changeOfChargesMessage, IEnumerable <ValidationRuleConfiguration> ruleConfigurations)
        {
            var startOfValidIntervalFromNowInDays = ruleConfigurations
                                                    .GetSingleRule(ValidationRuleNames.StartOfValidIntervalFromNowInDays).GetValueAsInteger();
            var endOfValidIntervalFromNowInDays = ruleConfigurations
                                                  .GetSingleRule(ValidationRuleNames.EndOfValidIntervalFromNowInDays).GetValueAsInteger();

            var startOfValidInterval = SystemClock.Instance.GetCurrentInstant()
                                       .Plus(Duration.FromDays(startOfValidIntervalFromNowInDays));
            var endOfValidInterval = SystemClock.Instance.GetCurrentInstant()
                                     .Plus(Duration.FromDays(endOfValidIntervalFromNowInDays));
            var startDate = changeOfChargesMessage.MktActivityRecord?.ValidityStartDate;
            var success   = startDate >= startOfValidInterval && startDate <= endOfValidInterval;

            return(success
                ? new ValidationStatus(success, null)
                : new ValidationStatus(false, new ValidationError("VR209", "Time limits not followed")));
        }
        public void Ensure_all_properties_are_mapped(
            [Frozen] Mock <IPostOfficeDocumentFactorySettings> settings,
            ChangeOfChargesMessage changeOfChargesMessage,
            MarketParticipant marketParticipant,
            PostOfficeDocumentFactory sut)
        {
            // Arrange
            settings.Setup(x => x.GetHubMRid()).Returns("MRidFromSettings");
            MakeMessageValid(changeOfChargesMessage);
            var receivers = new List <MarketParticipant> {
                marketParticipant
            };

            // Act
            var actual = sut.Create(receivers, changeOfChargesMessage)
                         .ToList();

            // Assert
            actual.ForEach(d => d.Should().NotContainNullsOrEmptyEnumerables());
        }
        public void Ensure_all_types_of_MarketParticipantRole_are_handled_by_Create(
            PostOfficeDocumentFactory sut,
            ChangeOfChargesMessage changeOfChargesMessage,
            MarketParticipant marketParticipant)
        {
            // Arrange
            MakeMessageValid(changeOfChargesMessage);
            var receivers = new List <MarketParticipant> {
                marketParticipant
            };
            var roles = Enum.GetValues(typeof(MarketParticipantRole)).Cast <MarketParticipantRole>();

            foreach (var role in roles)
            {
                changeOfChargesMessage.MarketDocument !.SenderMarketParticipant !.Role = role;

                // Act & Assert
                // Create throws a NotImplemented exception if a value in MarketParticipantRole is not handled.
                _ = sut.Create(receivers, changeOfChargesMessage).ToList();
            }
        }
예제 #19
0
        public async Task <ChargeStorageStatus> StoreChargeAsync(ChangeOfChargesMessage chargeMessage)
        {
            var chargeType = await GetChargeTypeAsync(chargeMessage).ConfigureAwait(false);

            if (chargeType == null)
            {
                return(ChargeStorageStatus.CreateFailure($"No charge type for {chargeMessage.Type}"));
            }

            var resolutionType = await GetResolutionTypeAsync(chargeMessage).ConfigureAwait(false);

            if (resolutionType == null)
            {
                return(ChargeStorageStatus.CreateFailure($"No resolution type for {chargeMessage.Period?.Resolution}"));
            }

            var vatPayerType = await GetVatPayerTypeAsync(chargeMessage).ConfigureAwait(false);

            if (vatPayerType == null)
            {
                return(ChargeStorageStatus.CreateFailure($"No VAT payer type for {chargeMessage.MktActivityRecord?.ChargeType?.VATPayer}"));
            }

            var chargeTypeOwnerMRid = await GetChargeTypeOwnerMRidAsync(chargeMessage) !.ConfigureAwait(false);

            if (chargeTypeOwnerMRid == null)
            {
                return(ChargeStorageStatus.CreateFailure($"No market participant for {chargeMessage.ChargeTypeOwnerMRid}"));
            }

            var charge = ChangeOfChargesMapper.MapChangeOfChargesMessageToCharge(chargeMessage, chargeType, chargeTypeOwnerMRid, resolutionType, vatPayerType);

            await _chargesDatabaseContext.Charge.AddAsync(charge);

            await _chargesDatabaseContext.SaveChangesAsync().ConfigureAwait(false);

            return(ChargeStorageStatus.CreateSuccess());
        }
        public async Task AcceptAsync_WhenAddingDuration_ShouldInvokeStorageProviderWithCalculatedTimeProperty(int numberOfDurations, [Frozen] Mock <IIso8601Durations> iso8601Durations, [Frozen] Mock <IChargeRepository> storageProvider, ChangeOfChargesCommandHandlerTestable sut)
        {
            // Arrange
            var startTime = SystemClock.Instance.GetCurrentInstant();
            var message   = new ChangeOfChargesMessage
            {
                MktActivityRecord = new MktActivityRecord
                {
                    ValidityStartDate = startTime
                },
                Period = new ChargeTypePeriod
                {
                    Resolution = "PT1H",
                    Points     = new List <Point>
                    {
                        new Point {
                            Position = numberOfDurations, PriceAmount = 1
                        },
                    },
                },
            };

            var calculatedInstant =
                message.MktActivityRecord.ValidityStartDate.Plus(Duration.FromHours(numberOfDurations));

            iso8601Durations.Setup(i => i.AddDuration(It.IsAny <Instant>(), It.IsAny <string>(), It.IsAny <int>()))
            .Returns(calculatedInstant);

            // Act
            await sut.CallAcceptAsync(message).ConfigureAwait(false);

            // Assert
            storageProvider.Verify(s => s.StoreChargeAsync(It.Is <ChangeOfChargesMessage>(msg =>
                                                                                          msg.Period != null && msg.Period.Points != null &&
                                                                                          msg.Period.Points.First().Time == calculatedInstant)));
        }
예제 #21
0
 private async Task <ResolutionType?> GetResolutionTypeAsync(ChangeOfChargesMessage chargeMessage)
 {
     return(string.IsNullOrWhiteSpace(chargeMessage.Period?.Resolution)
         ? throw new ArgumentException($"Fails as {nameof(chargeMessage.Period.Resolution)} is invalid")
         : await _chargesDatabaseContext.ResolutionType.SingleOrDefaultAsync(type => type.Name == chargeMessage.Period.Resolution));
 }
 private static void MakeMessageValid(ChangeOfChargesMessage changeOfChargesMessage)
 {
     changeOfChargesMessage.MarketDocument !.SenderMarketParticipant !.MRid = "ads";
     changeOfChargesMessage.Type = "D01";
     changeOfChargesMessage.MktActivityRecord !.ChargeType !.VATPayer = "D01";
 }
 public async Task CallRejectAsync(ChangeOfChargesMessage changeOfChargesMessage)
 {
     await RejectAsync(changeOfChargesMessage, CancellationToken.None);
 }
 public async Task <bool> CallValidateAsync(ChangeOfChargesMessage changeOfChargesMessage)
 {
     return(await ValidateAsync(changeOfChargesMessage, CancellationToken.None).ConfigureAwait(false));
 }
예제 #25
0
 private async Task <ChargeType?> GetChargeTypeAsync(ChangeOfChargesMessage chargeMessage)
 {
     return(string.IsNullOrWhiteSpace(chargeMessage.Type)
         ? throw new ArgumentException($"Fails as {nameof(chargeMessage.Type)} is invalid")
         : await _chargesDatabaseContext.ChargeType.SingleOrDefaultAsync(type => type.Code == chargeMessage.Type));
 }
        public static Charge MapChangeOfChargesMessageToCharge(
            ChangeOfChargesMessage chargeMessage,
            ChargeType chargeType,
            MarketParticipant chargeTypeOwnerMRid,
            ResolutionType resolutionType,
            VatPayerType vatPayerType)
        {
            if (string.IsNullOrWhiteSpace(chargeMessage.ChargeTypeMRid))
            {
                throw new ArgumentException($"{nameof(chargeMessage.ChargeTypeMRid)} must have value");
            }
            if (string.IsNullOrWhiteSpace(chargeMessage.CorrelationId))
            {
                throw new ArgumentException($"{nameof(chargeMessage.CorrelationId)} must have value");
            }
            if (string.IsNullOrWhiteSpace(chargeMessage.LastUpdatedBy))
            {
                throw new ArgumentException($"{nameof(chargeMessage.LastUpdatedBy)} must have value");
            }
            if (chargeMessage.MktActivityRecord?.ChargeType == null)
            {
                throw new ArgumentException($"{nameof(chargeMessage.MktActivityRecord.ChargeType)} can't be null");
            }
            if (string.IsNullOrWhiteSpace(chargeMessage.MktActivityRecord.ChargeType.Name))
            {
                throw new ArgumentException($"{nameof(chargeMessage.MktActivityRecord.ChargeType.Name)} must have value");
            }
            if (string.IsNullOrWhiteSpace(chargeMessage.MktActivityRecord.ChargeType.Description))
            {
                throw new ArgumentException($"{nameof(chargeMessage.MktActivityRecord.ChargeType.Description)} must have value");
            }
            if (chargeMessage.Period == null)
            {
                throw new ArgumentException($"{nameof(chargeMessage.Period)} can't be null");
            }
            if (chargeMessage.Period.Points == null)
            {
                throw new ArgumentException($"{nameof(chargeMessage.Period.Points)} can't be null");
            }

            var charge = new Charge
            {
                ChargePrices               = new List <ChargePrice>(),
                ChargeType                 = chargeType,
                ChargeTypeOwner            = chargeTypeOwnerMRid,
                Description                = chargeMessage.MktActivityRecord.ChargeType.Description,
                LastUpdatedBy              = chargeMessage.LastUpdatedBy,
                LastUpdatedByCorrelationId = chargeMessage.CorrelationId,
                LastUpdatedByTransactionId = chargeMessage.Transaction.MRID,
                Name                 = chargeMessage.MktActivityRecord.ChargeType.Name,
                RequestDateTime      = chargeMessage.RequestDate.ToUnixTimeTicks(),
                ResolutionType       = resolutionType,
                StartDate            = chargeMessage.MktActivityRecord.ValidityStartDate.ToUnixTimeTicks(),
                EndDate              = chargeMessage.MktActivityRecord.ValidityEndDate?.ToUnixTimeTicks(),
                Status               = (int)chargeMessage.MktActivityRecord.Status,
                TaxIndicator         = chargeMessage.MktActivityRecord.ChargeType.TaxIndicator,
                TransparentInvoicing = chargeMessage.MktActivityRecord.ChargeType.TransparentInvoicing,
                VatPayer             = vatPayerType,
                MRid                 = chargeMessage.ChargeTypeMRid,
                Currency             = "DKK",
            };

            foreach (var point in chargeMessage.Period.Points)
            {
                var newChargePrice = new ChargePrice
                {
                    Time   = point.Time.ToUnixTimeTicks(),
                    Amount = point.PriceAmount,
                    LastUpdatedByCorrelationId = chargeMessage.CorrelationId,
                    LastUpdatedByTransactionId = chargeMessage.Transaction.MRID,
                    LastUpdatedBy   = chargeMessage.LastUpdatedBy,
                    RequestDateTime = chargeMessage.RequestDate.ToUnixTimeTicks(),
                };

                charge.ChargePrices.Add(newChargePrice);
            }

            return(charge);
        }
        public async Task <ChangeOfChargesMessageResult> HandleAsync([NotNull] ChangeOfChargesMessage message)
        {
            var result = await HandleTransactionsAsync(message).ConfigureAwait(false);

            return(result);
        }