DoSoapCalc/backend/routes/api.js

141 lines
4.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// routes/api.js
// API маршруты для калькуляторов
const express = require('express');
const multer = require('multer');
const { getCalculator, hasCalculator } = require('../calculators');
const { sendTelegramMessage } = require('../lib/telegram');
const { validateRequiredFields, validateNumericFields } = require('../lib/validator');
const router = express.Router();
// Настраиваем multer (храним файлы в памяти)
const storage = multer.memoryStorage();
const upload = multer({ storage });
/**
* Обработчик POST /api/submit/:calculatorType
* Принимает данные калькулятора и отправляет результат в Telegram
*/
router.post(
'/submit/:calculatorType',
upload.single('photo'),
async (req, res) => {
try {
const { calculatorType } = req.params;
const { chat_id, ...formData } = req.body;
const photoFile = req.file;
// Проверяем, существует ли калькулятор
if (!hasCalculator(calculatorType)) {
return res.status(404).json({
error: `Калькулятор "${calculatorType}" не найден`,
});
}
// Получаем модуль калькулятора
const calculator = getCalculator(calculatorType);
// Валидация обязательных полей
const requiredValidation = validateRequiredFields(
{ chat_id, ...formData },
['chat_id', ...calculator.getRequiredFields()]
);
if (!requiredValidation.valid) {
return res.status(400).json({ error: requiredValidation.error });
}
// Валидация числовых полей
const numericValidation = validateNumericFields(
formData,
calculator.getNumericFields()
);
if (!numericValidation.valid) {
return res.status(400).json({ error: numericValidation.error });
}
// Подготавливаем данные для расчёта
const calculationData = prepareCalculationData(formData, calculator.fieldSchema);
// Выполняем расчёт
const calculationResult = calculator.calculate(calculationData);
// Вычисляем финальную цену и цену за 100г (если применимо)
const markup = parseFloat(formData.markup || 0);
const totalCost = calculationResult.total;
const finalPrice = totalCost * (1 + markup / 100);
const weight = parseFloat(formData.weight || 0);
const pricePer100g = weight > 0 ? (finalPrice / weight) * 100 : 0;
// Формируем сообщение для Telegram
const messageData = {
...formData,
totalCost,
finalPrice,
pricePer100g,
};
const telegramMessage = calculator.formatMessage(messageData, calculationResult);
// Отправляем в Telegram
try {
await sendTelegramMessage(
req.app.locals.bot,
chat_id,
telegramMessage,
photoFile ? photoFile.buffer : null
);
res.sendStatus(200);
} catch (telegramError) {
console.error('Ошибка при отправке в Telegram:', telegramError);
res.status(500).json({
error: 'Ошибка при отправке сообщения в Telegram',
details: telegramError.message,
});
}
} catch (err) {
console.error('Ошибка в /api/submit:', err);
res.status(500).json({
error: 'Внутренняя ошибка сервера',
details: err.message,
});
}
}
);
/**
* Подготавливает данные для расчёта из формы
* @param {Object} formData - Данные из формы
* @param {Array} fieldSchema - Схема полей калькулятора
* @returns {Object} Подготовленные данные для расчёта
*/
function prepareCalculationData(formData, fieldSchema) {
const data = {};
for (const field of fieldSchema) {
if (formData[field.name] !== undefined) {
const value = formData[field.name];
if (field.type === 'number') {
data[field.name] = parseFloat(value) || 0;
} else {
data[field.name] = value;
}
}
}
// Специфичная обработка для мыла (упаковка)
if (formData.box !== undefined || formData.filler !== undefined ||
formData.ribbon !== undefined || formData.labelValue !== undefined) {
data.packaging = {
box: parseFloat(formData.box || 0),
filler: parseFloat(formData.filler || 0),
ribbon: parseFloat(formData.ribbon || 0),
label: parseFloat(formData.labelValue || 0),
};
}
return data;
}
module.exports = router;