GuDingZiChan/backend/src/controllers/__tests__/statisticsController.dashboard.test.ts

190 lines
7.8 KiB
TypeScript

import test from 'node:test'
import assert from 'node:assert/strict'
import prisma from '../../utils/prisma'
import { getDashboardStats, getValueStatistics } from '../statisticsController'
test('首页统计应排除已报废库存、完整覆盖在册状态并使用上海自然日', async () => {
const originalAssetTypeFindMany = prisma.assetType.findMany
const originalEquipmentGroupBy = prisma.equipment.groupBy
const originalEquipmentFindMany = prisma.equipment.findMany
const originalEquipmentAggregate = prisma.equipment.aggregate
const originalEquipmentCount = prisma.equipment.count
const originalBorrowRecordFindMany = prisma.borrowRecord.findMany
const borrowRanges: any[] = []
;(prisma.assetType.findMany as any) = async () => [{ name: '内存条' }]
;(prisma.equipment.groupBy as any) = async (args: any) => {
if (args.by.length === 1 && args.by[0] === 'status') {
return [
{ status: '可用', _sum: { total_quantity: 1122, remaining_quantity: 1122, total_value: 424805, borrowed_value: 0, available_value: 424805 } },
{ status: '已借出', _sum: { total_quantity: 4507, remaining_quantity: 0, total_value: 2848258.44, borrowed_value: 2848258.44, available_value: 0 } },
{ status: '待报废', _sum: { total_quantity: 1, remaining_quantity: 1, total_value: 0, borrowed_value: 0, available_value: 0 } },
{ status: '已丢失', _sum: { total_quantity: 3, remaining_quantity: 0, total_value: 300, borrowed_value: 0, available_value: 0 } },
{ status: '已报废', _sum: { total_quantity: 127, remaining_quantity: 127, total_value: 83257, borrowed_value: 0, available_value: 0 } }
]
}
if (args.by.includes('status')) {
return [
{ equipment_type: '显示器', status: '可用', _sum: { total_quantity: 10, remaining_quantity: 10 } },
{ equipment_type: '显示器', status: '待报废', _sum: { total_quantity: 1, remaining_quantity: 1 } },
{ equipment_type: '仅丢失资产类型', status: '已丢失', _sum: { total_quantity: 3, remaining_quantity: 0 } }
]
}
return [{ equipment_type: '显示器', _sum: { remaining_quantity: 8 } }]
}
;(prisma.equipment.findMany as any) = async () => [
{
status: '可用',
total_value: 424805,
borrowed_value: 0,
available_value: 424805,
total_value_with_children: 0
},
{
status: '已借出',
total_value: 2848998.44,
borrowed_value: 2848998.44,
available_value: 0,
total_value_with_children: 0
}
]
;(prisma.equipment.aggregate as any) = async (args: any) => {
assert.deepEqual(args.where.status.notIn, ['已报废', '已丢失'])
return { _count: { id: 2057 }, _sum: { total_quantity: 2057 } }
}
;(prisma.equipment.count as any) = async () => 3
;(prisma.borrowRecord.findMany as any) = async (args: any) => {
borrowRanges.push(args.where.borrow_time || args.where.return_time)
if (args.where.return_time) {
assert.deepEqual(args.where.return_condition, { not: '丢失' })
}
return args.where.borrow_time
? [{ children_snapshot: '[{"unit_price":20}]', equipment: { unit_price: 100 } }]
: []
}
const state = { status: 200, body: null as any }
const response = {
status(code: number) {
state.status = code
return this
},
json(body: any) {
state.body = body
return this
}
}
try {
await getDashboardStats({} as any, response as any)
assert.equal(state.status, 200)
assert.equal(state.body.data.total_equipment, 5630)
assert.equal(state.body.data.root_asset_records, 2057)
assert.equal(state.body.data.accessory_equipment, 3573)
assert.equal(state.body.data.available_equipment, 1122)
assert.equal(state.body.data.borrowed_equipment, 4507)
assert.equal(state.body.data.pending_disposal_equipment, 1)
assert.equal(state.body.data.disposed_equipment, 127)
assert.equal(state.body.data.lost_equipment, 3)
assert.equal(state.body.data.other_equipment, 0)
const lostOnlyType = state.body.data.inventory_by_type.find((row: any) => row.equipment_type === '仅丢失资产类型')
assert.equal(lostOnlyType.total_quantity, 0)
assert.equal(lostOnlyType.lost_quantity, 3)
assert.equal(lostOnlyType.other_quantity, 0)
assert.equal(state.body.data.borrowed_without_active_record, 3)
assert.equal(state.body.data.today_borrow, 1)
assert.equal(state.body.data.today_return, 0)
assert.equal(state.body.data.today_borrow_value, 120)
assert.equal(state.body.data.business_timezone, 'Asia/Shanghai')
assert.equal(state.body.data.inventory_scope, 'current_excluding_disposed_and_lost')
assert.equal(state.body.data.value_scope, 'book_value_excluding_disposed_including_lost')
assert.equal(state.body.data.total_value, 3273363.44)
assert.equal(state.body.data.borrowed_value, 2848258.44)
assert.equal(
state.body.data.available_equipment +
state.body.data.borrowed_equipment +
state.body.data.maintenance_equipment +
state.body.data.pending_disposal_equipment +
state.body.data.damaged_equipment +
state.body.data.other_equipment,
state.body.data.total_equipment
)
assert.ok(Math.abs(state.body.data.usage_rate - 80.06750755018653) < 0.000001)
assert.ok(Math.abs(state.body.data.value_usage_rate - 87.021180377732) < 0.000001)
assert.equal(borrowRanges.length, 2)
for (const range of borrowRanges) {
assert.equal(range.gte.getUTCHours(), 16)
assert.equal(range.lt.getTime() - range.gte.getTime(), 24 * 60 * 60 * 1000)
}
} finally {
;(prisma.assetType.findMany as any) = originalAssetTypeFindMany
;(prisma.equipment.groupBy as any) = originalEquipmentGroupBy
;(prisma.equipment.findMany as any) = originalEquipmentFindMany
;(prisma.equipment.aggregate as any) = originalEquipmentAggregate
;(prisma.equipment.count as any) = originalEquipmentCount
;(prisma.borrowRecord.findMany as any) = originalBorrowRecordFindMany
}
})
test('价值统计应按当前资产本体汇总并忽略已报废和过期组合金额缓存', async () => {
const originalEquipmentFindMany = prisma.equipment.findMany
let capturedWhere: any
;(prisma.equipment.findMany as any) = async (args: any) => {
capturedWhere = args.where
return [
{
equipment_name: '显示器',
equipment_type: '显示器',
unit_price: 1500,
total_quantity: 1,
total_value: 1500,
borrowed_value: 1500,
available_value: 0,
total_value_with_children: 2240,
status: '已借出'
},
{
equipment_name: '扩展坞',
equipment_type: '扩展坞',
unit_price: 740,
total_quantity: 1,
total_value: 740,
borrowed_value: 0,
available_value: 740,
total_value_with_children: 0,
status: '可用'
}
]
}
const state = { status: 200, body: null as any }
const response = {
status(code: number) {
state.status = code
return this
},
json(body: any) {
state.body = body
return this
}
}
try {
await getValueStatistics({ query: { start_date: '2026-07-17', end_date: '2026-07-17' } } as any, response as any)
assert.equal(capturedWhere.status.not, '已报废')
assert.equal(capturedWhere.created_at.gte.toISOString(), '2026-07-16T16:00:00.000Z')
assert.equal(capturedWhere.created_at.lt.toISOString(), '2026-07-17T16:00:00.000Z')
assert.equal(state.body.data.total_value, 2240)
assert.equal(state.body.data.borrowed_value, 1500)
assert.equal(state.body.data.available_value, 740)
assert.equal(state.body.data.value_by_type.length, 2)
assert.equal(state.body.data.top_equipment[0].item_value, 1500)
assert.equal(state.body.data.top_equipment[0].stock_total_value, 1500)
} finally {
;(prisma.equipment.findMany as any) = originalEquipmentFindMany
}
})