Microsoft Great Plains is one of three Microsoft Business Solutions mid-market ERP products: Great Plains, Solomon, Navision.
Considering that Great Plains is now very good candidate for integration with POS application, such as Microsoft Retail Management System or RMS and Client Relation Systems, such as Microsoft CRM – there is common need in Great Plains customizations and integrations, especially on the level of MS SQL Server transact SQL queries and stored procedures. In this small article we’ll show you how to create auto-apply utility, when you integrate huge number of sales transactions and payments. We will be working with RM20101 – Receivables Open File and RM20201 – Receivables Apply Open File. Let’s see SQL code:
declare @curpmtamt numeric(19,5)
declare @curinvamt numeric(19,5)
declare @curpmtnum varchar(20)
declare @curinvnum varchar(20)
declare @curinvtype int
declare @curpmttype int
declare @maxid int
declare @counter int
-- Create a temporary table
create table #temp
(
     [ID] int identity(1,1) primary key,
     CUSTNMBR varchar(15),
     INVNUM varchar(20),
     INVTYPE int,
     PMTNUM varchar(20),
     PMTTYPE int,
     INVAMT numeric(19,5),
     PMTAMT numeric(19,5),
     AMTAPPLIED numeric(19,5)
)
create index IDX_INVNUM on #temp (INVNUM)
create index IDX_PMTNUM on #temp (PMTNUM)
-- Insert unapplied invoices and payments
insert into #temp
     (
     CUSTNMBR,
     INVNUM,
     INVTYPE,
     PMTNUM,
     PMTTYPE    ,
     INVAMT,
     PMTAMT,
     AMTAPPLIED
)
select
     CUSTNMBR = a.CUSTNMBR,
     INVNUM = b.DOCNUMBR,
     INVTYPE = b.RMDTYPAL,
     PMTNUM = a.DOCNUMBR,
     PMTTYPE = a.RMDTYPAL,
     INVAMT = b.CURTRXAM,
     PMTAMT = a.CURTRXAM,
     AMTAPPLIED = 0
from RM20101 a
     join RM20101 b on (a.CUSTNMBR = b.CUSTNMBR)
     join RM00101 c on (a.CUSTNMBR = c.CUSTNMBR)
where
     a.RMDTYPAL in (7, 8, 9) and
     b.RMDTYPAL in (1, 3) and
     a.CURTRXAM 0 and
     b.CURTRXAM 0
order by
     a.custnmbr,
     b.DOCDATE,
     a.DOCDATE,
     a.DOCNUMBR,
     b.DOCNUMBR
-- Iterate through each record
select @maxid = max([ID])
from #temp
select @counter = 1
while @counter = @curpmtamt) and (@curpmtamt>0) and (@curinvamt>0)-- if the invoice amount is greater or the same as the payment amount
     begin
         select @curinvamt = @curinvamt - @curpmtamt -- invoice amount remaining
         -- update with the amount that is applied to the current invoice from
         -- the current payment
         update #temp
         set
             AMTAPPLIED = @curpmtamt
         where
             [ID] = @counter
         -- update with amount of invoice remaining
         update #temp
         set
             INVAMT = @curinvamt
         where
             INVNUM = @curinvnum and
             INVTYPE = @curinvtype
         -- update with amount of payment remaining
         update #temp
         set
             PMTAMT = 0
         where
             PMTNUM = @curpmtnum and
             PMTTYPE = @curpmttype
     end
     else if (@curinvamt 0) and (@curinvamt>0)-- if the invoice amount is lesser to the payment amount
     begin
         select @curpmtamt = @curpmtamt - @curinvamt -- payment amount remaining
         -- update with the amount that is applied to the current invoice from
         -- the current payment
         update #temp
         set
             AMTAPPLIED = @curinvamt
         where
             [ID] = @counter
         -- update with amount of invoice remaining
         update #temp
         set
             INVAMT = 0
         where
             INVNUM = @curinvnum and
             INVTYPE = @curinvtype
         -- update with amount of payment remaining
         update #temp
         set
             PMTAMT = @curpmtamt
         where
             PMTNUM = @curpmtnum and
             PMTTYPE = @curpmttype
     end
     -- go to the next record
     select @counter = @counter + 1
