19 Commits

Author SHA1 Message Date
wangjia e19c498dba fix(backend): 历史导入出库明细价格错列——售价误落成本列,新增修复工具
Design Source Checks / design-source (push) Successful in 39s
根因:旧系统出库明细「单价/金额」是售价口径(应收侧),import-history 误落
cost_price/cost_amount,sale_price 留 0(整单显示待定价);单头 sale_total
却按售价口径正确落库,明细与单头矛盾。实证:ZXZ027628 出库"成本"14300=售价,
真实进价 13600 在库存/入库侧。

- import-history:出库明细「单价/金额」改落 sale_price/sale_amount(成本留 0 待回查)
- 新增 cmd/fix-history-prices 一次性修复线上数据:售价归位 + 按商品编号
  回查真实进价(①入库明细 ②库存快照 ③商品进价)+ profit_total 同口径重算;
  sale_total 不动(应收不变);默认 dry-run,--apply 落库,幂等可重跑
- 测试:四种成本来源/dry-run 回滚/幂等/非占位明细不波及/利润应收口径

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 16:55:03 +08:00
wangjia 4fd0bb8b83 feat(backend): 出入库定价字段消歧 + 总利润落库 + 成本仅管理员可见
- 字段重命名(旧列弃用保留,启动幂等回填 BackfillPricingColumns):
  入库 unit_price/total_price/total_amount → cost_price/cost_amount/cost_total;
  出库同前缀 + 新增 sale_amount(售价小计)/ sale_total(应收)/ profit_total(总利润)
- 建单落三值;确认售价联动重算 sale_amount/sale_total/profit_total;
  确认进价回填成本后联动重算受影响出库单利润(recalcStockOutProfit)
- 出库 List/Get 对 operator/readonly 抹零成本与利润(stripStockOutCost 服务端兜底)
- 兼容一版:Create/Update 接受旧 key unit_price 回落(v1.0.87 及之前客户端)
- SUM 聚合/价格趋势/导入/种子工具同步切新列;测试全量改名 + 6 个新回归

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
2026-07-03 12:44:22 +08:00
wangjia ca7595b113 feat(backend): 出入库汇总近30天滚动窗口 + 跨租户安全加固
- summaryBounds:本月/近30天滚动双口径(stock-in/out Summary ?window=rolling30)
- security(SEC-001):新增 ownership.go ensureShopRef 写入侧防线(stock-in/out/finance/
  盘点建单的 warehouse/partner/product 外键归属校验);读取侧全部 Preload 补
  shop_id 作用域,finance Summary JOIN 补租户条件;回归测试 CrossTenantRefs
- security(SEC-002):release 模式 JWT 密钥为空/默认值时拒绝启动
- gofmt 对齐若干 model/cmd 文件

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
2026-07-03 09:57:52 +08:00
wangjia 3641f1cf16 chore: release server-v1.0.75
Deploy Server / release-deploy-server (push) Successful in 1m7s
出库售价(应收按售价) + 库存选择器分页上限修复 + seed 改为序列号模型

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-22 13:01:25 +08:00
wangjia 6faadf8670 fix(backend): 库存导入按商品编号匹配不再按名称合并 + 新增 fix-inventory-products 修复工具
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-21 21:24:53 +08:00
wangjia 90d2c8668b feat(backend): 历史进销存导入器 cmd/import-history + 单据明细快照列
一次性 CLI 导入旧系统 data/ 入库·出库 总表/详情表到当前库,历史只读(绝不
回放 inventories/inventory_logs)。明细忠实直存不做 SKU 归一:order/item 表
新增 creator_id(制单人)与 product_code/product_name/series/spec 快照列
(出库另补 batch_no/production_date),导入行 product_id 指向共享占位商品。
order_no 天然主键 (shop_id,order_no) 幂等去重,可重复跑。

