/// <summary> /// The main calculation method for the accounting period in Taf-1. /// </summary> /// <param name="supplier">Contains the calculation data.</param> /// <param name="meterReading">The MeterReading instance with the raw data.</param> /// <param name="startReading">The intervalReading at the beginning of the section.</param> /// <param name="endReading">The intervalReading at the end of the section.</param> /// <param name="tariffId">The valid tariffId.</param> /// <returns>The calculated AccountingSection</returns> public AccountingMonth GetSection(UsagePointLieferant supplier, MeterReading meterReading, IntervalReading startReading, IntervalReading endReading, ushort tariffId) { var registers = supplier.GetRegister(); this.UpdateReadingTypeFromOriginalValueList(registers); var section = new AccountingMonth(registers) { Reading = new Reading() { Amount = startReading.Value, ObisCode = new ObisId(meterReading.ReadingType.ObisCode) } }; var start = startReading.TargetTime.Value; var end = endReading.TargetTime.Value; long amount = (long)(endReading.Value - startReading.Value); var range = new MeasuringRange(start, end, tariffId, amount); section.Add(range); section.Start = start; return(section); }
// Check whether all referenced DayIds in SpecialDayProfiles are valid DayIds private static void ValidateSupplierModelDayProfileOccurence(UsagePointLieferant supplier, List <Exception> exceptions) { var dayProfileIds = new List <ushort?>(); foreach (DayProfile profile in supplier.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles) { dayProfileIds.Add(profile.DayId); } foreach (SpecialDayProfile spProfile in supplier.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles) { bool match = false; foreach (var id in dayProfileIds) { if (id == spProfile.DayId) { match = true; break; } } if (!match) { exceptions.Add(new InvalidOperationException("TAF-7: Das Element \"DayProfile\" im Element \"SpecialDayProfile\" ist ungültig.")); } } }
/// <summary> /// Returns the SpecialDayProfiles which are needed. /// </summary> /// <param name="supplier">The supplier object which contains the SpecialDayProfiles</param> /// <param name="dayProfile">The dayId</param> /// <returns>The SpecialDayProfiles corresponding to the dayProfile</returns> public List <SpecialDayProfile> GetSpecialDayProfiles(UsagePointLieferant supplier, ushort dayProfile) { var trigger = supplier.AnalysisProfile.TariffChangeTrigger.TimeTrigger; return(trigger.SpecialDayProfiles.Where(s => s.DayId == dayProfile) .OrderBy(s => s.SpecialDayDate.GetDate()).ToList()); }
// Check whether all referenced tarif stages which are used in the DayTimeProfiles are valid private static void ValidateTarifStageOccurence(UsagePointLieferant supplier, List <Exception> exceptions) { var tarifStages = new List <ushort>(); foreach (TariffStage stage in supplier.AnalysisProfile.TariffStages) { tarifStages.Add(stage.TariffNumber); } foreach (DayProfile dayProfile in supplier.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles) { foreach (DayTimeProfile dtProfile in dayProfile.DayTimeProfiles) { bool match = false; foreach (int stage in tarifStages) { if (stage == dtProfile.TariffNumber) { match = true; break; } } if (!match) { exceptions.Add(new InvalidOperationException($"TAF-7: Ungültige Tarif-Nummer innerhalb eines Tagesprofils: {dtProfile.TariffNumber}")); } } } }
// Taf-7: Validate if the supplier periods have a duration of 15 minutes private static void ValidateTaf7SupplierDayProfiles(UsagePointLieferant supplier, List <Exception> exceptions) { var profiles = supplier.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles; foreach (DayProfile profile in profiles) { var dtProfiles = profile.DayTimeProfiles; for (int i = 0; i < dtProfiles.Count; i++) { if (i + 1 == dtProfiles.Count) { break; } var current = new TimeSpan((int)dtProfiles[i].StartTime.Hour, (int)dtProfiles[i].StartTime.Minute, 0); var next = new TimeSpan((int)dtProfiles[i + 1].StartTime.Hour, (int)dtProfiles[i + 1].StartTime.Minute, 0); if ((int)(next - current).TotalSeconds == 900) { continue; } exceptions.Add(new InvalidOperationException($"TAF-7: Die Tarifschaltzeiten für Tagesprofil {profile.DayId} in der Tarifdatei des Lieferanten sind nicht für jede 15-Minuten-Messperiode angegeben: {current} zu {next}")); } } }
/// <summary> /// In Taf 1 a tariff change is not allowed. This will be checked in this method. /// </summary> /// <param name="supplier">The supplier object which is checked</param> /// <param name="dayProfile">The current day profile number</param> public void CheckValidSupplierFile(UsagePointLieferant supplier, ushort dayProfile, ushort tariff) { var profiles = this.GetSpecialDayProfiles(supplier, dayProfile); var days = (int)(billingPeriodEnd - billingPeriodStart).TotalDays; if (profiles.Count % days != 0) { throw new InvalidOperationException($"Die Anzahl der SpecialDayProfile Objekte muss einem vielfachen von {days} entsprechen."); } }
/// <summary> /// Looks for SpecialDayProfiles which have the right dayProfile and are between /// the begin and end time. /// </summary> /// <param name="supplier">The supplier object which contains the SpecialDayProfiles.</param> /// <param name="dayProfiles">The valid dayProfiles for the current day.</param> /// <param name="begin">The start timestamp.</param> /// <param name="end">The end timestamp.</param> /// <returns>A list of all valid SpecialDayProfiles.</returns> public List <SpecialDayProfile> GetSpecialDayProfiles(UsagePointLieferant supplier, List <ushort?> dayProfiles, DateTime begin, DateTime end) { // Needed if Begin or End are in the middle of a day var open = begin.Date; var close = end.Date; return(supplier.AnalysisProfile.TariffChangeTrigger.TimeTrigger .SpecialDayProfiles .Where(s => dayProfiles.Contains(s.DayId) && s.SpecialDayDate.GetDate() >= open && s.SpecialDayDate.GetDate() <= close) .OrderBy(s => s.SpecialDayDate.GetDate()).ToList()); }
// Validation of additional requirements with additional supplier xml (only Taf-7) public static void ValidateContext(UsagePointAdapterTRuDI usagePoint, UsagePointLieferant supplierModel, AdapterContext ctx) { ValidateContext(usagePoint, ctx); var exceptions = new List <Exception>(); ValidateTaf7ModelSupplierCompatibility(usagePoint, supplierModel, exceptions); ValidateSupplierModelTariffStageCount(supplierModel, exceptions); ValidateSpecialDayProfilesWithinBillingPeriod(supplierModel, exceptions); ValidateSupplierModelCompletelyEnrolledCalendar(usagePoint, supplierModel, exceptions); ValidateTarifStageOccurence(supplierModel, exceptions); ValidateSupplierModelDayProfileOccurence(supplierModel, exceptions); if (exceptions.Any()) { throw new AggregateException("Taf-7 Context error:>", exceptions); } }
// Check if any SpecialDayProfiles are within the billing period private static void ValidateSpecialDayProfilesWithinBillingPeriod(UsagePointLieferant supplier, List <Exception> exceptions) { var begin = supplier.AnalysisProfile.BillingPeriod.Start; var end = supplier.AnalysisProfile.BillingPeriod.GetEnd(); var counter = 0; foreach (SpecialDayProfile profile in supplier.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles) { if (profile.SpecialDayDate.GetDate() >= begin && profile.SpecialDayDate.GetDate() <= end) { counter++; } } if (counter == 0) { exceptions.Add(new InvalidOperationException("Die Abrechnungsperiode in der Tarifdatei des Lieferanten umfasst keinen vollen Tagesprofil.")); } }
// Validates the maximum amount of tariff stages private static void ValidateSupplierModelTariffStageCount(UsagePointLieferant supplier, List <Exception> exceptions) { if (supplier.AnalysisProfile.TariffStages.Count > 20) { var stages = supplier.AnalysisProfile.TariffStages; int errorRegisterCount = 0; foreach (TariffStage stage in stages) { var obisId = new ObisId(stage.ObisCode); if (obisId.E == 63) { errorRegisterCount++; } } if (stages.Count - errorRegisterCount > 20) { exceptions.Add(new InvalidOperationException("Es sind maximal 20 Tarifstuffen zulässig.")); } } }
// The public method for the validation of the supplier model public static UsagePointLieferant ValidateSupplierModel(UsagePointLieferant usagePoint) { var exceptions = new List <Exception>(); CommonModelValidation(usagePoint, exceptions); if (usagePoint.Certificates.Count >= 1) { foreach (Certificate cert in usagePoint.Certificates) { ValidateCertificate(cert, exceptions); } } ValidateAnalysisProfile(usagePoint.AnalysisProfile, exceptions); ValidateTaf7SupplierDayProfiles(usagePoint, exceptions); if (exceptions.Any()) { throw new AggregateException("Supplier Model error:>", exceptions); } return(usagePoint); }
public void TestGetRegister() { var supplier = new UsagePointLieferant(); var analysisProfile = new AnalysisProfile(); var obisId181 = "0100010801FF"; var obisId182 = "0100010802FF"; var obisId183 = "0100010803FF"; var obisId1863 = "010001083FFF"; var obisId281 = "0100020801FF"; var obisId282 = "0100020802FF"; var obisId2863 = "010002083FFF"; var tariffStage1 = new TariffStage() { Description = "T1", ObisCode = obisId181, TariffNumber = 1 }; var tariffStage2 = new TariffStage() { Description = "T2", ObisCode = obisId182, TariffNumber = 2 }; var tariffStage3 = new TariffStage() { Description = "T3", ObisCode = obisId183, TariffNumber = 3 }; var tariffStage4 = new TariffStage() { Description = "T4", ObisCode = obisId1863, TariffNumber = 4 }; var tariffStage5 = new TariffStage() { Description = "T5", ObisCode = obisId281, TariffNumber = 5 }; var tariffStage6 = new TariffStage() { Description = "T6", ObisCode = obisId282, TariffNumber = 6 }; var tariffStage7 = new TariffStage() { Description = "T7", ObisCode = obisId2863, TariffNumber = 7 }; analysisProfile.TariffStages.Add(tariffStage1); analysisProfile.TariffStages.Add(tariffStage2); analysisProfile.TariffStages.Add(tariffStage3); analysisProfile.TariffStages.Add(tariffStage4); analysisProfile.TariffStages.Add(tariffStage5); analysisProfile.TariffStages.Add(tariffStage6); analysisProfile.TariffStages.Add(tariffStage7); supplier.AnalysisProfile = analysisProfile; var target = supplier.GetRegister(); Assert.AreEqual(7, target.Count); foreach (Register reg in target) { Assert.AreEqual(0, reg.Amount); } Assert.AreEqual("0100010801FF", target[0].ObisCode.ToHexString()); Assert.AreEqual("0100010802FF", target[1].ObisCode.ToHexString()); Assert.AreEqual("0100010803FF", target[2].ObisCode.ToHexString()); Assert.AreEqual("010001083FFF", target[3].ObisCode.ToHexString()); Assert.AreEqual("0100020801FF", target[4].ObisCode.ToHexString()); Assert.AreEqual("0100020802FF", target[5].ObisCode.ToHexString()); Assert.AreEqual("010002083FFF", target[6].ObisCode.ToHexString()); Assert.AreEqual(1, target[0].TariffId); Assert.AreEqual(2, target[1].TariffId); Assert.AreEqual(3, target[2].TariffId); Assert.AreEqual(4, target[3].TariffId); Assert.AreEqual(5, target[4].TariffId); Assert.AreEqual(6, target[5].TariffId); Assert.AreEqual(7, target[6].TariffId); supplier.AnalysisProfile.TariffUseCase = HanAdapter.Interface.TafId.Taf2; target = supplier.GetRegister(); Assert.AreEqual(1, target[0].TariffId); Assert.AreEqual(2, target[1].TariffId); Assert.AreEqual(3, target[2].TariffId); Assert.AreEqual(63, target[3].TariffId); Assert.AreEqual(5, target[4].TariffId); Assert.AreEqual(6, target[5].TariffId); Assert.AreEqual(63, target[6].TariffId); var analysisProfile2 = new AnalysisProfile { TariffUseCase = HanAdapter.Interface.TafId.Taf2 }; analysisProfile2.TariffStages.Add(tariffStage1); analysisProfile2.TariffStages.Add(tariffStage2); analysisProfile2.TariffStages.Add(tariffStage3); analysisProfile2.TariffStages.Add(tariffStage5); analysisProfile2.TariffStages.Add(tariffStage6); supplier.AnalysisProfile = analysisProfile2; target = supplier.GetRegister(); foreach (Register reg in target) { Assert.AreEqual(0, reg.Amount); } Assert.AreEqual(7, target.Count); Assert.AreEqual("0100010801FF", target[0].ObisCode.ToHexString()); Assert.AreEqual("0100010802FF", target[1].ObisCode.ToHexString()); Assert.AreEqual("0100010803FF", target[2].ObisCode.ToHexString()); Assert.AreEqual("0100020801FF", target[3].ObisCode.ToHexString()); Assert.AreEqual("0100020802FF", target[4].ObisCode.ToHexString()); Assert.AreEqual("010001083FFF", target[5].ObisCode.ToHexString()); Assert.AreEqual("010002083FFF", target[6].ObisCode.ToHexString()); Assert.AreEqual(1, target[0].TariffId); Assert.AreEqual(2, target[1].TariffId); Assert.AreEqual(3, target[2].TariffId); Assert.AreEqual(5, target[3].TariffId); Assert.AreEqual(6, target[4].TariffId); Assert.AreEqual(63, target[5].TariffId); Assert.AreEqual(63, target[6].TariffId); var analysisProfile3 = new AnalysisProfile { TariffUseCase = HanAdapter.Interface.TafId.Taf2 }; var obisId381 = "0100030801FF"; var obisId481 = "0100040801FF"; var obisId482 = "0100040802FF"; var tariffStage8 = new TariffStage() { Description = "T8", ObisCode = obisId381, TariffNumber = 8 }; var tariffStage9 = new TariffStage() { Description = "T9", ObisCode = obisId481, TariffNumber = 9 }; var tariffStage10 = new TariffStage() { Description = "T10", ObisCode = obisId482, TariffNumber = 10 }; analysisProfile3.TariffStages.Add(tariffStage1); analysisProfile3.TariffStages.Add(tariffStage2); analysisProfile3.TariffStages.Add(tariffStage3); analysisProfile3.TariffStages.Add(tariffStage5); analysisProfile3.TariffStages.Add(tariffStage6); analysisProfile3.TariffStages.Add(tariffStage8); analysisProfile3.TariffStages.Add(tariffStage9); analysisProfile3.TariffStages.Add(tariffStage10); supplier.AnalysisProfile = analysisProfile3; target = supplier.GetRegister(); foreach (Register reg in target) { Assert.AreEqual(0, reg.Amount); } Assert.AreEqual(12, target.Count); Assert.AreEqual("0100010801FF", target[0].ObisCode.ToHexString()); Assert.AreEqual("0100010802FF", target[1].ObisCode.ToHexString()); Assert.AreEqual("0100010803FF", target[2].ObisCode.ToHexString()); Assert.AreEqual("0100020801FF", target[3].ObisCode.ToHexString()); Assert.AreEqual("0100020802FF", target[4].ObisCode.ToHexString()); Assert.AreEqual("0100030801FF", target[5].ObisCode.ToHexString()); Assert.AreEqual("0100040801FF", target[6].ObisCode.ToHexString()); Assert.AreEqual("0100040802FF", target[7].ObisCode.ToHexString()); Assert.AreEqual("010001083FFF", target[8].ObisCode.ToHexString()); Assert.AreEqual("010002083FFF", target[9].ObisCode.ToHexString()); Assert.AreEqual("010003083FFF", target[10].ObisCode.ToHexString()); Assert.AreEqual("010004083FFF", target[11].ObisCode.ToHexString()); Assert.AreEqual(1, target[0].TariffId); Assert.AreEqual(2, target[1].TariffId); Assert.AreEqual(3, target[2].TariffId); Assert.AreEqual(5, target[3].TariffId); Assert.AreEqual(6, target[4].TariffId); Assert.AreEqual(8, target[5].TariffId); Assert.AreEqual(9, target[6].TariffId); Assert.AreEqual(10, target[7].TariffId); Assert.AreEqual(63, target[8].TariffId); Assert.AreEqual(63, target[9].TariffId); Assert.AreEqual(63, target[10].TariffId); Assert.AreEqual(63, target[11].TariffId); }
/// <summary> /// The main calculation method for every day in the billing period. /// </summary> /// <param name="profile">The current SpecialDayProfile</param> /// <param name="dayProfiles">A List of all DayProfiles</param> /// <param name="meterReading">The MeterReading instance with the raw data.</param> /// <param name="supplier">Contains the calculation data.</param> /// <param name="latestReading">The last valid value of an IntervalReading.</param> /// <param name="latestTariffId">The last vaild tariff.</param> /// <returns>The calculated AccountingSection</returns> public (AccountingDay day, long latestReading, ushort tariffId) GetDayData(SpecialDayProfile profile, List <DayProfile> dayProfiles, MeterReading meterReading, UsagePointLieferant supplier, long latestReading, ushort latestTariffId) { var registers = supplier.GetRegister(); this.UpdateReadingTypeFromOriginalValueList(registers); var currentDay = new AccountingDay(registers); // Every SpecialDayProfile is linked to a dayProfile which contains dayTimeProfiles. // This dayTimeProfiles are needed because they contain the tariff change information of the day. var dayTimeProfiles = GetValidDayTimeProfiles(dayProfiles, profile); var start = ModelExtensions.GetDateTimeFromSpecialDayProfile(profile, dayTimeProfiles[0]); var index = 1; var startReading = meterReading.GetIntervalReadingFromDate(start); // If the current day has a gap at 00:00 if (startReading == null || !IsStatusValid(startReading)) { var startData = this.GetStartReading(start, dayTimeProfiles, profile, meterReading, currentDay, index, latestReading, latestTariffId); index = startData.index; startReading = startData.startReading; start = startData.startReading != null && IsStatusValid(startData.startReading) ? startData.startReading.TargetTime.Value : start; latestTariffId = startData.tariffId; latestReading = startData.latestReading; } // Check whether dayTimeProfiles is null or empty this.CheckInitSettings(dayTimeProfiles); if (startReading != null && IsStatusValid(startReading)) { currentDay.Reading = new Reading() { Amount = startReading.Value, ObisCode = new ObisId(meterReading.ReadingType.ObisCode) }; currentDay.Start = profile.SpecialDayDate.GetDate(); } var endReading = SetConcreteIntervalReading(null, DateTime.MinValue); for (var i = index; i < dayTimeProfiles.Count; i++) { DateTime end; // Check if the tariff number changes if (dayTimeProfiles[i - 1].TariffNumber != dayTimeProfiles[i].TariffNumber) { // Set the end of the current range end = ModelExtensions.GetDateTimeFromSpecialDayProfile(profile, dayTimeProfiles[i]); endReading = SetIntervalReading(meterReading, end, i, dayTimeProfiles.Count); var rangeData = GetNextRange(endReading.reading, endReading.end, startReading, start, end, dayTimeProfiles, meterReading, profile, currentDay, i, latestReading, latestTariffId); latestReading = rangeData.latestReading; start = rangeData.reading.TargetTime.Value; startReading = rangeData.reading; i = rangeData.index; latestTariffId = rangeData.range.TariffId; latestReading = this.GetLatestReading(latestReading, rangeData.reading); if (!this.IsRangeEmpty(rangeData.range)) { currentDay.Add(rangeData.range, new ObisId(meterReading.ReadingType.ObisCode)); } } // If there is no tariff change at the current timestamp else { // Check if it is the last value of the current day if (i == dayTimeProfiles.Count - 1) { end = ModelExtensions.GetDateTimeFromSpecialDayProfile(profile, dayTimeProfiles[i]); endReading = SetIntervalReading(meterReading, end, i, dayTimeProfiles.Count); var rangeData = GetNextRange(endReading.reading, endReading.end, startReading, start, end, dayTimeProfiles, meterReading, profile, currentDay, i, latestReading, latestTariffId); latestReading = rangeData.latestReading; start = end; startReading = rangeData.reading; i = rangeData.index; latestTariffId = rangeData.range.TariffId; latestReading = this.GetLatestReading(latestReading, rangeData.reading); if (!this.IsRangeEmpty(rangeData.range)) { currentDay.Add(rangeData.range, new ObisId(meterReading.ReadingType.ObisCode)); } } } } return(currentDay, latestReading, latestTariffId); }
/// <inheritdoc /> /// <summary> /// Calculates the derived register for Taf1. /// </summary> /// <param name="device">Date from the SMGW. There should be just original value lists.</param> /// <param name="supplier">The calculation data from the supplier.</param> /// <returns>An ITaf2Data instance. The object contains the calculated data.</returns> public TafAdapterData Calculate(UsagePointAdapterTRuDI device, UsagePointLieferant supplier) { this.originalValueLists = device.MeterReadings.Where(mr => mr.IsOriginalValueList()).Select(mr => new OriginalValueList(mr, device.ServiceCategory.Kind ?? Kind.Electricity)).ToList(); if (!this.originalValueLists.Any()) { throw new InvalidOperationException("Es ist keine originäre Messwertliste verfügbar."); } this.ValidateOriginalValueLists(originalValueLists, supplier, device.MeterReadings.Count); var registers = supplier.GetRegister(); this.UpdateReadingTypeFromOriginalValueList(registers); var accountingPeriod = new Taf1Data(registers, supplier.AnalysisProfile.TariffStages); accountingPeriod.SetDate(supplier.AnalysisProfile.BillingPeriod.Start, supplier.AnalysisProfile.BillingPeriod.GetEnd()); this.SetTotalBillingPeriod(accountingPeriod); ValidateBillingPeriod(); var dayProfiles = supplier.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles; foreach (OriginalValueList ovl in originalValueLists) { var startReading = ovl.MeterReading.GetIntervalReadingFromDate(billingPeriodStart); var endReading = ovl.MeterReading.GetIntervalReadingFromDate(billingPeriodEnd); if (startReading == null || !IsStatusValid(startReading)) { throw new InvalidOperationException($"Zu dem Zeitpunkt {billingPeriodStart} ist kein Wert vorhanden oder der Status kritisch oder fatal."); } if (endReading == null || !IsStatusValid(endReading)) { throw new InvalidOperationException($"Zu dem Zeitpunkt {billingPeriodEnd} ist kein Wert vorhanden oder der Status kritisch oder fatal."); } var dayProfile = this.GetDayProfileNumber(dayProfiles, new ObisId(ovl.MeterReading.ReadingType.ObisCode), supplier.AnalysisProfile); var tariffStages = supplier.AnalysisProfile.TariffStages; var tariffId = this.GetTariffId(tariffStages, dayProfiles, dayProfile); CheckValidSupplierFile(supplier, dayProfile, tariffId); var result = this.GetSection(supplier, ovl.MeterReading, startReading, endReading, tariffId); accountingPeriod.Add(result); accountingPeriod.AddInitialReading(new Reading() { Amount = accountingPeriod.AccountingSections.First(s => s.Reading.ObisCode == ovl.MeterReading.ReadingType.ObisCode).Reading.Amount, ObisCode = new ObisId(ovl.MeterReading.ReadingType.ObisCode) }); } return(new TafAdapterData(typeof(Taf2SummaryView), typeof(Taf2DetailView), accountingPeriod)); }
/// <summary> /// The method provides the derrived register for the Taf7 calculation. /// </summary> /// <param name="supplier">The supplier model which contains the needed tariff data for the register.</param> /// <returns>A list of all register which are needed for the calculation.</returns> public static List <Register> GetRegister(this UsagePointLieferant supplier) { var register = new List <Register>(); var tariffStages = supplier.AnalysisProfile.TariffStages; foreach (TariffStage stage in tariffStages) { var reg = new Register() { ObisCode = new ObisId(stage.ObisCode), TariffId = stage.TariffNumber, Amount = 0 }; register.Add(reg); } if (supplier.AnalysisProfile.TariffUseCase == HanAdapter.Interface.TafId.Taf2) { var errorRegister = register.Where(r => r.ObisCode.E == 63).ToList() ?? new List <Register>(); if (errorRegister.Count > 0) { foreach (Register reg in errorRegister) { reg.TariffId = 63; } } else { var first = true; var seccond = true; var next = 2; foreach (Register reg in register.ToList()) { if (first && reg.ObisCode.C == 1) { var oc = reg.ObisCode.ToHexString(); var errRegister = new Register() { ObisCode = new ObisId(oc) { E = 63 }, TariffId = 63, Amount = 0 }; register.Add(errRegister); first = false; } else if (seccond && reg.ObisCode.C == 2) { var oc = reg.ObisCode.ToHexString(); var errRegister = new Register() { ObisCode = new ObisId(oc) { E = 63 }, TariffId = 63, Amount = 0 }; register.Add(errRegister); seccond = false; } else if (reg.ObisCode.C != 1 && reg.ObisCode.C != 2 && reg.ObisCode.C > next) { var oc = reg.ObisCode.ToHexString(); var errRegister = new Register() { ObisCode = new ObisId(oc) { E = 63 }, TariffId = 63, Amount = 0 }; next++; register.Add(errRegister); } } } } return(register); }
public static UsagePointLieferant ParseSupplierModel(IEnumerable <XElement> elements) { UsagePointLieferant usagePoint = null; var exceptions = new List <Exception>(); var dayIdAlreadyExists = false; foreach (XElement e in elements) { switch (e.Name.LocalName) { case "UsagePoint": usagePoint = new UsagePointLieferant(); break; case "usagePointId": usagePoint.UsagePointId = e.Value; break; case "tariffName": usagePoint.TariffName = e.Value; break; case "Customer": usagePoint.Customer = new Customer(); break; case "customerId": usagePoint.Customer.CustomerId = e.Value; break; case "InvoicingParty": usagePoint.InvoicingParty = new InvoicingParty(); break; case "invoicingPartyId": usagePoint.InvoicingParty.InvoicingPartyId = e.Value; break; case "ServiceCategory": usagePoint.ServiceCategory = new ServiceCategory(); break; case "kind": usagePoint.ServiceCategory.Kind = (Kind)Convert.ToInt32(e.Value); break; case "SMGW": usagePoint.Smgw = new SMGW(); break; case "certId": if (e.Parent.Name.LocalName == "SMGW") { usagePoint.Smgw.CertIds.Add(Convert.ToByte(e.Value)); } else if (e.Parent.Name.LocalName == "Certificate") { usagePoint.Certificates.LastOrDefault().CertId = Convert.ToByte(e.Value); } break; case "smgwId": usagePoint.Smgw.SmgwId = e.Value; break; case "Certificate": usagePoint.Certificates.Add(new Certificate()); break; case "certType": usagePoint.Certificates.LastOrDefault().CertType = (CertType)Convert.ToByte(e.Value); break; case "parentCertId": usagePoint.Certificates.LastOrDefault().ParentCertId = Convert.ToByte(e.Value); break; case "certContent": if (e.Value.ValidateHexString()) { usagePoint.Certificates.LastOrDefault().HexStringToByteArray(e.Value); } else { exceptions.Add(new InvalidOperationException("Das Element \"certContent\" enthält keinen gültigen Wert.")); } break; case "AnalysisProfile": usagePoint.AnalysisProfile = new AnalysisProfile(); break; case "tariffUseCase": usagePoint.AnalysisProfile.TariffUseCase = (TafId)Convert.ToUInt16(e.Value); break; case "tariffId": usagePoint.AnalysisProfile.TariffId = e.Value; break; case "defaultTariffNumber": usagePoint.AnalysisProfile.DefaultTariffNumber = Convert.ToUInt16(e.Value); break; case "billingPeriod": usagePoint.AnalysisProfile.BillingPeriod = new Interval(); break; case "duration": usagePoint.AnalysisProfile.BillingPeriod.Duration = Convert.ToUInt32(e.Value); break; case "start": usagePoint.AnalysisProfile.BillingPeriod.Start = Convert.ToDateTime(e.Value); break; case "TariffStage": usagePoint.AnalysisProfile.TariffStages.Add(new TariffStage()); break; case "tariffNumber": if (e.Parent.Name.LocalName == "TariffStage") { usagePoint.AnalysisProfile.TariffStages.LastOrDefault().TariffNumber = Convert.ToUInt16(e.Value); } else if (e.Parent.Name.LocalName == "DayTimeProfile") { usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault() .DayTimeProfiles.LastOrDefault().TariffNumber = Convert.ToUInt16(e.Value); } break; case "description": usagePoint.AnalysisProfile.TariffStages.LastOrDefault().Description = e.Value; break; case "obisCode": usagePoint.AnalysisProfile.TariffStages.LastOrDefault().ObisCode = e.Value; break; case "TariffChangeTrigger": usagePoint.AnalysisProfile.TariffChangeTrigger = new TariffChangeTrigger(); break; case "TimeTrigger": usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger = new TimeTrigger(); break; case "DayProfile": usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.Add(new DayProfile()); dayIdAlreadyExists = false; break; case "dayId": if (e.Parent.Name.LocalName == "DayProfile") { if (dayIdAlreadyExists) { exceptions.Add(new InvalidOperationException("Es ist nur ein Element \"dayId\" innerhalb des Elements \"DayProfile\" erlaubt.")); } else { usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault() .DayId = Convert.ToUInt16(e.Value); dayIdAlreadyExists = true; } } else if (e.Parent.Name.LocalName == "SpecialDayProfile") { var id = Convert.ToUInt16(e.Value); usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles .LastOrDefault().DayId = id; try { usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles .LastOrDefault().DayProfile = usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger .DayProfiles.Single(dp => dp.DayId == id); } catch (Exception ex) { exceptions.Add(ex); } } break; case "DayTimeProfile": usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault() .DayTimeProfiles.Add(new DayTimeProfile()); usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault() .DayTimeProfiles.LastOrDefault().DayProfile = usagePoint.AnalysisProfile .TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault(); break; case "startTime": usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault() .DayTimeProfiles.LastOrDefault().StartTime = new TimeVarType(); break; case "hour": usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault() .DayTimeProfiles.LastOrDefault().StartTime.Hour = Convert.ToByte(e.Value); break; case "minute": usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault() .DayTimeProfiles.LastOrDefault().StartTime.Minute = Convert.ToByte(e.Value); break; case "second": usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault() .DayTimeProfiles.LastOrDefault().StartTime.Second = Convert.ToByte(e.Value); break; case "hundreds": usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault() .DayTimeProfiles.LastOrDefault().StartTime.Hundreds = Convert.ToByte(e.Value); break; case "SpecialDayProfile": usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles.Add(new SpecialDayProfile()); break; case "specialDayDate": usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles.LastOrDefault() .SpecialDayDate = new DayVarType(); break; case "year": usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles.LastOrDefault() .SpecialDayDate.Year = Convert.ToUInt16(e.Value); break; case "month": usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles.LastOrDefault() .SpecialDayDate.Month = Convert.ToByte(e.Value); break; case "day_of_month": usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles.LastOrDefault() .SpecialDayDate.DayOfMonth = Convert.ToByte(e.Value); break; default: if (usagePoint == null) { throw new InvalidOperationException("Keine gültige Datei."); } exceptions.Add(new InvalidOperationException($"Das Element \"{e.Name.LocalName}\" wird nicht unterstützt.")); break; } } if (exceptions.Any()) { throw new AggregateException("Supplier Parsing error:>", exceptions); } return(usagePoint); }
// Validate of all the neccessary ids of the model xml match with the ids in the supplier xml private static void ValidateTaf7ModelSupplierCompatibility(UsagePointAdapterTRuDI model, UsagePointLieferant supplier, List <Exception> exceptions) { if (model.UsagePointId != supplier.UsagePointId) { exceptions.Add(new InvalidOperationException($"TAF-7: Die ID der Messlokation \"{model.UsagePointId}\" stimmt nicht mit der ID der Messlokation \"{supplier.UsagePointId}\" aus der Tarifdatei des Lieferanten überein.")); } if (model.InvoicingParty.InvoicingPartyId != supplier.InvoicingParty.InvoicingPartyId) { exceptions.Add(new InvalidOperationException($"TAF-7: Die ID des Rechnungsstellers \"{model.InvoicingParty.InvoicingPartyId}\" stimmt nicht mit der ID des Rechnungssteller \"{supplier.InvoicingParty.InvoicingPartyId}\" aus der Tarifdatei des Lieferanten überein.")); } if (model.ServiceCategory.Kind != supplier.ServiceCategory.Kind) { exceptions.Add(new InvalidOperationException($"TAF-7: Die Service-Kategory \"{model.ServiceCategory.Kind}\" stimmt nicht mit der Service-Kategory \"{supplier.ServiceCategory.Kind}\" aus der Tarifdatei des Lieferanten überein.")); } if (string.Compare(model.Smgw.SmgwId, supplier.Smgw.SmgwId, StringComparison.OrdinalIgnoreCase) != 0) { exceptions.Add(new InvalidOperationException($"TAF-7: Die ID des Smart Meter Gateway \"{model.Smgw.SmgwId}\" stimmt nicht mit der ID \"{supplier.Smgw.SmgwId}\" aus der Tarifdatei des Lieferanten überein.")); } if (model.TariffName != supplier.TariffName) { exceptions.Add(new InvalidOperationException($"TAF-7: Der Tarifname \"{model.TariffName}\" stimmt nicht mit dem Tariffnamen \"{supplier.TariffName}\" aus der Tarifdatei des Lieferanten überein.")); } }
/// <summary> /// Check if the count of the original value lists are valid and if all meterReadings are original value lists. /// The TariffStages count is also checked. The max is one TariffStage per original value list. /// </summary> /// <param name="originalValueList">The list with all original value lists.</param> /// <param name="supplier">raw data from the supplier.</param> public void ValidateOriginalValueLists(List <OriginalValueList> originalValueLists, UsagePointLieferant supplier, int meterReadingsCount) { if (originalValueLists.Count > 3) { throw new InvalidOperationException("Es werden maximal 3 originäre Messwertlisten unterstützt."); } if (originalValueLists.Count != meterReadingsCount) { throw new InvalidOperationException("Es sind nur originäre Messwertlisten zulässig."); } if (supplier.AnalysisProfile.TariffStages.Count > originalValueLists.Count) { throw new InvalidOperationException("Die Anzahl der Tarifstufen darf die Anzahl der originären Messwertlisten nicht überschreiten."); } }
// Check if the delivered supplier xml has an completely enrolled calendar private static void ValidateSupplierModelCompletelyEnrolledCalendar(UsagePointAdapterTRuDI model, UsagePointLieferant supplier, List <Exception> exceptions) { var period = supplier.AnalysisProfile.BillingPeriod; var profiles = supplier.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles; var sdpCheckList = new Dictionary <DateTime, int>(); var timestamp = period.Start; var hasCounted = false; while (timestamp <= period.GetEnd().AddDays(-1)) { sdpCheckList.Add(timestamp, 0); timestamp = timestamp.AddDays(1); } foreach (var profile in profiles) { if (sdpCheckList.ContainsKey(profile.SpecialDayDate.GetDate())) { sdpCheckList[profile.SpecialDayDate.GetDate()] += 1; hasCounted = true; } } foreach (var item in sdpCheckList) { if (item.Value == 0 && hasCounted) { exceptions.Add(new InvalidOperationException($"Tagesprofil für Tag {item.Key:dd.MM.yyy} nicht vorhanden.")); } } }
/// <inheritdoc /> /// <summary> /// Calculates the derived registers for Taf2. /// </summary> /// <param name="device">Data from the SMGW. There should be just original value lists.</param> /// <param name="supplier">The calculation data from the supplier.</param> /// <returns>An ITaf2Data instance. The object contains the calculated data.</returns> public TafAdapterData Calculate(UsagePointAdapterTRuDI device, UsagePointLieferant supplier) { this.originalValueLists = device.MeterReadings.Where(mr => mr.IsOriginalValueList()).Select(mr => new OriginalValueList(mr, device.ServiceCategory.Kind ?? Kind.Electricity)).ToList(); if (!this.originalValueLists.Any()) { throw new InvalidOperationException("Es ist keine originäre Messwertliste verfügbar."); } var registers = supplier.GetRegister(); this.UpdateReadingTypeFromOriginalValueList(registers); var accountingPeriod = new Taf2Data(registers, supplier.AnalysisProfile.TariffStages); var dayProfiles = supplier.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles; foreach (var ovl in this.originalValueLists) { var bpStart = ovl.MeterReading.GetFirstReadingTimestamp(supplier.AnalysisProfile.BillingPeriod.Start, supplier.AnalysisProfile.BillingPeriod.GetEnd()); var bpEnd = ovl.MeterReading.GetLastReadingTimestamp(supplier.AnalysisProfile.BillingPeriod.Start, supplier.AnalysisProfile.BillingPeriod.GetEnd()); if (bpEnd == null || bpStart == null || bpStart == bpEnd) { throw new InvalidOperationException("Keine Messwerte innerhalb des Abbrechnungszeitraums gefunden."); } accountingPeriod.SetDates(bpStart.Value, bpEnd.Value); this.SetTotalBillingPeriod(accountingPeriod); var validDayProfiles = dayProfiles.GetValidDayProfilesForMeterReading(ovl.Obis, supplier.AnalysisProfile.TariffStages); var specialDayProfiles = this.GetSpecialDayProfiles(supplier, validDayProfiles, accountingPeriod.Begin, accountingPeriod.End); long latestReading = 0; ushort latestTariffId = 63; // Check if the lists validDayProfiles and special DayProfiles are null or empty if (!this.CheckUsedLists(validDayProfiles, specialDayProfiles)) { continue; } // Calculation of the single days (latestReading and latestTariffId are needed for days across gap detection) foreach (SpecialDayProfile profile in specialDayProfiles) { var currentDayData = this.GetDayData(profile, dayProfiles, ovl.MeterReading, supplier, latestReading, latestTariffId); if (!(currentDayData.day.Start == DateTime.MinValue) || currentDayData.day.MeasuringRanges.Count != 0) { accountingPeriod.Add(currentDayData.day); } latestReading = currentDayData.latestReading; latestTariffId = currentDayData.tariffId; } // Set the initial overall meter reading accountingPeriod.AddInitialReading(new Reading() { Amount = accountingPeriod.AccountingSections.First().Reading.Amount, ObisCode = ovl.Obis }); } accountingPeriod.OrderSections(); return(new TafAdapterData(typeof(Taf2SummaryView), typeof(Taf2DetailView), accountingPeriod)); }