Hello from MCP server

List Files | Just Commands | Repo | Logs

← back |
/**
 * TNFR Pricing Formula with Implied Rate
 *
 * This formula is similar to the legacy formula, but captures a new value
 * "Implied Rate" which is used to price additional hours on the job.
 *
 * The algorithm:
 * 1. Calculate material fee using tiered markup function
 * 2. Calculate base time fee using hourly rate
 * 3. Add service call fee to get trip fee
 * 4. Apply tier multiplier to get tier price
 * 5. Calculate implied hourly rate from tier price (for additional time)
 * 6. Apply additional time using implied rate
 * 7. Apply additional material with its own markup
 * 8. Calculate final price with SA discount
 */

export interface PricingVars {
  // Input variables
  material: number;           // Base material cost
  salesTax: number;           // Sales tax multiplier (e.g., 1.07 for 7%)
  hourlyFee: number;          // Base hourly rate
  serviceCallFee: number;     // Trip/service call fee
  multiplier: number;         // Tier multiplier (e.g., 1.0 for band-aid, higher for platinum)
  saDiscount: number;         // SA discount multiplier (e.g., 0.9 for 10% off)
  standardDeduction: number;  // Standard deduction multiplier applied after calculation (e.g., 0.9 for 10% off)
  additionalHourDiscount: number; // Discount multiplier for additional hours (e.g., 0.9 for 10% off)
  time: number;               // Base time in hours
  additionalTime: number;     // Extra time in hours
  additionalMaterial: number; // Extra material cost

  // Markup scale - array of [threshold, multiplier] pairs
  // Sorted descending by threshold
  markupScale: [number, number][];
}

/**
 * Default standard deduction (0% off - no deduction)
 * Change this value to adjust the standard deduction across all pricing
 */
export const DEFAULT_STANDARD_DEDUCTION = 1.0;

/**
 * Default additional hour discount (60% off)
 * Change this value to adjust the discount applied to additional hours
 */
export const DEFAULT_ADDITIONAL_HOUR_DISCOUNT = 0.4;

export interface PricingResult {
  // Intermediate values
  taxedMaterialCost: number;
  markupMultiplier: number;
  materialFee: number;
  timeFee: number;
  combinedFee: number;
  tripFee: number;
  tierPrice: number;

  // Implied rate calculation
  impliedTimeFee: number;
  impliedHourlyRate: number;

  // Additional costs
  additionalMaterialTaxed: number;
  additionalMaterialMarkup: number;
  additionalMaterialFee: number;
  additionalTimeFee: number;           // Fee for additional time before discount
  additionalTimeFeeDiscounted: number; // Fee for additional time after discount

  // Totals
  totalTime: number;
  totalTimeFee: number;
  totalMaterialFee: number;
  leveledPrice: number;
  priceAfterDeduction: number;  // Price after standard deduction
  finalPrice: number;           // Final price after SA discount
}

/**
 * Default markup scale from legacy formula
 * Format: [threshold, multiplier]
 * When material cost >= threshold, use that multiplier
 */
export const DEFAULT_MARKUP_SCALE: [number, number][] = [
  [6.571805718, 1.65],
  [3.943083431, 1.75],
  [2.628722287, 2],
  [1.577233372, 2.25],
  [1.051488915, 2.5],
  [0.5257444574, 2.75],
  [0.2628722287, 3],
  [0.1314361144, 3.5],
  [0, 4],
];

/**
 * Tiered markup function
 * Returns the markup multiplier based on material cost
 */
function markupFunction(materialCost: number, scale: [number, number][]): number {
  const match = scale.find(([threshold]) => threshold <= materialCost);
  return match ? match[1] : scale[scale.length - 1][1];
}

/**
 * Create default pricing variables
 */
export function createPricingVars(overrides: Partial<PricingVars> = {}): PricingVars {
  return {
    material: 0,
    salesTax: 1,
    hourlyFee: 5.262,
    serviceCallFee: 0,
    multiplier: 1,
    saDiscount: 1,
    standardDeduction: DEFAULT_STANDARD_DEDUCTION,
    additionalHourDiscount: DEFAULT_ADDITIONAL_HOUR_DISCOUNT,
    time: 0,
    additionalTime: 0,
    additionalMaterial: 0,
    markupScale: DEFAULT_MARKUP_SCALE,
    ...overrides,
  };
}