end
-- update the RM Open table with the correct amounts
update
     RM20101
set
     CURTRXAM = b.INVAMT
from
     RM20101 a
         join #temp b on (a.DOCNUMBR = b.INVNUM and a.RMDTYPAL = b.INVTYPE)
update
     RM20101
set
     CURTRXAM = b.PMTAMT
from
     RM20101 a
         join #temp b on (a.DOCNUMBR = b.PMTNUM and a.RMDTYPAL = b.PMTTYPE)
-- create the RM Apply record or update if records already exist
update
     RM20201
set
     DATE1 = convert(varchar(10), getdate(), 101),
     GLPOSTDT = convert(varchar(10), getdate(), 101),
     APPTOAMT = APPTOAMT + a.AMTAPPLIED,
     ORAPTOAM = ORAPTOAM + a.AMTAPPLIED,
     APFRMAPLYAMT = APFRMAPLYAMT + a.AMTAPPLIED,
   ActualApplyToAmount = APFRMAPLYAMT + a.AMTAPPLIED
from
     #temp a
         join RM20101 b on (b.DOCNUMBR = a.INVNUM and b.RMDTYPAL = a.INVTYPE)
         join RM20101 c on (c.DOCNUMBR = a.PMTNUM and c.RMDTYPAL = a.PMTTYPE)
         join RM20201 d on (d.APFRDCTY = a.PMTTYPE and
                 d.APFRDCNM = a.PMTNUM and
                 d.APTODCTY = a.INVTYPE and
                 d.APTODCNM = a.INVNUM)
where
     a.AMTAPPLIED 0
insert into RM20201
     (CUSTNMBR,
     DATE1,
     GLPOSTDT,
     POSTED, APTODCNM,
     APTODCTY,
     APTODCDT,
     ApplyToGLPostDate,
     CURNCYID,
     CURRNIDX,
     APPTOAMT,
     ORAPTOAM,
     APFRDCNM,
     APFRDCTY,
     APFRDCDT,
     ApplyFromGLPostDate,
     FROMCURR,
     APFRMAPLYAMT,
     ActualApplyToAmount)
select
     CUSTNMBR = a.CUSTNMBR,
     DATE1 = convert(varchar(10), getdate(), 101),
     GLPOSTDT = convert(varchar(10), getdate(), 101),
     POSTED = 1,
     APTODCNM = a.INVNUM,
     APTODCTY = a.INVTYPE,
     APTODCDT = b.DOCDATE,
     ApplyToGLPostDate = b.GLPOSTDT,
     CURNCYID = b.CURNCYID,
     CURRNIDX = '',
     APPTOAMT = a.AMTAPPLIED,
     ORAPTOAM = a.AMTAPPLIED,
     APFRDCNM = a.PMTNUM,
     APFRDCTY = a.PMTTYPE,
     APFRDCDT = c.DOCDATE,
     ApplyFromGLPostDate = c.GLPOSTDT,
     FROMCURR = c.CURNCYID,
     APFRMAPLYAMT = a.AMTAPPLIED,
     ActualApplyToAmount = a.AMTAPPLIED
from
     #temp a
         join RM20101 b on (b.DOCNUMBR = a.INVNUM and b.RMDTYPAL = a.INVTYPE)
         join RM20101 c on (c.DOCNUMBR = a.PMTNUM and c.RMDTYPAL = a.PMTTYPE)
where
     a.AMTAPPLIED 0 and
     not exists (select 1
         from RM20201 d
         where d.APFRDCTY = a.PMTTYPE and
             d.APFRDCNM = a.PMTNUM and
             d.APTODCTY = a.INVTYPE and
             d.APTODCNM = a.INVNUM)
drop table #temp
Andrew Karasev is Chief Technology Officer in Alba Spectrum Technologies USA nationwide Microsoft CRM, Microsoft Great Plains customization company, based in Chicago, California, Texas, New York, Georgia and Florida and having locations in multiple states and internationally (www.albaspectrum.com), he is Dexterity, SQL, C#.Net, Crystal Reports and Microsoft CRM SDK developer.