public void Split_SevenAmAndFivePm_Successful()
        {
            var db          = new SqlContext();
            var currentUser = db.Users.Find(1);

            var service = new PunchService();
            var inAt    = new DateTime(2020, 1, 1);
            var outAt   = new DateTime(2020, 1, 31);

            var originalPunches = GetPunches()
                                  .OrderBy(p => p.UserId)
                                  .ThenBy(p => p.InAt)
                                  .ToList();

            // Assert original count
            Assert.AreEqual(19, originalPunches.Count);

            // Split at midnight, must always do this first
            var splitMidnight = service.SplitAtMidnight(originalPunches, currentUser);

            // Assert that there are more punches now
            Assert.AreEqual(21, splitMidnight.Count);

            // Split again at 7am and assert that there are yet more punches
            var splitSevenAm = service.SplitAtMinute(splitMidnight, currentUser, minuteOfDay: 420); // Split at 7am = 420 minutes

            // Assert that there are more punches now
            Assert.AreEqual(22, splitSevenAm.Count);

            // Finally split at 5pm and assert that there are even more punches
            var splitFivePm = service.SplitAtMinute(splitSevenAm, currentUser, minuteOfDay: 1020); // Split at 5pm = 1020 minutes

            // Assert that there are more punches now
            Assert.AreEqual(34, splitFivePm.Count);
        }
        public void Populate_PayrollDayOfWeekOvertime_Successful()
        {
            var db          = new SqlContext();
            var currentUser = db.Users.Find(1);

            var service = new PunchService();
            var inAt    = new DateTime(2020, 1, 1);
            var outAt   = new DateTime(2020, 1, 31);

            var originalPunches = GetPunches()
                                  .OrderBy(p => p.UserId)
                                  .ThenBy(p => p.InAt)
                                  .ToList();

            // Splitting happens automatically during populate below

            var populateOptions = new PopulateRateOptions();

            populateOptions.InAt    = new DateTime(2020, 1, 1);
            populateOptions.OutAt   = new DateTime(2020, 1, 31);
            populateOptions.Options = new PopulateRateOption[]
            {
                // This option should populate anything
                // on Saturday with the overtime rate
                new PopulateRateOption()
                {
                    Type                   = "dayofweek",
                    DayOfWeek              = "Saturday",
                    BasePayrollRateId      = 1,
                    AlternatePayrollRateId = 2,
                    Order                  = 0
                }
            };

            var populatedPunches = service.Populate(populateOptions, originalPunches, currentUser);

            // Assert the number of punches after automatic split
            Assert.AreEqual(21, populatedPunches.Count);

            foreach (var punch in populatedPunches)
            {
                if (punch.InAt.DayOfWeek == DayOfWeek.Saturday)
                {
                    Assert.IsTrue(punch.PayrollRateId == 2);
                }
                else
                {
                    Assert.IsTrue(punch.PayrollRateId == 1);
                }
            }
        }
