示例#1
0
        /// <param name="deferralCode">The item-level deferral code for <paramref name="inventoryItem"/>.</param>
        /// <param name="inventoryItem">The inventory item from the document line.</param>
        /// <param name="transactionAmount">Total transaction amount (with ALL discounts applied).</param>
        /// <param name="fairUnitPrice">The item price from the price list.</param>
        /// <param name="compoundDiscountRate"> Compound discount rate of all discounts
        /// (including line, group and document discounts) that are applicable to deferred components.</param>
        public void CreateOriginalSchedule(
            DRProcess.DRScheduleParameters scheduleParameters,
            DRDeferredCode deferralCode,
            InventoryItem inventoryItem,
            AccountSubaccountPair salesOrExpenseAccountSubaccount,
            decimal?transactionAmount,
            decimal?fairUnitPrice,
            decimal?compoundDiscountRate,
            decimal?quantityInBaseUnit)
        {
            ValidateMDAConsistency(inventoryItem, deferralCode);

            _schedule = _drEntityStorage.CreateCopy(scheduleParameters);

            _schedule.IsDraft  = _isDraft;
            _schedule.IsCustom = false;

            _schedule = _drEntityStorage.Insert(_schedule);

            CreateDetails(
                scheduleParameters,
                deferralCode,
                inventoryItem,
                salesOrExpenseAccountSubaccount,
                transactionAmount,
                fairUnitPrice,
                compoundDiscountRate,
                quantityInBaseUnit);
        }
示例#2
0
        private DRScheduleDetail InsertScheduleDetail(
            int?componentID,
            DRDeferredCode defCode,
            decimal amount,
            AccountSubaccountPair deferralAccountSubaccount,
            AccountSubaccountPair salesOrExpenseAccountSubaccount,
            int?overridenSubID = null)
        {
            FinPeriod detailFinPeriod = FinPeriodRepository
                                        .GetFinPeriodByMasterPeriodID(PXAccess.GetParentOrganizationID(_branchID),
                                                                      _schedule.FinPeriodID).GetValueOrRaiseError();

            DRScheduleDetail scheduleDetail = new DRScheduleDetail
            {
                ScheduleID    = _schedule.ScheduleID,
                BranchID      = _branchID,
                ComponentID   = componentID,
                CuryTotalAmt  = amount,
                CuryDefAmt    = amount,
                DefCode       = defCode.DeferredCodeID,
                Status        = _isDraft ? DRScheduleStatus.Draft : DRScheduleStatus.Open,
                IsCustom      = false,
                IsOpen        = true,
                Module        = _schedule.Module,
                DocType       = _schedule.DocType,
                RefNbr        = _schedule.RefNbr,
                LineNbr       = _schedule.LineNbr,
                FinPeriodID   = detailFinPeriod.FinPeriodID,
                TranPeriodID  = detailFinPeriod.MasterFinPeriodID,
                BAccountID    = _schedule.BAccountID,
                AccountID     = salesOrExpenseAccountSubaccount.AccountID,
                SubID         = overridenSubID ?? salesOrExpenseAccountSubaccount.SubID,
                DefAcctID     = deferralAccountSubaccount.AccountID,
                DefSubID      = deferralAccountSubaccount.SubID,
                CreditLineNbr = 0,
                DocDate       = _schedule.DocDate,
                BAccountType  =
                    _schedule.Module == BatchModule.AP
                                                ? BAccountType.VendorType
                                                : BAccountType.CustomerType,
            };

            scheduleDetail = _drEntityStorage.Insert(scheduleDetail);

            if (!_isDraft)
            {
                _drEntityStorage.CreateCreditLineTransaction(scheduleDetail, defCode, _branchID);
            }

            return(scheduleDetail);
        }
