private void AddComponentScheduleDetail( INComponent inventoryItemComponent, DRDeferredCode componentDeferralCode, InventoryItem inventoryItem, decimal amount, DRProcess.DRScheduleParameters tranInfo, int?overridenSubID) { if (amount == 0m) { return; } DRScheduleDetail scheduleDetail = InsertScheduleDetail( inventoryItem.InventoryID, componentDeferralCode, amount, GetDeferralAccountSubaccount(componentDeferralCode, inventoryItem, tranInfo), GetSalesOrExpenseAccountSubaccount(inventoryItemComponent, inventoryItem), overridenSubID); if (!_isDraft) { IEnumerable <DRScheduleTran> deferralTransactions = _drEntityStorage.CreateDeferralTransactions(_schedule, scheduleDetail, componentDeferralCode, _branchID); _drEntityStorage.NonDraftDeferralTransactionsPrepared(scheduleDetail, componentDeferralCode, deferralTransactions); } }
private void UpdateOriginalSingleSchedule(ARRegister originalDocument, decimal amount) { foreach (PXResult <ARTran, InventoryItem, INComponent, DRDeferredCode> item in ARTransactionWithItems.Select()) { ARTran artran = item; InventoryItem inventoryItem = item; INComponent component = item; DRDeferredCode deferredCode = item; UpdateOriginalSchedule(artran, deferredCode, amount, originalDocument.DocDate, originalDocument.FinPeriodID, originalDocument.CustomerID, originalDocument.CustomerLocationID); } }
protected override decimal GetAmountForComponent(INComponent inventoryItemComponent, decimal amountToDistribute) { if (amountToDistribute == 0m) { return(0m); } decimal componentAmountRaw = (_fairUnitPrice - _fixedPerUnit) * _compoundDiscountRate * _qtyInBaseUnit * inventoryItemComponent.Percentage.Value * 0.01m; return(_roundingFunction(componentAmountRaw)); }
protected virtual decimal GetAmountForComponent(INComponent inventoryItemComponent, decimal amountToDistribute) { if (inventoryItemComponent != _percentageComponents.Last().Component) { decimal componentAmountRaw = amountToDistribute * inventoryItemComponent.Percentage.Value / _percentageComponents.Sum(componentInfo => componentInfo.Component.Percentage.Value); return(_roundingFunction(componentAmountRaw)); } else { return(amountToDistribute - _amounts.Sum(ca => ca.Item2)); } }
private AccountSubaccountPair GetSalesAccountSubaccount( DRDeferredCode deferralCode, InventoryItem item, INComponent component, ARTran transaction) { int?accountID = transaction.AccountID; int?subaccountID = transaction.SubID; if (deferralCode.MultiDeliverableArrangement == true) { accountID = component.SalesAcctID; } if (deferralCode.MultiDeliverableArrangement == true && item.UseParentSubID == true) { subaccountID = component.SalesSubID; } return(new AccountSubaccountPair(accountID, subaccountID)); }
public virtual IEnumerable <ComponentAmount> Distribute(decimal transactionAmount, decimal amountToDistribute) { _amounts = new List <ComponentAmount>(); foreach (InventoryItemComponentInfo componentInfo in _percentageComponents) { INComponent component = componentInfo.Component; decimal componentAmount = GetAmountForComponent(componentInfo.Component, amountToDistribute); if ((componentAmount < 0 && transactionAmount >= 0) || (componentAmount > 0 && transactionAmount <= 0)) { throw new PXException( Messages.NegativeAmountForComponent, _inventoryItemProvider.GetComponentName(component)); } _amounts.Add(new ComponentAmount(componentInfo, componentAmount)); } return(_amounts); }
private void AddComponentScheduleDetail( INComponent inventoryItemComponent, DRDeferredCode componentDeferralCode, InventoryItem inventoryItem, decimal amount, DRProcess.DRScheduleParameters tranInfo) { if (amount == 0m) { return; } DRScheduleDetail scheduleDetail = InsertScheduleDetail( inventoryItem.InventoryID, componentDeferralCode, amount, GetDeferralAccountSubaccount(componentDeferralCode, inventoryItem, tranInfo), GetSalesOrExpenseAccountSubaccount(inventoryItemComponent, inventoryItem)); if (!_isDraft) { _drEntityStorage.CreateDeferralTransactions(_schedule, scheduleDetail, componentDeferralCode, _branchID); } }
private AccountSubaccountPair GetSalesOrExpenseAccountSubaccount(INComponent component, InventoryItem componentItem) { return(_schedule.Module == BatchModule.AP ? new AccountSubaccountPair(componentItem.COGSAcctID, componentItem.COGSSubID) : new AccountSubaccountPair(component.SalesAcctID, component.SalesSubID)); }
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); } }
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); } }
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); }
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); } } }