/**
 * Calculate price using the TNFR pricing formula with implied rate
 *
 * This formula calculates an "implied hourly rate" from the tier price,
 * which is then used to price any additional time. This ensures that
 * additional hours are priced consistently with the tier's markup.
 *
 * Price flow:
 * tierPrice + additionalTimeFeeDiscounted + additionalMaterialFee = leveledPrice
 * leveledPrice -> priceAfterDeduction (standard deduction) -> finalPrice (SA discount)
 */
export function calculateWithImpliedRate(vars: PricingVars): PricingResult {
  const {
    material,
    salesTax,
    hourlyFee,
    serviceCallFee,
    multiplier,
    saDiscount,
    standardDeduction,
    additionalHourDiscount,
    time,
    additionalTime,
    additionalMaterial,
    markupScale,
  } = vars;

  // Step 1: Calculate material fee
  const taxedMaterialCost = material * salesTax;
  const markupMultiplier = markupFunction(material, markupScale);
  const materialFee = markupMultiplier * taxedMaterialCost;

  // Step 2: Calculate time fee
  const timeFee = time * hourlyFee;

  // Step 3: Combined fee
  const combinedFee = materialFee + timeFee;

  // Step 4: Add trip fee
  const tripFee = combinedFee + serviceCallFee;

  // Step 5: Apply tier multiplier
  const tierPrice = tripFee * multiplier;

  // Step 6: Calculate implied hourly rate
  let impliedTimeFee = 0;
  let impliedHourlyRate = hourlyFee;

  if (additionalTime > 0 && time > 0) {
    // Implied time fee is the tier price minus material contribution
    impliedTimeFee = tierPrice - materialFee;
    // Implied hourly rate is the rate that would produce this time fee
    impliedHourlyRate = impliedTimeFee / time;
  }

  // Step 7: Calculate additional material fee
  const additionalMaterialTaxed = additionalMaterial * salesTax;
  const additionalMaterialMarkup = markupFunction(additionalMaterial, markupScale);
  const additionalMaterialFee = additionalMaterialMarkup * additionalMaterialTaxed;

  // Step 8: Calculate additional time fee with discount
  const additionalTimeFee = additionalTime * impliedHourlyRate;
  const additionalTimeFeeDiscounted = additionalTimeFee * additionalHourDiscount;

  // Step 9: Calculate totals
  const totalTime = time + additionalTime;
  const totalTimeFee = (time * hourlyFee * multiplier) + additionalTimeFeeDiscounted;
  const totalMaterialFee = materialFee + additionalMaterialFee;

  // Step 10: Calculate leveled price
  // Base tier price plus discounted additional time plus additional material
  const leveledPrice = tierPrice + additionalTimeFeeDiscounted + additionalMaterialFee;

  // Step 11: Apply standard deduction (e.g., 10% off)
  const priceAfterDeduction = leveledPrice * standardDeduction;

  // Step 12: Apply SA discount
  const finalPrice = priceAfterDeduction * saDiscount;

  return {
    taxedMaterialCost,
    markupMultiplier,
    materialFee,
    timeFee,
    combinedFee,
    tripFee,
    tierPrice,
    impliedTimeFee,
    impliedHourlyRate,
    additionalMaterialTaxed,
    additionalMaterialMarkup,
    additionalMaterialFee,
    additionalTimeFee,
    additionalTimeFeeDiscounted,
    totalTime,
    totalTimeFee,
    totalMaterialFee,
    leveledPrice,
    priceAfterDeduction,
    finalPrice,
  };
}

/**
 * Simplified calculation function that returns just the final price
 * Compatible with the legacy calculatePrice function signature
 */
export function calculatePrice(
  materialCost: number,
  timeCost: number,
  orgVars: {
    hourlyFee: number;
    serviceCallFee: number;
    saDiscount: number;
    salesTax: number;
  },
  multiplier: number = 1,
  additionalTime: number = 0,
  additionalMaterial: number = 0,
): number {
  const vars = createPricingVars({
    material: materialCost,
    time: timeCost,
    hourlyFee: orgVars.hourlyFee,
    serviceCallFee: orgVars.serviceCallFee,
    saDiscount: orgVars.saDiscount,
    salesTax: orgVars.salesTax,
    multiplier,
    additionalTime,
    additionalMaterial,
  });

  const result = calculateWithImpliedRate(vars);
  return result.finalPrice;
}