示例#3
0
        private DRScheduleDetail InsertScheduleDetail(
            int?componentID,
            DRDeferredCode defCode,
            decimal amount,
            AccountSubaccountPair deferralAccountSubaccount,
            AccountSubaccountPair salesOrExpenseAccountSubaccount)
        {
            DRScheduleDetail scheduleDetail = new DRScheduleDetail
            {
                ScheduleID    = _schedule.ScheduleID,
                ComponentID   = componentID,
                TotalAmt      = amount,
                DefAmt        = amount,
                DefCode       = defCode.DeferredCodeID,
                Status        = _isDraft ? DRScheduleStatus.Draft : DRScheduleStatus.Open,
                IsCustom      = false,
                IsOpen        = true,
                Module        = _schedule.Module,
                DocType       = _schedule.DocType,
                RefNbr        = _schedule.RefNbr,
                LineNbr       = _schedule.LineNbr,
                FinPeriodID   = _schedule.FinPeriodID,
                BAccountID    = _schedule.BAccountID,
                AccountID     = salesOrExpenseAccountSubaccount.AccountID,
                SubID         = salesOrExpenseAccountSubaccount.SubID,
                DefAcctID     = deferralAccountSubaccount.AccountID,
                DefSubID      = deferralAccountSubaccount.SubID,
                CreditLineNbr = 0,
                DocDate       = _schedule.DocDate,
                BAccountType  =
                    _schedule.Module == BatchModule.AP
                                                ? BAccountType.VendorType
                                                : BAccountType.CustomerType,
            };

            scheduleDetail = _drEntityStorage.Insert(scheduleDetail);

            if (!_isDraft)
            {
                _drEntityStorage.CreateCreditLineTransaction(scheduleDetail, defCode, _branchID);
            }

            return(scheduleDetail);
        }
示例#4
0
        private void CreateDetails(
            DRProcess.DRScheduleParameters scheduleParameters,
            DRDeferredCode deferralCode,
            InventoryItem inventoryItem,
            AccountSubaccountPair salesOrExpenseAccountSubaccount,
            decimal?transactionAmount,
            decimal?fairUnitPrice,
            decimal?compoundDiscountRate,
            decimal?quantityInBaseUnit)
        {
            if (deferralCode.MultiDeliverableArrangement == true && inventoryItem != null && inventoryItem.IsSplitted == true)
            {
                CreateDetailsForSplitted(
                    scheduleParameters,
                    inventoryItem,
                    salesOrExpenseAccountSubaccount.SubID,
                    transactionAmount,
                    fairUnitPrice,
                    compoundDiscountRate ?? 1.0m,
                    quantityInBaseUnit ?? 0.0m);
            }
            else
            {
                var deferralAccountSubaccount = GetDeferralAccountSubaccount(deferralCode, inventoryItem, scheduleParameters);

                int?componentID = inventoryItem == null ? DRScheduleDetail.EmptyComponentID : inventoryItem.InventoryID;

                DRScheduleDetail scheduleDetail = InsertScheduleDetail(
                    componentID,
                    deferralCode,
                    transactionAmount.Value,
                    deferralAccountSubaccount,
                    salesOrExpenseAccountSubaccount);

                if (!_isDraft)
                {
                    IEnumerable <DRScheduleTran> deferralTransactions =
                        _drEntityStorage.CreateDeferralTransactions(_schedule, scheduleDetail, deferralCode, _branchID);

                    _drEntityStorage.NonDraftDeferralTransactionsPrepared(scheduleDetail, deferralCode, deferralTransactions);
                }
            }
        }
