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


單據編碼是ERP系統中必備的功能,用於生成各種單據的流水號,常常借助於日期時間等字符來生成一個唯一的單據號碼。從軟件的角度來說,就是為生成數據表的主鍵值(參考編號),從用戶的角度來說,就是給業務單據制定編碼規范。之后做到見名知意,比如銷售訂單號是SO201508190001,采購訂單號碼是PO201508190001。

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。

 

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

參考下面的數據例子來理解這個表的含義:

SeriesCode Prefix TextPattern NextSeqNo
SLSOSO ??@Y@M PO 9
SLSOSO ??@Y@M OE 17

使用問號作為占位符,在運行時彈出窗體讓用戶選擇哪一種單據編碼方案,用戶選擇PO,則生成PO201508前綴的采購訂單編碼,如用戶選擇OE,則生成OE201508前綴的采購訂單編碼。

為了加深對占位符號的理解,舉例說明以下幾種情況。

1  前綴定義值是 ??ABC,用戶選擇XY,則返回前綴結果XYABC。
2  前綴定義???ABC,用戶選擇XY,返回結果前墜XY_ABC,對於不多余的占位符號用下划線替代。
3  前綴定義@D@M@YABC,當前日期是2015年8月19日,則生成的前綴值是150819ABC。

 

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

有時候不同的用戶有不同的單據編碼規則,我們需要依照用戶來創建編碼規則。先創建數據庫。

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

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM