Commit Graph

560 Commits

Author SHA1 Message Date
021c92ee8a feat(purchase): 采购申请改为动态明细表,支持一行多物料批量提交
- 新建弹窗物料区改为动态明细表格:每行独立选择物料/规格/数量/日期/单价/总价/税率
- 支持 [+ 添加一行] 动态增行、行内删除
- 审批人/商家链接/备注/图片凭证为公共信息
- 提交时 for 循环逐行调用单条 createPurchase 接口,后端无需改动
- 行内价格半联动:改单价自动算总价,手动改总价后不再覆盖
2026-08-31 13:05:29 +08:00
5abc504619 feat(outbound): 审批列表页增加完结按钮 + 优化缺货提示文案
- 去掉缺货提醒末尾的『是否查看?』(纯文案,保持强提醒但不承诺展示清单)
- approval/index.vue 对已通过(status=1)的审批单新增「完结」按钮
  库管/主管/超管可见,完结后从已通过列表移除
- 筛选区新增「已完结」状态选项,状态标签支持 status=4
2026-08-31 10:46:33 +08:00
bf104535e5 V3.69,8.31推送 2026-08-31 10:30:03 +08:00
36e9f500aa feat(borrow): 借库未归还直接报废功能(关联报废单流程)
后端:
- trans_service 新增 scrap_borrow 方法:未归还借用标记为 scrapped,
  扣减总库存 stock_quantity(可用已在借出时冻结),生成 TransScrap 报废记录
- transactions.py 新增 POST /borrow/scrap 接口(复用 op_return:operation 权限,库管/主管可操作)
- scrap.py query_records 支持 trans_borrow 来源的物料名解析 + 行级隔离

前端:
- records.vue 未归还记录新增「报废」按钮(库管/主管可见)
- 报废弹窗:勾选明细 + 填报废原因 + 二次确认
- 状态显示新增「已报废」标签;整单所有明细报废时标记为 scrapped
2026-08-31 10:21:28 +08:00
39f3f8af45 feat(outbound): 审批单手动完结/作废功能
- 后端: outbound_service 新增 close_request 方法(状态 1-已通过 → 4-已完结)
- 后端: 新增 POST /api/v1/outbound/request/<id>/close 接口
- 模型: status_text 数组增加「已完结」
- 前端: create.vue 审批单选择区新增「强制完结此单」按钮
  完结后刷新列表,该单从已通过下拉中移除
- 权限: 超级管理员/审批人/拥有 outbound_create:operation 的用户可完结(库管可操作)
2026-08-31 10:15:33 +08:00
b6ec45a8b8 feat(outbound): 出库流程强化(缺料防漏 + 完全移除直接出库)
① BOM 清单 SKU 改为规格型号(getBomWithStock 返回 children 无 sku,只有 child_spec)
② 缺货清单自动写入出库申请备注(借鸡生蛋:历史欠料永久留存在申请单)
③ 打印单底部增加欠料待补签收区(补料人签字/日期)
④ 有缺料时阻断式二次确认,防手快漏看
⑤ 完全移除直接出库模式,所有出库必须按单出库
   - create.vue 删除 radio 切换、direct 相关逻辑
   - 提交前强制校验已选择审批申请单
2026-08-31 09:37:14 +08:00
a4bd6f54d4 feat(outbound): BOM 出库增加清单打印与缺货持久化提醒
- BOM 弹窗物料清单增加「本次结果」列(可出/缺货未出)
- 增加「打印 BOM 清单」按钮,可打印当前 BOM 的完整出库清单
- 缺货物料持久化到 localStorage,下次打开同一 BOM 时自动提示历史缺货记录
  防止重复出库或漏出
- 打印区域使用与 A4 出库单一致的 iframe 打印机制
2026-08-31 09:26:53 +08:00
0c3e57f5b5 fix(nginx): 生产 nginx 代理指向容器名 inventory_api_prod 避免 DNS 冲突
- 服务器上有多个 compose 项目(inventory-app / Track)都使用 backend 服务名
- nginx 中 proxy_pass http://backend:8000 会随机解析到 track_backend_prod
  导致 /api/ 请求 404