示例#5
0
        private void CreateDetailsForSplitted(
            DRProcess.DRScheduleParameters scheduleParameters,
            InventoryItem inventoryItem,
            int?subaccountID,
            decimal?transactionAmount,
            decimal?fairUnitPrice,
            decimal compoundDiscountRate,
            decimal qtyInBaseUnit)
        {
            int?salesExpenseSubIDOverride = inventoryItem.UseParentSubID == true ? null : subaccountID;

            IEnumerable <InventoryItemComponentInfo> fixedAllocationComponents =
                _inventoryItemProvider.GetInventoryItemComponents(inventoryItem.InventoryID, INAmountOption.FixedAmt);

            IEnumerable <InventoryItemComponentInfo> percentageAllocationComponents =
                _inventoryItemProvider.GetInventoryItemComponents(inventoryItem.InventoryID, INAmountOption.Percentage);

            IEnumerable <InventoryItemComponentInfo> residualAllocationComponents =
                _inventoryItemProvider.GetInventoryItemComponents(inventoryItem.InventoryID, INAmountOption.Residual);

            if (residualAllocationComponents.Any() && !residualAllocationComponents.IsSingleElement())
            {
                throw new PXException(Messages.TooManyResiduals);
            }

            bool canUseResidual = residualAllocationComponents.Any();

            decimal fixedTotalAmount = 0;

            foreach (InventoryItemComponentInfo componentInfo in fixedAllocationComponents)
            {
                INComponent component = componentInfo.Component;

                decimal amountRaw = (component.FixedAmt ?? 0) * qtyInBaseUnit * compoundDiscountRate;
                decimal amount    = _roundingFunction(amountRaw);

                fixedTotalAmount += amount;

                AddComponentScheduleDetail(
                    componentInfo.Component,
                    componentInfo.DeferralCode,
                    componentInfo.Item,
                    Math.Sign((decimal)transactionAmount) * amount,
                    scheduleParameters,
                    salesExpenseSubIDOverride);
            }

            decimal fixedPerUnit =
                fixedAllocationComponents.Sum(componentInfo => componentInfo.Component.FixedAmt ?? 0);

            decimal amountToDistribute = transactionAmount.Value - fixedTotalAmount;

            if (transactionAmount >= 0 && amountToDistribute < 0 ||
                transactionAmount < 0 && amountToDistribute > 0)
            {
                throw new PXException(Messages.FixedAmtSumOverload);
            }

            if (!percentageAllocationComponents.Any() && amountToDistribute != 0 && !canUseResidual)
            {
                throw new PXException(Messages.NoResidual);
            }

            if (percentageAllocationComponents.Any())
            {
                bool canUseResidualInPercentageDistribution =
                    canUseResidual && fairUnitPrice != null && fairUnitPrice != 0.0m;

                PercentageDistribution distribution;

                if (canUseResidualInPercentageDistribution)
                {
                    distribution = new PercentageWithResidualDistribution(
                        _inventoryItemProvider,
                        percentageAllocationComponents,
                        fairUnitPrice.Value,
                        fixedPerUnit,
                        compoundDiscountRate,
                        qtyInBaseUnit,
                        _roundingFunction);
                }
                else
                {
                    distribution = new PercentageDistribution(
                        _inventoryItemProvider,
                        percentageAllocationComponents,
                        _roundingFunction);
                }

                IEnumerable <ComponentAmount> percentageAmounts =
                    distribution.Distribute(transactionAmount.Value, amountToDistribute);

                foreach (var componentAmount in percentageAmounts)
                {
                    AddComponentScheduleDetail(
                        componentAmount.Item1.Component,
                        componentAmount.Item1.DeferralCode,
                        componentAmount.Item1.Item,
                        componentAmount.Item2,
                        scheduleParameters,
                        salesExpenseSubIDOverride);
                }

                amountToDistribute -= percentageAmounts.Sum(componentAmount => componentAmount.Item2);
            }

            if (canUseResidual && amountToDistribute > 0m)
            {
                INComponent   residualComponent     = residualAllocationComponents.Single().Component;
                InventoryItem residualComponentItem = residualAllocationComponents.Single().Item;

                AccountSubaccountPair salesOrExpenseAccountSubaccount =
                    GetSalesOrExpenseAccountSubaccount(residualComponent, residualComponentItem);

                InsertResidualScheduleDetail(
                    residualComponent.ComponentID,
                    amountToDistribute,
                    salesOrExpenseAccountSubaccount.AccountID,
                    salesExpenseSubIDOverride ?? salesOrExpenseAccountSubaccount.SubID);
            }
        }
