Анкета участника M2M: сформировать → проверить → отправить в НРД (обычный канал)
Требование НРД при подключении к сервису M2M (МОСТ): зарегистрировать организацию в справочнике участников анкетой M2MTransferParticipantForm, иначе сервис отбивает запросы кодом M2M14. Регистрация идёт ОБЫЧНЫМ каналом (письмом на M2MOST@nsd.ru с вложением), не через M2M-шлюз. - Новая страница /admin/setup/participant-form (participant_form.go): предзаполнение из автоопределения DEPO (ИНН, наименования, код депозитария), правка оператором, валидация (формат ИНН/кодов + m2m.HandbookParticipant.Validate), предпросмотр анкеты, «Скачать» (windows-1251) и «Отправить в НРД» письмом с вложением-анкетой. - Генерация XML строкой-шаблоном по образцу НРД (namespace participant/form, CreationTimestamp по МСК, блоки Eng/BrokerPlace — опциональны), кодировка windows-1251 через nsdxml.EncodeWindows1251; экранирование текста только & < >. - Почта: выделен транспорт smtpDeliver из sendSMTP; добавлены buildMIMEAttach (multipart/mixed + base64-вложение) и sendSMTPAttach. - Тесты: валидация, генерация XML (Eng/BrokerPlace), cp1251 round-trip, MIME-вложение. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XG3zNMMf2LMoDpXo22mwMX
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
package lkgateway
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/nsdxml"
|
||||
)
|
||||
|
||||
func validPF() participantFormData {
|
||||
return participantFormData{
|
||||
INN: "7703807489", FullName: `ООО "Фонтвьель"`, ShortName: "Фонтвьель",
|
||||
DisplayName: "Фонтвьель", DepoCode: "MC0413600000",
|
||||
}
|
||||
}
|
||||
|
||||
func TestParticipantFormValidate(t *testing.T) {
|
||||
if errs := participantFormValidate(validPF()); len(errs) != 0 {
|
||||
t.Fatalf("корректная анкета должна проходить, получили: %v", errs)
|
||||
}
|
||||
bad := validPF()
|
||||
bad.INN = "770380748" // 9 цифр
|
||||
if errs := participantFormValidate(bad); len(errs) == 0 {
|
||||
t.Fatal("ИНН из 9 цифр должен отклоняться")
|
||||
}
|
||||
bad = validPF()
|
||||
bad.DepoCode = "XX0413600000"
|
||||
if errs := participantFormValidate(bad); len(errs) == 0 {
|
||||
t.Fatal("код не в формате MC+10 должен отклоняться")
|
||||
}
|
||||
bad = validPF()
|
||||
bad.DisplayName = ""
|
||||
if errs := participantFormValidate(bad); len(errs) == 0 {
|
||||
t.Fatal("пустой DisplayName должен отклоняться")
|
||||
}
|
||||
bad = validPF()
|
||||
bad.BrokerCode = "MC12" // неверный формат
|
||||
if errs := participantFormValidate(bad); len(errs) == 0 {
|
||||
t.Fatal("неверный код брокера должен отклоняться")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParticipantFormXML(t *testing.T) {
|
||||
x := participantFormXML(validPF())
|
||||
for _, want := range []string{
|
||||
`encoding="windows-1251"`,
|
||||
`<pf:M2MTransferParticipantForm`,
|
||||
`http://nsd.ru/schemas/m2m/participant/form`,
|
||||
`<m2m:INN>7703807489</m2m:INN>`,
|
||||
`<m2m:DepositoryPlace>`,
|
||||
`<m2m:ParticipantCode>MC0413600000</m2m:ParticipantCode>`,
|
||||
`(МСК)`,
|
||||
} {
|
||||
if !strings.Contains(x, want) {
|
||||
t.Errorf("XML должен содержать %q\n---\n%s", want, x)
|
||||
}
|
||||
}
|
||||
if strings.Contains(x, "<m2m:Eng>") {
|
||||
t.Error("без англ. полей блок Eng не должен появляться")
|
||||
}
|
||||
if strings.Contains(x, "<m2m:BrokerPlace>") {
|
||||
t.Error("без кода брокера блок BrokerPlace не должен появляться")
|
||||
}
|
||||
// С англ. и брокером — блоки появляются.
|
||||
d := validPF()
|
||||
d.EngFull, d.BrokerCode = "Fontvielle LLC", "MC0413600001"
|
||||
x2 := participantFormXML(d)
|
||||
if !strings.Contains(x2, "<m2m:Eng>") || !strings.Contains(x2, "Fontvielle LLC") {
|
||||
t.Error("с англ. наименованием блок Eng обязателен")
|
||||
}
|
||||
if !strings.Contains(x2, "<m2m:BrokerPlace>") || !strings.Contains(x2, "MC0413600001") {
|
||||
t.Error("с кодом брокера блок BrokerPlace обязателен")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParticipantFormBytesCP1251(t *testing.T) {
|
||||
b, err := participantFormBytes(validPF())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Декод обратно из 1251 — кириллица восстанавливается.
|
||||
got := string(nsdxml.DecodeWindows1251(b))
|
||||
if !strings.Contains(got, `ООО "Фонтвьель"`) {
|
||||
t.Errorf("после cp1251 round-trip потеряна кириллица:\n%s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildMIMEAttach(t *testing.T) {
|
||||
msg := string(buildMIMEAttach("a@b.ru", []string{"M2MOST@nsd.ru"}, "Тема", "тело", "form.xml", []byte("<xml/>"), "application/xml"))
|
||||
for _, want := range []string{
|
||||
"multipart/mixed; boundary=",
|
||||
"Content-Disposition: attachment; filename=\"form.xml\"",
|
||||
"Content-Transfer-Encoding: base64",
|
||||
"To: M2MOST@nsd.ru",
|
||||
} {
|
||||
if !strings.Contains(msg, want) {
|
||||
t.Errorf("MIME должен содержать %q", want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user