單據編碼是ERP系統中必備的功能,用於生成各類單據的流水號,經常藉助於日期時間等字符來生成一個惟一的單據號碼。從軟件的角度來講,就是爲生成數據表的主鍵值(參考編號),從用戶的角度來講,就是給業務單據制定編碼規範。以後作到見名知意,好比銷售訂單號是SO201508190001,採購訂單號碼是PO201508190001。html
單據編碼主表,用於存放單據及其編碼規則。數據庫
CREATE TABLE [dbo].[DocumentSerialization]( [SeriesCode] [NVARCHAR](8) NOT NULL, [Description] [NVARCHAR](40) NOT NULL, [Suspended] [NVARCHAR](1) NULL, [SerialLength] [DECIMAL](2, 0) NULL, [PrefixLength] [DECIMAL](2, 0) NULL, [Prefix] [NVARCHAR](12) NULL, [NextSeqNo] [DECIMAL](10, 0) NULL, [AllowOverride] [NVARCHAR](1) NULL, [CreatedDate] [DATETIME] NULL, [CreatedBy] [NVARCHAR](10) NULL, [RevisedDate] [DATETIME] NULL, [RevisedBy] [NVARCHAR](10) NULL, [WithReset] [NVARCHAR](1) NULL, [PrevResetDate] [DATETIME] NULL, [PrefixDefault] [NVARCHAR](12) NULL, CONSTRAINT [PK_DocumentSerialization] PRIMARY KEY CLUSTERED ( [SeriesCode] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO
舉例說明,這些字段值的含義。編程
SeriesCode | Description | Suspended | SerialLength | PrefixLength | Prefix | NextSeqNo |
SLSOSC | Sales Order Cancellation | N | 12 | 6 | SC@Y@M | 55 |
SLSOSO | Sales Order Entry | N | 12 | 6 | SO@Y@M | 4 |
SLSOSQ | Sales Quotations Processing | N | 12 | 6 | SQ@Y@M | 2 |
處理銷售訂單功能SLSOSO,它的單據編碼總長度是12,序號前綴長度是6,序號前綴規則是SO@Y@M,@Y表示兩位數的年,@M表示兩位數的月份,下一個單據編碼流水號是4,因此當產生處理銷售訂單的單據編碼時,它是SO1508000004。session
有時候咱們須要根據狀況選擇一種或多種序列號生成方式,在生成序號的時候彈出窗體,讓咱們選擇要哪種前綴編碼方案,好比採購訂單的編碼規則,有時候是PO201508180001,有時候是OE201508180001,它們的前綴(Prefix)是不同的。爲達到這種目的,咱們給DocumentSerialization增長子表。併發
CREATE TABLE [dbo].[DocumentSerializationDetail] ( [Index] [int] NOT NULL, [SeriesCode] [nvarchar] (8) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL , [Prefix] [varchar] (12) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [TextPattern] [varchar] (12) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL CONSTRAINT , [NextSeqNo] [decimal] (10, 0) NULL, [CreatedDate] [datetime] NULL, [CreatedBy] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [RevisedDate] [datetime] NULL, [RevisedBy] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [Suspended] [varchar] (1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ) ON [PRIMARY] GO ALTER TABLE [dbo].[DocumentSerializationDetail] ADD CONSTRAINT [PK_DocumentSerializationDetail] PRIMARY KEY CLUSTERED ([Index], [SeriesCode]) ON [PRIMARY] GO ALTER TABLE [dbo].[DocumentSerializationDetail] ADD CONSTRAINT [FK_DocumentSerializationDetail_DocumentSerialization] FOREIGN KEY ([SeriesCode]) REFERENCES [dbo].[DocumentSerialization] ([SeriesCode]) GO
參考下面的數據例子來理解這個表的含義:ide
SeriesCode | Prefix | TextPattern | NextSeqNo |
SLSOSO | ??@Y@M | PO | 9 |
SLSOSO | ??@Y@M | OE | 17 |
使用問號做爲佔位符,在運行時彈出窗體讓用戶選擇哪種單據編碼方案,用戶選擇PO,則生成PO201508前綴的採購訂單編碼,如用戶選擇OE,則生成OE201508前綴的採購訂單編碼。編碼
爲了加深對佔位符號的理解,舉例說明如下幾種狀況。spa
1 前綴定義值是 ??ABC,用戶選擇XY,則返回前綴結果XYABC。
2 前綴定義???ABC,用戶選擇XY,返回結果前墜XY_ABC,對於很少餘的佔位符號用下劃線替代。
3 前綴定義@D@M@YABC,當前日期是2015年8月19日,則生成的前綴值是150819ABC。設計
有時候不一樣的用戶有不一樣的單據編碼規則,咱們須要依照用戶來建立編碼規則。先建立數據庫。code
CREATE TABLE [dbo].[DocumentSerializationUser] ( [Index] [int] NOT NULL, [SeriesCode] [nvarchar] (8) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL , [UserId] nvarchar(10) NOT NULL COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL , [Prefix] [varchar] (12) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [TextPattern] [varchar] (12) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL CONSTRAINT , [NextSeqNo] [decimal] (10, 0) NULL, [CreatedDate] [datetime] NULL, [CreatedBy] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [RevisedDate] [datetime] NULL, [RevisedBy] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [Suspended] [varchar] (1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ) ON [PRIMARY] GO
這個表也是序號編碼DocumentSerialization的子表,主鍵增長了用戶編碼字段UserId,記錄每一個用戶要編碼規則。
在系統中,優先使用基於用戶的編碼規則,其次是宏替換處理,最後纔是應用基礎的編碼規則。
當兩個併發用戶同時建立或保存一張一樣的業務單據時,系統會返回兩個相同的單據編碼,產生了併發問題。
A 方案
打開業務功能時,當即爲當前單據建立單據編碼,好比產生單據編碼SO15080004,在單據保存時,發現這張單據編碼被其它的用戶使用過,則從新產生一個新的業務單據編碼SO15080005,若有發現此編碼仍然被佔用,依此向下搜尋,直到找到能夠保存的單據編碼。
這種方案的優勢是老是能夠保存單據,缺點是界面中看到的單據編碼,不必定是最終保存的單據編碼。
B 方案
打開業務功能時,不產生單據編碼,只有在單據保存時才產生單據編碼。避免了單據併發衝突。
這種方案優勢是沒有併發衝突,缺點是隻有單據保存以後才能夠看到單據編碼。
在單據保存時,調用接口產生編碼規則,參考下面的程序片斷。
EcnEntity ecn..... if (ecn.IsNew && seriesCode != string.Empty) { IDocumentSerializationManager serializationManager =ProxyInstance<IDocumentSerializationManager>(); ecn.EcnNo = serializationManager.GetNextSerialNo(sessionId, seriesCode, ecn.EcnNo, ecn); }
若是業務單據的實體保存時發生異常,則須要重置用戶編碼,清除產生的序號編碼。
catch { adapter.Rollback(); if (ecn.IsNew && string.CompareOrdinal(ecn.EcnNo, currentRefNo) != 0) { try { ecn.EcnNo = currentRefNo; serializationManager.ResetNextSequenceNo(seriesCode); } catch { } } throw; }
以上實現了基於流水號的單據編碼規則,若是單據的編碼規則相對固定,則以上方法行不通。請先閱讀下面的需求說明:
接到客戶訂單,訂立合同編號:HT201508003;接着作合同評審,產生一個合同評審單號PS201508003;合同評審經過之後,再到ERP系統中作銷售單,銷售單號是XSD201508003;若是一個合同分三個銷售訂單下單,則會分別產生XSD201508003-01,XSD201508003-02,XSD201508003-03 三個銷售訂單號。繼續爲銷售訂單發貨,銷售訂單XSD201508003所產生的發貨單號應該是XSFH201508003,若是銷售訂單XSD201508003分三次發貨,則依次產生的三張銷售發貨單號是XSFH201508003-01,XSFH201508003-02,XSFH201508003-03。
銷售合同 |
合同評審 |
銷售訂單 |
銷售發貨 |
備註 |
HT201508003 |
PS201508003 |
一張銷售訂單 XSD201508003 三張銷售訂單 XSD201508003-01 XSD201508003-02 XSD201508003-03 |
一張銷售發貨單 XSFH201508003 二張銷售發貨單 XSFH201508003-01 XSFH201508003-02 |
單據編號201508003從銷售合同到銷售發貨都是同一個單據號,只是編碼前綴不一樣。 |
這種編碼方案要求一個單據號碼貫穿整個流程,單據編號從起始點業務單據傳遞到最終業務單據,僅僅是前綴不一樣。
要實現這種固定格式的單據編碼,須要對流轉的每一個單據進行編程處理,業務單據也應該有固定的下推流程,作不到通用性,可是優勢是很明顯的,一個號碼貫穿整個業務單據,很是清晰明瞭。