示例#6
0
        private DRScheduleDetail CreateScheduleDetail(
            ARTran artran,
            INComponent component,
            DRDeferredCode defCode,
            AccountSubaccountPair deferralAccountSubaccount,
            AccountSubaccountPair salesAccountSubaccount,
            bool isFlexibleMethod)
        {
            string  uom        = artran.UOM;
            decimal?qty        = artran.Qty;
            decimal coTermRate = 1m;

            if (component?.ComponentID != null)
            {
                uom = component.UOM;
                if (artran.UOM == component.UOM)
                {
                    qty = artran.Qty * component.Qty;
                }
                else
                {
                    var qtyBase = _salesPriceProvider.GetQuantityInBaseUOMs(artran);
                    qty = qtyBase * component.Qty;
                }
            }

            if (isFlexibleMethod == true)
            {
                coTermRate = (((artran.DRTermEndDate.Value - artran.DRTermStartDate.Value).Days + 1.0m) / 365.0m);
            }

            FinPeriod detailFinPeriod = FinPeriodRepository
                                        .GetFinPeriodByMasterPeriodID(PXAccess.GetParentOrganizationID(artran.BranchID), artran.TranPeriodID).GetValueOrRaiseError();

            DRScheduleDetail scheduleDetail = new DRScheduleDetail
            {
                ScheduleID        = _schedule.ScheduleID,
                BranchID          = artran.BranchID,
                ComponentID       = component?.ComponentID ?? artran.InventoryID,
                ParentInventoryID = component?.ComponentID != null ? artran.InventoryID : null,
                DefCode           = component?.DeferredCode ?? defCode.DeferredCodeID,
                Status            = _isDraft ? DRScheduleStatus.Draft : DRScheduleStatus.Open,
                IsCustom          = false,
                IsOpen            = true,
                Module            = _schedule.Module,
                DocType           = _schedule.DocType,
                RefNbr            = _schedule.RefNbr,
                LineNbr           = artran.LineNbr,
                FinPeriodID       = detailFinPeriod.FinPeriodID,
                TranPeriodID      = detailFinPeriod.MasterFinPeriodID,
                BAccountID        = _schedule.BAccountID,
                AccountID         = salesAccountSubaccount.AccountID,
                SubID             = salesAccountSubaccount.SubID,
                DefAcctID         = deferralAccountSubaccount.AccountID,
                DefSubID          = deferralAccountSubaccount.SubID,
                CreditLineNbr     = 0,
                DocDate           = _schedule.DocDate,
                UOM          = uom,
                Qty          = qty,
                BAccountType =
                    _schedule.Module == BatchModule.AP
                                                ? BAccountType.VendorType
                                                : BAccountType.CustomerType,
                TermStartDate = artran.DRTermStartDate,
                TermEndDate   = artran.DRTermEndDate,
                CoTermRate    = coTermRate,
            };

            return(scheduleDetail);
        }
