Расчет продолжительности и цены на основе предварительно определенных предложений и временного диапазона - PullRequest
0 голосов
/ 20 сентября 2018

Я пытался найти способ сделать это правильно, но, возможно, кто-то мог бы направить меня в правильном направлении, поскольку я потратил довольно много времени, пытаясь сделать это без успеха.

Я пытаюсьразработать в моем приложении функцию для моего игрового центра, которая позволяет пользователю устанавливать различные ценовые предложения в зависимости от времени входа / выхода, вот пример того, чего я хочу достичь:

  • В настоящее время у меня есть два ценовых предложения (в качестве примера я буду использовать валюту USD):

    1-й диапазон предложений:

    Offer_Start_Time Offer_End_Time ------------------------------------------------ 10:00:00 AM 05:00:00 PM

    2-й диапазон предложений:

    - это то, что находится за пределами диапазона 1-го Оффера (что-то вроде 05:05:00 PM to 09:59:59 AM)

  • Предполагается, что у меня в клубе Table Tennis, и он имеет следующие настройки: 1st Offer Pricing is 5 USD 2nd Offer Pricing is 10 USD

  • Так, если клиент приходит IN в 11 AM и идет OUT в 1:15 PM, тогда приложение будет взимать с него 5 USD

  • Если клиент приходит IN в 4:40 PM и идет OUT в 09:00 PM, то приложение должно разделитьсястоимость в двух диапазонах следующим образом: 4:40 PM to 05:00 PM will cost him 5 USD 5:00 PM to 09:00 PM will cost him 10 USD

    • То же самое должно работать, если клиент приходит IN в 11:40 PM и идет OUT в 02:00 AM (which is the next day)

То, что я сделал до сих пор, которое работает нормально только тогда, когда диапазон находится в пределах 1 дня: </p> <p>I first fetch the saved <code>Offer_Start_Time and Offer_End_Time из базы данных, затем сделайте это

 If New TimeSpan(TimeOfDay.Hour, TimeOfDay.Minute, TimeOfDay.Second) >= New TimeSpan(24, 0, 0) And New TimeSpan(TimeOfDay.Hour, TimeOfDay.Minute, TimeOfDay.Second) < New TimeSpan( Offer_End_Time.Hour,  Offer_End_Time.Minute,  Offer_End_Time.Second) Then    
                        Offer_Start_Time= Date.Today.AddDays(-1)
                        Offer_End_Time = Date.Today.AddDays(-1)
                        Offer_Start_Time_NextDay = Date.Today
                    Else
                        Offer_Start_Time= Date.Today
                        Offer_End_Time = Date.Today
                        Offer_Start_Time_NextDay = Date.Today.AddDays(1)
                    End If

Затем я использую приведенный ниже код дляполучить диапазон, цену и т. д. </p> <pre><code>If (INTIME >= Offer_Start_Time And OUTTIME <= Offer_End_Time And OUTTIME < Offer_Start_Time_NextDay) Then ' MsgBox("offer 1") xTotal_1 = CalculatePrice_Time(Table_Number, INTIME, OUTTIME, PerHour_Price1,PriceType, "Price1") ElseIf (INTIME >= Offer_Start_Time And INTIME <= Offer_End_Time And OUTTIME > Offer_End_Time And OUTTIME < Offer_Start_Time_NextDay) Then 'MsgBox("offer 1+2") xTotal_1 = CalculatePrice_Time(Table_Number, INTIME, Offer_End_Time, PerHour_Price1,PriceType, "Price1") '+' xTotal_2 = CalculatePrice_Time(Table_Number, Offer_End_Time, OUTTIME, PerHour_Price2,PriceType, "Price2") ElseIf (INTIME >= Offer_Start_Time And INTIME > Offer_End_Time And OUTTIME > Offer_End_Time And OUTTIME < Offer_Start_Time_NextDay) Then ' MsgBox("Offer 2") xTotal_2 = CalculatePrice_Time(Table_Number, INTIME, OUTTIME, PerHour_Price2,PriceType, "Price2") ElseIf (INTIME >= Offer_Start_Time And OUTTIME > Offer_End_Time And OUTTIME >= Offer_Start_Time_NextDay) Then 'MsgBox("Offer 2+3") '3 is the 2nd offer range which is outside 1st offer range xTotal_1 = CalculatePrice_Time(Table_Number, INTIME, Offer_Start_Time_NextDay, PerHour_Price1,PriceType, "Price1") '+' xTotal_2 = CalculatePrice_Time(Table_Number, Offer_Start_Time_NextDay, OUTTIME, PerHour_Price2,PriceType, "Price2") End If

  • PerHour_Price1 и PerHour_Price2 значения будут получены из базы данных, в которой он имеетКарта Table Number и ее столбца Price1 и переменной Price2

  • PriceType содержит "C" или "N", где C - форум пользовательских цен с использованием блоков 0-5,5-10 ... 55-60, а "N" - это формула Normal, в которой она будет умножать общее количество использованных минут на (PerHour_Price1 or PerHour_Price2)/60


