提交
This commit is contained in:
1 parent
98531845e4
commit
1ba1f38321
107 files changed
+65567
-36568
No files matched your search
@@ -0,0 +1,53 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { describe, it } from 'node:test'
|
||||
import {
|
||||
isProductOnShelf,
|
||||
partitionQuoteLinesForCopy,
|
||||
resolveSkippedProductDisplayName
|
||||
} from './crm-quote-copy-products'
|
||||
|
||||
describe('isProductOnShelf', () => {
|
||||
it('only on is shelf', () => {
|
||||
assert.equal(isProductOnShelf('on'), true)
|
||||
assert.equal(isProductOnShelf('off'), false)
|
||||
assert.equal(isProductOnShelf(undefined), false)
|
||||
assert.equal(isProductOnShelf(''), false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('partitionQuoteLinesForCopy', () => {
|
||||
it('keeps on, skips off/missing/failed', () => {
|
||||
const lines = [
|
||||
{ productId: '1', productName: '上架品' },
|
||||
{ productId: '2', productName: '下架品' },
|
||||
{ productId: '3', productName: '查不到' },
|
||||
{ productId: '4', productName: '无详情' }
|
||||
]
|
||||
const details = new Map<string, { status?: string; productName?: string } | null>([
|
||||
['1', { status: 'on', productName: '上架品' }],
|
||||
['2', { status: 'off', productName: '下架品' }],
|
||||
['3', null]
|
||||
// 4 absent
|
||||
])
|
||||
const { kept, skippedNames } = partitionQuoteLinesForCopy(lines, details)
|
||||
assert.deepEqual(
|
||||
kept.map((x) => x.productId),
|
||||
['1']
|
||||
)
|
||||
assert.deepEqual(skippedNames, ['下架品', '查不到', '无详情'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('resolveSkippedProductDisplayName', () => {
|
||||
it('prefers line name then detail name then id', () => {
|
||||
assert.equal(
|
||||
resolveSkippedProductDisplayName({ productId: '9', productName: '行名' }, { productName: '详名' }),
|
||||
'行名'
|
||||
)
|
||||
assert.equal(
|
||||
resolveSkippedProductDisplayName({ productId: '9' }, { productName: '详名' }),
|
||||
'详名'
|
||||
)
|
||||
assert.equal(resolveSkippedProductDisplayName({ productId: '9' }, null), '9')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,43 @@
|
||||
/** 报价单复制新增:按产品上下架状态过滤明细行 */
|
||||
|
||||
export function isProductOnShelf(status?: string | null): boolean {
|
||||
return String(status || '').trim() === 'on'
|
||||
}
|
||||
|
||||
export function resolveSkippedProductDisplayName(
|
||||
line: { productId?: string | number; productName?: string },
|
||||
detail?: { productName?: string } | null
|
||||
): string {
|
||||
const fromLine = String(line.productName || '').trim()
|
||||
if (fromLine) return fromLine
|
||||
const fromDetail = String(detail?.productName || '').trim()
|
||||
if (fromDetail) return fromDetail
|
||||
return String(line.productId ?? '')
|
||||
}
|
||||
|
||||
/**
|
||||
* @param detailsByProductId key = String(productId);值为详情对象;null/缺省视为不可带入
|
||||
*/
|
||||
export function partitionQuoteLinesForCopy<
|
||||
T extends { productId?: string | number; productName?: string }
|
||||
>(
|
||||
lines: T[],
|
||||
detailsByProductId: Map<string, { status?: string; productName?: string } | null>
|
||||
): { kept: T[]; skippedNames: string[] } {
|
||||
const kept: T[] = []
|
||||
const skippedNames: string[] = []
|
||||
for (const line of lines) {
|
||||
const id = String(line.productId ?? '').trim()
|
||||
if (!id) {
|
||||
skippedNames.push(resolveSkippedProductDisplayName(line, null))
|
||||
continue
|
||||
}
|
||||
const detail = detailsByProductId.has(id) ? detailsByProductId.get(id)! : undefined
|
||||
if (detail && isProductOnShelf(detail.status)) {
|
||||
kept.push(line)
|
||||
} else {
|
||||
skippedNames.push(resolveSkippedProductDisplayName(line, detail ?? null))
|
||||
}
|
||||
}
|
||||
return { kept, skippedNames }
|
||||
}
|
||||
@@ -492,7 +492,7 @@ export function getPlPlanCompleteStatusLabel(status?: string) {
|
||||
}
|
||||
|
||||
export function getPlFreightTypeLabel(type?: string) {
|
||||
const map: Record<string, string> = { by_weight: '按重量', by_trip: '按趟' }
|
||||
const map: Record<string, string> = { by_weight: '按重量', by_trip: '按趟次' }
|
||||
return type ? map[type] || type : '—'
|
||||
}
|
||||
|
||||
@@ -578,6 +578,63 @@ export function getPlFuelRegisterStatusTagType(status: string) {
|
||||
return map[status] || 'info'
|
||||
}
|
||||
|
||||
/** 附件 URL 逗号串 → 非空个数 */
|
||||
export function countPlAttachmentUrls(raw?: string | null): number {
|
||||
return String(raw || '')
|
||||
.split(',')
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean).length
|
||||
}
|
||||
|
||||
/** 加油登记发微信群纯文本(含库内序号、附件个数) */
|
||||
export function buildFuelRegisterCopyText(row: {
|
||||
seqNo?: number | null
|
||||
registerNo?: string | null
|
||||
fuelCategory?: string | null
|
||||
registerDate?: string | null
|
||||
registrantName?: string | null
|
||||
licensePlate?: string | null
|
||||
odometerKm?: number | null
|
||||
fuelLiters?: number | null
|
||||
fuelTons?: number | null
|
||||
attachmentUrls?: string | null
|
||||
remark?: string | null
|
||||
}): string {
|
||||
const dash = '—'
|
||||
const seq =
|
||||
row.seqNo != null && Number.isFinite(Number(row.seqNo)) ? String(row.seqNo) : dash
|
||||
const liters =
|
||||
row.fuelLiters != null && Number.isFinite(Number(row.fuelLiters))
|
||||
? Number(row.fuelLiters).toFixed(2)
|
||||
: dash
|
||||
let tons = dash
|
||||
if (row.fuelTons != null && Number.isFinite(Number(row.fuelTons))) {
|
||||
tons = Number(row.fuelTons).toFixed(3)
|
||||
} else if (row.fuelLiters != null && Number.isFinite(Number(row.fuelLiters))) {
|
||||
tons = (Number(row.fuelLiters) / 1176).toFixed(3)
|
||||
}
|
||||
const odometer =
|
||||
row.odometerKm != null && Number.isFinite(Number(row.odometerKm))
|
||||
? `${Number(row.odometerKm).toFixed(1)} KM`
|
||||
: dash
|
||||
const plate = row.licensePlate?.trim() || dash
|
||||
const lines = [
|
||||
`【${plate} - 加油登记】`,
|
||||
`序号:${seq}`,
|
||||
`登记单号:${row.registerNo || dash}`,
|
||||
`加油类别:${getPlFuelCategoryLabel(String(row.fuelCategory || '')) || dash}`,
|
||||
`日期:${row.registerDate || dash}`,
|
||||
`登记人:${row.registrantName || dash}`,
|
||||
`车牌号:${plate}`,
|
||||
`期初公里数:${odometer}`,
|
||||
`加油升数:${liters === dash ? dash : `${liters} L`}`,
|
||||
`加油/吨:${tons}`,
|
||||
`附件个数:${countPlAttachmentUrls(row.attachmentUrls)}`,
|
||||
`备注:${row.remark?.trim() || dash}`
|
||||
]
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
export function getPlRechargeApplyStatusLabel(status: string) {
|
||||
const map: Record<string, string> = {
|
||||
pending: '待发放',
|
||||
|
||||
Reference in new issue
Block a user