testutil sqlite DDL 同步补列以保持 service 测试通过。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 07:05:08 +08:00
wangjia 23dff69c62 feat(backend): 授权改为时长兑换券体系 + 退役 ed25519/HMAC + 平台生码工具
- 新增 license_codes 码池表 + model.LicenseCode;licenses 加 tier 档位列
- LicenseService.Redeem:单事务 FOR UPDATE 校验码未用 → 时长叠加(可叠加,0=永久)
  → 写 type/tier/max_devices → 绑设备(超限整笔回滚) → 标记已用 → 即时失效 phase 缓存
  路由仍 POST /license/activate,客户端零破坏
- util.GenerateRedeemCode/NormalizeCode:JIUKU-XXXX-XXXX 短码(crypto/rand)
- cmd/gencode:平台批量生成兑换码并落库;删除 cmd/issue、cmd/genkey
- 退役 ed25519 + HMAC:删 util/license_key、GenerateKey、License 全部 config 字段
  及生产启动私钥校验;trial 改直接建行(无需私钥、去 Fatal)
- tier 档位钩子默认 standard,分档消费模式后续设计
- 测试:Redeem 全场景(叠加/过期重置/永久/一码一次/无效/设备上限回滚)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 12:14:27 +08:00
wangjia eca62ba2c3 fix(backend): 库存导入改用 shakinm/xlsReader,按唯一编号去重,入库日期取自 Excel
extrame/xls 误读真实 .xls(3264 行只读出 455 行、编号丢失、数字被当
日期序列),换用 shakinm/xlsReader 正确读取全部行。去重改为「有商品编号
时仅按编号匹配」,避免不同批次被 NSS 回退合并;Inventory.ProductCode
存行自身唯一编号。入库时间取 Excel 入库日期列写入 created_at。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 08:04:04 +08:00
wangjia 36564571fa chore: 补提测试修复、新增测试工具和设计文档
- fix(test): 同步 listInventory 签名(补 series/spec 参数)
- test(backend): 新增 import_parse_test.go
- chore(backend): 新增 cmd/test_xls 调试工具
- docs: UI 筛选组件设计规范、Gemini 项目配置

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 11:17:35 +08:00
wangjia e0bee00ff4 fix: 批量改进 (#2/#23/#38/#39/#40/#47)
- Web: 隐藏 ICP 备案号(条件渲染),联系入口改为微信咨询(条件渲染,配置 wechat 字段后生效)
- backend: 拼音回填抽取为独立 cmd/backfill-pinyin 工具,不再在启动时运行
- backend: DB 连接池参数(max_idle_conns/max_open_conns)改为配置可控,默认 10/100
- backend: Inventory 反范式字段添加注释说明快照语义
- backend: 全量 handler 采用 util.RespondSuccess/RespondCreated 统一响应格式(51 处)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 09:33:43 +08:00
wangjia 47b3c89460 feat(web): 新增更新日志、服务条款、隐私政策页面;关于页更新日志链接修正
- web/dist/changelog/ 版本历史页,收录 v1.0.0–v1.0.29 全部发版记录
- web/dist/terms/ 服务条款页(付费/授权/数据/免责等)
- web/dist/privacy/ 隐私政策页(数据收集/使用/共享/用户权利等)
- 全站页脚补充 更新日志、服务条款、隐私政策三个链接
- about_screen 「更新日志」按钮链接由 /downloads/ 改为 /changelog/
- 新增 backend/cmd/issue 工具,用于签发指定门店的授权码 token

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 22:56:22 +08:00
wangjia 40a80467ce feat(backend): Ed25519 license signing utilities (21A)
- util/license_key.go: LicensePayload struct, GenerateEd25519KeyPair,
  IssueLicenseToken (sign), VerifyLicenseToken (verify offline)
- cmd/genkey: one-shot keypair generator with demo sign+verify
- config: add Ed25519PublicKey field (LICENSE_ED25519_PUBLIC_KEY env)

Token format: base64url(header).base64url(payload).base64url(ed25519-sig)
Private key stored in Bitwarden; public key embedded in config/client.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 00:28:55 +08:00
wangjia 86baaf3a1c fix(model): users 唯一索引改为 (shop_id, username) 复合索引
Deploy / deploy (push) Successful in 1m13s
原来 uniqueIndex:uk_shop_username 只在 Username 字段上,导致用户名全局唯一。
S002/S003 的 admin 用户与 S001 冲突,INSERT 被静默跳过,无法登录。

将 User 的 TenantBase 改为直接定义 ShopID,使其参与复合唯一索引。
需要 Reset DB 使新索引生效。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 14:50:34 +08:00
wangjia c1ed81dfab feat: 财务结清、酒行信息、库存备注编辑、标签溯源、入库必填校验
后端
- 新增 shop handler:GET/PUT /shop/info(管理员权限)
- 新增 finance CloseByRef:按单据 ref_type+ref_id 结清账款
- 新增 inventory UpdateRemark:PUT /inventory/:id/remark
- 入库/出库审批自动生成财务应付/应收记录(去除金额>0限制)
- 种子数据 S001-S003 补充真实门店信息

前端
- 设置页新增「酒行信息」Tab,管理员可编辑门店名称/地址/电话/负责人
- 入库单列表新增结清按钮(含确认弹窗),出库单同步
- 入库表单:规格、系列、生产日期、供应商、商品名称改为提交必填
- 入库/出库列表新增入库时间、出库时间、创建时间列
- 商品标签标题改为读取 shop 表门店名,扫码文案改为「扫码溯源 · TRACE」
- 标签页脚显示门店地址和电话(从 API 读取,不再依赖编译时 dart-define)
- 库存备注支持点击编辑,超4字截断显示+Hover展示全文
- ApiClient 新增 patch() 方法(已改用 PUT 规避 CORS)

文档
- 新增 docs/user-manual.md 完整用户操作手册(12章)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 14:05:41 +08:00
wangjia 655c1d366e feat: 公开商品页重设计 + web 上传修复 + 二维码配置
- 公开商品页(/product/:uuid)全面重设计:全宽正方形图片轮播、
  左右滑动切图、点击放大全屏查看、商品参数含描述、页脚贴底
- 修复 Flutter web 文件上传无反应(path→bytes)
- 修复 web 路由空白页(usePathUrlStrategy + 单层 MaterialApp.router)
- 二维码 URL 改为从 STORAGE_PUBLIC_URL 环境变量读取
- 新增 PUBLIC_URL dart-define → AppConfig.publicBaseUrl
- 新增 CI/CD workflows + NAS runner compose 配置
- seed S001 补充商品描述字段

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 00:31:11 +08:00
wangjia 14e285e756 feat(db): H001 改名 S001,新增 S002(空库存版)
S001: 含完整入库/出库/库存历史数据
S002: 基础数据相同(商品/供应商/仓库),入库/出库/库存均为空,模拟新门店

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 23:43:21 +08:00
wangjia 902c3c3046 feat(db): 补全测试种子数据所有字段
入库单补全供应商/仓库,出库单补全客户/仓库,商品补全价格/条码/规格,
往来单位补全地址/银行账户/信用额度,财务记录关联已审核出库单。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 22:43:00 +08:00
wangjia 754275cbd6 fix(backend): 修复日期字段解析失败导致创建单据报错
新增 model.Date 类型,支持前端传入的纯日期格式 YYYY-MM-DD:
- UnmarshalJSON 优先解析 YYYY-MM-DD,回退支持 RFC3339
- MarshalJSON 输出 YYYY-MM-DD
- Value/Scan 实现 GORM MySQL DATE 列读写
- StockInOrder/StockOutOrder/InventoryCheck 的 OrderDate/CheckDate 改用 Date 类型

feat(client): SelectionArea 全局开启文字可选中复制

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 22:29:15 +08:00
wangjia 31ea370cea fix(backend): JWT config mapstructure tag 修复 + 模型从 hotel 重构为 shop
- 修复 JWTConfig 缺少 mapstructure tag 导致 access_expire_min 解析为 0,
  token 签发即过期,所有 API 请求返回 401
- 全部 config struct 补齐 mapstructure tag(secret/dsn/hmac_secret 等)
- 模型层从 hotel/HotelID 统一重命名为 shop/ShopID
- 删除旧 migrations(001-004),新增 001_init 综合迁移文件
- 更新 schema.sql、testutil、handler/service/model 相关引用

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 22:20:12 +08:00