. Мне нужноНиже приведена справка:

  • Я получаю неправильную длительность и цену, если предположить, что клиент приходит IN по 10:00 PM 20/09/2018 и идет OUT по 01:00 PM 21/09/2018, имея в виду, что у меня только значение TimeвOffer_Start_Time и Offer_End_Time переменная диапазона
  • Я хочу иметь возможность добавлять несколько предложений в один и тот же день вместо двух в текущей настройке.например: Offer 1 Range 10:00 AM to 01:00 PM Offer 2 Range 01:00 PM to 06:00 PM Offer 3 Range 06:00 PM to 09:59 AM

Я надеюсь, что моя проблема объяснена четко

Я был бы благодарен, если кто-нибудь может помочь мне с этим или поделиться наилучшим способом сделать это, как я считаюмой код громоздок и не будет работать для определенных сценариев


EDIT (добавлены коды):

   Public Function CalculatePrice_Time(ByVal Table_Number As String, ByVal xDateTime_IN As DateTime, ByVal xDateTime_OUT As DateTime _
        , ByVal Price As Double, ByVal PriceType As String, ByVal Price_DBColumn As String) As Double


    Dim Result As Double = 0.0


    Dim Hours_Used As Double = 0
    Dim Minutes_Used As Double = 0

    Dim HourToPrice As Double = 0
    Dim MinutesToPrice As Double = 0


    Dim Usage_Duration As TimeSpan = Calculate_Usage_Time(xDateTime_IN, xDateTime_OUT, True) 'True means return result without rounding to nearest 5 minutes

    Dim Usage_Duration_Rounded As TimeSpan = Calculate_Usage_Time(xDateTime_IN, xDateTime_OUT) 

    Hours_Used = Usage_Duration.Hours

    Minutes_Used = Usage_Duration.Minutes

    If PriceType = "C" Then  'Custom pricing in blocks  0-5,  5-10 ... 55-60
        MinutesToPrice = GetCustomPrice(Table_Number, "C", Minutes_Used, Price_DBColumn)  '<-- this is where I fetch the pricing from database, Price_DBColumn = "Price1" will point to the database column for pricing of Offer 1, and Price2 means Offer 2
    End If

    HourToPrice = Hours_Used * Price

    If PriceType = "C" Then
        Result = HourToPrice + MinutesToPrice
    ElseIf PriceType = "N" Then
        Result = (Price / 60) * Usage_Duration_Rounded.TotalMinutes
    End If

    Return Result

End Function
  • GetCustomPrice() функция будет искать базу данных, которая содержит данные в видеПример ниже: Table_Number Minutes_Start Minutes_End Price1 Price2 1 0 5 0.050 0.100 1 5 10 0.100 0.150 1 10 15 0.400 0.500 . .. .. ..... ..... 1 55 60 5.000 10.00

РЕДАКТИРОВАТЬ: (показывая, что я сделал с примером кода Дэвида)

    -Output Test for CalculateOverlapPrice and CalculateOverlapMinutes functions 
