public static Common.Models.Timing.Time Edit(
            Common.Models.Timing.Time model,
            Common.Models.Account.Users modifier,
            IDbConnection conn   = null,
            bool closeConnection = true)
        {
            model.ModifiedBy = modifier;
            model.Modified   = DateTime.UtcNow;
            DBOs.Timing.Time dbo = Mapper.Map <DBOs.Timing.Time>(model);

            conn = DataHelper.OpenIfNeeded(conn);

            if (dbo.TimeCategoryId.HasValue && dbo.TimeCategoryId.Value == 0)
            {
                dbo.TimeCategoryId = null;
            }

            conn.Execute("UPDATE \"time\" SET " +
                         "\"start\"=@Start, \"stop\"=@Stop, \"worker_contact_id\"=@WorkerContactId, \"time_category_id\"=@TimeCategoryId, \"details\"=@Details, \"billable\"=@Billable, \"utc_modified\"=@UtcModified, \"modified_by_user_pid\"=@ModifiedByUserPId " +
                         "WHERE \"id\"=@Id", dbo);

            DataHelper.Close(conn, closeConnection);

            return(model);
        }
 public static Common.Models.Timing.Time Edit(
     Transaction t,
     Common.Models.Timing.Time model,
     Common.Models.Account.Users modifier)
 {
     return(Edit(model, modifier, t.Connection, false));
 }
        public static Common.Models.Timing.Time Create(
            Common.Models.Timing.Time model,
            Common.Models.Account.Users creator,
            IDbConnection conn   = null,
            bool closeConnection = true)
        {
            if (!model.Id.HasValue)
            {
                model.Id = Guid.NewGuid();
            }
            model.CreatedBy = model.ModifiedBy = creator;
            model.Created   = model.Modified = DateTime.UtcNow;
            DBOs.Timing.Time dbo = Mapper.Map <DBOs.Timing.Time>(model);

            conn = DataHelper.OpenIfNeeded(conn);

            if (dbo.TimeCategoryId.HasValue && dbo.TimeCategoryId.Value == 0)
            {
                dbo.TimeCategoryId = null;
            }

            conn.Execute("INSERT INTO \"time\" (\"id\", \"start\", \"stop\", \"worker_contact_id\", \"time_category_id\", \"details\", \"billable\", \"utc_created\", \"utc_modified\", \"created_by_user_pid\", \"modified_by_user_pid\") " +
                         "VALUES (@Id, @Start, @Stop, @WorkerContactId, @TimeCategoryId, @Details, @Billable, @UtcCreated, @UtcModified, @CreatedByUserPId, @ModifiedByUserPId)",
                         dbo);

            DataHelper.Close(conn, closeConnection);

            return(model);
        }
 public static Common.Models.Timing.Time Create(
     Transaction t,
     Common.Models.Timing.Time model,
     Common.Models.Account.Users creator)
 {
     return(Create(model, creator, t.Connection, false));
 }
Exemple #5
0
        public static Common.Models.Tasks.TaskTime RelateTask(Common.Models.Timing.Time timeModel,
                                                              long taskId, Common.Models.Account.Users creator)
        {
            Common.Models.Tasks.TaskTime taskTime = new Common.Models.Tasks.TaskTime()
            {
                Id   = Guid.NewGuid(),
                Task = new Common.Models.Tasks.Task()
                {
                    Id = taskId, IsStub = true
                },
                Time       = timeModel,
                Created    = DateTime.UtcNow,
                Modified   = DateTime.UtcNow,
                CreatedBy  = creator,
                ModifiedBy = creator
            };

            DBOs.Tasks.TaskTime dbo = Mapper.Map <DBOs.Tasks.TaskTime>(taskTime);

            using (IDbConnection conn = Database.Instance.GetConnection())
            {
                conn.Execute("INSERT INTO \"task_time\" (\"id\", \"task_id\", \"time_id\", \"utc_created\", \"utc_modified\", \"created_by_user_pid\", \"modified_by_user_pid\") " +
                             "VALUES (@Id, @TaskId, @TimeId, @UtcCreated, @UtcModified, @CreatedByUserPId, @ModifiedByUserPId)",
                             dbo);
            }

            return(taskTime);
        }
 public static Common.Models.Tasks.TaskTime RelateTask(
     Transaction t,
     Common.Models.Timing.Time timeModel,
     long taskId,
     Common.Models.Account.Users creator)
 {
     return(RelateTask(timeModel, taskId, creator, t.Connection, false));
 }
