这套网店系统之所以存在,是因为一个靠聊天记录卖货的本地商家迟早会漏掉一单。取代聊天记录的东西刻意毫不花哨:带搜索和分类筛选的商品目录、在点击之前就显示库存的商品页、绝不含糊属于哪家店的购物车,以及一张走过五个命名状态、每次流转都发通知的订单。
商品页:规格、库存和折扣,都在点击之前
每件商品有照片、描述、库存,以及可以打折的价格——促销价旁边是划掉的原价和一个百分比角标,让折扣的幅度是读得出来的,而不是暗示出来的。商品缺货时,那句话画在照片上,而不是等到结账才被发现。这遵循整个应用共同的一条规则:任何会改变一次点击后果的信息,必须在点击之前可见。按钮绝不能承诺下一屏会拒绝的事。
规格由属性生成,而不是一条条录入。卖家声明轴——尺码、颜色,或这件商品实际在变化的那个维度——组合出来的每个规格各自持有库存。这样就把常见的坏数据挡在外面:同一件衬衫被分别录成三个商品,永远无法合在一起统计,而库存只有其中一个是对的。
一个购物车只属于一家店
购物车是单店的。从另一家卖家添加商品会先询问是否清空,而不是悄悄堆出一个横跨四家商户的篮子。这是一次设计上的拒绝,不是缺失的功能:多店购物车意味着一次结账、一次运费计算和一个出问题时负责的对象,而当卖家是四家各有各配送安排的独立本地商户时,这三样都不存在。
一车一店,是故意的。切换店铺会询问是否清空购物车。横跨多个卖家的篮子要想诚实,就需要一次统一结账,而这里没有全平台的结账——每一单都发生在一位买家和一家商户之间。
运费不是应用传上来的字段。下单时,服务器从店铺自己的记录里读取,而且只对配送生效。
结账:配送或自取,以及一笔客户端定不了的运费
结账只问一张订单真正需要的东西:配送还是自取、姓名、电话、地址、备注和支付方式。选自取会完全移除运费,而不是显示为零,因为这两种状态含义不同,而“零”读起来像 bug。地址来自带默认项的地址簿,所以第二单不必重打第一单的地址——而且只有一份地址簿,与个人资料共用,因为资料地址和收货地址是同一个事实,存两份就注定两份迟早对不上。
运费本身在服务端。place_shop_order 从数据库读取 businesses.delivery_fee,忽略客户端提交的任何值,正如堂食路径自己给每一行定价一样。一个被信任的客户端字段就是一张自助折扣券;金额归服务器管。这不是一条能在设置里关掉的策略——它就是这个数字的来源。
五个订单状态、运单号,两侧都收到通知
订单流转经过待处理、已确认、打包中、已发货和已送达,另有已取消与已拒绝两个终止分支。买家看到的是进度条而不是孤零零的状态词,所以“打包中”读起来是序列里的一个位置,后面还有东西。运单号在发货这一步附上,同时还要选一家承运商——名单由管理端维护,每家都带一个追踪网址模板,所以商家填进去的号码会变成买家能点开的链接。商家不能只填运单号而不指明承运商,因为一个不知道属于谁的号码永远变不成链接。
两种结束都要给理由:顾客取消要说明原因,店家拒绝也要说明原因,而理由随订单保存,不会像聊天里的一句话那样滚走。每次流转两侧都收到通知——一个没有通知的下单流程,会让店家漏单、买家干等。
- 待处理 — 已下单,等店家
- 已确认 — 已接受,店家做出了承诺
- 打包中 — 正在准备
- 已发货 — 已寄出,附有运单号
- 已送达 — 已完结,买家因此获得评价资格
卖家这一侧:门店 POS、线上订单和库存
零售商家拿到三块控制台磁贴:面对面销售的收银台、承接应用内订单的线上订单台,以及带低库存预警的商品与库存。仪表盘的实时角标每隔几秒刷新,所以新订单会自己出声,而不是等着被发现。店里卖和线上卖写进同一本流水。
正因为两条渠道落在同一处,报表覆盖的是整间店而不是线上那一片:营业额、订单数、客单价、现金/PromptPay/其他的构成、销量前五、七日营业额柱状图,以及今天/七天/三十天/全部四个周期。收据可以补打,也能生成可分享的收据文本;开不了税务发票——只有增值税登记人才能开具,而系统里还没有记录任何一家店的登记信息。客户名单同样由这本流水生成,附带逐客户的备注与标签、购买历史,以及按店家自设汇率(以店家自己的货币计)累积的积分,对应可配置的最低消费额与奖励。
员工访问由带角色预设和按人覆盖的权限矩阵管理,所以可以只给店员商品和订单,而不给工资表和报表。同一套矩阵在数据库里以 has_capability(business_id, capability) 存在,为行级安全策略在服务端展开预设——服务器从不听信客户端关于某人是什么角色的说法。
商品评价只有真的买过的人才能写
商品评价与商家评价是分开的,但门槛一样:只有平台能证明发生过交易的顾客才能写。资格是一个数据库视图,而“买过”是其中一种合格类型,与堂食、外送、住宿和使用服务并列。其余的人看到的是一张说明为什么没有写入按钮的锁定卡片,而不是一个点了会失败的按钮。
星级不是谁能编辑的存储数字:数据库触发器从评价记录重算,所以店铺卡片上的评分和页面上的评价不会各说各话。买家可以编辑或删除自己最新的一条,回购时新增一条而旧的一条保留;店家可以公开回复。
顾客把买到的设备登记进资产台账之后,理赔会回到卖出它的那家店——也就是你这一侧。