for the Range (IN : 23/09/2018 12:00:00 AM , OUT : 23/09/2018 01:00:00 AM)

        [custArrival] : 23/09/2018 12:00:00 AM
        [custExit] : 23/09/2018 01:00:00 AM
        [currentDateOfferStart] : 23/09/2018 10:00:00 AM
        [currentDateOfferEnd] : 23/09/2018 01:00:00 PM
        [offer] : 5  Timing : 10:00 AM - 01:00 PM
        Used Minutes : 0
        Block Price : 0
        -------------------
        [custArrival] : 23/09/2018 12:00:00 AM
        [custExit] : 23/09/2018 01:00:00 AM
        [currentDateOfferStart] : 23/09/2018 01:00:00 PM
        [currentDateOfferEnd] : 23/09/2018 06:00:00 PM
        [offer] : 10  Timing : 01:00 PM - 06:00 PM
        Used Minutes : 0
        Block Price : 0
        -------------------
        [custArrival] : 23/09/2018 12:00:00 AM
        [custExit] : 23/09/2018 01:00:00 AM
        [currentDateOfferStart] : 23/09/2018 06:00:00 PM
        [currentDateOfferEnd] : 24/09/2018 10:00:00 AM
        [offer] : 5  Timing : 06:00 PM - 10:00 AM
        Used Minutes : 0
        Block Price : 0
        -------------------
        Total : 0
        -------------------

-Подбор предложения отбазы данных и добавив их в список:

            Dim Offer_Start As Date = CDate(dRow("TablePrice_StartPeriod"))
            Dim Offer_End As Date = CDate(dRow("TablePrice_EndPeriod"))
            Dim Price As Double = CDbl(dRow("TablePrice_HourlyRate"))

            Offer_Start = New Date(1, 1, 1, Offer_Start.Hour, Offer_Start.Minute, 0)



            If Offer_Start.Hour > Offer_End.Hour Or (Offer_Start.Hour = Offer_End.Hour And Offer_Start.Minute = Offer_End.Minute) Then ' it means offer end next day 

                Offer_End = New Date(1, 1, 2, Offer_End.Hour, Offer_End.Minute, 0)

            Else
                Offer_End = New Date(1, 1, 1, Offer_End.Hour, Offer_End.Minute, 0)

            End If

            Dim T_Offer As New Offer(Offer_Start, Offer_End, Price)


            CurrentOffers.Add(T_Offer)

Новый

Я обновил свой код, чтобы получать предложения из базы данных, чтобы они были совместимы с новыми разделенными изменениями, предоставленными Дэвидом.а также настроил его для сортировки в противном случае CurrentOffers (0) .StartTime вернет неправильное время, которое я не выяснил, пока не использовал образец, предоставленный для тестирования.

   Dim DB_Offer_Start As Date = CDate(dRow("TablePrice_StartPeriod"))
   Dim DB_Offer_End As Date = CDate(dRow("TablePrice_EndPeriod"))
   Dim Price As Double = CDbl(dRow("TablePrice_HourlyRate"))

            Dim New_Offer_Start As Date = Nothing
            Dim New_Offer_End As Date = Nothing

            If DB_Offer_Start.Hour > DB_Offer_End.Hour Or (DB_Offer_Start.Hour = DB_Offer_End.Hour And DB_Offer_Start.Minute = DB_Offer_End.Minute) Then ' it means offer end next day 
                '================ Split offer into two ranges  [Before Midnight to midnight    PM to AM]
                New_Offer_Start = New Date(1, 1, 1, DB_Offer_Start.Hour, DB_Offer_Start.Minute, 0)
                New_Offer_End = New Date(1, 1, 2, 0, 0, 0)
                CurrentOffers.Add(New Offer(New_Offer_Start, New_Offer_End, Price))
                '======================================
                '================ Split offer into two ranges  [After Midnight to end time  AM to AM/PM]
                New_Offer_Start = New Date(1, 1, 1, 0, 0, 0)
                New_Offer_End = New Date(1, 1, 1, DB_Offer_End.Hour, DB_Offer_End.Minute, 0)

                CurrentOffers.Add(New Offer(New_Offer_Start, New_Offer_End, Price))
                '======================================
            Else
                New_Offer_Start = New Date(1, 1, 1, DB_Offer_Start.Hour, DB_Offer_Start.Minute, 0)
                New_Offer_End = New Date(1, 1, 1, DB_Offer_End.Hour, DB_Offer_End.Minute, 0)
                CurrentOffers.Add(New Offer(New_Offer_Start, New_Offer_End, Price))

            End If

        Next

        If CurrentOffers.Count > 0 Then  'Sort to had 0 or 12 AM as first 
            CurrentOffers.Sort(Function(x, y) x.StartTime.CompareTo(y.StartTime))
        End If

