← Files TeleCallARCHIVED FILE

src/services/pricingService.ts

3.16 KB · Sep 30, 2026 · 23:16 UTC

↓ Download file

import { TeleCallProduct } from '../types/product';
import { PriceBreakdown, PriceItem } from '../types/pricing';
import { ADDITIONAL_LINE_PRODUCTS } from '../catalog/additionalLines';
import { SECOND_RESIDENCE_PRODUCTS } from '../catalog/secondResidence';

export class PricingService {
  /**
   * Calcula el precio total mensual de una configuración de productos
   */
  public calculatePrice(
    baseProduct: TeleCallProduct,
    additionalLinesCount: number = 0,
    preferredAdditionalLineGB: number = 40,
    secondResidenceSpeedMbps?: number
  ): PriceBreakdown {
    const baseMonthly = baseProduct.price?.monthly || 0;
    const items: PriceItem[] = [
      {
        name: baseProduct.name,
        monthly: baseMonthly,
        category: "base",
        detail: baseProduct.description
      }
    ];

    const additionalLinesBreakdown: PriceBreakdown['additionalLines'] = [];
    let additionalLinesTotal = 0;

    if (additionalLinesCount > 0) {
      // Find best matching additional line product
      let addProduct = ADDITIONAL_LINE_PRODUCTS.find(
        p => (p.mobile?.dataGB || 0) >= preferredAdditionalLineGB
      );
      if (!addProduct) {
        // Default to largest or smallest available
        addProduct = ADDITIONAL_LINE_PRODUCTS[0];
      }

      const priceEach = addProduct.price?.monthly || 0;
      const total = priceEach * additionalLinesCount;
      additionalLinesTotal += total;

      additionalLinesBreakdown.push({
        product: addProduct,
        quantity: additionalLinesCount,
        priceEach,
        total
      });

      items.push({
        name: `${additionalLinesCount}x ${addProduct.name}`,
        monthly: total,
        category: "additional_line",
        detail: `${additionalLinesCount} línea(s) adicional(es) de ${addProduct.mobile?.dataGB} GB a ${priceEach} €/ud`
      });
    }

    let secondResidenceBreakdown: PriceBreakdown['secondResidence'] | undefined;
    let secondResidenceTotal = 0;

    if (secondResidenceSpeedMbps) {
      const secProd = SECOND_RESIDENCE_PRODUCTS.find(
        p => (p.fiber?.speedMbps || 0) >= secondResidenceSpeedMbps
      ) || SECOND_RESIDENCE_PRODUCTS[0];

      const secPrice = secProd.price?.monthly || 0;
      secondResidenceTotal = secPrice;
      secondResidenceBreakdown = {
        product: secProd,
        price: secPrice
      };

      items.push({
        name: secProd.name,
        monthly: secPrice,
        category: "second_residence",
        detail: `Fibra de ${secProd.fiber?.speedMbps} Mb para segunda residencia`
      });
    }

    const totalMonthly = baseMonthly + additionalLinesTotal + secondResidenceTotal;

    return {
      baseProduct,
      basePrice: baseMonthly,
      additionalLines: additionalLinesBreakdown,
      secondResidence: secondResidenceBreakdown,
      discounts: [],
      totalMonthly,
      currency: "EUR",
      items
    };
  }

  /**
   * Determina si una configuración cabe dentro del presupuesto del usuario
   */
  public isWithinBudget(totalMonthly: number, budget?: number): boolean {
    if (budget === undefined || budget === null || budget <= 0) return true;
    return totalMonthly <= budget;
  }
}

export const pricingService = new PricingService();

SHA-256: 7be8e4cd1f05582fbab7b57266d9cd9f4d79f721aaa1cc83d29e4650e9c7bc5e