USP_RECURRINGGIFTSTATUSUPDATEPROCESS

Parameters

Parameter Parameter Type Mode Description
@PARAMETERSETID uniqueidentifier IN
@BUSINESSPROCESSSTATUSID uniqueidentifier IN
@CHANGEAGENTID uniqueidentifier IN
@RECORDSECURITYCTE nvarchar(max) IN
@RECORDSPROCESSED int INOUT

Definition

Copy


CREATE procedure dbo.USP_RECURRINGGIFTSTATUSUPDATEPROCESS (
  @PARAMETERSETID uniqueidentifier,
  @BUSINESSPROCESSSTATUSID uniqueidentifier,
  @CHANGEAGENTID uniqueidentifier,
  @RECORDSECURITYCTE nvarchar(max),
  @RECORDSPROCESSED int output
)
as
begin
  if @CHANGEAGENTID is null
      exec dbo.USP_CHANGEAGENT_GETORCREATECHANGEAGENT @CHANGEAGENTID output;

  declare @CURRENTDATE datetime = getdate();
  declare @PROCESSDATE date = @CURRENTDATE;

  declare @RGS table (ID uniqueidentifier,
                      ORIGINALSTATUSCODE tinyint,
                      NEWSTATUSCODE tinyint,
                      ADDMISSINGINSTALLMENTS bit,
                      AMOUNT money,
                      BASECURRENCYID uniqueidentifier,
                      ORGANIZATIONAMOUNT money,
                      ORGANIZATIONEXCHANGERATEID uniqueidentifier,
                      TRANSACTIONAMOUNT money,
                      TRANSACTIONCURRENCYID uniqueidentifier,
                      BASEEXCHANGERATEID uniqueidentifier,
                      TYPECODE tinyint);

  --------------------------------------------------------------------------------------------

  -- get process parameter values


  declare @IDSETREGISTERID uniqueidentifier,
          @PAYMENTMETHODVALUE xml,
          @FREQUENCYVALUE xml,
          @PASTDUECODE tinyint,
          @DAYSPASTDUE smallint,
          @LAPSEDCODE tinyint,
          @LAPSEDINSTALLMENTSPASTDUE smallint,
          @LAPSEDINSTALLMENTSDAYSPAST smallint,
          @TERMINATEDCODE tinyint,
          @TERMINATEDINSTALLMENTSPASTDUE smallint,
          @TERMINATEDINSTALLMENTSDAYSPAST smallint,
          @OTHERPAYMENTMETHODS xml,
          @CHECKLEGACYHELD bit;

  select @IDSETREGISTERID = IDSETREGISTERID,
         @PAYMENTMETHODVALUE = PAYMENTMETHODVALUE,
         @FREQUENCYVALUE = FREQUENCYVALUE,
         @PASTDUECODE = PASTDUECODE,
         @DAYSPASTDUE = DAYSPASTDUE,
         @LAPSEDCODE = LAPSEDCODE,
         @LAPSEDINSTALLMENTSPASTDUE = LAPSEDINSTALLMENTSPASTDUE,
         @LAPSEDINSTALLMENTSDAYSPAST = LAPSEDINSTALLMENTSDAYSPAST,
         @TERMINATEDCODE = TERMINATEDCODE,
         @TERMINATEDINSTALLMENTSPASTDUE = TERMINATEDINSTALLMENTSPASTDUE,
         @TERMINATEDINSTALLMENTSDAYSPAST = TERMINATEDINSTALLMENTSDAYSPAST,
         @OTHERPAYMENTMETHODS = OTHERPAYMENTMETHODS,
         @CHECKLEGACYHELD = CHECKLEGACYHELD
  from dbo.RECURRINGGIFTSTATUSUPDATEPROCESS
  where ID = @PARAMETERSETID;

  declare @PAYMENTMETHODS table (PAYMENTMETHODCODE tinyint);
  declare @FREQUENCIES table (FREQUENCYCODE tinyint);
  declare @OTHERMETHODS table (ID nvarchar(36));  

  if @IDSETREGISTERID is null
  begin
    insert into @PAYMENTMETHODS
    select
      T.c.value('(PAYMENTMETHODCODE)[1]','tinyint') AS 'PAYMENTMETHODCODE'
    from @PAYMENTMETHODVALUE.nodes('/PAYMENTMETHODVALUE/ITEM') T(c);

    insert into @FREQUENCIES
    select
      T.c.value('(FREQUENCYCODE)[1]','tinyint') AS 'FREQUENCYCODE'
    from @FREQUENCYVALUE.nodes('/FREQUENCYVALUE/ITEM') T(c);

    insert into @OTHERMETHODS
    select
      T.c.value('(ID)[1]','nvarchar(36)') AS 'ID'
    from @OTHERPAYMENTMETHODS.nodes('/OTHERPAYMENTMETHODS/ITEM') T(c);
  end

  --------------------------------------------------------------------------------------------

  -- identify recurring gifts to process


  declare @SQL nvarchar(max);

  if isnull(@RECORDSECURITYCTE,'') <> ''
    set @SQL = @RECORDSECURITYCTE;

  set @SQL = isnull(@SQL,'') +  
   'select f.ID,' + char(13) +
   '       s.STATUSCODE ORIGINALSTATUSCODE,' + char(13) +

   '       case when s.ENDDATE <= @PROCESSDATE and t.TYPECODE <> 9 then 3' + char(13) +       -- End date passed = Canceled

   '            when nextinstallment.STATUSCODE = 3 then 1' + char(13) +  -- Next installment is Skipped = Held (may be overruled by Terminated below)

   '            when s.STATUSCODE = 5 then 5' + char(13) +     -- Don't change Lapsed to Active

   '            else 0 end NEWSTATUSCODE,' + char(13) +                   -- Active (may be overruled by Lapsed below)


           -- fields for bringing the installment schedule up to date

   '       case when nextinstallment.STATUSCODE is null then 1 else 0 end ADDMISSINGINSTALLMENTS,' + char(13) +
   '       case when nextinstallment.STATUSCODE is null then r.AMOUNT end,' + char(13) +
   '       case when nextinstallment.STATUSCODE is null then r.BASECURRENCYID end,' + char(13) +
   '       case when nextinstallment.STATUSCODE is null then r.ORGANIZATIONAMOUNT end,' + char(13) +
   '       case when nextinstallment.STATUSCODE is null then r.ORGANIZATIONEXCHANGERATEID end,' + char(13) +
   '       case when nextinstallment.STATUSCODE is null then r.TRANSACTIONAMOUNT end,' + char(13) +
   '       case when nextinstallment.STATUSCODE is null then r.TRANSACTIONCURRENCYID end,' + char(13) +
   '       case when nextinstallment.STATUSCODE is null then r.BASEEXCHANGERATEID end,' + char(13) +
   '       t.TYPECODE' + char(13) +
   'from dbo.FINANCIALTRANSACTION f' + char(13) +
   'inner join dbo.REVENUESCHEDULE s on s.ID = f.ID' + char(13) +
   'outer apply (select top 1 i.STATUSCODE' + char(13) +
   '             from dbo.RECURRINGGIFTINSTALLMENT i' + char(13) +
   '             where i.REVENUEID = f.ID' + char(13) +
   '             and i.DATE >= @PROCESSDATE' + char(13) +

   -- We are expecting one of two scenarios here:

   -- 1. The installments are out of date, and there are NO installments in the future, so this status condition doesn't matter.  (nextinstallment.STATUSCODE is null)

   -- 2. There is an Expected/Past due installment in the future, so we don't need to add missing installments, but we do need to know if the next non-paid, non-written-off

   --    installment is Held or not.  (nextinstallment.STATUSCODE is not null)

   -- The only valid way to have a Paid or Written-off installment in the future, with no installment after it meeting this status condition, is if the RG is Canceled

   -- (or possibly Terminated), in which case it is excluded from this query anyway.

   '             and i.STATUSCODE in(0,1,3)' + char(13) +
   '             order by i.DATE) nextinstallment' + char(13) +
   'cross apply (select min(rs.TYPECODE) TYPECODE' + char(13) +
   '             from dbo.FINANCIALTRANSACTIONLINEITEM fl' + char(13) +
   '             inner join dbo.REVENUESPLIT_EXT rs on rs.ID = fl.ID' + char(13) +
   '             where fl.FINANCIALTRANSACTIONID = f.ID) t' + char(13) +
   'left join ' + case when isnull(@RECORDSECURITYCTE,'') <> '' then 'REVENUE_RACS' else 'dbo.REVENUE' end + ' r on r.ID = f.ID' + char(13);

  declare @ALLPAYMENTMETHODSCOUNT tinyint = 9;

  -- account for standing order if the UK flag is enabled

  if dbo.UFN_INSTALLEDPRODUCTS_PRODUCTIS('9568A6C2-F7AA-45fd-8F54-21FE9654EE2D') = 1
    set @ALLPAYMENTMETHODSCOUNT = 10;

  -- check if other methods where specified for the Other payment method

  declare @OTHERMETHODSSELECTED bit = case when (select count(*) from @OTHERMETHODS) > 0 then 1 else 0 end;

  declare @DOPAYMENTMETHODS bit = case when @IDSETREGISTERID is null and (select count(*) from @PAYMENTMETHODS) between 1 and (@ALLPAYMENTMETHODSCOUNT- case @OTHERMETHODSSELECTED when 1 then 0 else 1 end) then 1 else 0 end;

  if @DOPAYMENTMETHODS = 1
  begin
    set @SQL = @SQL + 'inner join dbo.REVENUEPAYMENTMETHOD p on p.REVENUEID = f.ID' + char(13);

    if @OTHERMETHODSSELECTED = 1 
      set @SQL = @SQL + 'left join dbo.OTHERPAYMENTMETHODDETAIL d on d.ID = p.ID' + char(13);
  end
  else if @IDSETREGISTERID is not null
    set @SQL = @SQL + 'inner join dbo.UFN_IDSETREADER_GETRESULTS_GUID(@IDSETREGISTERID) sel on sel.ID = f.ID' + char(13);

  -- basic conditions

  set @SQL = @SQL +
   'where f.TYPECODE = 2' + char(13) +    -- Recurring gifts

   'and s.ISPENDING = 0' + char(13) +     -- Not in batch

   'and s.STATUSCODE in(0,1,5)';          -- Active, Held, Lapsed


  if isnull(@RECORDSECURITYCTE,'') <> ''
    set @SQL = @SQL + char(13) + 'and r.ID is not null';

  if @IDSETREGISTERID is null
  begin
    if @DOPAYMENTMETHODS = 1
    begin
      declare @PAYMENTMETHODLIST nvarchar(30) = '';

      select @PAYMENTMETHODLIST = @PAYMENTMETHODLIST + ',' + cast(PAYMENTMETHODCODE as nvarchar(3))
      from @PAYMENTMETHODS;

      set @SQL = @SQL + char(13) + 'and case when (p.PAYMENTMETHODCODE = 2 and s.CREDITCARDID is null) then 98 else p.PAYMENTMETHODCODE end in(' + substring(@PAYMENTMETHODLIST,2,len(@PAYMENTMETHODLIST)-1) + ')';

     if @OTHERMETHODSSELECTED = 1
     begin
       declare @OTHERMETHODLIST nvarchar(max) = '';

       select @OTHERMETHODLIST = @OTHERMETHODLIST + ',''''' + ID + ''''
       from @OTHERMETHODS;

       set @SQL = @SQL + char(13) + 'and (p.PAYMENTMETHODCODE <> 10 or d.OTHERPAYMENTMETHODCODEID in(' + substring(@OTHERMETHODLIST,3,len(@OTHERMETHODLIST)-1) + '))';
     end
    end

    declare @ALLFREQUENCIESCOUNT tinyint = 9;

    if (select count(*) from @FREQUENCIES) between 1 and @ALLFREQUENCIESCOUNT-1
    begin
      declare @FREQUENCYLIST nvarchar(30) = '';

      select @FREQUENCYLIST = @FREQUENCYLIST + ',' + cast(FREQUENCYCODE as nvarchar(3))
      from @FREQUENCIES;

      set @SQL = @SQL + char(13) + 'and s.FREQUENCYCODE in(' + substring(@FREQUENCYLIST,2,len(@FREQUENCYLIST)-1) + ')';
    end
  end

  -- Exclude legacy Held RGs so they don't get improperly activated

  if @CHECKLEGACYHELD = 1
  begin
    if exists(select top 1 'x' from dbo.UFN_SELECTION_REVENUE_LEGACYHELDRECURRINGGIFTS())
      set @SQL = @SQL + char(13) + 'and f.ID not in(select ID from dbo.UFN_SELECTION_REVENUE_LEGACYHELDRECURRINGGIFTS())';
    else
      -- When no more records exist in the selection, it is no longer needed, so disable the check for future runs.

      update dbo.RECURRINGGIFTSTATUSUPDATEPROCESS
      set CHECKLEGACYHELD = 0,
          CHANGEDBYID = @CHANGEAGENTID,
          DATECHANGED = @CURRENTDATE
      where ID = @PARAMETERSETID;
  end

  declare @PARAMETERDEF nvarchar(100) = '@PROCESSDATE date, @IDSETREGISTERID uniqueidentifier';

  insert into @RGS
  exec sp_executesql @SQL, @PARAMETERDEF, @PROCESSDATE, @IDSETREGISTERID;

  --------------------------------------------------------------------------------------------

  -- add missing installments

  declare @ORGANIZATIONCURRENCYID uniqueidentifier = dbo.UFN_CURRENCY_GETORGANIZATIONCURRENCY();

  insert into dbo.RECURRINGGIFTINSTALLMENT (
    ID,
    REVENUEID,
    AMOUNT,
    DATE,
    BASECURRENCYID,
    ORGANIZATIONAMOUNT,
    ORGANIZATIONEXCHANGERATEID,
    TRANSACTIONAMOUNT,
    TRANSACTIONCURRENCYID,
    BASEEXCHANGERATEID,
    ADDEDBYID, CHANGEDBYID, DATEADDED, DATECHANGED)
  select
    newid(),
    rg.ID,
    rg.AMOUNT,
    i.DATE,
    coalesce(rg.BASECURRENCYID,@ORGANIZATIONCURRENCYID),
    coalesce(rg.ORGANIZATIONAMOUNT,rg.AMOUNT),
    rg.ORGANIZATIONEXCHANGERATEID,
    coalesce(rg.TRANSACTIONAMOUNT,rg.AMOUNT),
    coalesce(rg.TRANSACTIONCURRENCYID,@ORGANIZATIONCURRENCYID),
    rg.BASEEXCHANGERATEID,
    @CHANGEAGENTID, @CHANGEAGENTID, @CURRENTDATE, @CURRENTDATE
  from @RGS rg
  cross apply dbo.UFN_RECURRINGGIFT_GETMISSINGINSTALLMENTS_ASOFDATE(rg.ID,@PROCESSDATE) i
  where rg.ADDMISSINGINSTALLMENTS = 1
  -- don't add the "next" installment here if we already know the RG is going to be Canceled

  and (rg.NEWSTATUSCODE <> 3 or i.DATE <= @PROCESSDATE);

  --------------------------------------------------------------------------------------------

  -- find/update past due installments


  declare @PASTDUECOUNT int = 0;
  if @PASTDUECODE = 1
  begin
    -- unpaid balance x days past installment date

    update i
    set STATUSCODE = 1,
        PASTDUEDATE = @CURRENTDATE,
        CHANGEDBYID = @CHANGEAGENTID,
        DATECHANGED = @CURRENTDATE
    from @RGS rg
    inner join dbo.RECURRINGGIFTINSTALLMENT i on i.REVENUEID = rg.ID
    where i.STATUSCODE = 0
    and datediff(d,i.DATE,@PROCESSDATE) >= @DAYSPASTDUE;

    set @PASTDUECOUNT = @@ROWCOUNT;
  end

  else if @PASTDUECODE = 2
  begin
    -- later installment exists that is on or before the process date

    update i
    set STATUSCODE = 1,
        PASTDUEDATE = @CURRENTDATE,
        CHANGEDBYID = @CHANGEAGENTID,
        DATECHANGED = @CURRENTDATE
    from @RGS rg
    inner join dbo.RECURRINGGIFTINSTALLMENT i on i.REVENUEID = rg.ID
    where i.STATUSCODE = 0
    and exists(select 'x'
               from dbo.RECURRINGGIFTINSTALLMENT i2
               where i2.REVENUEID = rg.ID
               and i2.DATE between dateadd(d,1,i.DATE) and @PROCESSDATE);

    set @PASTDUECOUNT = @@ROWCOUNT;
  end

  --------------------------------------------------------------------------------------------

  -- Update RG status values for Lapsed and Terminated


  if @LAPSEDCODE <> 0 or @TERMINATEDCODE <> 0
  begin
    -- Code values of 1 check for a specified number of past due installments.

    -- Code values of 2 check for an installment with a balance a specified number of days past the installment date.


    declare @TERMINATEDVALUE smallint = case @TERMINATEDCODE when 1 then @TERMINATEDINSTALLMENTSPASTDUE when 2 then @TERMINATEDINSTALLMENTSDAYSPAST end;
    declare @MINIMUMVALUE smallint = case @LAPSEDCODE when 1 then @LAPSEDINSTALLMENTSPASTDUE when 2 then @LAPSEDINSTALLMENTSDAYSPAST else @TERMINATEDVALUE end;

    update rg
    set NEWSTATUSCODE = case when case when @TERMINATEDCODE = 1 then i.PASTDUECOUNT when @TERMINATEDCODE = 2 then i.UNPAIDINSTALLMENTDAYS end >= @TERMINATEDVALUE then 2  -- Terminated

                             when rg.NEWSTATUSCODE = 1 then 1  -- Held supersedes Lapsed

                             else 5 end  -- Lapsed

    from @RGS rg
    cross apply (select count(case when i.STATUSCODE = 1 then 1 end) PASTDUECOUNT,
                        -- The largest differential in days between existing unpaid installments and the process date.

                        isnull(datediff(d,min(i.DATE),@PROCESSDATE),0) UNPAIDINSTALLMENTDAYS
                 from dbo.RECURRINGGIFTINSTALLMENT i
                 where i.REVENUEID = rg.ID
                 and i.STATUSCODE in(0,1)  -- Expected or Past due installments have a balance

                 and i.DATE < @PROCESSDATE) i
    where rg.NEWSTATUSCODE <> 3  -- Not being updated to Canceled

    -- the RG meets the Lapsed condition, or the Terminated condition if we are not setting RGs to Lapsed

    -- the Lapsed condition will always be less than the Terminated condition, so this is the minimum requirement for update

    and case when isnull(nullif(@LAPSEDCODE,0),@TERMINATEDCODE) = 1 then i.PASTDUECOUNT else i.UNPAIDINSTALLMENTDAYS end >= @MINIMUMVALUE
    -- do not update the status of sponsorships

    and rg.TYPECODE <> 9;
  end

  --------------------------------------------------------------------------------------------

  -- START EDIT STATUS SECTION

  -- Bulk versions of logic in USP_RECURRINGGIFT_EDITSTATUS


  --delete future installments with no activity on change to Canceled or Terminated

  declare @CONTEXTCACHE varbinary(128);
  set @CONTEXTCACHE = CONTEXT_INFO();
  set CONTEXT_INFO @CHANGEAGENTID;

  delete i
  from @RGS rg
  inner join dbo.RECURRINGGIFTINSTALLMENT i on i.REVENUEID = rg.ID
  where i.DATE > @PROCESSDATE
  and not exists(select 'x' from dbo.RECURRINGGIFTINSTALLMENTPAYMENT where RECURRINGGIFTINSTALLMENTID = i.ID)
  and not exists(select 'x' from dbo.RECURRINGGIFTINSTALLMENTWRITEOFF where RECURRINGGIFTINSTALLMENTID = i.ID)
  and rg.NEWSTATUSCODE in(2,3);

  if @CONTEXTCACHE is not null
    set CONTEXT_INFO @contextCache

  -- I am intentionally excluding the logic for sponsorship recurring additional gifts from USP_RECURRINGGIFT_EDITSTATUS.

  -- That logic is not necessary here since we are never updating RGs from Canceled/Terminated to Active/Held/Lapsed.


  --------------------------------------------------------------------------------------------

  -- edit status

  update rs
  set STATUSCODE = rg.NEWSTATUSCODE,
      NEXTTRANSACTIONDATE = case when rg.NEWSTATUSCODE in(0,1,5) then NEXTTRANSACTIONDATE else null end,
      CHANGEDBYID = @CHANGEAGENTID,
      DATECHANGED = @CURRENTDATE
  from @RGS rg
  inner join dbo.REVENUESCHEDULE rs on rs.ID = rg.ID
  where rg.ORIGINALSTATUSCODE <> rg.NEWSTATUSCODE;

  -- I am intentionally excluding the logic for ensuring a future installment exists from USP_RECURRINGGIFT_EDITSTATUS.

  -- That logic is not necessary here since we are never updating RGs from Canceled/Terminated to Active/Held/Lapsed.

  -- Active/Held/Lapsed RGs will always have a future installment already.

  --------------------------------------------------------------------------------------------

  -- status change amendments

  insert into dbo.RECURRINGGIFTAMENDMENT(ID,
                                         FINANCIALTRANSACTIONID,
                                         AMENDMENTTYPECODE,
                                         DATE,
                                         STATUSCODE,
                                         PREVIOUSSTATUSCODE,
                                         STATUSCHANGETYPECODE,
                                         ADDEDBYID,CHANGEDBYID,DATEADDED,DATECHANGED)
  select newid(),
         ID,
         1,
         @PROCESSDATE,
         NEWSTATUSCODE,
         ORIGINALSTATUSCODE,
         6,
         @CHANGEAGENTID,@CHANGEAGENTID,@CURRENTDATE,@CURRENTDATE
  from @RGS
  where ORIGINALSTATUSCODE <> NEWSTATUSCODE;

  --------------------------------------------------------------------------------------------

  -- write results to outcome table

  declare @RESULTTABLE table (RECORDSPROCESSED int);
  insert into dbo.RECURRINGGIFTSTATUSUPDATEPROCESSOUTCOME (
    ID,
    RECORDSPROCESSED,
    PASTDUECOUNT,
    ACTIVECOUNT,
    LAPSEDCOUNT,
    HELDCOUNT,
    TERMINATEDCOUNT,
    CANCELEDCOUNT,
    ADDEDBYID,CHANGEDBYID,DATEADDED,DATECHANGED
  )
  output inserted.RECORDSPROCESSED into @RESULTTABLE
  select
    @BUSINESSPROCESSSTATUSID,
    count(*),
    @PASTDUECOUNT,
    count(case when ORIGINALSTATUSCODE <> 0 and NEWSTATUSCODE = 0 then 1 end),
    count(case when ORIGINALSTATUSCODE <> 5 and NEWSTATUSCODE = 5 then 1 end),
    count(case when ORIGINALSTATUSCODE <> 1 and NEWSTATUSCODE = 1 then 1 end),
    count(case when ORIGINALSTATUSCODE <> 2 and NEWSTATUSCODE = 2 then 1 end),
    count(case when ORIGINALSTATUSCODE <> 3 and NEWSTATUSCODE = 3 then 1 end),
    @CHANGEAGENTID,@CHANGEAGENTID,@CURRENTDATE,@CURRENTDATE
  from @RGS;

  select @RECORDSPROCESSED = RECORDSPROCESSED
  from @RESULTTABLE;
end