public virtual void RecalculateChangeOrders(PMProject project, ProjectBalance projectBalance, Dictionary <BudgetKeyTuple, PMBudgetEx> existingBudgetRecords)
        {
            var select = new PXSelect <PMChangeOrderBudget,
                                       Where <PMChangeOrderBudget.projectID, Equal <Required <PMChangeOrderBudget.projectID> >,
                                              And <PMChangeOrderBudget.released, Equal <True> > > >(this);

            foreach (PMChangeOrderBudget change in select.Select(project.ContractID))
            {
                BudgetKeyTuple key = GetKey(change);

                PMBudgetEx existing = null;
                if (existingBudgetRecords.TryGetValue(key, out existing))
                {
                    PMBudgetAccum budget = new PMBudgetAccum();
                    budget.ProjectID      = key.ProjectID;
                    budget.ProjectTaskID  = key.ProjectTaskID;
                    budget.AccountGroupID = key.AccountGroupID;
                    budget.InventoryID    = key.InventoryID;
                    budget.CostCodeID     = key.CostCodeID;

                    budget = Budget.Insert(budget);
                    budget.ChangeOrderAmount += change.Amount.GetValueOrDefault();
                    budget.RevisedAmount     += change.Amount.GetValueOrDefault();

                    var rollup = projectBalance.CalculateRollupQty <PMChangeOrderBudget>(change, existing);
                    if (rollup.Qty.GetValueOrDefault() != 0)
                    {
                        budget.ChangeOrderQty += change.Qty.GetValueOrDefault();
                        budget.RevisedQty     += change.Qty.GetValueOrDefault();
                    }
                }
                else
                {
                    PMAccountGroup accountGroup = null;
                    if (AccountGroups.TryGetValue(key.AccountGroupID, out accountGroup))
                    {
                        PMBudgetAccum budget = new PMBudgetAccum();
                        budget.ProjectID      = key.ProjectID;
                        budget.ProjectTaskID  = key.ProjectTaskID;
                        budget.AccountGroupID = key.AccountGroupID;
                        budget.InventoryID    = key.InventoryID;
                        budget.CostCodeID     = key.CostCodeID;
                        budget.Type           = accountGroup.IsExpense == true ? GL.AccountType.Expense : accountGroup.Type;

                        budget = Budget.Insert(budget);
                        budget.ChangeOrderAmount += change.Amount.GetValueOrDefault();
                        budget.RevisedAmount     += change.Amount.GetValueOrDefault();
                    }
                }
            }
        }
