c021fb8273
Требование НРД при подключении к сервису 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
101 lines
3.5 KiB
Go
101 lines
3.5 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|