// Конфигурация калькулятора мыла import { CalculatorConfig } from '@/lib/calculator-types'; import { calculateSoapStep, calculateSoapSubtotal, round } from './calc'; export const soapCalculatorConfig: CalculatorConfig = { id: 'soap', name: 'Калькулятор мыла', description: 'Расчет себестоимости мыла ручной работы', icon: '🧼', fields: [ { id: 'soapName', type: 'text', label: 'Название мыла', placeholder: 'Введите название', defaultValue: '', gridCols: 1, required: false, }, { id: 'photo', type: 'file', label: 'Фото мыла (необязательно)', accept: 'image/*', gridCols: 1, required: false, }, { id: 'weight', type: 'number', label: 'Вес мыла, г', defaultValue: '', gridCols: 2, required: false, groupName: 'base', showStepAfter: 'base', }, { id: 'basePrice', type: 'number', label: 'Цена основы, руб', defaultValue: '', gridCols: 2, required: false, groupName: 'base', }, { id: 'aromaPrice', type: 'number', label: 'Цена отдушки, руб', defaultValue: '', gridCols: 2, required: false, groupName: 'aroma', showStepAfter: 'aroma', }, { id: 'aromaWeight', type: 'number', label: 'Фасовка отдушки, г', defaultValue: '', gridCols: 2, required: false, groupName: 'aroma', }, { id: 'pigmentPrice', type: 'number', label: 'Цена пигмента, руб', defaultValue: '', gridCols: 2, required: false, groupName: 'pigment', showStepAfter: 'pigment', }, { id: 'pigmentWeight', type: 'number', label: 'Фасовка пигмента, г', defaultValue: '', gridCols: 2, required: false, groupName: 'pigment', }, { id: 'moldPrice', type: 'number', label: 'Цена формы, руб', defaultValue: '', gridCols: 1, required: false, groupName: 'mold', showStepAfter: 'mold', }, { id: 'box', type: 'number', label: 'Пакет/коробка, руб', defaultValue: '', gridCols: 2, required: false, groupName: 'packaging', showStepAfter: 'packaging', }, { id: 'filler', type: 'number', label: 'Наполнитель, руб', defaultValue: '', gridCols: 2, required: false, groupName: 'packaging', }, { id: 'ribbon', type: 'number', label: 'Лента, руб', defaultValue: '', gridCols: 2, required: false, groupName: 'packaging', }, { id: 'label', type: 'number', label: 'Наклейка, руб', defaultValue: '', gridCols: 2, required: false, groupName: 'packaging', }, { id: 'markup', type: 'number', label: 'Наценка, %', defaultValue: '', gridCols: 2, required: false, }, ], calculationSteps: [ { id: 'base', name: 'Себестоимость основы', formula: (values) => round(calculateSoapStep('base', values)), formulaDescription: '(вес / 1000) * цена_основы', }, { id: 'aroma', name: 'Себестоимость отдушки (1 %)', formula: (values) => round(calculateSoapStep('aroma', values)), formulaDescription: '((вес * 0.01) / фасовка_отдушки) * цена_отдушки', }, { id: 'pigment', name: 'Себестоимость пигмента (0.5 %)', formula: (values) => round(calculateSoapStep('pigment', values)), formulaDescription: '((вес * 0.005) / фасовка_пигмента) * цена_пигмента', }, { id: 'mold', name: 'Себестоимость формы', formula: (values) => round(calculateSoapStep('mold', values)), formulaDescription: 'цена_формы / 100', }, { id: 'packaging', name: 'Стоимость упаковки', formula: (values) => round(calculateSoapStep('packaging', values)), formulaDescription: 'пакет + наполнитель + лента + наклейка', }, ], subtotals: [ { id: 'operational', name: 'Операционные расходы (5 %)', formula: (values, steps) => round(calculateSoapSubtotal('operational', values, steps)), formulaDescription: '(основа + отдушка + пигмент + форма + упаковка) * 0.05', }, { id: 'total', name: 'Итого себестоимость', formula: (values, steps) => round(calculateSoapSubtotal('total', values, steps)), highlight: true, formulaDescription: 'основа + отдушка + пигмент + форма + упаковка + операционные', }, ], additionalCalculations: [ { id: 'finalPrice', name: 'Итоговая цена с наценкой', formula: (values, steps, subtotals) => { const total = subtotals.total || 0; const markup = values.markup || 0; return round(total * (1 + markup / 100)); }, formulaDescription: 'итого_себестоимость * (1 + наценка / 100)', }, { id: 'pricePer100g', name: 'Цена за 100 г', formula: (values, steps, subtotals, additional) => { const weight = values.weight || 0; const finalPrice = additional?.finalPrice || 0; if (weight > 0) { return round((finalPrice / weight) * 100); } return 0; }, formulaDescription: '(итоговая_цена / вес) * 100', }, ], formatTelegramMessage: (values, steps, subtotals, additional) => { const soapName = values.soapName || 'Без названия'; const weight = values.weight || 0; const box = values.box || 0; const filler = values.filler || 0; const ribbon = values.ribbon || 0; const label = values.label || 0; const markup = values.markup || 0; const totalCost = subtotals.total || 0; const finalPrice = additional?.finalPrice || 0; const pricePer100g = additional?.pricePer100g || 0; let text = `🧼 Расчёт мыла: ${soapName}\n\n`; text += `⚖️ Вес мыла: ${weight} г\n\n`; text += `📦 Упаковка:\n`; text += ` 📥 Пакет/коробка: ${box} ₽\n`; text += ` 🌾 Наполнитель: ${filler} ₽\n`; text += ` 🎀 Лента: ${ribbon} ₽\n`; text += ` 🏷️ Наклейка: ${label} ₽\n\n`; text += `💹 Наценка: ${markup}%\n\n`; text += `📊 Итоги расчёта:\n`; text += ` 💵 Себестоимость: ${totalCost.toFixed(1)} ₽\n`; text += ` 🎯 Итоговая цена с наценкой: ${finalPrice.toFixed(1)} ₽\n`; text += ` ⚗️ Цена за 100 г: ${pricePer100g.toFixed(1)} ₽`; return text; }, };