USP_PLEDGE_PAYINSTALLMENTS
Stored proc to apply a payment to a pledge
Parameters
Parameter | Parameter Type | Mode | Description |
---|---|---|---|
@PLEDGEID | uniqueidentifier | IN | |
@REVENUEID | uniqueidentifier | IN | |
@AMOUNT | money | INOUT | |
@CAID | uniqueidentifier | IN | |
@CHANGEDATE | datetime | IN | |
@CREATEDSPLITS | xml | INOUT | |
@OVERPAYMENTAPPLICATIONTYPECODE | tinyint | IN | |
@BASEAMOUNT | money | IN | |
@ORGANIZATIONAMOUNT | money | IN | |
@APPLICATIONSPLITS | xml | IN |
Definition
Copy
CREATE procedure [dbo].[USP_PLEDGE_PAYINSTALLMENTS]
(
@PLEDGEID uniqueidentifier,
@REVENUEID uniqueidentifier,
@AMOUNT money output, -- the transaction amount of the revenue stream
@CAID uniqueidentifier,
@CHANGEDATE datetime,
@CREATEDSPLITS xml = null output,
@OVERPAYMENTAPPLICATIONTYPECODE tinyint = null,
@BASEAMOUNT money = null,
@ORGANIZATIONAMOUNT money = null,
@APPLICATIONSPLITS xml = null
)
as
set nocount on;
declare @installmentPayAmount money;
declare @amountPaid money;
declare @amountLeft money;
declare @installmentBalance money;
declare @PLEDGETYPECODE tinyint;
declare @APPLICATIONCODE tinyint;
set @amountPaid = 0;
set @amountLeft = @AMOUNT;
declare @splits table
(
INSTALLMENTSPLITID uniqueidentifier,
AMOUNTAPPLICATION money,
DESIGNATIONID uniqueidentifier,
PLEDGETYPECODE tinyint,
PLEDGEREVENUESPLITID uniqueidentifier
);
declare @splitsXml xml;
declare @paymentSplitsXml xml;
declare @applicationSplitsTable table
(
ID uniqueidentifier,
AMOUNT money
);
declare @amountApplication money;
declare @installmentPayAmountApplication money;
declare @amountPaidApplication money;
declare @amountLeftApplication money;
declare @PAYMENTBASECURRENCYID uniqueidentifier;
declare @PAYMENTTRANSACTIONCURRENCYID uniqueidentifier;
declare @PAYMENTBASEEXCHANGERATEID uniqueidentifier;
declare @PAYMENTORGANIZATIONEXCHANGERATEID uniqueidentifier;
declare @PAYMENTRANSACTIONCURRENCYDECIMALDIGITS tinyint;
declare @PAYMENBASECURRENCYDECIMALDIGITS tinyint;
declare @REVENUEDATE datetime;
declare @APPLICATIONCURRENCYID uniqueidentifier;
declare @APPLICATIONEXCHANGERATEID uniqueidentifier;
declare @APPLICATIONCURRENCYDECIMALDIGITS tinyint;
declare @ORGANIZATIONCURRENCYID uniqueidentifier = dbo.UFN_CURRENCY_GETORGANIZATIONCURRENCY();
declare @ORGANIZATIONCURRENCYDECIMALDIGITS tinyint;
select
@REVENUEDATE = FINANCIALTRANSACTION.DATE,
@PAYMENTBASECURRENCYID = CURRENCYSET.BASECURRENCYID,
@PAYMENTTRANSACTIONCURRENCYID = FINANCIALTRANSACTION.TRANSACTIONCURRENCYID,
@PAYMENTBASEEXCHANGERATEID = FINANCIALTRANSACTION.BASEEXCHANGERATEID,
@PAYMENTORGANIZATIONEXCHANGERATEID = FINANCIALTRANSACTION.ORGEXCHANGERATEID,
@PAYMENTRANSACTIONCURRENCYDECIMALDIGITS = TRANSACTIONCURRENCY.DECIMALDIGITS,
@PAYMENBASECURRENCYDECIMALDIGITS = BASECURRENCY.DECIMALDIGITS
from
dbo.FINANCIALTRANSACTION
inner join dbo.REVENUE_EXT on FINANCIALTRANSACTION.ID = REVENUE_EXT.ID
inner join dbo.PDACCOUNTSYSTEM on FINANCIALTRANSACTION.PDACCOUNTSYSTEMID = PDACCOUNTSYSTEM.ID
inner join dbo.CURRENCYSET on PDACCOUNTSYSTEM.CURRENCYSETID = CURRENCYSET.ID
inner join dbo.CURRENCY as TRANSACTIONCURRENCY on FINANCIALTRANSACTION.TRANSACTIONCURRENCYID = TRANSACTIONCURRENCY.ID
inner join dbo.CURRENCY as BASECURRENCY on CURRENCYSET.BASECURRENCYID = BASECURRENCY.ID
where
FINANCIALTRANSACTION.ID = @REVENUEID
and FINANCIALTRANSACTION.DELETEDON is null;
select
@ORGANIZATIONCURRENCYDECIMALDIGITS = CURRENCY.DECIMALDIGITS
from
dbo.CURRENCY
where
CURRENCY.ID = @ORGANIZATIONCURRENCYID;
select
@APPLICATIONCURRENCYID = TRANSACTIONCURRENCYID,
@APPLICATIONCURRENCYDECIMALDIGITS = CURRENCY.DECIMALDIGITS,
@APPLICATIONCODE = case FINANCIALTRANSACTION.TYPECODE
when 3 then 7 -- Matching Gift Pledge
when 4 then 6 -- Planned Gift
when 6 then 8 -- Grant award
when 8 then 13 -- Donor Challenge
when 9 then 17 -- Pending Gift
when 15 then 19 -- Membership installment plan
else 2 -- Pledge
end
from
dbo.FINANCIALTRANSACTION
inner join dbo.REVENUE_EXT on FINANCIALTRANSACTION.ID = REVENUE_EXT.ID
inner join dbo.CURRENCY on FINANCIALTRANSACTION.TRANSACTIONCURRENCYID = CURRENCY.ID
where
FINANCIALTRANSACTION.ID = @PLEDGEID
and FINANCIALTRANSACTION.DELETEDON is null;
if @APPLICATIONCURRENCYID <> @PAYMENTTRANSACTIONCURRENCYID
begin
if @APPLICATIONCURRENCYID = @PAYMENTBASECURRENCYID
set @APPLICATIONEXCHANGERATEID = @PAYMENTBASEEXCHANGERATEID;
else
set @APPLICATIONEXCHANGERATEID = dbo.UFN_CURRENCYEXCHANGERATE_GETLATEST(@PAYMENTTRANSACTIONCURRENCYID,@APPLICATIONCURRENCYID,@REVENUEDATE,1,null);
if @APPLICATIONEXCHANGERATEID is null
begin
raiserror('BBERR_APPLICATIONEXCHANGERATEDOESNOTEXIST : You cannot apply the payment toward this application. No exchange rate exists between the payment and application currencies.', 13, 1);
return 1;
end
end
-- Convert the applied amount into base and organization amounts if it is not provided by the caller
if @BASEAMOUNT is null or @ORGANIZATIONAMOUNT is null
exec dbo.USP_CURRENCY_GETCURRENCYVALUES @AMOUNT, @REVENUEDATE, @PAYMENTBASECURRENCYID, @PAYMENTBASEEXCHANGERATEID, @PAYMENTTRANSACTIONCURRENCYID, @BASEAMOUNT output, null, @ORGANIZATIONAMOUNT output, @PAYMENTORGANIZATIONEXCHANGERATEID, 0, null;
if @APPLICATIONCURRENCYID = @PAYMENTTRANSACTIONCURRENCYID
set @amountApplication = @AMOUNT;
else
set @amountApplication = dbo.UFN_CURRENCY_CONVERT(@AMOUNT, @APPLICATIONEXCHANGERATEID);
set @amountPaidApplication = 0;
set @amountLeftApplication = @amountApplication;
declare @CREATEDSPLIT table
(
CREATEDREVENUESPLITID uniqueidentifier,
SOURCEREVENUESPLITID uniqueidentifier
);
if @OVERPAYMENTAPPLICATIONTYPECODE is null
set @OVERPAYMENTAPPLICATIONTYPECODE = coalesce(dbo.UFN_PLEDGE_GETDEFAULTOVERPAYMENTAPPLICATIONCODE(), 255);
if not @OVERPAYMENTAPPLICATIONTYPECODE in (0, 1, 255)
set @OVERPAYMENTAPPLICATIONTYPECODE = 1;
--Overpayment option to pay pledge balance, so pay first installment as usual, then pay from last installment forward
if @OVERPAYMENTAPPLICATIONTYPECODE = 0
begin
--Find the minimum valid sequence number to be paid
declare @MINSEQUENCE integer;
select @MINSEQUENCE = min(INSTALLMENT.SEQUENCE)
from dbo.INSTALLMENTSPLIT
inner join dbo.INSTALLMENT
on INSTALLMENTSPLIT.INSTALLMENTID = INSTALLMENT.ID
where
(
dbo.UFN_INSTALLMENT_GETINSTALLMENTSPLITBALANCE(INSTALLMENTSPLIT.ID) > 0 or
(
-- WI 191314: $0 pledges can have $0 installments that need to be included
-- so the link between the pledge and payment isn't broken
INSTALLMENT.AMOUNT = 0 and
@AMOUNT = 0
)
)
and INSTALLMENT.REVENUEID = @PLEDGEID;
--Find a sequence number above valid installments for this pledge
declare @PAYFIRSTSEQUENCE integer;
select @PAYFIRSTSEQUENCE = (MAX(SEQUENCE) + 1) from [dbo].[UFN_PLEDGE_GETINSTALLMENTS](@PLEDGEID)
declare INSTALLMENTCURSOR cursor local fast_forward for
select
INSTALLMENT.ID,
dbo.UFN_INSTALLMENT_GETINSTALLMENTBALANCE(INSTALLMENT.ID) [BALANCE]
from
dbo.INSTALLMENT
where
(
dbo.UFN_INSTALLMENT_GETINSTALLMENTBALANCE(INSTALLMENT.ID) > 0 or
(
-- WI 191314: $0 pledges can have $0 installments that need to be included
-- so the link between the pledge and payment isn't broken
INSTALLMENT.AMOUNT = 0 and
@AMOUNT = 0
)
)
and INSTALLMENT.REVENUEID = @PLEDGEID
order by
case
--mark the first installment to pay with the highest sequence
when SEQUENCE = @MINSEQUENCE then @PAYFIRSTSEQUENCE
else SEQUENCE
end desc;
end
--No overpayment option or overpay to next installments, so pay installments in order
else
begin
declare INSTALLMENTCURSOR cursor local fast_forward for
select
INSTALLMENT.ID,
dbo.UFN_INSTALLMENT_GETINSTALLMENTBALANCE(INSTALLMENT.ID) [BALANCE]
from
dbo.INSTALLMENT
where
(
dbo.UFN_INSTALLMENT_GETINSTALLMENTBALANCE(ID) > 0 or
(
-- WI 191314: $0 pledges can have $0 installments that need to be included
-- so the link between the pledge and payment isn't broken
INSTALLMENT.AMOUNT = 0 and
@AMOUNT = 0
)
)
and INSTALLMENT.REVENUEID = @PLEDGEID
order by
SEQUENCE asc;
end
declare @INSTALLMENTCOUNTER int = 0;
declare @INSTALLMENTID uniqueidentifier;
open INSTALLMENTCURSOR;
fetch next from INSTALLMENTCURSOR into @INSTALLMENTID, @installmentBalance;
while @@FETCH_STATUS = 0
begin
-- WI 191314: Changed break condition to support $0 pledges. For those pledges,
-- @amountPaidApplication always equals @amountApplication so need to check that
-- @amountPaidApplication is greater than 0. To avoid applying the same $0 payment
-- to multiple installments, only allow this condition change to take affect on the
-- first loop.
if @amountPaidApplication = @amountApplication and (@amountPaidApplication > 0 or @INSTALLMENTCOUNTER > 0)
break;
-- determine payment amount
if @amountLeftApplication < @installmentBalance
begin
set @installmentPayAmountApplication = @amountLeftApplication;
if (@APPLICATIONSPLITS is not null and @APPLICATIONSPLITS.exist('/APPLICATIONSPLITS/ITEM') = 1)
and (@APPLICATIONCODE = 7) --Matching gift claim
and (@PAYMENTTRANSACTIONCURRENCYID = @APPLICATIONCURRENCYID)
begin
--This should only be executed for the last installment, but clear this
-- table just in case.
delete from @applicationSplitsTable;
if @APPLICATIONCURRENCYID <> @PAYMENTTRANSACTIONCURRENCYID
begin
--Convert application splits amounts from payment transaction currency to application currency.
declare @DECIMALDIGITSAPPLICATIONCURRENCY tinyint;
select @DECIMALDIGITSAPPLICATIONCURRENCY = DECIMALDIGITS from dbo.CURRENCY where ID = @APPLICATIONCURRENCYID;
with CTE_ITEMLIST as ( --Generate row numbers and amounts for each item in the given list.
select
ITEMNUMBER.ROW,
ITEMLIST.ITEM.value('(ITEM[position() = sql:column("ITEMNUMBER.ROW")]/ID)[1]','uniqueidentifier') ID,
ITEMLIST.ITEM.value('(ITEM[position() = sql:column("ITEMNUMBER.ROW")]/AMOUNT)[1]','money') AMOUNT
from @APPLICATIONSPLITS.nodes('/APPLICATIONSPLITS') ITEMLIST(ITEM)
cross join (
select
row_number() over (order by ITEMLIST.ITEM) ROW
from
@APPLICATIONSPLITS.nodes('/APPLICATIONSPLITS/ITEM') ITEMLIST(ITEM)
) ITEMNUMBER
),
CTE_ITEMAPPLIEDRUNNINGTOTAL as ( --Calculate the running total for the applied amount.
select
ROW,
ID,
dbo.UFN_CURRENCY_CONVERTBYPROPORTION(
(
select sum(ALLPREVIOUSITEMAMOUNT.AMOUNT)
from CTE_ITEMLIST ALLPREVIOUSITEMAMOUNT
where ALLPREVIOUSITEMAMOUNT.ROW <= ITEMLIST.ROW
),
@AMOUNT,
@amountApplication,
@DECIMALDIGITSAPPLICATIONCURRENCY
) APPLIEDAMOUNTORRUNNINGTOTAL
from CTE_ITEMLIST as ITEMLIST
)
insert into @applicationSplitsTable
(
ID,
AMOUNT
)
select
ID,
ITEMAPPLIEDRUNNINGTOTAL.APPLIEDAMOUNTORRUNNINGTOTAL
- coalesce(
(
select PREVIOUSCONVERTEDRUNNINGTOTAL.APPLIEDAMOUNTORRUNNINGTOTAL
from CTE_ITEMAPPLIEDRUNNINGTOTAL as PREVIOUSCONVERTEDRUNNINGTOTAL
where PREVIOUSCONVERTEDRUNNINGTOTAL.ROW = ITEMAPPLIEDRUNNINGTOTAL.ROW - 1
)
,0
) APPLIEDAMOUNT
from CTE_ITEMAPPLIEDRUNNINGTOTAL as ITEMAPPLIEDRUNNINGTOTAL;
end
else
begin
insert into @applicationSplitsTable
(
ID,
AMOUNT
)
select
APPLICATIONSPLITS.ITEM.value('ID[1]', 'uniqueidentifier'),
APPLICATIONSPLITS.ITEM.value('AMOUNT[1]', 'money')
from
@APPLICATIONSPLITS.nodes('/APPLICATIONSPLITS/ITEM') as APPLICATIONSPLITS(ITEM);
end
-- use the splits that were passed in (e.g. paying a specific matching gift claim split)
set @splitsXml =
(
select
INSTALLMENTSPLIT.ID,
case
when APPLICATIONSPLITS.AMOUNT < dbo.UFN_INSTALLMENT_GETINSTALLMENTSPLITBALANCE(INSTALLMENTSPLIT.ID)
then APPLICATIONSPLITS.AMOUNT
else
dbo.UFN_INSTALLMENT_GETINSTALLMENTSPLITBALANCE(INSTALLMENTSPLIT.ID)
end as AMOUNT
from
dbo.INSTALLMENTSPLIT
inner join @applicationSplitsTable as APPLICATIONSPLITS on INSTALLMENTSPLIT.REVENUESPLITID = APPLICATIONSPLITS.ID
where
INSTALLMENTSPLIT.INSTALLMENTID = @INSTALLMENTID
for xml raw('ITEM'),type,elements,root('AMOUNTSTOPRORATE'),BINARY BASE64
);
--We will prorate below based on these splits and the @installmentBalance;
-- since the splits may be lower than the full potential allowed by the installment
-- we want to update @installmentBalance here.
set @installmentBalance = (select sum(SPLITS.ITEM.value('AMOUNT[1]', 'money')) from @splitsXml.nodes('/AMOUNTSTOPRORATE/ITEM') as SPLITS(ITEM));
--The amounts are prorated below, but these values represent the maximum that should be applied
-- if the amount remaining to be applied would exceed this sum (which itself is up to but not
-- exceeding the true installment balance), we should not allow the application with this value.
-- @APPLICATIONSPLITS should only be used when there is a single installment (e.g. with a matching gift claim).
if @installmentBalance < @installmentPayAmountApplication
begin
raiserror('BBERR_APPLICATIONSPLITSUNDERPAIDFINALINSTALLMENT : The amount applied to a designation exceeded the balance for that portion of the commitment.', 13, 1);
return 1;
end
end
else
-- otherwise, prorate among designations
set @splitsXml =
(
select
INSTALLMENTSPLIT.ID,
dbo.UFN_INSTALLMENT_GETINSTALLMENTSPLITBALANCE(INSTALLMENTSPLIT.ID) as AMOUNT
from
dbo.INSTALLMENTSPLIT
where
INSTALLMENTSPLIT.INSTALLMENTID = @INSTALLMENTID
for xml raw('ITEM'),type,elements,root('AMOUNTSTOPRORATE'),BINARY BASE64
);
--TODO: We could probably do away with these CTEs if we want to say this function should fail when there
-- are multiple pledge splits with the same designation. This would affect unit tests and my affect customizations.
with
INSTALLMENTSPLITFORINSTALLMENT as
(
select
INSTALLMENTSPLIT.ID,
INSTALLMENTSPLIT.TRANSACTIONAMOUNT,
INSTALLMENTSPLIT.DESIGNATIONID,
INSTALLMENTSPLIT.REVENUESPLITID
from
dbo.INSTALLMENTSPLIT
inner join
dbo.INSTALLMENT on INSTALLMENTSPLIT.INSTALLMENTID = INSTALLMENT.ID
where
INSTALLMENT.ID = @INSTALLMENTID
),
REVENUESPLITFORINSTALLMENT as
(
select
REVENUESPLIT_EXT.DESIGNATIONID,
REVENUESPLIT_EXT.TYPECODE,
FINANCIALTRANSACTIONLINEITEM.ID
from
dbo.INSTALLMENT
inner join
dbo.FINANCIALTRANSACTIONLINEITEM on FINANCIALTRANSACTIONLINEITEM.FINANCIALTRANSACTIONID = INSTALLMENT.REVENUEID
inner join
dbo.REVENUESPLIT_EXT on FINANCIALTRANSACTIONLINEITEM.ID = REVENUESPLIT_EXT.ID
where
INSTALLMENT.ID = @INSTALLMENTID
and FINANCIALTRANSACTIONLINEITEM.DELETEDON is null
and FINANCIALTRANSACTIONLINEITEM.TYPECODE <> 1
)
insert into @splits (INSTALLMENTSPLITID, AMOUNTAPPLICATION, DESIGNATIONID, PLEDGETYPECODE, PLEDGEREVENUESPLITID)
select
INSTALLMENTSPLITFORINSTALLMENT.ID,
PRORATEDAMOUNT.AMOUNT,
INSTALLMENTSPLITFORINSTALLMENT.DESIGNATIONID,
REVENUESPLITFORINSTALLMENT.TYPECODE,
REVENUESPLITFORINSTALLMENT.ID
from
INSTALLMENTSPLITFORINSTALLMENT
inner join
REVENUESPLITFORINSTALLMENT on
INSTALLMENTSPLITFORINSTALLMENT.REVENUESPLITID = REVENUESPLITFORINSTALLMENT.ID
inner join
dbo.UFN_SPLITS_PRORATEAMOUNTS(@installmentBalance, @installmentPayAmountApplication, @APPLICATIONCURRENCYDECIMALDIGITS, @splitsXml) PRORATEDAMOUNT on PRORATEDAMOUNT.ID = INSTALLMENTSPLITFORINSTALLMENT.ID
where
--Don't include $0 payment splits unless the pledge split had a $0 amount.
-- This avoids problem with extra payment splits when paying a matching gift claim that
-- has had certain splits paid off by other payments. It also could come up where
-- a very small payment is paid and some of the splits have $0.01 applied and others
-- have a $0.00 applied.
-- However, do allow $0 application to pledges only. This information is used by clients
-- to track pledge payment history.
PRORATEDAMOUNT.AMOUNT > 0
or
(
(
INSTALLMENTSPLITFORINSTALLMENT.TRANSACTIONAMOUNT = 0
and @AMOUNT = 0
)
or
(
PRORATEDAMOUNT.AMOUNT = 0
and @APPLICATIONCODE = 2
)
);
end
else
begin
set @installmentPayAmountApplication = @installmentBalance;
-- use the full remaining balance for each split because we are paying the whole installment balance
--TODO: We could probably do away with these CTEs if we want to say this function should fail when there
-- are multiple pledge splits with the same designation. This would affect unit tests and my affect customizations.
with
INSTALLMENTSPLITFORINSTALLMENT as
(
select
INSTALLMENTSPLIT.ID,
INSTALLMENTSPLIT.TRANSACTIONAMOUNT,
dbo.UFN_INSTALLMENT_GETINSTALLMENTSPLITBALANCE(INSTALLMENTSPLIT.ID) as BALANCE,
INSTALLMENTSPLIT.DESIGNATIONID,
INSTALLMENTSPLIT.REVENUESPLITID
from
dbo.INSTALLMENTSPLIT
inner join
dbo.INSTALLMENT on INSTALLMENTSPLIT.INSTALLMENTID = INSTALLMENT.ID
where
INSTALLMENT.ID = @INSTALLMENTID
),
REVENUESPLITFORINSTALLMENT as
(
select
REVENUESPLIT_EXT.DESIGNATIONID,
REVENUESPLIT_EXT.TYPECODE,
FINANCIALTRANSACTIONLINEITEM.ID
from
dbo.INSTALLMENT
inner join
dbo.FINANCIALTRANSACTIONLINEITEM on FINANCIALTRANSACTIONLINEITEM.FINANCIALTRANSACTIONID = INSTALLMENT.REVENUEID
inner join
dbo.REVENUESPLIT_EXT on FINANCIALTRANSACTIONLINEITEM.ID = REVENUESPLIT_EXT.ID
where
INSTALLMENT.ID = @INSTALLMENTID
and FINANCIALTRANSACTIONLINEITEM.DELETEDON is null
and FINANCIALTRANSACTIONLINEITEM.TYPECODE <> 1
)
insert into @splits (INSTALLMENTSPLITID, AMOUNTAPPLICATION, DESIGNATIONID, PLEDGETYPECODE, PLEDGEREVENUESPLITID)
select
INSTALLMENTSPLITFORINSTALLMENT.ID,
INSTALLMENTSPLITFORINSTALLMENT.BALANCE,
INSTALLMENTSPLITFORINSTALLMENT.DESIGNATIONID,
REVENUESPLITFORINSTALLMENT.TYPECODE,
REVENUESPLITFORINSTALLMENT.ID
from
INSTALLMENTSPLITFORINSTALLMENT
inner join
REVENUESPLITFORINSTALLMENT on
INSTALLMENTSPLITFORINSTALLMENT.REVENUESPLITID = REVENUESPLITFORINSTALLMENT.ID
where
--Don't include $0 payment splits unless the pledge split had a $0 amount.
-- This avoids problem with extra payment splits when paying a matching gift claim that
-- has had certain splits paid off by other payments. It also could come up where
-- nearly all of a pledge is paid and some of the splits have a $0.01 balance and others
-- have a $0.00 balance.
INSTALLMENTSPLITFORINSTALLMENT.BALANCE > 0
or
(
INSTALLMENTSPLITFORINSTALLMENT.TRANSACTIONAMOUNT = 0
and @AMOUNT = 0
);
end
set @amountPaidApplication = @amountPaidApplication + @installmentPayAmountApplication;
set @amountLeftApplication = @amountLeftApplication - @installmentPayAmountApplication;
set @INSTALLMENTCOUNTER = @INSTALLMENTCOUNTER + 1;
fetch next from INSTALLMENTCURSOR into @INSTALLMENTID, @installmentBalance;
end -- fetch while
close INSTALLMENTCURSOR;
deallocate INSTALLMENTCURSOR;
set @amountPaid = dbo.UFN_CURRENCY_CONVERTBYPROPORTION(@amountPaidApplication, @amountApplication, @AMOUNT, @PAYMENTRANSACTIONCURRENCYDECIMALDIGITS);
-- Determine payment split amounts in the transaction currency of the pledge
set @paymentSplitsXml =
(
select
ID,
AMOUNT
from
(
select
PLEDGEREVENUESPLITID as ID,
sum(AMOUNTAPPLICATION) as AMOUNT
from
@splits
group by
PLEDGEREVENUESPLITID
union all
-- if any amount is unapplied, include that too so the proportions work out, filter this row out of the results below
select
null as ID,
@amountApplication - (select sum(AMOUNTAPPLICATION) from @splits) as AMOUNT
where
@amountPaidApplication <> @amountApplication
) T
for xml raw('ITEM'),type,elements,root('AMOUNTSTOPRORATE'),BINARY BASE64
);
-- Convert payment split amounts to the transaction currency of the payment
set @paymentSplitsXml =
(
select
case when V1.ID is not null and V1.TYPECODE = 99 then V1.ID else newid() end as PAYMENTREVENUESPLITID,
--newid() as PAYMENTREVENUESPLITID,
PRORATEDAMOUNT.ID as PLEDGEREVENUESPLITID,
REVENUESPLIT_EXT.DESIGNATIONID,
PRORATEDAMOUNT.AMOUNT,
REVENUESPLIT_EXT.TYPECODE as PLEDGETYPECODE
from
dbo.UFN_SPLITS_PRORATEAMOUNTS(@amountApplication, @AMOUNT, @PAYMENTRANSACTIONCURRENCYDECIMALDIGITS, @paymentSplitsXml) as PRORATEDAMOUNT
left join dbo.FINANCIALTRANSACTIONLINEITEM on PRORATEDAMOUNT.ID = FINANCIALTRANSACTIONLINEITEM.ID
left join dbo.REVENUESPLIT_EXT on FINANCIALTRANSACTIONLINEITEM.ID = REVENUESPLIT_EXT.ID
left join
(select FINANCIALTRANSACTIONLINEITEM.ID, REVENUESPLIT_EXT.DESIGNATIONID, FINANCIALTRANSACTIONLINEITEM.TYPECODE
from dbo.FINANCIALTRANSACTIONLINEITEM inner join dbo.REVENUESPLIT_EXT on FINANCIALTRANSACTIONLINEITEM.ID = REVENUESPLIT_EXT.ID
where FINANCIALTRANSACTIONLINEITEM.FINANCIALTRANSACTIONID = @REVENUEID
and FINANCIALTRANSACTIONLINEITEM.DELETEDON is null
and FINANCIALTRANSACTIONLINEITEM.TYPECODE != 1) V1 on REVENUESPLIT_EXT.DESIGNATIONID = V1.DESIGNATIONID and V1.TYPECODE = 99
where FINANCIALTRANSACTIONLINEITEM.DELETEDON is null
and FINANCIALTRANSACTIONLINEITEM.TYPECODE <> 1
for xml raw('ITEM'),type,elements,root('ITEMLIST'),BINARY BASE64
);
declare @ADJUSTMENTPOSTSTATUSCODE tinyint;
declare @ADJUSTMENTPOSTDATE date;
declare @ADJUSTMENTID uniqueidentifier;
select top 1
@ADJUSTMENTPOSTSTATUSCODE = case A.POSTSTATUSCODE when 2 then 3 else 1 end
,@ADJUSTMENTPOSTDATE = A.POSTDATE
,@ADJUSTMENTID = ALI.ID
from dbo.ADJUSTMENT A
left join dbo.FINANCIALTRANSACTIONLINEITEMADJUSTMENT ALI on A.ID = ALI.ID
where A.REVENUEID = @REVENUEID
order by A.DATEADDED desc;
declare @PAYMENTREVENUESPLITAPPLIEDCONVERTED table
(
PAYMENTREVENUESPLITID uniqueidentifier,
BASEAMOUNT money,
TRANSACTIONAMOUNT money,
ORGANIZATIONAMOUNT money,
DESIGNATIONID uniqueidentifier,
PLEDGETYPECODE tinyint,
PLEDGEREVENUESPLITID uniqueidentifier
);
insert into
@PAYMENTREVENUESPLITAPPLIEDCONVERTED
select
PAYMENTREVENUESPLITAPPLIEDCONVERTED.ITEM.value('(ITEM/PAYMENTREVENUESPLITID)[1]', 'uniqueidentifier'),
PAYMENTREVENUESPLITAPPLIEDCONVERTED.BASEAMOUNT,
PAYMENTREVENUESPLITAPPLIEDCONVERTED.ITEM.value('(ITEM/AMOUNT)[1]', 'money'),
PAYMENTREVENUESPLITAPPLIEDCONVERTED.ORGANIZATIONAMOUNT,
PAYMENTREVENUESPLITAPPLIEDCONVERTED.ITEM.value('(ITEM/DESIGNATIONID)[1]', 'uniqueidentifier'),
PAYMENTREVENUESPLITAPPLIEDCONVERTED.ITEM.value('(ITEM/PLEDGETYPECODE)[1]', 'tinyint'),
PAYMENTREVENUESPLITAPPLIEDCONVERTED.ITEM.value('(ITEM/PLEDGEREVENUESPLITID)[1]', 'uniqueidentifier')
from
dbo.UFN_CURRENCY_GETCURRENCYVALUESBYPROPORTIONINXML
(
@paymentSplitsXml,
@PAYMENTTRANSACTIONCURRENCYID,
@PAYMENTBASECURRENCYID,
@ORGANIZATIONCURRENCYID,
@AMOUNT,
@BASEAMOUNT,
@PAYMENBASECURRENCYDECIMALDIGITS,
@ORGANIZATIONAMOUNT,
@ORGANIZATIONCURRENCYDECIMALDIGITS
) PAYMENTREVENUESPLITAPPLIEDCONVERTED
merge dbo.FINANCIALTRANSACTIONLINEITEM as target
using
(select
PAYMENTREVENUESPLITAPPLIEDCONVERTED.PAYMENTREVENUESPLITID as FINANCIALTRANSACTIONLINEITEMID,
@REVENUEID as FINANCIALTRANSACTIONID,
PAYMENTREVENUESPLITAPPLIEDCONVERTED.BASEAMOUNT,
PAYMENTREVENUESPLITAPPLIEDCONVERTED.TRANSACTIONAMOUNT as TRANSACTIONAMOUNT,
PAYMENTREVENUESPLITAPPLIEDCONVERTED.ORGANIZATIONAMOUNT,
isnull(@ADJUSTMENTPOSTSTATUSCODE, case when FINANCIALTRANSACTION.POSTSTATUSCODE = 3 then 3 else 1 end) as POSTSTATUSCODE,
coalesce(@ADJUSTMENTPOSTDATE, FINANCIALTRANSACTION.POSTDATE, @REVENUEDATE) as POSTDATE,
PAYMENTREVENUESPLITAPPLIEDCONVERTED.PLEDGEREVENUESPLITID as SOURCELINEITEMID
from
@PAYMENTREVENUESPLITAPPLIEDCONVERTED as PAYMENTREVENUESPLITAPPLIEDCONVERTED
inner join dbo.FINANCIALTRANSACTION on FINANCIALTRANSACTION.ID = @REVENUEID
inner join dbo.REVENUE_EXT on FINANCIALTRANSACTION.ID = REVENUE_EXT.ID
where
PAYMENTREVENUESPLITAPPLIEDCONVERTED.DESIGNATIONID is not null --filter out the null designation holding the unapplied amount
or (PAYMENTREVENUESPLITAPPLIEDCONVERTED.PLEDGETYPECODE in (2, 18)) --filter back in null designations if typecode is for membership or membership add-on
and FINANCIALTRANSACTION.DELETEDON is null
) as source
on (source.FINANCIALTRANSACTIONLINEITEMID = target.ID)
when matched and target.TYPECODE = 99 and target.DELETEDON is null then update
set target.BASEAMOUNT = source.BASEAMOUNT,
target.TRANSACTIONAMOUNT = source.TRANSACTIONAMOUNT,
target.ORGAMOUNT = source.ORGANIZATIONAMOUNT,
target.POSTSTATUSCODE = source.POSTSTATUSCODE,
target.POSTDATE = source.POSTDATE,
target.DATEADDED = @CHANGEDATE,
target.DATECHANGED = @CHANGEDATE,
target.ADDEDBYID = @CAID,
target.CHANGEDBYID = @CAID,
target.FINANCIALTRANSACTIONLINEITEMADJUSTMENTID = @ADJUSTMENTID,
target.SOURCELINEITEMID = source.SOURCELINEITEMID,
target.TYPECODE = 0
when not matched by target then insert
(ID, FINANCIALTRANSACTIONID, BASEAMOUNT, ADDEDBYID, CHANGEDBYID, DATEADDED, DATECHANGED, TRANSACTIONAMOUNT, ORGAMOUNT, POSTSTATUSCODE, POSTDATE, FINANCIALTRANSACTIONLINEITEMADJUSTMENTID, SOURCELINEITEMID)
values
(source.FINANCIALTRANSACTIONLINEITEMID, source.FINANCIALTRANSACTIONID, source.BASEAMOUNT, @CAID, @CAID, @CHANGEDATE, @CHANGEDATE, source.TRANSACTIONAMOUNT, source.ORGANIZATIONAMOUNT, source.POSTSTATUSCODE, source.POSTDATE, @ADJUSTMENTID, source.SOURCELINEITEMID);
merge dbo.REVENUESPLIT_EXT as target
using
(select
PAYMENTREVENUESPLITAPPLIEDCONVERTED.PAYMENTREVENUESPLITID as FINANCIALTRANSACTIONLINEITEMID,
PAYMENTREVENUESPLITAPPLIEDCONVERTED.DESIGNATIONID as DESIGNATIONID,
PAYMENTREVENUESPLITAPPLIEDCONVERTED.PLEDGETYPECODE as TYPECODE
from
@PAYMENTREVENUESPLITAPPLIEDCONVERTED as PAYMENTREVENUESPLITAPPLIEDCONVERTED
where
PAYMENTREVENUESPLITAPPLIEDCONVERTED.DESIGNATIONID is not null --filter out the null designation holding the unapplied amount
or (PAYMENTREVENUESPLITAPPLIEDCONVERTED.PLEDGETYPECODE in (2, 18)) --filter back in null designations if typecode is for membership or membership add-on
) as source
on (source.FINANCIALTRANSACTIONLINEITEMID = target.ID)
when not matched by target then insert
(ID, DESIGNATIONID, APPLICATIONCODE, TYPECODE, ADDEDBYID, CHANGEDBYID, DATEADDED, DATECHANGED)
values
(source.FINANCIALTRANSACTIONLINEITEMID, source.DESIGNATIONID, @APPLICATIONCODE, source.TYPECODE, @CAID, @CAID, @CHANGEDATE, @CHANGEDATE);
insert into @CREATEDSPLIT(CREATEDREVENUESPLITID, SOURCEREVENUESPLITID)
select
SPLIT.ITEM.value('PAYMENTREVENUESPLITID[1]', 'uniqueidentifier'),
SPLIT.ITEM.value('PLEDGEREVENUESPLITID[1]', 'uniqueidentifier')
from
@paymentSplitsXml.nodes('/ITEMLIST/ITEM') as SPLIT(ITEM)
insert into dbo.INSTALLMENTSPLITPAYMENT
(
ID,
PAYMENTID,
PLEDGEID,
INSTALLMENTSPLITID,
AMOUNT,
OVERPAYMENTAPPLICATIONTYPECODE,
ADDEDBYID,
CHANGEDBYID,
DATEADDED,
DATECHANGED,
APPLICATIONCURRENCYID,
APPLICATIONEXCHANGERATEID
)
select
newid(),
PAYMENTSPLIT.ITEM.value('PAYMENTREVENUESPLITID[1]', 'uniqueidentifier'),
@PLEDGEID,
PLEDGESPLIT.INSTALLMENTSPLITID,
PLEDGESPLIT.AMOUNTAPPLICATION,
@OVERPAYMENTAPPLICATIONTYPECODE,
@CAID,
@CAID,
@CHANGEDATE,
@CHANGEDATE,
@APPLICATIONCURRENCYID,
@APPLICATIONEXCHANGERATEID
from
@splits as PLEDGESPLIT
cross apply @paymentSplitsXml.nodes('/ITEMLIST/ITEM[sql:column("PLEDGESPLIT.PLEDGEREVENUESPLITID") = PLEDGEREVENUESPLITID]') PAYMENTSPLIT(ITEM);
set @AMOUNT = @amountPaid;
set @CREATEDSPLITS = (
select
FINANCIALTRANSACTIONLINEITEM.BASEAMOUNT AMOUNT,
REVENUESPLIT_EXT.DESIGNATIONID,
FINANCIALTRANSACTIONLINEITEM.ID,
FINANCIALTRANSACTIONLINEITEM.FINANCIALTRANSACTIONID,
REVENUESPLIT_EXT.APPLICATIONCODE,
REVENUESPLIT_EXT.TYPECODE,
SOURCEREVENUESPLITID,
FINANCIALTRANSACTION.TRANSACTIONCURRENCYID
from @CREATEDSPLIT as CREATEDSPLIT
inner join dbo.FINANCIALTRANSACTIONLINEITEM on FINANCIALTRANSACTIONLINEITEM.ID = CREATEDSPLIT.CREATEDREVENUESPLITID
inner join dbo.REVENUESPLIT_EXT on FINANCIALTRANSACTIONLINEITEM.ID = REVENUESPLIT_EXT.ID
inner join dbo.FINANCIALTRANSACTION on FINANCIALTRANSACTIONLINEITEM.FINANCIALTRANSACTIONID = FINANCIALTRANSACTION.ID
inner join dbo.REVENUE_EXT on FINANCIALTRANSACTION.ID = REVENUE_EXT.ID
where FINANCIALTRANSACTIONLINEITEM.DELETEDON is null
and FINANCIALTRANSACTIONLINEITEM.TYPECODE <> 1
for xml raw('ITEM'),type,elements,root('SPLITS'),BINARY BASE64
)