AI 写完订单后台,退货按钮点两次会怎样:Go + MySQL 幂等检查
AI 或代码生成器把订单、商品、库存页面做出来只能说明 CRUD 有了。退货按钮点两次库存会不会回滚两次退款回调晚到订单状态会不会倒退运营拿旧 token 直接打接口能不能绕过页面按钮。这些才是进销存后台上线前最该先验的地方。这篇不讲完整进销存系统怎么从零搭。我只拆一个很窄的动作退货。因为它同时碰到状态机、库存流水、幂等键、RBAC 权限和审计日志。页面看起来再完整如果这几个点没有验后面补起来很难受。退货不是一个 update很多后台初版会把退货写成这样UPDATE order_item SET refund_status refunded WHERE id 1001; UPDATE product_stock SET available_qty available_qty 2 WHERE sku_id 2001;这段 SQL 看着没问题实际少了几层判断订单是不是当前租户的订单是否已经发货、已退货或已取消同一个退货请求是不是重放过库存流水有没有唯一业务单号谁发起退货、走的是哪个权限码后面做导出、对账、补偿任务时能不能查回完整链路。AI 很容易根据表名生成“退货接口”但它不知道你的业务里退货能不能撤销、部分退货怎么算、支付退款和库存释放谁先谁后。这里不能靠页面验收要靠数据约束和接口重放验收。表结构先把幂等和租户写进去我会先把退货请求和库存流水分开。订单状态是一件事库存动作是另一件事。库存流水表里必须有业务动作、业务单号、租户和幂等键。CREATE TABLE inventory_flow ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id BIGINT NOT NULL, sku_id BIGINT NOT NULL, order_id BIGINT NOT NULL, action VARCHAR(32) NOT NULL COMMENT sale/refund/reversal/adjust, qty INT NOT NULL, idempotency_key VARCHAR(96) NOT NULL, operator_id BIGINT NOT NULL, remark VARCHAR(255) DEFAULT , created_at DATETIME NOT NULL, UNIQUE KEY uk_tenant_idem (tenant_id, idempotency_key), KEY idx_tenant_sku_time (tenant_id, sku_id, created_at), KEY idx_order_action (tenant_id, order_id, action) );uk_tenant_idem是兜底不是装饰。接口层可以先查 Redis 或幂等表但数据库唯一键必须在最后拦住重复插入。否则网关重试、前端连点、定时补偿任务重复跑都可能把库存加两遍。订单明细也要带状态条件不要只按 id 更新UPDATE order_item SET refund_status refunded, updated_at NOW() WHERE tenant_id ? AND id ? AND refund_status none AND pay_status paid;这条 SQL 的返回行数很重要。影响 1 行才说明状态从none变到了refunded。影响 0 行不一定是数据库异常也可能是重复退货、跨租户、订单状态不允许退。接口要把这些分开记录不能统一回“操作失败”。Go 接口里先验权限再验状态退货接口的顺序不要写反。先验证登录和权限再拿租户上下文再进入业务事务。否则你会在日志里看到一堆状态错误却漏掉真正的问题没有退货权限的人已经打到了业务层。func RefundOrder(ctx context.Context, req RefundReq) error { user : auth.UserFromCtx(ctx) if user nil { return ErrUnauthorized } if !rbac.HasPermission(ctx, user.ID, inventory:refund) { return ErrForbidden } tenantID : user.TenantID idemKey : fmt.Sprintf(refund:%d:%d:%s, tenantID, req.OrderID, req.RequestNo) return dao.Transaction(ctx, func(ctx context.Context) error { item, err : dao.OrderItem. Ctx(ctx). Where(tenant_id, tenantID). Where(order_id, req.OrderID). Where(refund_status, none). ForUpdate(). One() if err ! nil { return err } if item.IsEmpty() { return ErrRefundState } _, err dao.InventoryFlow.Ctx(ctx).Insert(g.Map{ tenant_id: tenantID, sku_id: req.SkuID, order_id: req.OrderID, action: refund, qty: req.Qty, idempotency_key: idemKey, operator_id: user.ID, created_at: gtime.Now(), }) if isDuplicateKey(err) { return ErrDuplicateRefund } if err ! nil { return err } _, err dao.ProductStock.Ctx(ctx). Where(tenant_id, tenantID). Where(sku_id, req.SkuID). Increment(available_qty, req.Qty) if err ! nil { return err } _, err dao.OrderItem.Ctx(ctx). Where(tenant_id, tenantID). Where(order_id, req.OrderID). Where(refund_status, none). Data(g.Map{refund_status: refunded, updated_at: gtime.Now()}). Update() return err }) }这里的重点不是把代码照搬到项目里而是顺序权限、租户、状态锁、流水唯一键、库存释放、订单状态更新。少任何一个退货按钮都可能在正常测试里过关在重复请求或跨租户场景里翻车。用两次 curl 重放不要只看 200最小验收可以很土。拿同一个请求打两次看第二次是不是被幂等逻辑挡住。curl -i -X POST https://api.example.com/admin/inventory/refund \ -H Authorization: Bearer admin-token \ -H Content-Type: application/json \ -d { order_id: 10001, sku_id: 20001, qty: 2, request_no: refund-10001-001 } curl -i -X POST https://api.example.com/admin/inventory/refund \ -H Authorization: Bearer admin-token \ -H Content-Type: application/json \ -d { order_id: 10001, sku_id: 20001, qty: 2, request_no: refund-10001-001 }我希望看到的结果类似这样HTTP/1.1 200 OK {code:0,message:ok,flow_id:88123} HTTP/1.1 409 Conflict {code:40901,message:duplicate refund request}再查库存和流水SELECT available_qty FROM product_stock WHERE tenant_id 10 AND sku_id 20001; SELECT action, qty, idempotency_key, COUNT(*) AS cnt FROM inventory_flow WHERE tenant_id 10 AND order_id 10001 GROUP BY action, qty, idempotency_key;第二条查询里cnt应该是 1。库存只释放一次。这个检查比“页面提示退货成功”更可靠。跨租户和低权限账号要单独测进销存后台很容易把“能不能看到菜单”和“能不能打接口”混在一起。前端隐藏退货按钮只能减少误点不能当权限边界。接口层必须独立拦截。# 没登录 curl -i -X POST https://api.example.com/admin/inventory/refund # 期望401 # 登录了但没有退货权限 curl -i -X POST https://api.example.com/admin/inventory/refund \ -H Authorization: Bearer viewer-token # 期望403 # A 租户 token 操作 B 租户订单 curl -i -X POST https://api.example.com/admin/inventory/refund \ -H Authorization: Bearer tenant-a-token \ -H Content-Type: application/json \ -d {order_id:90001,sku_id:20001,qty:1,request_no:x-1} # 期望404 或 403但不能改到 B 租户库存后台权限最好拆到动作级。inventory:view、inventory:export、inventory:refund、inventory:reversal不能全塞进一个“库存管理”权限里。退货和冲销都在改库存但风险不同审批、日志和授权也应该不同。审计日志要能回答“谁把库存放回去了”退货出问题时运营不会只问“接口成功了吗”。他们会问哪个人、哪个租户、哪张订单、释放了哪个 SKU、是不是重复请求、当时的权限码是什么。日志至少要这样记录{ event: inventory.refund, tenant_id: 10, operator_id: 501, permission: inventory:refund, order_id: 10001, sku_id: 20001, qty: 2, idempotency_key: refund:10:10001:refund-10001-001, result: success, flow_id: 88123, request_id: req-20260730-0001 }失败也要记尤其是duplicate、forbidden、state_not_allowed。这些日志会决定后面能不能查账。如果只记“按钮点击成功”排查时基本等于没有日志。代码生成器适合生成骨架不适合替你决定业务状态我在看 XYGo Admin 的代码生成器时更愿意把它当后台骨架样本页面、权限和字段同步能先立起来但像退货幂等、库存释放和租户隔离这种业务动作生成后还要补验收。可以对照它的server/internal/logic/gencodes/generate.go、server/internal/logic/gencodes/sync_fields.go和server/internal/middleware/admin_permission.go看生成器、字段同步和接口权限分别落在哪一层。源码入口放这里方便对照路径GitHub 仓库。这里要说清楚边界它不是现成进销存 SaaS也不会替某个行业直接决定退货、冲销、支付退款和云打印规则。这个判断也能和仓库里的 Issue #9 对上用户问的是 SaaS、多租户、库销存、支付配置和云打印机需求真正难点就在业务动作和边界不是多生成几张表。适合参考的是后台底座怎么组织 RBAC、CRUD 生成器和字段同步业务动作还要按自己的订单状态和库存模型补。上线前我会保留这张检查表检查项期望结果常见坏味道重复退货请求第二次返回 duplicate库存不变两次都 200库存加两次低权限账号返回 403前端没按钮但接口能打跨租户订单查不到或 403只按 order_id 更新状态回退已退货不能再退只改 refund_status没有状态条件库存流水同一 idempotency_key 只有一条只有库存余额没有流水审计日志有 tenant、operator、permission、request_id只记“操作成功”导出对账可按订单和 SKU 查回流水导出只查余额表如果一个 AI 生成的后台连这张表都过不了我不会急着补页面细节。页面错了通常还能改库存和退货链路错了后面就是对账、退款和客服一起补锅。结尾留个问题你们验收进销存后台时会先看页面流程还是先用重复请求把库存接口打一遍

