[轉載] Dynamics 365 Business Central開發實戰-5:過帳程式客製

 << 以下為轉載文章。。。>>

2019/6/10
在前面的文章,我們學習了在 CSIDE 中 Event-driven 的設計模式,以及 Publisher function 和 Subscriber function。接下來,我們來完成規格第七項和第八項的程式。
7. 在 Purchase Line 過帳時,”Expense Code” 是必備 (mandatory) 的,而且系統會檢查 “Expense Code” 是否沒有被 Disabled 掉。否則,系統跳出錯誤訊息。
分析:要去追蹤過帳程式。因為跟 Purchase Order 有關,所以去追 Codeunit 90 (Purch.-Post)

我們開始追蹤 Codeunit 90 — Purchase Order 過帳的程式碼。最後,我們鎖定了 Publisher function “OnBeforePostLines”。畢竟要在過帳 Purchase Line 之前做好檢查也是合情合理。

定位在 OnBeforePostLines()

接下來,我們一樣在 Codeunit 50000 去建一個 Subscriber function “OnBeforePurchaseOrderPostLines”,其 properties 如下圖:

Properties of function “OnBeforePurchaseOrderPostLines”

然後我們就開始在 Function “OnBeforePurchaseOrderPostLines” 裡加入驗證的程式碼了對吧。沒錯,但筆者覺得這樣做還不是最好。一個更好的方式是再先建另一個普通 function “OnBeforePurchaseOrderPostLines_CheckExpenseCode”,它的參數跟 “OnBeforePurchaseOrderPostLines” 一模一樣,然後裡頭放驗證的程式碼。我們最後在 function “OnBeforePurchaseOrderPostLines 中去 call 它。

OnBeforePurchaseOrderPostLines() will call OnBeforePurchaseOrderPostLines_CheckExpenseCode(), the business logic codes stores in the OnBeforePurchaseOrderPostLines_CheckExpenseCode() function

閱讀者可能會覺得有一種包裝兩層的概念。很像是 Codeunit 90 中的 Publisher function “OnBeforePostLines” 會找到 Codeunit 50000 中的 Subscriber function “OnBeforePurchaseOrderPostLines”,然後再進入 function “OnBeforePurchaseOrderPostLines_CheckExpenseCode” 執行程式碼。其實這樣做有一個好處,就是可以控制 functions 的執行順序
我們知道,一個 Publisher function 可能會有多個 Subscriber functions 去訂閱它。就像是 OnBeforePostLines() 這種,可能不只有要檢查 “Expense Code” 這種客製需求,還會有其它的。那這麼多 Subscriber functions,誰先被執行誰後被執行呢答案是不知道。微軟官方說這個目前是隨機的,沒有選項或是設定可以去控制這件事。既然如此,我們就自己寫一個 function 去控制這件事吧 (有一種 wrapper 的感覺)。於是,我們就在 “OnBeforePurchaseOrderPostLines” 裡面自己呼叫要執行的 function,自己控制順序。


上面的 IF PurchLine.FINDFIRST THEN REPEAT … UNTIL (PurchLine.Next = 0) 的程式碼區塊我就不解釋了,想了解的話可以去讀 C/AL 開發的語法,不難的。接下來我們來看看最後一項需求:
8. 在過帳時, “Expense Code” 的資訊也要被帶入到 General Ledger Entries
分析:要去追蹤過帳程式。因為跟 GL Entries 有關,所以會追到 Codeunit 12 (Gen. Jnl.-Post Line)。另外,我們還是一樣從 Codeunit 90 開始追蹤。因為按照經驗,中間還會經過 Table 81 “Gen. Journal Line”
首先開始做 trace codes 的工作。這邊會一層一層的追下去,截圖也會比較多。不過沒辦法,畢竟這是系統客製,躲不掉的。

從 Codeunit 90 的 OnRun() 追起,找到 PostPurchLine()

繼續從 PostPurchLine() 追到 FillInvoicePostBuffer()

繼續追到 PreparePurchase()

終於找到用 Purchase Line 對 Invoice Post. Buffer 賦值的地方了,而且找到了 Publisher function “OnAfterInvPostBufferPreparePurchase()”

最後在 Codeunit 50000 中新增 Subscriber function 並加上程式碼。記得在做這個動做前,要先確定 Table 49 “Invoice Post. Buffer” 是否有加上客製欄位 “Expense Code”


“Expense Code” 的值已經從 Purchase Line 帶到 Invoice Post. Buffer 了,接下來估記是繼續從 Invoice Post. Buffer 帶到 Gen. Journal Line 吧。我們繼續從 Codeunit 90 的 OnRun() 追下去:

PostGLAndVendor()

PostInvoicePostingBuffer()

PostInvoicePostBufferLine()

CopyFromInvoicePostBuffer()

終於找到用 Invoice Post. Buffer 對 Gen Journal Line 賦值的地方了,而且找到了 Publisher function “OnAfterCopyGenJnlLineFromInvPostBuffer”

最後在 Codeunit 50000 中新增 Subscriber function 並加上程式碼。記得在做這個動做前,要先確定 Table 81 “Gen. Journal Line” 是否有加上客製欄位 “Expense Code”


最後,有關於 G/L Entry 的產生 (目前其實只還差將 Table 81 “Gen. Journal Line” 中的 “Expense Code” 帶到 Table 17 “G/L Entry” 的 “Expense Code”)。我們知道 G/L Entry 的產生最後都會追到 Codeunit 12 “Gen. Jnl.-Post Line” 的 RunWithCheck() 函式。就算你從 Codeunit 90 一路追下來也會最後追到同樣的地方,這邊就直接從 Codeunit 12 開始繼續追下去了。

RunWithCheck() => Code()

Code() => PostGenJnlLine()。有人可能會好奇這邊 Codes 那麼多,到底怎麼追?其實只要往 Posting, Gen. Journal Line, G/L Entry 的方向去找,就對了

PostGenJnlLine() => PostGLAcc():我們現在要幹嘛,當然是過帳 G/L 然後得到 G/L Entry 啊

PostGLAcc() => InitGLEntry():所以 InitGLEntry 也不過份吧

InitGLEntry() => CopyFromGenJnlLine()。終於找到了把欄位從 Gen. Journal Line 複製到 G/L Entry 的函式

終於找到用 Gen Journal Line 對 G/L Entry 賦值的地方了,而且找到了 Publisher function “OnAfterCopyGLEntryFromGenJnlLine”

最後在 Codeunit 50000 中新增 Subscriber function 並加上程式碼。記得在做這個動做前,要先確定 Table 17 “G/L Entry” 是否有加上客製欄位 “Expense Code”


經過了五篇 Dynamics 365 Business Central 的開發實戰文,我們對這個系統的開發原則、模式也有了一定的了解。在下一篇文章,我將總結一些我個人先前在業界擔任技術顧問的心得與看法,和如何邁向 Extensions, AL, VSCode 的開發之路。

*********************************************************************************

<< 以上文章,經作者 Ray 同意,轉載自 https://medium.com/@nturay0321 >>

發佈留言