解析大型.NET ERP系統 單據編碼功能實現

單據編碼是ERP系統中必備的功能,用於生成各類單據的流水號,經常藉助於日期時間等字符來生成一個惟一的單據號碼。從軟件的角度來講,就是爲生成數據表的主鍵值(參考編號),從用戶的角度來講,就是給業務單據制定編碼規範。以後作到見名知意,好比銷售訂單號是SO201508190001,採購訂單號碼是PO201508190001。html

1 基礎單據編碼 Document serialization basic 

單據編碼主表,用於存放單據及其編碼規則。數據庫

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

 

2 宏處理 Macro

有時候咱們須要根據狀況選擇一種或多種序列號生成方式,在生成序號的時候彈出窗體,讓咱們選擇要哪種前綴編碼方案,好比採購訂單的編碼規則,有時候是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。設計

 

3 基於用戶的須要編碼方案 User-based document serialization

有時候不一樣的用戶有不一樣的單據編碼規則,咱們須要依照用戶來建立編碼規則。先建立數據庫。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,記錄每一個用戶要編碼規則。

在系統中,優先使用基於用戶的編碼規則,其次是宏替換處理,最後纔是應用基礎的編碼規則。

 

4 併發處理 Concurrency

當兩個併發用戶同時建立或保存一張一樣的業務單據時,系統會返回兩個相同的單據編碼,產生了併發問題。

A 方案

打開業務功能時,當即爲當前單據建立單據編碼,好比產生單據編碼SO15080004,在單據保存時,發現這張單據編碼被其它的用戶使用過,則從新產生一個新的業務單據編碼SO15080005,若有發現此編碼仍然被佔用,依此向下搜尋,直到找到能夠保存的單據編碼。

這種方案的優勢是老是能夠保存單據,缺點是界面中看到的單據編碼,不必定是最終保存的單據編碼。

B 方案

打開業務功能時,不產生單據編碼,只有在單據保存時才產生單據編碼。避免了單據併發衝突。

這種方案優勢是沒有併發衝突,缺點是隻有單據保存以後才能夠看到單據編碼。

 

5 編碼規則程序設計 Document serialization programming

在單據保存時,調用接口產生編碼規則,參考下面的程序片斷。

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;
}

 

6 固定編碼規則  Fixed document serialization

以上實現了基於流水號的單據編碼規則,若是單據的編碼規則相對固定,則以上方法行不通。請先閱讀下面的需求說明:

接到客戶訂單,訂立合同編號: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從銷售合同到銷售發貨都是同一個單據號,只是編碼前綴不一樣。

這種編碼方案要求一個單據號碼貫穿整個流程,單據編號從起始點業務單據傳遞到最終業務單據,僅僅是前綴不一樣。

要實現這種固定格式的單據編碼,須要對流轉的每一個單據進行編程處理,業務單據也應該有固定的下推流程,作不到通用性,可是優勢是很明顯的,一個號碼貫穿整個業務單據,很是清晰明瞭。

相關文章
相關標籤/搜索