相关新闻

RGD-PEG-Mal 线肽 RGD - 聚乙二醇马来酰亚胺 靶向偶联试剂特性介绍

RGD-PEG-Mal 线肽 RGD - 聚乙二醇马来酰亚胺 靶向偶联试剂特性介绍

多链长规格可选 RGD-PEG-MAL 靶向巯基专用偶联试剂,分子结构整合线性 RGD 靶向三肽、柔性 PEG 亲水间隔链与末端 MAL 马来酰亚胺巯基特异性活性基团;该试剂适用于体外巯基修饰多肽、巯基荧光染料、巯基磷脂的定点靶向改性研究,依托巯基特异性…

2026/9/14 19:47:52 阅读更多 →
揭秘claude-powerline工作原理:核心组件与代码实现分析

揭秘claude-powerline工作原理:核心组件与代码实现分析

揭秘claude-powerline工作原理:核心组件与代码实现分析 【免费下载链接】claude-powerline Beautiful vim-style powerline for Claude Code 项目地址: https://gitcode.com/gh_mirrors/cl/claude-powerline claude-powerline是一款为Claude Code打造的vim风…

2026/9/21 1:16:52 阅读更多 →
react-native-biometrics性能优化:提升生物识别响应速度的5个技巧

react-native-biometrics性能优化:提升生物识别响应速度的5个技巧

