Calculating the Forecast based on Invoices and not Opportunities

Question

I need to perform calculations based on invoices in the [Forecast] section

Answer

1. Modify the ForecastBuilder schema. Replace the following code in the openForecastPage() method:

var valuePairs = [
 {
  name: "EntitySchemaUId",
  value: "ae46fb87-c02c-4ae8-ad31-a923cdd994cf"
 },
 {
  name: "EntitySchemaName",
  value: "Opportunity"
 }
];

for:

var valuePairs = [
 {
  name: "EntitySchemaUId",
  value: "bfb313dd-bb55-4e1b-8e42-3d346e0da7c5"
 },
 {
  name: "EntitySchemaName",
  value: "Invoice"
 }
];

2. Apply changes to the stored tsp_RecalculateForecastFact procedure.

Replace the opportunity table for the invoice table, change the stage and data conditions. The source code of the stored procedure:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[tsp_RecalculateForecastFact]
@ForecastId UNIQUEIDENTIFIER = NULL,
@CurrentUserContactId UNIQUEIDENTIFIER = NULL
AS
IF @ForecastId IS NULL
BEGIN
	RETURN;
END
DECLARE @PlanIndicatorId UNIQUEIDENTIFIER
DECLARE @FactIndicatorId UNIQUEIDENTIFIER
DECLARE @FactPercentIndicatorId UNIQUEIDENTIFIER
DECLARE @PotentialIndicatorId UNIQUEIDENTIFIER
DECLARE @CompletedId UNIQUEIDENTIFIER
DECLARE @ForecastItemId UNIQUEIDENTIFIER
DECLARE @DimensionId UNIQUEIDENTIFIER
DECLARE @DimensionValueId UNIQUEIDENTIFIER
DECLARE @PeriodId UNIQUEIDENTIFIER
DECLARE @StartDate DATE
DECLARE @DueDate DATE
DECLARE @MaxDueDate DATE
DECLARE @ColumnName NVARCHAR(100)
DECLARE @SQLText NVARCHAR(MAX)
DECLARE @PlanAmount DECIMAL(18,2)
DECLARE @FactAmount DECIMAL(18,2)
DECLARE @PotentialAmount DECIMAL(18,2)
DECLARE @FactPotentialAmountTable TABLE (PlanAmount DECIMAL(18,2), FactAmount DECIMAL(18,2), PotentialAmount DECIMAL(18,2))
SET @PlanIndicatorId = '{CBD311C7-6E1B-4324-BF21-192681349DDF}'
SET @FactIndicatorId = '{52CAE26F-84F6-42A0-AAEF-97790AF3B8D9}'
SET @FactPercentIndicatorId = '{E0D66FFB-A3E3-4DA9-BCB7-95D27033286E}'
SET @PotentialIndicatorId = '{A004FC7A-D63D-4E3C-9356-0AD77B2600F3}'
--SET @CompletedId = '{60D5310C-5BE6-DF11-971B-001D60E938C6}'
SET @CompletedId = '{698D39FD-52E6-DF11-971B-001D60E938C6}' --Paid PaymentStatusId from InvoicePaymentStatus
DELETE FROM ForecastItemValue 
WHERE ForecastIndicatorId IN (@FactIndicatorId, @FactPercentIndicatorId, @PotentialIndicatorId)
AND EXISTS (SELECT 1 
			FROM ForecastItem fi 
			WHERE ForecastItemValue.ForecastItemId = fi.Id
				AND fi.ForecastId = @ForecastId 
			) 
SET @MaxDueDate = (SELECT Convert(Date, MAX(StartDate), 104) FROM Invoice o WHERE o.PaymentStatusId = @CompletedId)
DECLARE Cur CURSOR STATIC LOCAL FOR
SELECT
fi.Id ForecastItemId,
d.Id DimensionId, 
fi.DimensionValueId DimensionValueId,
p.Id PeriodId,
p.StartDate StartDate,
p.DueDate DueDate,
d.[Path] + 'Id'
FROM ForecastItem fi
INNER JOIN Forecast f ON f.Id = fi.ForecastId
INNER JOIN ForecastDimension fd ON fd.Id = fi.ForecastDimensionId
INNER JOIN Dimension d ON d.Id = fd.DimensionId
INNER JOIN Period p ON p.PeriodTypeId = f.PeriodTypeId
WHERE f.Id = @ForecastId
AND ISNULL(d.[Path],'') <> ''
AND p.StartDate <= @MaxDueDate
 
SET NOCOUNT ON;
 
