From 2b3ba383fbd25b775002bd29b9de411b3f41966a Mon Sep 17 00:00:00 2001 From: romantarkin Date: Sun, 31 May 2026 21:18:41 +0500 Subject: [PATCH] fix --- README.MD | 4 ++ server.js | 110 +++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 101 insertions(+), 13 deletions(-) diff --git a/README.MD b/README.MD index a9c6067..09cc5c5 100644 --- a/README.MD +++ b/README.MD @@ -90,3 +90,7 @@ Content-Type: application/json ] } ``` + +Поле `email` обязательно: на этот адрес сервис отправит письмо со ссылкой на чек после успешного создания чека в ФНС. + +Если чек создан в ФНС, но письмо клиенту не отправилось, API вернет `success: true`, `receiptCreated: true`, `emailSent: false`, `receiptId`, `printLink` и `technicalError`. Ошибка отправки сохранится в `error.json`. diff --git a/server.js b/server.js index 9a67b25..4ce5f7b 100644 --- a/server.js +++ b/server.js @@ -1,4 +1,5 @@ import express from "express"; +import net from "net"; import nodemailer from "nodemailer"; import dotenv from "dotenv"; import pkg from "lknpd-nalog-api"; @@ -80,6 +81,43 @@ function withTimeout(promise, timeoutMs, label) { }); } +function formatTechnicalError(err) { + return { + message: err.message || "Unknown error", + code: err.code, + command: err.command, + responseCode: err.responseCode, + response: err.response + }; +} + +function smtpConfigForResponse() { + return { + host: process.env.SMTP_HOST, + port: SMTP_PORT, + secure: SMTP_SECURE, + user: process.env.SMTP_USER, + from: process.env.SMTP_MAIL_FROM + }; +} + +function checkTcpConnection(host, port, timeoutMs) { + return new Promise((resolve, reject) => { + const socket = net.createConnection({ host, port }); + + socket.setTimeout(timeoutMs); + socket.once("connect", () => { + socket.destroy(); + resolve(); + }); + socket.once("timeout", () => { + socket.destroy(); + reject(new Error(`TCP connection timeout after ${timeoutMs}ms`)); + }); + socket.once("error", reject); + }); +} + async function createReceiptWithRetry(income, retries = MAX_RETRIES) { for (let attempt = 1; attempt <= retries; attempt++) { try { @@ -208,14 +246,30 @@ app.get("/health/deep", async (req, res) => { }); app.get("/health/smtp", async (req, res) => { + const smtp = smtpConfigForResponse(); + + try { + await checkTcpConnection(process.env.SMTP_HOST, SMTP_PORT, SMTP_TIMEOUT_MS); + } catch (err) { + return res.status(500).json({ + status: "error", + smtp: "error", + step: "tcp_connect", + config: smtp, + technicalError: formatTechnicalError(err) + }); + } + try { await withTimeout(transporter.verify(), SMTP_TIMEOUT_MS, "SMTP health check"); - res.json({ status: "ok", smtp: "ok" }); + res.json({ status: "ok", smtp: "ok", config: smtp }); } catch (err) { res.status(500).json({ status: "error", smtp: "error", - message: err.message || "SMTP check failed" + step: "smtp_verify", + config: smtp, + technicalError: formatTechnicalError(err) }); } }); @@ -304,19 +358,47 @@ ${process.env.APPNAME} `; - await withTimeout( - transporter.sendMail({ - from: process.env.SMTP_MAIL_FROM, - to: email, - subject: `Чек ${process.env.APPNAME}`, - html - }), - SMTP_TIMEOUT_MS, - "Client email sending" - ); + try { + await withTimeout( + transporter.sendMail({ + from: process.env.SMTP_MAIL_FROM, + to: email, + subject: `Чек ${process.env.APPNAME}`, + html + }), + SMTP_TIMEOUT_MS, + "Client email sending" + ); + } catch (emailErr) { + console.error("Чек создан, но email клиенту не отправлен:", emailErr); + const technicalError = formatTechnicalError(emailErr); + + await saveToErrorFile({ + type: "email_send_failed", + email, + items, + amount: total, + receiptId, + printLink, + error: emailErr.message || "Не удалось отправить email клиенту", + technicalError + }); + + return res.json({ + success: true, + receiptCreated: true, + emailSent: false, + receiptId, + printLink, + warning: "Чек создан в ФНС, но письмо клиенту не отправлено. Данные сохранены в error.json.", + technicalError + }); + } res.json({ success: true, + receiptCreated: true, + emailSent: true, receiptId, printLink }); @@ -329,6 +411,7 @@ ${process.env.APPNAME} items: req.body?.items, amount: calculateTotal(req.body?.items), error: err.message || "Неизвестная ошибка", + technicalError: formatTechnicalError(err), api_pass: req.body?.api_pass }; @@ -337,7 +420,8 @@ ${process.env.APPNAME} res.status(500).json({ error: "Не удалось создать чек. Данные сохранены для повторной попытки.", - saved_to_error_file: true + saved_to_error_file: true, + technicalError: formatTechnicalError(err) }); } }); -- 2.45.2