沖銷調整

2006 年 1 月 2 日
這是 進一步的企業應用程式架構開發 寫作的一部分,我在 2000 年代中期進行。遺憾的是,自那時起,太多其他事情吸引了我的注意力,所以我沒有時間進一步研究它們,我也看不到在可預見的未來會有太多時間。因此,此材料在很大程度上仍處於草稿形式,在我能夠找到時間再次研究它之前,我不會進行任何更正或更新。
運作方式
對於需要調整的每個項目,您建立兩個新項目。一個項目是前一個項目的簡單沖銷,使用相同的發生日期和相同金額但符號相反。然後,您發布一個新項目,這就是舊金額應該是什麼。
因此,假設我們記錄了 3 月份使用 50kwh 小時的電力。此事件最初記錄在 4 月 5 日,並在 4 月 10 日處理。這產生了 圖 1 中的物件

圖 1:調整前的事件。
然後在 6 月 1 日,我們意識到發生錯誤,金額應該是 80 kwh。這導致了 圖 2 的結構。
您可能會驚訝地發現,沖銷項目出現在舊事件上,而不是新事件上。這是因為新事件本身可能會在稍後進行調整,在這種情況下,我們不希望產生沖銷沖銷項目的項目。因此,將它們放在原始事件上更有意義。我們還將該事件標記為已調整,以清楚地表明它已調整,因此不應再次調整。

圖 2:調整後的事件
使用 沖銷調整 會在這些沖銷對中產生大量項目。因此,這表示如果有人想要查看項目清單,他們通常會希望查看排除所有沖銷對的項目。因此,您需要提供一個查詢方法來過濾此資訊。由於可能會涉及大量資料,這通常也會影響您的資料庫查詢。
何時使用
反轉調整 是當分錄無法變更,因此無法使用 替換調整 時的簡單替代方案。其主要缺點是會產生大量分錄:一旦完成,您會為每個先前分錄新增三個分錄。執行此動作數次後,您會產生大量分錄,其中許多為反向配對。雖然您可以篩選這些分錄,但它們仍然會造成困擾。
差異調整 是主要的替代方案。通常,在它們之間的選擇取決於您的使用者想要如何查看資訊。如果分錄可以變更,最好使用 替換調整。您通常會發現分錄在特定日期之前可以變更,但在該日期之後無法變更。這會讓您使用 反轉調整 和 替換調整 的組合。
範例:反轉不正確的用電量(Java)
以下是我們不正確用電量的範例,以及如何反轉。
public void setUp() { MfDate.setToday(2004,4,1); watson = new Customer("Dr Watson"); watson.setServiceAgreement(testAgreement()); usageEvent = new Usage(Unit.KWH.amount(50), new MfDate(2004, 3, 31), watson); eventList.add(usageEvent); eventList.process(); MfDate.setToday(2004,6,1); replacement = new Usage(Unit.KWH.amount(70), new MfDate(2004, 3, 31), watson, usageEvent); eventList.add(replacement); eventList.process(); }
在此實作中,我們提供會計事件的建構函式,其中包含調整事件的時段。
class AccountingEvent...
public AccountingEvent(EventType type, MfDate whenOccurred, Subject subject, AccountingEvent adjustedEvent) { this.type = type; this.whenOccurred = whenOccurred; this.whenNoticed = MfDate.today(); this.subject = subject; this.adjustedEvent = adjustedEvent; adjustedEvent.setReplacementEvent(this); }
private AccountingEvent adjustedEvent;
在處理過程中,如果存在調整事件,則會先反轉該事件。反轉僅涉及為每個原始分錄過帳相反分錄。然後,可以像平常一樣完成事件處理的其餘部分。
class AccountingEvent...
public void process() { assert !isProcessed; if (adjustedEvent != null) adjustedEvent.reverse(); subject.process(this); markProcessed(); }
public void reverse() { assert isProcessed(); for (Entry e : getResultingEntries()) reverseEntry(e); for(AccountingEvent ev : getSecondaryEvents()) ev.reverse(); } public void reverseEntry(Entry arg) { Entry reversingEntry = new Entry(arg.getAmount().negate(), arg.getDate()); Account targetAccount = subject.accountFor(arg.getAccount().type()); targetAccount.post(reversingEntry); }