From c546773840e2c5d714bd0893815f7629f64e895c Mon Sep 17 00:00:00 2001
From: fontvielle
Date: Thu, 22 Oct 2026 10:07:33 +0300
Subject: [PATCH] =?UTF-8?q?=D0=90=D0=BD=D0=BA=D0=B5=D1=82=D0=B0=20=D1=83?=
=?UTF-8?q?=D1=87=D0=B0=D1=81=D1=82=D0=BD=D0=B8=D0=BA=D0=B0:=20=D1=87?=
=?UTF-8?q?=D1=82=D0=BE=20=D0=BD=D0=B5=20=D0=B8=D0=B7=D0=B2=D0=B5=D1=81?=
=?UTF-8?q?=D1=82=D0=BD=D0=BE=20=D1=82=D0=BE=D1=87=D0=BD=D0=BE=20=E2=80=94?=
=?UTF-8?q?=20=D1=83=D1=82=D0=BE=D1=87=D0=BD=D0=B8=D1=82=D1=8C=20=D1=83=20?=
=?UTF-8?q?=D0=9D=D0=A0=D0=94?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Источник наименований: карточка нашей фирмы в справочнике НРД, без неё —
DEPO (черновик). Анкета предупреждает и даёт готовый текст запроса в НРД,
если карточки нет, полное похоже на краткое, отличается от карточки или
английские неполные; при ответе M2M37 — подсказка запросить наименования.
Co-Authored-By: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
---
internal/lkgateway/participant_form.go | 77 +++++++++++++++++++--
internal/lkgateway/participant_name_test.go | 12 ++++
2 files changed, 84 insertions(+), 5 deletions(-)
diff --git a/internal/lkgateway/participant_form.go b/internal/lkgateway/participant_form.go
index 554f7ed..f2a2f8e 100644
--- a/internal/lkgateway/participant_form.go
+++ b/internal/lkgateway/participant_form.go
@@ -146,6 +146,59 @@ func participantFormValidate(d participantFormData) []string {
return errs
}
+// pfAbbrRe — наименование начинается с сокращённой формы (ООО, АО…) — для полного это ошибка.
+var pfAbbrRe = regexp.MustCompile(`^(ООО|ОАО|ЗАО|ПАО|НАО|АО|АКБ|КБ|НКО|ИК)[\s"«]`)
+
+// pfAskNSD — текст запроса в НРД о точных наименованиях участника (ответ НРД — источник истины).
+func pfAskNSD(code string) string {
+ if code == "" {
+ code = "наш код участника"
+ }
+ return "Просим сообщить точное наименование, под которым участник " + code +
+ " зарегистрирован в клиентской базе НРД: полное (FullName), сокращённое (ShortName), " +
+ "а также английские полное и сокращённое, если они есть."
+}
+
+// pfNameCheck — что в наименованиях надо уточнить у НРД. НРД сверяет их со своей клиентской
+// базой (M2M37): точный источник — карточка нашей фирмы в справочнике НРД или ответ НРД;
+// данные DEPO — только черновик.
+func pfNameCheck(rc *RuntimeConfig, d participantFormData) []string {
+ var w []string
+ hb, ok := participantCard(rc, d.INN)
+ switch {
+ case ok && strings.TrimSpace(hb.FullName) != "":
+ x := participantFormData{FullName: hb.FullName}
+ pfNames(&x)
+ if x.FullName != d.FullName {
+ w = append(w, "Полное наименование отличается от карточки нашей фирмы в справочнике НРД: «"+x.FullName+"». НРД сверяет с ней — без причины не меняйте.")
+ }
+ default:
+ w = append(w, "Наименования взяты из DEPO, в справочнике НРД нашей карточки нет. НРД сверяет их со своей клиентской базой — уточните точные наименования у НРД и впишите как есть.")
+ }
+ if pfAbbrRe.MatchString(d.FullName) || (d.FullName != "" && d.FullName == d.ShortName) {
+ w = append(w, "Полное наименование похоже на сокращённое — нужно полное («Общество с ограниченной ответственностью …»), как в клиентской базе НРД.")
+ }
+ if (d.EngShort != "" || d.EngDisplay != "") && d.EngFull == "" {
+ w = append(w, "Английские: указано краткое без полного — уточните полное у НРД или оставьте английские пустыми.")
+ }
+ return w
+}
+
+// participantCard — карточка нашей фирмы в справочнике НРД: по MC-коду, затем по ИНН.
+func participantCard(rc *RuntimeConfig, inn string) (HandbookEntry, bool) {
+ if rc == nil {
+ return HandbookEntry{}, false
+ }
+ s := rc.Snapshot()
+ if hb, ok := handbookByCode(orgCode(s)); ok {
+ return hb, true
+ }
+ if inn = strings.TrimSpace(pick(inn, orgINN(s))); inn != "" {
+ return handbookByINN(inn)
+ }
+ return HandbookEntry{}, false
+}
+
// pfQuotes — кавычки как в клиентской базе НРД: прямые ".
var pfQuotes = strings.NewReplacer("«", `"`, "»", `"`, "“", `"`, "”", `"`, "„", `"`)
@@ -376,7 +429,16 @@ func registerParticipantForm(mux *http.ServeMux, rc *RuntimeConfig, igwClient *i
}
xmlPreview := participantFormXML(d)
- participantFormRender(w, d, errs, action, flash, flashKind, xmlPreview, participantRegStatus(rc), igwClient != nil && igwChannel != "", isProdIGW(igwChannel))
+ reg := participantRegStatus(rc)
+ if ws := pfNameCheck(rc, d); len(ws) > 0 {
+ code := ""
+ if rc != nil {
+ code = orgCode(rc.Snapshot())
+ }
+ reg += `Уточните у НРД:- ` + strings.Join(escapeAll(ws), "
- ") +
+ `
Запрос в НРД (можно скопировать):
` + html.EscapeString(pfAskNSD(code)) + `
`
+ }
+ participantFormRender(w, d, errs, action, flash, flashKind, xmlPreview, reg, igwClient != nil && igwChannel != "", isProdIGW(igwChannel))
})
}
@@ -400,6 +462,9 @@ func participantRegStatus(rc *RuntimeConfig) string {
out.WriteString(`Ответ НРД пока не получен.`)
case strings.EqualFold(reg.Status, "ERROR"):
out.WriteString(`НРД отклонил ` + reg.RespAt.Format("02.01 15:04") + `: ` + html.EscapeString(reg.RespText) + `. Исправьте указанное и отправьте снова.`)
+ if containsStr(reg.Codes, "M2M37") {
+ out.WriteString(` Наименование не совпало с клиентской базой НРД — запросите у НРД точные наименования (текст запроса ниже) и впишите их без изменений.`)
+ }
default:
out.WriteString(`НРД принял ` + reg.RespAt.Format("02.01 15:04") + `. ` + html.EscapeString(reg.RespText))
}
@@ -467,18 +532,20 @@ button.primary{background:#1763cc;color:#fff;border-color:#1763cc}
pre{background:#f6f8fa;border:1px solid #ddd;border-radius:8px;padding:12px;overflow:auto;white-space:pre-wrap}
.ok{background:#e7f6e7;border:1px solid #58a858;padding:8px 12px;border-radius:6px;margin:10px 0}
.bad{background:#fdecec;border:1px solid #d66;padding:8px 12px;border-radius:6px;margin:10px 0}
-.note{color:#555;font-size:13px}
+.note{color:#555;font-size:13px}
+.warn{background:#fff7e0;border:1px solid #e0b040;padding:8px 12px;border-radius:6px;margin:10px 0}.warn pre{margin:6px 0 0}
Регистрация участника сервиса M2M (МОСТ)
Требование НРД при подключении: зарегистрировать организацию в справочнике участников M2M.
Без регистрации сервис отбивает запросы кодом M2M14. В боевом контуре анкета подаётся через ИШ
пакетом #M2MPF (businessLine=MOST, подпись боевым контейнером на стороне ИШ); письмо на
-` + participantFormRecipient + ` оставлено запасным каналом. Поля предзаполнены из
-автоопределения DEPO — проверьте юридические реквизиты.
+` + participantFormRecipient + ` оставлено запасным каналом. Наименования должны точно совпадать с
+клиентской базой НРД (иначе M2M37): bj берёт их из карточки нашей фирмы в справочнике НРД, а если её нет — из DEPO.
+Чего нет или в чём bj не уверен — уточните у НРД. Кавычки — прямые ".
` + regHTML + flashHTML + vErr + `