示例#1
0
        public ReservationDurations GetReservationDurations(DataTable dtToolDataClean)
        {
            var reservations = GetReservationDateRangeItems(dtToolDataClean);
            var range        = new ReservationDateRange(reservations);
            var result       = new ReservationDurations(range);

            return(result);
        }
示例#2
0
        public void CanGetTransferDruation()
        {
            int resourceId = 14021;
            var dateRange  = DateRange.GetDateRange(DateTime.Parse("2018-05-01"));

            // step 1: get ReservationDateRangeItems
            var costs = Provider.Data.Cost.FindToolCosts(resourceId, dateRange.EndDate);
            var toolBillingReservations = Provider.Billing.Tool.SelectReservations(dateRange.StartDate, dateRange.EndDate, resourceId);
            var reservations            = ReservationDateRangeItem.GetReservationDateRangeItems(toolBillingReservations, costs);

            // step 2: get ReservationDurations
            var range     = new ReservationDateRange(reservations);
            var durations = new ReservationDurations(range);

            var item = durations.First(x => x.Reservation.ReservationID == 833138);

            Assert.AreEqual(TimeSpan.Zero, item.TransferredDuration);
            //Assert.IsTrue(item.TransferredDuration.TotalMinutes > 0);
        }
示例#3
0
        //This handles generation of toolData table since 2011-04-01
        public override void ProcessCleanData(DataTable dtToolDataClean)
        {
            // must be done before any changes are made to the table, this will be used later to calculate transfer durations
            _durations = GetReservationDurations(dtToolDataClean);

            dtToolDataClean.Columns.Add("Uses", typeof(double));
            dtToolDataClean.Columns.Add("TransferredDuration", typeof(double));
            dtToolDataClean.Columns.Add("IsCancelledBeforeAllowedTime", typeof(bool));
            dtToolDataClean.Columns.Add("ChargeBeginDateTime", typeof(DateTime));
            dtToolDataClean.Columns.Add("ChargeEndDateTime", typeof(DateTime));
            dtToolDataClean.Columns.Add("ChargeDuration", typeof(double));

            //handled started separately from unstarted
            double   schedDuration, chargeDuration;
            DateTime beginDateTime, endDateTime, actualBeginDateTime, actualEndDateTime, chargeBeginDateTime, chargeEndDateTime;
            int      toolDataCleanRowCount = dtToolDataClean.Rows.Count;

            //2011-12-05 Get ReservationHistory so we can calculate the max charge time
            //DataTable dtResHistory = GetReservationHistory();

            for (int i = 0; i < toolDataCleanRowCount; i++)
            {
                DataRow dr = dtToolDataClean.Rows[i];

                // ClientID check. dtToolDataClean contains data for all clients even when ClientID > 0 because of transferred duration calculation.
                if (ClientID == 0 || ClientID == dr.Field <int>("ClientID"))
                {
                    //only chargeable activities get written to Tooldata
                    if (IsChargeable(dr))
                    {
                        //this means reservation was started
                        schedDuration       = dr.Field <double>("SchedDuration");
                        beginDateTime       = dr.Field <DateTime>("BeginDateTime");
                        endDateTime         = beginDateTime.AddMinutes(schedDuration); //to prevent auto end's modified end time, which is wrong
                        actualBeginDateTime = dr.Field <DateTime>("ActualBeginDateTime");
                        actualEndDateTime   = dr.Field <DateTime>("ActualEndDateTime");

                        dr["IsCancelledBeforeAllowedTime"] = IsCancelledBeforeAllowedTime(dr);

                        DateTime begDate = (beginDateTime > actualBeginDateTime) ? actualBeginDateTime : beginDateTime;
                        DateTime finDate = (endDateTime > actualEndDateTime) ? endDateTime : actualEndDateTime;

                        chargeBeginDateTime = begDate;
                        chargeEndDateTime   = finDate;

                        chargeDuration = (chargeEndDateTime - chargeBeginDateTime).TotalMinutes;

                        dr["ChargeBeginDateTime"] = begDate;
                        dr["ChargeEndDateTime"]   = finDate;
                        dr["ChargeDuration"]      = chargeDuration;

                        begDate = begDate.Date;

                        //if the finDate is right on the edge, eg. the next day at 00:00am, we don't need to create a new row, because it's not crossing day
                        if (finDate == new DateTime(finDate.Year, finDate.Month, finDate.Day, 0, 0, 0))
                        {
                            finDate = finDate.AddSeconds(-1);
                        }

                        finDate = finDate.Date;

                        if (begDate != finDate)
                        {
                            //handle case where reservation starts and ends on different days
                            double runningOverTime = 0D;
                            int    loopDays        = finDate.Subtract(begDate).Days;
                            for (int j = 0; j <= loopDays; j++)
                            {
                                DateTime bDate = begDate.AddDays(j);
                                DateTime fDate = begDate.AddDays(j + 1);

                                DataRow adr = dtToolDataClean.NewRow();
                                adr.ItemArray = dr.ItemArray; //start by copying everything

                                adr["ChargeBeginDateTime"] = (bDate > chargeBeginDateTime) ? bDate : chargeBeginDateTime;
                                adr["ChargeEndDateTime"]   = (fDate < chargeEndDateTime) ? fDate : chargeEndDateTime;
                                adr["ChargeDuration"]      = (adr.Field <DateTime>("ChargeEndDateTime") - adr.Field <DateTime>("ChargeBeginDateTime")).TotalMinutes;
                                adr["Uses"] = adr.Field <double>("ChargeDuration") / chargeDuration;
                                adr["MaxReservedDuration"] = GetMaxReservedDuration(adr);

                                ////2011-11-08 we have to see of MaxReservedDuration is greater than the ChargeDuration - preventing cases when user shortened the reservation after the 2 hours allowed time
                                //if (!Convert.ToBoolean(adr["IsCancelledBeforeAllowedTime"]))
                                //{
                                //    if (Convert.ToDouble(adr["MaxReservedDuration"]) > Convert.ToDouble(adr["ChargeDuration"]))
                                //        adr["ChargeDuration"] = adr["MaxReservedDuration"];
                                //}

                                //For backward compatibilty reason, I have to repopulate the correct ActDuration as well
                                adr["ActualBeginDateTime"] = (bDate > actualBeginDateTime) ? bDate : actualBeginDateTime;
                                adr["ActualEndDateTime"]   = (fDate < actualEndDateTime) ? fDate : actualEndDateTime;

                                var fixDate = new DateTime(2012, 12, 1);

                                if (Period >= fixDate)
                                {
                                    /*
                                     * [jg 2013-01-24]
                                     * Only do this for periods after 2012-12-01. Before that time the next line of code was missing which caused the 2nd part of a split
                                     * reservation to not be written to the database. In other words the part that happened on the first day of the period. Note: this is
                                     * only for reservations that cross over two periods. For periods before Dec 2012 we are purposefully doing this wrong so that amounts
                                     * billed previously aren't changed retroactively.
                                     *
                                     * [jg 2020-02-04]
                                     * Note that only ChargeBeginDateTime ChargeEndDateTime, ChargeDuration, ActDuration, and SchedDuration are in ToolData.
                                     * Other columns like BeginDateTime, ActualBeginDateTime, etc are set here only because they're used in calculations or
                                     * checks elsewhere.
                                     */
                                    adr["BeginDateTime"] = adr["ActualBeginDateTime"]; //for convenience below when writing new table
                                }

                                // ActDuration will only be for this part of a multi-part reservation because the actuals were modified above
                                adr["ActDuration"] = adr.Field <DateTime>("ActualEndDateTime").Subtract(adr.Field <DateTime>("ActualBeginDateTime")).TotalMinutes;

                                // make sure ActDuration is greater than 0, because if a user finish this reservation on the same day (a cross day reservation originally),
                                // it's possible to have negative ActDuration
                                if (adr.Field <double>("ActDuration") < 0D)
                                {
                                    adr["ActDuration"] = 0D; //since user finished on the previous day, today's reservation actual duration is zero
                                }
                                if (adr.Field <DateTime>("ChargeEndDateTime") > endDateTime)
                                {
                                    adr["OverTime"]  = (adr.Field <DateTime>("ChargeEndDateTime") - endDateTime).TotalMinutes - runningOverTime;
                                    runningOverTime += adr.Field <double>("OverTime");
                                }
                                else
                                {
                                    adr["OverTime"] = 0D;
                                }

                                // [2022-03-25 jg] Rounding to two digits now
                                RoundDouble(adr, "ActDuration");
                                RoundDouble(adr, "ChargeDuration");
                                RoundDouble(adr, "OverTime");
                                RoundDouble(adr, "MaxReservedDuration");

                                dtToolDataClean.Rows.Add(adr); //will add to end

                                //make sure next month's data is not included.
                                if (adr.Field <DateTime>("ChargeBeginDateTime") >= Period.AddMonths(1))
                                {
                                    adr.Delete();
                                }
                            }

                            dr.Delete(); //remove original, multi-day row
                        }
                        else
                        {
                            dr["Uses"] = 1D;
                            if (!dr.Field <bool>("IsStarted"))
                            {
                                dr["ActDuration"] = dr["SchedDuration"];
                            }

                            //2011-11-08 we have to see of MaxReservedDuration is greater than the ChargeDuration - preventing cases when user shortened the reservation after the 2 hours allowed time
                            if (!dr.Field <bool>("IsCancelledBeforeAllowedTime"))
                            {
                                //this will return a list of reservation changigin history ordered by ModifiedDateTime
                                DataRow[] drsResHistory = ReservationHistoryTable.Select($"ReservationID = {dr["ReservationID"]}");

                                //must be at least two rows (becuase I inlcude Insert event as well, when reservation is firstly created)
                                if (drsResHistory.Length > 1)
                                {
                                    DataRow  drPrevious = null;
                                    double   maxResTimeAfterTwoHoursLimit = 0.0;
                                    double   currentResTime;
                                    bool     flagtemp = false;
                                    DateTime beginTimeTemp, endTimeTemp;

                                    foreach (DataRow drResHist in drsResHistory)
                                    {
                                        //the idea here is compare every reservation change and find out the max reservation time
                                        if (drResHist.Field <int>("BeforeMinutes") <= 120)
                                        {
                                            flagtemp       = true;
                                            beginTimeTemp  = drResHist.Field <DateTime>("BeginDateTime");
                                            endTimeTemp    = drResHist.Field <DateTime>("EndDateTime");
                                            currentResTime = (endTimeTemp - beginTimeTemp).TotalMinutes;

                                            if (currentResTime > maxResTimeAfterTwoHoursLimit)
                                            {
                                                maxResTimeAfterTwoHoursLimit = currentResTime;
                                            }
                                        }

                                        if (!flagtemp)
                                        {
                                            //We need to track the last change of reservation right before the 2 hours limit, this is our true chargeTime
                                            drPrevious = drResHist;
                                        }
                                    }

                                    if (drPrevious != null)
                                    {
                                        beginTimeTemp  = drPrevious.Field <DateTime>("BeginDateTime");
                                        endTimeTemp    = drPrevious.Field <DateTime>("EndDateTime");
                                        currentResTime = (endTimeTemp - beginTimeTemp).TotalMinutes;

                                        if (currentResTime > maxResTimeAfterTwoHoursLimit)
                                        {
                                            maxResTimeAfterTwoHoursLimit = currentResTime;
                                        }
                                    }

                                    //Lastly, make sure we charge the max time - please note that ChargeDuration could still be higher than maxResTimeAfterTwoHoursLimit because of actual tool usage time
                                    if (maxResTimeAfterTwoHoursLimit > dr.Field <double>("ChargeDuration"))
                                    {
                                        dr["ChargeDuration"] = maxResTimeAfterTwoHoursLimit;
                                    }
                                }
                            }

                            // [2022-03-25 jg] Rounding to two digits now
                            RoundDouble(dr, "ActDuration");
                            RoundDouble(dr, "ChargeDuration");
                            RoundDouble(dr, "OverTime");
                            RoundDouble(dr, "MaxReservedDuration");
                        }
                    }
                    else
                    {
                        dr.Delete(); //not chargeable, so remove
                    }
                }
            }
        }