我们戏称KTV业务部是点评公司内的小“创业公司”,加入KTV事业部一年来,我们也像一个初创团队一样,从0开始,基本完成了KTV预订业务第一个阶段的探索。
今天从业务角度上对KTV预订的流程,以及我们在KTV预订流程发展过程中的探索给大家做一下介绍。今天的介绍主要分为如下几个大块:
- KTV预订业务基本介绍
- KTV预订展示侧的抽象
- KTV订单模型的演变
- KTV预订流程的演变
KTV预订业务基本介绍
一个完整的KTV预订流程如上图所示:
- 用户从商户列表中找到目标KTV;
- 进入商户详情页后,在详情页中选择欢唱的时间段、包型,进入套餐选择页;
- 用户选择到店时间和套餐内容;
- 进入支付页面进行支付;
- 告知用户预订结果。
对于用户来说,预订流程中需要决策的内容非常多,如:商户、时间、包型、套餐等;我们在产品设计时,对用户的决策流程进行了简化,用户在三页之内就可以选择完所有的内容。简单流畅的购买流程、较少的决策环节,对提升用户的购买体验非常有帮助,举个例子:曾经在刚与美团合并时,我们没法直接修改美团的商户详情页,就通过在商户详情页中增加一个链接链到价目表页面上;随着融合的深入我们对美团的商户详情页进行改版,将价目表嵌入到商户详情页后,美团侧的成交量在一天内增加了50%以上。
在简单的流程背后,是KTV业务部成立一年以来对业务的多次探索。一年左右的时间,KTV预订业务经历了四轮比较大的迭代:
1.在KTV预订业务开发之初,KTV预订是通过商家自助录单+IVR(声讯电话)通知商家接单的方式进行,每当有新用户下单时,都向商家拨打一个IVR电话播报到店时间、需要的包型、用户的手机号等信息,然后由商家决定是否接待。这种方式商家有最大的*度可以决定是否接单,但对于用户来说从支付成功到预订成功(或失败)的时间间隔会比较长,用户体验并不是很好。
2. 第二个阶段我们尝试引入了库存模式:商家事先预留一部分库存给点评平台售卖,当用户下单的时候,如果库存尚未售卖完成,则直接扣减库存并告知商家;然后将IVR通知商家的方式作为库存模式的降级:当库存售光的时候再采用之前的IVR接单方式让商家决定是否接单。在这个阶段,我们也对商家接单的途径进行了扩充,除了IVR之外,增加了商户后台通知和点评管家通知能通知方式,并让用户自行决定采用哪种方式通知。
3. 第三个阶段对售卖方式进行了扩充:增加了按人数售卖的方式(主要针对华南部分城市KTV+自助餐捆绑销售的场景)、增加了时间段包段模式;
4. 第四个阶段,我们承接了美团APP上的KTV预订业务,在展示侧,为商家提供了POI++等增值服务;在交易侧,进行了三方系统直连的探索和售中客服的介入,同时、引入了房态管理的概念,扩充了原有的KTV库存的概念。
KTV预订平台的整体流程与团购的流程比较类似,都包含上单、审核、展示、下单、批价、支付、消费、退款、结算等流程。区别于传统团购模式,在展示环节和下单环节,我们需要关注用户选择的日期、时段、包型、套餐等信息;从订单维度上看,KTV预订订单所包含的内容比传统的团购包含的内容会更丰富一些;另外,在支付成功之后,区别于传统团购直接扣减库存的方式,KTV预订会走一个完整的预订流程,才能决定商家是否接受该用户的订单。
目前,KTV预订平台服务的对象有销售、运营、用户、售中客服、商户等。KTV预订平台订单录入采用销售提报的形式发起,通过运营审核后,订单会被放到线上供用户购买;运营可以在KTV预订平台上进行预订方案审核、广告发布、活动和立减发布等;会员参与购买流程并支付;支付后如果商家拒绝或者超时未对订单做出响应,售中客服就回介入联系商家,挽回这些失败的订单;商户可以在平台上进行订单查询、验证、对账,发布自己的预订折扣、自促活动等,从而提高自己的曝光量。
KTV预订平台在设计和开发时,以微服务的形式进行系统组织,主要分为 各种service组成的服务层 和 web接口/界面组成的展示层。
在服务层:针对KTV预订平台的流程,有admin-service(审核、运营) product-service(展示) order-service(下单) checkout-service(预订) verify-service(消费) refund-service(退款)等;这些服务在运行时又依赖于更底层的服务,如 promo-service(优惠)、stock-service(房态、预订库存)、gateway-service(预订三方对接)、notify-service(预订商家通知)、In-Sale-Service(预订售中客服)等。
在展示层:我们分别向用户、商户、运营、售中客服等提供对应的展示界面。展示侧在开发的时候,各个web端只提供前端调用的jsonp接口,采用动静分离的形式完成界面与逻辑的解耦以及接口的复用,举例来说:订单查询、验证的jsonp接口,可以同时为PC上的商户后台和手机上的点评管家提供数据源。
KTV预订展示侧的抽象
在接下来的介绍开始前,首先简单介绍下KTV预订的房态模型。房态模型会影响展示侧的展示方式、是否可以生成新订单、订单下单成功后如何走预订流程。
既然是预订业务,在预订前就需要确定某个事情发生的时间、地点。对于KTV预订,时间维度即为 几月几日几点几分到店、几点几分离店;地点维度即为选择什么样的包型。基于此,就抽象出了KTV预订的房态模型:
某一天、某个时间段、某个包型可能会有三种状态:有房可售卖、需要商家接单确认、满房状态。房态的转换,发生在KTV预订平台发生预订行为后或者商家、售中平台对库存进行修改时。
对于库存类的订单,当有一个预订成功发生后,库存扣减1,当库存扣光后,某个特定时间段的某个包型就切换到接单状态(之所以这样做是因为商户只会给我们留较少的保底库存,还会有线下未售光的包房);接单状态有订单发起预订,并且商家不接单的总数超过某个值后,这个时段的包型就切换到了满房状态,将不会再有新的预订订单进入到这个时段的包型。
商家和售中客服可以调整具体某一天某个包型的房态。商家可以从有房状态切换为满房状态、也可以在满房状态和接单中状态直接互相切换。
不难发现,KTV预订的房态是周期性生成的,所以在房态模型存储时,会划分为房态规则表和每日房态表两张表。当各个调用方调用每日房态表查询某个特定时段的房态时,如果此时段的房态尚未生成,则会从房态规则表中复制一份数据到每日房态表。
预订产品的SKU粒度比传统的团购产品要复杂的多,这一点是在设计预订系统时候的一项挑战。
在KTV预订场景下,一个SKU需要细化到某一天、某一个包型在某一个时间段的某个套餐。我们在数据落地时设计了Product、 Product-Item、Product-Item-Attribute三张表用来存储数据。其中 Product表用来给所有的Item分组,Item与Item-Attr是对多的关系,Attribute表用于补充Item表中的属性。这样设计的存储结构在系统需求扩展的时候比较灵活:如我们在KTV预订系统研发之初,是没有套餐模式售卖的,当后来加入套餐售卖模式后,在不改变表结构的情况下,只需要在Attr表里面增加一种新的属性,即可对新业务进行支持。
当KTV预订的内容展示在用户的界面上时,又是另外一种样式:分为价目表页面展示 和 套餐选择页展示。其中价目表页面只关注周x,某个时段,某种包型的最低价格;用户选择包型后,进入套餐选择页,关注点则落在了套餐类型上(详见第三页的流程2,3),为了简化逻辑,我们在将存储层的数据转换为表现层的数据时,我们抽象出了一个 ItemGroup的概念:将同一个周次、同一个时段、同一个包型的不同套餐归为一个ItemGroup,ItemGroup用于价目表的展示;ItemGroup里面的内容用于套餐选择页展示。
在实际上单的阶段,一个ItemGroup下的所有套餐,共享一个库存单元。
KTV订单模型的演变
接下来介绍下KTV预订订单模型的演变。KTV预订业务的订单模型,大体分为四个阶段。在演变过程中,数据结构越来越复杂,进行订单状态修改、订单状态查询时候涉及到的子系统、查询接口等也慢慢细化。下面对四个阶段的演变分别作出说明。
在KTV预订产品开发之初,KTV业务模型还不清晰,为了完成快速线上验证,我们将订单可能出现的所有状态全部杂糅到一个字段上,导致订单状态既包含预订流程的状态、也杂合了支付流程、消费流程、退款流程等多个流程的状态。
这种状态存在一个很大的问题就是没法进行状态回溯和流程梳理,打个比方,如果一个订单经历了这样一个流程:支付成功(1)->预订失败(3)->系统自动发起退款(4)->退款成功(5);那么它的流程和:支付成功(1)->预订成功(2)->用户自己发起退款(4)->退款成功(5)这条路径的终态一致,单从数据库中的订单终态,没法区分这两个订单在预订流程上的区别。
第二个阶段为业务扩展阶段。在这个阶段,系统需要快速地支持新的业务需求,如预订流程不再是简单的IVR声讯电话通知商家接单的模式、还加入了库存模式,在有库存的情况下需要先扣减库存,当没有库存的时候才需要用多种方式通知到商家由商家决定是否接单。为了支持这些业务,并且利于业务流程的回溯,在开发进度的压力下,我们对订单表进行了扩充,增加了ReserveStatus、VerifyStatus、RefundStatus等字段,从而最业务流程也做了部分支持。
这次订单模型演变快速解决了业务扩张的问题。如后来当我们引入了系统直连、售中挽回等多种预订模型时,单凭借ReserveStatus已经不足以支持各个预订模式的业务切换需求了。于是我们开始尝试将不同的业务数据存放在它们自己的数据表中,于是便有了第三个阶段。
第三个阶段时候,KTV预订的订单量已经达到了一定的规模,预订、退款等流程在进一步扩充,将杂糅在订单表中的数据拆分到各个服务下面,不同的服务根据自身的实际场景进行数据组织。为了简化订单服务,订单状态只保留了订单声明周期中的关键节点如支付成功、预订成功、消费成功等节点;由于退款会发生在订生命周期的各个阶段,在订单表中也冗余了一份退款结果的数据,从而方便订单服务的各种查询场景。
这个阶段的架构能够基本支持KTV预订业务,订单表的查询压力也分担到了各个系统。如结算过程进行结算时依赖消费记录表和退款记录表,无需再直接从订单表上查询数据。
为了进一步提高订单服务的稳定性,我们又尝试将订单服务拆分为订单创建、更新服务 和 订单查询服务,通过读写分离保证系统的可靠性,防止因为大量的查询拥堵导致订单创建、更新流程受到影响;也防止查询服务挂掉或者创建服务挂掉保证订单的所有逻辑都不可用。
在实际应用场景中,各个调用方不止关注订单的状态,还会去关注订单状态变化过程中都产生了哪些流程上的变化,如在预订成功时,调用方会关注是三方直连预订成功的还是扣减库存预订成功的等;在消费成功后,业务方会关注是谁在什么平台上发起的消费。要拼装出诸如“预订成功,已消费,消费后由客服发起退款,并退款成功” 这样一个订单状态描述,除了依赖订单表中的数据外、还需要消费数据、退款数据等数据的支持。
KTV预订面向的调用方有用户、商户、运营、售中、售后等很多个,在综合查询订单流程和订单状态时,每个调用方都需要理解订单状态、预订流程、消费流程、退款流程等业务流程,这就导致了很多功能的重复解释和重复开发,代价太大。于是我们在原有的所有服务基础上,增加了一个综合查询服务:综合查询服务用于应对不同调用方的查询需求,并隔离调用方和复杂的业务逻辑。
目前KTV的订单模型正处于第三和第四阶段的中间阶段,正在逐步完善综合查询服务。对于近期的业务,第四个阶段的订单模型已经可以满足KTV预订业务的订单查询需求了。
KTV预订流程的演变
下面对KTV预订流程的演变做简单的说明
在KTV预订的业务模型演进过程中,预订流程做过一次比较大的重构。
KTV1.0探索阶段,当订单支付成功后、直接使用IVR通知商家,由商家决定接单还是拒绝、或者商家超时无应答放弃订单。此时的预订流程非常简单,在一个checkout服务中就可以搞定。
KTV2.0阶段为了缩短订单预订成功的时间、并且尽量减少对商家的打扰,我们引入了库存模式:当有库存时,首先消耗库存订单,这种订单无需商家接单,在用户支付成功后很短的时间内即可完成预订。与此同时,商家接单模式下通知商家的渠道除了原有的IVR电话外,增加了商户后台和点评管家等渠道,这时候我们将商家通知的流程从checkout服务中拆分出来,作为notify服务,负责使用各种渠道对商家进行通知,并提供给商家通知方式配置的功能。
这两个阶段相对来说,项目的结构都比较简单,但当三方系统直连和售中客服渠道接入后,checkout服务中的简单逻辑判断就不符合要求了。
在近期的一次迭代过程中,增加了三方系统直连预订模式和售中客服挽回订单模式。
三方系统直连指的是直接与第三方KTV商户的ERP对接库存,当有新的预订请求发起时,直接向第三方平台发起扣减库存请求,并将预订人、预订时间等相关信息一并发送到第三方平台。这种对接方式应该是最方便的KTV预订方式,但受KTV行业系统研发能力所限,只有一部分KTV能采取此种方式进行预订,所以KTV2.0阶段的库存方案和通知接单方案仍将继续存留。
售中客服挽回订单指的是通知商户接单商户拒绝或者超时未接单的情况下,售中客服主动联系商家咨询其拒绝或者错过订单的原因,并最大程度地挽回订单。售中客服介入的预订渠道在酒店预订、旅游产品预订等场景中已经有了一些比较成熟的应用,KTV预订业务引入售中客服这个流程,事实证明对提高商户的接单量也具有很大的促进作用。
在加入三方直连和售中客服模式后,预订流程就变得更加复杂了(如上图):订单支付成功后,首先判断是三方直连的订单还是传统库存模式的订单:如果是三方直连的订单,会直接向第三方平台发起预订,第三方平台会告知预订成功或失败,有一种异常情况是当第三方平台异常时,三方直连模式将会降级为商家接单模式;库存模式在有库存的情况下直接扣减库存、在没有库存的情况下通知商家接单;当商家拒单或者超时未接单的时候,会将订单流入到售中客服的订单池中,由售中客服联系商家看是否能够挽回订单。这样看起来,比KTV2.0时代的预订流程复杂了许多。
为了简化模型,我们对库存模式下走库存流程还是接单流程进行了抽象,将通知商户接单的模式当做是库存扣减模式的一种服务降级(如上图所示),这样调整后,模型得到了一定的简化:每一种预订模式可以有他的一种降级预订模式、当当前预订模式有明确的预订结果时,预订流程结束、当没有确定的预订结果时,切换到其对应的降级模式重新发起预订。因为每一种模式都只有一个后继的降级模式,所以checkout的流程就比较好抽象了。
抽象后的预订流程checkout模块执行流程如上图所示:当订单支付成功向预订平台发起预订时,预订平台根据参数判定当前使用的预订渠道、判断完成后向对应渠道发起异步预订流程并在checkout表中记录流程执行状态;当特定的渠道返回预订结果后,对预订结果进行判定:如果预订结果为预订成功 或 预订失败的终态时,预订流程结束;当预订结果不为终态时,则去查询当前渠道的降级渠道,查询到降级渠道后,向降级渠道再次发起预订。
此次抽象后,KTV预订流程被拆分成了5个服务:checkout服务(用来协调责任链上的执行流程)、gateway(用来与三方系统进行直连)、stock(用来管理房态)、notify(用来采用各种渠道通知商家接单)、In-Sale(用来进行售中客服接单)。每个服务的权责比较清晰,耦合度也比较低:如当需要增加一种新的三方直连方案时,只需要在gateway服务中做出扩展;当需要扩充一种新的商家通知方式只需要在notify服务中进行相关开发即可;当有新的预订方式增加时,在checkout的调用责任链中再增加一个新的环节即可。整个系统的扩展性非常良好。
以上是我对KTV业务部一年的业务发展过程中我们经历过的一些业务上的变化和重构的理解。自己在互联网行业的经验还不够丰富,对业务演进的总结和理解还有一些不全面的地方,希望大家可以批评指正。
本文来自中生代技术群 freshmanTechnology
本文分享者简介:
由文超,2014年毕业于江南大学。毕业后在联想集团MBG做手机传感器驱动的研发,15年转行互联网加入点评,现就职于新美大KTV业务部。