react-native-biometrics性能优化:提升生物识别响应速度的5个技巧 【免费下载链接】react-native-biometrics React Native module for iOS and Android biometrics 项目地址: https://gitcode.com/gh_mirrors/re/react-native-biometrics react-native-biom…

2026/9/21 21:15:59 阅读更多 →

最新新闻

5个视频在线压缩方案图解原理与选型避坑

5个视频在线压缩方案图解原理与选型避坑

5个视频在线压缩方案图解原理与选型避坑 昨天帮一个做跨境电商的朋友排查故障,他发来的代码是从某技术论坛复制的“视频在线压缩”片段,本地跑报错,服务器部署直接502超时。这种 复制来的代码跑不通不知道怎么调…

2026/9/22 2:08:09 阅读更多 →
雷柏机械键盘源码揭秘:性能优化实战与面试避坑指南

雷柏机械键盘源码揭秘:性能优化实战与面试避坑指南

雷柏机械键盘源码揭秘:性能优化实战与面试避坑指南 面试时被问“机械键盘的触发原理与驱动优化”,你答得上来吗?很多后端或嵌入式开发者,平时只关注业务逻辑,对底层硬件交互一知半解。一旦面试官深挖 性能优化…

2026/9/22 2:08:09 阅读更多 →
心经讲解避坑指南:新手必读的3个致命错误与修复方案

心经讲解避坑指南:新手必读的3个致命错误与修复方案

心经讲解避坑指南:新手必读的3个致命错误与修复方案 复制来的代码跑不通,报错信息像天书一样看不懂,这是很多刚接触“心经讲解”相关项目或数据处理的开发者最头疼的事。别急,这种问题往往不是你的逻辑错了,而是环境配置或依赖库版本出了岔子。这份避坑…

2026/9/22 2:08:09 阅读更多 →
新浪图床从入门到精通:5步打通前端资源托管底层逻辑

新浪图床从入门到精通:5步打通前端资源托管底层逻辑

新浪图床从入门到精通:5步打通前端资源托管底层逻辑 学会语法却不知怎么搭项目,这是很多转行前端或后端开发的伙伴最头疼的事。你背熟了 HTTP 协议,写得了复杂的正则,但一遇到图片上传、CDN…

2026/9/22 2:08:09 阅读更多 →
搞定微信地区自定义,告别环境卡壳,3步实现性能优化

搞定微信地区自定义,告别环境卡壳,3步实现性能优化

搞定微信地区自定义,告别环境卡壳,3步实现性能优化 配置环境就卡半天,是不是你的常态?别慌,这真不是你的错。很多后端开发者在接入【微信地区自定义】时,往往死磕在SDK依赖冲突和API调用延迟上,不仅浪费了大量调试时间,更导致接口响应慢,直接…

2026/9/22 2:08:09 阅读更多 →
3个核心模块搞定录屏软件手机版,面试必问的底层逻辑

3个核心模块搞定录屏软件手机版,面试必问的底层逻辑

3个核心模块搞定录屏软件手机版,面试必问的底层逻辑 官方文档里全是晦涩的 API 定义和回调机制,读完脑子还是空的,根本抓不住重点。 别慌,今天不讲虚的,直接拆解一个能跑的 录屏软件手机版 核心实现。 这不仅是项目实战,更是 面试必问…

2026/9/22 2:07:09 阅读更多 →

日新闻

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天 配置环境就卡半天?别怪机器慢,多半是你没选对工具链。在Java、Go或Python的项目现场, 手写实现…

2026/9/22 0:00:41 阅读更多 →
剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑 面试被问原理答不上来,是不是常态?别慌。很多开发者对着 GitHub 开源仓库里的代码发呆,看似简单实则暗藏玄机。今天这份【剑帝加点】速查手册,直接带你拆解核心实现,把面试必考的原理讲透。…

2026/9/22 0:00:41 阅读更多 →
手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优 复制来的代码跑不通不知道怎么调?别慌,这种“复制粘贴地狱”在开发圈太常见了。尤其是做 图片压缩网站…

2026/9/22 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →