用友ERP T6技術解析(六) 庫齡分析
2.4 庫存管理
2.4.1 庫齡分析
介紹:庫存賬齡是在某時間節點,某種或某類存貨的庫存時間的加權平均值,跟庫存周轉率關系明顯。庫存周轉率越高,庫存賬齡越低,可是二者又不是反比關系。不能簡單把庫存賬齡看成庫存周轉率的一個衍生指標來對待 ,
主界面 (如圖2.4.1圖1)。
目的:一、庫存成本的控制。二、存貨跌價準備計提。
功能:【所有導出】將當前頁的所有倉庫相應的所有產品導出到Excel文檔。【選擇導出】將當前頁選擇的的產品導出到Excel文檔。【查詢】多條件篩選查詢數據(如圖2.4.1 圖2)。【定位】查詢某產品定位到某行,假設產品在多個倉庫,能夠選擇下條定位(如圖2.4.2 圖3)。
主界面:
2.4.1(圖1)
篩選查詢框:
2.4.2(圖2)
定位查詢框:
2.4.3(圖3)
從界面上能夠看到00我們這裏用到的控件有
控件名稱 |
說明 |
日期控件(DateTimePicker) |
控件能夠在工具箱直接拖動至窗口。拖至窗口後右擊屬性能夠改動控件的樣式和各種屬性,還能夠編輯事件。 |
下拉框(ComboBox) |
|
文本(TextBox) |
|
button(Button) |
|
表格(DataGridView) |
|
復選框(CheckBox) |
功能實現:
第一步:數據庫
1、表與關系
2.4.4(圖4)
表1: 出入庫記錄明細表(InAndOutOfInventoryRecordList)
列名 |
數據類型 |
主鍵/外鍵 |
說明 |
InAndOutOfInventoryRecordListID |
int - Identity |
主鍵 |
出入庫記錄明細ID |
Quantity |
decimal (18, 3) |
|
數量 |
TheUnitPrice |
decimal (18, 3) |
|
單位價格 |
InAndOutOfInventoryRecordID |
int |
外鍵 |
存貨ID |
TheInventoryID |
int |
外鍵 |
出入庫存記錄ID |
表2: 出入庫記錄表(InAndOutOfInventoryRecord)
列名 |
數據類型 |
主鍵/外鍵 |
說明 |
InAndOutOfInventoryRecordID |
int - Identity |
主鍵 |
出入庫存記錄ID |
WarehouseID_Dispatch |
int |
外鍵 |
倉庫ID_出庫 |
ForTheTypeID |
int |
外鍵 |
出入庫類型ID |
WarehouseInventory_ID |
int |
外鍵 |
倉庫ID_入庫 |
OoperateDate |
datetime |
|
操作日期 |
2、模糊查詢匹配
第一步:界面層(UIL)代碼,寫在查詢button點擊事件
截圖效果:
首先選擇好模糊匹配定位(比方輸入“雙”字,假設選擇左模糊。則查出“雙XX”的產品,假設選擇右模糊,則查出“XX雙”,假設選擇包括能夠為左、右模糊加上“XX雙XX”,假設是精確查詢,則為“雙”的產品)
代碼:
private voidbtnFixedPosition_Click(object sender, EventArgs e) { stringstrRowFilter = ""; //查詢條件 stringstrProductName = txtProductName1.Text.Trim(); //定位到篩選後的一行 if(strProductName == "") { return; } if(radLeft.Checked) //左模糊 { strRowFilter = string.Format("產品名稱 like '%{0}'", strProductName.Trim()); } else { if(radRight.Checked) //右模糊 { strRowFilter = string.Format("產品名稱 like '{0}%'", strProductName.Trim()); } else { if(radContain.Checked) //包括模糊 { strRowFilter = string.Format("產品名稱 like '%{0}%'", strProductName.Trim()); } else //精確查詢 { strRowFilter = string.Format("產品名稱 like '{0}'", strProductName.Trim()); } } } dvtest = newDataView(dtExisting) { RowFilter =strRowFilter }; dttest = dvtest.ToTable(); if(dttest.Rows.Count > 1) //是否篩選後有一行以上 { btnNext.Enabled = true; //下一個 button 啟用 } else { btnNext.Enabled = false; //下一個 button 不啟用 } intTpage = 0; FixedPosition(intTpage); }
3、庫齡明細查詢分析(依據產品ID與相應的存庫進行分析)
第一步:數據庫的存儲過程
if(@Type='btnCountAnalysis_Click_SELECTBeLaidUpQuantity') --查詢入庫量計算庫齡賬齡 BEGIN DECLARE @出入庫流水表 TABLE (產品名稱 char(30),出入庫時間 nchar(10), 出入庫數量 decimal,時間 DATETIME) --創建暫時表 [email protected] SELECT LTRIM(RTRIM(TheProductTable.ProductName)) AS 產品名稱, CONVERT(nchar(10),InAndOutOfInventoryRecord.OoperateDate , 20) AS 出入庫時間, LTRIM(RTRIM(CAST(-InAndOutOfInventoryRecordList.Quantity AS DECIMAL))) AS 出入庫數量, InAndOutOfInventoryRecord.OoperateDate AS 時間 FROM InAndOutOfInventoryRecordListINNER JOIN InAndOutOfInventoryRecord ON InAndOutOfInventoryRecordList.InAndOutOfInventoryRecordID= InAndOutOfInventoryRecord.InAndOutOfInventoryRecordIDINNER JOIN TheInventoryTable ON InAndOutOfInventoryRecordList.TheInventoryID = TheInventoryTable.TheInventoryID INNER JOIN TheProductTable ON TheInventoryTable.ProductID = TheProductTable.ProductID WHERE InAndOutOfInventoryRecord.WarehouseID_Dispatch!= 0 AND InAndOutOfInventoryRecordList.TheInventoryID IN (SELECT TheInventoryTable.TheInventoryID AS 存貨ID FROM TheInventoryTableINNER JOIN TheProductTable ON TheInventoryTable.ProductID = TheProductTable.ProductID WHERE TheProductTable.ProductID = 3 AND TheInventoryTable.WarehouseID = 1) --產品ID、倉庫ID UNION ALL SELECT LTRIM(RTRIM(TheProductTable.ProductName)) AS 產品名稱, CONVERT(nchar(10),InAndOutOfInventoryRecord.OoperateDate , 20) AS 出入庫時間, LTRIM(RTRIM(CAST(InAndOutOfInventoryRecordList.Quantity AS DECIMAL))) AS 出入庫數量, InAndOutOfInventoryRecord.OoperateDate AS 時間 FROM InAndOutOfInventoryRecordListINNER JOIN InAndOutOfInventoryRecord ON InAndOutOfInventoryRecordList.InAndOutOfInventoryRecordID= InAndOutOfInventoryRecord.InAndOutOfInventoryRecordIDINNER JOIN TheInventoryTable ON InAndOutOfInventoryRecordList.TheInventoryID = TheInventoryTable.TheInventoryID INNER JOIN TheProductTable ON TheInventoryTable.ProductID = TheProductTable.ProductID WHERE InAndOutOfInventoryRecord.WarehouseInventory_ID!= 0 AND InAndOutOfInventoryRecordList.TheInventoryID IN (SELECT TheInventoryTable.TheInventoryID AS 存貨ID FROM TheInventoryTableINNER JOIN TheProductTable ON TheInventoryTable.ProductID = TheProductTable.ProductID WHERE TheProductTable.ProductID = @ProductID AND TheInventoryTable.WarehouseID = @WarehouseID) --產品ID、倉庫ID ORDER BYInAndOutOfInventoryRecord.OoperateDate; SELECT 產品名稱,庫齡,CASE WHEN 出入庫數量 > 數量 THEN 數量 ELSE 出入庫數量 END AS數量 FROM ( SELECT 產品名稱, DATEDIFF(DAY,出入庫時間,GETDATE()) AS 庫齡, --與今天相比,計算出相差的天數 出入庫數量, ( SELECT ISNULL(SUM(CAST(出入庫數量 AS DECIMAL)),0) FROM @出入庫流水表 WHERE 產品名稱 =(SELECT ProductName FROM TheProductTable WHERE TheProductTable.ProductID = @ProductID) AND 出入庫時間 <= GETDATE() AND (出入庫時間 <= 出入庫流水表.出入庫時間 OR(出入庫時間 > 出入庫流水表.出入庫時間 AND 出入庫數量 < 0)) )AS數量 FROM @出入庫流水表 AS 出入庫流水表 WHERE 產品名稱 =(SELECT ProductName FROM TheProductTable WHERE TheProductTable.ProductID = @ProductID) and 出入庫時間 <= GETDATE() and 出入庫數量 > 0 ) as計算表 WHERE 數量 > 0 SELECT *FROM @出入庫流水表 END
第二步:邏輯層(BLL)代碼
///<summary> ///查詢入庫量計算庫齡賬齡 ///</summary> ///<param name="intProductID">產品ID</param> ///<param name="intWarehouseID">倉庫ID</param> ///<returns></returns> [OperationContract] public DataSetbtnCountAnalysis_Click_SELECTBeLaidUpQuantity(intintProductID, int intWarehouseID) { SqlParameter[] SQlCMDpas = { newSqlParameter("@Type",SqlDbType.Char), new SqlParameter("@ProductID", SqlDbType.Int),//產品ID new SqlParameter("@WarehouseID", SqlDbType.Int),//倉庫ID }; SQlCMDpas[0].Value = "btnCountAnalysis_Click_SELECTBeLaidUpQuantity"; SQlCMDpas[1].Value = intProductID; SQlCMDpas[2].Value = intWarehouseID; return myDALMethod.QueryDataSet("InventoryManage_frm_StockLookIntoTheDistance",SQlCMDpas); }
第三步:界面層(UIL)代碼。在具體庫齡窗口的Load事件中綁定的數據
截圖效果(在主界面點擊相應的產品相應的倉庫的具體庫齡):
截圖效果(具體庫齡的主界面):
左邊為產品相應的庫齡與及相應庫齡的數量。右邊為相應產品的出入庫情況(時間、數量)
截圖效果(點擊同樣庫齡合並數量):
將同樣庫齡的數量加起來(為什麽出現同樣庫齡?由於在某天對該產品的進出次數多!)
代碼:
(一)Load事件:
DataSet dsAgeAnalysis =myfrm_StockLookIntoTheDistance.btnCountAnalysis_Click_SELECTBeLaidUpQuantity(intProductID,intWarehouseID); dgvInventoryAgeAnalysis.DataSource = dsAgeAnalysis.Tables[0]; //查詢庫齡 dgvDiscrepancyAgeAnalysis.DataSource = dsAgeAnalysis.Tables[1]; //具體出入明細 ChangeColour(); //出庫標識 入庫 標識 顏色
(二) 合計數量
#region 合計 ///<summary> ///合計 ///</summary> ///<param name="sender"></param> ///<param name="e"></param> private voidbtnTotal_Click(object sender, EventArgs e) { listAgeAnalysis.Clear(); //又一次點擊時。清空庫齡集合 DataTable dtSumAgeAnalysis = new DataTable(); //保存合計的庫齡 dtSumAgeAnalysis = ((DataTable)(dgvInventoryAgeAnalysis.DataSource)).Clone(); for (int intRows = 0;intRows < dgvInventoryAgeAnalysis.Rows.Count; intRows++) { if (!listAgeAnalysis.Exists(i => i ==Convert.ToInt32(dgvInventoryAgeAnalysis.Rows[intRows].Cells["庫齡"].Value))) { listAgeAnalysis.Add(Convert.ToInt32(dgvInventoryAgeAnalysis.Rows[intRows].Cells["庫齡"].Value)); dtSumAgeAnalysis.Rows.Add(); dtSumAgeAnalysis.Rows[dtSumAgeAnalysis.Rows.Count - 1]["產品名稱"] =dgvInventoryAgeAnalysis.Rows[intRows].Cells["產品名稱"].Value; dtSumAgeAnalysis.Rows[dtSumAgeAnalysis.Rows.Count - 1]["庫齡"] =dgvInventoryAgeAnalysis.Rows[intRows].Cells["庫齡"].Value; dtSumAgeAnalysis.Rows[dtSumAgeAnalysis.Rows.Count - 1]["數量"] = 0; } if (listAgeAnalysis.Exists(i => i == Convert.ToInt32(dgvInventoryAgeAnalysis.Rows[intRows].Cells["庫齡"].Value))) { dtSumAgeAnalysis.Rows[dtSumAgeAnalysis.Rows.Count - 1]["數量"] = Convert.ToInt32(dtSumAgeAnalysis.Rows[dtSumAgeAnalysis.Rows.Count- 1]["數量"]) + Convert.ToInt32(dgvInventoryAgeAnalysis.Rows[intRows].Cells["數量"].Value); } } dgvInventoryAgeAnalysis.DataSource = dtSumAgeAnalysis; } #endregion
(三)出庫標識 入庫 標識 顏色
///<summary> ///出庫標識 入庫 標識 顏色 ///</summary> void ChangeColour() { for (int intRows = 0;intRows < dgvDiscrepancyAgeAnalysis.Rows.Count; intRows++) { if (Convert.ToInt32(dgvDiscrepancyAgeAnalysis.Rows[intRows].Cells["出入庫數量"].Value) > 0) { dgvDiscrepancyAgeAnalysis.Rows[intRows].DefaultCellStyle.BackColor= Color.Gold; //為入庫 } else { dgvDiscrepancyAgeAnalysis.Rows[intRows].DefaultCellStyle.BackColor = Color.OldLace; //為出庫 } } }
以上技術僅供參考,禁止用於商業用途。上述內容不代表用友立場!
用友ERP T6技術解析(六) 庫齡分析