/**
 * Get the implied hourly rate for a tier
 * This is useful for displaying what rate additional hours will be charged at
 */
export function getImpliedRate(
  materialCost: number,
  timeCost: number,
  orgVars: {
    hourlyFee: number;
    serviceCallFee: number;
    salesTax: number;
  },
  multiplier: number = 1,
): number {
  const vars = createPricingVars({
    material: materialCost,
    time: timeCost,
    hourlyFee: orgVars.hourlyFee,
    serviceCallFee: orgVars.serviceCallFee,
    salesTax: orgVars.salesTax,
    multiplier,
    additionalTime: 1, // Need > 0 to trigger implied rate calculation
  });

  const result = calculateWithImpliedRate(vars);
  return result.impliedHourlyRate;
}

/**
 * Documentation for the TNFR Pricing Formula
 */
export const docs = `
# TNFR Pricing Formula with Implied Rate

This module implements a tiered pricing system for service jobs that calculates prices based on materials, labor time, and various multipliers.

## Currency Note

All monetary values (material, hourlyFee, serviceCallFee, etc.) are represented in a **base currency unit** tied to the price of silver in August 2025. Use the currency conversion utilities available in the framework to convert to display currencies.

## Algorithm Flow

1. **Material Fee**: Base material × sales tax × tiered markup (higher markup for cheaper materials)
2. **Time Fee**: Hours × hourly rate
3. **Trip Fee**: Material fee + time fee + service call fee
4. **Tier Price**: Trip fee × tier multiplier (e.g., "Good/Better/Best" pricing tiers)
5. **Implied Rate**: Derives an hourly rate from the tier price for pricing additional hours
6. **Additional Costs**: Extra time (discounted) + extra materials (with markup)
7. **Final Price**: Apply standard deduction, then SA discount

## Input Variables & Defaults

| Variable | Default | Description |
|----------|---------|-------------|
| material | 0 | Base material cost (in base currency) |
| salesTax | 1 | Sales tax multiplier (1 = no tax, 1.07 = 7% tax) |
| hourlyFee | 5.262 | Base hourly rate (in base currency) |
| serviceCallFee | 0 | Trip/service call fee (in base currency) |
| multiplier | 1 | Tier multiplier (1 = base tier) |
| saDiscount | 1 | SA discount multiplier (1 = no discount, 0.9 = 10% off) |
| standardDeduction | 1.0 | Standard deduction multiplier (1 = no deduction) |
| additionalHourDiscount | 0.4 | Additional hours discount (0.4 = 60% off) |
| time | 0 | Base time in hours |
| additionalTime | 0 | Extra time in hours |
| additionalMaterial | 0 | Extra material cost (in base currency) |
| markupScale | DEFAULT_MARKUP_SCALE | Tiered markup thresholds |

## Markup Scale

Material costs receive higher multipliers when they are cheaper (in base currency):

| Material Cost ≥ | Markup |
|-----------------|--------|
| 6.57 | 1.65× |
| 3.94 | 1.75× |
| 2.63 | 2.00× |
| 1.58 | 2.25× |
| 1.05 | 2.50× |
| 0.53 | 2.75× |
| 0.26 | 3.00× |
| 0.13 | 3.50× |
| 0 | 4.00× |

## Price Flow

\`\`\`
tierPrice + additionalTimeFeeDiscounted + additionalMaterialFee = leveledPrice
leveledPrice × standardDeduction = priceAfterDeduction
priceAfterDeduction × saDiscount = finalPrice
\`\`\`

## Exported Functions

- **calculateWithImpliedRate(vars)**: Full calculation returning all intermediate values
- **calculatePrice(...)**: Simplified function returning just the final price
- **getImpliedRate(...)**: Get the implied hourly rate for a tier
- **createPricingVars(overrides)**: Create pricing variables with defaults
`;

export default {
  calculateWithImpliedRate,
  calculatePrice,
  getImpliedRate,
  createPricingVars,
  DEFAULT_MARKUP_SCALE,
  docs,
};