import express from "express";
import bodyParser from "body-parser";
import nodemailer from "nodemailer";
import dotenv from "dotenv";
import pkg from "lknpd-nalog-api";
dotenv.config();
const { NalogApi } = pkg;
const app = express();
app.use(bodyParser.json());
const PORT = process.env.PORT || 4000;
const MAX_RETRIES = 3;
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: Number(process.env.SMTP_PORT),
secure: false,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS
}
});
const nalogApi = new NalogApi({
inn: process.env.INN,
password: process.env.PASSWORD
});
async function createReceiptWithRetry(income, retries = MAX_RETRIES) {
for (let attempt = 1; attempt <= retries; attempt++) {
try {
return await nalogApi.addIncome(income);
} catch (err) {
console.error(`Попытка ${attempt} не удалась`, err.message || err);
if (attempt === retries) throw err;
await new Promise(r => setTimeout(r, 2000));
}
}
}
app.get("/health", async (req, res) => {
const result = {
status: "ok",
connect_to_fns: "ok",
smtp: "ok",
};
try {
await transporter.verify();
} catch (err) {
result.smtp = "error";
result.status = "degraded";
}
try {
await nalogApi.getUserInfo();
} catch (err) {
console.error("FNS health error:", err.message || err);
result.connect_to_fns = "error";
result.status = "degraded";
}
res.json(result);
});
app.post("/api/v1/create-receipt", async (req, res) => {
try {
const { api_pass, email, items } = req.body;
if (api_pass !== process.env.API_PASS) {
return res.status(401).json({ error: "Unauthorized" });
}
if (!email || !Array.isArray(items) || items.length === 0) {
return res.status(400).json({ error: "Неверные данные" });
}
const total = items.reduce(
(sum, i) => sum + i.price * (i.quantity || 1),
0
);
const income = {
name: `${process.env.APPNAME}`,
amount: Number(total.toFixed(2)),
quantity: 1
};
const receiptId = await createReceiptWithRetry(income);
const printLink = `https://lknpd.nalog.ru/api/v1/receipt/${process.env.INN}/${receiptId}/print`;
const rows = items.map(i => {
const qty = i.quantity || 1;
return `
| ${i.id} |
${i.name} |
${i.price.toFixed(2)} |
${qty} |
${(i.price * qty).toFixed(2)} |
`;
}).join("");
const html = `
Чек
Ваш чек
Чек сформирован в ФНС (Мой налог)
| ID | Название | Цена | Кол-во | Сумма |
${rows}
Итого: ${total.toFixed(2)} ₽
Посмотреть чек
${process.env.APPNAME}
|
|
`;
await transporter.sendMail({
from: process.env.SMTP_MAIL_FROM,
to: email,
subject: `Чек ${process.env.APPNAME}`,
html
});
res.json({
success: true,
receiptId,
printLink
});
} catch (err) {
console.error("Ошибка:", err);
res.status(500).json({ error: "Не удалось создать чек" });
}
});
app.listen(PORT, () => {
console.log(`✅ Сервер запущен: http://localhost:${PORT}`);
});