/// <summary>
        /// Gets invoice milestone details for invoice file generation
        /// </summary>
        /// <param name="invoiceHeaderVO">Header details</param>
        /// <param name="invoiceGLDetail">GL coding details</param>
        /// <param name="fromDate">from date</param>
        /// <param name="toDate">to date</param>
        /// <returns></returns>
        public MilestoneVO GetMilestoneDetails(InvoiceHeaderVO invoiceHeaderVO, InvoiceGLDetailVO invoiceGLDetails,
                                               DateTime fromDate, DateTime toDate)
        {
            Milestone milestones =
                mdbDataContext.Milestones.FirstOrDefault(m => m.ID == invoiceGLDetails.MilestoneId && !m.IsDeleted);
            //Where(m => m.ContractLineID == invoiceGlDetailVO.ContractLineId
            //           && m.ContractID == invoiceHeaderVO.ContractId
            //           && m.ContractMaintenance.ID == invoiceGlDetailVO.ContractMaintenanceId &&
            //           m.MilestoneStatusID == Convert.ToInt32(Constants.MilestoneStatus.IN_PROGRESS) // 4 In Progress
            //           && m.ContractMaintenance.IsGrouped == null &&
            //           (m.EstimatedDate >= fromDate &&
            //            m.EstimatedDate <= toDate)
            //           && !m.IsDeleted).ToList();

            //foreach (var milestone in milestones)
            //{
            MilestoneVO milestoneVO = new MilestoneVO(milestones);

            //}

            return(milestoneVO);

            //Get milestone details for contract & contract lines
            //List<Milestone> milestones = mdbDataContext.Milestones.
            //                                            Where(m => m.ContractLineID == invoiceGLDetail.ContractLineId
            //                                                       && m.ContractID == invoiceHeaderVO.ContractId
            //                                                       && m.ContractMaintenance.ID == invoiceGLDetail.ContractMaintenanceId &&
            //                                                       m.MilestoneStatusID == Convert.ToInt32(Constants.MilestoneStatus.IN_PROGRESS) // 4 In Progress
            //                                                       && m.ContractMaintenance.IsGrouped == null &&
            //                                                       (m.EstimatedDate >= fromDate &&
            //                                                        m.EstimatedDate <= toDate)
            //                                                       && !m.IsDeleted).ToList();

            //return milestones.Select(milestone => new MilestoneVO(milestone)).ToList();
        }
        /// <summary>
        /// Return contract line deatils based on contract maintenance id
        /// </summary>
        /// <param name="contractMaintenanceId">Contract maintenance id</param>
        /// <returns>Return contract line</returns>
        public InvoiceGLDetailVO GetContractLineBasedOnContractMaintenanceId(int contractMaintenanceId)
        {
            ContractMaintenance contractMaintenance = mdbDataContext.ContractMaintenances.FirstOrDefault(cm => cm.ID == contractMaintenanceId & !cm.IsDeleted);

            InvoiceGLDetailVO contractLineVO = new InvoiceGLDetailVO(contractMaintenance.ContractLine);

            return(contractLineVO);
        }
        /// <summary>
        /// Validate Job code is associated with customer or not
        /// </summary>
        /// <param name="invoiceHeaderVO">Invoice header value object</param>
        /// <param name="glDetail">General ledger details</param>
        /// <returns>if job code associated with customer then true else false</returns>
        private bool ValidateJobCode(InvoiceHeaderVO invoiceHeaderVO, InvoiceGLDetailVO glDetail)
        {
            JobCodeService jobCodeService = new JobCodeService();

            List <JobCodeVO> jobCodeList = jobCodeService.GetJobCodeList(invoiceHeaderVO.CompanyId,
                                                                         invoiceHeaderVO.InvoiceCustomerId);

            bool isJobCodeExist = jobCodeList.Any(x => x.Id == Convert.ToInt32(glDetail.JobCodeId));

            return(isJobCodeExist);
        }
        /// <summary>
        /// Create nominal line
        /// </summary>
        /// <param name="invoiceHeaderVO">Invoice header value object</param>
        /// <param name="nominalLine">Nominal line</param>
        /// <param name="milestone">Milestone object</param>
        private void CreateNominalLine(InvoiceHeaderVO invoiceHeaderVO, InvoiceGLDetailVO nominalLine,
                                       MilestoneVO milestone)
        {
            nominalLine.TaxCode          = invoiceHeaderVO.VatCode;
            nominalLine.Value            = milestone.Amount;
            nominalLine.RenewalStartDate = String.Format("{0:ddMMyyyy}",
                                                         milestone.RenewalStartDate.Value);
            nominalLine.RenewalEndDate   = String.Format("{0:ddMMyyyy}", milestone.RenewalEndDate.Value);
            nominalLine.ContractDetails  = invoiceHeaderVO.CompanyId == 159 ? "N,D," : "Y,D,";
            nominalLine.ContractDetails += nominalLine.RenewalStartDate + " to " +
                                           nominalLine.RenewalEndDate + ",M" + milestone.ID;

            nominalLine.GroupId           = milestone.GroupId;
            nominalLine.PeriodFrequencyId = milestone.PeriodFrequencyId;
        }
        /// <summary>
        /// Get general ledger details for invoice
        /// </summary>
        /// <param name="invoiceHeaderVO"></param>
        /// <returns></returns>
        public List <InvoiceGLDetailVO> GetInvoiceDetails(InvoiceHeaderVO invoiceHeaderVO, DateTime fromDate, DateTime toDate)
        {
            List <Milestone> milestones = mdbDataContext.Milestones.Where(m => m.ContractID == invoiceHeaderVO.ContractId &&
                                                                          m.MilestoneStatusID == Convert.ToInt32(Constants.MilestoneStatus.IN_PROGRESS) && // 4 In Progress
                                                                          m.ContractMaintenance.DocumentTypeID == invoiceHeaderVO.DocumentTypeID &&
                                                                          (m.EstimatedDate >= fromDate && m.EstimatedDate <= toDate) &&
                                                                          !m.IsDeleted).ToList();

            List <InvoiceGLDetailVO> invoiceGlDetailVos = new List <InvoiceGLDetailVO>();

            foreach (var item in milestones)
            {
                InvoiceGLDetailVO invoiceGlDetailVO = new InvoiceGLDetailVO(item);

                if (!invoiceGlDetailVos.Contains(invoiceGlDetailVO))
                {
                    invoiceGlDetailVos.Add(invoiceGlDetailVO);
                }
            }

            return(invoiceGlDetailVos);

            //List<ContractMaintenance> contractMaintenance = mdbDataContext.ContractMaintenances.Where(cm => cm.ContractID == invoiceHeaderVO.ContractId
            //                                                                                                 && cm.DocumentTypeID == invoiceHeaderVO.DocumentTypeID).ToList();

            //List<ContractLine> contractLines = new  List<ContractLine>();
            //foreach (var item in contractMaintenance)
            //{
            //    contractLines.Add(item.ContractLine);
            //}

            //Get contract line details for contracts
            //List<ContractLine> contractLines = mdbDataContext.ContractLines
            //                                                 .Where(
            //                                                     cl =>
            //                                                     cl.ContractID == invoiceHeaderVO.ContractId &&
            //                                                     !cl.IsDeleted)
            //                                                 .ToList();
            //return contractLines.Select(contractLine => new InvoiceGLDetailVO(contractLine)).ToList();
        }
        /// <summary>
        /// Process grouped billing lines with milestone
        /// </summary>
        /// <param name="invoiceDetails"></param>
        /// <param name="invoiceHeaderVO"></param>
        /// <param name="fromDate"></param>
        /// <param name="toDate"></param>
        /// <returns></returns>
        private List <InvoiceDetailVO> ProcessGroupedBillingLines(List <InvoiceGLDetailVO> invoiceDetails, InvoiceHeaderVO invoiceHeaderVO, DateTime fromDate,
                                                                  DateTime toDate)
        {
            List <InvoiceDetailVO> invoiceDetailVos = new List <InvoiceDetailVO>();

            List <MilestoneVO> milestoneVoList = approveMaintenanceDAL.GetGroupedMilestoneDetails(invoiceHeaderVO,
                                                                                                  invoiceDetails,
                                                                                                  fromDate, toDate);

            //Get milestone details by group
            var groupedMilestones = (from milestone in milestoneVoList
                                     select new
            {
                milestone.ContractMaintenanceID,
                milestone.ContractLineID,
                milestone.ID,
                milestone.GroupId,
                milestone.PeriodFrequencyId
            }).GroupBy(g => new { g.GroupId, g.PeriodFrequencyId }).ToList();

            // How many nonimal line per group
            foreach (var groupedMilestone in groupedMilestones)
            {
                InvoiceDetailVO          invoiceDetail  = new InvoiceDetailVO();
                List <InvoiceGLDetailVO> nominalLineVos = new List <InvoiceGLDetailVO>();

                int totalQty = 0;
                foreach (var item in groupedMilestone)
                {
                    InvoiceGLDetailVO nominalLine =
                        invoiceDetails.FirstOrDefault(c => c.ContractLineId == item.ContractLineID &&
                                                      c.ContractMaintenanceId == item.ContractMaintenanceID &&
                                                      c.MilestoneId == item.ID &&
                                                      c.GroupId == groupedMilestone.Key.GroupId &&
                                                      c.PeriodFrequencyId == groupedMilestone.Key.PeriodFrequencyId);

                    MilestoneVO milestone = milestoneVoList.FirstOrDefault(m => m.ID == item.ID &&
                                                                           m.GroupId == groupedMilestone.Key.GroupId &&
                                                                           m.PeriodFrequencyId == groupedMilestone.Key.PeriodFrequencyId);

                    if (milestone != null)
                    {
                        InvoiceGLDetailVO invoiceGlDetailVO = new InvoiceGLDetailVO(nominalLine);
                        CreateNominalLine(invoiceHeaderVO, invoiceGlDetailVO, milestone);

                        totalQty += milestone.QTY;
                        nominalLineVos.Add(invoiceGlDetailVO);
                    }
                }

                // Check how many coding lines are grouped based on period frequency and group id
                //var grpedMilestoneVo = milestoneVoList.Where(m => m.GroupId == groupedMilestone.Key.GroupId
                //                                                  &&
                //                                                  m.PeriodFrequencyId ==
                //                                                  groupedMilestone.Key.PeriodFrequencyId)
                //                                      .GroupBy(g => g.ContractMaintenanceID).ToList();



                //foreach (var nLine in grpedMilestoneVo)
                //{
                //    InvoiceGLDetailVO nominalLine =
                //        invoiceDetails.FirstOrDefault(c => c.ContractMaintenanceId == nLine.Key &&
                //                                           c.GroupId == groupedMilestone.Key.GroupId &&
                //                                           c.PeriodFrequencyId == groupedMilestone.Key.PeriodFrequencyId);

                //    InvoiceGLDetailVO invoiceGlDetailVO = new InvoiceGLDetailVO(nominalLine);

                //    //InvoiceGLDetailVO nominalLine =
                //    //    approveMaintenanceDAL.GetContractLineBasedOnContractMaintenanceId(nLine.Key);

                //    MilestoneVO milestone =
                //        milestoneVoList.FirstOrDefault(m => m.ContractLineID == invoiceGlDetailVO.ContractLineId
                //                                            && m.ContractMaintenanceID == nLine.Key &&
                //                                            m.IsGrouped == true
                //                                            && m.PeriodFrequencyId == groupedMilestone.Key.PeriodFrequencyId
                //                                            && m.GroupId == groupedMilestone.Key.GroupId);


                //    CreateNominalLine(invoiceHeaderVO, invoiceGlDetailVO, milestone);

                //    totalQty += milestone.QTY;
                //    nominalLineVos.Add(invoiceGlDetailVO);
                //}

                MilestoneVO defaultPrintingBillingLine =
                    milestoneVoList.FirstOrDefault(m => m.GroupId == groupedMilestone.Key.GroupId &&
                                                   m.PeriodFrequencyId == groupedMilestone.Key.PeriodFrequencyId &&
                                                   m.IsDefaultLineInGroup == true);

                //If default print line milestone not found in milestone list then get default milestone line database
                if (defaultPrintingBillingLine == null)
                {
                    MilestoneVO milestoneVO = approveMaintenanceDAL.GetDefaultBillingLine(nominalLineVos[0].ContractId,
                                                                                          nominalLineVos[0].GroupId,
                                                                                          nominalLineVos[0].PeriodFrequencyId,
                                                                                          fromDate, toDate);
                    if (milestoneVO == null)
                    {
                        string error = String.Format(Constants.MILESTONE_MISSING + "'" +
                                                     invoiceHeaderVO.ContractNumber + "',"
                                                     + "Company - '" + invoiceHeaderVO.CompanyId + "'");
                        if (!errorList.Contains(error))
                        {
                            errorList.Add(error);
                        }
                    }
                    else
                    {
                        defaultPrintingBillingLine = milestoneVO;

                        string billingLines = defaultPrintingBillingLine.MilestoneBillingLineVos.Aggregate(string.Empty,
                                                                                                           (current,
                                                                                                            billingLine) =>
                                                                                                           current +
                                                                                                           billingLine
                                                                                                           .LineText);

                        //Generate Billing line details for - extra line for invoice flat file
                        if (string.IsNullOrEmpty(billingLines))
                        {
                            string error =
                                String.Format(Constants.MISSING_BILLING_LINES + "'" + invoiceHeaderVO.ContractNumber + "',"
                                              + "Company - '" + invoiceHeaderVO.CompanyId + "'");

                            errorList.Add(error);
                        }
                    }
                }

                //To check defaultPrintingLine is not null
                if (defaultPrintingBillingLine != null)
                {
                    string billingLines = defaultPrintingBillingLine.MilestoneBillingLineVos.Aggregate(string.Empty,
                                                                                                       (current,
                                                                                                        billingLine) =>
                                                                                                       current +
                                                                                                       billingLine
                                                                                                       .LineText);

                    //Generate Billing line details for - extra line for invoice flat file
                    if (string.IsNullOrEmpty(billingLines))
                    {
                        string error =
                            String.Format(Constants.MISSING_BILLING_LINES + "'" + invoiceHeaderVO.ContractNumber + "',"
                                          + "Company - '" + invoiceHeaderVO.CompanyId + "'");

                        if (!errorList.Contains(error))
                        {
                            errorList.Add(error);
                        }
                    }

                    decimal amount = nominalLineVos.Sum(nLine => nLine.Value);

                    invoiceDetail.isCreaditInvoice = amount < 0;

                    InvoiceBillingLineVO invoiceBillingLine =
                        new InvoiceBillingLineVO(defaultPrintingBillingLine.MilestoneBillingLineVos);

                    invoiceBillingLine.VatCode   = invoiceHeaderVO.VatCode;
                    invoiceBillingLine.Amount    = amount;   //defaultPrintingBillingLine.Amount;
                    invoiceBillingLine.Qty       = totalQty; //defaultPrintingBillingLine.QTY;
                    invoiceBillingLine.UnitPrice =
                        Convert.ToDecimal(String.Format(Constants.STRING_FORMAT_FOR_NUMERIC_VALUE,
                                                        (amount / invoiceBillingLine.Qty)));

                    //Add nominal line
                    invoiceDetail.NominalLinesList = nominalLineVos;
                    // Add X line billing printing line
                    invoiceDetail.InvoiceBillingLines = invoiceBillingLine;

                    //Add N & X line details in header
                    invoiceDetailVos.Add(invoiceDetail);
                }
            }

            return(invoiceDetailVos);
        }
        /// <summary>
        /// Process invoice details - N & X line
        /// </summary>
        /// <param name="invoiceDetails">Invoice details object</param>
        /// <param name="invoiceHeaderVO">Invoice header object</param>
        /// <param name="fromDate">from date</param>
        /// <param name="toDate">to date</param>
        /// <returns></returns>
        private List <InvoiceDetailVO> ProcessInvoiceDetails(List <InvoiceGLDetailVO> invoiceDetails,
                                                             InvoiceHeaderVO invoiceHeaderVO, DateTime fromDate,
                                                             DateTime toDate)
        {
            var invoiceDetailVos = new List <InvoiceDetailVO>();

            //Process only grouped billing details/ milestone lines
            invoiceDetailVos.AddRange(ProcessGroupedBillingLines(invoiceDetails, invoiceHeaderVO, fromDate, toDate));


            // process line for ungrouped milestone & billing details
            foreach (var invoiceGlDetail in invoiceDetails)
            {
                if (invoiceGlDetail.IsGrouped != true)
                {
                    // Get milestone details
                    MilestoneVO milestoneVos = approveMaintenanceDAL.GetMilestoneDetails(invoiceHeaderVO,
                                                                                         invoiceGlDetail,
                                                                                         fromDate, toDate);

                    //foreach (var milestoneVo in milestoneVos)
                    //{
                    if (milestoneVos.IsGrouped == null || milestoneVos.IsGrouped == false)
                    {
                        InvoiceDetailVO invoiceDetailVO = new InvoiceDetailVO();

                        // Create clone object of GL line object
                        InvoiceGLDetailVO nominalLine = new InvoiceGLDetailVO(invoiceGlDetail);

                        if (ValidateJobCode(invoiceHeaderVO, nominalLine) == false)
                        {
                            //ARBS-144-to have customer name and customer code in error file
                            string error =
                                String.Format(Constants.JOB_CODE_MISSING + "'" + invoiceHeaderVO.ContractNumber +
                                              "', "
                                              + "Company - '" + invoiceHeaderVO.CompanyId + " - " +
                                              invoiceHeaderVO.CompanyName + " , Customer Name - " + invoiceHeaderVO.CustomerName + " , Customer Code - " + invoiceHeaderVO.CustomerCode + "'");
                            if (!errorList.Contains(error))
                            {
                                errorList.Add(error);
                            }
                            isValid = false;
                        }

                        CreateNominalLine(invoiceHeaderVO, nominalLine, milestoneVos);

                        //glDetail.TaxCode = invoiceHeaderVO.VatCode;
                        //glDetail.Value = milestoneVo.Amount;
                        //glDetail.RenewalStartDate = String.Format("{0:ddMMyyyy}",
                        //                                          milestoneVo.RenewalStartDate.Value);
                        //glDetail.RenewalEndDate = String.Format("{0:ddMMyyyy}", milestoneVo.RenewalEndDate.Value);
                        //glDetail.ContractDetails = invoiceHeaderVO.CompanyId == 159 ? "N,D," : "Y,D,";
                        //glDetail.ContractDetails += glDetail.RenewalStartDate + " to " +
                        //                            glDetail.RenewalEndDate + ",M" + milestoneVo.ID;

                        //Add GL details to invoice header
                        //invoiceDetailVO.InvoiceGlDetails = glDetail;

                        if (!invoiceDetailVO.NominalLinesList.Contains(nominalLine))
                        {
                            invoiceDetailVO.NominalLinesList.Add(nominalLine);
                        }

                        string billingLines = milestoneVos.MilestoneBillingLineVos.Aggregate(string.Empty,
                                                                                             (current, billingLine)
                                                                                             =>
                                                                                             current +
                                                                                             billingLine.LineText);

                        //Generate Billing line details for - extra line for invoice flat file
                        if (string.IsNullOrEmpty(billingLines))
                        {
                            string error = String.Format(Constants.MISSING_BILLING_LINES + "'" + invoiceHeaderVO.ContractNumber + "'," + "Company - '" + invoiceHeaderVO.CompanyId + "'");
                            if (!errorList.Contains(error))
                            {
                                errorList.Add(error);
                            }
                        }

                        InvoiceBillingLineVO invoiceBillingLine =
                            new InvoiceBillingLineVO(milestoneVos.MilestoneBillingLineVos);

                        invoiceBillingLine.VatCode   = invoiceHeaderVO.VatCode;
                        invoiceBillingLine.Amount    = milestoneVos.Amount;
                        invoiceBillingLine.Qty       = milestoneVos.QTY;
                        invoiceBillingLine.UnitPrice =
                            Convert.ToDecimal(String.Format(Constants.STRING_FORMAT_FOR_NUMERIC_VALUE,
                                                            (milestoneVos.Amount / invoiceBillingLine.Qty)));


                        invoiceDetailVO.isCreaditInvoice = nominalLine.Value < 0;

                        invoiceDetailVO.InvoiceBillingLines = invoiceBillingLine;

                        invoiceDetailVos.Add(invoiceDetailVO);
                        //}
                    }
                }
            }
            // Invoice details associated with header
            return(invoiceDetailVos);
        }