- 改为使用固定容器名 inventory_api_prod:8000
2026-08-28 16:46:02 +08:00
57a6ab38d1 fix(outbound): 修复选单列表移除按钮排序后索引错位导致删错行
- 表格绑定 sortedSelectedItems(按库位排序),但移除按钮用 $index 操作原始 selectedItems
- 排序后索引与原始数组不一致,导致删除错误的行
- 改为按 uniqueKey 精确定位删除
2026-08-13 17:17:54 +08:00
9c0414b802 fix(outbound): 出库备注改为必填,按单出库自动填充申请原因
- 备注字段新增 required 校验规则
- placeholder 从「可选填」改为「请填写出库原因」
- 按单出库模式选择申请单后,自动将申请原因填入备注
2026-08-07 15:58:59 +08:00
7b5846b489 V3.68,8.3推送 2026-08-03 15:53:52 +08:00
d0776f1036 feat(import): 前端导入策略选择器 + 部分导入支持
- 新增导入策略单选:跳过重复行 / 覆盖更新
- 预览状态新增「将被更新」标签(橙色),区分「通过」「失败」
- 支持部分导入:有错误行时显示「忽略错误,仅导入正确的 N 条」按钮
- 预览时传递 mode 参数给后端
- 导入结果展示新增/更新/跳过数量
2026-08-03 15:53:24 +08:00
bc9cc18142 V3.67,8.3推送 2026-08-03 13:26:08 +08:00
6c7f8dbe61 fix: 修复搜索跳转弹窗无法打开的问题
- AppMain.vue: 将 router-view 的 key 从 route.fullPath 改为 route.path,避免 query 参数变化导致组件销毁重建
- list.vue: watch 中 router.replace 增加 query 非空判断,防止不必要的 URL 清理
- list.vue: handleEdit 的 nextTick 增加 try-catch 防御性保护
- list.vue: 添加 onUnmounted 调试探针
2026-08-03 13:25:54 +08:00
b84fffbd37 V3.66,8.3推送 2026-08-03 09:47:10 +08:00
65aba4b313 fix: token 刷新时缺少 company_name 导致多租户过滤返回空数据 2026-08-03 09:22:50 +08:00
60c6f634ce V3.65,8.3推送 2026-08-03 09:15:45 +08:00
d68ba1e987 fix: 页面刷新时主动续期 access_token,避免过期 token 触发 401 竞态导致权限空白 2026-07-23 09:48:33 +08:00
5cb1f3b24b V3.64 2026-07-21 10:21:27 +08:00
9ceb6ddc1d debug: 诊断出库审批/借库审批的 operationCode 是否被正确识别 2026-07-21 10:19:21 +08:00
d7d7d65a4f fix: inbound_summary 页面 v-if 从不存在权限码 inbound_summary:view 改为菜单权限 inbound_summary 2026-07-21 10:11:13 +08:00
01122a58f3 debug: inbound_summary 加日志确认 list.value 数据加载状态 2026-07-21 10:06:55 +08:00
63c36d1466 fix: 借库记录签名改回 null(始终可见),暂等 sys_element 补齐权限码 2026-07-21 09:59:14 +08:00
a8a0290cd8 fix: outbound total_amount 改为需权限 outbound_list:total_amount,库管无此权限则隐藏总金额 2026-07-21 09:49:46 +08:00
4ab7b6f541 fix: borrow/return/records permissionMap 基础列改为 null 始终可见,对齐 inbound 模式,移除 records alwaysVisible 硬编码 2026-07-21 09:40:58 +08:00
35690c5b8f fix: 出库列表 permissionMap 基础列改为 null(始终可见),对齐 inbound 模式;单价/小计保留权限控制 2026-07-21 09:39:16 +08:00
451d7b5719 V3.63 2026-07-20 14:33:26 +08:00
f6c1dedd22 V3.62,库管权限修改内容 2026-07-17 17:06:27 +08:00
097fbb319f fix: validateUnique 编辑模式下值未变时跳过重复校验,仅值改变时才检查冲突 2026-07-17 17:04:10 +08:00
1f43de4ccc debug: buy.vue validateUnique 加详细日志——打印 form.id/row.id/value 比对过程 2026-07-17 17:02:25 +08:00
9bcd02c742 fix: update_buy perm_code=None 导致 NoneType 崩溃 + validateUnique 编辑时排除自身改用 Number() 防类型不一致 2026-07-17 16:57:46 +08:00
a8fb0cfc94 debug: validateUnique 加详细日志追踪编辑时误报重复编号问题 2026-07-17 16:53:57 +08:00
76c7e3d3dc V3.61,出库审批的可编辑即可操作 2026-07-17 16:31:33 +08:00
29de22b575 fix: crossDomain 重复收集 — 真实树中的 system_mgmt/crossDomain 与虚拟 global_privileges 冲突,从真实树中移除 crossDomain 避免双重收集 2026-07-17 16:22:59 +08:00
0e6294890c debug: crossDomain 收集逻辑加精确断点日志 2026-07-17 16:20:22 +08:00
0074d96163 fix: 权限配置页 GET 请求加 _t 防浏览器缓存 + 保存后自动刷新 UI 2026-07-17 16:13:12 +08:00
96eb56766e fix: 回退权限保存后的 auto-refresh,改为手动刷新提示 2026-07-17 16:07:54 +08:00
c9cf4e0901 fix: 权限保存后自动刷新 UI 回显,确保勾选框状态与数据库同步 2026-07-17 16:02:51 +08:00
686186d7d6 fix: Create/Update 成本字段分离 — Create 保留 BOM 自动计算值,Update 按 hasFormFieldPermission 剥离敏感字段 2026-07-17 14:50:06 +08:00
8b6539b976 fix: semi/product 对话框中成本字段添加 v-if 权限守卫,与 buy.vue 的 hasFormFieldPermission 模式对齐 2026-07-17 14:43:08 +08:00
cac8a360ec V3.60,邮件发送失败问题修复 2026-07-17 14:28:40 +08:00
a4a6d027fe V3.59,紧急修复出入库问题 2026-07-17 14:04:18 +08:00
036d756fbd fix: 前端 product.vue permissionMap null→显式权限码 + fetchMaterialSuggestions 改用 async/await 修复首次搜索空白 2026-07-17 13:45:38 +08:00
9fe64847a7 fix: 前端 buy/semi permissionMap 数量字段 null→显式权限码,与后端 RBAC 统一对齐 2026-07-17 13:45:32 +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
d647af6bc3 fix: Odoo页面排序失效 — 排序参数未传递+缓存未清除
## buyOdoo.vue
- handleSortChange: 排序时清除已展开分组缓存,强制重新加载
- loadGroupItems: 传递 orderByColumn + isAsc 排序参数到API
2026-07-16 17:34:30 +08:00
754c46bd59 feat: 采购申请字段级价格权限 — 库管看不到采购价格
## permission_service.py
- init_all_menus: 新增3个采购权限元素
  inbound_purchase:unit_price, :total_price, :tax_rate

