diff --git a/.env.example b/.env.example index 1e2d696..17ada53 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,7 @@ PASSWORD=your_fns_password # Пароль от приложения « # === Настройки приложения === APPNAME=Моя компания # Название, отображаемое в чеке ФНС +ADMIN_EMAIL=a@ga1maz.ru # Email администратора для уведомлений # === SMTP настройки === SMTP_HOST=smtp.gmail.com # SMTP сервер diff --git a/.gitignore b/.gitignore index 13b7380..c1f8aed 100644 --- a/.gitignore +++ b/.gitignore @@ -37,8 +37,10 @@ build/ * +!error.json !.gitignore !.env.example !package.json !README.md !server.js +!LICENSE diff --git a/README.MD b/README.MD index 139fe06..572d04e 100644 --- a/README.MD +++ b/README.MD @@ -97,7 +97,7 @@ PASSWORD=your_fns_password # === Приложение === APPNAME=Моя компания - +ADMIN_EMAIL=admin@example.com # === SMTP === SMTP_HOST=smtp.gmail.com SMTP_PORT=587 @@ -207,6 +207,9 @@ GET /health * до **3 попыток** * задержка **2 секунды** между попытками + * При окончательной ошибке: + * ошибка логируется в `error.json` + * администратору отправляется email с деталями ошибки ### 📤 Response (Success) @@ -242,6 +245,13 @@ GET /health { "error": "Не удалось создать чек" } ``` +#### 500 — Internal Server Error + +```json +{ "error": "Не удалось создать чек. Данные сохранены для повторной попытки. } +``` + + --- ## 🧩 Переменные окружения (.env) @@ -252,6 +262,7 @@ GET /health | `INN` | ИНН самозанятого | | `PASSWORD` | Пароль «Мой налог» | | `APPNAME` | Название в чеке ФНС | +| `ADMIN_EMAIL` | Email администратора | | `SMTP_HOST` | SMTP сервер | | `SMTP_PORT` | SMTP порт | | `SMTP_USER` | SMTP логин | diff --git a/error.json b/error.json new file mode 100644 index 0000000..e69de29 diff --git a/server.js b/server.js index 50a736e..c5f7b80 100644 --- a/server.js +++ b/server.js @@ -3,16 +3,24 @@ import bodyParser from "body-parser"; import nodemailer from "nodemailer"; import dotenv from "dotenv"; import pkg from "lknpd-nalog-api"; +import fs from "fs/promises"; +import path from "path"; +import { fileURLToPath } from "url"; dotenv.config(); const { NalogApi } = pkg; +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + const app = express(); app.use(bodyParser.json()); const PORT = process.env.PORT || 4000; const MAX_RETRIES = 3; +const ERROR_FILE = path.join(__dirname, "error.json"); +const ADMIN_EMAIL = process.env.ADMIN_EMAIL; const transporter = nodemailer.createTransport({ host: process.env.SMTP_HOST, @@ -41,6 +49,68 @@ async function createReceiptWithRetry(income, retries = MAX_RETRIES) { } } +async function saveToErrorFile(errorData) { + try { + let errors = []; + + try { + const data = await fs.readFile(ERROR_FILE, "utf8"); + const parsedData = JSON.parse(data); + if (Array.isArray(parsedData)) { + errors = parsedData; + } + } catch (err) { + } + + errors.push({ + ...errorData, + timestamp: new Date().toISOString(), + retryAttempt: 0 + }); + + await fs.writeFile(ERROR_FILE, JSON.stringify(errors, null, 2)); + console.log(`Ошибка сохранена в ${ERROR_FILE}`); + } catch (err) { + console.error("Не удалось сохранить ошибку в файл:", err); + } +} + +async function notifyAdmin(errorData) { + try { + const html = ` + + + + +Ошибка создания чека + + +

⚠️ Ошибка при создании чека

+

Время: ${new Date().toLocaleString()}

+

Email клиента: ${errorData.email}

+

Сумма: ${errorData.amount} ₽

+

Ошибка: ${errorData.error}

+

Данные заказа:

+
${JSON.stringify(errorData.items, null, 2)}
+

Ошибка сохранена в error.json для последующей обработки.

+

Пробейте чек вручную через приложение Мой налог и вручную отправте клиенту чек по email.

+ + +`; + + await transporter.sendMail({ + from: process.env.SMTP_MAIL_FROM, + to: ADMIN_EMAIL, + subject: `Ошибка создания чека ${process.env.APPNAME}`, + html + }); + + console.log(`Администратор ${ADMIN_EMAIL} уведомлен об ошибке`); + } catch (err) { + console.error("Не удалось отправить уведомление администратору:", err); + } +} + app.get("/health", async (req, res) => { const result = { status: "ok", @@ -166,11 +236,27 @@ ${process.env.APPNAME} }); } catch (err) { - console.error("Ошибка:", err); - res.status(500).json({ error: "Не удалось создать чек" }); + console.error("Ошибка создания чека:", err); + + const errorData = { + email: req.body.email, + items: req.body.items, + amount: req.body.items.reduce((sum, i) => sum + i.price * (i.quantity || 1), 0), + error: err.message || "Неизвестная ошибка", + api_pass: req.body.api_pass + }; + + await saveToErrorFile(errorData); + await notifyAdmin(errorData); + + res.status(500).json({ + error: "Не удалось создать чек. Данные сохранены для повторной попытки.", + saved_to_error_file: true + }); } }); app.listen(PORT, () => { console.log(`✅ Сервер запущен: http://localhost:${PORT}`); -}); + console.log(`📁 Файл ошибок: ${ERROR_FILE}`); +}); \ No newline at end of file