Beispiel #2
0
        public List <Batch> Release(JournalEntry je, PMRegister doc, out List <PMTask> allocTasks)
        {
            doc = OnBeforeRelease(doc);

            allocTasks = new List <PMTask>();

            List <Batch> batches = new List <Batch>();
            Dictionary <string, PMTask> tasksToAutoAllocate = new Dictionary <string, PMTask>();
            List <PMTran> sourceForAllocation = new List <PMTran>();
            Dictionary <string, List <TranInfo> > transByFinPeriod = GetTransByBranchAndFinPeriod(doc);

            Debug.Assert(transByFinPeriod.Count > 0, "Failed to select transactions by finperiod in PMRegister Release.");

            ProjectBalance pb = CreateProjectBalance();

            using (var ts = new PXTransactionScope())
            {
                foreach (KeyValuePair <string, List <TranInfo> > kv in transByFinPeriod)
                {
                    string[] parts    = kv.Key.Split('.');
                    int?     branchID = parts[0] == "0" ? null : (int?)int.Parse(parts[0]);

                    je.Clear(PXClearOption.ClearAll);

                    CurrencyInfo info = new CurrencyInfo();
                    info.CuryID      = parts[2];
                    info.CuryEffDate = Accessinfo.BusinessDate;
                    info             = je.currencyinfo.Insert(info);

                    Batch newbatch = new Batch();
                    newbatch.Module      = doc.Module;
                    newbatch.Status      = BatchStatus.Unposted;
                    newbatch.Released    = true;
                    newbatch.Hold        = false;
                    newbatch.BranchID    = branchID;
                    newbatch.FinPeriodID = parts[1];
                    newbatch.CuryID      = parts[2];
                    newbatch.CuryInfoID  = info.CuryInfoID;
                    newbatch.Description = doc.Description;
                    je.BatchModule.Insert(newbatch);

                    bool tranAdded = false;
                    foreach (TranInfo t in kv.Value)
                    {
                        bool isGL = false;

                        if (t.Tran.Released != true && t.Tran.IsNonGL != true && t.Project.BaseType == CT.CTPRType.Project &&
                            !string.IsNullOrEmpty(t.AccountGroup.Type) && t.AccountGroup.Type != PMAccountType.OffBalance && !ProjectDefaultAttribute.IsNonProject(t.Tran.ProjectID) &&
                            t.Tran.AccountID != null && t.Tran.SubID != null && t.Tran.OffsetAccountID != null && t.Tran.OffsetSubID != null)
                        {
                            GLTran tran1 = new GLTran();
                            tran1.TranDate      = t.Tran.Date;
                            tran1.TranPeriodID  = t.Tran.TranPeriodID;
                            tran1.SummPost      = false;
                            tran1.BranchID      = t.Tran.BranchID;
                            tran1.PMTranID      = t.Tran.TranID;
                            tran1.ProjectID     = t.Tran.ProjectID;
                            tran1.TaskID        = t.Tran.TaskID;
                            tran1.CostCodeID    = t.Tran.CostCodeID;
                            tran1.TranDesc      = t.Tran.Description;
                            tran1.ReferenceID   = t.Tran.BAccountID;
                            tran1.InventoryID   = t.Tran.InventoryID == PMInventorySelectorAttribute.EmptyInventoryID ? null : t.Tran.InventoryID;
                            tran1.Qty           = t.Tran.Qty;
                            tran1.UOM           = t.Tran.UOM;
                            tran1.TranType      = t.Tran.TranType;
                            tran1.CuryInfoID    = t.Tran.BaseCuryInfoID;
                            tran1.CuryCreditAmt = 0;
                            tran1.CreditAmt     = 0;
                            tran1.CuryDebitAmt  = t.Tran.TranCuryAmount;
                            tran1.DebitAmt      = t.Tran.Amount;
                            tran1.AccountID     = t.Tran.AccountID;
                            tran1.SubID         = t.Tran.SubID;
                            tran1.Released      = true;
                            je.GLTranModuleBatNbr.Insert(tran1);

                            GLTran tran2 = new GLTran();
                            tran2.TranDate      = t.Tran.Date;
                            tran2.TranPeriodID  = t.Tran.TranPeriodID;
                            tran2.SummPost      = false;
                            tran2.BranchID      = t.Tran.BranchID;
                            tran2.PMTranID      = t.Tran.TranID;
                            tran2.ProjectID     = t.OffsetAccountGroup.GroupID != null ? t.Tran.ProjectID : ProjectDefaultAttribute.NonProject();
                            tran2.TaskID        = t.OffsetAccountGroup.GroupID != null ? t.Tran.TaskID : null;
                            tran2.CostCodeID    = tran2.TaskID != null ? t.Tran.CostCodeID : null;
                            tran2.TranDesc      = t.Tran.Description;
                            tran2.ReferenceID   = t.Tran.BAccountID;
                            tran2.InventoryID   = t.Tran.InventoryID == PMInventorySelectorAttribute.EmptyInventoryID ? null : t.Tran.InventoryID;
                            tran2.Qty           = t.Tran.Qty;
                            tran2.UOM           = t.Tran.UOM;
                            tran2.TranType      = t.Tran.TranType;
                            tran2.CuryInfoID    = t.Tran.BaseCuryInfoID;
                            tran2.CuryCreditAmt = t.Tran.TranCuryAmount;
                            tran2.CreditAmt     = t.Tran.Amount;
                            tran2.CuryDebitAmt  = 0;
                            tran2.DebitAmt      = 0;
                            tran2.AccountID     = t.Tran.OffsetAccountID;
                            tran2.SubID         = t.Tran.OffsetSubID;
                            tran2.Released      = true;
                            je.GLTranModuleBatNbr.Insert(tran2);

                            tranAdded       = true;
                            isGL            = true;
                            t.Tran.BatchNbr = je.BatchModule.Current.BatchNbr;
                        }

                        if (!isGL)
                        {
                            if (t.Tran.AccountGroupID == null && t.Project.BaseType == CT.CTPRType.Project && t.Project.NonProject != true)
                            {
                                throw new PXException(Messages.AccountGroupIsRequired, doc.RefNbr);
                            }
                        }

                        if (t.Tran.ExcludedFromBalance != true)
                        {
                            JournalEntryProjectExt        xje      = je.GetExtension <JournalEntryProjectExt>();
                            IList <ProjectBalance.Result> balances = pb.Calculate(t.Project, t.Tran, t.Account, t.AccountGroup, t.OffsetAccount, t.OffsetAccountGroup);
                            foreach (ProjectBalance.Result balance in balances)
                            {
                                if (balance.Status != null)
                                {
                                    PMBudgetAccum ps = new PMBudgetAccum();
                                    ps.ProjectID      = balance.Status.ProjectID;
                                    ps.ProjectTaskID  = balance.Status.ProjectTaskID;
                                    ps.AccountGroupID = balance.Status.AccountGroupID;
                                    ps.InventoryID    = balance.Status.InventoryID;
                                    ps.CostCodeID     = balance.Status.CostCodeID;
                                    ps.UOM            = balance.Status.UOM;
                                    ps.IsProduction   = balance.Status.IsProduction;
                                    ps.Type           = balance.Status.Type;
                                    ps.Description    = balance.Status.Description;
                                    ps.CuryInfoID     = balance.Status.CuryInfoID;

                                    ps                   = xje.ProjectBudget.Insert(ps);
                                    ps.ActualQty        += balance.Status.ActualQty.GetValueOrDefault();
                                    ps.CuryActualAmount += balance.Status.CuryActualAmount.GetValueOrDefault();
                                    ps.ActualAmount     += balance.Status.ActualAmount.GetValueOrDefault();
                                }

                                if (balance.ForecastHistory != null)
                                {
                                    PMForecastHistoryAccum forecast = new PMForecastHistoryAccum();
                                    forecast.ProjectID      = balance.ForecastHistory.ProjectID;
                                    forecast.ProjectTaskID  = balance.ForecastHistory.ProjectTaskID;
                                    forecast.AccountGroupID = balance.ForecastHistory.AccountGroupID;
                                    forecast.InventoryID    = balance.ForecastHistory.InventoryID;
                                    forecast.CostCodeID     = balance.ForecastHistory.CostCodeID;
                                    forecast.PeriodID       = balance.ForecastHistory.PeriodID;

                                    forecast = xje.ForecastHistory.Insert(forecast);

                                    forecast.ActualQty        += balance.ForecastHistory.ActualQty.GetValueOrDefault();
                                    forecast.CuryActualAmount += balance.ForecastHistory.CuryActualAmount.GetValueOrDefault();
                                    forecast.ActualAmount     += balance.ForecastHistory.ActualAmount.GetValueOrDefault();
                                }

                                if (balance.TaskTotal != null)
                                {
                                    PMTaskTotal ta = new PMTaskTotal();
                                    ta.ProjectID = balance.TaskTotal.ProjectID;
                                    ta.TaskID    = balance.TaskTotal.TaskID;

                                    ta                = xje.ProjectTaskTotals.Insert(ta);
                                    ta.CuryAsset     += balance.TaskTotal.CuryAsset.GetValueOrDefault();
                                    ta.Asset         += balance.TaskTotal.Asset.GetValueOrDefault();
                                    ta.CuryLiability += balance.TaskTotal.CuryLiability.GetValueOrDefault();
                                    ta.Liability     += balance.TaskTotal.Liability.GetValueOrDefault();
                                    ta.CuryIncome    += balance.TaskTotal.CuryIncome.GetValueOrDefault();
                                    ta.Income        += balance.TaskTotal.Income.GetValueOrDefault();
                                    ta.CuryExpense   += balance.TaskTotal.CuryExpense.GetValueOrDefault();
                                    ta.Expense       += balance.TaskTotal.Expense.GetValueOrDefault();
                                }

                                if (!isGL)
                                {
                                    foreach (PMHistory item in balance.History)
                                    {
                                        PMHistoryAccum hist = new PMHistoryAccum();
                                        hist.ProjectID      = item.ProjectID;
                                        hist.ProjectTaskID  = item.ProjectTaskID;
                                        hist.AccountGroupID = item.AccountGroupID;
                                        hist.InventoryID    = item.InventoryID;
                                        hist.CostCodeID     = item.CostCodeID;
                                        hist.PeriodID       = item.PeriodID;
                                        hist.BranchID       = item.BranchID;

                                        hist = (PMHistoryAccum)je.Caches[typeof(PMHistoryAccum)].Insert(hist);
                                        hist.FinPTDCuryAmount  += item.FinPTDCuryAmount.GetValueOrDefault();
                                        hist.FinPTDAmount      += item.FinPTDAmount.GetValueOrDefault();
                                        hist.FinYTDCuryAmount  += item.FinYTDCuryAmount.GetValueOrDefault();
                                        hist.FinYTDAmount      += item.FinYTDAmount.GetValueOrDefault();
                                        hist.FinPTDQty         += item.FinPTDQty.GetValueOrDefault();
                                        hist.FinYTDQty         += item.FinYTDQty.GetValueOrDefault();
                                        hist.TranPTDCuryAmount += item.TranPTDCuryAmount.GetValueOrDefault();
                                        hist.TranPTDAmount     += item.TranPTDAmount.GetValueOrDefault();
                                        hist.TranYTDCuryAmount += item.TranYTDCuryAmount.GetValueOrDefault();
                                        hist.TranYTDAmount     += item.TranYTDAmount.GetValueOrDefault();
                                        hist.TranPTDQty        += item.TranPTDQty.GetValueOrDefault();
                                        hist.TranYTDQty        += item.TranYTDQty.GetValueOrDefault();
                                    }
                                }
                            }
                        }

                        AddToUnbilledSummary(je, t.Tran);

                        t.Tran.Released = true;
                        je.Caches[typeof(PMTran)].Update(t.Tran);

                        sourceForAllocation.Add(t.Tran);
                        if (t.Tran.Allocated != true && t.Tran.ExcludedFromAllocation != true && t.Project.AutoAllocate == true)
                        {
                            if (!tasksToAutoAllocate.ContainsKey(string.Format("{0}.{1}", t.Task.ProjectID, t.Task.TaskID)))
                            {
                                tasksToAutoAllocate.Add(string.Format("{0}.{1}", t.Task.ProjectID, t.Task.TaskID), t.Task);
                            }
                        }
                    }

                    if (tranAdded)
                    {
                        je.Save.Press();
                        batches.Add(je.BatchModule.Current);
                    }
                    else
                    {
                        je.Persist(typeof(PMTran), PXDBOperation.Update);
                        je.Persist(typeof(PMBudgetAccum), PXDBOperation.Insert);
                        je.Persist(typeof(PMForecastHistoryAccum), PXDBOperation.Insert);
                        je.Persist(typeof(PMTaskTotal), PXDBOperation.Insert);
                        je.Persist(typeof(PMTaskAllocTotalAccum), PXDBOperation.Insert);
                        je.Persist(typeof(PMHistoryAccum), PXDBOperation.Insert);                        //only non-gl balance is updated
                        je.Persist(typeof(PMUnbilledDailySummaryAccum), PXDBOperation.Insert);
                        je.SelectTimeStamp();
                    }
                }

                allocTasks.AddRange(tasksToAutoAllocate.Values);

                doc.Released = true;
                doc.Status   = PMRegister.status.Released;
                je.Caches[typeof(PMRegister)].Update(doc);

                je.Persist(typeof(PMTran), PXDBOperation.Update);
                je.Persist(typeof(PMRegister), PXDBOperation.Update);
                je.Persist(typeof(PMBudgetAccum), PXDBOperation.Insert);
                je.Persist(typeof(PMForecastHistoryAccum), PXDBOperation.Insert);
                je.Persist(typeof(PMTaskAllocTotalAccum), PXDBOperation.Insert);
                je.Persist(typeof(PMTaskTotal), PXDBOperation.Insert);


                ts.Complete();
            }

            return(batches);
        }
        public virtual void RecalculateDraftInvoicesAmount(PMProject project, ProjectBalance pb)
        {
            var selectProforma = new PXSelectJoinGroupBy <PMProformaLine,
                                                          InnerJoin <Account, On <PMProformaLine.accountID, Equal <Account.accountID> > >,
                                                          Where <PMProformaLine.projectID, Equal <Required <PMProformaLine.projectID> >,
                                                                 And <PMProformaLine.released, Equal <False> > >,
                                                          Aggregate <GroupBy <PMProformaLine.projectID,
                                                                              GroupBy <PMProformaLine.taskID,
                                                                                       GroupBy <PMProformaLine.accountID,
                                                                                                GroupBy <PMProformaLine.inventoryID,
                                                                                                         GroupBy <PMProformaLine.costCodeID,
                                                                                                                  Sum <PMProformaLine.lineTotal> > > > > > > >(this);

            var selectInvoice = new PXSelectJoinGroupBy <ARTran,
                                                         InnerJoin <Account, On <ARTran.accountID, Equal <Account.accountID> > >,
                                                         Where <ARTran.projectID, Equal <Required <ARTran.projectID> >,
                                                                And <ARTran.released, Equal <False> > >,
                                                         Aggregate <GroupBy <ARTran.tranType,
                                                                             GroupBy <ARTran.projectID,
                                                                                      GroupBy <ARTran.taskID,
                                                                                               GroupBy <ARTran.accountID,
                                                                                                        GroupBy <ARTran.inventoryID,
                                                                                                                 GroupBy <ARTran.costCodeID,
                                                                                                                          Sum <ARTran.tranAmt> > > > > > > > >(this);


            var selectRevenueBudget = new PXSelect <PMRevenueBudget,
                                                    Where <PMRevenueBudget.projectID, Equal <Required <PMRevenueBudget.projectID> >,
                                                           And <PMRevenueBudget.type, Equal <GL.AccountType.income> > > >(this);
            var revenueBudget = selectRevenueBudget.Select(project.ContractID);

            foreach (PXResult <PMProformaLine, Account> res in selectProforma.Select(project.ContractID))
            {
                PMProformaLine line    = (PMProformaLine)res;
                Account        account = (Account)res;

                int?inventoryID = PMInventorySelectorAttribute.EmptyInventoryID;

                foreach (PMRevenueBudget rev in revenueBudget)
                {
                    foreach (PMRevenueBudget budget in revenueBudget)
                    {
                        if (budget.TaskID == line.TaskID && line.InventoryID == budget.InventoryID)
                        {
                            inventoryID = line.InventoryID;
                        }
                    }
                }

                PMBudgetAccum invoiced = new PMBudgetAccum();
                invoiced.Type           = GL.AccountType.Income;
                invoiced.ProjectID      = line.ProjectID;
                invoiced.ProjectTaskID  = line.TaskID;
                invoiced.AccountGroupID = account.AccountGroupID;
                invoiced.InventoryID    = inventoryID;
                invoiced.CostCodeID     = line.CostCodeID.GetValueOrDefault(CostCodeAttribute.GetDefaultCostCode());

                invoiced = Budget.Insert(invoiced);
                invoiced.InvoicedAmount += line.LineTotal.GetValueOrDefault();

                if (line.IsPrepayment == true)
                {
                    invoiced.PrepaymentInvoiced += line.LineTotal.GetValueOrDefault();
                }
            }

            foreach (PXResult <ARTran, Account> res in selectInvoice.Select(project.ContractID))
            {
                ARTran  line    = (ARTran)res;
                Account account = (Account)res;

                int?inventoryID = PMInventorySelectorAttribute.EmptyInventoryID;

                foreach (PMRevenueBudget rev in revenueBudget)
                {
                    foreach (PMRevenueBudget budget in revenueBudget)
                    {
                        if (budget.TaskID == line.TaskID && line.InventoryID == budget.InventoryID)
                        {
                            inventoryID = line.InventoryID;
                        }
                    }
                }

                PMBudgetAccum invoiced = new PMBudgetAccum();
                invoiced.Type           = GL.AccountType.Income;
                invoiced.ProjectID      = line.ProjectID;
                invoiced.ProjectTaskID  = line.TaskID;
                invoiced.AccountGroupID = account.AccountGroupID;
                invoiced.InventoryID    = inventoryID;
                invoiced.CostCodeID     = line.CostCodeID.GetValueOrDefault(CostCodeAttribute.GetDefaultCostCode());

                invoiced = Budget.Insert(invoiced);
                invoiced.InvoicedAmount += line.TranAmt.GetValueOrDefault() * ARDocType.SignAmount(line.TranType);
            }
        }
        public virtual void ProcessTransaction(PMProject project, PXResult <PMTran, Account, OffsetAccount, PMAccountGroup, OffsetPMAccountGroup> res, ProjectBalance pb)
        {
            PMTran               tran      = (PMTran)res;
            Account              acc       = (Account)res;
            PMAccountGroup       ag        = (PMAccountGroup)res;
            OffsetAccount        offsetAcc = (OffsetAccount)res;
            OffsetPMAccountGroup offsetAg  = (OffsetPMAccountGroup)res;

            IList <ProjectBalance.Result> balances = pb.Calculate(project, tran, acc, ag, offsetAcc, offsetAg);

            foreach (ProjectBalance.Result balance in balances)
            {
                if (balance.Status != null)
                {
                    PMBudgetAccum ps = new PMBudgetAccum();
                    ps.ProjectID      = balance.Status.ProjectID;
                    ps.ProjectTaskID  = balance.Status.ProjectTaskID;
                    ps.AccountGroupID = balance.Status.AccountGroupID;
                    ps.InventoryID    = balance.Status.InventoryID;
                    ps.CostCodeID     = balance.Status.CostCodeID;
                    ps.UOM            = balance.Status.UOM;
                    ps.IsProduction   = balance.Status.IsProduction;
                    ps.Type           = balance.Status.Type;
                    ps.Description    = balance.Status.Description;

                    ps = Budget.Insert(ps);

                    ps.ActualQty    += balance.Status.ActualQty.GetValueOrDefault();
                    ps.ActualAmount += balance.Status.ActualAmount.GetValueOrDefault();
                }

                if (balance.TaskTotal != null)
                {
                    PMTaskTotal ta = new PMTaskTotal();
                    ta.ProjectID = balance.TaskTotal.ProjectID;
                    ta.TaskID    = balance.TaskTotal.TaskID;

                    ta            = TaskTotals.Insert(ta);
                    ta.Asset     += balance.TaskTotal.Asset.GetValueOrDefault();
                    ta.Liability += balance.TaskTotal.Liability.GetValueOrDefault();
                    ta.Income    += balance.TaskTotal.Income.GetValueOrDefault();
                    ta.Expense   += balance.TaskTotal.Expense.GetValueOrDefault();
                }


                foreach (PMHistory item in balance.History)
                {
                    PMHistoryAccum hist = new PMHistoryAccum();
                    hist.ProjectID      = item.ProjectID;
                    hist.ProjectTaskID  = item.ProjectTaskID;
                    hist.AccountGroupID = item.AccountGroupID;
                    hist.InventoryID    = item.InventoryID;
                    hist.CostCodeID     = item.CostCodeID;
                    hist.PeriodID       = item.PeriodID;

                    hist = History.Insert(hist);
                    hist.FinPTDAmount  += item.FinPTDAmount.GetValueOrDefault();
                    hist.FinYTDAmount  += item.FinYTDAmount.GetValueOrDefault();
                    hist.FinPTDQty     += item.FinPTDQty.GetValueOrDefault();
                    hist.FinYTDQty     += item.FinYTDQty.GetValueOrDefault();
                    hist.TranPTDAmount += item.TranPTDAmount.GetValueOrDefault();
                    hist.TranYTDAmount += item.TranYTDAmount.GetValueOrDefault();
                    hist.TranPTDQty    += item.TranPTDQty.GetValueOrDefault();
                    hist.TranYTDQty    += item.TranYTDQty.GetValueOrDefault();
                }
            }
        }
        public virtual void RunProjectBalanceVerification(PMProject project, PMValidationFilter options)
        {
            InitAccountGroup();

            PXDatabase.Delete <PMTaskTotal>(new PXDataFieldRestrict(typeof(PMTaskTotal.projectID).Name, PXDbType.Int, 4, project.ContractID, PXComp.EQ));
            PXDatabase.Delete <PMTaskAllocTotal>(new PXDataFieldRestrict(typeof(PMTaskAllocTotal.projectID).Name, PXDbType.Int, 4, project.ContractID, PXComp.EQ));
            PXDatabase.Delete <PMHistory>(new PXDataFieldRestrict(typeof(PMHistory.projectID).Name, PXDbType.Int, 4, project.ContractID, PXComp.EQ));
            PXDatabase.Delete <PMCommitment>(new PXDataFieldRestrict(typeof(PMCommitment.projectID).Name, PXDbType.Int, 4, project.ContractID, PXComp.EQ),
                                             new PXDataFieldRestrict(typeof(PMCommitment.type).Name, PXDbType.Char, 1, PMCommitmentType.Internal, PXComp.EQ));

            if (options.RecalculateUnbilledSummary == true)
            {
                PXDatabase.Delete <PMUnbilledDailySummary>(new PXDataFieldRestrict(typeof(PMUnbilledDailySummary.projectID).Name, PXDbType.Int, 4, project.ContractID, PXComp.EQ));
            }

            ProjectBalance pb = CreateProjectBalance();

            Dictionary <BudgetKeyTuple, PMBudgetEx> existingBudgetRecords = new Dictionary <BudgetKeyTuple, PMBudgetEx>();

            if (options.RecalculateChangeOrders == true && project.ChangeOrderWorkflow == true)
            {
                var selectBudget = new PXSelect <PMBudgetEx, Where <PMBudgetEx.projectID, Equal <Required <PMBudgetEx.projectID> > > >(this);
                using (new PXFieldScope(selectBudget.View, typeof(PMBudgetEx.projectID), typeof(PMBudgetEx.projectTaskID)
                                        , typeof(PMBudgetEx.accountGroupID), typeof(PMBudgetEx.inventoryID), typeof(PMBudgetEx.costCodeID)
                                        , typeof(PMBudgetEx.uOM), typeof(PMBudgetEx.qty), typeof(PMBudgetEx.amount)))
                {
                    foreach (PMBudgetEx record in selectBudget.Select(project.ContractID))
                    {
                        existingBudgetRecords.Add(GetKey(record), record);

                        List <PXDataFieldParam> list = BuildBudgetClearCommandWithChangeOrders(options, record);
                        PXDatabase.Update <PMBudget>(list.ToArray());
                    }
                }
            }
            else
            {
                HashSet <int> clearedAccountGroups = new HashSet <int>();
                var           selectBudget         = new PXSelect <PMBudgetEx, Where <PMBudgetEx.projectID, Equal <Required <PMBudgetEx.projectID> > > >(this);
                using (new PXFieldScope(selectBudget.View, typeof(PMBudgetEx.projectID), typeof(PMBudgetEx.projectTaskID)
                                        , typeof(PMBudgetEx.accountGroupID), typeof(PMBudgetEx.inventoryID), typeof(PMBudgetEx.costCodeID)
                                        , typeof(PMBudgetEx.uOM)))
                {
                    foreach (PMBudgetEx record in selectBudget.Select(project.ContractID))
                    {
                        existingBudgetRecords.Add(GetKey(record), record);

                        if (!clearedAccountGroups.Contains(record.AccountGroupID.Value))
                        {
                            List <PXDataFieldParam> list = BuildBudgetClearCommand(options, record);
                            PXDatabase.Update <PMBudget>(list.ToArray());
                            clearedAccountGroups.Add(record.AccountGroupID.Value);
                        }
                    }
                }
            }

            PXSelectBase <PMTran> select = null;

            if (options.RecalculateUnbilledSummary == true)
            {
                select = new PXSelectJoinGroupBy <PMTran,
                                                  LeftJoin <Account, On <PMTran.accountID, Equal <Account.accountID> >,
                                                            LeftJoin <OffsetAccount, On <PMTran.offsetAccountID, Equal <OffsetAccount.accountID> >,
                                                                      LeftJoin <PMAccountGroup, On <PMAccountGroup.groupID, Equal <Account.accountGroupID> >,
                                                                                LeftJoin <OffsetPMAccountGroup, On <OffsetPMAccountGroup.groupID, Equal <OffsetAccount.accountGroupID> > > > > >,
                                                  Where <PMTran.projectID, Equal <Required <PMTran.projectID> >,
                                                         And <PMTran.released, Equal <True> > >,
                                                  Aggregate <GroupBy <PMTran.tranType,
                                                                      GroupBy <PMTran.finPeriodID,
                                                                               GroupBy <PMTran.tranPeriodID,
                                                                                        GroupBy <PMTran.projectID,
                                                                                                 GroupBy <PMTran.taskID,
                                                                                                          GroupBy <PMTran.inventoryID,
                                                                                                                   GroupBy <PMTran.costCodeID,
                                                                                                                            GroupBy <PMTran.date,
                                                                                                                                     GroupBy <PMTran.accountID,
                                                                                                                                              GroupBy <PMTran.accountGroupID,
                                                                                                                                                       GroupBy <PMTran.offsetAccountID,
                                                                                                                                                                GroupBy <PMTran.offsetAccountGroupID,
                                                                                                                                                                         GroupBy <PMTran.uOM,
                                                                                                                                                                                  GroupBy <PMTran.released,
                                                                                                                                                                                           GroupBy <PMTran.remainderOfTranID,
                                                                                                                                                                                                    GroupBy <PMTran.duplicateOfTranID,
                                                                                                                                                                                                             Sum <PMTran.qty,
                                                                                                                                                                                                                  Sum <PMTran.amount,
                                                                                                                                                                                                                       Max <PMTran.billable,
                                                                                                                                                                                                                            GroupBy <PMTran.billed,
                                                                                                                                                                                                                                     GroupBy <PMTran.reversed> > > > > > > > > > > > > > > > > > > > > > >(this);
            }
            else
            {
                select = new PXSelectJoinGroupBy <PMTran,
                                                  LeftJoin <Account, On <PMTran.accountID, Equal <Account.accountID> >,
                                                            LeftJoin <OffsetAccount, On <PMTran.offsetAccountID, Equal <OffsetAccount.accountID> >,
                                                                      LeftJoin <PMAccountGroup, On <PMAccountGroup.groupID, Equal <Account.accountGroupID> >,
                                                                                LeftJoin <OffsetPMAccountGroup, On <OffsetPMAccountGroup.groupID, Equal <OffsetAccount.accountGroupID> > > > > >,
                                                  Where <PMTran.projectID, Equal <Required <PMTran.projectID> >,
                                                         And <PMTran.released, Equal <True> > >,
                                                  Aggregate <GroupBy <PMTran.tranType,
                                                                      GroupBy <PMTran.finPeriodID,
                                                                               GroupBy <PMTran.tranPeriodID,
                                                                                        GroupBy <PMTran.projectID,
                                                                                                 GroupBy <PMTran.taskID,
                                                                                                          GroupBy <PMTran.inventoryID,
                                                                                                                   GroupBy <PMTran.costCodeID,
                                                                                                                            GroupBy <PMTran.accountID,
                                                                                                                                     GroupBy <PMTran.accountGroupID,
                                                                                                                                              GroupBy <PMTran.offsetAccountID,
                                                                                                                                                       GroupBy <PMTran.offsetAccountGroupID,
                                                                                                                                                                GroupBy <PMTran.uOM,
                                                                                                                                                                         GroupBy <PMTran.released,
                                                                                                                                                                                  GroupBy <PMTran.remainderOfTranID,
                                                                                                                                                                                           GroupBy <PMTran.duplicateOfTranID,
                                                                                                                                                                                                    Sum <PMTran.qty,
                                                                                                                                                                                                         Sum <PMTran.amount> > > > > > > > > > > > > > > > > > >(this);
            }

            foreach (PXResult <PMTran, Account, OffsetAccount, PMAccountGroup, OffsetPMAccountGroup> res in select.Select(project.ContractID))
            {
                PMTran tran = (PMTran)res;

                RegisterReleaseProcess.AddToUnbilledSummary(this, tran);

                //suppose we have allocated unbilled 100 - unearned 100
                //during billing we reduced the amount to 80.
                //as a result of this. only 80 will be reversed. leaving 20 on the unbilled.
                //plus a remainder transaction will be generated. (if we allow this remainder to update balance it will add additional 20 to the unbilled.)
                if (tran.RemainderOfTranID != null)
                {
                    continue;                     //skip remainder transactions.
                }
                ProcessTransaction(project, res, pb);
            }

            RebuildAllocationTotals(project);

            if (options.RebuildCommitments == true)
            {
                ProcessPOCommitments(project);
                ProcessSOCommitments(project);
                ProcessExternalCommitments(project);
            }

            if (options.RecalculateDraftInvoicesAmount == true)
            {
                RecalculateDraftInvoicesAmount(project, pb);
            }

            if (options.RecalculateChangeOrders == true && project.ChangeOrderWorkflow == true)
            {
                RecalculateChangeOrders(project, pb, existingBudgetRecords);
            }

            InitCostCodeOnModifiedEntities();
        }
        public virtual void RunProjectBalanceVerification(PMProject project, PMValidationFilter options)
        {
            InitAccountGroup();

            PXDatabase.Delete <PMTaskTotal>(new PXDataFieldRestrict(typeof(PMTaskTotal.projectID).Name, PXDbType.Int, 4, project.ContractID, PXComp.EQ));
            PXDatabase.Delete <PMTaskAllocTotal>(new PXDataFieldRestrict(typeof(PMTaskAllocTotal.projectID).Name, PXDbType.Int, 4, project.ContractID, PXComp.EQ));
            PXDatabase.Delete <PMHistory>(new PXDataFieldRestrict(typeof(PMHistory.projectID).Name, PXDbType.Int, 4, project.ContractID, PXComp.EQ));
            PXDatabase.Delete <PMCommitment>(new PXDataFieldRestrict(typeof(PMCommitment.projectID).Name, PXDbType.Int, 4, project.ContractID, PXComp.EQ),
                                             new PXDataFieldRestrict(typeof(PMCommitment.type).Name, PXDbType.Char, 1, PMCommitmentType.Internal, PXComp.EQ));

            if (options.RecalculateUnbilledSummary == true)
            {
                PXDatabase.Delete <PMUnbilledDailySummary>(new PXDataFieldRestrict(typeof(PMUnbilledDailySummary.projectID).Name, PXDbType.Int, 4, project.ContractID, PXComp.EQ));
            }

            ProjectBalance pb = CreateProjectBalance();

            var selectAggregateBudget = new PXSelectGroupBy <PMBudgetEx, Where <PMBudgetEx.projectID, Equal <Required <PMBudgetEx.projectID> > >,
                                                             Aggregate <GroupBy <PMBudgetEx.projectID, GroupBy <PMBudgetEx.accountGroupID> > > >(this);

            foreach (PMBudgetEx status in selectAggregateBudget.Select(project.ContractID))
            {
                if (options.RecalculateDraftInvoicesAmount == true)
                {
                    PXDatabase.Update <PMBudget>(
                        new PXDataFieldRestrict(typeof(PMBudget.projectID).Name, PXDbType.Int, 4, project.ContractID, PXComp.EQ),
                        new PXDataFieldRestrict(typeof(PMBudget.accountGroupID).Name, PXDbType.Int, 4, status.AccountGroupID, PXComp.EQ),
                        new PXDataFieldAssign(typeof(PMBudget.type).Name, PXDbType.Char, 1, GetAccountGroupType(status.AccountGroupID)),
                        new PXDataFieldAssign(typeof(PMBudget.invoicedAmount).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.actualAmount).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.actualQty).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.committedAmount).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.committedQty).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.committedOpenAmount).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.committedOpenQty).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.committedReceivedQty).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.committedInvoicedAmount).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.committedInvoicedQty).Name, PXDbType.Decimal, 0m)
                        );
                }
                else
                {
                    PXDatabase.Update <PMBudget>(
                        new PXDataFieldRestrict(typeof(PMBudget.projectID).Name, PXDbType.Int, 4, project.ContractID, PXComp.EQ),
                        new PXDataFieldRestrict(typeof(PMBudget.accountGroupID).Name, PXDbType.Int, 4, status.AccountGroupID, PXComp.EQ),
                        new PXDataFieldAssign(typeof(PMBudget.type).Name, PXDbType.Char, 1, GetAccountGroupType(status.AccountGroupID)),
                        new PXDataFieldAssign(typeof(PMBudget.actualAmount).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.actualQty).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.committedAmount).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.committedQty).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.committedOpenAmount).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.committedOpenQty).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.committedReceivedQty).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.committedInvoicedAmount).Name, PXDbType.Decimal, 0m),
                        new PXDataFieldAssign(typeof(PMBudget.committedInvoicedQty).Name, PXDbType.Decimal, 0m)
                        );
                }
            }

            PXSelectBase <PMTran> select = null;

            if (options.RecalculateUnbilledSummary == true)
            {
                select = new PXSelectJoinGroupBy <PMTran,
                                                  LeftJoin <Account, On <PMTran.accountID, Equal <Account.accountID> >,
                                                            LeftJoin <OffsetAccount, On <PMTran.offsetAccountID, Equal <OffsetAccount.accountID> >,
                                                                      LeftJoin <PMAccountGroup, On <PMAccountGroup.groupID, Equal <Account.accountGroupID> >,
                                                                                LeftJoin <OffsetPMAccountGroup, On <OffsetPMAccountGroup.groupID, Equal <OffsetAccount.accountGroupID> > > > > >,
                                                  Where <PMTran.projectID, Equal <Required <PMTran.projectID> >,
                                                         And <PMTran.released, Equal <True> > >,
                                                  Aggregate <GroupBy <PMTran.tranType,
                                                                      GroupBy <PMTran.finPeriodID,
                                                                               GroupBy <PMTran.tranPeriodID,
                                                                                        GroupBy <PMTran.projectID,
                                                                                                 GroupBy <PMTran.taskID,
                                                                                                          GroupBy <PMTran.inventoryID,
                                                                                                                   GroupBy <PMTran.costCodeID,
                                                                                                                            GroupBy <PMTran.date,
                                                                                                                                     GroupBy <PMTran.accountID,
                                                                                                                                              GroupBy <PMTran.accountGroupID,
                                                                                                                                                       GroupBy <PMTran.offsetAccountID,
                                                                                                                                                                GroupBy <PMTran.offsetAccountGroupID,
                                                                                                                                                                         GroupBy <PMTran.uOM,
                                                                                                                                                                                  GroupBy <PMTran.released,
                                                                                                                                                                                           GroupBy <PMTran.remainderOfTranID,
                                                                                                                                                                                                    Sum <PMTran.qty,
                                                                                                                                                                                                         Sum <PMTran.amount,
                                                                                                                                                                                                              Max <PMTran.billable,
                                                                                                                                                                                                                   GroupBy <PMTran.billed,
                                                                                                                                                                                                                            GroupBy <PMTran.reversed> > > > > > > > > > > > > > > > > > > > > >(this);
            }
            else
            {
                select = new PXSelectJoinGroupBy <PMTran,
                                                  LeftJoin <Account, On <PMTran.accountID, Equal <Account.accountID> >,
                                                            LeftJoin <OffsetAccount, On <PMTran.offsetAccountID, Equal <OffsetAccount.accountID> >,
                                                                      LeftJoin <PMAccountGroup, On <PMAccountGroup.groupID, Equal <Account.accountGroupID> >,
                                                                                LeftJoin <OffsetPMAccountGroup, On <OffsetPMAccountGroup.groupID, Equal <OffsetAccount.accountGroupID> > > > > >,
                                                  Where <PMTran.projectID, Equal <Required <PMTran.projectID> >,
                                                         And <PMTran.released, Equal <True> > >,
                                                  Aggregate <GroupBy <PMTran.tranType,
                                                                      GroupBy <PMTran.finPeriodID,
                                                                               GroupBy <PMTran.tranPeriodID,
                                                                                        GroupBy <PMTran.projectID,
                                                                                                 GroupBy <PMTran.taskID,
                                                                                                          GroupBy <PMTran.inventoryID,
                                                                                                                   GroupBy <PMTran.costCodeID,
                                                                                                                            GroupBy <PMTran.accountID,
                                                                                                                                     GroupBy <PMTran.accountGroupID,
                                                                                                                                              GroupBy <PMTran.offsetAccountID,
                                                                                                                                                       GroupBy <PMTran.offsetAccountGroupID,
                                                                                                                                                                GroupBy <PMTran.uOM,
                                                                                                                                                                         GroupBy <PMTran.released,
                                                                                                                                                                                  GroupBy <PMTran.remainderOfTranID,
                                                                                                                                                                                           Sum <PMTran.qty,
                                                                                                                                                                                                Sum <PMTran.amount> > > > > > > > > > > > > > > > > >(this);
            }

            foreach (PXResult <PMTran, Account, OffsetAccount, PMAccountGroup, OffsetPMAccountGroup> res in select.Select(project.ContractID))
            {
                PMTran tran = (PMTran)res;

                RegisterReleaseProcess.AddToUnbilledSummary(this, tran);

                //suppose we have allocated unbilled 100 - unearned 100
                //during billing we reduced the amount to 80.
                //as a result of this. only 80 will be reversed. leaving 20 on the unbilled.
                //plus a remainder transaction will be generated. (if we allow this remainder to update balance it will add additional 20 to the unbilled.)
                if (tran.RemainderOfTranID != null)
                {
                    continue;                     //skip remainder transactions.
                }
                ProcessTransaction(res, pb);
            }

            RebuildAllocationTotals(project);

            if (options.RebuildCommitments == true)
            {
                ProcessPOCommitments(project);
                ProcessSOCommitments(project);
                ProcessExternalCommitments(project);
            }

            if (options.RecalculateDraftInvoicesAmount == true)
            {
                RecalculateDraftInvoicesAmount(project, pb);
            }
        }