2026-04-27 14:49:00 +08:00
|
|
|
export function safeTruncate(num, decimals = 2) {
|
|
|
|
|
if (Number.isNaN(num) || !Number.isFinite(num))
|
|
|
|
|
return '0.00'
|
|
|
|
|
|
|
|
|
|
const factor = 10 ** decimals
|
|
|
|
|
const scaled = Math.trunc(num * factor)
|
|
|
|
|
return (scaled / factor).toFixed(decimals)
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-28 16:12:14 +08:00
|
|
|
function toTruncatedCents(num) {
|
|
|
|
|
if (Number.isNaN(num) || !Number.isFinite(num))
|
|
|
|
|
return 0
|
|
|
|
|
return Math.trunc((num + Number.EPSILON) * 100)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function centsToFixed(cents) {
|
|
|
|
|
return (cents / 100).toFixed(2)
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-27 14:49:00 +08:00
|
|
|
function calculatePlatformOverpricingCost(price, config) {
|
|
|
|
|
if (price <= config.p_pricing_standard)
|
|
|
|
|
return 0
|
|
|
|
|
return (price - config.p_pricing_standard) * config.p_overpricing_ratio
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function calculateSuperiorOverpricingCost(price, config) {
|
|
|
|
|
if (config.a_overpricing_ratio <= 0)
|
|
|
|
|
return 0
|
|
|
|
|
if (price <= config.a_pricing_standard)
|
|
|
|
|
return 0
|
|
|
|
|
if (config.a_pricing_end <= config.a_pricing_standard)
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
const superiorRangeAmount = Math.min(price, config.a_pricing_end) - config.a_pricing_standard
|
|
|
|
|
return Math.max(0, superiorRangeAmount) * config.a_overpricing_ratio
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function calculatePromotionPricing(priceInput, config) {
|
|
|
|
|
if (!config)
|
|
|
|
|
return { costPrice: '0.00', promotionRevenue: '0.00' }
|
|
|
|
|
|
|
|
|
|
const price = Number(priceInput)
|
|
|
|
|
if (!Number.isFinite(price))
|
|
|
|
|
return { costPrice: '0.00', promotionRevenue: '0.00' }
|
|
|
|
|
|
|
|
|
|
const baseCost = Number(config.cost_price) || 0
|
|
|
|
|
const platformOverpricingCost = calculatePlatformOverpricingCost(price, config)
|
|
|
|
|
const superiorOverpricingCost = calculateSuperiorOverpricingCost(price, config)
|
|
|
|
|
const totalCost = baseCost + platformOverpricingCost + superiorOverpricingCost
|
2026-04-28 16:12:14 +08:00
|
|
|
const priceCents = toTruncatedCents(price)
|
|
|
|
|
const costCents = toTruncatedCents(totalCost)
|
|
|
|
|
const revenueCents = priceCents - costCents
|
2026-04-27 14:49:00 +08:00
|
|
|
|
|
|
|
|
return {
|
2026-04-28 16:12:14 +08:00
|
|
|
costPrice: centsToFixed(costCents),
|
|
|
|
|
promotionRevenue: centsToFixed(revenueCents),
|
2026-04-27 14:49:00 +08:00
|
|
|
}
|
|
|
|
|
}
|