Добавлено:Результаты тестов

Offers List 
    [offer] : 5  Timing : 01/01/0001 12:00:00 AM - 01/01/0001 10:00:00 AM
    [offer] : 10  Timing : 01/01/0001 10:00:00 AM - 01/01/0001 01:00:00 PM
    [offer] : 5  Timing : 01/01/0001 01:00:00 PM - 01/01/0001 06:00:00 PM
    [offer] : 5  Timing : 01/01/0001 06:00:00 PM - 02/01/0001 12:00:00 AM
=====================================================
    Output for range 22/09/2018 11:00:00 PM - 23/09/2018 11:00:00 AM
    -------------------
    [offer] : 5  Timing : 12:00 AM - 10:00 AM
    Used Minutes : 0
    Block Price : 0
    -------------------
    [offer] : 10  Timing : 10:00 AM - 01:00 PM
    Used Minutes : 0
    Block Price : 0
    -------------------
    [offer] : 5  Timing : 01:00 PM - 06:00 PM
    Used Minutes : 0
    Block Price : 0
    -------------------
    [offer] : 5  Timing : 06:00 PM - 12:00 AM
    Used Minutes : 60
    Block Price : 5
    -------------------
    This is inside the [If custExit.DayOfYear <> custArrival.DayOfYear Then] block
    [offer] : 5  Timing : 12:00 AM - 10:00 AM
    Cust Arrival/Exit Timing : 23/09/2018 12:00:00 AM - 23/09/2018 11:00:00 AM <--- Output of (New Date(custExit.Year, custExit.Month, custExit.Day, 0, 0, 0)) to custExit
    Used Minutes : 600   <---- CalculateOverlapprice ignored the extra 1 hour, because offer block ended at 10 AM? 
    Block Price : 50
    -------------------
    Total : 55
    -------------------
</code>

1 Ответ

0 голосов
/ 22 сентября 2018

После наших сообщений в комментариях, я думаю, что может быть лучше, я просто дам вам функцию, которая правильно рассчитывает перекрытие - хотя я подозреваю, что ваши вычисления могут работать с настройкой к информации в базе данных.

Подпрограмма ниже основана на данных для каждого предложения, хранящихся в Date объекте, подобном следующему определению класса

Private Class Offer
    Public ReadOnly StartTime As Date
    Public ReadOnly EndTime As Date
    Public ReadOnly Price As Decimal

    Public Sub New(tmpStartTime As Date, tmpEndTime As Date, tmpPrice As Decimal)
        StartTime = tmpStartTime
        EndTime = tmpEndTime
        Price = tmpPrice
    End Sub
End Class

Вы, конечно, должны адаптировать его к своим потребностям, если хотите использоватьэто.

Затем я создал List( Of Offer) и заполнил его в своем тестовом коде следующим образом:

Dim CurrentOffers As New List(Of Offer)

ОБНОВЛЕНО Предложения должны выглядеть примерно так, как показано ниже, ноВаши предложения, которые пересекают полночь, должны быть разделены на два диапазона предложений, например, с 18:00 до 10:00 на следующий день, на самом деле они должны быть с 12:00 до 10:00, а в конце дня предложения должны иметь предложение, действующее с 18:00 до 12:00 следующего дня

