本文只是從技術角度來討論庫存及庫齡的實現方法,這些是本人在工作中的總結,拋出來和大家一起討論一下。
1. Oracle 庫存的演算法。
Oracle Applications 提供了計算庫存的表 MTL_ONHAND_QUANTITIES_DETAIL,開發人員只要按要求對錶進行分組求和即可得到庫存的現有,這個數量就是我們在系統中查詢的 數量。但是如果使用者要開發人員提供上個月或上個季度的庫存就麻煩了。因為表MTL_ONHAND_QUANTITIES_DETAIL不提供追溯庫存計算 的方法。那怎麼解決這個問題?
我們先來看看錶MTL_ONHAND_QUANTITIES_DETAIL和 mtl_material_transactions 表的關係。mtl_material_transactions 是 Oracle Applications 庫存的基表,凡是和庫存有關的資料都必須存入這個表,如初期的庫存匯入,採購的接受入庫。銷售,製造的完工入庫。子庫轉移等。 mtl_material_transactions 的分組求和應該等於MTL_ONHAND_QUANTITIES_DETAIL表的分組求和,但表mtl_material_transactions 的記錄一般資料龐大,不會在這個表中求現有。mtl_material_transactions表中每筆的資料異動都會影響到 MTL_ONHAND_QUANTITIES_DETAIL 的最終結果。我們通過研究發現。mtl_material_transactions 每筆入庫的記錄都會相應的在MTL_ONHAND_QUANTITIES_DETAI 表中增加此記錄。在庫存未消失前我們可以通過 mtl_material_transactions表的TRANSACTION_ID欄位和表 MTL_ONHAND_QUANTITIES_DETAIL的欄位CREATE_TRANSACTION_ID 建立一一對應關係。 而當有出庫的記錄時,MTL_ONHAND_QUANTITIES_DETAIL不會有對應的一筆出庫記錄而是按照 Oracle 堆棧的邏輯去扣減原先入庫的記錄數量。直道扣減到為零。Oracle Applications 會定期清理 MTL_ONHAND_QUANTITIES_DETAIL 表中為零的數。所以如果我們拿MTL_ONHAND_QUANTITIES_DETAIL 去追溯上期庫存是錯誤的。
2.庫齡的演算法:
根據各個公司不同的業務情況,可能會對Oracle Applications 庫存有不同的設定。
A)有批號和序號控制的物料帳齡計算
如果庫存系統中有設定物料接收入庫時有批號和序號控制時,那麼庫齡的演算法相對較容易,可根據上面現有的演算法SQL中增加批號,和序號等資訊。再根據這些資訊算出物料賬齡。
B)有設定原始接收日期先進先出物料帳齡演算法。
如果在系統上線時設定了庫存系統的profile option:‘INV: 原始接收日期先進先出’
的選項為‘是’,則庫存系統在處理物料的出入庫時按原始接收日期先進先出順序來處理交易數量。則MTL_ONHAND_QUANTITIES_DETAIL表中的欄位ORIG_DATE_RECEIVED 就會記錄原始的接收日期,一直到它的庫存消失為止。
演算法如A)的演算法大同小異。
C)假設FIFO的原理物料帳齡演算法
如果庫存系統不能滿足上面的A),B)條件,那麼我們如何計算物料的賬齡?這雷根據我們公司的賬齡演算法,給出一個解決方案。首先是假設物料是按FIFO的 原理來出入庫的。然後我們還要假設一個原始的物料賬齡,在這個基礎上再按FIFO的原理運算出新的賬齡。如果是剛上線的系統,則初期匯入的庫存為原始的物 料賬齡,可認為匯入時刻的物料庫存賬齡為零。如果是系統已經用了好多年了,那怎樣計算物料的賬齡呢?這裡我們有一個近似的演算法。可以用本文開始介紹的庫存 追溯的計算方法,求出一年或二年前的庫存資料,再預設此時的物料賬齡為零。再以此資料為基礎,按物料的FIFO原理計算到現在的物料賬齡。一般我們認為物 料如果超過180天還在庫存,就認為是呆料了,所以一年或二年的時間就可以了。我們實現的方法如下:
a) 用追溯的演算法計算出一年或二年前的物料庫存。
預設此時的物料賬齡為零。具體的演算法參考前面的SQL。這裡要看公司對這個賬齡的分類要求,是按倉位,還是要到貨位,不同的公司有不同的要求。我們這裡是以倉位為基本分類。
b) 根據前期的初始賬齡。來推算現在的物料賬齡。
2.1 建立一個表存放初始賬齡的表。
初始的帳齡記錄放入此表,以後的帳齡計算根據此表的資料來演算。
2.2 物料帳齡滾動計算。
截取初始賬齡時間到現在某個時間為止的時間段內mtl_material_transactions表中的所有類型的記錄(除成本更新)。對這段記錄要按 交易時間的先後循序每一條,每一條的計算。按入庫和出庫情況進行分類。對新入庫的要記錄到表BITC_ITEM_INV_ATUO_AGE 中,原始的入庫時間為這筆記錄的交易時間。如果是出庫的要找到這個物料最早的賬齡日期的那筆庫存。如果此筆庫存不過扣減,則找到這個料下一筆賬齡庫存數。 直到滿足這筆記錄出庫為止。這樣不停的計算直到最後一筆。且每計算一筆記錄,我們要在mtl_material_transactions表中標記為此筆 記錄已運算過,下次不要重複計算。保證資料的準確性。如果運行到現在就是我們要的物料賬齡表了,我們可以制定一個程式在後台定時運算。這樣就能及時地得到 所要的物料賬齡表。
具體的實現方法如下:
1. 截取初始賬齡時間到現在某個時間為止的時間段內mtl_material_transactions表中的所有類型的記錄(除成本更新),
2. 對此段記錄的排序要特別處理。要按TRANSACTION_ID 和 PRIMARY_QUANTITY 排序。記住單位的不一致的要轉化成一致。對子庫存轉移和挑庫類型以及組織間轉移的類型TRANSACTION_ID 要做一下特殊處理要,讓此類型的資料的正數的記錄排在負數記錄的前面。因為Oracle 處理這些類型時,是先做一筆負數的扣減,從來源倉位扣去要轉出的庫存。然後再做一筆正數的到目的倉位的庫存。為了記錄帳齡表中的庫存來源日期。我們要讓正 數的到目的倉位先入庫存。再讓負數從來源倉出庫。
3. 要對出入庫的記錄要分類處理。不同的類型有不同的處理演算法。
3.1 對入庫類型為:1:PO接收 2:工單完工入庫,3:雜入,4:工單退回
要按新入庫的記錄放入初始賬齡的表。
3.2 對出庫類型和庫存轉移類型轉出的部分。是要按帳齡的先後順序扣減。
3.3 庫存轉移類型入庫的部分要記錄此筆記的原始入庫時間,及將來原倉位的原始入庫時間帶過來。