UpDaet
This commit is contained in:
parent
5662425a23
commit
8c4056edcd
@ -4,6 +4,7 @@ PASSWORD=your_fns_password # Пароль от приложения «
|
|||||||
|
|
||||||
# === Настройки приложения ===
|
# === Настройки приложения ===
|
||||||
APPNAME=Моя компания # Название, отображаемое в чеке ФНС
|
APPNAME=Моя компания # Название, отображаемое в чеке ФНС
|
||||||
|
ADMIN_EMAIL=a@ga1maz.ru # Email администратора для уведомлений
|
||||||
|
|
||||||
# === SMTP настройки ===
|
# === SMTP настройки ===
|
||||||
SMTP_HOST=smtp.gmail.com # SMTP сервер
|
SMTP_HOST=smtp.gmail.com # SMTP сервер
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -37,8 +37,10 @@ build/
|
|||||||
|
|
||||||
*
|
*
|
||||||
|
|
||||||
|
!error.json
|
||||||
!.gitignore
|
!.gitignore
|
||||||
!.env.example
|
!.env.example
|
||||||
!package.json
|
!package.json
|
||||||
!README.md
|
!README.md
|
||||||
!server.js
|
!server.js
|
||||||
|
!LICENSE
|
||||||
|
|||||||
13
README.MD
13
README.MD
@ -97,7 +97,7 @@ PASSWORD=your_fns_password
|
|||||||
|
|
||||||
# === Приложение ===
|
# === Приложение ===
|
||||||
APPNAME=Моя компания
|
APPNAME=Моя компания
|
||||||
|
ADMIN_EMAIL=admin@example.com
|
||||||
# === SMTP ===
|
# === SMTP ===
|
||||||
SMTP_HOST=smtp.gmail.com
|
SMTP_HOST=smtp.gmail.com
|
||||||
SMTP_PORT=587
|
SMTP_PORT=587
|
||||||
@ -207,6 +207,9 @@ GET /health
|
|||||||
|
|
||||||
* до **3 попыток**
|
* до **3 попыток**
|
||||||
* задержка **2 секунды** между попытками
|
* задержка **2 секунды** между попытками
|
||||||
|
* При окончательной ошибке:
|
||||||
|
* ошибка логируется в `error.json`
|
||||||
|
* администратору отправляется email с деталями ошибки
|
||||||
|
|
||||||
### 📤 Response (Success)
|
### 📤 Response (Success)
|
||||||
|
|
||||||
@ -242,6 +245,13 @@ GET /health
|
|||||||
{ "error": "Не удалось создать чек" }
|
{ "error": "Не удалось создать чек" }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 500 — Internal Server Error
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "error": "Не удалось создать чек. Данные сохранены для повторной попытки. }
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🧩 Переменные окружения (.env)
|
## 🧩 Переменные окружения (.env)
|
||||||
@ -252,6 +262,7 @@ GET /health
|
|||||||
| `INN` | ИНН самозанятого |
|
| `INN` | ИНН самозанятого |
|
||||||
| `PASSWORD` | Пароль «Мой налог» |
|
| `PASSWORD` | Пароль «Мой налог» |
|
||||||
| `APPNAME` | Название в чеке ФНС |
|
| `APPNAME` | Название в чеке ФНС |
|
||||||
|
| `ADMIN_EMAIL` | Email администратора |
|
||||||
| `SMTP_HOST` | SMTP сервер |
|
| `SMTP_HOST` | SMTP сервер |
|
||||||
| `SMTP_PORT` | SMTP порт |
|
| `SMTP_PORT` | SMTP порт |
|
||||||
| `SMTP_USER` | SMTP логин |
|
| `SMTP_USER` | SMTP логин |
|
||||||
|
|||||||
0
error.json
Normal file
0
error.json
Normal file
92
server.js
92
server.js
@ -3,16 +3,24 @@ import bodyParser from "body-parser";
|
|||||||
import nodemailer from "nodemailer";
|
import nodemailer from "nodemailer";
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
import pkg from "lknpd-nalog-api";
|
import pkg from "lknpd-nalog-api";
|
||||||
|
import fs from "fs/promises";
|
||||||
|
import path from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
const { NalogApi } = pkg;
|
const { NalogApi } = pkg;
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
|
|
||||||
const PORT = process.env.PORT || 4000;
|
const PORT = process.env.PORT || 4000;
|
||||||
const MAX_RETRIES = 3;
|
const MAX_RETRIES = 3;
|
||||||
|
const ERROR_FILE = path.join(__dirname, "error.json");
|
||||||
|
const ADMIN_EMAIL = process.env.ADMIN_EMAIL;
|
||||||
|
|
||||||
const transporter = nodemailer.createTransport({
|
const transporter = nodemailer.createTransport({
|
||||||
host: process.env.SMTP_HOST,
|
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 = `
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Ошибка создания чека</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2>⚠️ Ошибка при создании чека</h2>
|
||||||
|
<p><b>Время:</b> ${new Date().toLocaleString()}</p>
|
||||||
|
<p><b>Email клиента:</b> ${errorData.email}</p>
|
||||||
|
<p><b>Сумма:</b> ${errorData.amount} ₽</p>
|
||||||
|
<p><b>Ошибка:</b> ${errorData.error}</p>
|
||||||
|
<p><b>Данные заказа:</b></p>
|
||||||
|
<pre>${JSON.stringify(errorData.items, null, 2)}</pre>
|
||||||
|
<p>Ошибка сохранена в error.json для последующей обработки.</p>
|
||||||
|
<p>Пробейте чек вручную через приложение Мой налог и вручную отправте клиенту чек по email.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
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) => {
|
app.get("/health", async (req, res) => {
|
||||||
const result = {
|
const result = {
|
||||||
status: "ok",
|
status: "ok",
|
||||||
@ -166,11 +236,27 @@ ${process.env.APPNAME}
|
|||||||
});
|
});
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Ошибка:", err);
|
console.error("Ошибка создания чека:", err);
|
||||||
res.status(500).json({ error: "Не удалось создать чек" });
|
|
||||||
|
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, () => {
|
app.listen(PORT, () => {
|
||||||
console.log(`✅ Сервер запущен: http://localhost:${PORT}`);
|
console.log(`✅ Сервер запущен: http://localhost:${PORT}`);
|
||||||
});
|
console.log(`📁 Файл ошибок: ${ERROR_FILE}`);
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user