SaaS ERP:自定义状态流的订单锁定与释放
编辑导语:如今随着互联网的不断发展,很多传统的方式也逐渐朝着互联网方向转换,比如现在比较流行的电商行业,其中很多订单状态都是要通过各种系统实现;本文作者分享了关于自定义状态流的订单锁定与释放,我们一起来了解一下。
一、标准化状态流与自定义状态流
标准化状态流是指类似于天猫,京东,苏宁等主流电商的订单状态流,一个状态要满足一定的条件才能流转到下一个状态。
主流电商的订单状态流
之前在做海外仓的时候,无论是OMS还是WMS中,订单的状态流也都是提前预设好的,可以理解为也是一种“标准化”的状态流,如下图所示。
OMS和WMS的订单状态流
对于标准化的订单状态流,业内已经有很多很成熟的方案,所以在设计此类产品功能的时候,可以借鉴的资料和方案就比较多,也比较清晰。
例如电商后台可配置“下单锁库存”还是“支付后锁库存”;OMS可以配置某些客户“进单锁库存”,然后其他客户“预报时所库存”;WMS一般是“系统进单时锁定库存”,然后“分波时再锁定一次库存”……
而自定义订单状态流一般适用于SaaS类软件,因为SaaS类软件是做通用型产品,针对不同行业,不同玩法,需要提供比较灵活的自定义功能。
例如产品需求管理神器TAPD就是很典型的一款SaaS类软件,不同行业,不同公司,不同团队对于需求、迭代管理的方式都不一样,所以TAPD提供了很灵活的自定义功能。
截图自TAPD帮助文档
TAPD自定义工作流
而对于SaaS类的外贸管理软件(可以等同为B2B类进销存软件)来说,也会面临相似的问题。不同的行业,对于订单有不同的处理方式,也同样需要灵活地自定义订单的状态流。
自定义订单状态流示意图1
自定义订单状态流示意图2
有一些公司是无库存管理的,所有的订单产品都需要采购后再发出(以销定采)。有一些公司是有库存管理的,部分产品需要采购,部分产品有库存直接出库。还有一些公司是工贸一体型,可以自己的工厂加工生产,然后交付相应的订单……
所以不同的公司使用SaaS软件的时候会配置出很多“独具个性”的业务流程, 而SaaS产品经理要做的就是抽象出其中最核心、最具代表性的业务特征,从而完成相应的“业务建模”和“系统建模”,以便于支撑复杂的、多变的业务场景。
二、自定义状态流的特点
通过上面的简单案例,我们会发现:对标准化状态流的系统来说,订单的一些操作或者逻辑的处理是可以通过状态来控制的,在某个状态可以做某些事情,然后会变换到另一个状态。
而自定义状态流的系统则比较难实现此功能,有可能A公司定义了5个状态,而B公司则定义了8个状态;A公司的状态1可以直接切换到状态3、状态4、状态5,B公司的状态1,只能切换到状态2,然后再从状态2切换到状态3,以此类推……
A公司的状态切换示意图
即使是A公司和B公司都定义了相同的状态值,但是流转的条件和逻辑不一样,也会导致产生完全不同的工作流模式。
B公司的状态切换示意图
所以,自定义状态流的订单,很难在状态这个字段上做一些判断或者逻辑的处理,从而衍生出了一些跟标准化状态流的不一样的处理逻辑。
可以简单理解为:时代变了,玩法不一样的,不能直接套用2C电商的那一套玩法了。
三、标准化状态流的订单锁定与释放库存
在剖析“自定义状态流的订单是如何锁定和释放库存”这个问题之前,我们不妨先来看看标准化的状态流的订单锁定与释放库存的过程是怎么样的。
拿我最熟悉的跨境电商海外仓OMS和WMS这一套玩法来举例,一般来说客户从自己平台或者ERP中推送订单到OMS中,然后OMS预报面单之后再下推到WMS中,WMS作业出库之后再将信息回传到OMS,然后再推送给客户自己的平台或者ERP中。 注意,这里的客户是指电商卖家,而不是消费者。
其中OMS和WMS分别管理一套库存,OMS的库存可以理解为账面库存,WMS的库存可以理解为实物库存。对于外部的商家客户来说,他们关注的是OMS端有多少库存,因为这些库存决定了在平台上可以销售的库存是多少。
所以客户的平台订单进入OMS之后,OMS需要锁定这部分的库存,避免客户推送超量的订单而库存又不足,造成发货延期的问题。这个时候锁库的节点是根据订单的状态来判断的,例如可以设置进单锁定,则意味着OMS接收到了客户的平台订单之后,订单状态是「新建」,此刻就可以锁定库存,然后等到订单状态变成了「已出库」之后,此时就可以释放并扣减对应锁定的库存。
也可以设置预报之后再锁定库存,这里的预报指的是订单状态为「已预报」,释放的逻辑也是「已出库」之后再释放……
无论是哪种锁定方式,其实本质上都是根据订单的状态来判断的,只要抓住这个核心逻辑,那么订单的锁定与释放就不会很难 。这也是市面上主流的解决方案,网络上有很多相关的介绍资料,感兴趣的朋友可以自行搜索。
四、自定义状态流的订单锁定与释放
1. 了解背景
有了前面铺垫的知识背景之后,我们再来看看今天的主题: 自定义状态流的订单如何锁定与释放库存?
介绍一下背景,目前已有订单模块,但是没有库存模块。订单都是手动创建的合同订单,类似于TAPD的需求一样,可以任意的流转状态,但是不会产生实质性影响,例如影响库存,影响外部系统的状态等。
现在的需求是要引入库存模块,通过采购单可以创建入库单,增加库存;通过订单可以创建出库单,扣减库存,而订单除了要支持创建出库单扣减库存之外,还要考虑库存锁定和释放的问题,因为可能会有多个业务员同时建单,但是出库的时候发现库存不足的情况,本文重点讨论的就是关于订单的库存锁定与释放的问题。
起初接到这个任务的时候,我第一反应就是要么在创建订单的时候就锁定库存,要么在创建出库单的时候锁定库存,这样是最简单的。
但是随着对业务场景的调研,我发现这两种方案都存在一些问题:
- 由于外贸B2B订单有很多都是通过邮件沟通的,而且订单履约时间会特别长,为了管理整个销售过程,业务员会提前创建好订单,然后通过不同的状态来判断订单进行到了哪一步。如果提前太久锁定库存,后期面临订单取消或者变更的时候,会造成库存的积压问题;
- 外贸商家有一些是无库存经营的模式,有订单了之后再去采购,然后采购了之后就直接发出了。通过创建订单就锁定库存不具有普适性,可能还会引入负库存的概念,比较麻烦;
- 如果是创建出库单再锁定库存,那么在库存锁定之前可能会出现多个业务员争抢库存的情况,因为双方在报价确认订单的时候,看到系统的库存都是有货的,但是一旦谁先创建了出库单锁定了这部分的库存,那么剩下的一方就会面临库存不足的情况;
2. 踩坑方案
在一开始的时候我并没有清晰地认识到自定义状态流有这么一些坑,所以我还是试着用2C电商的玩法来剖析这个问题。
状态流虽然是自定义的,但是可以归纳为三个大类:
- 起始状态;
- 中间状态;
- 完结状态;
订单状态归纳
只要是中间状态,就可以锁定订单的库存。如果订单锁定了库存,在创建出库单的时候,订单锁定的部分会流转为出库单锁定;如果订单没有锁定库存,则创建出库单时候,直接变成出库单锁定库存。
订单无锁定库存
订单锁定了库存
通过上述的分析可以知道:
- 一个订单可以创建多个出库单,也就是多批次发货;
- 订单在创建出库单的时候,可能已经锁定了库存,也可能没有锁定库存;
- 订单创建了出库单之后,可以更改状态(自定义工作流),可以从未锁定转为锁定(因为配置了到某个状态时则锁定库存),但是不可以从已锁定转为未锁定,因为锁定的释放逻辑不是这样的;
- 创建的出库单可以删除,也可以正常作业,直到出库完成扣减库存;
从未锁定到锁定状态
以上方案看似没有什么问题,但是最大的坑就隐藏在 一旦后台配置好了在某个节点锁定库存,那么接下来新增的后续的状态也必须要配置锁定,否则就会出现错乱的问题 。
如下图所示,这个是一个理想的状态流转,除了起始和完结状态之外,其他的中间状态都可以锁定库存都可以创建出库单,而且只能一步一步流转,这样就只会有“未锁定转为锁定”的情况,当最后一步要转为完结的时候,可以增加判断条件“只有订单明细的全部库存都出库释放了”才能流转到完结。
理想的自定义情况
其实这还是2C电商的玩法, 通过一些规则和配置,强制性的将自定义流转的玩法变成了按要求流转。
如下图所示,当在状态2没有锁定库存的时候创建了1/3数量的出库单,但是没有出库;等到了状态3的时候,可以自动锁定的数量就变成了2/3了;如果在状态4的时候删除了原来1/3数量的出库单,那么流转到状态5的时候又要重新锁定库存,此刻可能会出现库存不足情况,那么此订单就不能及时完成发货了。
不锁库的时候创建了出库单,但是后续又删除了
还是上面的例子,如果新增状态5的时候忘记了配置自动锁定库存和支持创建出库单,那么这个单到了状态5的时候就不会锁定库存也不能支持创建出库单了,订单处于一个“死局”的状态。
同时,如果配置状态流的时候是支持一个状态流转到多个状态,例如状态1可以到状态3、状态4、状态5这种,那么背后的判断逻辑就会变得更加复杂。需要考量到每个状态自身能做什么,然后考虑每个状态能流转到哪些状态,会带来什么样的逻辑冲突等。
新增的状态没有配置锁定和支持出库
通过对自定义状态流来配置不同的状态节点可以支持锁库和创建出库单,看似很美好,但是实操起来风险很大,加重了实施成本。而且一旦配置错误,后续一些锁定的数据还需要手动运维解锁处理,增加了很多运维的成本。
直觉告诉我,如果一个产品方案拆解到后面,越来越复杂,越来越乱,那么很有可能这个方案的源头就出现了问题。 因为好的产品解决方案应该是和写出的代码一样,是“优雅的”,“简洁的”,“清晰的”,如果不是,那么很有可能就是踩坑了。
3. 避坑方案
此方案是在研究了好几个竞品之后突然顿悟的,回过头再想想其实解决方案也很简单,类似于解数学题一样: 引入一个“中间变量” 。
上面的踩坑方面看得大家一脸懵逼,脑子已经成了浆糊,现在我们跳出上面的解决方案来分析一下。我们面临的问题是什么?我们应该去解决?
订单要锁定,是为了防止多个业务员同时需要某个库存的时候产生争议,所以锁定的目的是为了提前分配,但是因为自定义状态流的原因,系统不能根据状态来自动锁定相应的库存从而分配给对应的订单,那么系统不能做到的话,交给用户自己手动去锁定是否可行呢?当业务员觉得此订单涉及的SKU库存比较紧俏的时候,手动锁定相应的数量,然后占为己有。此时,其他业务员也有类似的订单的时候,可以看到可用库存数量已经减少了,就知道自己的订单可能库存不足需要进行采购了。
此时,我们引入一个订单锁库表的“中间变量”,也可以理解为手动占用表,这样便于后续与出库单锁定作区分。当某个订单快要谈成的时候,业务员可以选择手动锁库,提前占用相应的库存,当然占用的数量不能大于订单的数量,避免恶意占用。
订单被提前占用了之后,当关联了相应的出库单时(创建销售出库单),出库单会优先通过订单号来查询手动占用表,然后从手动占用表中读取已占用的数量,将占用的数量转为出库单锁定。然后出库单正常出库了之后,出库单锁定的库存就会扣减掉,生成库存流水。
订单、锁库表、出库单直接的关系销售订单可以创建锁库表(也可以叫做占用表),也可以创建出库单。创建锁库表时可以手动输入要锁定的数量,锁定类型为锁库表锁定(手动占用)。创建出库单时,出库数量是多少则锁定多少,如果直接出库了则扣减库存,这种形式的锁定为出库单锁定。如果先创建锁库表,再创建出库单,则出库单的锁定数量从锁库表中获取。如果出库数量大于锁库表,则锁库表自动释放,锁库表锁定的库存全部转为出库锁定;如果出库数量小于锁库表,则锁库表部分释放,释放的部分转为了出库锁定;剩余的锁库表锁定数量可以手动释放,也可以继续创建出库单,流转到出库锁定。
如果先创建出库单,再创建锁库表,则锁库表(手动占用)可锁定的库存数量也会相应的减少,因为出库单占用了一部分的锁定,不用担心锁库表数量会超出出库单的数量。
释放有两种方式: 手动释放和自动释放 。
手动释放只能作用于锁库表,手动对锁库表的内容进行解锁释放。
自动释放则可以针对锁库表和出库单锁定,锁库表可以通过出库单来释放锁定,将锁库表锁定转为出库单锁定;出库单锁定则可以通过完成出库扣减库存的方式来释放锁定。
简单概括上述方案就是:
- 手动对订单创建一个“预占用池”,然后出库单优先从这边扣减库存;
- 这个“预占用池”可以调整容量的大小,但是不能超出订单数量;创建了出库单就要从池子里放水,流到另一个池子;如果删除了出库单,则水又要装回来;
从结论来看,此方案特别简洁,而且便于理解和介绍;从分析过程看,没有那么多弯弯绕绕,那么多异常分支;从操作体验上看,让用户手动锁库,容易感知到库存状态的变化,也能减少实施的成本,而且也便于用户理解锁定的逻辑。
五、踩坑与总结
之前我一直在试着用2C电商的那一套玩法来设计产品方案,最后发现困难重重,逻辑复杂而且有很多漏洞。
我先入为主地将订单的锁定与释放逻辑跟订单的状态挂钩在一起,结果发现自定义状态流的订单中,状态是一个完全不可控的东西,越是想要在这上面做文章,越会陷入一团乱麻中无法抽离。
直到后面试着引入一个锁库表之后,才发现原来这个方案缺了“一座桥”,一座跨在订单和出库单之间通过订单号关联的“桥”。有了这座“桥”,很多混乱的,交缠在一起的逻辑一下子就通了。
这个方案困扰了我很久,即使是我想出了锁库表这个方案之后,我还是不太死心,还是想试着重新推理一下,看看通过状态是否真的无法解决这个问题。
不过遗憾的是,到目前为止我还是没有找出比锁库表更好的解决方案。所以我决定将这个案例记录下来,分享出来,看看是否有感兴趣的朋友有其他更好的解法。
如果你对上述产品设计方案感兴趣,欢迎留言更多业务背景和细节,讨论更好的解决方案。
#专栏作家#
vitamin,也自称“皮酱”,微信公众号:皮酱叨逼叨。目前是一位外贸SaaS领域的供应链产品经理,曾做过3年半的跨境仓储物流方向的产品,也是《人人都是产品经理》专栏作家。除了产品方面的知识,也会写点工作总结,投资理财,读书笔记和资料分享等……
本文原创发布于人人都是产品经理,未经作者许可,禁止转载
题图来自 Unsplash,基于CC0协议。