239 lines
6.7 KiB
TypeScript
239 lines
6.7 KiB
TypeScript
import type { Prisma, PrismaClient } from '@prisma/client'
|
|
|
|
type EquipmentClient = PrismaClient | Prisma.TransactionClient
|
|
|
|
const NON_AVAILABLE_STATUSES = new Set(['维护中', '待报废', '已报废', '已损坏'])
|
|
|
|
const toSafeNumber = (value: unknown) => {
|
|
if (value === null || value === undefined || value === '') {
|
|
return 0
|
|
}
|
|
|
|
const numericValue = Number(value)
|
|
return Number.isNaN(numericValue) ? 0 : numericValue
|
|
}
|
|
|
|
const clampRemainingQuantity = (totalQuantity: number, remainingQuantity: number) => {
|
|
if (remainingQuantity < 0) return 0
|
|
if (remainingQuantity > totalQuantity) return totalQuantity
|
|
return remainingQuantity
|
|
}
|
|
|
|
export const calculateEquipmentValues = ({
|
|
unitPrice,
|
|
totalQuantity,
|
|
remainingQuantity,
|
|
status
|
|
}: {
|
|
unitPrice: number
|
|
totalQuantity: number
|
|
remainingQuantity: number
|
|
status?: string | null
|
|
}) => {
|
|
const normalizedUnitPrice = toSafeNumber(unitPrice)
|
|
const normalizedTotalQuantity = Math.max(0, Math.floor(toSafeNumber(totalQuantity)))
|
|
const normalizedRemainingQuantity = clampRemainingQuantity(
|
|
normalizedTotalQuantity,
|
|
Math.floor(toSafeNumber(remainingQuantity))
|
|
)
|
|
const totalValue = normalizedUnitPrice * normalizedTotalQuantity
|
|
|
|
if (status && NON_AVAILABLE_STATUSES.has(status)) {
|
|
return {
|
|
total_value: totalValue,
|
|
borrowed_value: 0,
|
|
available_value: 0
|
|
}
|
|
}
|
|
|
|
const borrowedQuantity = Math.max(normalizedTotalQuantity - normalizedRemainingQuantity, 0)
|
|
|
|
return {
|
|
total_value: totalValue,
|
|
borrowed_value: normalizedUnitPrice * borrowedQuantity,
|
|
available_value: normalizedUnitPrice * normalizedRemainingQuantity
|
|
}
|
|
}
|
|
|
|
export const sumBundleChildrenValue = (
|
|
children: Array<{
|
|
unit_price?: number | string | null
|
|
quantity?: number | string | null
|
|
}>
|
|
) => {
|
|
return children.reduce((sum, child) => {
|
|
const quantity = Math.max(1, Math.floor(toSafeNumber(child.quantity) || 1))
|
|
return sum + toSafeNumber(child.unit_price) * quantity
|
|
}, 0)
|
|
}
|
|
|
|
export const deriveParentBaseUnitPrice = (bundleTotalPrice: unknown, childrenTotalValue: number) => {
|
|
const normalizedBundleTotalPrice = toSafeNumber(bundleTotalPrice)
|
|
const normalizedChildrenTotalValue = toSafeNumber(childrenTotalValue)
|
|
|
|
if (normalizedChildrenTotalValue > normalizedBundleTotalPrice) {
|
|
throw new Error('整机总价不能小于子资产总价,请先调整价格后再保存')
|
|
}
|
|
|
|
return normalizedBundleTotalPrice - normalizedChildrenTotalValue
|
|
}
|
|
|
|
export const calculateChildrenTotalValueFromRecords = (
|
|
children: Array<{ unit_price?: unknown }>
|
|
) => {
|
|
return children.reduce((sum, child) => sum + toSafeNumber(child.unit_price), 0)
|
|
}
|
|
|
|
export const refreshParentTotalValueWithChildren = async (client: EquipmentClient, parentId: number) => {
|
|
const parent = await client.equipment.findUnique({
|
|
where: { id: parentId },
|
|
include: {
|
|
children: {
|
|
select: {
|
|
unit_price: true
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
if (!parent) {
|
|
return
|
|
}
|
|
|
|
const totalValueWithChildren =
|
|
toSafeNumber(parent.unit_price) + calculateChildrenTotalValueFromRecords(parent.children)
|
|
|
|
await client.equipment.update({
|
|
where: { id: parentId },
|
|
data: {
|
|
total_value_with_children: totalValueWithChildren
|
|
}
|
|
})
|
|
}
|
|
|
|
export const syncMountedChildrenState = async (
|
|
client: EquipmentClient,
|
|
parentId: number,
|
|
targetStatus: '可用' | '已借出' | '维护中' | '待报废' | '已报废'
|
|
) => {
|
|
const children = await client.equipment.findMany({
|
|
where: { parent_id: parentId },
|
|
select: {
|
|
id: true,
|
|
unit_price: true,
|
|
total_quantity: true
|
|
}
|
|
})
|
|
|
|
for (const child of children) {
|
|
const remainingQuantity = targetStatus === '已借出' ? 0 : Number(child.total_quantity)
|
|
const values = calculateEquipmentValues({
|
|
unitPrice: Number(child.unit_price),
|
|
totalQuantity: Number(child.total_quantity),
|
|
remainingQuantity,
|
|
status: targetStatus
|
|
})
|
|
|
|
await client.equipment.update({
|
|
where: { id: child.id },
|
|
data: {
|
|
status: targetStatus,
|
|
remaining_quantity: remainingQuantity,
|
|
total_value: values.total_value,
|
|
borrowed_value: values.borrowed_value,
|
|
available_value: values.available_value
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
export const getDisplayEquipmentValue = (equipment: {
|
|
unit_price?: unknown
|
|
total_value_with_children?: unknown
|
|
}) => {
|
|
const totalValueWithChildren = toSafeNumber(equipment.total_value_with_children)
|
|
if (totalValueWithChildren > 0) {
|
|
return totalValueWithChildren
|
|
}
|
|
|
|
return toSafeNumber(equipment.unit_price)
|
|
}
|
|
|
|
export const getEquipmentDisplayTotalValue = (equipment: {
|
|
total_value?: unknown
|
|
total_value_with_children?: unknown
|
|
}) => {
|
|
const totalValueWithChildren = toSafeNumber(equipment.total_value_with_children)
|
|
if (totalValueWithChildren > 0) {
|
|
return totalValueWithChildren
|
|
}
|
|
|
|
return toSafeNumber(equipment.total_value)
|
|
}
|
|
|
|
export const getEquipmentDisplayItemValue = (equipment: {
|
|
unit_price?: unknown
|
|
total_quantity?: unknown
|
|
total_value?: unknown
|
|
total_value_with_children?: unknown
|
|
}) => {
|
|
const displayTotalValue = getEquipmentDisplayTotalValue(equipment)
|
|
const totalQuantity = Math.max(1, Math.floor(toSafeNumber(equipment.total_quantity) || 1))
|
|
|
|
if (displayTotalValue <= 0) {
|
|
return toSafeNumber(equipment.unit_price)
|
|
}
|
|
|
|
return displayTotalValue / totalQuantity
|
|
}
|
|
|
|
export const getEquipmentDisplayBorrowedValue = (equipment: {
|
|
borrowed_value?: unknown
|
|
total_value_with_children?: unknown
|
|
status?: unknown
|
|
}) => {
|
|
const totalValueWithChildren = toSafeNumber(equipment.total_value_with_children)
|
|
|
|
if (totalValueWithChildren > 0) {
|
|
return equipment.status === '已借出' ? totalValueWithChildren : 0
|
|
}
|
|
|
|
return toSafeNumber(equipment.borrowed_value)
|
|
}
|
|
|
|
export const getEquipmentDisplayAvailableValue = (equipment: {
|
|
available_value?: unknown
|
|
total_value_with_children?: unknown
|
|
status?: unknown
|
|
}) => {
|
|
const totalValueWithChildren = toSafeNumber(equipment.total_value_with_children)
|
|
|
|
if (totalValueWithChildren > 0) {
|
|
return equipment.status === '可用' ? totalValueWithChildren : 0
|
|
}
|
|
|
|
return toSafeNumber(equipment.available_value)
|
|
}
|
|
|
|
export const getEquipmentMountedChildrenValue = (equipment: {
|
|
total_value?: unknown
|
|
total_value_with_children?: unknown
|
|
}) => {
|
|
const displayTotalValue = getEquipmentDisplayTotalValue(equipment)
|
|
const ownTotalValue = toSafeNumber(equipment.total_value)
|
|
return Math.max(displayTotalValue - ownTotalValue, 0)
|
|
}
|
|
|
|
export const sumSnapshotChildrenValue = (snapshot?: string | null) => {
|
|
if (!snapshot) {
|
|
return 0
|
|
}
|
|
|
|
try {
|
|
const children = JSON.parse(snapshot) as Array<{ unit_price?: unknown }>
|
|
return calculateChildrenTotalValueFromRecords(children)
|
|
} catch {
|
|
return 0
|
|
}
|
|
}
|