DEPO: полное наименование организации из OD_U_FACES, действующая версия лица
Автоопределение читало исходную запись лица (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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
This commit is contained in:
@@ -27,9 +27,11 @@ type DepoRequisites struct {
|
|||||||
Sections []string // все открытые разделы счёта
|
Sections []string // все открытые разделы счёта
|
||||||
OrgCode string // = DeponentCode
|
OrgCode string // = DeponentCode
|
||||||
OrgINN string
|
OrgINN string
|
||||||
OrgName string
|
OrgName string // краткое (OD_FACES.NAME)
|
||||||
OrgShort string
|
OrgShort string // = OrgName (MNEM в DEPO — мнемоника, не наименование)
|
||||||
OrgEng string
|
OrgEng string // английское краткое
|
||||||
|
OrgFull string // полное (OD_U_FACES.FULL_NAME)
|
||||||
|
OrgEngFull string // английское полное
|
||||||
Notes []string // что не нашли / на что обратить внимание
|
Notes []string // что не нашли / на что обратить внимание
|
||||||
At time.Time
|
At time.Time
|
||||||
}
|
}
|
||||||
@@ -127,15 +129,23 @@ func depoDetectRequisites(ctx context.Context, fs FancyMSSQLSettings) (*DepoRequ
|
|||||||
}
|
}
|
||||||
// организация по коду участника
|
// организация по коду участника
|
||||||
if res.DeponentCode != "" {
|
if res.DeponentCode != "" {
|
||||||
var name, inn, mnem, eng string
|
var name, inn, mnem, eng, full, engFull string
|
||||||
err := db.QueryRowContext(ctx, fsql.Det02, sql.Named("code", res.DeponentCode)).Scan(&name, &inn, &mnem, &eng)
|
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 {
|
switch {
|
||||||
case err == sql.ErrNoRows:
|
case err == sql.ErrNoRows:
|
||||||
res.Notes = append(res.Notes, "лицо с кодом "+res.DeponentCode+" в DEPO не найдено — ИНН и наименование организации введите вручную")
|
res.Notes = append(res.Notes, "лицо с кодом "+res.DeponentCode+" в DEPO не найдено — ИНН и наименование организации введите вручную")
|
||||||
case err != nil:
|
case err != nil:
|
||||||
res.Notes = append(res.Notes, "карточка организации: "+err.Error())
|
res.Notes = append(res.Notes, "карточка организации: "+err.Error())
|
||||||
default:
|
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
|
return res, nil
|
||||||
|
|||||||
@@ -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
|
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`
|
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,'')
|
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`
|
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`
|
||||||
|
|||||||
@@ -53,12 +53,30 @@ type participantFormData struct {
|
|||||||
// participantFormPrefill — предзаполнение из автоопределения DEPO и настроек НРД.
|
// participantFormPrefill — предзаполнение из автоопределения DEPO и настроек НРД.
|
||||||
func participantFormPrefill(rc *RuntimeConfig) participantFormData {
|
func participantFormPrefill(rc *RuntimeConfig) participantFormData {
|
||||||
var d 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.INN = strings.TrimSpace(r.OrgINN)
|
||||||
d.FullName = strings.TrimSpace(r.OrgName)
|
d.FullName = strings.TrimSpace(pick(r.OrgFull, r.OrgName))
|
||||||
d.ShortName = strings.TrimSpace(r.OrgShort)
|
d.ShortName = strings.TrimSpace(r.OrgName)
|
||||||
d.DisplayName = strings.TrimSpace(r.OrgShort)
|
d.DisplayName = strings.TrimSpace(r.OrgName)
|
||||||
d.EngFull = strings.TrimSpace(r.OrgEng)
|
if strings.TrimSpace(r.OrgEngFull) != "" {
|
||||||
|
d.EngFull = strings.TrimSpace(r.OrgEngFull)
|
||||||
|
d.EngShort = strings.TrimSpace(r.OrgEng)
|
||||||
|
d.EngDisplay = d.EngShort
|
||||||
|
}
|
||||||
if d.DepoCode == "" {
|
if d.DepoCode == "" {
|
||||||
d.DepoCode = strings.TrimSpace(r.DeponentCode)
|
d.DepoCode = strings.TrimSpace(r.DeponentCode)
|
||||||
}
|
}
|
||||||
@@ -81,18 +99,13 @@ func participantFormPrefill(rc *RuntimeConfig) participantFormData {
|
|||||||
if ok {
|
if ok {
|
||||||
// НРД сверяет наименования анкеты со своей клиентской базой (M2M37) — карточка в справочнике
|
// НРД сверяет наименования анкеты со своей клиентской базой (M2M37) — карточка в справочнике
|
||||||
// НРД главнее DEPO: в DEPO «наименование» бывает кратким (21.10.2026 краткое ушло в FullName).
|
// НРД главнее DEPO: в DEPO «наименование» бывает кратким (21.10.2026 краткое ушло в FullName).
|
||||||
// Английские — только если их ввели: в справочнике есть лишь краткое, полного нет.
|
// Английские — из DEPO: в справочнике НРД есть лишь краткое.
|
||||||
if n := strings.TrimSpace(hb.FullName); n != "" {
|
if n := strings.TrimSpace(hb.FullName); n != "" {
|
||||||
d.FullName = n
|
d.FullName = n
|
||||||
}
|
}
|
||||||
if n := strings.TrimSpace(hb.Name); n != "" && hb.FullName != "" {
|
if n := strings.TrimSpace(hb.Name); n != "" && hb.FullName != "" {
|
||||||
d.ShortName, d.DisplayName = n, n // отображаемое НРД советует как краткое
|
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 == "" {
|
if hb.Kind == "broker" && d.BrokerCode == "" {
|
||||||
d.BrokerCode = strings.ToUpper(strings.TrimSpace(hb.Code))
|
d.BrokerCode = strings.ToUpper(strings.TrimSpace(hb.Code))
|
||||||
}
|
}
|
||||||
@@ -172,8 +185,8 @@ func pfNameCheck(rc *RuntimeConfig, d participantFormData) []string {
|
|||||||
if x.FullName != d.FullName {
|
if x.FullName != d.FullName {
|
||||||
w = append(w, "Полное наименование отличается от карточки нашей фирмы в справочнике НРД: «"+x.FullName+"». НРД сверяет с ней — без причины не меняйте.")
|
w = append(w, "Полное наименование отличается от карточки нашей фирмы в справочнике НРД: «"+x.FullName+"». НРД сверяет с ней — без причины не меняйте.")
|
||||||
}
|
}
|
||||||
default:
|
case strings.TrimSpace(d.FullName) == "":
|
||||||
w = append(w, "Наименования взяты из DEPO, в справочнике НРД нашей карточки нет. НРД сверяет их со своей клиентской базой — уточните точные наименования у НРД и впишите как есть.")
|
w = append(w, "Полного наименования нет ни в DEPO, ни в справочнике НРД — уточните его у НРД и впишите как есть.")
|
||||||
}
|
}
|
||||||
if pfAbbrRe.MatchString(d.FullName) || (d.FullName != "" && d.FullName == d.ShortName) {
|
if pfAbbrRe.MatchString(d.FullName) || (d.FullName != "" && d.FullName == d.ShortName) {
|
||||||
w = append(w, "Полное наименование похоже на сокращённое — нужно полное («Общество с ограниченной ответственностью …»), как в клиентской базе НРД.")
|
w = append(w, "Полное наименование похоже на сокращённое — нужно полное («Общество с ограниченной ответственностью …»), как в клиентской базе НРД.")
|
||||||
@@ -539,7 +552,7 @@ pre{background:#f6f8fa;border:1px solid #ddd;border-radius:8px;padding:12px;over
|
|||||||
Без регистрации сервис отбивает запросы кодом <b>M2M14</b>. В боевом контуре анкета подаётся <b>через ИШ</b>
|
Без регистрации сервис отбивает запросы кодом <b>M2M14</b>. В боевом контуре анкета подаётся <b>через ИШ</b>
|
||||||
пакетом <code>#M2MPF</code> (businessLine=MOST, подпись боевым контейнером на стороне ИШ); письмо на
|
пакетом <code>#M2MPF</code> (businessLine=MOST, подпись боевым контейнером на стороне ИШ); письмо на
|
||||||
<code>` + participantFormRecipient + `</code> оставлено запасным каналом. Наименования должны точно совпадать с
|
<code>` + participantFormRecipient + `</code> оставлено запасным каналом. Наименования должны точно совпадать с
|
||||||
клиентской базой НРД (иначе <b>M2M37</b>): bj берёт их из карточки нашей фирмы в справочнике НРД, а если её нет — из DEPO.
|
клиентской базой НРД (иначе <b>M2M37</b>): bj берёт их из карточки нашей фирмы в справочнике НРД и из DEPO (полное — карточка юрлица).
|
||||||
Чего нет или в чём bj не уверен — уточните у НРД. Кавычки — прямые <code>"</code>.</p>
|
Чего нет или в чём bj не уверен — уточните у НРД. Кавычки — прямые <code>"</code>.</p>
|
||||||
` + regHTML + flashHTML + vErr + `
|
` + regHTML + flashHTML + vErr + `
|
||||||
<form method="post">
|
<form method="post">
|
||||||
|
|||||||
@@ -32,10 +32,26 @@ func TestParticipantFormNames(t *testing.T) {
|
|||||||
func TestParticipantNameCheck(t *testing.T) {
|
func TestParticipantNameCheck(t *testing.T) {
|
||||||
d := participantFormData{FullName: `ООО "ИК "Фонтвьель"`, ShortName: `ООО "ИК "Фонтвьель"`}
|
d := participantFormData{FullName: `ООО "ИК "Фонтвьель"`, ShortName: `ООО "ИК "Фонтвьель"`}
|
||||||
ws := pfNameCheck(nil, d)
|
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)
|
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") {
|
if !strings.Contains(pfAskNSD("MC0413600000"), "MC0413600000") {
|
||||||
t.Error("в запросе нет кода участника")
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user