Example #3
0
        public JsonResult Approve(FormCollection col)
        {
            Punch punch = new Punch();

            int pId;

            int.TryParse(col.Get("models[0][punchId]"), out pId);
            punch.Id = pId;

            int uId;

            int.TryParse(col.Get("models[0][userId]"), out uId);
            punch.UserId = uId;

            punch.Comments = col.Get("models[0][comments]");

            bool approved;

            bool.TryParse(col.Get("models[0][isManagerAccepted]"), out approved);
            punch.Approved = approved;

            UserService ub             = new UserService();
            string      userTimeZoneId = ub.GetTimeZoneOfUser(uId);

            //var ci = new System.Globalization.CultureInfo("en-us");
            punch.PunchIn  = Parse.ToUtcTime(jsOffsetTime: col.Get("models[0][punchIn]"), timeZoneId: userTimeZoneId);
            punch.PunchOut = Parse.ToUtcTime(jsOffsetTime: col.Get("models[0][punchOut]"), timeZoneId: userTimeZoneId);

            punch.PunchDate = Parse.ToDate(col.Get("models[0][punchDate]"));
            punch.PunchDate = new DateTime(punch.PunchDate.Year, punch.PunchDate.Month, punch.PunchDate.Day,
                                           punch.PunchIn.Hours, punch.PunchIn.Minutes, punch.PunchIn.Seconds);
            punch.PunchDate = TimeZoneInfo.ConvertTimeToUtc(punch.PunchDate,
                                                            TimeZoneInfo.FindSystemTimeZoneById(OperatingUser.RegisteredTimeZone));

            bool isApproved = false;

            if (Get.AdminUsers().Any(y => OperatingUser.UserTypeId.Equals(y)))
            {
                PunchService pb = new PunchService();
                isApproved = pb.Approve(punch: punch, opUserId: OperatingUser.Uid);
            }
            //return Json(new { isSuccess = isApproved });
            return(Json(isApproved));
        }
        public void Split_Midnight_Successful()
        {
            var db          = new SqlContext();
            var currentUser = db.Users.Find(1);

            var service = new PunchService();

            var originalPunches = GetPunches()
                                  .OrderBy(p => p.UserId)
                                  .ThenBy(p => p.InAt)
                                  .ToList();

            // Assert original count
            Assert.AreEqual(19, originalPunches.Count);

            // Split at midnight
            var splitMidnight = service.SplitAtMidnight(originalPunches, currentUser);

            // Assert that there are more punches now
            Assert.AreEqual(21, splitMidnight.Count);
        }
        public PdfPTable PhotoLogView(Inspection inspectionObject)
        {
            PdfPTable ParentTable = new PdfPTable(4);

            ParentTable.TotalWidth  = PageSize.A4.Width - 20;
            ParentTable.LockedWidth = true;
            //Header of Report
            PdfPCell PhotoReportHeader = new PdfPCell(new Phrase("Location Identification", headerFont));

            PhotoReportHeader.BackgroundColor     = Color.RED;
            PhotoReportHeader.FixedHeight         = 30;
            PhotoReportHeader.BorderWidth         = 1;
            PhotoReportHeader.HorizontalAlignment = PdfCell.ALIGN_CENTER;
            PhotoReportHeader.BorderColor         = Color.GRAY;
            PhotoReportHeader.Colspan             = 4;
            ParentTable.AddCell(PhotoReportHeader);
            foreach (var LocationImage in inspectionObject.locationIDImages)
            {
                if (LocationImage != null)
                {
                    iTextSharp.text.Image image = Image.GetInstance(LocationImage);
                    if (null != image)
                    {
                        image.ScaleAbsolute(574.5f, 300f);
                        PdfPCell cellPhotoAdd1;
                        cellPhotoAdd1                 = new PdfPCell(image);
                        cellPhotoAdd1.Colspan         = 4;
                        cellPhotoAdd1.BorderWidthLeft = 0;
                        cellPhotoAdd1.FixedHeight     = 300;
                        cellPhotoAdd1.BorderColor     = Color.GRAY;
                        ParentTable.AddCell(cellPhotoAdd1);
                    }
                }
                PdfPCell Blankcell1 = new PdfPCell(new Phrase(" ", headerFont));
                Blankcell1.FixedHeight = 10;
                Blankcell1.BorderWidth = 0;
                Blankcell1.Colspan     = 4;
                ParentTable.AddCell(Blankcell1);

                if (ParentTable.Rows.Count > RowLimit)
                {
                    break;
                }
            }
            PdfPCell Blankcell = new PdfPCell(new Phrase("Inspection Photos", headerFont));

            Blankcell.FixedHeight = 30;
            Blankcell.BorderWidth = 0;
            Blankcell.Colspan     = 4;
            ParentTable.AddCell(Blankcell);

            foreach (var seq in inspectionObject.sequences)
            {
                if (ParentTable.Rows.Count > RowLimit)
                {
                    break;
                }

                if (seq.Levels != null)
                {
                    foreach (var lvl in seq.Levels)
                    {
                        if (ParentTable.Rows.Count > RowLimit)
                        {
                            break;
                        }

                        if (lvl.Spaces != null && lvl.Spaces.Count > 0)
                        {
                            foreach (var spc in lvl.Spaces)
                            {
                                if (ParentTable.Rows.Count > RowLimit)
                                {
                                    break;
                                }
                                if (spc.Options != null && spc.isSelected)
                                {
                                    foreach (var opt in spc.Options)
                                    {
                                        if (opt.ID == Constants.GUIDED_OPTIONID)
                                        {
                                            if (opt.checkListItems != null && opt.checkListItems.Count > 0)
                                            {
                                                bool RepeatHeading = false;
                                                foreach (var checkList in opt.checkListItems)
                                                {
                                                    if (ParentTable.Rows.Count > RowLimit)
                                                    {
                                                        break;
                                                    }
                                                    if (checkList.photos != null && checkList.photos.Count > 0)
                                                    {
                                                        if (!RepeatHeading)
                                                        {
                                                            PdfPCell cellSequence = new PdfPCell(
                                                                new Phrase("" + seq.name + " - " + lvl.name + " - " + spc.name + " - " + opt.name, headerFont));
                                                            cellSequence.HorizontalAlignment = PdfCell.ALIGN_CENTER;
                                                            cellSequence.BorderWidthTop      = 1;
                                                            cellSequence.BorderWidthRight    = 1;
                                                            cellSequence.BorderWidthBottom   = 0;
                                                            cellSequence.BorderWidthLeft     = 0;
                                                            cellSequence.BackgroundColor     = Color.RED;
                                                            cellSequence.Colspan             = 4;
                                                            ParentTable.AddCell(cellSequence);
                                                            RepeatHeading = true;
                                                        }

                                                        //PdfPTable guidedDetails = new PdfPTable (1);
                                                        PdfPCell guidedItem = new PdfPCell(
                                                            new Phrase("" + checkList.description, headerFont));
                                                        //guidedItem.BorderWidth = 0;
                                                        guidedItem.BorderWidthTop    = 1;
                                                        guidedItem.BorderWidthRight  = 0;
                                                        guidedItem.BorderWidthBottom = 1;
                                                        guidedItem.BorderWidthLeft   = 1;

                                                        guidedItem.Colspan = 1;
                                                        //guidedDetails.AddCell (guidedItem);
                                                        PdfPCell cellPhotoAdd;
                                                        foreach (var photo in checkList.photos)
                                                        {
                                                            if (ParentTable.Rows.Count > RowLimit)
                                                            {
                                                                break;
                                                            }
                                                            iTextSharp.text.Image image = Image.GetInstance(photo);
                                                            if (null != image)
                                                            {
                                                                image.ScaleAbsolute(430f, 370f);
                                                                cellPhotoAdd                   = new PdfPCell(image);
                                                                cellPhotoAdd.PaddingLeft       = 1;
                                                                cellPhotoAdd.PaddingTop        = 1;
                                                                cellPhotoAdd.Colspan           = 3;
                                                                cellPhotoAdd.PaddingBottom     = 1;
                                                                cellPhotoAdd.BorderWidthTop    = 1;
                                                                cellPhotoAdd.BorderWidthRight  = 1;
                                                                cellPhotoAdd.BorderWidthBottom = 1;
                                                                cellPhotoAdd.BorderWidthLeft   = 1;
                                                                cellPhotoAdd.BorderColor       = Color.GRAY;
                                                                ParentTable.AddCell(guidedItem);
                                                                ParentTable.AddCell(cellPhotoAdd);
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        else
                                        if (opt.photos != null && opt.photos.Count > 0)
                                        {
                                            bool RepeatHeader = false;
                                            foreach (var photo in opt.photos)
                                            {
                                                if (ParentTable.Rows.Count > RowLimit)
                                                {
                                                    break;
                                                }
                                                iTextSharp.text.Image image = Image.GetInstance(photo.Image);
                                                if (null != image)
                                                {
                                                    if (!RepeatHeader)
                                                    {
                                                        PdfPCell cellSequence = new PdfPCell(
                                                            new Phrase("" + seq.name + " - " + lvl.name + " - " + spc.name + " - " + opt.name, headerFont));
                                                        cellSequence.HorizontalAlignment = PdfCell.ALIGN_CENTER;
                                                        cellSequence.BorderWidth         = 0;
                                                        cellSequence.BackgroundColor     = Color.RED;
                                                        cellSequence.Colspan             = 4;
                                                        ParentTable.AddCell(cellSequence);
                                                        RepeatHeader = true;
                                                    }

                                                    PdfPCell cellPhotoAdd;
                                                    image.ScaleAbsolute(574.5f, 300f);
                                                    cellPhotoAdd = new PdfPCell(image);
                                                    cellPhotoAdd.BorderWidthLeft = 0;
                                                    cellPhotoAdd.Colspan         = 4;
                                                    cellPhotoAdd.BorderColor     = Color.GRAY;
                                                    cellPhotoAdd.FixedHeight     = 300;
                                                    ParentTable.AddCell(cellPhotoAdd);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        else if (lvl.Options != null)
                        {
                            if (ParentTable.Rows.Count > RowLimit)
                            {
                                break;
                            }
                            foreach (var opt in lvl.Options)
                            {
                                if (ParentTable.Rows.Count > RowLimit)
                                {
                                    break;
                                }
                                if (opt.photos != null && opt.photos.Count > 0)
                                {
                                    bool RepeatHeader = false;
                                    if (opt.photos != null)
                                    {
                                        foreach (var photo in opt.photos)
                                        {
                                            if (ParentTable.Rows.Count > RowLimit)
                                            {
                                                break;
                                            }
                                            iTextSharp.text.Image image = Image.GetInstance(photo.Image);
                                            if (null != image)
                                            {
                                                if (!RepeatHeader)
                                                {
                                                    PdfPCell cellSequence = new PdfPCell(
                                                        new Phrase("" + seq.name + " - " + "" + lvl.name + " - " + opt.name, headerFont));
                                                    cellSequence.HorizontalAlignment = PdfCell.ALIGN_CENTER;
                                                    cellSequence.BorderWidth         = 0;
                                                    cellSequence.BackgroundColor     = Color.RED;
                                                    cellSequence.Colspan             = 4;
                                                    ParentTable.AddCell(cellSequence);
                                                    RepeatHeader = true;
                                                }
                                                PdfPCell cellPhotoAdd;

                                                image.ScaleAbsolute(574.5f, 300f);
                                                cellPhotoAdd = new PdfPCell(image);
                                                cellPhotoAdd.BorderWidthLeft = 0;
                                                cellPhotoAdd.Colspan         = 4;
                                                cellPhotoAdd.BorderColor     = Color.GRAY;
                                                cellPhotoAdd.FixedHeight     = 300;
                                                ParentTable.AddCell(cellPhotoAdd);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                else if (seq.Options != null)
                {
                    if (ParentTable.Rows.Count > RowLimit)
                    {
                        break;
                    }
                    foreach (var opt in seq.Options)
                    {
                        if (ParentTable.Rows.Count > 10)
                        {
                            break;
                        }
                        if (opt.photos != null && opt.photos.Count > RowLimit)
                        {
                            bool RepeatHeader = false;
                            if (opt.photos != null)
                            {
                                foreach (var photo in opt.photos)
                                {
                                    if (ParentTable.Rows.Count > RowLimit)
                                    {
                                        break;
                                    }
                                    iTextSharp.text.Image image = Image.GetInstance(photo.Image);
                                    if (null != image)
                                    {
                                        if (!RepeatHeader)
                                        {
                                            PdfPCell cellSequence = new PdfPCell(
                                                new Phrase("" + seq.name + " - " + opt.name, headerFont));
                                            cellSequence.HorizontalAlignment = PdfCell.ALIGN_CENTER;
                                            cellSequence.BorderWidth         = 0;
                                            cellSequence.BackgroundColor     = Color.RED;
                                            cellSequence.Colspan             = 4;
                                            ParentTable.AddCell(cellSequence);
                                            RepeatHeader = true;
                                        }
                                        PdfPCell cellPhotoAdd;
                                        image.ScaleAbsolute(574.5f, 300f);
                                        cellPhotoAdd = new PdfPCell(image);
                                        cellPhotoAdd.BorderWidthLeft = 0;
                                        cellPhotoAdd.Colspan         = 4;
                                        cellPhotoAdd.BorderColor     = Color.GRAY;
                                        cellPhotoAdd.FixedHeight     = 300;
                                        ParentTable.AddCell(cellPhotoAdd);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            PdfPCell Blankcel1 = new PdfPCell(new Phrase(" ", headerFont));

            Blankcel1.FixedHeight = 30;
            Blankcel1.BorderWidth = 0;
            Blankcel1.Colspan     = 4;
            ParentTable.AddCell(Blankcel1);

            PunchService PunchTab   = new PunchService(AppDelegate.DatabaseContext);
            var          punchItems = PunchTab.GetPunchList(AppDelegate.DatabaseContext, inspectionObject.inspectionID, inspectionObject.projectID);

            if (punchItems != null)
            {
                int count = 0;
                if (punchItems != null && punchItems.Count > 0)
                {
                    bool RepeatHeader = false;
                    foreach (var Punchpic in punchItems)
                    {
                        if (ParentTable.Rows.Count > RowLimit)
                        {
                            break;
                        }
                        count++;
                        var PunchImage = DAL.DO.PunchListImageDO.getPunchImageList(AppDelegate.DatabaseContext, Punchpic.PunchID);
                        if (PunchImage != null && PunchImage.Count > 0)
                        {
                            foreach (var imagecollection in PunchImage)
                            {
                                if (ParentTable.Rows.Count > RowLimit)
                                {
                                    break;
                                }
                                PdfPCell PunchItem = new PdfPCell();

                                PunchItem.AddElement(new Phrase("Item " + count, headerFont));
                                PunchItem.AddElement(new Phrase(Punchpic.punchDescription, cellContentFont));
                                //PunchItem.BorderWidth = 0;
                                PunchItem.BorderWidthTop    = 1;
                                PunchItem.BorderWidthRight  = 0;
                                PunchItem.BorderWidthBottom = 1;
                                PunchItem.BorderWidthLeft   = 1;
                                PdfPCell punchHeading = new PdfPCell(
                                    new Phrase(Punchpic.punchDescription, cellContentFont));
                                punchHeading.FixedHeight = 80;
                                punchHeading.BorderWidth = 0;
                                PunchItem.Colspan        = 1;
                                punchHeading.BorderColor = Color.GRAY;

                                //adding the cell for adding photo
                                PdfPCell cellPhotoAdd;
                                if (imagecollection != null)
                                {
                                    if (imagecollection.PunchListImage != null)
                                    {
                                        if (!RepeatHeader)
                                        {
                                            RepeatHeader = true;
                                            string punchListHeading = "Non Conformance Items";
                                            if (inspectionObject.inspectionID == Constants.FINAL_INSPECTIONID)
                                            {
                                                punchListHeading = "Punch List Items";
                                            }

                                            PdfPCell HeadingPunch = new PdfPCell(new Phrase(punchListHeading, headerFont));
                                            HeadingPunch.BackgroundColor     = Color.RED;
                                            HeadingPunch.FixedHeight         = 30;
                                            HeadingPunch.BorderWidth         = 0;
                                            HeadingPunch.HorizontalAlignment = PdfCell.ALIGN_CENTER;
                                            HeadingPunch.Colspan             = 4;
                                            ParentTable.AddCell(HeadingPunch);
                                        }
                                        ParentTable.AddCell(PunchItem);


                                        iTextSharp.text.Image image1 = Image.GetInstance(imagecollection.PunchListImage);
                                        if (null != imagecollection)
                                        {
                                            image1.ScaleAbsolute(430f, 370f);

                                            cellPhotoAdd = new PdfPCell(image1);
                                            cellPhotoAdd.BorderWidthLeft = 0;


                                            cellPhotoAdd.PaddingLeft = 1;
                                            cellPhotoAdd.PaddingTop  = 1;
                                            cellPhotoAdd.Colspan     = 3;
                                            //cellPhotoAdd.Rowspan = 2;
                                            cellPhotoAdd.PaddingBottom = 1;

                                            cellPhotoAdd.BorderColor = Color.GRAY;
                                            ParentTable.AddCell(cellPhotoAdd);
                                        }
                                    }
                                }

                                //ParentTable.AddCell (photoLogTable);
                            }
                        }
                    }
                }
            }
            return(ParentTable);
        }
        // POST: odata/Commits
        public IHttpActionResult Post(Commit commit)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            var currentUser = CurrentUser();

            // Ensure that user is authorized.
            if (!currentUser.CanCreateLocks)
            {
                return(StatusCode(HttpStatusCode.Forbidden));
            }

            using (var transaction = db.Database.BeginTransaction())
            {
                try
                {
                    var inAt  = new DateTime(commit.InAt.Year, commit.InAt.Month, commit.InAt.Day, 0, 0, 0, DateTimeKind.Unspecified);
                    var outAt = new DateTime(commit.OutAt.Year, commit.OutAt.Month, commit.OutAt.Day, 23, 59, 59, DateTimeKind.Unspecified);

                    // Ensure that no two commits overlap
                    var overlap = db.Commits
                                  .Where(c => c.OrganizationId == commit.OrganizationId)
                                  .Where(c => (inAt < c.OutAt) && (c.InAt < outAt))
                                  .FirstOrDefault();
                    if (overlap != null)
                    {
                        return(BadRequest(string.Format(
                                              "The commit overlaps another commit: {0} thru {1}",
                                              overlap.InAt.ToString("yyyy-MM-dd"),
                                              overlap.OutAt.ToString("yyyy-MM-dd")
                                              )));
                    }

                    // Auto-generated
                    commit.CreatedAt      = DateTime.UtcNow;
                    commit.Guid           = Guid.NewGuid();
                    commit.OrganizationId = currentUser.OrganizationId;
                    commit.UserId         = currentUser.Id;
                    commit.InAt           = inAt;
                    commit.OutAt          = outAt;

                    db.Commits.Add(commit);

                    db.SaveChanges();

                    // Split the punches at midnight.
                    var   service = new PunchService();
                    int[] userIds = db.Users
                                    .Where(u => u.OrganizationId == currentUser.OrganizationId)
                                    .Select(u => u.Id)
                                    .ToArray();
                    var originalPunchesTracked = db.Punches
                                                 .Where(p => userIds.Contains(p.UserId))
                                                 .Where(p => p.InAt >= inAt && p.OutAt.HasValue && p.OutAt.Value <= outAt)
                                                 .Where(p => !p.CommitId.HasValue); // Only uncommited punches
                    var originalPunchesNotTracked = originalPunchesTracked
                                                    .AsNoTracking()                 // Will be manipulated in memory
                                                    .ToList();
                    var splitPunches = service.SplitAtMidnight(originalPunchesNotTracked, currentUser);

                    // Delete the old punches and save the new ones.
                    db.Punches.RemoveRange(originalPunchesTracked);
                    db.SaveChanges();

                    // Save the commit id with the new punches.
                    foreach (var punch in splitPunches)
                    {
                        punch.CommitId = commit.Id;
                    }
                    commit.PunchCount = splitPunches.Count();

                    db.Punches.AddRange(splitPunches);
                    db.SaveChanges();

                    transaction.Commit();

                    return(Created(commit));
                }
                catch (Exception ex)
                {
                    transaction.Rollback();

                    return(BadRequest(ex.ToString()));
                }
            }
        }
        public void Populate_PayrollFourHoursPerDayOvertime_Successful()
        {
            var db          = new SqlContext();
            var currentUser = db.Users.Find(1);

            var service = new PunchService();
            var inAt    = new DateTime(2020, 1, 1);
            var outAt   = new DateTime(2020, 1, 31);

            var originalPunches = GetPunches()
                                  .OrderBy(p => p.UserId)
                                  .ThenBy(p => p.InAt)
                                  .ToList();

            // Splitting happens automatically during populate below

            var populateOptions = new PopulateRateOptions();

            populateOptions.InAt    = new DateTime(2020, 1, 1);
            populateOptions.OutAt   = new DateTime(2020, 1, 31);
            populateOptions.Options = new PopulateRateOption[]
            {
                // This option should populate anything
                // after 4 hours per day with the overtime rate
                new PopulateRateOption()
                {
                    Type                   = "count",
                    CountScope             = "day",
                    CountMinute            = 240,
                    BasePayrollRateId      = 1,
                    AlternatePayrollRateId = 2,
                    Order                  = 0
                }
            };

            var populatedPunches = service.Populate(populateOptions, originalPunches, currentUser);

            // Assert the number of punches after automatic split
            Assert.AreEqual(38, populatedPunches.Count);

            var userIds = populatedPunches.GroupBy(p => p.UserId).Select(g => g.Key);

            foreach (var userId in userIds)
            {
                // Assert that punches over 4 hours per day (240 minutes) are overtime
                var filtered = populatedPunches.Where(p => p.UserId == userId);
                var dates    = filtered
                               .GroupBy(p => p.InAt.Date)
                               .Select(g => new {
                    Date = g.Key
                })
                               .ToList();

                foreach (var date in dates)
                {
                    var punchesForDay = filtered
                                        .Where(p => p.InAt.Date == date.Date)
                                        .ToList();
                    var count = 0;
                    foreach (var punch in punchesForDay)
                    {
                        count += punch.Minutes;
                        if (count <= 240)
                        {
                            Assert.IsTrue(punch.PayrollRateId == 1);
                        }
                        else
                        {
                            Assert.IsTrue(punch.PayrollRateId == 2);
                        }
                    }
                }
            }
        }
        public void Populate_PayrollBeforeSevenAmAfterFivePmAsOvertime_Successful()
        {
            var db          = new SqlContext();
            var currentUser = db.Users.Find(1);

            var service = new PunchService();
            var inAt    = new DateTime(2020, 1, 1);
            var outAt   = new DateTime(2020, 1, 31);

            var originalPunches = GetPunches()
                                  .OrderBy(p => p.UserId)
                                  .ThenBy(p => p.InAt)
                                  .ToList();

            // Splitting happens automatically during populate below

            var populateOptions = new PopulateRateOptions();

            populateOptions.InAt    = new DateTime(2020, 1, 1);
            populateOptions.OutAt   = new DateTime(2020, 1, 31);
            populateOptions.Options = new PopulateRateOption[]
            {
                // This option should populate anything
                // from midnight through 7am with the overtime rate
                new PopulateRateOption()
                {
                    Type                   = "range",
                    RangeDirection         = "before",
                    RangeMinutes           = 420,
                    BasePayrollRateId      = 1,
                    AlternatePayrollRateId = 2,
                    Order                  = 0
                },

                // This option should populate anything
                // from 5pm through midnight with overtime rate
                new PopulateRateOption()
                {
                    Type                   = "range",
                    RangeDirection         = "after",
                    RangeMinutes           = 1020,
                    BasePayrollRateId      = 1,
                    AlternatePayrollRateId = 2,
                    Order                  = 1
                }
            };

            var populatedPunches = service.Populate(populateOptions, originalPunches, currentUser);

            // Assert the number of punches after automatic split
            Assert.AreEqual(34, populatedPunches.Count);

            foreach (var punch in populatedPunches.Where(p => p.UserId == 3))
            {
                var midnight     = new DateTime(punch.InAt.Year, punch.InAt.Month, punch.InAt.Day, 0, 0, 0, 0);
                var spanInAt     = punch.InAt.Subtract(midnight);
                var minuteOfInAt = spanInAt.TotalMinutes;

                switch (punch.PayrollRateId)
                {
                case 1:
                    // Should be regular
                    Assert.IsTrue(minuteOfInAt >= 420 || minuteOfInAt <= 1020);
                    break;

                case 2:
                    // Should be overtime
                    Assert.IsTrue(minuteOfInAt <= 420 || minuteOfInAt >= 1020);
                    break;
                }
            }
        }
        public IHttpActionResult PopulateRates(ODataActionParameters parameters)
        {
            telemetryClient.TrackEvent("Populate:Requested");

            using (var transaction = db.Database.BeginTransaction())
            {
                try
                {
                    var populateOptions = parameters["Options"] as PopulateRateOptions;
                    var currentUser     = CurrentUser();
                    var nowUtc          = DateTime.UtcNow;
                    var inAt            = new DateTime(populateOptions.InAt.Year, populateOptions.InAt.Month, populateOptions.InAt.Day, 0, 0, 0, 0, DateTimeKind.Unspecified);
                    var outAt           = new DateTime(populateOptions.OutAt.Year, populateOptions.OutAt.Month, populateOptions.OutAt.Day, 23, 59, 0, 0, DateTimeKind.Unspecified);
                    populateOptions.InAt  = inAt;
                    populateOptions.OutAt = outAt;
                    int[] userIds = db.Users
                                    .Where(u => u.OrganizationId == currentUser.OrganizationId)
                                    .Select(u => u.Id)
                                    .ToArray();
                    var originalPunchesTracked = db.Punches
                                                 .Where(p => userIds.Contains(p.UserId))
                                                 .Where(p => p.OutAt.HasValue)
                                                 .Where(p => DbFunctions.TruncateTime(p.InAt) >= inAt.Date)
                                                 .Where(p => DbFunctions.TruncateTime(p.InAt) <= outAt.Date)
                                                 .Where(p => !p.CommitId.HasValue); // Only unlocked punches
                    var originalPunchesNotTracked = originalPunchesTracked
                                                    .AsNoTracking()                 // Will be manipulated in memory
                                                    .ToList();

                    telemetryClient.TrackEvent("Populate:Starting", new Dictionary <string, string>()
                    {
                        { "InAt", inAt.ToString("G") },
                        { "OutAt", outAt.ToString("G") },
                        { "UserId", currentUser.Id.ToString() },
                        { "OrganizationId", currentUser.OrganizationId.ToString() }
                    });

                    // Save what the punches looked like before.
                    var before = originalPunchesNotTracked;

                    var populatedPunches = new PunchService().Populate(populateOptions, originalPunchesNotTracked, currentUser);

                    // Save what the punches look like after.
                    var after = populatedPunches;

                    // Delete the old punches and save the new ones.
                    db.Punches.RemoveRange(originalPunchesTracked);
                    db.SaveChanges();

                    db.Punches.AddRange(populatedPunches);
                    db.SaveChanges();

                    try
                    {
                        // Attempt to save the backup of the punches on Azure.
                        var backup = new
                        {
                            Before = before,
                            After  = after
                        };
                        var json = JsonConvert.SerializeObject(backup);

                        // Prepare to upload the backup.
                        var azureConnectionString             = ConfigurationManager.AppSettings["PunchBackupsAzureStorageConnectionString"].ToString();
                        BlobServiceClient   blobServiceClient = new BlobServiceClient(azureConnectionString);
                        BlobContainerClient containerClient   = blobServiceClient.GetBlobContainerClient("populate-punch-backups");
                        BlobClient          blobClient        = containerClient.GetBlobClient($"{currentUser.OrganizationId}/{nowUtc.Ticks}.json");

                        // Perform the upload.
                        using (var stream = new MemoryStream(Encoding.Default.GetBytes(json), false))
                        {
                            blobClient.Upload(stream);
                        }
                    }
                    catch (Exception ex)
                    {
                        telemetryClient.TrackException(ex);
                    }

                    telemetryClient.TrackEvent("Populate:Succeeded");
                    telemetryClient.Flush();

                    transaction.Commit();

                    return(Ok());
                }
                catch (Exception ex)
                {
                    telemetryClient.TrackEvent("Populate:Failed");
                    telemetryClient.TrackException(ex);
                    telemetryClient.Flush();

                    transaction.Rollback();

                    return(BadRequest(ex.ToString()));
                }
            }
        }
Example #10
0
        /// <summary>
        /// Syncs the data.
        /// </summary>
        public void syncData()
        {
            lock (syncLock)
            {
                try
                {
                    if (!IsSyncProgress)
                    {
                        IsSyncProgress = true;

                        if (syncProgress != null)
                        {
                            syncProgress(true);
                        }
                        //Check if there are finished inspections
                        InspectionTransactionService transSer = new InspectionTransactionService(conn);
                        OptionTransactionService     OTS      = new OptionTransactionService(conn);
                        //int count = 0;
                        var                     finishedInspectionsQry = transSer.GetInspectionTransactions().Where(i => i.IsFinalise > 0);    // && (i.pass.ToLower () == "pass" || i.pass.ToLower () == "fail"));
                        UserService             userService            = new UserService(conn);
                        User                    user            = userService.GetUser();
                        IServices               service         = new Services();
                        InspectionDetailService ids             = new InspectionDetailService(conn);
                        OptionImageService      optImageservice = new OptionImageService(conn);
                        PunchService            pushservice     = new PunchService(conn);
                        DocViewService          docService      = new DocViewService(conn);
                        NotificationRepository  notificationRep = new NotificationRepository(conn);

                        if (finishedInspectionsQry.Any())
                        {
                            List <Inspection> finishedInspections = finishedInspectionsQry.Where(i => i.IsFinalise > 0).ToList();
                            if (finishedInspections.Count > 0)
                            {
                                int reportCount    = 0;
                                int punchListCount = 0;

                                Debug.WriteLine("sync thread started");

                                foreach (var inspection in finishedInspections)
                                {
                                    if (inspection == null)
                                    {
                                        Debug.WriteLine(string.Format("inspection is null"));
                                    }

                                    if (!inspection.isInspectionSynced)
                                    {
                                        if (notifiy != null)
                                        {
                                            notifiy(new notificationEventArgs
                                            {
                                                current = new Notifications
                                                {
                                                    notificationTypeID = inspection.projectID,
                                                    notificationType   = "Inspection",
                                                },
                                                isSyncCompleted = false,
                                            });
                                        }

                                        Model.ServiceModel.InspectionResults req = new Model.ServiceModel.InspectionResults();
                                        req.token       = user.Token;
                                        req.inspections = new List <Model.ServiceModel.InspectionResult>();
                                        Model.Inspection inspectionSer = ids.GetInspectionDetail(inspection, true);


                                        if (inspectionSer != null)
                                        {
                                            var insp = inspectionSer.getServiceModel();



                                            req.inspections.Add(insp);

                                            Model.ServiceModel.InspectionResultsAck inspectinPushRes = service.PushInspections(req);


                                            if (inspectinPushRes.result != null && inspectinPushRes.result.code == 0)
                                            {
                                                int inspectionTransactionID = 0;
                                                InspectionTransactionService insTransService = new InspectionTransactionService(conn);
                                                inspectionTransactionID = insTransService.GetInspectionTransactionID(inspection.projectID, inspection.inspectionID);

                                                //Loaction Image Delete after sync
                                                DAL.LocationImageDo.DeleteImage(conn, inspectionTransactionID);

                                                //Inspection Document Delete after sync
                                                var documents = docService.GetDocumentsForSync(inspection.inspectionID, inspection.projectID);
                                                if (documents != null && documents.Count > 0)
                                                {
                                                    if (DocumentDeleted != null)
                                                    {
                                                        DocumentDeleted(this, new DocumentDeletionEventArgs()
                                                        {
                                                            documentList = documents
                                                        });
                                                    }
                                                    docService.DeleteDocumentItemsForSync(inspection.inspectionID, inspection.projectID);
                                                }

                                                /// Punch List Delete for only final Inspection
                                                if (inspection.inspectionID == BALConstant.FINAL_INSPECTIONID)
                                                {
                                                    List <Punch> punchList = pushservice.getPunchList(inspection.inspectionID, inspection.projectID);
                                                    foreach (var punch in punchList)
                                                    {
                                                        PunchListImageDO.DeletePunchImageList(conn, punch.PunchID);
                                                        OptionPunchDO.DeleteOptionPunchID(conn, punch.PunchID);
                                                    }
                                                    PunchListDO.DeletePunchList(conn, BALConstant.FINAL_INSPECTIONID, inspection.projectID);
                                                }

                                                using (LevelTransactionService levelTransactionService = new LevelTransactionService(conn))
                                                {
                                                    var levelTransactions = levelTransactionService.GetLevelTransactions();

                                                    if (levelTransactions != null)
                                                    {
                                                        foreach (var levelTrans in levelTransactions)
                                                        {
                                                            levelTransactionService.DeleteLevelTransactions(levelTrans);
                                                        }
                                                    }
                                                }


                                                using (SpaceTransactionService spaceTransactionService = new SpaceTransactionService(conn))
                                                {
                                                    var spaceTransactions = spaceTransactionService.GetSpaceTransactions();

                                                    if (spaceTransactions != null)
                                                    {
                                                        foreach (var spaceTrans in spaceTransactions
                                                                 )
                                                        {
                                                            spaceTransactionService.DeleteSpaceTransactions(spaceTrans);
                                                        }
                                                    }
                                                }


                                                //Get Option transactions for inspection(Not including punch list)
                                                List <OptionTransaction> optiontransactionLst = null;
                                                optiontransactionLst = OTS.GetOptionTransactionsForInspection(inspectionTransactionID);

                                                //Delete Item Transaction
                                                if (optiontransactionLst != null && optiontransactionLst.Count > 0)
                                                {
                                                    foreach (var optiontransaction in optiontransactionLst)
                                                    {
                                                        //Option Image Deletion
                                                        optImageservice.DeleteOptionImagesForSync(conn, optiontransaction.ID);

                                                        //Guided picture deletion
                                                        if (optiontransaction.OptionId == BALConstant.GUIDEDPICTURE_OPTIONID)
                                                        {
                                                            var chkTransIDs = CheckListTransactionDO.GetCheckListTransaction(conn, optiontransaction.ID).Select(s => s.ID);
                                                            if (chkTransIDs != null && chkTransIDs.Count() > 0)
                                                            {
                                                                foreach (var chkId in chkTransIDs)
                                                                {
                                                                    GuildedPhotoDO.DeleteGuidedImageList(conn, chkId);
                                                                }
                                                            }
                                                        }
                                                        // Checklist transaction Deletion
                                                        CheckListTransactionDO.DeletecheckList(conn, optiontransaction.ID);

                                                        //Option Transaction Row deletion
                                                        OTS.DeleteOptionTransactions(optiontransaction);
                                                    }
                                                }

                                                inspection.isInspectionSynced = true;
                                                inspection.InspectionStarted  = 0;

                                                transSer.UpdateInspectionTransaction(inspection);
                                                //update notification table with successfully uploaded insÏpection
                                                notificationRep.Save("Inspection", inspection.projectID, "Inspection Results for App ID  : " + inspection.projectID + "  successfully synced");
                                            }
                                            else
                                            {
                                                //update notification table with retry count for inspection
                                                notificationRep.Save("Inspection", inspection.projectID, "Inspection Results for App ID : " + inspection.projectID + " not synced");
                                            }
                                        }
                                    }

                                    if (inspection.isInspectionSynced)
                                    {                                     ///If inspection sync is success
                                        ReportService        repservice = new ReportService(conn);
                                        IEnumerable <Report> reports    = repservice.GetReports().Where(r => r.InspectionTransID == inspection.ID);
                                        if (reports != null)
                                        {
                                            foreach (var report in reports)
                                            {
                                                if (notifiy != null)
                                                {
                                                    notifiy(new notificationEventArgs
                                                    {
                                                        current = new Notifications
                                                        {
                                                            notificationTypeID = report.ReportID + "-" + inspection.projectID,
                                                            notificationType   = "Report",
                                                        },
                                                        isSyncCompleted = false,
                                                    });
                                                }

                                                Model.ServiceModel.InspectionReportAck inspectionReoprtRes = service.PushReport(new Model.ServiceModel.InspectionReport()
                                                {
                                                    inspectionTypeID = inspection.inspectionID,
                                                    appID            = inspection.projectID,
                                                    report           = report.ReportDesc,
                                                    reportName       = report.ReportType,
                                                    token            = user.Token,
                                                });
                                                if (inspectionReoprtRes.result != null && inspectionReoprtRes.result.code == 0)
                                                {
                                                    notificationRep.Save(report.ReportType.ToUpper(), inspection.projectID, report.ReportType.ToUpper() + " Report for App ID : " + inspection.projectID + " successfully synced");
                                                    repservice.DeleteReport(report);
                                                }
                                                else
                                                {
                                                    notificationRep.Save(report.ReportType.ToUpper(), inspection.projectID, report.ReportType.ToUpper() + " Report for App ID  : " + inspection.projectID + " not synced");
                                                }
                                            }
                                        }


                                        List <Model.ServiceModel.PunchListItem> PunchItemList = new List <Model.ServiceModel.PunchListItem>();
                                        if (inspection.inspectionID != BALConstant.FINAL_INSPECTIONID)
                                        {
                                            if (notifiy != null)
                                            {
                                                notifiy(new notificationEventArgs
                                                {
                                                    current = new Notifications
                                                    {
                                                        notificationTypeID = inspection.projectID,
                                                        notificationType   = "Punchlist",
                                                    },
                                                    isSyncCompleted = false,
                                                });
                                            }

                                            List <Punch> punchList = pushservice.getPunchList(inspection.inspectionID, inspection.projectID);
                                            if (punchList != null && punchList.Count > 0)
                                            {
                                                foreach (var punch in punchList)
                                                {
                                                    List <PunchListImageDO> ImageTransLst = PunchListImageDO.getPunchImageList(conn, punch.PunchID);
                                                    List <byte[]>           images        = new List <byte[]>();

                                                    if (ImageTransLst != null)
                                                    {
                                                        foreach (var ImageTrans in ImageTransLst)
                                                        {
                                                            images.Add(ImageTrans.PunchListImage);
                                                        }
                                                    }

                                                    PunchItemList.Add(new Model.ServiceModel.PunchListItem()
                                                    {
                                                        photos   = images,
                                                        comment  = punch.punchDescription,
                                                        sequence = -1
                                                    });
                                                }

                                                Model.ServiceModel.PunchListAck inspectionPunchListRes = service.PushPunchList(new Model.ServiceModel.PunchListResult()
                                                {
                                                    inspectionTypeID = inspection.inspectionID,
                                                    appID            = inspection.projectID,
                                                    punchList        = PunchItemList,
                                                    token            = user.Token
                                                });
                                                if (inspectionPunchListRes.result != null && inspectionPunchListRes.result.code == 0)
                                                {
                                                    //update notification table with successfully uploaded punch list
                                                    notificationRep.Save("Punchlist", inspection.projectID, "Punch List for App ID : " + inspection.projectID + " successfully synced");
                                                    foreach (Punch item in punchList)
                                                    {
                                                        pushservice.DeletePunchItem(item);
                                                        PunchListImageDO.DeletePunchImageList(conn, item.PunchID);
                                                    }
                                                    OptionTransactionDO.DeleteInspectionOptions(conn, inspection.ID);
                                                }
                                                else
                                                {
                                                    //update notification table with retry count for punch list
                                                    notificationRep.Save("Punchlist", inspection.projectID, "Punch List for App ID : " + inspection.projectID + " not synced");
                                                }
                                            }
                                        }
                                    }

                                    if (inspection.isInspectionSynced)
                                    {
                                        using (ReportService repservice = new ReportService(conn))
                                        {
                                            IEnumerable <Report> reports = repservice.GetReports().Where(r => r.InspectionTransID == inspection.ID);
                                            if (reports != null && reports.Count() > 0)
                                            {
                                                reportCount = reports.Count();
                                            }
                                        }
                                        if (inspection.inspectionID != BALConstant.FINAL_INSPECTIONID)
                                        {
                                            List <Punch> punchList = pushservice.getPunchList(inspection.inspectionID, inspection.projectID);
                                            if (punchList != null && punchList.Count > 0)
                                            {
                                                punchListCount = punchList.Count;
                                            }
                                        }
                                        if (reportCount == 0 && punchListCount == 0)
                                        {
                                            transSer.DeleteInspectionTransaction(inspection);
                                            continue;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("Exception Occured in Syncdata method due to " + ex.Message);
                }
                finally
                {
                    if (notifiy != null)
                    {
                        notifiy(new notificationEventArgs
                        {
                            current         = new Notifications(),
                            isSyncCompleted = true,
                        });
                    }
                    if (syncProgress != null)
                    {
                        syncProgress(false);
                    }
                    IsSyncProgress = false;
                    UIApplication.SharedApplication.InvokeOnMainThread(delegate
                    {
                        UIApplication.SharedApplication.IdleTimerDisabled = false;
                        Debug.WriteLine("sync thread finished");
                    });
                }
            }
        }
Example #11
0
        /// <summary>
        /// Gets the punch list for seq.
        /// </summary>
        /// <returns>The punch list for seq.</returns>
        /// <param name="inspectionID">Inspection I.</param>
        /// <param name="projectID">Project I.</param>
        /// <param name="inspectionTransactionID">Inspection transaction I.</param>
        public List <Option> getPunchListForSeq(string inspectionID, string projectID, int inspectionTransactionID)
        {
            List <Option> options = new List <Option> ();

            try
            {
                PunchService           punchservice = new PunchService(conn);
                List <Punch>           punchs       = punchservice.GetPunchList(conn, inspectionID, projectID);
                OptionsDO              optPunch     = OptionsDO.GetPunchOptions(conn, BALConstant.PUNCH_OPTIONID).FirstOrDefault();
                List <byte[]>          imagesList   = null;
                List <Model.CheckList> checkList    = new List <Model.CheckList>();
                if (punchs != null && punchs.Count > 0)
                {
                    List <PunchListImage> images = new List <PunchListImage>();
                    foreach (var punchItem in punchs)
                    {
                        string     comments = "";
                        ResultType results  = ResultType.NA;
                        int        checkListTransactionID = -1;
                        imagesList = new List <byte[]>();
                        var finalPunchTransaction = GetFinalPunchTransactionData(inspectionTransactionID, BALConstant.PUNCH_OPTIONID, punchItem.PunchID);
                        if (finalPunchTransaction != null && finalPunchTransaction.Count > 0)
                        {
                            var finalPunch = finalPunchTransaction.FirstOrDefault();
                            checkListTransactionID = finalPunch.CheckListTransactionID;
                            results  = (ResultType)finalPunch.CheckListResultTypeID;
                            comments = finalPunch.CheckLIstComment;
                            foreach (var item in finalPunchTransaction)
                            {
                                images.Add(new PunchListImage()
                                {
                                    Image             = item.Images,
                                    inspectionTransID = item.IspectionTransactionID,
                                    PunchID           = item.PunchID
                                });
                                imagesList.Add(item.Images);
                            }
                        }
                        checkList.Add(new Model.CheckList()
                        {
                            description      = punchItem.punchDescription,
                            itemType         = ItemType.PunchList,
                            ID               = punchItem.PunchID,
                            CheckListTransID = checkListTransactionID,
                            comments         = comments,
                            Result           = results,
                            PunchID          = punchItem.PunchID,
                            photos           = imagesList
                        });
                    }
                    options.Add(new Option()
                    {
                        ID              = optPunch.ID,
                        name            = optPunch.OptionsDesc,
                        checkListItems  = checkList,
                        InspectionID    = inspectionID,
                        isGuidedPicture = false,

                        SequenceID = BALConstant.PUNCH_SEQUENCEID
                    });
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception Occured in getPunchListForSeq method due to " + ex.Message);
            }
            return(options);
        }
        public IActionResult SplitAtMidnight(ODataActionParameters parameters)
        {
            _telemetryClient.TrackEvent("Split:Requested");

            using (var transaction = _context.Database.BeginTransaction())
            {
                try
                {
                    var   parsedInAt  = DateTime.Parse(parameters["InAt"] as string);
                    var   parsedOutAt = DateTime.Parse(parameters["OutAt"] as string);
                    var   currentUser = CurrentUser();
                    var   nowUtc      = DateTime.UtcNow;
                    var   inAt        = new DateTime(parsedInAt.Year, parsedInAt.Month, parsedInAt.Day, 0, 0, 0, 0);
                    var   outAt       = new DateTime(parsedOutAt.Year, parsedOutAt.Month, parsedOutAt.Day, 23, 59, 0, 0);
                    int[] userIds     = _context.Users
                                        .Where(u => u.OrganizationId == currentUser.OrganizationId)
                                        .Select(u => u.Id)
                                        .ToArray();
                    var originalPunchesTracked = _context.Punches
                                                 .Where(p => userIds.Contains(p.UserId))
                                                 .Where(p => p.OutAt.HasValue)
                                                 .Where(p => p.InAt.Date >= inAt.Date)
                                                 .Where(p => p.InAt.Date <= outAt.Date)
                                                 .Where(p => !p.CommitId.HasValue); // Only unlocked punches
                    var originalPunchesNotTracked = originalPunchesTracked
                                                    .AsNoTracking()                 // Will be manipulated in memory
                                                    .ToList();

                    _telemetryClient.TrackEvent("Split:Starting", new Dictionary <string, string>()
                    {
                        { "InAt", inAt.ToString("G") },
                        { "OutAt", outAt.ToString("G") },
                        { "UserId", currentUser.Id.ToString() },
                        { "OrganizationId", currentUser.OrganizationId.ToString() }
                    });

                    // Save what the punches looked like before.
                    var before = originalPunchesNotTracked;

                    var splitPunches = new PunchService(_context).SplitAtMidnight(originalPunchesNotTracked, currentUser);

                    // Save what the punches look like after.
                    var after = splitPunches;

                    // Delete the old punches and save the new ones
                    _context.Punches.RemoveRange(originalPunchesTracked);
                    _context.SaveChanges();

                    _context.Punches.AddRange(splitPunches);
                    _context.SaveChanges();

                    try
                    {
                        // Attempt to save the backup of the punches on Azure.
                        var backup = new
                        {
                            Before = before,
                            After  = after
                        };
                        var json = JsonSerializer.Serialize(backup);

                        // Prepare to upload the backup.
                        var azureConnectionString             = _configuration["PunchBackupsAzureStorageConnectionString"];
                        BlobServiceClient   blobServiceClient = new BlobServiceClient(azureConnectionString);
                        BlobContainerClient containerClient   = blobServiceClient.GetBlobContainerClient("split-punch-backups");
                        BlobClient          blobClient        = containerClient.GetBlobClient($"{currentUser.OrganizationId}/{nowUtc.Ticks}.json");

                        // Perform the upload.
                        using (var stream = new MemoryStream(Encoding.Default.GetBytes(json), false))
                        {
                            blobClient.Upload(stream);
                        }
                    }
                    catch (Exception ex)
                    {
                        _telemetryClient.TrackException(ex);
                    }

                    _telemetryClient.TrackEvent("Split:Succeeded");
                    _telemetryClient.Flush();

                    transaction.Commit();

                    return(Ok());
                }
                catch (Exception ex)
                {
                    _telemetryClient.TrackEvent("Split:Failed");
                    _telemetryClient.TrackException(ex);
                    _telemetryClient.Flush();

                    transaction.Rollback();

                    return(BadRequest(ex.ToString()));
                }
            }
        }