import { formatPercentDisplay, roundHalfUp } from "@/lib/math"; import { prisma } from "@/lib/prisma"; export type MarkupType = "percent" | "fixed"; export interface MarkupRule { type: MarkupType; percent: number; fixedAmount: number; } export const DEFAULT_MARKUP_RULE: MarkupRule = { type: "percent", percent: 0, fixedAmount: 0, }; export interface MarkupResult { markupAmount: number; finalTotal: number; } /** 加价公式:百分比仅 raw_freight 参与;固定金额为每档固定叠加(GD-6 扩展) */ export function applyMarkup( rawFreight: number, rawTotal: number, rule: MarkupRule | number, ): MarkupResult { const normalized = typeof rule === "number" ? { type: "percent" as const, percent: rule, fixedAmount: 0 } : rule; const markupAmount = normalized.type === "fixed" ? roundHalfUp(normalized.fixedAmount, 2) : roundHalfUp(rawFreight * (normalized.percent / 100), 2); const finalTotal = roundHalfUp(rawTotal + markupAmount, 2); return { markupAmount, finalTotal }; } /** 读取客户加价规则;未配置默认 0%(BR-6.3) */ export async function getMarkupRule(customerId: string): Promise { const config = await prisma.markupConfig.findFirst({ where: { customerId, isDeleted: false }, select: { markupType: true, markupPercent: true, markupFixedAmount: true, }, }); if (!config) { return DEFAULT_MARKUP_RULE; } if (config.markupType === "fixed") { return { type: "fixed", percent: 0, fixedAmount: Number(config.markupFixedAmount ?? 0), }; } return { type: "percent", percent: Number(config.markupPercent), fixedAmount: 0, }; } /** @deprecated 请使用 getMarkupRule;保留兼容旧调用 */ export async function getMarkupPercent(customerId: string): Promise { const rule = await getMarkupRule(customerId); return rule.type === "percent" ? rule.percent : 0; } export interface RawQuoteTier { service_level: string; rate_option: string; carrier: string; transit_days: string; transit_description: string; raw_freight: number; surcharges: number; raw_total: number; } export interface MarkedUpQuoteTier extends RawQuoteTier { markup_percent: number; markup_amount: number; final_total: number; breakdown: Array<{ item: string; amount: number }>; } function markupBreakdownLabel(rule: MarkupRule): string { if (rule.type === "fixed") { return `运营加价(固定 ${rule.fixedAmount.toFixed(2)} USD)`; } return `运营加价(${formatPercentDisplay(rule.percent)})`; } /** 对单档报价应用加价并生成 breakdown */ export function applyMarkupToTier( tier: RawQuoteTier, rule: MarkupRule | number, ): MarkedUpQuoteTier { const normalized = typeof rule === "number" ? { type: "percent" as const, percent: rule, fixedAmount: 0 } : rule; const { markupAmount, finalTotal } = applyMarkup( tier.raw_freight, tier.raw_total, normalized, ); return { ...tier, markup_percent: normalized.type === "percent" ? normalized.percent : 0, markup_amount: markupAmount, final_total: finalTotal, breakdown: [ { item: "运费", amount: tier.raw_freight }, { item: "附加费", amount: tier.surcharges }, { item: markupBreakdownLabel(normalized), amount: markupAmount, }, ], }; } /** 对多档原始报价批量加价 */ export function applyMarkupToQuotes( quotes: RawQuoteTier[], rule: MarkupRule | number, ): MarkedUpQuoteTier[] { return quotes.map((tier) => applyMarkupToTier(tier, rule)); }