多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

超市收银系统设计说明书:表结构、促销规则与避坑指南

超市收银系统设计说明书:表结构、促销规则与避坑指南 简介一份面向计算机相关专业毕业设计使用的《超市收银系统设计说明书》文档类资源适合需要完成超市管理系统或收银系统课程设计、毕业论文撰写的学生参考。资源以docx文件形式呈现共1个文件压缩包约500KB内容涵盖从需求分析、数据流图、数据字典、实体联系图到系统概要设计、数据库逻辑结构设计、详细人机交互设计及软件测试等完整章节可作为毕业设计说明书撰写模板和格式范例。已有152人浏览学习文档结构清晰可直接对照目录查阅。其中对前台收银、后台进货与库存管理等模块的划分、数据库表设计以及C#与VS2013开发环境的选择均有具体论述能帮助读者快速理解超市收银系统的设计思路与文档规范减少从零撰写论文的时间成本。1. 超市收银系统设计说明书一张表结构决定收银台会不会排长队收银台卡顿、打折价算错、交接班对不平账这些事在超市里几乎每天发生多数门店把锅甩给硬件老旧或者网络差。做过收银系统的都明白根子往往在那一份没写清楚的设计说明书——商品怎么建档、折扣怎么叠加、退款走什么流程全要落在文字和表结构里。这份标题为“超市收银系统设计说明书.docx”的文档实际上是把进销存、收银、支付、对账、报表五个子系统用一份文档锁死让开发、店长、财务三方按同一套规则做事。适合准备自建收银系统的小型连锁、接管理系统外包的团队以及想把现有收银流程整理成可落地方案的产品和技术负责人。2. 从设计说明书拆出数据模型进销存与收银的耦合关系超市收银系统的数据模型决定了后面所有功能能不能长出来。很多团队拿到设计说明书先画页面原型这是反的。收银系统最值钱的部分是商品、库存、价格、流水这四类数据的关系页面只是数据的投影。2.1 商品主档、库存与价格三张表的字段边界与主键策略商品主档解决“卖的是什么”库存表解决“还有多少”价格表解决“现在卖多少钱”。三张表职责不同最容易犯的错是往商品主档里塞库存数量和当前售价。我一般会把商品主档做成这样CREATE TABLE product ( sku_id VARCHAR(32) PRIMARY KEY, -- 箱规维度SKU扫码枪直接命中 barcode VARCHAR(32) NOT NULL, -- 69开头的EAN-13条码 product_name VARCHAR(128) NOT NULL, spec VARCHAR(64), -- 规格如500ml/瓶 unit VARCHAR(8) NOT NULL, -- 销售单位瓶、包、袋 category_id INT NOT NULL, -- 分类决定报表汇总口径 status TINYINT NOT NULL DEFAULT 1 -- 1上架 0下架 );注意主键用sku_id而不是条码。原因是同一件商品可能有多套条码整箱码、单瓶码、促销码条码更适合做唯一索引而不是主键。扫码枪扫到条码后通过barcode查到唯一sku_id再走价格表取价。这样换包装、加促销码时不需要动商品主键。库存和价格要独立成表CREATE TABLE stock ( sku_id VARCHAR(32) NOT NULL, store_id INT NOT NULL, -- 连锁场景必须带门店维度 quantity INT NOT NULL DEFAULT 0, locked_qty INT NOT NULL DEFAULT 0, -- 挂单/预定占用的库存 PRIMARY KEY (store_id, sku_id) ); CREATE TABLE product_price ( sku_id VARCHAR(32) NOT NULL, price_type TINYINT NOT NULL, -- 1正常售价 2会员价 3促销价 price DECIMAL(10,2) NOT NULL, begin_time DATETIME NULL, end_time DATETIME NULL, PRIMARY KEY (sku_id, price_type) );库存表不存金额价格表不存数量。这样设计的好处是盘点只动stock调价只动product_price两边互不锁。如果按“一张商品表带库存带价格”来做每次改价都会触发库存行的更新并发高一点就会出现锁等待收银台表现就是扫码后转圈。关键参数计价用DECIMAL(10,2)不要用FLOAT。收银涉及金额累加和折扣分摊浮点数在“满100减20再9折”这种嵌套计算里会出现 0.01 的误差财务对账时极难定位。宁可所有金额字段都定义成DECIMAL换来的是一年下来对账不用靠“调账”找平。2.2 交易流水与支付流水为什么不能合成一张表把交易流水和支付流水合成一张表是收银系统早期最常见的败笔。看上去省了一次插入等到接微信支付、支付宝、现金三种支付方式后会发现一个订单可能拆成“部分现金 部分扫码”这时候一张表就怎么都塞不下了。正确做法是拆两级结构订单级交易头和支付级支付流水。CREATE TABLE sale_order ( order_id VARCHAR(32) PRIMARY KEY, -- 业务单号格式见下 store_id INT NOT NULL, cashier_id INT NOT NULL, order_time DATETIME NOT NULL, total_amount DECIMAL(10,2) NOT NULL, -- 商品原价合计 discount_amount DECIMAL(10,2) NOT NULL DEFAULT 0, payable_amount DECIMAL(10,2) NOT NULL, -- 应收 status TINYINT NOT NULL DEFAULT 1 -- 1已支付 2已退款 3挂单 ); CREATE TABLE payment_flow ( flow_id INT AUTO_INCREMENT PRIMARY KEY, order_id VARCHAR(32) NOT NULL, pay_type TINYINT NOT NULL, -- 1现金 2微信 3支付宝 4储值卡 pay_amount DECIMAL(10,2) NOT NULL, trade_no VARCHAR(64), -- 微信/支付宝的渠道流水号 paid_time DATETIME NOT NULL, refund_status TINYINT NOT NULL DEFAULT 0 -- 0无 1部分退 2全退 );订单号生成建议用门店编号(3位) 收银机编号(2位) 日期(YYYYMMDD) 流水号(4位)例如008-03-20250601-0012。这个格式的好处是从订单号直接看出哪家店、哪台机器、哪天、当天第几单排查问题时不需要翻数据库查门店名称。合表之后用一条 SQL 就能查“今天微信支付总金额”但如果未来要接入新的支付渠道比如数字人民币或者银行聚合支付合表就需要加字段加字段就会影响核心交易表的写入性能。分开之后支付渠道的扩展只是往payment_flow加一个pay_type枚举值不动订单主表。设计说明书里如果只有“交易记录”一张表一定要让作者拆开。2.3 用 SQL 描述“买二赠一”促销规则怎么落库“买二赠一”这类促销是收银系统里最让开发头疼的需求。它跟打折不一样打折是改单价买赠是加商品而且赠品的库存也要扣。我的做法是把促销规则抽成一张独立的规则表不在商品表上加“促销类型”字段因为一个商品可能同时挂在多套促销下CREATE TABLE promotion_rule ( rule_id INT PRIMARY KEY AUTO_INCREMENT, rule_name VARCHAR(64) NOT NULL, rule_type TINYINT NOT NULL, -- 1满减 2折扣 3买赠 4第N件优惠 condition_qty INT NOT NULL DEFAULT 1, -- 满X件 condition_amount DECIMAL(10,2) NULL, -- 满X元与qty二选一 benefit_qty INT NULL, -- 买赠赠送X件 benefit_discount DECIMAL(10,2) NULL, -- 折扣打X折8.0表示八折 max_discount DECIMAL(10,2) NULL, -- 满减封顶金额 begin_time DATETIME NOT NULL, end_time DATETIME NOT NULL, store_scope VARCHAR(100) NOT NULL DEFAULT * -- 适用门店*为全部 ); CREATE TABLE promotion_sku ( rule_id INT NOT NULL, sku_id VARCHAR(32) NOT NULL, PRIMARY KEY (rule_id, sku_id) );结算服务取规则时先按“当前时间落在begin_time和end_time之间”过滤再按门店范围过滤最后去promotion_sku查这个商品参与了哪些规则按优先级排出最终生效的那一条。这里有个经验买赠的赠品不要改库存单价而是在订单明细里插入一行数量为正、单价为 0 的商品并在这一行记录来源promotion_rule_id。这样后续盘点、毛利分析才能看出“赠送出去多少”如果直接改主商品单价财务算毛利时完全是糊涂账。2.4 数据字典必须在设计说明书里单独占一章设计说明书如果只有流程图和页面描述没有数据字典开发阶段一定会出现“这里加个字段”的失控蔓延。规范的做法是在文档里为每张核心表列字段清单字段名、类型、默认值、是否可空、枚举含义、备注。前面贴出的建表语句实际上就是数据字典的可执行版本。写文档的时候要约定枚举值的含义比如pay_type的 1 代表现金、2 代表微信、3 代表支付宝这个映射写进数据字典后前端、后端、对账脚本都用同一份定义。否则就会出现后端返回pay_type2前端弹窗显示“支付宝”的翻车现场。数据字典不要求在原型完成前就 100% 齐全但核心交易表必须在动手写第一行代码前定稿。3. 把说明书拆成模块与里程碑一份文档驱动整个收银项目的排期拿到“超市收银系统设计说明书”之后第一件事不是读需求而是拆模块。说明书通常按业务功能组织开发排期要按“数据依赖 验收闭环”组织两者不是一回事。3.1 从说明书目录反推系统边界我拿到一份设计说明书先翻目录确认有没有这些模块基础资料商品、供应商、门店、采购入库、库存管理、收银结算、支付对接、会员营销、报表统计、系统权限。这八个模块如果说明书里都有那它描述的是一个完整的小型连锁收银系统如果只有收银和商品那它更像一个单店 POS 的需求。系统边界定了之后模块拆分才能谈。我的拆分原则是每个模块都能独立演示一个业务闭环。比如“库存管理”至少要能演示采购入库、盘点调整、销售扣减三个动作“收银结算”至少要能演示扫商品、算折扣、混合支付、打印小票四个动作。不能出现“这些功能要等报表模块做完才能看效果”的说法。3.2 模块依赖顺序为什么商品主档先于收银收银先于支付模块开发顺序不要按说明书章节顺序来要按依赖关系排。第一批做基础资料和库存。没有商品主档收银台没法扫码没有库存表入库单无处可写。这一批的验收标准是能通过管理端新增商品、调整库存、查询库存流水。第二批做收银核心链路。收银台扫商品、算价格、生成订单、落交易流水。这一阶段不接真实支付用“模拟支付成功”来打通订单状态流转。很多人急着接微信支付结果订单状态还没设计好支付回调来了不知道往哪写这是本末倒置。第三批接支付与对账。真实支付接入后才有支付流水、退款、隔日对账这些事。支付回调要能自动匹配订单号匹配不上的进异常账池人工处理。第四批做报表和权限。这一步放在最后因为报表依赖前面的数据积累权限控制依赖角色和操作日志的定义。3.3 里程碑与验收标准每个阶段能演示什么用设计说明书作为项目合同的话每个里程碑都要有可勾选的验收清单。比如第二个里程碑“收银核心链路”的验收项至少包括扫码枪扫 EAN-13 条码能命中商品命中失败有提示音。同一商品连续扫 3 次订单明细合并成一行、数量累加为 3。商品单价取自product_price中当前时间有效的促销价不是商品主档里的字段。现金支付找零金额小数部分不超过两位。模拟支付成功后sale_order.status变更为已支付payment_flow生成一条记录。验收不通过就继续迭代不要带着半成品进入支付联调。很多项目拖期的原因就是前一个模块的欠账压在后面最后所有问题都在上线前爆发。4. 收银系统必调的 5 个业务参数价格、折扣与退换货的边界设计说明书写得再完整落到系统里也得有几百个业务参数。收银系统里最敏感的是下面这 5 类调错了直接体现为金额算错或对账不平。4.1 折扣叠加优先级满减、会员价、限时秒杀的正确执行顺序促销叠加是收银系统最大的“黑匣子”。不做约束的话满 100 减 20 的活动会和会员价、限时秒杀同时生效出现“5 折之后再满减结算金额为负”的极端结果。我的经验是把促销执行顺序做成可配置的优先级而不是写死在代码里。常见顺序是优先级促销类型说明1限时秒杀/直降直接改商品销售价不可与会员价叠加2会员价未命中秒杀时生效标记为会员专享3满减按订单金额阶梯扣减可与其他券叠加但设上限4折扣按商品行打折在满减之后计算5抹零最后一步处理不参与折扣计算每一项都要设置“是否可叠加”的开关。比如秒杀商品不允许参与满减这是行业里的硬规则必须在参数里强制不能依赖收银员现场判断。收银员在结账时看到的价格应该是系统算好的一口价而不是由她心算叠加结果。4.2 抹零与舍入分账对不上的元凶抹零看似简单实际坑很深。常见做法是“应付金额抹去分位”比如 10.56 元抹零为 10.50 元。但支付平台是按照实付金额结算的如果抹零在本地做支付渠道侧的钱和本地订单金额差 0.06 元日终对账就出现一笔“未知名目的长款”。我在设计说明书里的约定是抹零只允许作用于现金支付扫码支付不做抹零。因为现金交易不产生第三方对账单抹零的损失由门店承担属于营销成本扫码支付的每一分钱都要和渠道对账单对上抹零会让自动对账脚本罢工。如果一定要对扫码支付做抹零就把抹零金额单独记录到一张discount_detail表注明“抹零-现金”或“抹零-扫码”日终对账时把这笔金额排除掉并且每天汇总抹零总额给财务确认。4.3 退款、原路退回与冲正库存回滚的边界退款的难点不在退款动作本身而在库存回滚和支付原路退回的时序。设计说明书里必须写清楚整单退款时订单明细里每件商品库存在什么时间点加回去部分退款时退掉的商品数量和剩余商品数量怎么区分。我的做法是订单明细增加refunded_qty字段每次退款先把数量记上再异步回滚库存。先记退款再回滚库存避免回滚失败导致重复加库存。原路退回要区分支付渠道。现金支付的退款直接在收银台操作让收银员从钱箱退款并在系统里记录微信支付宝支付的退款要么调渠道 API 原路退回要么生成退款单让财务线下转账。设计说明书如果写的是“所有退款都原路退回”上线前一定要确认聚合支付服务商是否支持部分退款很多渠道部分退款有次数和时间限制不支持的话就要有线下处理兜底。4.4 挂单、锁单与离线收银收银台最容易被忽略的三个开关挂单功能在早市和高峰期特别重要。顾客买了一半发现忘带东西收银员点挂单下一单结完再恢复。挂单设计有几个细节挂单数量上限默认给 10 单多了收银界面会卡挂单订单要锁定已扫描商品的库存否则会被其他收银台卖完。离线收银是连锁超市必须有的能力断网时收银台变成独立模式商品价格从本地缓存读取订单写入本地队列支付只接受现金。网络恢复后本地订单上传到服务端服务端按order_id去重合并。设计说明书如果没写离线模式上线后门店一断网就变成手写小票财务晚上对账就会崩。4.5 价格审计日志谁在什么时间改了什么价调价权限是收银系统里最容易漏的审计点。门店店长能不能直接改商品售价如果能改价操作必须留痕。我在系统里做了一张price_change_log每次修改product_price都记录操作人、门店、商品、原价、新价、生效时间、操作终端 IP。财务月结时要能查到“上周三 14:05 谁把可口可乐从 3.5 改成了 2.9持续了多久”。这个日志表不需要在收银链路里查询只对管理端和审计导出可见但数据要实时写入不能攒批。没有审计日志的促销系统被员工利用改价漏洞刷单后财务连证据都拿不出来。5. 收银系统避坑指南并发、对账、数据迁移与硬件适配的翻车现场收银系统上线前后最容易翻车的不是业务逻辑而是并发数据一致性、对账偏差、老系统迁移和硬件兼容。这部分的问题多数是“现象明显根因埋在其他模块里”排查起来特别费劲。5.1 峰值并发扣库存乐观锁和事务锁怎么选现象门店促销日收银台同时提交订单后台库存扣减出现负数或者同一件商品被两台机器同时卖掉后付款的顾客只能退款。原因库存扣减用的是“先查库存再减库存”两步操作两个请求同时读到库存等于 1各自减 1结果变成 0 而不是 -1。解决扣库存 SQL 必须用原子的条件更新UPDATE stock SET quantity quantity - 1 WHERE store_id 8 AND sku_id 692000000001 AND quantity 1;quantity 1这个条件让数据库在更新时做并发检查如果影响行数为 0说明库存不足收银端拦截。这是乐观锁思路在库存场景的变体比在应用层加分布式锁简单得多。注意不要把locked_qty和quantity混在一个 UPDATE 里做多行计算先扣锁定再扣可用顺序写清楚否则高压下会出现锁定数量为负的脏数据。5.2 日结对账不平支付回调与本地流水的时间窗口现象每天 23:00 对账本地订单显示“已支付”渠道账单里查不到或者渠道账单里有一笔本地订单状态还是“待支付”。原因支付回调是异步的顾客扫码付完钱渠道的回调可能需要几秒才到达本地服务。如果对账脚本恰好在这个时间窗口里跑了两边数据就不一致。解决对账不要把“本地订单状态”当成唯一依据。正确做法是把payment_flow中的trade_no和渠道账单按天做全量比对本地有而渠道没有的单据标记为“待确认”隔 30 分钟再查一次渠道订单状态渠道有而本地没有的走“人工认领”流程先确认是否漏单。对账脚本只做标记不做自动改单改单必须人工确认后执行否则误把正在支付中的订单标记为失败就会引发客诉。5.3 老系统数据迁移编码混乱、重复单号与历史库存差异现象新系统上线第一天商品档案导入了他的编码库存也是按供应商给的 Excel 录入的。开业第三天盘点发现 300 个 SKU 数量和实际对不上。原因老系统和新系统的商品编码规则不一致。老系统用九位编码新系统用 SKU 条码双主键导入时只带了条码和历史库存没带历史成本价。加上老系统一年没做清点库存数本身就是错的。解决迁移时不要把历史库存当“期初数据”要先做一次实物盘点用盘点结果做期初。历史库存只用来做参考和对账看板。商品编码要建立对照表老编码、新 SKU、条码、名称、规格五列缺一不可。迁移完成后先跑一遍“无主商品”查询把所有条码在旧表中存在但新表里没有对应关系的数据找出来人工补全后再正式开放收银。5.4 硬件适配小票打印机、钱箱与扫码枪的兼容坑现象新收银台装好了小票打印机连不上或者钱箱打不开扫码枪扫条码经常多打一个回车导致收银界面跳单。原因小票打印机驱动用的指令集不兼容。超市收银最常用的是 ESC/POS 指令但不同品牌的实现有差异尤其是切纸和钱箱开闸指令GS V和ESC p两种指令不能混用。扫码枪默认开启了回车后缀收银台界面绑定的是 Enter 键触发结账于是扫完商品直接弹到支付页。解决统一采购支持 ESC/POS 的打印机小票打印走qpos58这类通用驱动不要每台设备单独写驱动适配。钱箱开闸用打印机的钱箱口通过 ESC/POS 指令控制别用 USB 继电器。扫码枪设置里把后缀从回车改成 Tab或者在收银台输入框绑定keydown事件拦掉物理回车。硬件测试清单里必须有“打印小票 100 张无卡纸”“钱箱连续开关 50 次”“扫码枪扫 300 个条码无重码”三条这比任何软件测试都更早暴露问题。6. 从说明书到上线检查表六个最容易漏的验收项设计说明书里最后往往有一章“其他要求”所有坑都藏在这里。我自用的收银系统上线检查表有六项每一项都是过去踩过坑换来的交接班日结。早班和晚班交接时收银员各自打印当班小计系统能按“收银员 班次”独立统计收款金额且现金差额能录入备注。没有这一项门店每天短款长款全是糊涂账。断网演练。拔掉网线收银台要能用缓存商品继续结账 2 小时网络恢复后自动上传订单不重复、不丢单。上不了这一条说明离线模块没做完。退款权限分级。收银员只能退当班当店订单店长能退本店近 30 天订单区域经理才可跨店退货。每一档权限要对应一次短信/应用内审批不然退款漏洞会被薅到关店。商品改价审计。查 24 小时内所有price_change_log确认每一笔调价都有授权记录。没有日志的商品等于没有改价功能。数据库备份恢复演练。至少做过一次从备份文件恢复到测试库的完整流程恢复后数据不能只恢复到凌晨而是恢复到最近一次“全量 增量”的合并点。从没演练过的备份方案等于没有备份。促销日历生效。把“6 月 1 日零点全场 9 折”配置好验证 23:59 的订单是原价、00:00 的订单是折扣价。促销时间边界差一分钟大促当天就是投诉热点。经验里最疼的一次是老系统的库存数据迁移生产环境已经切过去盘点才知道期初库存错了两百多件后台调账调了整整一周。这之后我的原则就一句话能用盘点结果做期初的绝不用 Excel 数据能先跑一轮全链路演练的绝不直接上生产。收银系统这种直接碰钱的项目设计说明书是起点但真正决定成败的是表结构、促销规则、对账逻辑和迁移边界。希望这份拆解和检查清单能帮到你少走几步我们当时绕远的路。本文还有配套的精品资源点击获取
返回列表