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); } }
/// <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); }
/// <param name="attachedToOriginalSchedule"> /// Flag added to handle <see cref="DRScheduleDetail"/>'s status /// in the same way as <see cref="DRProcess"/> had done for documents /// attached to original schedule. /// </param> public void ReevaluateSchedule( DRSchedule schedule, DRProcess.DRScheduleParameters scheduleParameters, Amount lineAmount, bool attachedToOriginalSchedule) { if (schedule.IsOverridden == true && _isDraft == false) { decimal?totalComponentAmt = _drEntityStorage.GetScheduleDetails(schedule.ScheduleID).Sum(s => s.TotalAmt); if (totalComponentAmt != lineAmount.Cury) { throw new PXException(Messages.CannotReleaseOverriden, totalComponentAmt, lineAmount.Base, _currencyInfo.BaseCuryID); } } _dataProvider.DeleteAllDetails(schedule.ScheduleID); _schedule = schedule; _schedule.DocDate = scheduleParameters.DocDate; _schedule.BAccountID = scheduleParameters.BAccountID; _schedule.BAccountLocID = scheduleParameters.BAccountLocID; _schedule.FinPeriodID = scheduleParameters.FinPeriodID; _schedule.TranDesc = scheduleParameters.TranDesc; _schedule.IsCustom = false; _schedule.IsDraft = _isDraft; _schedule.BAccountType = _schedule.Module == BatchModule.AP ? BAccountType.VendorType : BAccountType.CustomerType; _schedule.TermStartDate = scheduleParameters.TermStartDate; _schedule.TermEndDate = scheduleParameters.TermEndDate; _schedule.ProjectID = scheduleParameters.ProjectID; _schedule.TaskID = scheduleParameters.TaskID; _schedule = _drEntityStorage.Update(_schedule); CreateScheduleDetails(scheduleParameters, lineAmount); }
/// <param name="attachedToOriginalSchedule"> /// Flag added to handle <see cref="DRScheduleDetail"/>'s status /// in the same way as <see cref="DRProcess"/> had done for documents /// attached to original schedule. /// </param> public void ReevaluateSchedule( DRSchedule schedule, DRProcess.DRScheduleParameters scheduleParameters, DRDeferredCode deferralCode, decimal?lineAmount, bool attachedToOriginalSchedule) { _schedule = schedule; _schedule.DocDate = scheduleParameters.DocDate; _schedule.BAccountID = scheduleParameters.BAccountID; _schedule.BAccountLocID = scheduleParameters.BAccountLocID; _schedule.FinPeriodID = scheduleParameters.FinPeriodID; _schedule.TranDesc = scheduleParameters.TranDesc; _schedule.IsCustom = false; _schedule.IsDraft = _isDraft; _schedule.BAccountType = _schedule.Module == BatchModule.AP ? BAccountType.VendorType : BAccountType.CustomerType; _schedule.TermStartDate = scheduleParameters.TermStartDate; _schedule.TermEndDate = scheduleParameters.TermEndDate; _schedule.ProjectID = scheduleParameters.ProjectID; _schedule.TaskID = scheduleParameters.TaskID; _schedule = _drEntityStorage.Update(_schedule); IList <DRScheduleDetail> scheduleDetails = _drEntityStorage.GetScheduleDetails(_schedule.ScheduleID); ReevaluateComponentAmounts(scheduleDetails, lineAmount); foreach (DRScheduleDetail scheduleDetail in scheduleDetails) { scheduleDetail.DocDate = _schedule.DocDate; scheduleDetail.BAccountID = _schedule.BAccountID; scheduleDetail.FinPeriodID = _schedule.FinPeriodID; if (!attachedToOriginalSchedule) { scheduleDetail.Status = _isDraft ? DRScheduleStatus.Draft : (scheduleDetail.IsResidual == null ? DRScheduleStatus.Closed : DRScheduleStatus.Open); } else { scheduleDetail.Status = _isDraft ? DRScheduleStatus.Draft : (scheduleDetail.IsOpen == true ? DRScheduleStatus.Open : DRScheduleStatus.Closed); } _drEntityStorage.Update(scheduleDetail); if (scheduleDetail.IsResidual != true) { ReevaluateOrCreateTransactions(scheduleDetail); if (_isDraft == false) { _drEntityStorage.CreateCreditLineTransaction(scheduleDetail, deferralCode, _branchID); } } } }
/// <param name="deferralCode">The item-level deferral code for the inventory item /// <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, Amount lineTotal) { _schedule = _drEntityStorage.CreateCopy(scheduleParameters); _schedule.IsDraft = _isDraft; _schedule.IsCustom = false; _schedule = _drEntityStorage.Insert(_schedule); CreateScheduleDetails(scheduleParameters, lineTotal); }
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); } } }
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 GetDeferralAccountSubaccount( DRDeferredCode deferralCode, InventoryItem item, DRProcess.DRScheduleParameters scheduleParameters) { int?accountID = deferralCode.AccountID; string subaccountCD = null; int? subaccountID = null; if (deferralCode.AccountSource == DeferralAccountSource.Item) { accountID = item != null ? item.DeferralAcctID : subaccountID; // this is fishy. subID is always null at this point. } if (deferralCode.CopySubFromSourceTran == true) { subaccountID = scheduleParameters.SubID; } else if (scheduleParameters.Module == BatchModule.AP) { int?itemSubID = item?.DeferralSubID; Location location = _businessAccountProvider .GetLocation(scheduleParameters.BAccountID, scheduleParameters.BAccountLocID); int?locationSubID = location?.VExpenseSubID; EPEmployee employee = _businessAccountProvider .GetEmployee(scheduleParameters.EmployeeID); int?employeeSubaccountID = employee?.ExpenseSubID; subaccountCD = _subaccountProvider.MakeSubaccount <DRScheduleDetail.subID>( deferralCode.DeferralSubMaskAP, new object[] { locationSubID, itemSubID, employeeSubaccountID, deferralCode.SubID }, new [] { typeof(Location.vExpenseSubID), typeof(InventoryItem.deferralSubID), typeof(EPEmployee.expenseSubID), typeof(DRDeferredCode.subID) }); } else if (scheduleParameters.Module == BatchModule.AR) { int?itemSubID = item?.DeferralSubID; Location location = _businessAccountProvider .GetLocation(scheduleParameters.BAccountID, scheduleParameters.BAccountLocID); int?locationSubaccountID = location?.CSalesSubID; EPEmployee employee = _businessAccountProvider .GetEmployee(scheduleParameters.EmployeeID); int?employeeSubaccountID = employee?.SalesSubID; SalesPerson salesPerson = _businessAccountProvider .GetSalesPerson(scheduleParameters.SalesPersonID); int?salesPersonSubaccountID = salesPerson?.SalesSubID; subaccountCD = _subaccountProvider.MakeSubaccount <DRScheduleDetail.subID>( deferralCode.DeferralSubMaskAR, new object[] { locationSubaccountID, itemSubID, employeeSubaccountID, deferralCode.SubID, salesPersonSubaccountID }, new [] { typeof(Location.cSalesSubID), typeof(InventoryItem.deferralSubID), typeof(EPEmployee.salesSubID), typeof(DRDeferredCode.subID), typeof(SalesPerson.salesSubID) }); } if (subaccountCD != null) { subaccountID = _subaccountProvider.GetSubaccountID(subaccountCD); } return(new AccountSubaccountPair(accountID, subaccountID)); }
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); } }
/// <param name="attachedToOriginalSchedule"> /// Flag added to handle <see cref="DRScheduleDetail"/>'s status /// in the same way as <see cref="DRProcess"/> had done for documents /// attached to original schedule. /// </param> public void ReevaluateSchedule( DRSchedule schedule, DRProcess.DRScheduleParameters scheduleParameters, DRDeferredCode deferralCode, decimal?lineAmount, bool attachedToOriginalSchedule) { _schedule = schedule; _schedule.DocDate = scheduleParameters.DocDate; _schedule.BAccountID = scheduleParameters.BAccountID; _schedule.BAccountLocID = scheduleParameters.BAccountLocID; _schedule.FinPeriodID = scheduleParameters.FinPeriodID; _schedule.TranDesc = scheduleParameters.TranDesc; _schedule.IsCustom = false; _schedule.IsDraft = _isDraft; _schedule.BAccountType = _schedule.Module == BatchModule.AP ? BAccountType.VendorType : BAccountType.CustomerType; _schedule.TermStartDate = scheduleParameters.TermStartDate; _schedule.TermEndDate = scheduleParameters.TermEndDate; _schedule.ProjectID = scheduleParameters.ProjectID; _schedule.TaskID = scheduleParameters.TaskID; _schedule = _drEntityStorage.Update(_schedule); IList <DRScheduleDetail> scheduleDetails = _drEntityStorage.GetScheduleDetails(_schedule.ScheduleID); ReevaluateComponentAmounts(scheduleDetails, lineAmount); foreach (DRScheduleDetail scheduleDetail in scheduleDetails) { scheduleDetail.DocDate = _schedule.DocDate; scheduleDetail.BAccountID = _schedule.BAccountID; FinPeriod detailFinPeriod = FinPeriodRepository .GetFinPeriodByMasterPeriodID(PXAccess.GetParentOrganizationID(scheduleDetail.BranchID), _schedule.FinPeriodID).GetValueOrRaiseError(); scheduleDetail.FinPeriodID = detailFinPeriod.FinPeriodID; scheduleDetail.TranPeriodID = detailFinPeriod.MasterFinPeriodID; if (!attachedToOriginalSchedule) { scheduleDetail.Status = _isDraft ? DRScheduleStatus.Draft : (scheduleDetail.IsResidual == null ? DRScheduleStatus.Closed : DRScheduleStatus.Open); } else { scheduleDetail.Status = _isDraft ? DRScheduleStatus.Draft : (scheduleDetail.IsOpen == true ? DRScheduleStatus.Open : DRScheduleStatus.Closed); } _drEntityStorage.Update(scheduleDetail); if (scheduleDetail.IsResidual != true) { DRDeferredCode detailDeferralCode = _drEntityStorage.GetDeferralCode(scheduleDetail.DefCode); IEnumerable <DRScheduleTran> componentTransactions = _drEntityStorage.GetDeferralTransactions(scheduleDetail.ScheduleID, scheduleDetail.ComponentID, scheduleDetail.DetailLineNbr); if (componentTransactions.Any()) { ReevaluateTransactionAmounts(scheduleDetail, detailDeferralCode, componentTransactions); } if (!_isDraft) { if (!componentTransactions.Any()) { componentTransactions = _drEntityStorage.CreateDeferralTransactions(_schedule, scheduleDetail, detailDeferralCode, _branchID); } _drEntityStorage.CreateCreditLineTransaction(scheduleDetail, deferralCode, _branchID); _drEntityStorage.NonDraftDeferralTransactionsPrepared(scheduleDetail, detailDeferralCode, componentTransactions); } } } }
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); } } }