Korat
功能

网店系统——柜台上卖,也送到家

一套店家自己就能配好的网店系统:一个有真实规格和诚实库存的商品页,一个分得清配送与自取的结账流程,以及一张在每一步都告诉买卖双方它走到哪里的订单。收银和网店共用一份库存,免费,没有月费。

这套网店系统之所以存在,是因为一个靠聊天记录卖货的本地商家迟早会漏掉一单。取代聊天记录的东西刻意毫不花哨:带搜索和分类筛选的商品目录、在点击之前就显示库存的商品页、绝不含糊属于哪家店的购物车,以及一张走过五个命名状态、每次流转都发通知的订单。

商品页:规格、库存和折扣,都在点击之前

每件商品有照片、描述、库存,以及可以打折的价格——促销价旁边是划掉的原价和一个百分比角标,让折扣的幅度是读得出来的,而不是暗示出来的。商品缺货时,那句话画在照片上,而不是等到结账才被发现。这遵循整个应用共同的一条规则:任何会改变一次点击后果的信息,必须在点击之前可见。按钮绝不能承诺下一屏会拒绝的事。

规格由属性生成,而不是一条条录入。卖家声明轴——尺码、颜色,或这件商品实际在变化的那个维度——组合出来的每个规格各自持有库存。这样就把常见的坏数据挡在外面:同一件衬衫被分别录成三个商品,永远无法合在一起统计,而库存只有其中一个是对的。

一个购物车只属于一家店

购物车是单店的。从另一家卖家添加商品会先询问是否清空,而不是悄悄堆出一个横跨四家商户的篮子。这是一次设计上的拒绝,不是缺失的功能:多店购物车意味着一次结账、一次运费计算和一个出问题时负责的对象,而当卖家是四家各有各配送安排的独立本地商户时,这三样都不存在。

一车一店,是故意的。切换店铺会询问是否清空购物车。横跨多个卖家的篮子要想诚实,就需要一次统一结账,而这里没有全平台的结账——每一单都发生在一位买家和一家商户之间。

运费不是应用传上来的字段。下单时,服务器从店铺自己的记录里读取,而且只对配送生效。

结账:配送或自取,以及一笔客户端定不了的运费

结账只问一张订单真正需要的东西:配送还是自取、姓名、电话、地址、备注和支付方式。选自取会完全移除运费,而不是显示为零,因为这两种状态含义不同,而“零”读起来像 bug。地址来自带默认项的地址簿,所以第二单不必重打第一单的地址——而且只有一份地址簿,与个人资料共用,因为资料地址和收货地址是同一个事实,存两份就注定两份迟早对不上。

运费本身在服务端。place_shop_order 从数据库读取 businesses.delivery_fee,忽略客户端提交的任何值,正如堂食路径自己给每一行定价一样。一个被信任的客户端字段就是一张自助折扣券;金额归服务器管。这不是一条能在设置里关掉的策略——它就是这个数字的来源。

五个订单状态、运单号,两侧都收到通知

订单流转经过待处理、已确认、打包中、已发货和已送达,另有已取消与已拒绝两个终止分支。买家看到的是进度条而不是孤零零的状态词,所以“打包中”读起来是序列里的一个位置,后面还有东西。运单号在发货这一步附上,同时还要选一家承运商——名单由管理端维护,每家都带一个追踪网址模板,所以商家填进去的号码会变成买家能点开的链接。商家不能只填运单号而不指明承运商,因为一个不知道属于谁的号码永远变不成链接。

两种结束都要给理由:顾客取消要说明原因,店家拒绝也要说明原因,而理由随订单保存,不会像聊天里的一句话那样滚走。每次流转两侧都收到通知——一个没有通知的下单流程,会让店家漏单、买家干等。

  • 待处理 — 已下单,等店家
  • 已确认 — 已接受,店家做出了承诺
  • 打包中 — 正在准备
  • 已发货 — 已寄出,附有运单号
  • 已送达 — 已完结,买家因此获得评价资格

卖家这一侧:门店 POS、线上订单和库存

零售商家拿到三块控制台磁贴:面对面销售的收银台、承接应用内订单的线上订单台,以及带低库存预警的商品与库存。仪表盘的实时角标每隔几秒刷新,所以新订单会自己出声,而不是等着被发现。店里卖和线上卖写进同一本流水。

正因为两条渠道落在同一处,报表覆盖的是整间店而不是线上那一片:营业额、订单数、客单价、现金/PromptPay/其他的构成、销量前五、七日营业额柱状图,以及今天/七天/三十天/全部四个周期。收据可以补打,也能生成可分享的收据文本;开不了税务发票——只有增值税登记人才能开具,而系统里还没有记录任何一家店的登记信息。客户名单同样由这本流水生成,附带逐客户的备注与标签、购买历史,以及按店家自设汇率(以店家自己的货币计)累积的积分,对应可配置的最低消费额与奖励。

员工访问由带角色预设和按人覆盖的权限矩阵管理,所以可以只给店员商品和订单,而不给工资表和报表。同一套矩阵在数据库里以 has_capability(business_id, capability) 存在,为行级安全策略在服务端展开预设——服务器从不听信客户端关于某人是什么角色的说法。

商品评价只有真的买过的人才能写

商品评价与商家评价是分开的,但门槛一样:只有平台能证明发生过交易的顾客才能写。资格是一个数据库视图,而“买过”是其中一种合格类型,与堂食、外送、住宿和使用服务并列。其余的人看到的是一张说明为什么没有写入按钮的锁定卡片,而不是一个点了会失败的按钮。

星级不是谁能编辑的存储数字:数据库触发器从评价记录重算,所以店铺卡片上的评分和页面上的评价不会各说各话。买家可以编辑或删除自己最新的一条,回购时新增一条而旧的一条保留;店家可以公开回复。

顾客把买到的设备登记进资产台账之后,理赔会回到卖出它的那家店——也就是你这一侧。

按天或按月出借而不是卖断的东西,走租赁;店里还有堂食的,点餐读的是同一份商品与库存。

常见问题

我能在一单里买两家店的东西吗?

不能。购物车一次只装一家店,切换时会询问是否清空。每一单都发生在你和一家商户之间,用那家商户自己的配送安排——这里没有合并的全平台结账。

运费是怎么算的?

由店家配置,下单时服务器从店铺记录里读取。应用传上来的运费不会被信任。自取订单是完全没有运费,而不是运费为零。

店家没法履行我的订单会怎样?

店家带着理由拒绝,你会收到通知。订单还在流程早期时,你也可以自己带着理由取消。两种结束都会把理由留在订单记录上。

任何人都能给我的商品写评价吗?

不能。评价资格是一个数据库视图,买过这件商品才有资格写它。没买过的人看到一张说明为什么缺少写入按钮的卡片,而星级平均分由触发器从真实记录重算。

面对面销售还需要另一套软件吗?

不需要。控制台自带收银台,面对面销售与线上订单写进同一本流水——所以营业额、畅销榜和客户名单覆盖的是整间店,而不是其中一条渠道。

上架一件商品,下一单

在控制台里创建一家零售商家,把生命周期的两半都亲自走一遍。