Exemple #7
0
        public static Common.Models.Timing.Time Edit(Common.Models.Timing.Time model,
                                                     Common.Models.Account.Users modifier)
        {
            model.ModifiedBy = modifier;
            model.Modified   = DateTime.UtcNow;
            DBOs.Timing.Time dbo = Mapper.Map <DBOs.Timing.Time>(model);

            using (IDbConnection conn = Database.Instance.GetConnection())
            {
                conn.Execute("UPDATE \"time\" SET " +
                             "\"start\"=@Start, \"stop\"=@Stop, \"worker_contact_id\"=@WorkerContactId, \"details\"=@Details, \"billable\"=@Billable, \"utc_modified\"=@UtcModified, \"modified_by_user_pid\"=@ModifiedByUserPId " +
                             "WHERE \"id\"=@Id", dbo);
            }

            return(model);
        }
Exemple #8
0
        public static Common.Models.Timing.Time Create(Common.Models.Timing.Time model,
                                                       Common.Models.Account.Users creator)
        {
            if (!model.Id.HasValue)
            {
                model.Id = Guid.NewGuid();
            }
            model.CreatedBy = model.ModifiedBy = creator;
            model.Created   = model.Modified = DateTime.UtcNow;
            DBOs.Timing.Time dbo = Mapper.Map <DBOs.Timing.Time>(model);

            using (IDbConnection conn = Database.Instance.GetConnection())
            {
                conn.Execute("INSERT INTO \"time\" (\"id\", \"start\", \"stop\", \"worker_contact_id\", \"details\", \"billable\", \"utc_created\", \"utc_modified\", \"created_by_user_pid\", \"modified_by_user_pid\") " +
                             "VALUES (@Id, @Start, @Stop, @WorkerContactId, @Details, @Billable, @UtcCreated, @UtcModified, @CreatedByUserPId, @ModifiedByUserPId)",
                             dbo);
            }

            return(model);
        }
        public static Common.Models.Tasks.TaskTime RelateTask(
            Common.Models.Timing.Time timeModel,
            long taskId,
            Common.Models.Account.Users creator,
            IDbConnection conn   = null,
            bool closeConnection = true)
        {
            Common.Models.Tasks.TaskTime taskTime = new Common.Models.Tasks.TaskTime()
            {
                Id   = Guid.NewGuid(),
                Task = new Common.Models.Tasks.Task()
                {
                    Id = taskId, IsStub = true
                },
                Time       = timeModel,
                Created    = DateTime.UtcNow,
                Modified   = DateTime.UtcNow,
                CreatedBy  = creator,
                ModifiedBy = creator
            };

            DBOs.Tasks.TaskTime dbo = Mapper.Map <DBOs.Tasks.TaskTime>(taskTime);

            conn = DataHelper.OpenIfNeeded(conn);

            if (conn.Execute("INSERT INTO \"task_time\" (\"id\", \"task_id\", \"time_id\", \"utc_created\", \"utc_modified\", \"created_by_user_pid\", \"modified_by_user_pid\") " +
                             "VALUES (@Id, @TaskId, @TimeId, @UtcCreated, @UtcModified, @CreatedByUserPId, @ModifiedByUserPId)",
                             dbo) > 0)
            {
                timeModel.Id = conn.Query <DBOs.Tasks.TaskTime>("SELECT currval(pg_get_serial_sequence('task_time', 'id')) AS \"id\"").Single().Id;
            }

            DataHelper.Close(conn, closeConnection);

            return(taskTime);
        }
        public ActionResult PhoneCall(Guid id, ViewModels.Tasks.PhoneCallViewModel viewModel)
        {
            int contactId;

            Common.Models.Account.Users  currentUser;
            Common.Models.Matters.Matter matter;

            dynamic profile = ProfileBase.Create(Membership.GetUser().UserName);

            if (profile.ContactId == null && string.IsNullOrEmpty(profile.ContactId))
            {
                throw new Exception("Profile.ContactId not configured.");
            }

            using (Data.Transaction trans = Data.Transaction.Create(true))
            {
                try
                {
                    contactId   = int.Parse(profile.ContactId);
                    currentUser = Data.Account.Users.Get(trans, User.Identity.Name);
                    matter      = Data.Matters.Matter.Get(trans, id);

                    // Task
                    Common.Models.Tasks.Task task = new Common.Models.Tasks.Task()
                    {
                        Active      = true,
                        DueDate     = DateTime.Now,
                        Title       = viewModel.Title,
                        Description = new Ganss.XSS.HtmlSanitizer().Sanitize(viewModel.TaskAndNoteDetails)
                    };

                    // TaskAssignedContact
                    Common.Models.Tasks.TaskAssignedContact taskAssignedContact = new Common.Models.Tasks.TaskAssignedContact()
                    {
                        Contact = new Common.Models.Contacts.Contact()
                        {
                            Id = contactId
                        },
                        Task           = task,
                        AssignmentType = Common.Models.Tasks.AssignmentType.Direct
                    };

                    // Time
                    Common.Models.Timing.Time time = new Common.Models.Timing.Time()
                    {
                        Billable     = viewModel.Billable,
                        Details      = viewModel.TimeDetails,
                        Start        = viewModel.Start,
                        Stop         = viewModel.Stop,
                        TimeCategory = new Common.Models.Timing.TimeCategory()
                        {
                            Id = viewModel.TimeCategory.Id.Value
                        },
                        Worker = new Common.Models.Contacts.Contact()
                        {
                            Id = contactId
                        }
                    };

                    // Note
                    Common.Models.Notes.Note note = new Common.Models.Notes.Note()
                    {
                        Body      = viewModel.TaskAndNoteDetails,
                        Timestamp = DateTime.Now,
                        Title     = viewModel.Title
                    };


                    task = Data.Tasks.Task.Create(trans, task, currentUser);
                    Data.Tasks.Task.RelateMatter(trans, task, matter.Id.Value, currentUser);
                    Data.Tasks.TaskAssignedContact.Create(trans, taskAssignedContact, currentUser);

                    if (viewModel.MakeTime)
                    {
                        time = Data.Timing.Time.Create(trans, time, currentUser);
                        Data.Timing.Time.RelateTask(trans, time, task.Id.Value, currentUser);
                    }

                    if (viewModel.MakeNote)
                    {
                        note = Data.Notes.Note.Create(trans, note, currentUser);
                        Data.Notes.Note.RelateTask(trans, note, task.Id.Value, currentUser);

                        if (viewModel.NotifyContactIds != null)
                        {
                            foreach (string x in viewModel.NotifyContactIds)
                            {
                                Data.Notes.NoteNotification.Create(trans, new Common.Models.Notes.NoteNotification()
                                {
                                    Contact = new Common.Models.Contacts.Contact()
                                    {
                                        Id = int.Parse(x)
                                    },
                                    Note    = note,
                                    Cleared = null
                                }, currentUser);
                            }
                            ;
                        }
                    }

                    trans.Commit();

                    return(RedirectToAction("Details", "Tasks", new { Id = task.Id }));
                }
                catch
                {
                    trans.Rollback();
                    return(PhoneCall(id));
                }
            }
        }
        public ActionResult PhoneCall(Guid id, ViewModels.Tasks.PhoneCallViewModel viewModel)
        {
            int contactId;
            Common.Models.Account.Users currentUser;
            Common.Models.Matters.Matter matter;

            dynamic profile = ProfileBase.Create(Membership.GetUser().UserName);
            if (profile.ContactId == null && string.IsNullOrEmpty(profile.ContactId))
                throw new Exception("Profile.ContactId not configured.");

            using (Data.Transaction trans = Data.Transaction.Create(true))
            {
                try
                {
                    contactId = int.Parse(profile.ContactId);
                    currentUser = Data.Account.Users.Get(trans, User.Identity.Name);
                    matter = Data.Matters.Matter.Get(trans, id);

                    // Task
                    Common.Models.Tasks.Task task = new Common.Models.Tasks.Task()
                    {
                        Active = true,
                        DueDate = DateTime.Now,
                        Title = viewModel.Title,
                        Description = new Ganss.XSS.HtmlSanitizer().Sanitize(viewModel.TaskAndNoteDetails)
                    };

                    // TaskAssignedContact
                    Common.Models.Tasks.TaskAssignedContact taskAssignedContact = new Common.Models.Tasks.TaskAssignedContact()
                    {
                        Contact = new Common.Models.Contacts.Contact() { Id = contactId },
                        Task = task,
                        AssignmentType = Common.Models.Tasks.AssignmentType.Direct
                    };

                    // Time
                    Common.Models.Timing.Time time = new Common.Models.Timing.Time()
                    {
                        Billable = viewModel.Billable,
                        Details = viewModel.TimeDetails,
                        Start = viewModel.Start,
                        Stop = viewModel.Stop,
                        Worker = new Common.Models.Contacts.Contact() { Id = contactId }
                    };

                    // Note
                    Common.Models.Notes.Note note = new Common.Models.Notes.Note()
                    {
                        Body = viewModel.TaskAndNoteDetails,
                        Timestamp = DateTime.Now,
                        Title = viewModel.Title
                    };


                    task = Data.Tasks.Task.Create(trans, task, currentUser);
                    Data.Tasks.Task.RelateMatter(trans, task, matter.Id.Value, currentUser);
                    Data.Tasks.TaskAssignedContact.Create(trans, taskAssignedContact, currentUser);

                    if (viewModel.MakeTime)
                    {
                        time = Data.Timing.Time.Create(trans, time, currentUser);
                        Data.Timing.Time.RelateTask(trans, time, task.Id.Value, currentUser);
                    }

                    if (viewModel.MakeNote)
                    {
                        note = Data.Notes.Note.Create(trans, note, currentUser);
                        Data.Notes.Note.RelateTask(trans, note, task.Id.Value, currentUser);

                        if (viewModel.NotifyContactIds != null)
                        {
                            foreach (string x in viewModel.NotifyContactIds)
                            {
                                Data.Notes.NoteNotification.Create(trans, new Common.Models.Notes.NoteNotification()
                                {
                                    Contact = new Common.Models.Contacts.Contact() { Id = int.Parse(x) },
                                    Note = note,
                                    Cleared = null
                                }, currentUser);
                            };
                        }
                    }

                    trans.Commit();

                    return RedirectToAction("Details", "Tasks", new { Id = task.Id });
                }
                catch
                {
                    trans.Rollback();
                    return PhoneCall(id);
                }
            }
        }