## purchase.py
- _filter_purchase_prices(): 无价格权限则pop价格字段
- GET /purchase (列表): 应用价格过滤
- GET /purchase/<id> (详情): 应用价格过滤
- approved-unstocked: 保留价格(入库数据源,前端按inbound_buy权限控制)

## purchase/index.vue
- 列表: 单价/总价/税率列 v-if hasPermission
- 详情: 单价/总价 v-if hasPermission
2026-07-16 17:34:24 +08:00
6e064064d5 V3.58 2026-07-16 14:28:37 +08:00
382b461b68 feat: 挂载ImportDialog + 修复路由白屏
## 页面挂载
- buyOdoo.vue: 新增「批量导入」按钮(新增旁边), ImportDialog material
- list.vue: 新增「批量导入」按钮, ImportDialog material
- BomManage.vue: 新增「导入BOM」按钮(新建BOM左边), ImportDialog bom

## 白屏修复
- AppMain.vue: 移除 transition mode=out-in 动画包裹(导致首次访问白屏)
  改为 :key=route.fullPath 强制创建新实例
2026-07-16 14:00:44 +08:00
ebe79be9cb feat: ImportDialog组件 — 三步骤批量导入弹窗(拖拽上传+预览+执行)
## ImportDialog.vue (新增)
- Step1: 模板下载 + el-upload drag 拖拽上传
- Step2: el-table 预览验证结果(绿色通过/红色失败+错误详情)
- Step3: 确认导入(事务保护), errorCount>0时按钮disabled
- Props: importType ('material'|'bom'), modelValue
- Emits: success (刷新列表)
2026-07-16 14:00:36 +08:00