public virtual void CreateSingleSchedule(AR.Standalone.ARCashSale originalDocument, Amount lineTotal, int?defScheduleID, bool isDraft)
        {
            DRScheduleParameters scheduleParameters = GetSingleScheduleParameters(originalDocument);

            CreateSingleSchedule <AR.Standalone.ARCashSale>(originalDocument, lineTotal, defScheduleID, isDraft, scheduleParameters);
        }
        private void CreateSingleSchedule <T>(T originalDocument, Amount lineTotal, int?DefScheduleID, bool isDraft, DRScheduleParameters scheduleParameters)
            where T : ARRegister
        {
            ARSetup arSetup = PXSelect <ARSetup> .Select(this);

            DRSchedule existingSchedule = PXSelect <
                DRSchedule,
                Where <
                    DRSchedule.module, Equal <BatchModule.moduleAR>,
                    And <DRSchedule.docType, Equal <Required <ARRegister.docType> >,
                         And <DRSchedule.refNbr, Equal <Required <ARRegister.refNbr> > > > > >
                                          .SelectSingleBound(this, null, originalDocument.DocType, originalDocument.RefNbr, 1);

            if (existingSchedule?.LineNbr != null)
            {
                throw new PXException(Messages.CantCompleteBecauseASC606FeatureIsEnabled);
            }

            if (DefScheduleID == null)
            {
                Location location = PXSelect <Location, Where <Location.locationID, Equal <Required <DRSchedule.bAccountLocID> > > > .SelectSingleBound(this, null, scheduleParameters.BAccountLocID);

                CurrencyInfo currencyInfo = PXSelect <CurrencyInfo, Where <CurrencyInfo.curyInfoID, Equal <Required <DRSchedule.curyInfoID> > > > .SelectSingleBound(this, null, scheduleParameters.CuryInfoID);

                SingleScheduleCreator scheduleCreator = new SingleScheduleCreator(
                    this, new ARSubaccountProvider(this), this, this, this, this, this, FinPeriodRepository,
                    roundingFunction: x => PXDBCurrencyAttribute.Round(Schedule.Cache, Schedule.Current, x, CMPrecision.TRANCURY),
                    branchID: originalDocument.BranchID, isDraft: isDraft, location: location, currencyInfo: currencyInfo);

                if (existingSchedule == null)
                {
                    scheduleCreator.CreateOriginalSchedule(
                        scheduleParameters,
                        lineTotal);
                }
                else
                {
                    scheduleCreator.ReevaluateSchedule(
                        existingSchedule,
                        scheduleParameters,
                        lineTotal,
                        attachedToOriginalSchedule: false);
                }
            }
            else
            {
                if (originalDocument.DocType == ARDocType.CreditMemo || originalDocument.DocType == ARDocType.DebitMemo)
                {
                    bool accountForPostedTransactions = originalDocument.DocType == ARDocType.CreditMemo;

                    if (existingSchedule == null)
                    {
                        CreateRelatedSingleSchedule(scheduleParameters, DefScheduleID, lineTotal, isDraft, accountForPostedTransactions);
                    }
                    else
                    {
                        Location location = PXSelect <Location, Where <Location.locationID, Equal <Required <DRSchedule.bAccountLocID> > > > .SelectSingleBound(this, null, scheduleParameters.BAccountLocID);

                        CurrencyInfo currencyInfo = PXSelect <CurrencyInfo, Where <CurrencyInfo.curyInfoID, Equal <Required <DRSchedule.curyInfoID> > > > .SelectSingleBound(this, null, scheduleParameters.CuryInfoID);

                        var scheduleCreator = new SingleScheduleCreator(
                            this, new ARSubaccountProvider(this), this, this, this, this, this, FinPeriodRepository,
                            roundingFunction: x => PXCurrencyAttribute.BaseRound(this, x),
                            branchID: originalDocument.BranchID, isDraft: !accountForPostedTransactions,
                            location: location, currencyInfo: currencyInfo);

                        scheduleCreator.ReevaluateSchedule(
                            existingSchedule,
                            scheduleParameters,
                            lineTotal,
                            attachedToOriginalSchedule: true);
                    }
                }
            }
        }
        private void CreateRelatedSingleSchedule(DRScheduleParameters scheduleParameters, int?defScheduleID, Amount tranAmt, bool isDraft, bool accountForPostedTransactions)
        {
            DRSchedule relatedSchedule = (this as IDREntityStorage).CreateCopy(scheduleParameters);

            relatedSchedule.IsDraft  = isDraft;
            relatedSchedule.IsCustom = false;

            relatedSchedule = Schedule.Insert(relatedSchedule);

            DRSchedule originalDeferralSchedule = GetDeferralSchedule(defScheduleID);

            DRScheduleDetail originalDetailsTotalDetail = PXSelectGroupBy <
                DRScheduleDetail,
                Where <
                    DRScheduleDetail.scheduleID, Equal <Required <DRScheduleDetail.scheduleID> > >, Aggregate <Sum <DRScheduleDetail.curyTotalAmt> > >
                                                          .Select(this, originalDeferralSchedule.ScheduleID);

            decimal originalDetailsTotal = originalDetailsTotalDetail.CuryTotalAmt ?? 0m;
            decimal adjustmentTotal      = tranAmt.Cury.Value;

            decimal newDetailTotal = 0m;

            var originalDetails = PXSelectJoin <DRScheduleDetail,
                                                LeftJoin <ARTran,
                                                          On <DRScheduleDetail.lineNbr, Equal <ARTran.lineNbr> >,
                                                          InnerJoin <InventoryItem,
                                                                     On <ARTran.inventoryID, Equal <InventoryItem.inventoryID> >,
                                                                     LeftJoin <INComponent,
                                                                               On <DRScheduleDetail.componentID, Equal <INComponent.inventoryID> >,
                                                                               InnerJoin <DRDeferredCode,
                                                                                          On <ARTran.deferredCode, Equal <DRDeferredCode.deferredCodeID> > > > > >,
                                                Where <DRScheduleDetail.scheduleID, Equal <Required <DRSchedule.scheduleID> >,
                                                       And <ARTran.tranType, Equal <Required <DRSchedule.docType> >,
                                                            And <ARTran.refNbr, Equal <Required <DRSchedule.refNbr> > > > > > .Select(this, defScheduleID, scheduleParameters.DocType, scheduleParameters.RefNbr);

            foreach (PXResult <DRScheduleDetail, ARTran, InventoryItem, INComponent, DRDeferredCode> item in originalDetails)
            {
                DRScheduleDetail originalDetail = item;
                ARTran           tran           = item;
                InventoryItem    inventoryItem  = item;
                INComponent      inComponent    = item;
                DRDeferredCode   defCode        = item;


                decimal detailPartRaw = originalDetailsTotal == 0 ? 0 :
                                        originalDetail.CuryTotalAmt.Value * adjustmentTotal / originalDetailsTotal;

                decimal detailPart = PXDBCurrencyAttribute.BaseRound(this, detailPartRaw);

                decimal takeFromPostedRaw = 0;

                if (accountForPostedTransactions && originalDetail.CuryTotalAmt.Value != 0)
                {
                    takeFromPostedRaw =
                        detailPartRaw * (originalDetail.CuryTotalAmt.Value - originalDetail.CuryDefAmt.Value) / originalDetail.CuryTotalAmt.Value;
                }

                decimal takeFromPosted = PXDBCurrencyAttribute.BaseRound(this, takeFromPostedRaw);

                decimal adjustmentDeferredAmountRaw = detailPartRaw - takeFromPosted;
                decimal adjustmentDeferredAmount    = PXDBCurrencyAttribute.BaseRound(this, adjustmentDeferredAmountRaw);

                INComponent    inventoryItemComponent = null;
                DRDeferredCode componentDeferralCode  = null;

                if (inventoryItem != null && inComponent != null)
                {
                    inventoryItemComponent = GetInventoryItemComponent(inventoryItem.InventoryID, originalDetail.ComponentID);

                    if (inventoryItemComponent != null)
                    {
                        componentDeferralCode = PXSelect <
                            DRDeferredCode,
                            Where <
                                DRDeferredCode.deferredCodeID, Equal <Required <DRDeferredCode.deferredCodeID> > > >
                                                .Select(this, inventoryItemComponent.DeferredCode);
                    }
                }

                InventoryItem component = GetInventoryItem(originalDetail.ComponentID);

                DRScheduleDetail relatedScheduleDetail;

                if (componentDeferralCode != null)
                {
                    // Use component's deferral code
                    // -
                    relatedScheduleDetail = InsertScheduleDetail(
                        tran.BranchID,
                        relatedSchedule,
                        inventoryItemComponent,
                        component,
                        componentDeferralCode,
                        detailPart,
                        originalDetail.DefAcctID,
                        originalDetail.DefSubID,
                        isDraft);
                }
                else
                {
                    // Use deferral code and accounts from the document line
                    // -
                    relatedScheduleDetail = InsertScheduleDetail(
                        tran.BranchID,
                        relatedSchedule,
                        component == null ? DRScheduleDetail.EmptyComponentID : component.InventoryID,
                        defCode,
                        detailPart,
                        originalDetail.DefAcctID,
                        originalDetail.DefSubID,
                        tran.AccountID,
                        tran.SubID,
                        isDraft);
                }

                newDetailTotal += detailPart;

                IList <DRScheduleTran> relatedTransactions             = new List <DRScheduleTran>();
                DRDeferredCode         relatedTransactionsDeferralCode = componentDeferralCode ?? defCode;

                IEnumerable <DRScheduleTran> originalPostedTransactions = null;

                if (accountForPostedTransactions)
                {
                    originalPostedTransactions = PXSelect <
                        DRScheduleTran,
                        Where <
                            DRScheduleTran.status, Equal <DRScheduleTranStatus.PostedStatus>,
                            And <DRScheduleTran.scheduleID, Equal <Required <DRScheduleTran.scheduleID> >,
                                 And <DRScheduleTran.componentID, Equal <Required <DRScheduleTran.componentID> >,
                                      And <DRScheduleTran.detailLineNbr, Equal <Required <DRScheduleTran.detailLineNbr> >,
                                           And <DRScheduleTran.lineNbr, NotEqual <Required <DRScheduleTran.lineNbr> > > > > > > >
                                                 .Select(
                        this,
                        originalDetail.ScheduleID,
                        originalDetail.ComponentID,
                        originalDetail.DetailLineNbr,
                        originalDetail.CreditLineNbr)
                                                 .RowCast <DRScheduleTran>();
                }

                if (adjustmentDeferredAmount != 0m ||
                    accountForPostedTransactions && takeFromPosted != 0m)
                {
                    string requiredTransactionStatus =
                        relatedTransactionsDeferralCode.Method == DeferredMethodType.CashReceipt ?
                        DRScheduleTranStatus.Projected :
                        DRScheduleTranStatus.Open;

                    IEnumerable <DRScheduleTran> originalOpenTransactions = PXSelect <
                        DRScheduleTran,
                        Where <
                            DRScheduleTran.status, Equal <Required <DRScheduleTran.status> >,
                            And <DRScheduleTran.scheduleID, Equal <Required <DRScheduleTran.scheduleID> >,
                                 And <DRScheduleTran.componentID, Equal <Required <DRScheduleTran.componentID> >,
                                      And <DRScheduleTran.detailLineNbr, Equal <Required <DRScheduleTran.detailLineNbr> > > > > > >
                                                                            .Select(
                        this,
                        requiredTransactionStatus,
                        originalDetail.ScheduleID,
                        originalDetail.ComponentID,
                        originalDetail.DetailLineNbr)
                                                                            .RowCast <DRScheduleTran>();

                    IList <DRScheduleTran> relatedDeferralTransactions =
                        GetTransactionsGenerator(relatedTransactionsDeferralCode).GenerateRelatedTransactions(
                            relatedScheduleDetail,
                            originalOpenTransactions,
                            originalPostedTransactions,
                            adjustmentDeferredAmount,
                            takeFromPosted,
                            tran.BranchID);

                    foreach (DRScheduleTran deferralTransaction in relatedDeferralTransactions)
                    {
                        Transactions.Insert(deferralTransaction);
                        relatedTransactions.Add(deferralTransaction);
                    }
                }

                UpdateBalanceProjection(relatedTransactions, relatedScheduleDetail, defCode.AccountType);
            }
        }