Exemple #12
0
        public ActionResult SingleMatterBill(Guid id, ViewModels.Billing.InvoiceViewModel viewModel)
        {
            // Create Invoice
            // Loop Expenses
            // Loop Fees
            // Loop Times
            // Redirect to invoice viewing
            Common.Models.Account.Users  currentUser;
            Common.Models.Matters.Matter matter;
            DateTime?start = null, stop = null;
            List <Common.Models.Billing.InvoiceExpense> invoiceExpenseList;
            List <Common.Models.Billing.InvoiceFee>     invoiceFeeList;
            List <Common.Models.Billing.InvoiceTime>    invoiceTimeList;

            Common.Models.Billing.Invoice invoice = null;

            if (!string.IsNullOrEmpty(Request["StartDate"]))
            {
                start = DateTime.Parse(Request["StartDate"]);
            }
            if (!string.IsNullOrEmpty(Request["StopDate"]))
            {
                stop = DateTime.Parse(Request["StopDate"]);
            }

            using (Data.Transaction trans = Data.Transaction.Create(true))
            {
                try
                {
                    currentUser = Data.Account.Users.Get(trans, User.Identity.Name);
                    invoice     = Mapper.Map <Common.Models.Billing.Invoice>(viewModel);
                    ViewModels.Billing.InvoiceViewModel        builtInvoice = BuildSingleMatterViewModel(id, trans.Connection, false, start, stop, Request["rateFrom"]);
                    ViewModels.Billing.InvoiceExpenseViewModel ievm;
                    ViewModels.Billing.InvoiceFeeViewModel     ifvm;
                    ViewModels.Billing.InvoiceTimeViewModel    itvm;

                    // Validation
                    for (int i = 0; i < viewModel.Expenses.Count; i++)
                    {
                        ievm = builtInvoice.Expenses.Single(x => x.Expense.Id.Value == viewModel.Expenses[i].Expense.Id.Value);
                        viewModel.Expenses[i].Expense = ievm.Expense;
                        if (string.IsNullOrEmpty(viewModel.Expenses[i].Details))
                        {
                            ModelState.AddModelError(string.Format("Expenses[{0}].Details", i), "Required");
                        }
                    }
                    ;
                    for (int i = 0; i < viewModel.Fees.Count; i++)
                    {
                        ifvm = builtInvoice.Fees.Single(x => x.Fee.Id.Value == viewModel.Fees[i].Fee.Id.Value);
                        viewModel.Fees[i].Fee = ifvm.Fee;
                        if (string.IsNullOrEmpty(viewModel.Fees[i].Details))
                        {
                            ModelState.AddModelError(string.Format("Fees[{0}].Details", i), "Required");
                        }
                    }
                    ;
                    for (int i = 0; i < viewModel.TimeGroups.Count; i++)
                    {
                        if (viewModel.TimeGroups[i].Times.Count > 0)
                        {
                            Common.Models.Timing.Time         zItem = Data.Timing.Time.Get(viewModel.TimeGroups[i].Times[0].Time.Id.Value);
                            Common.Models.Timing.TimeCategory zTc;
                            if (zItem.TimeCategory != null && zItem.TimeCategory.Id.HasValue)
                            {
                                zTc = Data.Timing.TimeCategory.Get(zItem.TimeCategory.Id.Value);
                                viewModel.TimeGroups[i].GroupName = zTc.Title;
                                viewModel.TimeGroups[i].Id        = zTc.Id.Value;
                            }
                        }


                        for (int j = 0; j < viewModel.TimeGroups[i].Times.Count; j++)
                        {
                            itvm = builtInvoice.TimeGroups[i].Times.Single(x => x.Time.Id.Value == viewModel.TimeGroups[i].Times[j].Time.Id);
                            viewModel.TimeGroups[i].Times[j].Time = itvm.Time;
                            if (string.IsNullOrEmpty(viewModel.TimeGroups[i].Times[j].Details))
                            {
                                ModelState.AddModelError(string.Format("TimeGroups[{0}].Times[{1}].Details", i, j), "Required");
                            }
                        }
                        ;
                    }

                    if (!ModelState.IsValid)
                    {
                        // Errors - do nothing, but tell user and show again for fixing
                        matter = Data.Matters.Matter.Get(trans, id);
                        ViewData["MatterTitle"] = matter.Title;
                        ViewData["CaseNumber"]  = matter.CaseNumber;
                        ViewData["FirmName"]    = Common.Settings.Manager.Instance.System.BillingFirmName;
                        ViewData["FirmAddress"] = Common.Settings.Manager.Instance.System.BillingFirmAddress;
                        ViewData["FirmCity"]    = Common.Settings.Manager.Instance.System.BillingFirmCity;
                        ViewData["FirmState"]   = Common.Settings.Manager.Instance.System.BillingFirmState;
                        ViewData["FirmZip"]     = Common.Settings.Manager.Instance.System.BillingFirmZip;
                        ViewData["FirmPhone"]   = Common.Settings.Manager.Instance.System.BillingFirmPhone;
                        ViewData["FirmWeb"]     = Common.Settings.Manager.Instance.System.BillingFirmWeb;
                        return(View(viewModel));
                    }

                    invoiceExpenseList = new List <Common.Models.Billing.InvoiceExpense>();
                    invoiceFeeList     = new List <Common.Models.Billing.InvoiceFee>();
                    invoiceTimeList    = new List <Common.Models.Billing.InvoiceTime>();

                    viewModel.Expenses.ForEach(vm =>
                    {
                        invoiceExpenseList.Add(new Common.Models.Billing.InvoiceExpense()
                        {
                            Invoice = invoice,
                            Expense = new Common.Models.Billing.Expense()
                            {
                                Id = vm.Expense.Id
                            },
                            Amount  = vm.Amount,
                            Details = vm.Details
                        });
                    });

                    viewModel.Fees.ForEach(vm =>
                    {
                        invoiceFeeList.Add(new Common.Models.Billing.InvoiceFee()
                        {
                            Invoice = invoice,
                            Fee     = new Common.Models.Billing.Fee()
                            {
                                Id = vm.Fee.Id
                            },
                            Amount  = vm.Amount,
                            Details = vm.Details
                        });
                    });

                    viewModel.TimeGroups.ForEach(tg =>
                    {
                        tg.Times.ForEach(vm =>
                        {
                            invoiceTimeList.Add(new Common.Models.Billing.InvoiceTime()
                            {
                                Invoice = invoice,
                                Time    = new Common.Models.Timing.Time()
                                {
                                    Id           = vm.Time.Id,
                                    TimeCategory = new Common.Models.Timing.TimeCategory()
                                    {
                                        Id    = tg.Id,
                                        Title = tg.GroupName
                                    }
                                },
                                Duration     = vm.Duration,
                                PricePerHour = vm.PricePerHour,
                                Details      = vm.Details
                            });
                        });
                    });

                    // Clear id from invoice as the ID is the ID of the matter
                    invoice.Id = null;

                    invoice = Data.Billing.Billing.SingleMatterBill(
                        invoice,
                        invoiceExpenseList,
                        invoiceFeeList,
                        invoiceTimeList,
                        currentUser,
                        trans);

                    trans.Commit();
                }
                catch (Exception ex)
                {
                    trans.Rollback();
                }
            }

            return(RedirectToAction("Details", "Invoices", new { id = invoice.Id }));
        }
        public ActionResult MatterEdit(Guid id, ViewModels.Billing.InvoiceViewModel viewModel)
        {
            // Update Invoice
            // Loop Expenses
            // Loop Fees
            // Loop Times
            // Redirect to invoice viewing
            Common.Models.Account.Users  currentUser;
            Common.Models.Matters.Matter matter;
            DateTime?start = null, stop = null;
            List <Common.Models.Billing.InvoiceExpense> invoiceExpenseList;
            List <Common.Models.Billing.InvoiceFee>     invoiceFeeList;
            List <Common.Models.Billing.InvoiceTime>    invoiceTimeList;

            Common.Models.Billing.Invoice invoice = null;

            if (!string.IsNullOrEmpty(Request["StartDate"]))
            {
                start = DateTime.Parse(Request["StartDate"]);
            }
            if (!string.IsNullOrEmpty(Request["StopDate"]))
            {
                stop = DateTime.Parse(Request["StopDate"]);
            }

            using (Data.Transaction trans = Data.Transaction.Create(true))
            {
                try
                {
                    currentUser = Data.Account.Users.Get(trans, User.Identity.Name);
                    invoice     = Mapper.Map <Common.Models.Billing.Invoice>(viewModel);
                    ViewModels.Billing.InvoiceViewModel        savedInvoice;
                    ViewModels.Billing.InvoiceExpenseViewModel ievm;
                    ViewModels.Billing.InvoiceFeeViewModel     ifvm;
                    ViewModels.Billing.InvoiceTimeViewModel    itvm;

                    // Validation
                    for (int i = 0; i < viewModel.TimeGroups.Count; i++)
                    {
                        if (viewModel.TimeGroups[i].Times.Count > 0)
                        {
                            Common.Models.Timing.TimeCategory zTc;
                            Common.Models.Timing.Time         zItem = Data.Timing.Time.Get(viewModel.TimeGroups[i].Times[0].Time.Id.Value);

                            if (zItem.TimeCategory == null || !zItem.TimeCategory.Id.HasValue || zItem.TimeCategory.Id.Value < 1)
                            {
                                viewModel.TimeGroups[i].GroupName = "Standard";
                                viewModel.TimeGroups[i].Id        = 0;
                            }
                            else
                            {
                                zTc = Data.Timing.TimeCategory.Get(zItem.TimeCategory.Id.Value);
                                viewModel.TimeGroups[i].GroupName = zTc.Title;
                                viewModel.TimeGroups[i].Id        = zTc.Id.Value;
                            }
                        }
                    }

                    savedInvoice          = Mapper.Map <ViewModels.Billing.InvoiceViewModel>(Data.Billing.Invoice.Get(trans, id));
                    savedInvoice.Expenses = new List <ViewModels.Billing.InvoiceExpenseViewModel>();
                    Data.Billing.Invoice.ListInvoiceExpensesForInvoice(trans, id).ForEach(x =>
                    {
                        savedInvoice.Expenses.Add(Mapper.Map <ViewModels.Billing.InvoiceExpenseViewModel>(x));
                    });
                    savedInvoice.Fees = new List <ViewModels.Billing.InvoiceFeeViewModel>();
                    Data.Billing.Invoice.ListInvoiceFeesForInvoice(trans, id).ForEach(x =>
                    {
                        savedInvoice.Fees.Add(Mapper.Map <ViewModels.Billing.InvoiceFeeViewModel>(x));
                    });

                    Data.Billing.Invoice.ListInvoiceTimesForInvoice(trans, id).ForEach(x =>
                    {
                        ViewModels.Billing.InvoiceTimeViewModel vm = Mapper.Map <ViewModels.Billing.InvoiceTimeViewModel>(x);
                        vm.Time = Mapper.Map <ViewModels.Timing.TimeViewModel>(Data.Timing.Time.Get(trans, vm.Time.Id.Value));

                        ViewModels.Billing.InvoiceTimeGroupViewModel timeGroup;
                        if (vm.Time.TimeCategory == null || !vm.Time.TimeCategory.Id.HasValue)
                        {
                            timeGroup = savedInvoice.TimeGroups.SingleOrDefault(y => y.Id == 0);
                        }
                        else
                        {
                            timeGroup = savedInvoice.TimeGroups.SingleOrDefault(y => y.Id == vm.Time.TimeCategory.Id);
                        }
                        if (timeGroup == null || timeGroup.Id == -1)
                        {
                            Common.Models.Timing.TimeCategory tc = Data.Timing.TimeCategory.Get(trans, vm.Time.TimeCategory.Id.Value);
                            timeGroup = new ViewModels.Billing.InvoiceTimeGroupViewModel()
                            {
                                Id        = tc.Id.Value,
                                GroupName = tc.Title,
                                Times     = new List <ViewModels.Billing.InvoiceTimeViewModel>()
                            };
                            timeGroup.Times.Add(vm);
                            savedInvoice.TimeGroups.Add(timeGroup);
                        }
                        else
                        {
                            timeGroup.Times.Add(vm);
                        }
                    });

                    // Validation
                    for (int i = 0; i < viewModel.Expenses.Count; i++)
                    {
                        ievm = savedInvoice.Expenses.Single(x => x.Expense.Id.Value == viewModel.Expenses[i].Expense.Id.Value);
                        viewModel.Expenses[i].Expense = ievm.Expense;
                        if (string.IsNullOrEmpty(viewModel.Expenses[i].Details))
                        {
                            ModelState.AddModelError(string.Format("Expenses[{0}].Details", i), "Required");
                        }
                    }
                    ;
                    for (int i = 0; i < viewModel.Fees.Count; i++)
                    {
                        ifvm = savedInvoice.Fees.Single(x => x.Fee.Id.Value == viewModel.Fees[i].Fee.Id.Value);
                        viewModel.Fees[i].Fee = ifvm.Fee;
                        if (string.IsNullOrEmpty(viewModel.Fees[i].Details))
                        {
                            ModelState.AddModelError(string.Format("Fees[{0}].Details", i), "Required");
                        }
                    }
                    ;
                    for (int i = 0; i < viewModel.TimeGroups.Count; i++)
                    {
                        for (int j = 0; j < viewModel.TimeGroups[i].Times.Count; j++)
                        {
                            itvm = savedInvoice.TimeGroups[i].Times.Single(x => x.Time.Id.Value == viewModel.TimeGroups[i].Times[j].Time.Id);
                            viewModel.TimeGroups[i].Times[j].Time = itvm.Time;
                            if (string.IsNullOrEmpty(viewModel.TimeGroups[i].Times[j].Details))
                            {
                                ModelState.AddModelError(string.Format("TimeGroups[{0}].Times[{1}].Details", i, j), "Required");
                            }
                        }
                        ;
                    }

                    if (!ModelState.IsValid)
                    {
                        // Errors - do nothing, but tell user and show again for fixing
                        matter = Data.Matters.Matter.Get(trans, id);
                        ViewData["MatterTitle"] = matter.Title;
                        ViewData["CaseNumber"]  = matter.CaseNumber;
                        ViewData["FirmName"]    = Common.Settings.Manager.Instance.System.BillingFirmName;
                        ViewData["FirmAddress"] = Common.Settings.Manager.Instance.System.BillingFirmAddress;
                        ViewData["FirmCity"]    = Common.Settings.Manager.Instance.System.BillingFirmCity;
                        ViewData["FirmState"]   = Common.Settings.Manager.Instance.System.BillingFirmState;
                        ViewData["FirmZip"]     = Common.Settings.Manager.Instance.System.BillingFirmZip;
                        ViewData["FirmPhone"]   = Common.Settings.Manager.Instance.System.BillingFirmPhone;
                        ViewData["FirmWeb"]     = Common.Settings.Manager.Instance.System.BillingFirmWeb;
                        return(View(viewModel));
                    }

                    decimal subtotal = 0;
                    invoiceExpenseList = new List <Common.Models.Billing.InvoiceExpense>();
                    invoiceFeeList     = new List <Common.Models.Billing.InvoiceFee>();
                    invoiceTimeList    = new List <Common.Models.Billing.InvoiceTime>();

                    viewModel.Expenses.ForEach(vm =>
                    {
                        Common.Models.Billing.InvoiceExpense mod = new Common.Models.Billing.InvoiceExpense()
                        {
                            Id      = vm.Id,
                            Invoice = invoice,
                            Expense = new Common.Models.Billing.Expense()
                            {
                                Id = vm.Expense.Id
                            },
                            Amount  = vm.Amount,
                            Details = vm.Details
                        };
                        subtotal += mod.Amount;
                        Data.Billing.InvoiceExpense.Edit(trans, mod, currentUser);
                    });

                    viewModel.Fees.ForEach(vm =>
                    {
                        Common.Models.Billing.InvoiceFee mod = new Common.Models.Billing.InvoiceFee()
                        {
                            Id      = vm.Id,
                            Invoice = invoice,
                            Fee     = new Common.Models.Billing.Fee()
                            {
                                Id = vm.Fee.Id
                            },
                            Amount  = vm.Amount,
                            Details = vm.Details
                        };
                        subtotal += mod.Amount;
                        Data.Billing.InvoiceFee.Edit(trans, mod, currentUser);
                    });

                    viewModel.TimeGroups.ForEach(tg =>
                    {
                        tg.Times.ForEach(vm =>
                        {
                            Common.Models.Billing.InvoiceTime mod = new Common.Models.Billing.InvoiceTime()
                            {
                                Id      = vm.Id,
                                Invoice = invoice,
                                Time    = new Common.Models.Timing.Time()
                                {
                                    Id           = vm.Time.Id,
                                    TimeCategory = new Common.Models.Timing.TimeCategory()
                                    {
                                        Id    = tg.Id,
                                        Title = tg.GroupName
                                    }
                                },
                                Duration     = vm.Duration,
                                PricePerHour = vm.PricePerHour,
                                Details      = vm.Details
                            };
                            subtotal += ((decimal)mod.Duration.TotalHours * mod.PricePerHour);
                            Data.Billing.InvoiceTime.Edit(trans, mod, currentUser);
                        });
                    });

                    invoice.Subtotal = subtotal;
                    invoice.Total    = invoice.Subtotal + invoice.TaxAmount;

                    Data.Billing.Invoice.Edit(trans, invoice, currentUser);

                    trans.Commit();
                }
                catch
                {
                    trans.Rollback();
                    throw;
                }
            }

            return(RedirectToAction("Details", "Invoices", new { id = invoice.Id }));
        }