JGJS2026/src/lib/pricingScaleFee.ts
2026-03-07 11:47:07 +08:00

120 lines
4.0 KiB
TypeScript

import { getBasicFeeFromScale } from '@/sql'
import { addNumbers, roundTo, toDecimal } from '@/lib/decimal'
import { toFiniteNumberOrNull } from '@/lib/number'
type ScaleMode = 'cost' | 'area'
export interface ScaleFeeSplitResult {
basic: number
optional: number
total: number
basicFormula: string
optionalFormula: string
}
export const getBenchmarkBudgetSplitByScale = (
value: unknown,
mode: ScaleMode
): ScaleFeeSplitResult | null => {
const scaleValue = toFiniteNumberOrNull(value)
const result = getBasicFeeFromScale(scaleValue, mode)
if (!result) return null
const basic = roundTo(result.basic, 2)
const optional = roundTo(result.optional, 2)
const basicFormula = typeof result.basicFormula === 'string' ? result.basicFormula : ''
const optionalFormula = typeof result.optionalFormula === 'string' ? result.optionalFormula : ''
return {
basic,
optional,
total: roundTo(addNumbers(basic, optional), 2),
basicFormula,
optionalFormula
}
}
export const getBenchmarkBudgetByScale = (value: unknown, mode: ScaleMode) => {
const splitResult = getBenchmarkBudgetSplitByScale(value, mode)
return splitResult ? splitResult.total : null
}
export const getScaleBudgetFeeSplit = (params: {
benchmarkBudgetBasic: unknown
benchmarkBudgetOptional: unknown
majorFactor: unknown
consultCategoryFactor: unknown
workStageFactor?: unknown
workRatio?: unknown
}): ScaleFeeSplitResult | null => {
const hasWorkStageFactor = Object.prototype.hasOwnProperty.call(params, 'workStageFactor')
const hasWorkRatio = Object.prototype.hasOwnProperty.call(params, 'workRatio')
const benchmarkBudgetBasic = toFiniteNumberOrNull(params.benchmarkBudgetBasic)
const benchmarkBudgetOptional = toFiniteNumberOrNull(params.benchmarkBudgetOptional)
const majorFactor = toFiniteNumberOrNull(params.majorFactor)
const consultCategoryFactor = toFiniteNumberOrNull(params.consultCategoryFactor)
const workStageFactor = hasWorkStageFactor ? toFiniteNumberOrNull(params.workStageFactor) : 1
const workRatio = hasWorkRatio ? toFiniteNumberOrNull(params.workRatio) : 100
if (
benchmarkBudgetBasic == null ||
benchmarkBudgetOptional == null ||
majorFactor == null ||
consultCategoryFactor == null ||
workStageFactor == null ||
workRatio == null
) {
return null
}
const multiplier = toDecimal(consultCategoryFactor)
.mul(majorFactor)
.mul(workStageFactor)
.mul(workRatio)
.div(100)
const roundedBenchmarkBudget = roundTo(addNumbers(benchmarkBudgetBasic, benchmarkBudgetOptional), 2)
const basic = roundTo(toDecimal(benchmarkBudgetBasic).mul(multiplier), 2)
const optional = roundTo(toDecimal(benchmarkBudgetOptional).mul(multiplier), 2)
return {
basic,
optional,
total: roundTo(toDecimal(roundedBenchmarkBudget).mul(multiplier), 2),
basicFormula: '',
optionalFormula: ''
}
}
export const getScaleBudgetFee = (params: {
benchmarkBudget: unknown
majorFactor: unknown
consultCategoryFactor: unknown
workStageFactor?: unknown
workRatio?: unknown
}) => {
const hasWorkStageFactor = Object.prototype.hasOwnProperty.call(params, 'workStageFactor')
const hasWorkRatio = Object.prototype.hasOwnProperty.call(params, 'workRatio')
const benchmarkBudget = toFiniteNumberOrNull(params.benchmarkBudget)
const majorFactor = toFiniteNumberOrNull(params.majorFactor)
const consultCategoryFactor = toFiniteNumberOrNull(params.consultCategoryFactor)
const workStageFactor = hasWorkStageFactor ? toFiniteNumberOrNull(params.workStageFactor) : 1
const workRatio = hasWorkRatio ? toFiniteNumberOrNull(params.workRatio) : 100
if (
benchmarkBudget == null ||
majorFactor == null ||
consultCategoryFactor == null ||
workStageFactor == null ||
workRatio == null
) {
return null
}
const roundedBenchmarkBudget = roundTo(benchmarkBudget, 2)
const multiplier = toDecimal(consultCategoryFactor)
.mul(majorFactor)
.mul(workStageFactor)
.mul(workRatio)
.div(100)
return roundTo(toDecimal(roundedBenchmarkBudget).mul(multiplier), 2)
}