public List <PXDataFieldParam> BuildBudgetClearCommand(PMValidationFilter options, PMBudgetEx status)
        {
            List <PXDataFieldParam> list = new List <PXDataFieldParam>();

            list.Add(new PXDataFieldRestrict(typeof(PMBudget.projectID).Name, PXDbType.Int, 4, status.ProjectID, PXComp.EQ));
            list.Add(new PXDataFieldRestrict(typeof(PMBudget.accountGroupID).Name, PXDbType.Int, 4, status.AccountGroupID, PXComp.EQ));

            list.Add(new PXDataFieldAssign(typeof(PMBudget.type).Name, PXDbType.Char, 1, GetAccountGroupType(status.AccountGroupID)));
            list.Add(new PXDataFieldAssign(typeof(PMBudget.actualAmount).Name, PXDbType.Decimal, 0m));
            list.Add(new PXDataFieldAssign(typeof(PMBudget.actualQty).Name, PXDbType.Decimal, 0m));

            if (options.RebuildCommitments == true)
            {
                list.Add(new PXDataFieldAssign(typeof(PMBudget.committedAmount).Name, PXDbType.Decimal, 0m));
                list.Add(new PXDataFieldAssign(typeof(PMBudget.committedQty).Name, PXDbType.Decimal, 0m));
                list.Add(new PXDataFieldAssign(typeof(PMBudget.committedOpenAmount).Name, PXDbType.Decimal, 0m));
                list.Add(new PXDataFieldAssign(typeof(PMBudget.committedOpenQty).Name, PXDbType.Decimal, 0m));
                list.Add(new PXDataFieldAssign(typeof(PMBudget.committedReceivedQty).Name, PXDbType.Decimal, 0m));
                list.Add(new PXDataFieldAssign(typeof(PMBudget.committedInvoicedAmount).Name, PXDbType.Decimal, 0m));
                list.Add(new PXDataFieldAssign(typeof(PMBudget.committedInvoicedQty).Name, PXDbType.Decimal, 0m));
                list.Add(new PXDataFieldAssign(typeof(PMBudget.committedOrigQty).Name, PXDbType.Decimal, 0m));
                list.Add(new PXDataFieldAssign(typeof(PMBudget.committedOrigAmount).Name, PXDbType.Decimal, 0m));
            }

            if (options.RecalculateDraftInvoicesAmount == true)
            {
                list.Add(new PXDataFieldAssign(typeof(PMBudget.invoicedAmount).Name, PXDbType.Decimal, 0m));
            }

            return(list);
        }
        protected virtual void PMValidationFilter_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
        {
            PMValidationFilter filter = Filter.Current;

            Items.SetProcessDelegate <ProjectBalanceValidationProcess>(
                delegate(ProjectBalanceValidationProcess graph, PMProject item)
            {
                graph.Clear();
                graph.RunProjectBalanceVerification(item, filter);
                graph.Actions.PressSave();
            });
        }
        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);
            }
        }