I'm trying to write a sql view to apply customer payments (oldest payment applied to oldest invoice in sequential order). I'd like to apply the customer payments based on the oldest payment date being applied to the oldest invoice date until the payment no longer has any value remaining, then the next payment for that customer and so on.
I can't change the table structure as it is tied to an ERP, payments and invoices are in the same table, payments are document type = 9 and invoices are document type 1. There will be no negative numbers. I can only apply up to the invoice/current amount (i.e. I cannot apply an amount that would cause a negative amount to be applied).
here is some sample data:
CREATE TABLE [dbo].[_ReceivablesDocuments](
[Customer] [char](15) NOT NULL,
[DocumentNbr] [char](21) NOT NULL,
[PaymentCID] [char](21) NOT NULL,
[DocumentType] [smallint] NOT NULL,
[DocumentDate] [datetime] NOT NULL,
[CurrentAmount] [numeric](19, 5) NOT NULL,
[_ID] [int] IDENTITY(1,1) NOT NULL
) ON [PRIMARY]
INSERT INTO _ReceivablesDocuments VALUES ('130308', 'OCK000000023830', '4328', 9, '12-05-2018', '43.60')
INSERT INTO _ReceivablesDocuments VALUES ('130308', 'OCK000000023B2C', '4328', 9, '12-06-2018', '43.60')
INSERT INTO _ReceivablesDocuments VALUES ('130666', 'OCC0000000295D7', '2232', 9, '12-20-2018', '226.10')
INSERT INTO _ReceivablesDocuments VALUES ('130666', 'RCC00000003C9AD', '2232', 9, '01-18-2019', '103.35')
INSERT INTO _ReceivablesDocuments VALUES ('131802', 'OCC00000002DF3B', '3701', 9, '01-02-2019', '200.00')
INSERT INTO _ReceivablesDocuments VALUES ('131802', 'OCC00000002DF3D', '3701', 9, '01-02-2019', '30.00')
INSERT INTO _ReceivablesDocuments VALUES ('131802', 'RCC00000002F7C3', '3701', 9, '01-02-2019', '17.65')
INSERT INTO _ReceivablesDocuments VALUES ('130308', '0130308M181231', '', 1, '12-31-2018', 16.80000)
INSERT INTO _ReceivablesDocuments VALUES ('130308', '130308-MIG-181031', '', 1, '10-31-2018', 16.80000)
INSERT INTO _ReceivablesDocuments VALUES ('130308', '130308-MIG-181130', '', 1, '11-30-2018', 26.80000)
INSERT INTO _ReceivablesDocuments VALUES ('130666', '0130666M181231', '', 1, '12-31-2018', 24.33000)
INSERT INTO _ReceivablesDocuments VALUES ('131802', '131802-MIG-181130', '', 1, '11-30-2018', 17.65000)
INSERT INTO _ReceivablesDocuments VALUES ('131802', '0131802M181231', '', 1, '12-31-2018', 131.83000)
The results should look like this (based on above):
| Customer | PaymentDate | PaymentNbr | PaymentCID | AvailableApplyAmount | ApplyToDocumentNbr | DocumentType | InvoiceBalance | InvoiceDate | ApplyAmount |
| 130308 | 12/5/2018 | OCK000000023830 | 4328 | $ 43.60 | 130308-MIG-181031 | 1 | $ 16.80 | 10/31/2018 | $ 16.80 |
| 130308 | 12/5/2018 | OCK000000023830 | 4328 | $ 26.80 | 130308-MIG-181130 | 1 | $ 26.80 | 11/30/2018 | $ 26.80 |
| 130308 | 12/6/2018 | OCK000000023B2C | 4328 | $ 43.60 | 0130308M181231 | 1 | $ 16.80 | 12/31/2018 | $ 16.80 |
| 130666 | 12/20/2018 | OCC0000000295D7 | 2232 | $ 226.10 | 0130666M181231 | 1 | $ 24.33 | 12/31/2018 | $ 24.33 |
| 131802 | 1/2/2019 | OCC00000002DF3B | 3701 | $ 200.00 | 131802-MIG-181130 | 1 | $ 17.65 | 11/30/2018 | $ 117.65 |
| 131802 | 1/2/2019 | OCC00000002DF3B | 3701 | $ 82.35 | 0131802M181231 | 1 | $ 131.83 | 12/31/2018 | $ 82.35 |
| 131802 | 1/2/2019 | OCC00000002DF3D | 3701 | $ 30.00 | 0131802M181231 | 1 | $ 49.48 | 12/31/2018 | $ 30.00 |
| 131802 | 1/2/2019 | RCC00000002F7C3 | 3701 | $ 17.65 | 0131802M181231 | 1 | $ 19.48 | 12/31/2018 | $ 17.65 |
Here is the query I have but it doesn't quite work properly...
WITH CTE AS (SELECT
ROWNUM = ROW_NUMBER() OVER (Partition by CR.CUSTNMBR order by INV.DOCDATE, INV.DOCNUMBR),
CR.CUSTNMBR as Customer_Nbr, CR.DOCDATE as Apply_Date
, CR.DOCNUMBR as Source_Document_Nbr, CR.CHEKNMBR as Check_Nbr
--, CR.CHEKBKID as Checkbook_Id
, CR.CURTRXAM as Available_Apply_Amount
--Apply Information
, INV.DOCNUMBR as Apply_to_Document_Nbr, INV.CURTRXAM
, INV.DOCDATE
, CASE WHEN CR.CURTRXAM - sum(INV.CURTRXAM) OVER (PARTITION BY CR.CUSTNMBR ORDER BY INV.DOCDATE, INV.DOCNUMBR) < 0 THEN 0 ELSE CR.CURTRXAM - sum(INV.CURTRXAM) OVER (Partition by CR.CUSTNMBR order by INV.DOCDATE, INV.DOCNUMBR) end as AvailableBalance
FROM RM20101 CR (nolock)
JOIN RM20101 INV (nolock) ON CR.CUSTNMBR = INV.CUSTNMBR
INNER JOIN
(
SELECT CR1.CUSTNMBR, CR1.DOCNUMBR, MIN(DOCDATE) as MinPaymentDate
FROM RM20101 CR1
WHERE CR1.RMDTYPAL = 9
AND CR1.CURTRXAM <> 0
AND CR1.VOIDSTTS = 0
GROUP BY CR1.CUSTNMBR, CR1.DOCNUMBR
) X ON X.CUSTNMBR = CR.CUSTNMBR AND X.MinPaymentDate = CR.DOCDATE AND X.DOCNUMBR = CR.DOCNUMBR
WHERE LEFT(INV.TRXSORCE,4) = 'SLST'
AND INV.RMDTYPAL <> 8
AND INV.CURTRXAM <> 0
AND CR.RMDTYPAL = 9
AND CR.CURTRXAM <> 0
)
SELECT
CTE.Customer_Nbr, CTE.Apply_Date, CTE.Source_Document_Nbr, CTE.Check_Nbr--, CTE.Checkbook_Id,
, CASE WHEN prev.AvailableBalance is null THEN CTE.Available_Apply_Amount else prev.AvailableBalance end as Available_Apply_Amount,
CTE.Apply_to_Document_Nbr,
CTE.CURTRXAM AS [Invoice Balance],
CTE.DOCDATE AS [Invoice Date],
--CASE WHEN prev.AvailableBalance is null THEN
--CASE WHEN CTE.Available_Apply_Amount < CTE.CURTRXAM then CTE.Available_Apply_Amount ELSE CTE.CURTRXAM END
--ELSE prev.AvailableBalance end as Apply_Amount
CASE WHEN prev.AvailableBalance is null AND CTE.Available_Apply_Amount < CTE.CURTRXAM THEN CTE.Available_Apply_Amount
WHEN prev.AvailableBalance is null AND CTE.Available_Apply_Amount >= CTE.CURTRXAM THEN CTE.CURTRXAM
WHEN prev.AvailableBalance <> 0 AND CTE.Available_Apply_Amount >= CTE.CURTRXAM THEN CTE.CURTRXAM
WHEN prev.AvailableBalance <> 0 AND (CTE.Available_Apply_Amount - CTE.CURTRXAM) > 0 THEN (CTE.Available_Apply_Amount - CTE.CURTRXAM)
ELSE 0 END AS Apply_Amount
FROM CTE
LEFT JOIN CTE prev ON prev.rownum = CTE.rownum - 1 AND CTE.Customer_Nbr = prev.Customer_Nbr