Files
KCGL/inventory-web/src/api/purchase.ts
yueli 26a1857acb fix(purchase): 待采购清单的参考价格改按 material_list:referencePrice 管控
修复一个权限旁路:待采购清单的「参考单价」原本后端无条件返回、前端列也没有
任何门控,而 material_list:referencePrice 只授予 SUPER_ADMIN 与 SUPERVISOR。

结果是 WAREHOUSE_MGR(库管) / INBOUND(入库员) / SALES(销售) 虽然都持有
inbound_purchase:pending_pool、能打开待采购清单,就会看到参考价格 —— 而这个
数字他们在物料列表里是被挡住的。等于本页面成了绕过该权限的后门。

参考价格来自 material_base.reference_price,与物料列表同源,因此复用同一个
权限码管控,不另造新码(同源数据用同码,口径才不会漂)。

改动:
- 后端 get_pending_purchase_pool 新增 include_reference_price 参数,
  fail-closed 默认 False;无权限时**整个字段不返回**而不是给 None
- 新增 _has_material_reference_price_perm(),判定方式与既有的
  _filter_purchase_prices 保持一致(超管/主管放行 + 逐个权限码比对)
- 前端「参考单价」列加 hasPermission 门控,TS 类型改为可选

★ 只挡前端等于没挡(接口仍然裸奔),前后端必须同时改。
2026-09-18 14:36:02 +08:00

210 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import request from '@/utils/request'
export interface PurchaseItem {
id?: number
request_no?: string
base_id?: number
name: string
spec_model?: string
quantity: number
purchase_date: string
supplier_link?: string
remark?: string
images?: string[]
unit_price?: number
total_price?: number
tax_rate?: number
status: number
status_text?: string
requester_id?: number
requester_name?: string
requester_email?: string
approver_id?: number
approver_name?: string
approved_at?: string
reject_reason?: string
created_at?: string
updated_at?: string
// [新增] 关联物料基础信息(已审批未入库列表返回)
material?: {
id: number
company_name: string
name: string
spec_model: string
category: string
unit: string
type: string
is_inspection_required: boolean
} | null
}
export interface Approver {
id: number
username: string
email: string
role: string
}
// 获取采购申请列表
//
// 搜索参数语义与出库/报废记录保持一致:
// search_type: all / no(单号) / name(物料名称) / spec_model / requester(申请人)
// start_date / end_date: 按采购日期过滤
export function getPurchaseList(params: {
page?: number
limit?: number
status?: number | ''
keyword?: string
search_type?: 'all' | 'no' | 'name' | 'spec_model' | 'requester'
start_date?: string
end_date?: string
}) {
return request({
url: '/purchase',
method: 'get',
params
})
}
// 创建采购申请
export function createPurchase(data: PurchaseItem) {
return request({
url: '/purchase',
method: 'post',
data
})
}
// 获取采购申请详情
export function getPurchaseDetail(id: number) {
return request({
url: `/purchase/${id}`,
method: 'get'
})
}
// 审批采购申请
export function approvePurchase(id: number, data: {
action: 'approve' | 'reject'
reject_reason?: string
}) {
return request({
url: `/purchase/${id}/approve`,
method: 'patch',
data
})
}
// 批量审批采购申请(循环提交产生的多条记录可一次审批)
export function batchApprovePurchase(data: {
ids?: number[]
batch_key?: string
action: 'approve' | 'reject'
reject_reason?: string
}) {
return request({
url: '/purchase/batch-approve',
method: 'post',
data
})
}
// 按批次前缀查询同批次的采购申请记录(批次=request_no去掉末尾流水号
export function getPurchaseByBatch(batchKey: string) {
return request({
url: `/purchase/batch/${encodeURIComponent(batchKey)}`,
method: 'get'
})
}
// 获取今日下一个采购批次号(提交一批时调用,同批所有行共享)
export function getNextBatchSeq() {
return request({
url: '/purchase/next-batch-seq',
method: 'get'
})
}
// 获取可选审批人列表
export function getPurchaseApprovers() {
return request({
url: '/purchase/approvers',
method: 'get'
})
}
// 根据名称/规格自动补全
export function autoFillPurchase(keyword: string) {
return request({
url: '/purchase/auto-fill',
method: 'get',
params: { keyword }
})
}
// 物料基础信息搜索(分页),用于采购申请弹窗
export function searchMaterialPurchase(keyword: string, page: number = 1) {
return request({
url: '/purchase/search-material',
method: 'get',
params: { keyword, page }
})
}
// [新增] 获取已审批通过且未入库的采购单列表(供库管按单入库使用)
export function getApprovedUnstockedRequests(params: {
page?: number
limit?: number
keyword?: string
}) {
return request({
url: '/purchase/approved-unstocked',
method: 'get',
params
})
}
// 待采购池的单条物料(防重复采购)
export interface PendingPoolItem {
material_id: number
name: string
spec_model: string
unit: string
category: string
material_type: string
company_name: string
image: string
purchase_link: string
// 仅供参考展示,受 material_list:referencePrice 管控 —— 无权限时后端**不返回该字段**
reference_price?: number | null
inventory_count: number
available_count: number
// 在途量 = 该物料所有活跃采购单的剩余待入库量之和
in_transit_qty: number
// 有效供给 = 库存 + 在途。判缺货与算建议量都基于它
effective_supply: number
warning_status: number // 0=正常 1=黄色 2=红色(进池的必然非 0
warning_red: number | null
warning_yellow: number | null
target_threshold: number | null
suggested_qty: number | null
is_ordered: boolean
}
// 待采购清单:库存已触及预警线、且没有活跃采购单的物料。
// 物料一旦有在途采购单(待审批/已通过/部分到货未齐)就会从这里消失。
export function getPendingPurchasePool(params: {
page?: number
limit?: number
keyword?: string
category?: string
type?: string
warning_status?: number
}) {
return request({
url: '/purchase/pending-pool',
method: 'get',
params
})
}