From 890e575d3d685a864f8e00cf3e1fa6978f75a258 Mon Sep 17 00:00:00 2001 From: fontvielle Date: Thu, 22 Oct 2026 10:28:42 +0300 Subject: [PATCH] =?UTF-8?q?DEPO:=20=D0=BF=D0=BE=D0=BB=D0=BD=D0=BE=D0=B5=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=B8=D0=BC=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BE=D1=80=D0=B3=D0=B0=D0=BD=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=B8=20=D0=B8=D0=B7=20OD=5FU=5FFACES,=20=D0=B4?= =?UTF-8?q?=D0=B5=D0=B9=D1=81=D1=82=D0=B2=D1=83=D1=8E=D1=89=D0=B0=D1=8F=20?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D1=8F=20=D0=BB=D0=B8=D1=86=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Автоопределение читало исходную запись лица (2016) и брало MNEM как краткое наименование. Теперь — действующая версия (SELF_ID/LAST_FLAG=1): краткое — OD_FACES.NAME, полное — OD_U_FACES.FULL_NAME, английские — ENG_FULL_NAME и ENG_NAME. Анкета участника заполняется из DEPO без справочника НРД; английские — только парой. Проверено на DEPO 28: полное есть у 141 из 145 участников, английские после замены кавычек совпали с ответом НРД. Если OD_U_FACES нет — прежний запрос и подсказка уточнить у НРД. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn --- internal/lkgateway/depo_detect.go | 22 ++++++++--- internal/lkgateway/fsql/depodetect.go | 10 ++++- internal/lkgateway/participant_form.go | 41 ++++++++++++++------- internal/lkgateway/participant_name_test.go | 18 ++++++++- 4 files changed, 69 insertions(+), 22 deletions(-) diff --git a/internal/lkgateway/depo_detect.go b/internal/lkgateway/depo_detect.go index 7b7739d..87646cb 100644 --- a/internal/lkgateway/depo_detect.go +++ b/internal/lkgateway/depo_detect.go @@ -27,9 +27,11 @@ type DepoRequisites struct { Sections []string // все открытые разделы счёта OrgCode string // = DeponentCode OrgINN string - OrgName string - OrgShort string - OrgEng string + OrgName string // краткое (OD_FACES.NAME) + OrgShort string // = OrgName (MNEM в DEPO — мнемоника, не наименование) + OrgEng string // английское краткое + OrgFull string // полное (OD_U_FACES.FULL_NAME) + OrgEngFull string // английское полное Notes []string // что не нашли / на что обратить внимание At time.Time } @@ -127,15 +129,23 @@ func depoDetectRequisites(ctx context.Context, fs FancyMSSQLSettings) (*DepoRequ } // организация по коду участника if res.DeponentCode != "" { - var name, inn, mnem, eng string - err := db.QueryRowContext(ctx, fsql.Det02, sql.Named("code", res.DeponentCode)).Scan(&name, &inn, &mnem, &eng) + var name, inn, mnem, eng, full, engFull string + err := db.QueryRowContext(ctx, fsql.Det03, sql.Named("code", res.DeponentCode)).Scan(&name, &inn, &mnem, &eng, &full, &engFull) + if err != nil && err != sql.ErrNoRows { + err = db.QueryRowContext(ctx, fsql.Det02, sql.Named("code", res.DeponentCode)).Scan(&name, &inn, &mnem, &eng) + } switch { case err == sql.ErrNoRows: res.Notes = append(res.Notes, "лицо с кодом "+res.DeponentCode+" в DEPO не найдено — ИНН и наименование организации введите вручную") case err != nil: res.Notes = append(res.Notes, "карточка организации: "+err.Error()) default: - res.OrgCode, res.OrgINN, res.OrgName, res.OrgShort, res.OrgEng = res.DeponentCode, strings.TrimSpace(inn), strings.TrimSpace(name), strings.TrimSpace(mnem), strings.TrimSpace(eng) + _ = mnem + res.OrgCode, res.OrgINN, res.OrgName, res.OrgShort, res.OrgEng = res.DeponentCode, strings.TrimSpace(inn), strings.TrimSpace(name), strings.TrimSpace(name), strings.TrimSpace(eng) + res.OrgFull, res.OrgEngFull = strings.TrimSpace(full), strings.TrimSpace(engFull) + if res.OrgFull == "" { + res.Notes = append(res.Notes, "полного наименования организации в DEPO нет — для анкеты участника уточните его у НРД") + } } } return res, nil diff --git a/internal/lkgateway/fsql/depodetect.go b/internal/lkgateway/fsql/depodetect.go index 98e2023..10f4297 100644 --- a/internal/lkgateway/fsql/depodetect.go +++ b/internal/lkgateway/fsql/depodetect.go @@ -7,6 +7,14 @@ package fsql var Det01 = `SELECT c.NUMBER, ISNULL(c.STATE,0), ISNULL(c.NAME,'') FROM OD_CLIENTS c JOIN OD_FACES f ON f.ID=c.FACE WHERE f.INN='7702165310' AND c.NUMBER LIKE '%/%/%/%' ORDER BY c.STATE, c.NUMBER` -// Det02 — карточка организации по коду участника НРД (кодер лица). +// Det03 — карточка организации по коду участника НРД: действующая версия лица (кодер ссылается на исходную +// запись SELF_ID, действующая — LAST_FLAG=1) и юридические наименования из OD_U_FACES. NAME в OD_FACES — +// краткое («ООО "…"»), полное и английское полное — только в OD_U_FACES, английское краткое — OD_FACES.ENG_NAME. +var Det03 = `SELECT TOP 1 ISNULL(f.NAME,''), ISNULL(f.INN,''), ISNULL(f.MNEM,''), ISNULL(f.ENG_NAME,''), ISNULL(u.FULL_NAME,''), ISNULL(u.ENG_FULL_NAME,'') + FROM OD_FACE_CODERS fc JOIN OD_FACES f ON (f.ID=fc.FACE OR f.SELF_ID=fc.FACE) LEFT JOIN OD_U_FACES u ON u.FACE=f.ID + WHERE fc.CODE=@code ORDER BY ISNULL(f.LAST_FLAG,0) DESC, f.B_DATE DESC, f.ID DESC` + +// Det02 — карточка организации по коду участника НРД (кодер лица); запасной вариант, если в DEPO нет +// OD_U_FACES или версионных полей. var Det02 = `SELECT TOP 1 ISNULL(f.NAME,''), ISNULL(f.INN,''), ISNULL(f.MNEM,''), ISNULL(f.ENG_NAME,'') FROM OD_FACE_CODERS fc JOIN OD_FACES f ON f.ID=fc.FACE WHERE fc.CODE=@code ORDER BY f.E_DATE DESC, f.ID DESC` diff --git a/internal/lkgateway/participant_form.go b/internal/lkgateway/participant_form.go index f2a2f8e..16233de 100644 --- a/internal/lkgateway/participant_form.go +++ b/internal/lkgateway/participant_form.go @@ -53,12 +53,30 @@ type participantFormData struct { // participantFormPrefill — предзаполнение из автоопределения DEPO и настроек НРД. func participantFormPrefill(rc *RuntimeConfig) participantFormData { var d participantFormData - if r := depoDetectResult(); r != nil { + r := depoDetectResult() + if r == nil && rc != nil && strings.TrimSpace(rc.Snapshot().Fancy.Server) != "" { + // после перезапуска bj автоопределения в памяти нет — прочитать DEPO сейчас + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + if res, err := depoDetectRequisites(ctx, rc.Snapshot().Fancy); err == nil { + lastDepoDetect.mu.Lock() + lastDepoDetect.r = res + lastDepoDetect.mu.Unlock() + r = res + } + cancel() + } + if r != nil { + // DEPO: полное — OD_U_FACES, краткое — OD_FACES.NAME, отображаемое = краткое (так советует НРД); + // английские — только парой (полное + краткое), иначе их не указываем d.INN = strings.TrimSpace(r.OrgINN) - d.FullName = strings.TrimSpace(r.OrgName) - d.ShortName = strings.TrimSpace(r.OrgShort) - d.DisplayName = strings.TrimSpace(r.OrgShort) - d.EngFull = strings.TrimSpace(r.OrgEng) + d.FullName = strings.TrimSpace(pick(r.OrgFull, r.OrgName)) + d.ShortName = strings.TrimSpace(r.OrgName) + d.DisplayName = strings.TrimSpace(r.OrgName) + if strings.TrimSpace(r.OrgEngFull) != "" { + d.EngFull = strings.TrimSpace(r.OrgEngFull) + d.EngShort = strings.TrimSpace(r.OrgEng) + d.EngDisplay = d.EngShort + } if d.DepoCode == "" { d.DepoCode = strings.TrimSpace(r.DeponentCode) } @@ -81,18 +99,13 @@ func participantFormPrefill(rc *RuntimeConfig) participantFormData { if ok { // НРД сверяет наименования анкеты со своей клиентской базой (M2M37) — карточка в справочнике // НРД главнее DEPO: в DEPO «наименование» бывает кратким (21.10.2026 краткое ушло в FullName). - // Английские — только если их ввели: в справочнике есть лишь краткое, полного нет. + // Английские — из DEPO: в справочнике НРД есть лишь краткое. if n := strings.TrimSpace(hb.FullName); n != "" { d.FullName = n } if n := strings.TrimSpace(hb.Name); n != "" && hb.FullName != "" { d.ShortName, d.DisplayName = n, n // отображаемое НРД советует как краткое } - if strings.TrimSpace(hb.FullName) != "" { - d.EngFull = "" - } else if d.EngFull == "" { - d.EngFull = strings.TrimSpace(hb.EngName) - } if hb.Kind == "broker" && d.BrokerCode == "" { d.BrokerCode = strings.ToUpper(strings.TrimSpace(hb.Code)) } @@ -172,8 +185,8 @@ func pfNameCheck(rc *RuntimeConfig, d participantFormData) []string { if x.FullName != d.FullName { w = append(w, "Полное наименование отличается от карточки нашей фирмы в справочнике НРД: «"+x.FullName+"». НРД сверяет с ней — без причины не меняйте.") } - default: - w = append(w, "Наименования взяты из DEPO, в справочнике НРД нашей карточки нет. НРД сверяет их со своей клиентской базой — уточните точные наименования у НРД и впишите как есть.") + case strings.TrimSpace(d.FullName) == "": + w = append(w, "Полного наименования нет ни в DEPO, ни в справочнике НРД — уточните его у НРД и впишите как есть.") } if pfAbbrRe.MatchString(d.FullName) || (d.FullName != "" && d.FullName == d.ShortName) { w = append(w, "Полное наименование похоже на сокращённое — нужно полное («Общество с ограниченной ответственностью …»), как в клиентской базе НРД.") @@ -539,7 +552,7 @@ pre{background:#f6f8fa;border:1px solid #ddd;border-radius:8px;padding:12px;over Без регистрации сервис отбивает запросы кодом M2M14. В боевом контуре анкета подаётся через ИШ пакетом #M2MPF (businessLine=MOST, подпись боевым контейнером на стороне ИШ); письмо на ` + participantFormRecipient + ` оставлено запасным каналом. Наименования должны точно совпадать с -клиентской базой НРД (иначе M2M37): bj берёт их из карточки нашей фирмы в справочнике НРД, а если её нет — из DEPO. +клиентской базой НРД (иначе M2M37): bj берёт их из карточки нашей фирмы в справочнике НРД и из DEPO (полное — карточка юрлица). Чего нет или в чём bj не уверен — уточните у НРД. Кавычки — прямые ".

` + regHTML + flashHTML + vErr + `
diff --git a/internal/lkgateway/participant_name_test.go b/internal/lkgateway/participant_name_test.go index abced2a..b7554b6 100644 --- a/internal/lkgateway/participant_name_test.go +++ b/internal/lkgateway/participant_name_test.go @@ -32,10 +32,26 @@ func TestParticipantFormNames(t *testing.T) { 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], "сокращённое") { + if len(ws) != 1 || !strings.Contains(ws[0], "сокращённое") { t.Fatalf("подсказки: %q", ws) } + if ws := pfNameCheck(nil, participantFormData{}); len(ws) != 1 || !strings.Contains(ws[0], "уточните") { + t.Fatalf("без полного: %q", ws) + } + full := participantFormData{FullName: `Общество с ограниченной ответственностью "Инвестиционная Компания "Фонтвьель"`, ShortName: `ООО "ИК "Фонтвьель"`} + if ws := pfNameCheck(nil, full); len(ws) != 0 { + t.Fatalf("полное из DEPO — без подсказок: %q", ws) + } if !strings.Contains(pfAskNSD("MC0413600000"), "MC0413600000") { t.Error("в запросе нет кода участника") } } + +// Английские из DEPO в «ёлочках» — после замены кавычек ровно как в ответе НРД от 22.10.2026. +func TestParticipantEngQuotes(t *testing.T) { + d := participantFormData{EngFull: "«Investment Company «Fontvielle» Limited Liability Company", EngShort: "«IC «Fontvielle» LLC"} + pfNames(&d) + if d.EngFull != `"Investment Company "Fontvielle" Limited Liability Company` || d.EngShort != `"IC "Fontvielle" LLC` { + t.Fatalf("%q / %q", d.EngFull, d.EngShort) + } +}