SaaS ERP:自定義狀態(tài)流的訂單鎖定與釋放
編輯導(dǎo)語:如今隨著互聯(lián)網(wǎng)的不斷發(fā)展,很多傳統(tǒng)的方式也逐漸朝著互聯(lián)網(wǎng)方向轉(zhuǎn)換,比如現(xiàn)在比較流行的電商行業(yè),其中很多訂單狀態(tài)都是要通過各種系統(tǒng)實(shí)現(xiàn);本文作者分享了關(guān)于自定義狀態(tài)流的訂單鎖定與釋放,我們一起來了解一下。
一、標(biāo)準(zhǔn)化狀態(tài)流與自定義狀態(tài)流
標(biāo)準(zhǔn)化狀態(tài)流是指類似于天貓,京東,蘇寧等主流電商的訂單狀態(tài)流,一個狀態(tài)要滿足一定的條件才能流轉(zhuǎn)到下一個狀態(tài)。
主流電商的訂單狀態(tài)流
之前在做海外倉的時候,無論是OMS還是WMS中,訂單的狀態(tài)流也都是提前預(yù)設(shè)好的,可以理解為也是一種“標(biāo)準(zhǔn)化”的狀態(tài)流,如下圖所示。
OMS和WMS的訂單狀態(tài)流
對于標(biāo)準(zhǔn)化的訂單狀態(tài)流,業(yè)內(nèi)已經(jīng)有很多很成熟的方案,所以在設(shè)計此類產(chǎn)品功能的時候,可以借鑒的資料和方案就比較多,也比較清晰。
例如電商后臺可配置“下單鎖庫存”還是“支付后鎖庫存”;OMS可以配置某些客戶“進(jìn)單鎖庫存”,然后其他客戶“預(yù)報時所庫存”;WMS一般是“系統(tǒng)進(jìn)單時鎖定庫存”,然后“分波時再鎖定一次庫存”……
而自定義訂單狀態(tài)流一般適用于SaaS類軟件,因?yàn)镾aaS類軟件是做通用型產(chǎn)品,針對不同行業(yè),不同玩法,需要提供比較靈活的自定義功能。
例如產(chǎn)品需求管理神器TAPD就是很典型的一款SaaS類軟件,不同行業(yè),不同公司,不同團(tuán)隊(duì)對于需求、迭代管理的方式都不一樣,所以TAPD提供了很靈活的自定義功能。
截圖自TAPD幫助文檔
TAPD自定義工作流
而對于SaaS類的外貿(mào)管理軟件(可以等同為B2B類進(jìn)銷存軟件)來說,也會面臨相似的問題。不同的行業(yè),對于訂單有不同的處理方式,也同樣需要靈活地自定義訂單的狀態(tài)流。
自定義訂單狀態(tài)流示意圖1
自定義訂單狀態(tài)流示意圖2
有一些公司是無庫存管理的,所有的訂單產(chǎn)品都需要采購后再發(fā)出(以銷定采)。有一些公司是有庫存管理的,部分產(chǎn)品需要采購,部分產(chǎn)品有庫存直接出庫。還有一些公司是工貿(mào)一體型,可以自己的工廠加工生產(chǎn),然后交付相應(yīng)的訂單……
所以不同的公司使用SaaS軟件的時候會配置出很多“獨(dú)具個性”的業(yè)務(wù)流程,而SaaS產(chǎn)品經(jīng)理要做的就是抽象出其中最核心、最具代表性的業(yè)務(wù)特征,從而完成相應(yīng)的“業(yè)務(wù)建?!焙汀跋到y(tǒng)建模”,以便于支撐復(fù)雜的、多變的業(yè)務(wù)場景。
二、自定義狀態(tài)流的特點(diǎn)
通過上面的簡單案例,我們會發(fā)現(xiàn):對標(biāo)準(zhǔn)化狀態(tài)流的系統(tǒng)來說,訂單的一些操作或者邏輯的處理是可以通過狀態(tài)來控制的,在某個狀態(tài)可以做某些事情,然后會變換到另一個狀態(tài)。
而自定義狀態(tài)流的系統(tǒng)則比較難實(shí)現(xiàn)此功能,有可能A公司定義了5個狀態(tài),而B公司則定義了8個狀態(tài);A公司的狀態(tài)1可以直接切換到狀態(tài)3、狀態(tài)4、狀態(tài)5,B公司的狀態(tài)1,只能切換到狀態(tài)2,然后再從狀態(tài)2切換到狀態(tài)3,以此類推……
A公司的狀態(tài)切換示意圖
即使是A公司和B公司都定義了相同的狀態(tài)值,但是流轉(zhuǎn)的條件和邏輯不一樣,也會導(dǎo)致產(chǎn)生完全不同的工作流模式。
B公司的狀態(tài)切換示意圖
所以,自定義狀態(tài)流的訂單,很難在狀態(tài)這個字段上做一些判斷或者邏輯的處理,從而衍生出了一些跟標(biāo)準(zhǔn)化狀態(tài)流的不一樣的處理邏輯。
可以簡單理解為:時代變了,玩法不一樣的,不能直接套用2C電商的那一套玩法了。
三、標(biāo)準(zhǔn)化狀態(tài)流的訂單鎖定與釋放庫存
在剖析“自定義狀態(tài)流的訂單是如何鎖定和釋放庫存”這個問題之前,我們不妨先來看看標(biāo)準(zhǔn)化的狀態(tài)流的訂單鎖定與釋放庫存的過程是怎么樣的。
拿我最熟悉的跨境電商海外倉OMS和WMS這一套玩法來舉例,一般來說客戶從自己平臺或者ERP中推送訂單到OMS中,然后OMS預(yù)報面單之后再下推到WMS中,WMS作業(yè)出庫之后再將信息回傳到OMS,然后再推送給客戶自己的平臺或者ERP中。注意,這里的客戶是指電商賣家,而不是消費(fèi)者。
其中OMS和WMS分別管理一套庫存,OMS的庫存可以理解為賬面庫存,WMS的庫存可以理解為實(shí)物庫存。對于外部的商家客戶來說,他們關(guān)注的是OMS端有多少庫存,因?yàn)檫@些庫存決定了在平臺上可以銷售的庫存是多少。
所以客戶的平臺訂單進(jìn)入OMS之后,OMS需要鎖定這部分的庫存,避免客戶推送超量的訂單而庫存又不足,造成發(fā)貨延期的問題。這個時候鎖庫的節(jié)點(diǎn)是根據(jù)訂單的狀態(tài)來判斷的,例如可以設(shè)置進(jìn)單鎖定,則意味著OMS接收到了客戶的平臺訂單之后,訂單狀態(tài)是「新建」,此刻就可以鎖定庫存,然后等到訂單狀態(tài)變成了「已出庫」之后,此時就可以釋放并扣減對應(yīng)鎖定的庫存。
也可以設(shè)置預(yù)報之后再鎖定庫存,這里的預(yù)報指的是訂單狀態(tài)為「已預(yù)報」,釋放的邏輯也是「已出庫」之后再釋放……
無論是哪種鎖定方式,其實(shí)本質(zhì)上都是根據(jù)訂單的狀態(tài)來判斷的,只要抓住這個核心邏輯,那么訂單的鎖定與釋放就不會很難。這也是市面上主流的解決方案,網(wǎng)絡(luò)上有很多相關(guān)的介紹資料,感興趣的朋友可以自行搜索。
四、自定義狀態(tài)流的訂單鎖定與釋放
1. 了解背景
有了前面鋪墊的知識背景之后,我們再來看看今天的主題:自定義狀態(tài)流的訂單如何鎖定與釋放庫存?
介紹一下背景,目前已有訂單模塊,但是沒有庫存模塊。訂單都是手動創(chuàng)建的合同訂單,類似于TAPD的需求一樣,可以任意的流轉(zhuǎn)狀態(tài),但是不會產(chǎn)生實(shí)質(zhì)性影響,例如影響庫存,影響外部系統(tǒng)的狀態(tài)等。
現(xiàn)在的需求是要引入庫存模塊,通過采購單可以創(chuàng)建入庫單,增加庫存;通過訂單可以創(chuàng)建出庫單,扣減庫存,而訂單除了要支持創(chuàng)建出庫單扣減庫存之外,還要考慮庫存鎖定和釋放的問題,因?yàn)榭赡軙卸鄠€業(yè)務(wù)員同時建單,但是出庫的時候發(fā)現(xiàn)庫存不足的情況,本文重點(diǎn)討論的就是關(guān)于訂單的庫存鎖定與釋放的問題。
起初接到這個任務(wù)的時候,我第一反應(yīng)就是要么在創(chuàng)建訂單的時候就鎖定庫存,要么在創(chuàng)建出庫單的時候鎖定庫存,這樣是最簡單的。
但是隨著對業(yè)務(wù)場景的調(diào)研,我發(fā)現(xiàn)這兩種方案都存在一些問題:
- 由于外貿(mào)B2B訂單有很多都是通過郵件溝通的,而且訂單履約時間會特別長,為了管理整個銷售過程,業(yè)務(wù)員會提前創(chuàng)建好訂單,然后通過不同的狀態(tài)來判斷訂單進(jìn)行到了哪一步。如果提前太久鎖定庫存,后期面臨訂單取消或者變更的時候,會造成庫存的積壓問題;
- 外貿(mào)商家有一些是無庫存經(jīng)營的模式,有訂單了之后再去采購,然后采購了之后就直接發(fā)出了。通過創(chuàng)建訂單就鎖定庫存不具有普適性,可能還會引入負(fù)庫存的概念,比較麻煩;
- 如果是創(chuàng)建出庫單再鎖定庫存,那么在庫存鎖定之前可能會出現(xiàn)多個業(yè)務(wù)員爭搶庫存的情況,因?yàn)殡p方在報價確認(rèn)訂單的時候,看到系統(tǒng)的庫存都是有貨的,但是一旦誰先創(chuàng)建了出庫單鎖定了這部分的庫存,那么剩下的一方就會面臨庫存不足的情況;
2. 踩坑方案
在一開始的時候我并沒有清晰地認(rèn)識到自定義狀態(tài)流有這么一些坑,所以我還是試著用2C電商的玩法來剖析這個問題。
狀態(tài)流雖然是自定義的,但是可以歸納為三個大類:
- 起始狀態(tài);
- 中間狀態(tài);
- 完結(jié)狀態(tài);
訂單狀態(tài)歸納
只要是中間狀態(tài),就可以鎖定訂單的庫存。如果訂單鎖定了庫存,在創(chuàng)建出庫單的時候,訂單鎖定的部分會流轉(zhuǎn)為出庫單鎖定;如果訂單沒有鎖定庫存,則創(chuàng)建出庫單時候,直接變成出庫單鎖定庫存。
訂單無鎖定庫存
訂單鎖定了庫存
通過上述的分析可以知道:
- 一個訂單可以創(chuàng)建多個出庫單,也就是多批次發(fā)貨;
- 訂單在創(chuàng)建出庫單的時候,可能已經(jīng)鎖定了庫存,也可能沒有鎖定庫存;
- 訂單創(chuàng)建了出庫單之后,可以更改狀態(tài)(自定義工作流),可以從未鎖定轉(zhuǎn)為鎖定(因?yàn)榕渲昧说侥硞€狀態(tài)時則鎖定庫存),但是不可以從已鎖定轉(zhuǎn)為未鎖定,因?yàn)殒i定的釋放邏輯不是這樣的;
- 創(chuàng)建的出庫單可以刪除,也可以正常作業(yè),直到出庫完成扣減庫存;
從未鎖定到鎖定狀態(tài)
以上方案看似沒有什么問題,但是最大的坑就隱藏在一旦后臺配置好了在某個節(jié)點(diǎn)鎖定庫存,那么接下來新增的后續(xù)的狀態(tài)也必須要配置鎖定,否則就會出現(xiàn)錯亂的問題。
如下圖所示,這個是一個理想的狀態(tài)流轉(zhuǎn),除了起始和完結(jié)狀態(tài)之外,其他的中間狀態(tài)都可以鎖定庫存都可以創(chuàng)建出庫單,而且只能一步一步流轉(zhuǎn),這樣就只會有“未鎖定轉(zhuǎn)為鎖定”的情況,當(dāng)最后一步要轉(zhuǎn)為完結(jié)的時候,可以增加判斷條件“只有訂單明細(xì)的全部庫存都出庫釋放了”才能流轉(zhuǎn)到完結(jié)。
理想的自定義情況
其實(shí)這還是2C電商的玩法, 通過一些規(guī)則和配置,強(qiáng)制性的將自定義流轉(zhuǎn)的玩法變成了按要求流轉(zhuǎn)。
如下圖所示,當(dāng)在狀態(tài)2沒有鎖定庫存的時候創(chuàng)建了1/3數(shù)量的出庫單,但是沒有出庫;等到了狀態(tài)3的時候,可以自動鎖定的數(shù)量就變成了2/3了;如果在狀態(tài)4的時候刪除了原來1/3數(shù)量的出庫單,那么流轉(zhuǎn)到狀態(tài)5的時候又要重新鎖定庫存,此刻可能會出現(xiàn)庫存不足情況,那么此訂單就不能及時完成發(fā)貨了。
不鎖庫的時候創(chuàng)建了出庫單,但是后續(xù)又刪除了
還是上面的例子,如果新增狀態(tài)5的時候忘記了配置自動鎖定庫存和支持創(chuàng)建出庫單,那么這個單到了狀態(tài)5的時候就不會鎖定庫存也不能支持創(chuàng)建出庫單了,訂單處于一個“死局”的狀態(tài)。
同時,如果配置狀態(tài)流的時候是支持一個狀態(tài)流轉(zhuǎn)到多個狀態(tài),例如狀態(tài)1可以到狀態(tài)3、狀態(tài)4、狀態(tài)5這種,那么背后的判斷邏輯就會變得更加復(fù)雜。需要考量到每個狀態(tài)自身能做什么,然后考慮每個狀態(tài)能流轉(zhuǎn)到哪些狀態(tài),會帶來什么樣的邏輯沖突等。
新增的狀態(tài)沒有配置鎖定和支持出庫
通過對自定義狀態(tài)流來配置不同的狀態(tài)節(jié)點(diǎn)可以支持鎖庫和創(chuàng)建出庫單,看似很美好,但是實(shí)操起來風(fēng)險很大,加重了實(shí)施成本。而且一旦配置錯誤,后續(xù)一些鎖定的數(shù)據(jù)還需要手動運(yùn)維解鎖處理,增加了很多運(yùn)維的成本。
直覺告訴我,如果一個產(chǎn)品方案拆解到后面,越來越復(fù)雜,越來越亂,那么很有可能這個方案的源頭就出現(xiàn)了問題。因?yàn)楹玫漠a(chǎn)品解決方案應(yīng)該是和寫出的代碼一樣,是“優(yōu)雅的”,“簡潔的”,“清晰的”,如果不是,那么很有可能就是踩坑了。
3. 避坑方案
此方案是在研究了好幾個競品之后突然頓悟的,回過頭再想想其實(shí)解決方案也很簡單,類似于解數(shù)學(xué)題一樣:引入一個“中間變量”。
上面的踩坑方面看得大家一臉懵逼,腦子已經(jīng)成了漿糊,現(xiàn)在我們跳出上面的解決方案來分析一下。我們面臨的問題是什么?我們應(yīng)該去解決?
訂單要鎖定,是為了防止多個業(yè)務(wù)員同時需要某個庫存的時候產(chǎn)生爭議,所以鎖定的目的是為了提前分配,但是因?yàn)樽远x狀態(tài)流的原因,系統(tǒng)不能根據(jù)狀態(tài)來自動鎖定相應(yīng)的庫存從而分配給對應(yīng)的訂單,那么系統(tǒng)不能做到的話,交給用戶自己手動去鎖定是否可行呢?當(dāng)業(yè)務(wù)員覺得此訂單涉及的SKU庫存比較緊俏的時候,手動鎖定相應(yīng)的數(shù)量,然后占為己有。此時,其他業(yè)務(wù)員也有類似的訂單的時候,可以看到可用庫存數(shù)量已經(jīng)減少了,就知道自己的訂單可能庫存不足需要進(jìn)行采購了。
此時,我們引入一個訂單鎖庫表的“中間變量”,也可以理解為手動占用表,這樣便于后續(xù)與出庫單鎖定作區(qū)分。當(dāng)某個訂單快要談成的時候,業(yè)務(wù)員可以選擇手動鎖庫,提前占用相應(yīng)的庫存,當(dāng)然占用的數(shù)量不能大于訂單的數(shù)量,避免惡意占用。
訂單被提前占用了之后,當(dāng)關(guān)聯(lián)了相應(yīng)的出庫單時(創(chuàng)建銷售出庫單),出庫單會優(yōu)先通過訂單號來查詢手動占用表,然后從手動占用表中讀取已占用的數(shù)量,將占用的數(shù)量轉(zhuǎn)為出庫單鎖定。然后出庫單正常出庫了之后,出庫單鎖定的庫存就會扣減掉,生成庫存流水。
訂單、鎖庫表、出庫單直接的關(guān)系銷售訂單可以創(chuàng)建鎖庫表(也可以叫做占用表),也可以創(chuàng)建出庫單。創(chuàng)建鎖庫表時可以手動輸入要鎖定的數(shù)量,鎖定類型為鎖庫表鎖定(手動占用)。創(chuàng)建出庫單時,出庫數(shù)量是多少則鎖定多少,如果直接出庫了則扣減庫存,這種形式的鎖定為出庫單鎖定。如果先創(chuàng)建鎖庫表,再創(chuàng)建出庫單,則出庫單的鎖定數(shù)量從鎖庫表中獲取。如果出庫數(shù)量大于鎖庫表,則鎖庫表自動釋放,鎖庫表鎖定的庫存全部轉(zhuǎn)為出庫鎖定;如果出庫數(shù)量小于鎖庫表,則鎖庫表部分釋放,釋放的部分轉(zhuǎn)為了出庫鎖定;剩余的鎖庫表鎖定數(shù)量可以手動釋放,也可以繼續(xù)創(chuàng)建出庫單,流轉(zhuǎn)到出庫鎖定。
如果先創(chuàng)建出庫單,再創(chuàng)建鎖庫表,則鎖庫表(手動占用)可鎖定的庫存數(shù)量也會相應(yīng)的減少,因?yàn)槌鰩靻握加昧艘徊糠值逆i定,不用擔(dān)心鎖庫表數(shù)量會超出出庫單的數(shù)量。
釋放有兩種方式:手動釋放和自動釋放。
手動釋放只能作用于鎖庫表,手動對鎖庫表的內(nèi)容進(jìn)行解鎖釋放。
自動釋放則可以針對鎖庫表和出庫單鎖定,鎖庫表可以通過出庫單來釋放鎖定,將鎖庫表鎖定轉(zhuǎn)為出庫單鎖定;出庫單鎖定則可以通過完成出庫扣減庫存的方式來釋放鎖定。
簡單概括上述方案就是:
- 手動對訂單創(chuàng)建一個“預(yù)占用池”,然后出庫單優(yōu)先從這邊扣減庫存;
- 這個“預(yù)占用池”可以調(diào)整容量的大小,但是不能超出訂單數(shù)量;創(chuàng)建了出庫單就要從池子里放水,流到另一個池子;如果刪除了出庫單,則水又要裝回來;
從結(jié)論來看,此方案特別簡潔,而且便于理解和介紹;從分析過程看,沒有那么多彎彎繞繞,那么多異常分支;從操作體驗(yàn)上看,讓用戶手動鎖庫,容易感知到庫存狀態(tài)的變化,也能減少實(shí)施的成本,而且也便于用戶理解鎖定的邏輯。
五、踩坑與總結(jié)
之前我一直在試著用2C電商的那一套玩法來設(shè)計產(chǎn)品方案,最后發(fā)現(xiàn)困難重重,邏輯復(fù)雜而且有很多漏洞。
我先入為主地將訂單的鎖定與釋放邏輯跟訂單的狀態(tài)掛鉤在一起,結(jié)果發(fā)現(xiàn)自定義狀態(tài)流的訂單中,狀態(tài)是一個完全不可控的東西,越是想要在這上面做文章,越會陷入一團(tuán)亂麻中無法抽離。
直到后面試著引入一個鎖庫表之后,才發(fā)現(xiàn)原來這個方案缺了“一座橋”,一座跨在訂單和出庫單之間通過訂單號關(guān)聯(lián)的“橋”。有了這座“橋”,很多混亂的,交纏在一起的邏輯一下子就通了。
這個方案困擾了我很久,即使是我想出了鎖庫表這個方案之后,我還是不太死心,還是想試著重新推理一下,看看通過狀態(tài)是否真的無法解決這個問題。
不過遺憾的是,到目前為止我還是沒有找出比鎖庫表更好的解決方案。所以我決定將這個案例記錄下來,分享出來,看看是否有感興趣的朋友有其他更好的解法。
如果你對上述產(chǎn)品設(shè)計方案感興趣,歡迎留言更多業(yè)務(wù)背景和細(xì)節(jié),討論更好的解決方案。
#專欄作家#
vitamin,也自稱“皮醬”,微信公眾號:皮醬叨逼叨。目前是一位外貿(mào)SaaS領(lǐng)域的供應(yīng)鏈產(chǎn)品經(jīng)理,曾做過3年半的跨境倉儲物流方向的產(chǎn)品,也是《人人都是產(chǎn)品經(jīng)理》專欄作家。除了產(chǎn)品方面的知識,也會寫點(diǎn)工作總結(jié),投資理財,讀書筆記和資料分享等……
本文原創(chuàng)發(fā)布于人人都是產(chǎn)品經(jīng)理,未經(jīng)作者許可,禁止轉(zhuǎn)載
題圖來自 Unsplash,基于CC0協(xié)議。
能否把總出庫分成兩部分,一部分是可預(yù)占庫存(占總庫存的1/3),一部分是可出庫庫存(占總庫存的2/3)。
銷售人員創(chuàng)建銷售訂單,使用的時可預(yù)占庫存;創(chuàng)建出庫單時,占用可出庫庫存。銷售訂單轉(zhuǎn)變成出庫單時,增加可出庫庫存;
出庫成功后,扣減庫存,并重新計算可預(yù)占與可出庫庫存
取消銷售訂單時,將釋放可占用庫存
取消出庫單,重新計算兩個庫存。
牛,上班時間花了兩天看了你的文章,國內(nèi)電商B端 學(xué)到很多
有這么多內(nèi)容嗎,要看兩天,哈哈
加了手動處理是可以處理問題,但客戶并不一定買賬愿意這么干
對,如果不愿意手動鎖定的話那就約定大家都是到了創(chuàng)建出庫單的時候再鎖定也可以解決問題。如果有人想要提前鎖定庫存,但是又不想去點(diǎn)擊,那就有點(diǎn)矛盾了。