他の誰かが設計した請求システムのバックエンドを約 4 年間使用しなければならなかった私のアドバイスは、請求書に「保留中」のステータスを持たないことです。それはあなたを狂わせます。
保留中の請求書を通常の請求書 (「保留中」フラグ/ステータス付き) として保存する際の問題は、投稿された請求書のみを考慮に入れることになっている何百もの操作/レポートが存在することです。これは文字通り、保留中を除くすべてのステータスを意味します。つまり、このステータスは毎回チェックする必要があります。独身。時間。 そして誰かが忘れる。そして、誰もがそれに気付くまでには数週間かかります。
保留中のフィルターが組み込まれたビューを作成できますActiveInvoices
が、それは問題をシフトするだけです。テーブルの代わりにビューを使用することを誰かが忘れるでしょう。
保留中の請求書は請求書ではありません。質問のコメントに下書き(または注文、要求など、すべて同じ概念)として正しく記載されています。これらのドラフトを変更できる必要があることは理解できます。だからここに私の推薦があります。
まず、ドラフト テーブルを作成します (これを と呼びますOrders
)。
CREATE TABLE Orders
(
OrderID int NOT NULL IDENTITY(1, 1)
CONSTRAINT PK_Orders PRIMARY KEY CLUSTERED,
OrderDate datetime NOT NULL
CONSTRAINT DF_Orders_OrderDate DEFAULT GETDATE(),
OrderStatus tinyint NOT NULL, -- 0 = Active, 1 = Canceled, 2 = Invoiced
...
)
CREATE TABLE OrderDetails
(
-- Optional, if individual details need to be referenced
OrderDetailID int NOT NULL IDENTITY(1, 1)
CONSTRAINT PK_OrderDetails PRIMARY KEY CLUSTERED,
OrderID int NOT NULL
CONSTRAINT FK_OrderDetails_Orders FOREIGN KEY
REFERENCES Orders (OrderID)
ON UPDATE CASCADE
ON DELETE CASCADE,
...
)
CREATE INDEX IX_OrderDetails
ON OrderDetails (OrderID)
INCLUDE (...)
これらは基本的な「ドラフト」テーブルです。それらは変更できます。Orders
変更を追跡するには、履歴テーブルを作成する必要があります。履歴テーブルには、元のテーブルとテーブルにあるすべての列OrderDetails
に加えて、最後に変更されたユーザー、日付、および変更の種類 (挿入、更新、または削除) の監査列が含まれます。
Cade が言及しているように、AutoAuditを使用してこのプロセスのほとんどを自動化できます。
また、アクティブでなくなった下書き (特に、投稿されて請求書になった下書き) の更新を防止するトリガーも必要です。このデータの一貫性を保つことが重要です。
CREATE TRIGGER tr_Orders_ActiveUpdatesOnly
ON Orders
FOR UPDATE, DELETE
AS
IF EXISTS
(
SELECT 1
FROM deleted
WHERE OrderStatus <> 0
)
BEGIN
RAISERROR('Cannot modify a posted/canceled order.', 16, 1)
ROLLBACK
END
請求書は 2 レベルの階層であるため、詳細については同様の少し複雑なトリガーが必要です。
CREATE TRIGGER tr_OrderDetails_ActiveUpdatesOnly
ON OrderDetails
FOR INSERT, UPDATE, DELETE
AS
IF EXISTS
(
SELECT 1
FROM
(
SELECT OrderID FROM deleted
UNION ALL
SELECT OrderID FROM inserted
) d
INNER JOIN Orders o
ON o.OrderID = d.OrderID
WHERE o.OrderStatus <> 0
)
BEGIN
RAISERROR('Cannot change details for a posted/canceled order.', 16, 1)
ROLLBACK
END
これは大変な作業のように思えるかもしれませんが、次のことを行う必要があります。
CREATE TABLE Invoices
(
InvoiceID int NOT NULL IDENTITY(1, 1)
CONSTRAINT PK_Invoices PRIMARY KEY CLUSTERED,
OrderID int NOT NULL
CONSTRAINT FK_Invoices_Orders FOREIGN KEY
REFERENCES Orders (OrderID),
InvoiceDate datetime NOT NULL
CONSTRAINT DF_Invoices_Date DEFAULT GETDATE(),
IsPaid bit NOT NULL
CONSTRAINT DF_Invoices_IsPaid DEFAULT 0,
...
)
私がここで何をしたかわかりますか?私たちの請求書は手付かずの神聖な存在であり、入社初日の顧客サービス担当者による恣意的な変更によって汚されることはありません。ここで失敗するリスクはありません。ただし、必要に応じて、元の請求書にリンクされているため、請求書の「履歴」全体を確認することができOrder
ます。思い出していただければ、有効なステータスを離れた後の変更は許可されていません。
これは、現実の世界で起こっていることを正しく表しています。請求書が送信/投稿されると、それを取り戻すことはできません。それはそこにあります。キャンセルしたい場合は、A/R (システムがそのようなことをサポートしている場合) に、または財務報告を満たすために負の請求書として、取り消しを転記する必要があります。これが完了すれば、各請求書の監査履歴を調べなくても実際に何が起こったかを確認できます。請求書自体を見るだけです。
請求書として投稿された後、開発者が注文ステータスを変更することを覚えておく必要があるという問題はまだありますが、トリガーを使用してこれを修正できます。
CREATE TRIGGER tr_Invoices_UpdateOrderStatus
ON Invoices
FOR INSERT
AS
UPDATE Orders
SET OrderStatus = 2
WHERE OrderID IN (SELECT OrderID FROM inserted)
これで、あなたのデータは、不注意なユーザーや不注意な開発者からも保護されます。また、請求書があいまいではなくなりました。ステータスがないため、誰かが請求書のステータスを確認するのを忘れたために忍び寄るバグを心配する必要はありません。
ですから、これを要約して言い換えると、請求書の履歴のためだけに、なぜこのようなトラブルに巻き込まれたのでしょうか?
まだ転記されていない請求書は実際の取引ではないためです。それらはトランザクションの「状態」、つまり進行中のトランザクションです。それらはあなたの取引データには属しません。このようにそれらを分離しておくことで、潜在的な将来の問題の多くを解決できます。
免責事項:これはすべて私の個人的な経験からの話であり、世界中のすべての請求システムを見たわけではありません。これが特定のアプリケーションに適していることを 100% 確実に保証することはできません。状態データとトランザクション データの混合による、「保留中」の請求書の概念に起因する、私が見たスズメバチの巣状の問題を繰り返すことしかできません。
インターネットで見つけた他のすべてのデザインと同様に、これを 1 つの可能なオプションとして調査し、それが実際に機能するかどうかを評価する必要があります。