128 lines
4.4 KiB
TypeScript
128 lines
4.4 KiB
TypeScript
import { fetchProductDetail } from '@/api/crm/product'
|
|
import type { PlanProduct } from '@/api/pl'
|
|
|
|
export type HazardFlagProduct = {
|
|
productId?: string
|
|
productName?: string
|
|
isToxic?: number
|
|
isExplosive?: number
|
|
is_toxic?: number
|
|
is_explosive?: number
|
|
}
|
|
|
|
function isTruthyHazardFlag(value: unknown) {
|
|
return value === 1 || value === true || value === '1'
|
|
}
|
|
|
|
export function resolveProductHazardFlags(product: HazardFlagProduct) {
|
|
const isToxic =
|
|
isTruthyHazardFlag(product.isToxic) || isTruthyHazardFlag(product.is_toxic)
|
|
const isExplosive =
|
|
isTruthyHazardFlag(product.isExplosive) || isTruthyHazardFlag(product.is_explosive)
|
|
return { isToxic, isExplosive }
|
|
}
|
|
|
|
export function isHazardProduct(product: Pick<PlanProduct, 'isToxic' | 'isExplosive'>) {
|
|
const flags = resolveProductHazardFlags(product)
|
|
return flags.isToxic || flags.isExplosive
|
|
}
|
|
|
|
export function getHazardProductLabel(product: Pick<PlanProduct, 'isToxic' | 'isExplosive'>) {
|
|
const flags = resolveProductHazardFlags(product)
|
|
if (flags.isExplosive) return '易制爆'
|
|
if (flags.isToxic) return '易制毒'
|
|
return ''
|
|
}
|
|
|
|
/** 产品名称后追加易制毒/易制爆标识:毒、爆,或「毒 爆」 */
|
|
export function formatPlProductNameWithHazardMarks(product: HazardFlagProduct) {
|
|
const name = product.productName || ''
|
|
const { isToxic, isExplosive } = resolveProductHazardFlags(product)
|
|
const marks: string[] = []
|
|
if (isToxic) marks.push('毒')
|
|
if (isExplosive) marks.push('爆')
|
|
if (!marks.length) return name
|
|
return `${name}${marks.join(' ')}`
|
|
}
|
|
|
|
/** 从 CRM 产品主数据读取易制毒/易制爆标识(覆盖计划产品快照字段) */
|
|
export async function enrichPlanProductsHazardFromCrm<T extends HazardFlagProduct & { productId: string }>(
|
|
products: T[]
|
|
): Promise<T[]> {
|
|
if (!products.length) return products
|
|
|
|
const lookupIds = [
|
|
...new Set(products.map(product => product.productId).filter(Boolean))
|
|
]
|
|
if (!lookupIds.length) return products
|
|
|
|
const hazardMap = new Map<string, { isToxic: number; isExplosive: number; taxRate?: number }>()
|
|
await Promise.all(
|
|
lookupIds.map(async productId => {
|
|
try {
|
|
const res = await fetchProductDetail({ id: productId })
|
|
const data = (res as { data?: Record<string, unknown> }).data ?? res
|
|
const row = data as Record<string, unknown>
|
|
const rawTaxRate = row.taxRate ?? row.tax_rate
|
|
hazardMap.set(productId, {
|
|
isToxic: Number(row.isToxic ?? row.is_toxic ?? 0),
|
|
isExplosive: Number(row.isExplosive ?? row.is_explosive ?? 0),
|
|
taxRate: rawTaxRate != null && rawTaxRate !== '' ? Number(rawTaxRate) : undefined
|
|
})
|
|
} catch {
|
|
// 单条产品查询失败时跳过
|
|
}
|
|
})
|
|
)
|
|
|
|
return products.map(product => {
|
|
const fromCrm = hazardMap.get(product.productId)
|
|
if (!fromCrm) return product
|
|
return {
|
|
...product,
|
|
isToxic: fromCrm.isToxic,
|
|
isExplosive: fromCrm.isExplosive,
|
|
taxRate: product.taxRate ?? fromCrm.taxRate
|
|
}
|
|
})
|
|
}
|
|
|
|
export function findMissingHazardCerts(products: PlanProduct[]) {
|
|
return products.filter(
|
|
p => isHazardProduct(p) && (!p.purchaseCertUrl?.trim() || !p.transportCertUrl?.trim())
|
|
)
|
|
}
|
|
|
|
export function planHasHazardProducts(products: PlanProduct[] | undefined) {
|
|
return (products ?? []).some(p => isHazardProduct(p))
|
|
}
|
|
|
|
export function isHazardCertReady(plan: { hazardCertReady?: number } | null | undefined) {
|
|
return Number(plan?.hazardCertReady ?? 0) === 1
|
|
}
|
|
|
|
/** 含危化品且尚未人工确认证书齐备时,阻断安排运输 */
|
|
export function shouldBlockTransportForHazardCert(
|
|
plan: { hazardCertReady?: number; products?: PlanProduct[] } | null | undefined,
|
|
products?: PlanProduct[]
|
|
) {
|
|
const prods = products ?? plan?.products
|
|
if (!planHasHazardProducts(prods)) return false
|
|
return !isHazardCertReady(plan)
|
|
}
|
|
|
|
export function buildMissingHazardCertReadyMessage(
|
|
plan: { hazardCertReady?: number; products?: PlanProduct[] } | null | undefined,
|
|
products?: PlanProduct[]
|
|
) {
|
|
if (!shouldBlockTransportForHazardCert(plan, products)) return ''
|
|
return '该计划危化品证书尚未确认齐备'
|
|
}
|
|
|
|
export function buildMissingHazardCertMessage(products: PlanProduct[]) {
|
|
const missing = findMissingHazardCerts(products)
|
|
if (!missing.length) return ''
|
|
const names = missing.map(p => `「${p.productName}」`).join('、')
|
|
return `以下产品须上传购买证和合法使用证明:${names}`
|
|
}
|