OPEN Cur
FETCH NEXT FROM Cur INTO @ForecastItemId, @DimensionId, @DimensionValueId, @PeriodId, @StartDate, @DueDate, @ColumnName
WHILE @@FETCH_STATUS = 0
BEGIN
	SET @DueDate = DATEADD(DAY, 1, @DueDate)
	DELETE FROM @FactPotentialAmountTable
	SET @SQLText = N' SELECT (SELECT SUM(ISNULL(fiv.[Value], 0)) FROM [ForecastItemValue] fiv WHERE fiv.[ForecastItemId] = @P5 AND fiv.[PeriodId] = @P6 AND fiv.[ForecastIndicatorId] = @P7 ) PlanAmount, (SELECT SUM(ISNULL(o.[Amount], 0)) FROM [Invoice] o WHERE o.[PaymentStatusId] = @P1 AND o.[StartDate] >= @P2 AND o.[StartDate] < @P3 AND o.' + @ColumnName + N' = @P4 ) FactAmount, (SELECT SUM(ISNULL(o.[Amount], 0)) FROM [Invoice] o INNER JOIN [InvoicePaymentStatus] os ON os.[Id] = o.[PaymentStatusId] WHERE os.[FinalStatus] = 0 AND o.[StartDate] >= @P2 AND o.[StartDate] < @P3 AND o.' + @ColumnName + N' = @P4 ) PotentialAmount'
	INSERT INTO @FactPotentialAmountTable exec sp_executesql @SQLText,
	N'@P1 UNIQUEIDENTIFIER, @P2 DATE, @P3 DATE, @P4 UNIQUEIDENTIFIER, @P5 UNIQUEIDENTIFIER, @P6 UNIQUEIDENTIFIER, @P7 UNIQUEIDENTIFIER',
	@P1 = @CompletedId, @P2 = @StartDate, @P3 = @DueDate, @P4 = @DimensionValueId, @P5 = @ForecastItemId,
	@P6 = @PeriodId, @P7 =  @PlanIndicatorId
	SELECT @PlanAmount = PlanAmount, @FactAmount = FactAmount, @PotentialAmount = PotentialAmount 
	FROM @FactPotentialAmountTable
	IF (@FactAmount <> 0)
	BEGIN
		INSERT INTO ForecastItemValue
		(
			Id,
			CreatedOn,
			CreatedById,
			ModifiedOn,
			ModifiedById,
			ProcessListeners,
			ForecastIndicatorId,
			[Value],
			PeriodId,
			ForecastItemId
		)
		VALUES
		(
			NEWID(),
			GETUTCDATE(),
			@CurrentUserContactId,
			GETUTCDATE(),
			@CurrentUserContactId,
			0,
			@FactIndicatorId,
			@FactAmount,
			@PeriodId,
			@ForecastItemId
		)
		IF (@PlanAmount <> 0)
		BEGIN
			INSERT INTO ForecastItemValue
			(
				Id,
				CreatedOn,
				CreatedById,
				ModifiedOn,
				ModifiedById,
				ProcessListeners,
				ForecastIndicatorId,
				[Value],
				PeriodId,
				ForecastItemId
			)
			VALUES
			(
				NEWID(),
				GETUTCDATE(),
				@CurrentUserContactId,
				GETUTCDATE(),
				@CurrentUserContactId,
				0,
				@FactPercentIndicatorId,
				CAST((@FactAmount * 100 / @PlanAmount) AS DECIMAL(18, 2)),
				@PeriodId,
				@ForecastItemId
			)
		END
	END
 
	IF (@PotentialAmount <> 0)
	BEGIN
		INSERT  INTO ForecastItemValue
		(
			Id,
			CreatedOn,
			CreatedById,
			ModifiedOn,
			ModifiedById,
			ProcessListeners,
			ForecastIndicatorId,
			[Value],
			PeriodId,
			ForecastItemId
		)
		VALUES
		(
			NEWID(),
			GETUTCDATE(),
			@CurrentUserContactId,
			GETUTCDATE(),
			@CurrentUserContactId,
			0,
			@PotentialIndicatorId,
			@PotentialAmount ,
			@PeriodId,
			@ForecastItemId
		)
	END
FETCH NEXT FROM Cur INTO @ForecastItemId, @DimensionId, @DimensionValueId, @PeriodId, @StartDate, @DueDate, @ColumnName
END
CLOSE Cur
DEALLOCATE Cur

 You can set the condition columns that create separate tabs in the following table:

SELECT * FROM Dimension

They have Account, ResponsibleDepartment, Owner and LeadType specified by default.

Like 0

Like

0 comments
Show all comments