diff --git a/src/api/prCost.js b/src/api/prCost.js index 13b4a1b..245d332 100644 --- a/src/api/prCost.js +++ b/src/api/prCost.js @@ -160,25 +160,6 @@ export async function prCostRemove(expense_code) { return res?.data ?? res } -/** POST /api/pr/cost/amortize — 月度批量分摊(聚合时间段内已确认采购,逐笔未分摊费用) */ -export async function prCostAmortize(body) { - const payload = { - start_time: str(body?.start_time), - end_time: str(body?.end_time), - } - if (!payload.start_time || !payload.end_time) throw new Error('请选择分摊时间段') - const expense_code = pickPrExpenseCode(body) - if (expense_code) payload.expense_code = expense_code - const res = await request.post('/api/pr/cost/amortize', payload, { skipErrorNotify: true }) - return res?.data ?? res -} - -/** 已分摊 / 无匹配采购 / 时段内无可分摊等业务提示,非致命错误 */ -export function isBenignAmortizeError(err) { - const msg = pickApiErrorMessage(err, '') - return !msg || /没有未分摊|已分摊|无需分摊|无可分摊|无匹配|没有.*采购|暂无/.test(msg) -} - /** 分页拉全量公关费用 */ export async function prCostListedAll(body = {}) { const limit = 50 diff --git a/src/api/pricingTable.js b/src/api/pricingTable.js new file mode 100644 index 0000000..a326e09 --- /dev/null +++ b/src/api/pricingTable.js @@ -0,0 +1,142 @@ +import request from '@/utils/request' +import { pickGoodsNameFromListedRow } from '@/utils/goodsCategorys' + +function str(v) { + return String(v ?? '').trim() +} + +/** 默认内销(暂无出口场景) */ +export const PRICING_TRADE_DOMESTIC = 'DOMESTIC' + +/** 成本围栏 · 纳税身份 Tab(key 即接口 taxpayer_type 枚举) */ +export const PRICING_TAXPAYER_TABS = [ + { key: 'GENERAL', label: '一般纳税人' }, + { key: 'SMALL', label: '小规模纳税人' }, + { key: 'INDIVIDUAL', label: '收据组织' }, +] + +/** @deprecated 请直接用 PRICING_TAXPAYER_TABS[].key */ +export const PRICING_TAXPAYER_BY_ORG = { + general: 'GENERAL', + small: 'SMALL', + personal: 'INDIVIDUAL', +} + +export const PRICING_TAXPAYER_DEFAULT = 'GENERAL' + +const PRICING_TAXPAYER_KEYS = new Set(PRICING_TAXPAYER_TABS.map((t) => t.key)) + +/** 接口 data.list */ +function unwrapPricingTableList(res) { + const envelope = res?.data ?? res + if (Array.isArray(envelope)) return envelope + const payload = envelope?.data ?? envelope + if (Array.isArray(payload)) return payload + if (payload && typeof payload === 'object') { + const list = payload.list ?? payload.rows ?? payload.table + if (Array.isArray(list)) return list + } + return [] +} + +function pickText(raw, ...keys) { + for (const k of keys) { + const v = raw[k] + if (v == null) continue + const s = String(v).trim() + if (s) return s + } + return null +} + +/** 税率等:0 为有效值 */ +function pickRate(raw, ...keys) { + for (const k of keys) { + const v = raw[k] + if (v == null || v === '') continue + const n = Number(v) + if (Number.isFinite(n)) return n + } + return null +} + +/** 金额:过滤 null / 非有限数 / 明显异常值 */ +function pickMoney(raw, ...keys) { + for (const k of keys) { + const v = raw[k] + if (v == null || v === '') continue + const n = Number(v) + if (!Number.isFinite(n)) continue + if (Math.abs(n) >= 1e12) continue + return n + } + return null +} + +/** 定价决策表行 → 成本围栏表格(字段对齐 /api/pricing/table) */ +export function normalizePricingTableRow(raw, idx = 0) { + if (!raw || typeof raw !== 'object') return null + + const supplier_bloc_name = pickText(raw, 'supplier_bloc_name') + const supplier_company_name = pickText(raw, 'supplier_company_name') + const goods_name = pickGoodsNameFromListedRow(raw) || pickText(raw, 'goods_name') + const bill_type = pickText(raw, 'bill_name', 'bill_type') + const input_tax_rate = pickRate(raw, 'bill_tax', 'input_tax_rate') + const source_company_name = pickText(raw, 'receive_company_name', 'source_company_name') + const internal_min_price = pickMoney(raw, 'internal_price', 'internal_min_price') + const internal_bill_type = pickText(raw, 'internal_bill_name', 'internal_bill_type') + const internal_input_tax_rate = pickRate(raw, 'internal_bill_tax', 'internal_input_tax_rate') + const source_rdc_name = pickText(raw, 'rdc_warehouse_name', 'source_rdc_name') + const source_rdc_code = pickText(raw, 'rdc_warehouse_code', 'source_rdc') + const fence_value = pickMoney(raw, 'fence_price', 'fence_value') + + const bloc = pickText(raw, 'supplier_bloc_code') + const company = pickText(raw, 'supplier_company_code') + + return { + key: pickText(raw, 'key', 'id') ?? `${bloc || 'bloc'}-${company || idx}`, + supplier_bloc_name, + supplier_company_name, + goods_name, + bill_type, + input_tax_rate, + source_company_name, + internal_min_price, + internal_bill_type, + internal_input_tax_rate, + source_rdc: source_rdc_name || source_rdc_code, + source_rdc_name, + fence_value, + } +} + +/** + * POST /api/pricing/table + * 定价决策表:按 RDC、商品、纳税人身份、交易类型生成围栏支持数据 + */ +export async function pricingTableQuery(body = {}) { + const taxpayer_type = str(body.taxpayer_type).toUpperCase() + const trade_type = str(body.trade_type) || PRICING_TRADE_DOMESTIC + const goods_code = str(body.goods_code) + const rdc_code = str(body.rdc_code) + if (!taxpayer_type) throw new Error('缺少纳税人身份') + if (!PRICING_TAXPAYER_KEYS.has(taxpayer_type)) { + throw new Error(`纳税人身份无效:${taxpayer_type}`) + } + if (!goods_code) throw new Error('缺少商品编码') + if (!rdc_code) throw new Error('缺少 RDC 仓库编码') + + const res = await request.post('/api/pricing/table', { + taxpayer_type, + trade_type, + goods_code, + rdc_code, + }) + return unwrapPricingTableList(res) + .map((row, idx) => normalizePricingTableRow(row, idx)) + .filter(Boolean) +} + +export function pickPricingTableError(err, fallback = '加载定价决策表失败') { + return String(err?.data?.message || err?.message || fallback).trim() || fallback +} diff --git a/src/api/warehouseAlloc.js b/src/api/warehouseAlloc.js index 366b481..e1a0daa 100644 --- a/src/api/warehouseAlloc.js +++ b/src/api/warehouseAlloc.js @@ -287,19 +287,3 @@ export async function allocShareListed(body = {}) { total, } } - -/** POST /api/warehouse/alloc/amortize */ -export async function allocAmortize(body) { - const payload = { - start_time: str(body?.start_time), - end_time: str(body?.end_time), - } - if (!payload.start_time || !payload.end_time) throw new Error('请选择分摊时间段') - const res = await request.post('/api/warehouse/alloc/amortize', payload, { skipErrorNotify: true }) - return res?.data ?? res -} - -export function isBenignAllocAmortizeError(err) { - const msg = pickApiErrorMessage(err, '') - return !msg || /没有|已分摊|无需分摊|无可分摊|暂无|为空/.test(msg) -} diff --git a/src/api/warehouseDeploy.js b/src/api/warehouseDeploy.js index 41c4510..acf9143 100644 --- a/src/api/warehouseDeploy.js +++ b/src/api/warehouseDeploy.js @@ -270,19 +270,3 @@ export async function deployShareListed(body = {}) { total, } } - -/** POST /api/warehouse/deploy/amortize */ -export async function deployAmortize(body) { - const payload = { - start_time: str(body?.start_time), - end_time: str(body?.end_time), - } - if (!payload.start_time || !payload.end_time) throw new Error('请选择分摊时间段') - const res = await request.post('/api/warehouse/deploy/amortize', payload, { skipErrorNotify: true }) - return res?.data ?? res -} - -export function isBenignDeployAmortizeError(err) { - const msg = pickApiErrorMessage(err, '') - return !msg || /没有|已分摊|无需分摊|无可分摊|暂无|为空/.test(msg) -} diff --git a/src/api/warehouseFreight.js b/src/api/warehouseFreight.js index d4726a9..319f773 100644 --- a/src/api/warehouseFreight.js +++ b/src/api/warehouseFreight.js @@ -291,40 +291,6 @@ export async function freightShareListed(body = {}) { } } -/** POST /api/warehouse/freight/amortize — 月度批量分摊(按已到库订单 + 运费日志维度) */ -export async function freightAmortize(body) { - const payload = { - start_time: str(body?.start_time), - end_time: str(body?.end_time), - } - if (!payload.start_time || !payload.end_time) throw new Error('请选择分摊时间段') - const res = await request.post('/api/warehouse/freight/amortize', payload, { skipErrorNotify: true }) - return res?.data ?? res -} - -/** 时段内无运费日志 / 已分摊等业务提示,非致命错误 */ -export function isBenignFreightAmortizeError(err) { - const msg = pickApiErrorMessage(err, '') - return !msg || /没有|已分摊|无需分摊|无可分摊|无运费|暂无|为空/.test(msg) -} - -/** 分页拉全量物料运费日志(跑批前校验时段内是否有日志) */ -export async function freightLogsListedAll(body = {}) { - const limit = 50 - let page = 1 - const all = [] - let total = 0 - for (;;) { - const res = await freightLogsListed({ ...body, page, limit }) - const batch = res.list || [] - all.push(...batch) - total = res.total - if (!batch.length || all.length >= total) break - page += 1 - } - return { list: all, total } -} - export function pickApiErrorMessage(err, fallback = '操作失败') { return String(err?.data?.message || err?.message || fallback).trim() || fallback } diff --git a/src/api/warehouseWaste.js b/src/api/warehouseWaste.js index b08c9a1..80e5060 100644 --- a/src/api/warehouseWaste.js +++ b/src/api/warehouseWaste.js @@ -254,22 +254,6 @@ export async function wasteShareListed(body = {}) { } } -/** POST /api/warehouse/waste/amortize */ -export async function wasteAmortize(body) { - const payload = { - start_time: str(body?.start_time), - end_time: str(body?.end_time), - } - if (!payload.start_time || !payload.end_time) throw new Error('请选择分摊时间段') - const res = await request.post('/api/warehouse/waste/amortize', payload, { skipErrorNotify: true }) - return res?.data ?? res -} - -export function isBenignWasteAmortizeError(err) { - const msg = pickApiErrorMessage(err, '') - return !msg || /没有|已分摊|无需分摊|无可分摊|暂无|为空/.test(msg) -} - export function pickApiErrorMessage(err, fallback = '操作失败') { return String( err?.data?.message diff --git a/src/components/global-tab/GlobalTabCostPanel.vue b/src/components/global-tab/GlobalTabCostPanel.vue index 6d95603..1a9ecfb 100644 --- a/src/components/global-tab/GlobalTabCostPanel.vue +++ b/src/components/global-tab/GlobalTabCostPanel.vue @@ -1,50 +1,56 @@