У меня проблема с распределением платежей по строкам счетов.
Данные выглядят так:
Таблица строк счета-фактуры (продажи):
lineId invoiceId value
1 1 100
2 1 -50
3 1 40
4 2 500
Таблица платежей (платежи):
paymentId invoiceId amount
1 1 50
2 1 40
3 2 300
Теперь я хочу знать для каждой строки счета-фактуры детали платежа.Платежи должны быть сначала распределены по наименьшим значениям (т. Е. Строка 2, -50)
Результат должен выглядеть следующим образом:
lineId invoiceId value paymentId valuePaid valueUnpaid
2 1 -50 1 -50 0
3 1 40 1 40 0
1 1 100 1 60 40
1 1 100 2 40 0
4 2 500 3 300 200
Проблема решенав посте ниже, но решение не работает, если у вас отрицательные значения счета или если вам нужно разделить строку счета на два платежа.
https://dba.stackexchange.com/questions/58474/how-can-i-use-running-total-aggregates-in-a-query-to-output-financial-accumulati/219925?noredirect=1#comment431486_219925
Это то, что я сделал такдалеко на основе статьи выше:
drop table dbo.#sales
drop table dbo.#payments
CREATE TABLE dbo.#sales
( lineId int primary key, -- unique line id
invoiceId int not null , -- InvoiceId foreign key
itemValue money not null ) -- value of invoice line.
CREATE TABLE dbo.#payments
( paymentId int primary key, -- Unique payment id
InvoiceId int not null, -- InvoiceId foreign key
PayAmount money not null
)
-- Example invoice, id #1, with 3 lines, total ammount = 90; id #2, with one line, value 500
INSERT dbo.#sales VALUES
(1, 1, 100),
(2, 1, -50),
(3, 1, 40),
(4, 2, 500) ;
-- Two payments paid towards invoice id#1, 50+40 = 90
-- One payment paid towards invoice id#2, 300
INSERT dbo.#Payments
VALUES (1, 1, 50),
(2, 1, 40),
(3, 2, 300);
-- Expected output should be as follows, for reporting purposes.
/* lineId, invoiceId, value, paymentId, valuePaid, valueUnpaid
2, 1, -50, 1, -50, 0
3, 1, 40, 1, 40, 0
1, 1, 100, 1, 60, 40
1, 1, 100, 2, 40, 0
4, 2, 500, 3, 300, 200 */
WITH inv AS
( SELECT lineId, invoiceId,
itemValue,
SumItemValue = SUM(itemValue) OVER
(PARTITION BY InvoiceId
ORDER BY ItemValue Asc
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
FROM dbo.#Sales
)
, pay AS
( SELECT
PaymentId, InvoiceId, PayAmount as PayAmt,
SumPayAmt = SUM(PayAmount) OVER
(PARTITION BY InvoiceId
ORDER BY PaymentId
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
FROM dbo.#payments
)
SELECT
inv.lineId,
inv.InvoiceId,
inv.itemValue,
pay.PaymentId,
PaymentAllocated =
CASE WHEN SumPayAmt <= SumItemValue - itemValue
OR SumItemValue <= SumPayAmt - PayAmt
THEN 0
ELSE
CASE WHEN SumPayAmt <= SumItemValue THEN SumPayAmt
ELSE SumItemValue END
- CASE WHEN SumPayAmt-PayAmt <= SumItemValue-itemValue
THEN SumItemValue-itemValue
ELSE SumPayAmt-PayAmt END
END
FROM inv JOIN pay
ON inv.InvoiceId = pay.InvoiceId
ORDER BY
inv.InvoiceId,
pay.PaymentId;
Токовый выход:
lineId InvoiceId itemValue PaymentId PaymentAllocated
2 1 -50.00 1 0.00
3 1 40.00 1 0.00
1 1 100.00 1 50.00
2 1 -50.00 2 0.00
3 1 40.00 2 0.00
1 1 100.00 2 40.00
4 2 500.00 3 300.00
Любое направление будет оценено.Спасибо.
Дополнительная информация о правилах распределения:
- Распределение первого платежа на наименьшую продажу (т. Е. -50) было просто условием, чтобы гарантировать, что все торговые линии получают платежи.Если бы я назначил произвольное или другое правило и строка 1 (значение 100) получило бы первый платеж, я бы использовал весь платеж для этой строки, а остальная часть счета-фактуры осталась бы нераспределенной.
- Как я уже сказал, это просто соглашение.Если кто-то приходит с другим правилом, которое работает, это нормально.На самом деле, структура упрощена по сравнению с производственными таблицами: платежи также имеют дату, тип и тип платежа, и правильное распределение должно указывать нам, какие строки счета-фактуры были оплачены при каждом времени платежа.
- Платежи ограниченылогика системы должна быть меньше суммы строк счета-фактуры.Что ж, это может быть случай, когда платежи больше: общий счет-фактура отрицательный (т.е.: -100).В этом случае мы можем вставить в таблицу платежей суммы в диапазоне -100: 0, а общая сумма платежей ограничена -100