public ActionResult SingleMatterBill(Guid id)
        {
            Common.Models.Matters.Matter matter;
            DateTime?start = null, stop = null;

            ViewModels.Billing.InvoiceViewModel viewModel = new ViewModels.Billing.InvoiceViewModel();

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

            matter    = Data.Matters.Matter.Get(id);
            viewModel = BuildSingleMatterViewModel(id, start, stop, Request["rateFrom"]);

            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));
        }
        public ActionResult MatterDetails(Guid id)
        {
            Common.Models.Billing.Invoice       invoice   = null;
            ViewModels.Billing.InvoiceViewModel viewModel = new ViewModels.Billing.InvoiceViewModel();

            invoice   = Data.Billing.Invoice.Get(id);
            viewModel = Mapper.Map <ViewModels.Billing.InvoiceViewModel>(invoice);

            if (invoice.Matter != null)
            {
                viewModel.Matter = Mapper.Map <ViewModels.Matters.MatterViewModel>(Data.Matters.Matter.Get(invoice.Matter.Id.Value));
            }

            Data.Billing.Invoice.ListInvoiceExpensesForInvoice(invoice.Id.Value).ForEach(x =>
            {
                ViewModels.Billing.InvoiceExpenseViewModel vm = Mapper.Map <ViewModels.Billing.InvoiceExpenseViewModel>(x);
                vm.Expense = Mapper.Map <ViewModels.Billing.ExpenseViewModel>(Data.Billing.Expense.Get(vm.Expense.Id.Value));
                viewModel.Expenses.Add(vm);
            });

            Data.Billing.Invoice.ListInvoiceFeesForInvoice(invoice.Id.Value).ForEach(x =>
            {
                ViewModels.Billing.InvoiceFeeViewModel vm = Mapper.Map <ViewModels.Billing.InvoiceFeeViewModel>(x);
                vm.Fee = Mapper.Map <ViewModels.Billing.FeeViewModel>(Data.Billing.Fee.Get(vm.Fee.Id.Value));
                viewModel.Fees.Add(vm);
            });

            Data.Billing.Invoice.ListInvoiceTimesForInvoice(invoice.Id.Value).ForEach(x =>
            {
                ViewModels.Billing.InvoiceTimeViewModel vm = Mapper.Map <ViewModels.Billing.InvoiceTimeViewModel>(x);
                vm.Time = Mapper.Map <ViewModels.Timing.TimeViewModel>(Data.Timing.Time.Get(vm.Time.Id.Value));
                viewModel.Times.Add(vm);
            });

            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));
        }
        public ActionResult MatterDetails(Guid id)
        {
            Common.Models.Billing.Invoice invoice = null;
            ViewModels.Billing.InvoiceViewModel viewModel = new ViewModels.Billing.InvoiceViewModel();

            invoice = Data.Billing.Invoice.Get(id);
            viewModel = Mapper.Map<ViewModels.Billing.InvoiceViewModel>(invoice);

            if (invoice.Matter != null)
                viewModel.Matter = Mapper.Map<ViewModels.Matters.MatterViewModel>(Data.Matters.Matter.Get(invoice.Matter.Id.Value));

            Data.Billing.Invoice.ListInvoiceExpensesForInvoice(invoice.Id.Value).ForEach(x =>
            {
                ViewModels.Billing.InvoiceExpenseViewModel vm = Mapper.Map<ViewModels.Billing.InvoiceExpenseViewModel>(x);
                vm.Expense = Mapper.Map<ViewModels.Billing.ExpenseViewModel>(Data.Billing.Expense.Get(vm.Expense.Id.Value));
                viewModel.Expenses.Add(vm);
            });

            Data.Billing.Invoice.ListInvoiceFeesForInvoice(invoice.Id.Value).ForEach(x =>
            {
                ViewModels.Billing.InvoiceFeeViewModel vm = Mapper.Map<ViewModels.Billing.InvoiceFeeViewModel>(x);
                vm.Fee = Mapper.Map<ViewModels.Billing.FeeViewModel>(Data.Billing.Fee.Get(vm.Fee.Id.Value));
                viewModel.Fees.Add(vm);
            });

            Data.Billing.Invoice.ListInvoiceTimesForInvoice(invoice.Id.Value).ForEach(x =>
            {
                ViewModels.Billing.InvoiceTimeViewModel vm = Mapper.Map<ViewModels.Billing.InvoiceTimeViewModel>(x);
                vm.Time = Mapper.Map<ViewModels.Timing.TimeViewModel>(Data.Timing.Time.Get(vm.Time.Id.Value));
                viewModel.Times.Add(vm);
            });

            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);
        }
        public ActionResult MatterDelete(Guid id, ViewModels.Billing.InvoiceViewModel viewModel)
        {
            Common.Models.Account.Users   currentUser;
            Common.Models.Billing.Invoice invoice = null;

            using (Data.Transaction trans = Data.Transaction.Create(true))
            {
                try
                {
                    invoice     = Mapper.Map <Common.Models.Billing.Invoice>(viewModel);
                    invoice     = Data.Billing.Invoice.Get(trans, invoice.Id.Value);
                    currentUser = Data.Account.Users.Get(trans, User.Identity.Name);
                    Data.Billing.Invoice.Delete(trans, invoice, currentUser);
                    trans.Commit();
                }
                catch
                {
                    trans.Rollback();
                    throw;
                }
            }

            return(RedirectToAction("Invoices", "Matters", new { id = invoice.Matter.Id }));
        }
        public ActionResult Index()
        {
            ViewModels.Billing.BillingViewModel           viewModel = new ViewModels.Billing.BillingViewModel();
            ViewModels.Billing.BillingViewModel.Item      item;
            ViewModels.Billing.BillingViewModel.GroupItem groupItem;

            Data.Billing.Invoice.ListBillableMatters().ForEach(matter =>
            {
                item        = new ViewModels.Billing.BillingViewModel.Item();
                item.Matter = Mapper.Map <ViewModels.Matters.MatterViewModel>(matter);
                if (matter.BillTo != null && matter.BillTo.Id.HasValue)
                {
                    item.BillTo = Mapper.Map <ViewModels.Contacts.ContactViewModel>(Data.Contacts.Contact.Get(matter.BillTo.Id.Value));
                }
                item.Expenses = Data.Billing.Expense.SumUnbilledExpensesForMatter(matter.Id.Value);
                item.Fees     = Data.Billing.Fee.SumUnbilledFeesForMatter(matter.Id.Value);
                item.Time     = Data.Timing.Time.SumUnbilledAndBillableTimeForMatter(matter.Id.Value);

                if ((item.Expenses + item.Fees + (decimal)item.Time.TotalHours) > 0)
                {
                    viewModel.Items.Add(item);
                }
            });

            Data.Billing.Invoice.ListBillableBillingGroups().ForEach(group =>
            {
                groupItem = new ViewModels.Billing.BillingViewModel.GroupItem();
                groupItem.BillingGroup        = Mapper.Map <ViewModels.Billing.BillingGroupViewModel>(group);
                groupItem.BillingGroup.BillTo = Mapper.Map <ViewModels.Contacts.ContactViewModel>(Data.Contacts.Contact.Get(group.BillTo.Id.Value));
                groupItem.Expenses            = Data.Billing.BillingGroup.SumBillableExpensesForGroup(group.Id.Value);
                groupItem.Fees = Data.Billing.BillingGroup.SumBillableFeesForGroup(group.Id.Value);
                groupItem.Time = Data.Timing.Time.SumUnbilledAndBillableTimeForBillingGroup(group.Id.Value);
                viewModel.GroupItems.Add(groupItem);
            });

            Data.Billing.Invoice.GetMostRecentInvoices(10).ForEach(invoice =>
            {
                ViewModels.Billing.InvoiceViewModel vm = Mapper.Map <ViewModels.Billing.InvoiceViewModel>(invoice);

                if (invoice.Matter != null && invoice.Matter.Id.HasValue)
                {
                    vm.Matter = Mapper.Map <ViewModels.Matters.MatterViewModel>(Data.Matters.Matter.Get(invoice.Matter.Id.Value));
                }
                else
                {
                    vm.Matter = null;
                }

                if (invoice.BillingGroup != null && invoice.BillingGroup.Id.HasValue)
                {
                    vm.BillingGroup = Mapper.Map <ViewModels.Billing.BillingGroupViewModel>(Data.Billing.BillingGroup.Get(invoice.BillingGroup.Id.Value));
                }
                else
                {
                    vm.BillingGroup = null;
                }

                vm.BillTo = Mapper.Map <ViewModels.Contacts.ContactViewModel>(Data.Contacts.Contact.Get(invoice.BillTo.Id.Value));

                viewModel.RecentInvoices.Add(vm);
            });

            return(View(viewModel));
        }
        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;

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

            currentUser = Data.Account.Users.Get(User.Identity.Name);
            Common.Models.Billing.Invoice              invoice = Mapper.Map <Common.Models.Billing.Invoice>(viewModel);
            ViewModels.Billing.InvoiceViewModel        builtInvoice = BuildSingleMatterViewModel(id, 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.Times.Count; i++)
            {
                itvm = builtInvoice.Times.Single(x => x.Time.Id.Value == viewModel.Times[i].Time.Id);
                viewModel.Times[i].Time = itvm.Time;
                if (string.IsNullOrEmpty(viewModel.Times[i].Details))
                {
                    ModelState.AddModelError(string.Format("Times[{0}].Details", i), "Required");
                }
            }
            ;

            if (!ModelState.IsValid)
            {
                // Errors - do nothing, but tell user and show again for fixing
                matter = Data.Matters.Matter.Get(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.Times.ForEach(vm =>
            {
                invoiceTimeList.Add(new Common.Models.Billing.InvoiceTime()
                {
                    Invoice = invoice,
                    Time    = new Common.Models.Timing.Time()
                    {
                        Id = vm.Time.Id
                    },
                    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,
                null, true);

            return(RedirectToAction("Details", "Invoices", new { id = invoice.Id }));
        }
        public ViewModels.Billing.InvoiceViewModel BuildSingleMatterViewModel(Guid id, DateTime?startDate = null, DateTime?stopDate = null, string rateFrom = null)
        {
            Common.Models.Billing.BillingRate   billingRate     = null;
            ViewModels.Billing.InvoiceViewModel viewModel       = new ViewModels.Billing.InvoiceViewModel();
            Common.Models.Billing.Invoice       previousInvoice = null;
            Common.Models.Matters.Matter        matter;

            matter = Data.Matters.Matter.Get(id);

            previousInvoice = Data.Billing.Invoice.GetMostRecentInvoiceForContact(matter.BillTo.Id.Value);

            // Set default billing rate
            if (matter.DefaultBillingRate != null && matter.DefaultBillingRate.Id.HasValue)
            {
                billingRate = Data.Billing.BillingRate.Get(matter.DefaultBillingRate.Id.Value);
            }

            viewModel.Id     = Guid.NewGuid();
            viewModel.BillTo = Mapper.Map <ViewModels.Contacts.ContactViewModel>(Data.Contacts.Contact.Get(matter.BillTo.Id.Value));
            viewModel.Date   = DateTime.Now;
            viewModel.Due    = DateTime.Now.AddDays(30);
            viewModel.Matter = Mapper.Map <ViewModels.Matters.MatterViewModel>(matter);

            if (previousInvoice == null)
            {
                viewModel.BillTo_NameLine1 = viewModel.BillTo.DisplayName;
                if (string.IsNullOrEmpty(viewModel.BillTo.Address1AddressPostOfficeBox))
                {
                    viewModel.BillTo_AddressLine1 = viewModel.BillTo.Address1AddressStreet;
                }
                else
                {
                    viewModel.BillTo_AddressLine1 = "P.O. Box " + viewModel.BillTo.Address1AddressPostOfficeBox;
                }
                viewModel.BillTo_City  = viewModel.BillTo.Address1AddressCity;
                viewModel.BillTo_State = viewModel.BillTo.Address1AddressStateOrProvince;
                viewModel.BillTo_Zip   = viewModel.BillTo.Address1AddressPostalCode;
            }
            else
            {
                viewModel.BillTo_NameLine1    = previousInvoice.BillTo_NameLine1;
                viewModel.BillTo_NameLine2    = previousInvoice.BillTo_NameLine2;
                viewModel.BillTo_AddressLine1 = previousInvoice.BillTo_AddressLine1;
                viewModel.BillTo_AddressLine2 = previousInvoice.BillTo_AddressLine2;
                viewModel.BillTo_City         = previousInvoice.BillTo_City;
                viewModel.BillTo_State        = previousInvoice.BillTo_State;
                viewModel.BillTo_Zip          = previousInvoice.BillTo_Zip;
            }

            Data.Timing.Time.ListUnbilledAndBillableTimeForMatter(matter.Id.Value, startDate, stopDate).ForEach(x =>
            {
                ViewModels.Billing.InvoiceTimeViewModel vm = new ViewModels.Billing.InvoiceTimeViewModel()
                {
                    Invoice = viewModel,
                    Time    = Mapper.Map <ViewModels.Timing.TimeViewModel>(x),
                    Details = x.Details
                };
                if (x.Stop.HasValue)
                {
                    vm.Duration = x.Stop.Value - x.Start;
                }
                else
                {
                    vm.Duration = new TimeSpan(0);
                }

                if (string.IsNullOrEmpty(rateFrom))
                { // Not specified in URL
                    if (matter.OverrideMatterRateWithEmployeeRate)
                    {
                        Common.Models.Contacts.Contact contact = Data.Contacts.Contact.Get(x.Worker.Id.Value);
                        if (contact.BillingRate != null && contact.BillingRate.Id.HasValue)
                        {
                            billingRate = Data.Billing.BillingRate.Get(contact.BillingRate.Id.Value);
                        }
                    }
                }
                else
                { // Overridden by current user in URL
                    if (rateFrom == "employee")
                    {
                        Common.Models.Contacts.Contact contact = Data.Contacts.Contact.Get(x.Worker.Id.Value);
                        if (contact.BillingRate != null && contact.BillingRate.Id.HasValue)
                        {
                            billingRate = Data.Billing.BillingRate.Get(contact.BillingRate.Id.Value);
                        }
                    }
                }

                if (billingRate != null)
                {
                    vm.PricePerHour = billingRate.PricePerUnit;
                }
                viewModel.Times.Add(vm);
            });

            Data.Billing.Expense.ListUnbilledExpensesForMatter(matter.Id.Value, startDate, stopDate).ForEach(x =>
            {
                viewModel.Expenses.Add(new ViewModels.Billing.InvoiceExpenseViewModel()
                {
                    Invoice = viewModel,
                    Expense = Mapper.Map <ViewModels.Billing.ExpenseViewModel>(x),
                    Details = x.Details,
                    Amount  = x.Amount
                });
            });

            Data.Billing.Fee.ListUnbilledFeesForMatter(matter.Id.Value, startDate, stopDate).ForEach(x =>
            {
                viewModel.Fees.Add(new ViewModels.Billing.InvoiceFeeViewModel()
                {
                    Invoice = viewModel,
                    Fee     = Mapper.Map <ViewModels.Billing.FeeViewModel>(x),
                    Details = x.Details,
                    Amount  = x.Amount
                });
            });

            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(viewModel);
        }
        public ActionResult MatterEdit(Guid id)
        {
            Common.Models.Billing.BillingRate billingRate = null;
            Common.Models.Matters.Matter matter = null;
            Common.Models.Billing.Invoice invoice = null;
            ViewModels.Billing.InvoiceViewModel viewModel = new ViewModels.Billing.InvoiceViewModel();

            using (IDbConnection conn = Data.Database.Instance.GetConnection())
            {
                invoice = Data.Billing.Invoice.Get(id, conn, false);
                viewModel = Mapper.Map<ViewModels.Billing.InvoiceViewModel>(invoice);

                if (invoice.Matter != null)
                {
                    matter = Data.Matters.Matter.Get(invoice.Matter.Id.Value, conn, false);
                    viewModel.Matter = Mapper.Map<ViewModels.Matters.MatterViewModel>(matter);
                    if (matter.DefaultBillingRate != null && matter.DefaultBillingRate.Id.HasValue)
                        billingRate = Data.Billing.BillingRate.Get(matter.DefaultBillingRate.Id.Value, conn, false);
                }

                invoice.BillTo = Data.Contacts.Contact.Get(invoice.BillTo.Id.Value, conn, false);

                Data.Billing.Invoice.ListInvoiceExpensesForInvoice(invoice.Id.Value, conn, false).ForEach(x =>
                {
                    ViewModels.Billing.InvoiceExpenseViewModel vm = Mapper.Map<ViewModels.Billing.InvoiceExpenseViewModel>(x);
                    vm.Expense = Mapper.Map<ViewModels.Billing.ExpenseViewModel>(
                        Data.Billing.Expense.Get(vm.Expense.Id.Value, conn, false));
                    viewModel.Expenses.Add(vm);
                });

                Data.Billing.Invoice.ListInvoiceFeesForInvoice(invoice.Id.Value, conn, false).ForEach(x =>
                {
                    ViewModels.Billing.InvoiceFeeViewModel vm = Mapper.Map<ViewModels.Billing.InvoiceFeeViewModel>(x);
                    vm.Fee = Mapper.Map<ViewModels.Billing.FeeViewModel>(
                        Data.Billing.Fee.Get(vm.Fee.Id.Value, conn, false));
                    viewModel.Fees.Add(vm);
                });
                
                Data.Billing.Invoice.ListInvoiceTimesForInvoice(invoice.Id.Value, conn, false).ForEach(x =>
                {
                    ViewModels.Billing.InvoiceTimeViewModel vm = Mapper.Map<ViewModels.Billing.InvoiceTimeViewModel>(x);
                    vm.Time = Mapper.Map<ViewModels.Timing.TimeViewModel>(
                        Data.Timing.Time.Get(vm.Time.Id.Value, conn, false));

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

            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);
        }
        public ViewModels.Billing.InvoiceViewModel BuildSingleMatterViewModel(Guid id, IDbConnection conn, bool closeConnection, DateTime? startDate = null, DateTime? stopDate = null, string rateFrom = null)
        {
            Common.Models.Billing.BillingRate billingRate = null;
            ViewModels.Billing.InvoiceViewModel viewModel = new ViewModels.Billing.InvoiceViewModel();
            Common.Models.Billing.Invoice previousInvoice = null;
            Common.Models.Matters.Matter matter;
            
            matter = Data.Matters.Matter.Get(id, conn, false);

            previousInvoice = Data.Billing.Invoice.GetMostRecentInvoiceForContact(matter.BillTo.Id.Value, conn, false);

            // Set default billing rate
            if (matter.DefaultBillingRate != null && matter.DefaultBillingRate.Id.HasValue)
                billingRate = Data.Billing.BillingRate.Get(matter.DefaultBillingRate.Id.Value, conn, false);

            viewModel.Id = Guid.NewGuid();
            viewModel.BillTo = Mapper.Map<ViewModels.Contacts.ContactViewModel>(Data.Contacts.Contact.Get(matter.BillTo.Id.Value, conn, false));
            viewModel.Date = DateTime.Now;
            viewModel.Due = DateTime.Now.AddDays(30);
            viewModel.Matter = Mapper.Map<ViewModels.Matters.MatterViewModel>(matter);

            if (previousInvoice == null)
            {
                viewModel.BillTo_NameLine1 = viewModel.BillTo.DisplayName;
                if (string.IsNullOrEmpty(viewModel.BillTo.Address1AddressPostOfficeBox))
                    viewModel.BillTo_AddressLine1 = viewModel.BillTo.Address1AddressStreet;
                else
                    viewModel.BillTo_AddressLine1 = "P.O. Box " + viewModel.BillTo.Address1AddressPostOfficeBox;
                viewModel.BillTo_City = viewModel.BillTo.Address1AddressCity;
                viewModel.BillTo_State = viewModel.BillTo.Address1AddressStateOrProvince;
                viewModel.BillTo_Zip = viewModel.BillTo.Address1AddressPostalCode;
            }
            else
            {
                viewModel.BillTo_NameLine1 = previousInvoice.BillTo_NameLine1;
                viewModel.BillTo_NameLine2 = previousInvoice.BillTo_NameLine2;
                viewModel.BillTo_AddressLine1 = previousInvoice.BillTo_AddressLine1;
                viewModel.BillTo_AddressLine2 = previousInvoice.BillTo_AddressLine2;
                viewModel.BillTo_City = previousInvoice.BillTo_City;
                viewModel.BillTo_State = previousInvoice.BillTo_State;
                viewModel.BillTo_Zip = previousInvoice.BillTo_Zip;
            }

            Data.Timing.Time.ListUnbilledAndBillableTimeForMatter(matter.Id.Value, startDate, stopDate, conn, false).ForEach(x =>
            {
                ViewModels.Billing.InvoiceTimeViewModel vm = new ViewModels.Billing.InvoiceTimeViewModel()
                {
                    Invoice = viewModel,
                    Time = Mapper.Map<ViewModels.Timing.TimeViewModel>(x),
                    Details = x.Details
                };
                if (x.Stop.HasValue)
                    vm.Duration = x.Stop.Value - x.Start;
                else
                    vm.Duration = new TimeSpan(0);

                if (string.IsNullOrEmpty(rateFrom))
                { // Not specified in URL
                    if (matter.OverrideMatterRateWithEmployeeRate)
                    {
                        Common.Models.Contacts.Contact contact = Data.Contacts.Contact.Get(x.Worker.Id.Value, conn, false);
                        if (contact.BillingRate != null && contact.BillingRate.Id.HasValue)
                            billingRate = Data.Billing.BillingRate.Get(contact.BillingRate.Id.Value, conn, false);
                    }
                }
                else
                { // Overridden by current user in URL
                    if (rateFrom == "employee")
                    {
                        Common.Models.Contacts.Contact contact = Data.Contacts.Contact.Get(x.Worker.Id.Value, conn, false);
                        if (contact.BillingRate != null && contact.BillingRate.Id.HasValue)
                            billingRate = Data.Billing.BillingRate.Get(contact.BillingRate.Id.Value, conn, false);
                    }
                }

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

            Data.Billing.Expense.ListUnbilledExpensesForMatter(matter.Id.Value, startDate, stopDate, conn, false).ForEach(x =>
            {
                viewModel.Expenses.Add(new ViewModels.Billing.InvoiceExpenseViewModel()
                {
                    Invoice = viewModel,
                    Expense = Mapper.Map<ViewModels.Billing.ExpenseViewModel>(x),
                    Details = x.Details,
                    Amount = x.Amount
                });
            });

            Data.Billing.Fee.ListUnbilledFeesForMatter(matter.Id.Value, startDate, stopDate, conn, false).ForEach(x =>
            {
                viewModel.Fees.Add(new ViewModels.Billing.InvoiceFeeViewModel()
                {
                    Invoice = viewModel,
                    Fee = Mapper.Map<ViewModels.Billing.FeeViewModel>(x),
                    Details = x.Details,
                    Amount = x.Amount
                });
            });

            viewModel.TimeGroups = viewModel.TimeGroups.OrderBy(y => y.GroupName).ToList();

            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 viewModel;
        }
        public ActionResult SingleMatterBill(Guid id)
        {
            Common.Models.Matters.Matter matter;
            DateTime? start = null, stop = null;
            ViewModels.Billing.InvoiceViewModel viewModel = new ViewModels.Billing.InvoiceViewModel();

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

            using (IDbConnection conn = Data.Database.Instance.GetConnection())
            {
                matter = Data.Matters.Matter.Get(id, conn, false);
                viewModel = BuildSingleMatterViewModel(id, conn, false, start, stop, Request["rateFrom"]);
            }

            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);
        }
        public ActionResult MatterEdit(Guid id)
        {
            Common.Models.Billing.BillingRate   billingRate = null;
            Common.Models.Matters.Matter        matter      = null;
            Common.Models.Billing.Invoice       invoice     = null;
            ViewModels.Billing.InvoiceViewModel viewModel   = new ViewModels.Billing.InvoiceViewModel();

            using (IDbConnection conn = Data.Database.Instance.GetConnection())
            {
                invoice   = Data.Billing.Invoice.Get(id, conn, false);
                viewModel = Mapper.Map <ViewModels.Billing.InvoiceViewModel>(invoice);

                if (invoice.Matter != null)
                {
                    matter           = Data.Matters.Matter.Get(invoice.Matter.Id.Value, conn, false);
                    viewModel.Matter = Mapper.Map <ViewModels.Matters.MatterViewModel>(matter);
                    if (matter.DefaultBillingRate != null && matter.DefaultBillingRate.Id.HasValue)
                    {
                        billingRate = Data.Billing.BillingRate.Get(matter.DefaultBillingRate.Id.Value, conn, false);
                    }
                }

                invoice.BillTo = Data.Contacts.Contact.Get(invoice.BillTo.Id.Value, conn, false);

                Data.Billing.Invoice.ListInvoiceExpensesForInvoice(invoice.Id.Value, conn, false).ForEach(x =>
                {
                    ViewModels.Billing.InvoiceExpenseViewModel vm = Mapper.Map <ViewModels.Billing.InvoiceExpenseViewModel>(x);
                    vm.Expense = Mapper.Map <ViewModels.Billing.ExpenseViewModel>(
                        Data.Billing.Expense.Get(vm.Expense.Id.Value, conn, false));
                    viewModel.Expenses.Add(vm);
                });

                Data.Billing.Invoice.ListInvoiceFeesForInvoice(invoice.Id.Value, conn, false).ForEach(x =>
                {
                    ViewModels.Billing.InvoiceFeeViewModel vm = Mapper.Map <ViewModels.Billing.InvoiceFeeViewModel>(x);
                    vm.Fee = Mapper.Map <ViewModels.Billing.FeeViewModel>(
                        Data.Billing.Fee.Get(vm.Fee.Id.Value, conn, false));
                    viewModel.Fees.Add(vm);
                });

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

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

            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));
        }
        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 }));
        }