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 += `
Уточните у НРД:Запрос в НРД (можно скопировать):
` + 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 + `
Организация ` + inp("inn", "ИНН (10 цифр)", d.INN, "7700000000") + ` -` + inp("full", "Полное наименование (по уставу)", d.FullName, "") + ` +` + inp("full", "Полное наименование (как в клиентской базе НРД)", d.FullName, "Общество с ограниченной ответственностью …") + `
` + inp("short", "Сокращённое", d.ShortName, "") + inp("display", "Отображаемое (DisplayName)", d.DisplayName, "") + `
Английские наименования (опционально) diff --git a/internal/lkgateway/participant_name_test.go b/internal/lkgateway/participant_name_test.go index 957bc17..abced2a 100644 --- a/internal/lkgateway/participant_name_test.go +++ b/internal/lkgateway/participant_name_test.go @@ -27,3 +27,15 @@ func TestParticipantFormNames(t *testing.T) { t.Error("пустые английские наименования не должны попадать в анкету") } } + +// Без карточки НРД и с кратким вместо полного — подсказка уточнить у НРД. +func TestParticipantNameCheck(t *testing.T) { + d := participantFormData{FullName: `ООО "ИК "Фонтвьель"`, ShortName: `ООО "ИК "Фонтвьель"`} + ws := pfNameCheck(nil, d) + if len(ws) != 2 || !strings.Contains(ws[0], "уточните") || !strings.Contains(ws[1], "сокращённое") { + t.Fatalf("подсказки: %q", ws) + } + if !strings.Contains(pfAskNSD("MC0413600000"), "MC0413600000") { + t.Error("в запросе нет кода участника") + } +}