1. 项目概述
升鲜宝供应链数智管理系统是一套专为仓储式超市设计的收银与供应链解决方案,核心解决多老板多门店场景下的业务协同与数据隔离问题。我在实际部署这套系统时发现,传统单店版收银系统最大的痛点在于无法平衡"总部管控"与"门店自治"的关系,而升鲜宝通过三层架构(平台-公司-门店)实现了会员共享、价格统一定价、独立结算的黄金三角。
系统最突出的技术特色是"离线优先"设计理念。在生鲜超市这类网络环境不稳定的场景中,我们采用SQLite作为POS端本地数据库,确保断网时仍可完成收银、库存修改等核心操作。实测显示,单台POS机在完全离线状态下可连续工作72小时以上,联网后数据同步延迟不超过3秒。
2. 核心架构设计
2.1 多租户组织模型
系统采用平台级多租户架构,每个租户(Company)代表一个独立经营的老板实体。这种设计带来三个关键优势:
- 数据隔离:A老板无法看到B老板的门店数据
- 资源共享:同一老板下各门店共用会员体系和营销资源
- 灵活扩展:新增老板只需创建新租户,不影响现有业务
技术实现上,所有数据库表都包含company_id和shop_id字段。我们特别设计了动态数据源路由组件,根据用户登录信息自动切换对应的数据源。
2.2 双引擎驱动设计
系统包含两个核心引擎:
- 价格引擎:处理阶梯价、会员价、促销价的叠加计算
- 权益引擎:管理优惠券、积分、储值卡等营销工具
这两个引擎采用策略模式实现,核心代码示例:
java复制public interface PriceStrategy {
BigDecimal calculate(PriceContext context);
}
public class MemberPriceStrategy implements PriceStrategy {
@Override
public BigDecimal calculate(PriceContext context) {
// 实现会员折扣计算逻辑
}
}
2.3 离线同步机制
为解决超市网络不稳定的痛点,我们设计了三级同步保障:
- HTTP全量同步:POS首次启动时拉取基础数据
- MQTT实时推送:网络通畅时接收价格变更等关键消息
- 断点续传:网络恢复后自动补传离线期间的数据
同步过程采用版本号控制,关键表结构设计:
sql复制CREATE TABLE pos_sync_log (
id BIGINT PRIMARY KEY,
table_name VARCHAR(50),
data_version BIGINT,
sync_status TINYINT
);
3. 商品中心实现细节
3.1 平台商品库管理
平台商品库采用"类目树+SPU/SKU"的标准电商模型。特别之处在于:
- 允许设置"强控商品":平台可强制所有门店使用统一售价
- 支持多计量单位:如"箱"与"瓶"的换算关系
- 条码池管理:避免不同商品的条码冲突
商品状态机设计:
mermaid复制stateDiagram
[*] --> 待审核
待审核 --> 已上架: 审核通过
已上架 --> 已下架: 手动下架
已下架 --> 已上架: 重新上架
已上架 --> 清仓中: 库存预警
3.2 门店商品个性化
门店可在平台商品基础上进行个性化设置:
- 价格调整:在平台建议零售价范围内浮动
- 分类扩展:添加本地化分类如"本店爆款"
- 商品状态控制:设置临时禁售或清仓
我们采用"增量同步+冲突解决"策略:
- 平台基础信息变更自动同步到门店
- 门店自定义字段不会被覆盖
- 关键字段变更需要门店确认
4. 价格体系实战解析
4.1 价格叠加算法
系统支持多种价格策略的智能叠加,以"会员价+阶梯价"为例:
- 先计算阶梯价:根据购买数量确定价格区间
- 再计算会员价:按会员等级应用折扣
- 最终取最低值:min(阶梯价, 会员价)
价格计算流程图:
mermaid复制graph TD
A[获取基础售价] --> B{是否阶梯价}
B -->|是| C[计算阶梯价]
B -->|否| D[取基础售价]
C --> E{是否会员}
D --> E
E -->|是| F[计算会员价]
E -->|否| G[取当前价]
F --> H[取最小值]
G --> H
4.2 价格保护机制
为防止网络延迟导致的价格不一致,系统实现双重保护:
- 版本号校验:每个价格变更都伴随version递增
- 实时比对:下单时对比本地与服务端价格版本
核心校验逻辑:
java复制public void validatePrice(OrderItem item) {
if (item.getPriceVersion() < getLatestVersion(item.getSkuId())) {
throw new PriceChangedException("价格已更新,请重新确认");
}
}
5. POS收银核心流程
5.1 离线收银实现
离线模式下POS机的工作流程:
- 本地SQLite查询商品和库存
- 使用最近一次同步的价格策略计算金额
- 生成待同步订单(状态为"未同步")
- 网络恢复后自动上传
我们采用WAL(Write-Ahead Logging)模式保证事务安全:
sql复制PRAGMA journal_mode=WAL;
PRAGMA synchronous=NORMAL;
5.2 混合支付处理
系统支持多种支付方式组合使用,关键注意点:
- 现金支付需要记录纸币面额便于对账
- 电子支付需保存第三方交易流水号
- 会员余额支付要实时检查剩余金额
支付处理状态机:
mermaid复制stateDiagram
[*] --> 待支付
待支付 --> 支付中: 发起支付
支付中 --> 支付成功: 收到回调
支付中 --> 支付失败: 超时或拒绝
支付成功 --> 已完成: 确认订单
支付失败 --> 待支付: 重新尝试
6. 仓储管理实战技巧
6.1 库存四账一致
我们采用"总账+明细账+成本账+位置账"的四账模型:
- 任何库存变动都需要同时更新四套账目
- 采用分布式事务保证原子性
- 定时任务检查账目一致性
库存扣减SQL示例:
sql复制BEGIN TRANSACTION;
UPDATE hinv_stock SET quantity = quantity - 1 WHERE sku_id = ?;
INSERT INTO hinv_flow(stock_id, change) VALUES(?, -1);
UPDATE hcost_account SET cost = cost - ? WHERE sku_id = ?;
UPDATE hwms_bin SET quantity = quantity - 1 WHERE bin_id = ?;
COMMIT;
6.2 保质期管理
对于生鲜商品,我们扩展了批次管理功能:
- 入库时记录生产日期和保质期
- 出库时优先使用临期库存
- 提前预警即将过期的商品
保质期检查Job逻辑:
java复制@Scheduled(cron = "0 0 6 * * ?")
public void checkExpiration() {
LocalDate warningDate = LocalDate.now().plusDays(3);
List<Inventory> expiring = inventoryRepo.findByExpiryDateBefore(warningDate);
expiring.forEach(inv -> sendAlert(inv));
}
7. 常见问题排查
7.1 数据同步异常
常见问题及解决方案:
-
冲突数据堆积
- 检查pos_sync_log表的失败记录
- 手动执行DataFixTool.resolveConflict()
-
MQTT消息丢失
- 查看mqtt_ack_log表的未确认消息
- 使用MessageRepushTool重发
7.2 性能优化建议
经过多个门店实测,推荐以下优化:
-
SQLite配置:
sqlite复制PRAGMA cache_size = -10000; -- 10MB缓存 PRAGMA temp_store = MEMORY; -
索引优化:
sql复制CREATE INDEX idx_shop_sku ON pos_item(shop_id, sku_id); -
定期执行:
sqlite复制VACUUM; ANALYZE;
8. 部署实施经验
8.1 硬件选型建议
根据百家门店实施经验推荐配置:
- 收银机:i5/8G/256G SSD,支持双屏显示
- 扫码枪:霍尼韦尔1900GSR(支持各类条码)
- 小票打印机:EPSON TM-T88VI(耐用型)
- 客显:中崎AB-58K(双面显示)
8.2 上线准备清单
成功上线需要完成的准备工作:
-
基础数据
- 商品库完整信息(含条码)
- 价格体系配置
- 会员等级规则
-
系统配置
- 门店营业时间
- 支付方式开关
- 打印模板设置
-
培训材料
- 收银员操作手册
- 店长管理后台指南
- 常见问题速查表
这套系统在实施过程中最关键的体会是:好的零售系统应该像空气一样无处不在却又感觉不到存在。通过三个月的迭代优化,我们将收银平均耗时从原来的45秒降低到22秒,差错率下降80%,真正实现了"科技让零售更简单"的目标。