示例#7
0
        private void CreateScheduleDetails(DRProcess.DRScheduleParameters scheduleParameters, Amount lineTotal)
        {
            decimal scheduleFairTotal = 0;

            var errors = new List <string>();

            foreach (PXResult <ARTran, InventoryItem, DRDeferredCode, INComponent,
                               DRSingleProcess.ComponentINItem, DRSingleProcess.ComponentDeferredCode> item in _singleScheduleViewProvider.GetParentDocumentDetails())
            {
                ARTran         artran        = item;
                InventoryItem  inventoryItem = item;
                DRDeferredCode deferredCode  = item;
                INComponent    component     = item;
                DRSingleProcess.ComponentINItem       componentINItem       = item;
                DRSingleProcess.ComponentDeferredCode componentDeferredCode = item;

                bool isMDA = deferredCode.MultiDeliverableArrangement == true;

                AccountSubaccountPair deferralAccountSubaccount = GetDeferralAccountSubaccount(
                    isMDA ? componentDeferredCode: deferredCode,
                    isMDA ? componentINItem : inventoryItem,
                    scheduleParameters,
                    artran.SubID);

                AccountSubaccountPair salesAccountSubaccount = GetSalesAccountSubaccount(deferredCode, inventoryItem, component, artran);

                bool isFlexibleMethod = deferredCode.Method == DeferredMethodType.FlexibleProrateDays ||
                                        deferredCode.Method == DeferredMethodType.FlexibleExactDays ||
                                        componentDeferredCode?.Method == DeferredMethodType.FlexibleProrateDays ||
                                        componentDeferredCode?.Method == DeferredMethodType.FlexibleExactDays;

                try
                {
                    DRScheduleDetail detail = CreateScheduleDetail(
                        artran,
                        component,
                        deferredCode,
                        deferralAccountSubaccount,
                        salesAccountSubaccount,
                        isFlexibleMethod);

                    detail = _drEntityStorage.Insert(detail);
                    SetFairValuePrice(detail);
                    detail = _drEntityStorage.Update(detail);

                    if (!_isDraft)
                    {
                        _drEntityStorage.CreateCreditLineTransaction(detail, deferredCode, _branchID);
                    }

                    scheduleFairTotal += detail.EffectiveFairValuePrice.Value * detail.Qty.Value;
                }
                catch (NoFairValuePriceFoundException e)
                {
                    errors.Add(e.Message);
                    continue;
                }
            }

            if (errors.Any())
            {
                throw new NoFairValuePricesFoundException(string.Join(Environment.NewLine, errors));
            }

            if (scheduleFairTotal == 0m)
            {
                throw new PXException(Messages.SumOfFairValuePricesEqualToZero);
            }

            IEnumerable <DRScheduleDetail> scheduleDetails = _drEntityStorage.GetScheduleDetails(_schedule.ScheduleID)
                                                             .RowCast <DRScheduleDetail>()
                                                             .ToList();

            if (scheduleDetails.IsSingleElement())
            {
                DRScheduleDetail scheduleDetail = scheduleDetails.Single();
                scheduleDetail.CuryTotalAmt = lineTotal.Cury;
                scheduleDetail.CuryDefAmt   = lineTotal.Cury;
                scheduleDetail.Percentage   = 1m;
                _drEntityStorage.Update(scheduleDetail);
            }
            else if (scheduleDetails.HasAtLeastTwoItems())
            {
                decimal          sumPercent = 0m;
                decimal          sumResult  = 0m;
                DRScheduleDetail maxAmtLine = null;

                scheduleDetails.ForEach(scheduleDetail =>
                {
                    scheduleDetail.Percentage = scheduleDetail.EffectiveFairValuePrice * scheduleDetail.Qty / scheduleFairTotal;
                    sumPercent += scheduleDetail.Percentage ?? 0m;

                    decimal?rawResult = lineTotal.Cury * scheduleDetail.Percentage;
                    decimal?result    = _roundingFunction(rawResult.Value);
                    sumResult        += result ?? 0m;

                    scheduleDetail.CuryTotalAmt = result;
                    scheduleDetail.CuryDefAmt   = result;

                    var detail = _drEntityStorage.Update(scheduleDetail);

                    if ((maxAmtLine?.CuryTotalAmt ?? 0m) < detail.CuryTotalAmt)
                    {
                        maxAmtLine = detail;
                    }
                });

                if (sumPercent != 1m || sumResult != lineTotal.Cury)
                {
                    decimal?amtDiff = lineTotal.Cury - sumResult;

                    maxAmtLine.CuryTotalAmt += amtDiff;
                    maxAmtLine.CuryDefAmt   += amtDiff;
                    maxAmtLine.Percentage   += 1m - sumPercent;

                    _drEntityStorage.Update(maxAmtLine);
                }
            }

            if (!_isDraft)
            {
                foreach (PXResult <DRScheduleDetail, DRDeferredCode> detail in _dataProvider.GetScheduleDetailsResultset(_schedule.ScheduleID))
                {
                    DRScheduleDetail scheduleDetail = detail;
                    DRDeferredCode   deferralCode   = detail;

                    IEnumerable <DRScheduleTran> deferralTransactions =
                        _drEntityStorage.CreateDeferralTransactions(_schedule, scheduleDetail, deferralCode, _branchID);

                    _drEntityStorage.NonDraftDeferralTransactionsPrepared(scheduleDetail, deferralCode, deferralTransactions);
                }
            }
        }