a2d3a2c43a
fix: 半成品列表字段权限过滤后补回 base_id,修复批号自增失效
...
- get_list 的 apply_strict_rbac 剥离 base_id,导致前端 checkHistoryAndSetMode 无法按物料匹配历史
- 过滤后补回 base_id,扫码/选物料联动时批号能按历史正确自增(如 000002 → 000003)
2026-09-01 16:08:27 +08:00
bee037f925
feat: MOM 扫码入库对接 Track 产品身份证自动填充
...
- 半成品/成品入库弹窗顶部新增'扫码入库'按钮,打开扫码面板(扫码枪/摄像头)
- 扫码 Track 身份证后自动填充物料信息与序列号,不再二次搜索
- 后端新增 track_query_service(httpx 调 Track lookup)、track-lookup 接口
- 入库成功后 notify_track 通知 Track 闭环
2026-09-01 13:52:56 +08:00
893e7250db
fix(api): update-stocktake-quantity 按 session_id 隔离更新,防止跨会话误改
...
后端 update_stocktake_quantity 原只按 stock_id+source_table 查草稿,
不同盘点会话会相互覆盖实盘数。后端增加 session_id 过滤,
前端 handleQuantityChange 配套传入当前会话ID,API 类型同步补全。
2026-08-31 16:00:20 +08:00
eb017d881c
perf(api): draft/list 与 stocktake/all-items 改为数据库级分页,消除 N+1
...
- /draft/list: 废弃 query.all() + 逐条查库存/material_base 的 N+1,
改为原生 SQL 连表(草稿 JOIN 三张库存表 + material_base)+ LIMIT/OFFSET 分页
- /stocktake/all-items: 废弃三表 .all() + item.base 懒加载 + 内存切片,
改为 UNION ALL + LEFT JOIN + LIMIT/OFFSET,COUNT 聚合求总数
2026-08-31 16:00:13 +08:00
6ba20fa3db
fix(stocktake): 修复盘库重复记录 — 去重条件去掉 user_id
...
根因: draft/add 用 (user_id, uuid, session_id) 匹配去重,
同一盘点单多个用户(手机/平板不同账号)操作同一物料时,
每个用户各建一条 → 重复记录。
修复:
- 去重改为 (session_id, uuid) 唯一,不按 user_id 隔离
- 已存在则更新数量并记录最后操作用户
- 清理现有重复数据(保留每组最小id)
- 新增唯一索引 uq_stocktake_draft_session_uuid 防未来再重复
数据库需执行:
DELETE FROM stocktake_draft a USING stocktake_draft b
WHERE a.session_id=b.session_id AND a.uuid=b.uuid AND a.id>b.id;
CREATE UNIQUE INDEX IF NOT EXISTS uq_stocktake_draft_session_uuid
ON stocktake_draft(session_id, uuid);
2026-08-31 15:18:47 +08:00
7a3ffd8ba5
feat(stocktake): 重复扫码提示并确认是否修改
...
问题: 同一个码扫两遍输入两个数,后端 draft/add 直接覆盖,无任何提示
可能误改已盘数量
改进:
- 后端 draft/list 支持 uuid 过滤,可精确查某物料是否已盘
- 扫码弹输入框前,先精确查询该物料是否已盘
- 已盘过 → 弹窗提示『当前实盘为 X,是否修改?』
确认后预填旧值供修改,取消则不改变
2026-08-31 15:13:52 +08:00
c6e8c887ec
perf(stocktake): 应盘清单分页 + 扫码置顶高亮
...
性能修复(解决打开费劲):
- get_all_stocktake_items 改为分页返回 {items(当前页), total, total_scanned}
不再三次 .all() 全量加载 + 内存排序
- 前端 fetchAllStockItems 分页拉取(每页200),stats 用后端返回的 total
不依赖全量数组长度
体验优化:
- 扫码成功后将物品置顶到当前表格第一行并浅绿高亮3秒
库管无需翻页找刚扫的物品,'嘀'一下确认数量即可继续
- 主表格行高亮样式 .just-scanned-row
2026-08-31 14:59:22 +08:00
7e281cf285
fix(stocktake): 盘库扫码改为精确匹配,修复漏匹配与性能问题
...
问题:
1. 准确性 bug: 前端用 getStockList({pageSize:10, keyword}) 模糊搜索 + find()
当 SKU 前缀相同、目标不在前10条时,误报'未找到该物料库存'
2. 性能: 每次扫码全表 ilike %x% 搜索 3 张表,不走索引
修复:
- 后端 get_stock_info 改为精确匹配(==)优先,未命中再回退模糊搜索
- 新增 GET /inbound/stock/scan 扫码精确匹配接口,返回唯一命中
- 前端 onScanSuccess/handleManualInput 改用 scanStockByBarcode
一次请求直接命中,不再依赖 pageSize:10 + find()
2026-08-31 14:49:24 +08:00
2ff0f92f94
fix(stocktake): 修复盘点报告导出 500 错误
...
- 导出盘点报告时第1126行使用了 func.sum()/func.coalesce()
但文件未导入 sqlalchemy 的 func
- 改为 db.func.sum()/db.func.coalesce(),与文件内其他用法一致
2026-08-28 15:53:03 +08:00
d80edc961c
fix: 三个模块 update endpoint 统一 Default Deny + 权限码全量对齐 sys_element
2026-07-20 14:26:22 +08:00
3dca2b9254
fix: buy.py update field_to_perm 库位权限码 inbound_buy:warehouse_location → inbound_buy:warehouse_loc,对齐 sys_element
2026-07-20 14:21:22 +08:00
9bcd02c742
fix: update_buy perm_code=None 导致 NoneType 崩溃 + validateUnique 编辑时排除自身改用 Number() 防类型不一致
2026-07-17 16:57:46 +08:00
1cc7d51e03
fix: semi/product submit 响应用 apply_strict_rbac 替代硬编码 resp.pop,成本字段纳入 RBAC 统一管控
2026-07-17 14:36:26 +08:00
61b60f7aa0
fix: 修复 semi/product 物料搜索空白 — search_base 移除错误地对 MaterialBase 数据使用 Stock 表映射过滤
2026-07-17 13:45:28 +08:00
3c0954598c
perf: 综合安全加固 — RBAC严格映射+异步邮件+字段权限白名单+前端对齐+导入模板
...
本次提交包含本会话所有修改的最终统一提交
## 权限系统重构
- permission_service.py: 添加入库/采购操作元素 + ensure_default_permissions
- field_permissions.py: 严格1-to-1 Default Deny 字段映射(StockBuy/Semi/Product/MaterialBase)
- decorators.py: _expand_operation_perms 双向粒度桥接 + prevent_double_submit
- deploy_production.sql: 修复 sys_element 别名码(qty_inbound→in_quantity)
## 采购模块
- purchase.py: 权限驱动可见性 + inbound_purchase独立权限 + 价格字段过滤
- purchase_service.py: 异步邮件 + 三阶段批量模糊匹配防N+1
- purchase/index.vue: canApprove严格操作权限 + upload重复修复
## 导出/入
- base_service.py: export_excel 流式写入防OOM + get_latest_specs 优化
- import_service.py + import_api.py: Excel批量导入(模板+预览+执行)
- ImportDialog.vue: 三步骤导入弹窗
## 异步邮件
- email_service.py: send_email_async (守护线程)
- inventory_task.py: send_email→send_email_async
## 前端对齐
- product/semi/buy.vue: 列对齐in_quantity/stock_quantity/available_quantity + localStorage缓存V2
- buyOdoo.vue: 排序修复 + 导入按钮 + 移除点击展开加载
- BomManage.vue: 懒加载分组 + 导入按钮
- list.vue: 导入按钮
- Selection.vue + borrow/apply: BOM匹配修复 + 导入按钮
- outbound/create.vue: 出库类型必选
- AppMain.vue: 移除transition白屏修复
- material_base.ts, outbound.ts, bom.ts, stock.ts: 新增API函数
2026-07-17 13:07:12 +08:00
2e903cff2c
perf: 规格连号助手优化 — 流式查询+宽松regex+Redis缓存
...
## base_service.py get_latest_specs
- .all()全量→with_entities().limit(10000) 防OOM
- regex放宽: 支持 LICA-3000/M3x12 等格式(旧版仅匹配OPT12046)
- 移除OPT硬编码→SUB_CATEGORY_PREFIXES可配置集合
- Redis缓存(1h): 首次查询后缓存,后续命中直接返回
## base.py 缓存失效
- 新增 _invalidate_specs_cache() 辅助函数
- create/update/delete 成功后清除缓存
2026-07-16 18:15:43 +08:00
8c10bb0903
feat: 盘点合并列表 — 服务端JOIN+DB分页,消除99999全量加载
...
## stock.py
- 新增 GET /draft/merged-list: UNION ALL三表+LEFT JOIN draft
数据库级 LIMIT/OFFSET 分页,不再加载全量到Python内存
- 参数: session_id, keyword, status_filter, page, pageSize
- 返回: list, total, total_scanned (已扫去重数)
## stock.ts
- 新增 getDraftMergedList() API函数
## stocktake/index.vue
- fetchInventoryList: 改用merged-list单次调用替代99999全量+find()
- resumeSession: limit 99999→1 先检查存在,再limit 500加载
2026-07-16 13:08:29 +08:00
c07f25b646
fix: Fail-Closed 字段级安全加固 — 堵住15+端点价格泄露
...
## stock.py
- _make_price_stripper(): 工厂函数,选单前缀自动剥离所有价格/成本字段
- _do_get_stock_list(permission_prefix): 每个item.to_dict()后剥离价格
- /all 端点: 非AI模式自动剥离价格字段
- /list 端点: permission_prefix='outbound_selection' 传递
## outbound.py
- /bom-match-stock: 返回前按stock_type剥离全部价格/成本字段
- /scan: result.pop('price', None)
## scrap.py
- /scan: result.pop('price', None)
- /records: 每条记录剥离 cost_at_scrap, total_loss
## transactions.py
- filter_item_by_permissions: 从空字典恢复完整20字段映射
- /borrow/stock-list: permission_prefix='op_borrow_apply' 传递
## buy.py / semi.py / product.py
- submit 成功响应剥离所有价格/成本字段(不泄露给前端)
## bom.py
- /base/list: 剥离 referencePrice
2026-07-16 11:26:05 +08:00
2556b77530
perf: 系统级性能优化与并发安全修复
...
## 并发安全修复 (4处)
- scrap.py: 报废执行添加 SELECT FOR UPDATE 悲观锁,消除 TOCTOU 竞态
- stock.py (adjust_stock): 盘点调整添加 for_update=True 行锁
- outbound_service.py: 低库存预警 SMTP 调用移到 commit 之后,避免长事务
- trans_service.py: execute_dispatch 按 (source_table, id) 排序 items,消除死锁风险
## N+1 查询优化 (2处)
- inventory_task.py: _prefetch_inventory_map 单条 UNION ALL+GROUP BY 替代循环内逐条查询(N*4次→2次)
- stock.py (export_stocktake): get_borrowed_qty 批量 GROUP BY 替代逐条 TransBorrow 查询(~18000次→1次)
## BOM 列表性能重构
- bom_service.py: get_bom_list 单条 GROUP BY+string_agg+分页,消除 N+1 循环查询
- bom_service.py: 新增 get_bom_summary (轻量 GROUP BY category+COUNT)
- bom.py: 新增 /api/v1/bom/summary 路由,/list 支持 category 过滤
## Odoo 基础信息懒加载
- base_service.py: 新增 get_odoo_summary (GROUP BY category+COUNT)
- base.py: 新增 /api/v1/inbound/base/odoo-summary 路由
- buyOdoo.vue: 懒加载分组架构 (fetchOdooSummary + loadGroupItems)
- material_base.ts: 新增 getOdooSummary API
## 前端 Bug 修复
- BomManage.vue: 懒加载分组 (fetchBomSummary + loadGroupItems + collapse)
- BomManage.vue: 适配新 API 格式 (res.data.items 替代 res.data)
- buyOdoo.vue: 移除 "点击展开加载" 文字
- Selection.vue + borrow/apply/index.vue: openBomSelect 适配新 API 格式
2026-07-15 17:37:57 +08:00
4b1a86a870
fix: 对齐field_to_perm与sys_element权限码 + 税率6% + 含税总价反算
...
- buy/semi/product: 数量字段映射对齐sys_element实际注册码(qty_inbound/qty_stock/qty_available)
- 数据库: 补全buy(9)+semi(10)+product(13)缺失权限码
- deploy_production.sql: 同步更新
- buy.vue: 税率新增6%选项, 价格联动以含税为主输入, 税率变化保持最后编辑价格不变
- buy.vue: 新增含税总价可输入反算功能
2026-07-15 15:03:37 +08:00
0651eb07fa
fix: 彻底解耦出库/借库权限联动 + 路由去硬编码roles + 补API权限保护
...
根因: 借库选单页面14处硬编码outbound_selection:operation, 导致两模块权限联动
修复:
- borrow/apply: 14处outbound_selection:operation→op_borrow_apply:operation
- stock.py: 拆分_do_get_stock_list裸逻辑, 出库/借库各绑独立权限码
- transactions: 新增/borrow/stock-list端点(@permission(op_borrow_apply))
- transaction.ts: 新增getBorrowStockList前端API函数
- outbound.py: 出库审批4端点改用独立outbound_approval权限码
- transactions.py: 借库审批3端点补@permission(op_borrow_approval)
- purchase.py: 采购管理7端点补@permission(inbound_buy)
- audit.py: 审计日志补@permission(system_audit)
- router: 清除全部6处硬编码roles, 交由动态权限树控制
2026-07-15 14:33:11 +08:00
e1417d740a
feat: 全模块公司隔离 + crossDomain权限码动态跨域控制
...
- get_current_company_filter: 新增_has_cross_domain_permission, 权限码替代硬编码
- 补全11个Service的get_current_company_filter调用(semi/product/service/outbound/bom/trans/scrap/summary)
- base/search修复: search_material此前无隔离, 已补全
- get_current_company_filter兜底: JWT缺company_name时返回__NO_COMPANY__防止放行
- permission.py: _get_operator_company补全返回值, 修复权限页保存逻辑
- 新增crossDomain迁移脚本, element_type=element挂system_mgmt下
2026-07-15 11:11:40 +08:00
8f468a0a39
fix: 修复全局字段权限导致数据显示为空的问题
...
根因: /permissions/role/<role_code> 接口要求 system_permission,
非管理员角色无法获取自身权限 → 权限数组为空 → 前后端字段全被过滤
修复:
- permission.py: 查自己角色不再需要 system_permission, 解除权限死锁
- 5个 inbound API: 恢复完整 field_to_perm 映射, 每个字段均可独立权限管控
- 补齐遗漏字段(qty_inbound/qty_stock/qty_available/request_id/request_no)
- buy.vue: 入库表单价格字段加入 hasFormFieldPermission 守卫
2026-07-14 16:09:41 +08:00
760f78e016
feat: 添加参考价格列 + 修复公司筛选跨域问题 + CLIP模型持久化
...
## 新增功能
- material_base 表新增 reference_price 列(NUMERIC(10,2))
- 基础信息 list.vue / buyOdoo.vue 页面增加「参考价格」列展示和编辑
- 新增 material_list:referencePrice 权限元素,支持按角色控制可见性
## Bug 修复
- 入库三页面(buy/product/semi)公司筛选:非超管用户 company=ALL 不再传给旧版后端
- 基础信息两页面(list/buyOdoo):buyOdoo 增加 v-if=isSuperAdmin 与 list.vue 行为统一
- company=ALL 默认值在各页面 getList/fetchData 中自动过滤,兼容旧版后端
## 运维优化
- docker-compose.prod.yml 增加 models_prod 卷挂载,CLIP模型持久化免重复上传
- deploy_code.sh 增加 models_prod 目录检查与模型文件存在性告警
2026-07-13 17:30:52 +08:00
4f5965db02
feat: JWT多租户数据权限隔离 & 主管系统管理权限 & 含税单价补齐
...
## 多租户公司数据隔离
- 新增 get_current_company_filter() 工具函数 (decorators.py)
SUPER_ADMIN: 可传company_name参数过滤或传ALL看全量
其他角色: 强制隔离到JWT中的company_name
- 重构 base_service.py / buy_service.py: 用集中式函数替换内联公司过滤
- SysRolePermission 表新增 company_name 字段,支持同角色不同公司权限
- get_user_permissions() 新增 company_name 参数,查公司定制+全局模板权限
- permission.py API 新增 @permission_required 拦截 + 公司过滤
- 19个API/service文件传递 company_name 到权限查询
## 主管系统管理权限
- delete_user() 允许SUPERVISOR删除同公司用户 (原仅SUPER_ADMIN)
- get_all_users() 新增 company_name 参数过滤
- 用户列表/权限分配 API 应用 get_current_company_filter()
- 前端 UserCreate.vue: 超管可见公司下拉框,主管隐藏部门字段
## 前端多租户适配
- material/list.vue / buy.vue: 公司下拉框仅超管可见,默认ALL
- UserCreate.vue: 新增搜索栏公司筛选,部门字段按角色显隐
- auth.ts: getUserList() 支持 params 参数
## Bug修复: 含税单价字段补齐
- buy.vue: 表格列/高级筛选/排序/权限映射新增 post_tax_unit_price
- buy_service.py: allowed_fields/sort_field_map 新增 post_tax_unit_price
2026-07-13 15:12:22 +08:00
c1092407ad
V3.50
2026-06-25 15:21:43 +08:00
8a2da1ac1e
半成品/成品入库:BOM 编号下拉按父件规格联动过滤(前后端双端改造)
...
- 后端 /inbound/{semi,product}/search-bom 增加 parent_spec 可选参数,Service 层在 MaterialBase.spec_model 上加等值过滤
2026-06-04 16:01:48 +08:00
bac670ef7a
基础信息页:计量单位改 el-select(下拉历史+手动输入);表单排版重排为 4 行(类别占满行);类别末级英文后缀自动填规格型号
2026-06-04 13:22:51 +08:00
cf55c94826
feat: 库存接口增加 ai_mode=true 极简返回模式,键名压缩为 n/s/c
2026-05-19 09:53:06 +08:00
259f3a7e0d
4.29扫码获取库位小工具接口
2026-04-29 15:40:43 +08:00
183b93012e
4.28
2026-04-28 16:07:11 +08:00
e08eaff40a
feat(outbound): 库存列表按规格+库位聚合 + BOM明细类型修复
2026-04-28 09:23:59 +08:00
40e405becd
4.27
2026-04-27 16:33:54 +08:00
48f2011a38
fix: 盘点草稿已盘数量统计兼容字段名 quantity
2026-04-24 13:32:46 +08:00
996056d46a
fix: 修复库存盘点已盘数量卡在500的问题
2026-04-24 13:19:57 +08:00
a849e14b2c
refactor(orm): 将所有的批量 delete/update 重构为对象级操作,以确保触发 SQLAlchemy 审计事件
2026-04-20 15:43:48 +08:00
477da7c434
fix-security-correct-field-permission-mapping-and-403-denial
2026-04-14 15:37:39 +08:00
ae05f3bb75
fix-security-field-permission-matching
2026-04-14 15:09:15 +08:00
ae1fd1afd4
fix-security-permission-codes
2026-04-14 14:49:53 +08:00
c7ac092be4
feat(material): add global floating helper to track latest specification codes with smart grouping
2026-04-13 08:28:27 +08:00
41b5118ecd
feat(repair): implement backend CRUD services and API routes with RBAC permissions for repair module
2026-04-08 18:34:48 +08:00
4a4baa2f8f
fix: sort warehouse tree by name, fix tree batch delete cascade, and implement safe history location autofill
2026-04-08 17:32:00 +08:00
6d80c90b66
feat: add 'not contains' operator, implement inbound record export, and verify export filter rules
2026-04-07 17:23:00 +08:00
0d8f697df4
fix(stocktake): enforce session_id in resume, make missing generation idempotent, update UI to show SN, and fix excel time offset
2026-04-03 09:42:51 +08:00
43e1d0aa55
fix(stocktake): strictly isolate stocktake drafts by session_id in list and finish generation to prevent historical data mixing
2026-04-03 09:25:52 +08:00
6aec571775
fix(stocktake): resolve 500 error caused by missing batch or sn attributes using strict getattr fallback
2026-04-03 09:05:48 +08:00
c361d25ea0
fix(stocktake): display batch number in scanning dialog and fix empty uncounted items in Excel export
2026-04-02 19:06:19 +08:00
a52ced0375
fix(backend): resolve DetachedInstanceError in audit_log, add pessimistic locks for stock adjustments, and eliminate N+1 queries with eager loading
2026-04-02 18:44:12 +08:00
b2ce9d31f8
fix(stocktake): replace hardcoded 'admin' with actual current user in excel export
2026-03-27 09:04:13 +08:00
2a27f2e0df
feat(stocktake): implement strict blind stocktake logic with hidden system qty, editable count and status filters
2026-03-26 17:42:51 +08:00