Exemple #1
0
        public void Add(AccountingDay day)
        {
            foreach (Register reg in this.summaryRegister)
            {
                reg.Amount = reg.Amount + day.SummaryRegister.FirstOrDefault(r => r.TariffId == reg.TariffId && reg.ObisCode.C == r.ObisCode.C).Amount;
            }

            this.accountingDays.Add(day);
        }
        /// <summary>
        /// Calculates the next valid range for the current day
        /// </summary>
        /// <param name="reading">The IntervalReading at the end of the new range.</param>
        /// <param name="endCurrentReading">The end date of the current range.</param>
        /// <param name="startReading">The IntervalReading at the start of the new range.</param>
        /// <param name="start">The start date of the current range.</param>
        /// <param name="end">The global end date of the current day.</param>
        /// <param name="dayTimeProfiles">The dayTimeProfiles for the current day.</param>
        /// <param name="meterReading">The meterReading object of the current original value list.</param>
        /// <param name="profile">The current SpecialDayProfile.</param>
        /// <param name="currentDay">The current AccountingDay object.</param>
        /// <param name="i">The current index value of the parent loop.</param>
        /// <param name="latestReading">The current meterReading value.</param>
        /// <param name="latestTariffId">The last valid tariff id.</param>
        /// <returns>The rangeData of the found range</returns>
        public (IntervalReading reading, MeasuringRange range, int index, long latestReading) GetNextRange(IntervalReading reading,
                                                                                                           DateTime endCurrentReading, IntervalReading startReading, DateTime start, DateTime end, List <DayTimeProfile> dayTimeProfiles,
                                                                                                           MeterReading meterReading, SpecialDayProfile profile, AccountingDay currentDay, int i, long latestReading, ushort latestTariffId)
        {
            var endReading = SetConcreteIntervalReading(reading, endCurrentReading);
            var range      = new MeasuringRange();

            // Normal situation: reading is valid.
            if (endReading.reading != null && IsStatusValid(endReading.reading))
            {
                range = new MeasuringRange(start, endReading.end, (ushort)dayTimeProfiles[i - 1].TariffNumber,
                                           (endReading.reading.Value.Value - startReading.Value.Value));
            }
            else // A gap was found
            {
                // Looking for the next valid IntervalReading
                var result = FindLastValidTime(start, end, profile, dayTimeProfiles, meterReading, i - 1);
                endReading = SetIntervalReading(meterReading, result.end, result.index, dayTimeProfiles.Count);

                if (result.end < end && endReading.reading != null) // An IntervalReading was found which is bigger than startReading but smaller than the detected gap.
                {
                    range = new MeasuringRange(start, endReading.end, (ushort)dayTimeProfiles[result.index].TariffNumber,
                                               (endReading.reading.Value.Value - startReading.Value.Value));
                }
                else
                {
                    // Count in error register
                    if (endReading.reading != null && IsStatusValid(endReading.reading))
                    {
                        range = new MeasuringRange(start, endReading.end, (endReading.reading.Value.Value - startReading.Value.Value));
                    }
                    else
                    {
                        // No closing valid IntervalReading for the current day was found (There was a gap at the last tariff change)
                        latestTariffId     = 63;
                        endReading.reading = startReading;     // No valid IntervalReading was found. Reset range to mark it as invalid.
                    }
                }

                // 1 Measurement period at tariff change is missing
                if ((i - 1) == result.index)
                {
                    latestReading  = this.GetLatestReading(latestReading, endReading.reading);
                    latestTariffId = range.TariffId;

                    currentDay.Add(range, new ObisId(meterReading.ReadingType.ObisCode));
                    var j           = result.index;
                    var nextDate    = ModelExtensions.GetDateTimeFromSpecialDayProfile(profile, dayTimeProfiles[j + 1]);
                    var nextReading = SetIntervalReading(meterReading, nextDate, j + 1, dayTimeProfiles.Count);
                    while (nextReading.reading == null || !IsStatusValid(nextReading.reading))
                    {
                        j++;
                        if (j < dayTimeProfiles.Count - 1)
                        {
                            nextDate = ModelExtensions.GetDateTimeFromSpecialDayProfile(profile,
                                                                                        dayTimeProfiles[j + 1]);
                            nextReading = SetIntervalReading(meterReading, nextDate, j + 1, dayTimeProfiles.Count);
                        }
                        else
                        {
                            nextDate = ModelExtensions.GetDateTimeFromSpecialDayProfile(profile,
                                                                                        dayTimeProfiles[j]);
                            nextReading = SetIntervalReading(meterReading, nextDate, j, dayTimeProfiles.Count);

                            if (nextReading.reading == null || !IsStatusValid(endReading.reading))
                            {
                                nextReading = endReading;
                                break;
                            }
                        }
                    }

                    // Count in error register
                    range        = new MeasuringRange(endReading.end, nextReading.end, (nextReading.reading.Value.Value - endReading.reading.Value.Value));
                    endReading   = nextReading;
                    result.index = j + 1;
                }

                // Protect for the special case i == dayTimeProfiles.Count -1 because it could lead to an endless loop.
                if (i != dayTimeProfiles.Count - 1)
                {
                    i = result.index;
                }
            }

            // Check if the range object is empty
            if (this.IsRangeEmpty(range))
            {
                range.TariffId = latestTariffId;
            }

            return(endReading.reading, range, i, latestReading);
        }
        /// <summary>
        /// Searches the next valid startReading (In case the first value or values of the day are gaps)
        /// </summary>
        /// <param name="start">the current timestamp.</param>
        /// <param name="dayTimeProfiles">The dayTimeProfiles for the current day.</param>
        /// <param name="profile">The specialDayProfile of the current day.</param>
        /// <param name="meterReading">The meterReading object of the current original value list.</param>
        /// <param name="currentDay">The current AccountingDay object.</param>
        /// <param name="dtpIndex">The current dayTimeProfiles index.</param>
        /// <param name="latestReading">The current meterReading value.</param>
        /// <param name="lastTariffId">The last valid tariff id.</param>
        /// <returns>The next valid start value.</returns>
        public (IntervalReading startReading, int index, long latestReading, ushort tariffId) GetStartReading(DateTime start, List <DayTimeProfile> dayTimeProfiles,
                                                                                                              SpecialDayProfile profile, MeterReading meterReading, AccountingDay currentDay, int dtpIndex, long latestReading, ushort lastTariffId)
        {
            var dayStart     = start;
            var startReading = new IntervalReading();
            var index        = dtpIndex;

            for (int i = 1; i < dayTimeProfiles.Count; i++)
            {
                start        = ModelExtensions.GetDateTimeFromSpecialDayProfile(profile, dayTimeProfiles[i]);
                startReading = meterReading.GetIntervalReadingFromDate(start);

                // If the gap reaches the next tariff change
                if (dayTimeProfiles[i].TariffNumber != lastTariffId && lastTariffId != 63)
                {
                    lastTariffId = 63;
                }

                // Checks if a startReading is found
                if (startReading != null && IsStatusValid(startReading))
                {
                    currentDay.Add(new MeasuringRange()
                    {
                        Start    = dayStart,
                        End      = start,
                        Amount   = (startReading.Value.Value - latestReading),
                        TariffId = lastTariffId
                    }, new ObisId(meterReading.ReadingType.ObisCode));

                    index         = i;
                    latestReading = GetLatestReading(latestReading, startReading);
                    lastTariffId  = (ushort)dayTimeProfiles[i].TariffNumber;
                    break;
                }
                else
                {
                    index = i;
                }
            }

            // if no startReading for the whole day was found, set index to 96
            if ((startReading == null || !IsStatusValid(startReading)) && index == dayTimeProfiles.Count - 1)
            {
                var nextDay0OClock = start.AddSeconds(900);
                startReading = meterReading.GetIntervalReadingFromDate(nextDay0OClock);

                // Check if a value for the next day at 0:00 o Clock exists
                if (startReading != null && IsStatusValid(startReading))
                {
                    currentDay.Add(new MeasuringRange()
                    {
                        Start    = dayStart,
                        End      = nextDay0OClock,
                        Amount   = startReading.Value.Value - latestReading,
                        TariffId = lastTariffId
                    }, new ObisId(meterReading.ReadingType.ObisCode));
                }
                index = dayTimeProfiles.Count;
            }

            return(startReading, index, latestReading, lastTariffId);
        }
        /// <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);
        }