USP_GROUP_GIVINGSUMMARYGET
Returns giving summary values for a group.
Parameters
Parameter | Parameter Type | Mode | Description |
---|---|---|---|
@CONSTITUENTID | uniqueidentifier | IN | |
@GROUPINCLUDESMEMBERGIVING | bit | INOUT | |
@ISHOUSEHOLD | bit | INOUT | |
@TOTALNUMBER | int | INOUT | |
@TOTALAMOUNT | money | INOUT | |
@TOTALGROUPAMOUNT | money | INOUT | |
@TOTALGROUPMEMBERAMOUNT | money | INOUT | |
@AVERAGEAMOUNT | money | INOUT | |
@MOSTFREQUENTAMOUNT | money | INOUT | |
@TOTALPLEDGEBALANCE | money | INOUT | |
@TOTALYEARS | int | INOUT | |
@CONSECUTIVEYEARS | int | INOUT | |
@GIVENSINCEFISCALYEAR | datetime | INOUT | |
@CURRENTAPPUSERID | uniqueidentifier | IN | |
@SITEFILTERMODE | tinyint | IN | |
@SITESSELECTED | xml | IN | |
@SECURITYFEATUREID | uniqueidentifier | IN | |
@SECURITYFEATURETYPE | tinyint | IN | |
@GROUPMEMBERTAXCLAIMAMOUNT | money | INOUT | |
@MATCHEDGIFTSAMOUNT | money | INOUT | |
@CURRENCYID | uniqueidentifier | IN |
Definition
Copy
CREATE procedure [dbo].[USP_GROUP_GIVINGSUMMARYGET]
(
@CONSTITUENTID uniqueidentifier,
@GROUPINCLUDESMEMBERGIVING bit = null output,
@ISHOUSEHOLD bit = null output,
@TOTALNUMBER int = null output,
@TOTALAMOUNT money = null output,
@TOTALGROUPAMOUNT money = null output,
@TOTALGROUPMEMBERAMOUNT money = null output,
@AVERAGEAMOUNT money = null output,
@MOSTFREQUENTAMOUNT money = null output,
@TOTALPLEDGEBALANCE money = null output,
@TOTALYEARS int = null output,
@CONSECUTIVEYEARS int = null output,
@GIVENSINCEFISCALYEAR datetime = null output,
@CURRENTAPPUSERID uniqueidentifier = null,
@SITEFILTERMODE tinyint = 0,
@SITESSELECTED xml = null,
@SECURITYFEATUREID uniqueidentifier = null,
@SECURITYFEATURETYPE tinyint = null,
@GROUPMEMBERTAXCLAIMAMOUNT money = null output,
@MATCHEDGIFTSAMOUNT money = null output,
@CURRENCYID uniqueidentifier = null
)
as
set nocount on
declare @CURRENTDATE datetime;
set @CURRENTDATE = getdate();
declare @HOUSEHOLDSCANBEDONORS as bit
set @HOUSEHOLDSCANBEDONORS = dbo.UFN_INSTALLATIONINFO_GETHOUSEHOLDSCANBEDONORS()
declare @ORGANIZATIONCURRENCYID uniqueidentifier;
declare @DECIMALDIGITS tinyint;
declare @ROUNDINGTYPECODE tinyint;
select @ORGANIZATIONCURRENCYID = dbo.UFN_CURRENCY_GETORGANIZATIONCURRENCY(),
@DECIMALDIGITS = DECIMALDIGITS,
@ROUNDINGTYPECODE = ROUNDINGTYPECODE
from
dbo.CURRENCY
where
CURRENCY.ID = @CURRENCYID;
-- Households can be donors depending on a value of a system flag, other groups are allowed to be
-- donors through their type
select
@GROUPINCLUDESMEMBERGIVING =
case
when GD.GROUPTYPECODE = 0 then 1
when GD.GROUPTYPECODE = 1 then GT.INCLUDEMEMBERGIVING
end,
@ISHOUSEHOLD =
case
when GD.GROUPTYPECODE = 0 then 1
when GD.GROUPTYPECODE = 1 then 0
end
from dbo.GROUPDATA GD
left join dbo.GROUPTYPE GT on GD.GROUPTYPEID = GT.ID
where GD.ID=@CONSTITUENTID;
-- put all group and member giving into table variable, then perform calculations/get data from it. This simplifies design
-- by placing the selection logic in a single function, rather than a half-dozen restatements of the same lengthy joins and filters.
-- It also improves performance by avoiding performing the same joins/filters multiple times
declare @GIVING table
(
REVENUEID uniqueidentifier,
TRANSACTIONTYPECODE tinyint,
TRANSACTIONTYPE nvarchar(19),
REVENUEAMOUNT money,
[DATE] datetime,
DATEADDED datetime,
SPLITID uniqueidentifier,
APPLICATIONCODE tinyint,
DESIGNATIONID uniqueidentifier,
SPLITAMOUNT money,
WRITEOFFAMOUNT money,
CONSTITUENTID uniqueidentifier,
SPLITNETAMOUNT money
)
declare @MEMBERIDS table
(
ID uniqueidentifier,
DATEFROM datetime,
DATETO datetime
)
if @GROUPINCLUDESMEMBERGIVING = 1
begin
insert into @MEMBERIDS
select
GROUPMEMBER.MEMBERID ID, DATEFROM, DATETO
from
dbo.GROUPMEMBER
left join
dbo.GROUPMEMBERDATERANGE on GROUPMEMBERDATERANGE.GROUPMEMBERID = GROUPMEMBER.ID
where
GROUPMEMBER.GROUPID = @CONSTITUENTID;
insert into @GIVING
select
REVENUEID,
TRANSACTIONTYPECODE,
TRANSACTIONTYPE,
REVENUEAMOUNT,
[DATE],
DATEADDED,
SPLITID,
APPLICATIONCODE,
REV.DESIGNATIONID,
SPLITAMOUNT,
WRITEOFFAMOUNT,
MEMBERIDS.ID CONSTITUENTID,
SPLITNETAMOUNT money
from
@MEMBERIDS MEMBERIDS
cross apply dbo.UFN_CONSTITUENT_GIVINGHISTORYINCURRENCY_BULK(
MEMBERIDS.ID,
@CURRENTAPPUSERID,
@SITEFILTERMODE,
@SITESSELECTED,
@SECURITYFEATUREID,
@SECURITYFEATURETYPE,
@CURRENCYID,
@ORGANIZATIONCURRENCYID,
@DECIMALDIGITS,
@ROUNDINGTYPECODE) REV
where
((MEMBERIDS.DATEFROM is null or REV.DATE >= MEMBERIDS.DATEFROM) and
(MEMBERIDS.DATETO is null or REV.DATE <= MEMBERIDS.DATETO));
end
if not (@ISHOUSEHOLD = 1 and @HOUSEHOLDSCANBEDONORS = 0)
begin
insert into @GIVING
select
REVENUEID,
TRANSACTIONTYPECODE,
TRANSACTIONTYPE,
REVENUEAMOUNT,
[DATE],
DATEADDED,
SPLITID,
APPLICATIONCODE,
REV.DESIGNATIONID,
SPLITAMOUNT,
WRITEOFFAMOUNT,
@CONSTITUENTID,
SPLITNETAMOUNT
from dbo.UFN_CONSTITUENT_GIVINGHISTORYINCURRENCY_BULK(
@CONSTITUENTID,
@CURRENTAPPUSERID,
@SITEFILTERMODE,
@SITESSELECTED,
@SECURITYFEATUREID,
@SECURITYFEATURETYPE,
@CURRENCYID,
@ORGANIZATIONCURRENCYID,
@DECIMALDIGITS,
@ROUNDINGTYPECODE) REV
end
select
@TOTALNUMBER = count(distinct G.REVENUEID),
@TOTALAMOUNT = cast(sum(cast(SPLITNETAMOUNT as decimal(20,5))) as money),
@TOTALPLEDGEBALANCE = cast(sum(case TRANSACTIONTYPECODE when 1 then cast(dbo.UFN_PLEDGESPLIT_GETBALANCEINCURRENCY(G.SPLITID, @CURRENCYID) as decimal(20,5)) else 0 end) as money)
from @GIVING G
select
@TOTALGROUPMEMBERAMOUNT = cast(sum(cast(SPLITNETAMOUNT as decimal(20,5))) as money),
@GROUPMEMBERTAXCLAIMAMOUNT = cast(sum(cast(dbo.UFN_GIFTAID_GETTAXCLAIMAMOUNTINCURRENCY(SPLITID, TRANSACTIONTYPECODE, APPLICATIONCODE, @CURRENCYID) as decimal(20,5))) as money)
from @GIVING G
where CONSTITUENTID in (select ID from @MEMBERIDS)
select
@TOTALGROUPAMOUNT = cast(sum(cast(SPLITNETAMOUNT as decimal(20,5))) as money)
from @GIVING G
where CONSTITUENTID not in (select ID from @MEMBERIDS)
-- values will be null if the selects got short-circuited for number of gifts, amounts, and pledge balances
set @TOTALGROUPMEMBERAMOUNT = ISNULL(@TOTALGROUPMEMBERAMOUNT, 0)
set @TOTALGROUPAMOUNT = ISNULL(@TOTALGROUPAMOUNT, 0)
set @TOTALNUMBER = isnull(@TOTALNUMBER, 0);
set @TOTALAMOUNT = isnull(@TOTALAMOUNT, 0);
set @TOTALPLEDGEBALANCE = isnull(@TOTALPLEDGEBALANCE, 0);
set @AVERAGEAMOUNT = 0;
if @TOTALNUMBER <> 0
set @AVERAGEAMOUNT = @TOTALAMOUNT / @TOTALNUMBER;
--Matched by organization amount
select
@MATCHEDGIFTSAMOUNT = sum(AMOUNT)
from
(
select
REVENUE.AMOUNTINCURRENCY as AMOUNT
from
@GIVING
inner join
dbo.REVENUEMATCHINGGIFT on REVENUEMATCHINGGIFT.MGSOURCEREVENUEID = REVENUEID
inner join
dbo.UFN_REVENUE_GETAMOUNTSINCURRENCY_BULK(@CURRENCYID, @ORGANIZATIONCURRENCYID, @DECIMALDIGITS, @ROUNDINGTYPECODE) REVENUE on REVENUE.ID = REVENUEMATCHINGGIFT.ID
group by
REVENUEID, REVENUE.AMOUNTINCURRENCY
) SUBQ
set @MATCHEDGIFTSAMOUNT = coalesce(@MATCHEDGIFTSAMOUNT, 0);
/*
For the most frequent gifts, the pattern taken is:
1. Figure out what the variant would be only for the group members IF
members are included in the giving.
2. Over-ride those values using the variant for the group itself IF the group
can be a donor AND a comparison passes (i.e. the largest gift from the group
is larger than the largest gift from the group members)
*/
-- most frequent group member amount
declare @GROUPMEMBERAMOUNTFREQUENCY integer;
declare @MOSTFREQUENTGROUPMEMBERAMOUNT money;
with PLEDGEANDPAYMENTCTE as
(
select
REVENUEID ID,
sum(SPLITNETAMOUNT) as NETAMOUNT
from @GIVING
where CONSTITUENTID in (select ID from @MEMBERIDS)
group by REVENUEID
)
select top 1
@MOSTFREQUENTGROUPMEMBERAMOUNT = X.NETAMOUNT,
@GROUPMEMBERAMOUNTFREQUENCY = X.MAXCOUNT
from
(select
R.NETAMOUNT NETAMOUNT,
count(R.ID) TOTAL,
max(count(R.ID)) over () MAXCOUNT
from
PLEDGEANDPAYMENTCTE R
group by NETAMOUNT) X
where
X.TOTAL = X.MAXCOUNT and X.TOTAL > 1
order by
X.NETAMOUNT desc;
-- most frequent group amount
declare @MOSTFREQUENTGROUPAMOUNT money;
declare @GROUPAMOUNTFREQUENCY integer;
with PLEDGEANDPAYMENTCTE as
(
select
REVENUEID ID,
sum(SPLITNETAMOUNT) as NETAMOUNT
from @GIVING
where CONSTITUENTID not in (select ID from @MEMBERIDS)
group by REVENUEID
)
select top 1
@MOSTFREQUENTGROUPAMOUNT = X.NETAMOUNT,
@GROUPAMOUNTFREQUENCY = X.MAXCOUNT
from
(select
NETAMOUNT,
count(R.ID) TOTAL,
max(count(R.ID)) over () MAXCOUNT
from
PLEDGEANDPAYMENTCTE R
group by NETAMOUNT) X
where
X.TOTAL = X.MAXCOUNT and X.TOTAL > 1
order by
X.NETAMOUNT desc;
select top(1)
@MOSTFREQUENTAMOUNT = coalesce(AMOUNT, 0)
from
(select @MOSTFREQUENTGROUPAMOUNT as AMOUNT, @GROUPAMOUNTFREQUENCY as FREQUENCY
union all
select @MOSTFREQUENTGROUPMEMBERAMOUNT as AMOUNT, @GROUPMEMBERAMOUNTFREQUENCY as FREQUENCY) X
order by X.AMOUNT desc;
-- YEAR CALCULATIONS
declare @GIFTYEARS table([YEAR] datetime);
insert into @GIFTYEARS
select dbo.UFN_DATE_THISFISCALYEAR_FIRSTDAY(DATE,0) [YEAR] from @GIVING
group by
dbo.UFN_DATE_THISFISCALYEAR_FIRSTDAY(DATE,0)
order by
dbo.UFN_DATE_THISFISCALYEAR_FIRSTDAY(DATE,0) desc;
--TOTALYEARS
select
@TOTALYEARS = count([YEAR])
from
@GIFTYEARS
--CONSECUTIVE YEARS
declare @FISCALYEAR_FIRSTDAY datetime;
declare @PREVIOUSFISCALYEAR_FIRSTDAY datetime;
declare @CONTINUE bit;
declare FISCALYEARCURSOR cursor local fast_forward for
select
[YEAR] FISCALYEAR_FIRSTDAY
from
@GIFTYEARS;
set @CONSECUTIVEYEARS = 0;
set @GIVENSINCEFISCALYEAR = null;
declare @CURRENTFIRSCALYEAR_FIRSTDAY datetime, @LASTFISCALYEAR_FIRSTDAY datetime
set @CURRENTFIRSCALYEAR_FIRSTDAY = dbo.UFN_DATE_THISFISCALYEAR_FIRSTDAY(@CURRENTDATE,0)
set @LASTFISCALYEAR_FIRSTDAY = dbo.UFN_DATE_THISFISCALYEAR_FIRSTDAY(dateadd(year,-1,@CURRENTDATE),0)
open FISCALYEARCURSOR;
fetch next from FISCALYEARCURSOR into @FISCALYEAR_FIRSTDAY;
if @@FETCH_STATUS = 0 begin
if @FISCALYEAR_FIRSTDAY > @CURRENTFIRSCALYEAR_FIRSTDAY begin
set @CONTINUE = 1;
fetch next from FISCALYEARCURSOR into @PREVIOUSFISCALYEAR_FIRSTDAY;
end
else if @FISCALYEAR_FIRSTDAY = @CURRENTFIRSCALYEAR_FIRSTDAY or
@FISCALYEAR_FIRSTDAY = @LASTFISCALYEAR_FIRSTDAY begin
set @CONSECUTIVEYEARS = @CONSECUTIVEYEARS + 1;
set @CONTINUE = 1;
fetch next from FISCALYEARCURSOR into @PREVIOUSFISCALYEAR_FIRSTDAY;
end
else
set @CONTINUE = 0;
end
while @@FETCH_STATUS = 0 and @CONTINUE = 1 begin
if @CONSECUTIVEYEARS = 0 begin
if @PREVIOUSFISCALYEAR_FIRSTDAY > @CURRENTFIRSCALYEAR_FIRSTDAY begin
set @FISCALYEAR_FIRSTDAY = @PREVIOUSFISCALYEAR_FIRSTDAY;
fetch next from FISCALYEARCURSOR into @PREVIOUSFISCALYEAR_FIRSTDAY;
end
else if @PREVIOUSFISCALYEAR_FIRSTDAY = @CURRENTFIRSCALYEAR_FIRSTDAY or
@PREVIOUSFISCALYEAR_FIRSTDAY = @LASTFISCALYEAR_FIRSTDAY begin
set @CONSECUTIVEYEARS = @CONSECUTIVEYEARS + 1;
set @FISCALYEAR_FIRSTDAY = @PREVIOUSFISCALYEAR_FIRSTDAY;
fetch next from FISCALYEARCURSOR into @PREVIOUSFISCALYEAR_FIRSTDAY;
end
else
set @CONTINUE = 0
end
else if @PREVIOUSFISCALYEAR_FIRSTDAY = dateadd(year, -1, @FISCALYEAR_FIRSTDAY) begin
set @CONSECUTIVEYEARS = @CONSECUTIVEYEARS + 1;
set @FISCALYEAR_FIRSTDAY = @PREVIOUSFISCALYEAR_FIRSTDAY;
fetch next from FISCALYEARCURSOR into @PREVIOUSFISCALYEAR_FIRSTDAY;
end
else
set @CONTINUE = 0;
end
--When a cursor is used, it should be explicitly closed/deallocated in case of blocking or USP running long
close FISCALYEARCURSOR;
deallocate FISCALYEARCURSOR;
if @CONSECUTIVEYEARS > 0
set @GIVENSINCEFISCALYEAR = @FISCALYEAR_FIRSTDAY;