Private Sub TestPopulateCurrentOffers()
    'the dates are 1/1/1 because the date object wont allow a date of 0,0,0
    Dim start1 As Date = New Date(1, 1, 1, 0, 0, 0)
    Dim end1 As Date = New Date(1, 1, 1, 10, 0, 0)
    Dim start2 As Date = New Date(1, 1, 1, 10, 0, 0)
    Dim end2 As Date = New Date(1, 1, 1, 13, 0, 0)
    Dim start3 As Date = New Date(1, 1, 1, 13, 0, 0)
    Dim end3 As Date = New Date(1, 1, 1, 18, 0, 0)
    Dim start4 As Date = New Date(1, 1, 1, 18, 0, 0)
    Dim end4 As Date = New Date(1, 1, 2, 0, 0, 0)
    CurrentOffers.Add(New Offer(start1, end1, 5))
    CurrentOffers.Add(New Offer(start2, end2, 10))
    CurrentOffers.Add(New Offer(start3, end3, 5))
    CurrentOffers.Add(New Offer(start4, end4, 5))
End Sub

Следующая подпрограмма вычисляет количество минут, в течение которых клиент перекрывает предложение.Если время прибытия - раньше, а время отправления - позже, то, разумеется, перекрытие относится к общему количеству минут в этом предложении.

Важно Я предполагаю, что информация в вашей базе данных для времени предложения хранится в формате даты с указанием года / месяца / дня, равного 1. Помимопредложение заканчивается в полночь, что должно быть 1/1/2, потому что полночь - это начало следующего дня. Если нет, то вы должны убедиться, что когда данные считываются в вашу программу, это так, как ясделали выше

Private Function CalculateOverlapMinutes(daytoCheck As Date, currentoffer As Offer, custArrival As Date, custExit As Date) As Integer
    Dim OverlapMinutes As Integer
    Dim currentDateOfferStart As Date = currentoffer.Start.AddYears(daytoCheck.Year - 1).AddMonths(daytoCheck.Month - 1).AddDays(daytoCheck.Day - 1)
    Dim currentDateOfferEnd As Date = currentoffer.End.AddYears(daytoCheck.Year - 1).AddMonths(daytoCheck.Month - 1).AddDays(daytoCheck.Day - 1)
    If custArrival <= currentDateOfferEnd And custExit >= currentDateOfferStart Then 'calculate which time to use 
        'If customer arrival Is before the offer start time then use the offer start time,
        'because the overlap of the particular offer starts at the offer start time. Otherwise
        'use the customer arrival time because it is after the offer start time
        '
        'if the customer exits after the offer end time, then use the offer end time etc
        Dim overlapStart As Date = If(custArrival < currentDateOfferStart, currentDateOfferStart, custArrival)
        Dim overlapEnd As Date = If(custExit > currentDateOfferEnd, currentDateOfferEnd, custExit)
        'calculate number of minutes of overlap for the offer being checked
        OverlapMinutes = CInt(overlapEnd.Subtract(overlapStart).TotalMinutes)
    Else
        OverlapMinutes = 0
    End If
    Return OverlapMinutes
End Function

Наконец, этот бит тестового кода просто перебирает каждое предложение и сравнивает количество совпадений и добавляет каждый результат к цене.Это упрощенная версия, которую вам, конечно, нужно будет адаптировать к вашим ценовым моделям, но вы поймете, что идея.

Обновлено

Private Function CalculateOverlapPrice(custArrival As Date, custExit As Date) As Decimal
    Dim price As Decimal
    Dim Days As New List(Of Date)
    Dim tmpDate As Date = custArrival.Date
    Do
        Days.Add(tmpDate)
        tmpDate = tmpDate.AddDays(1)
    Loop Until tmpDate > custExit.Date
    For Each checkDay As Date In Days
        For Each [offer] As Offer In CurrentOffers
            price += (CalculateOverlapMinutes(checkDay, [offer], custArrival, custExit) * [offer].Price) / 60
        Next
    Next
    Return price
End Function

Надеюсь, что это всепомогает

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...