feat(m2m): доменная модель сообщений + парсер windows-1251 + round-trip тесты

- internal/m2m/types.go: enum'ы и simple-типы из XSD НРД (M2MSchemas_260408)
- internal/m2m/validators.go: pattern-валидаторы ReferenceID/ISIN/INN/UUID/SecurityCode/IdentityDocSerial/AccountID + перечисления
- internal/m2m/messages.go: структуры 6 типов сообщений M2M, choice-типы через указатели, IsM2M=true автоматически в MarshalXML
- internal/nsdxml/datetime.go: тип NSDDateTime (формат "YYYY-MM-DDThh:mm:ss(МСК+N)")
- internal/nsdxml/codec.go: Marshal/Unmarshal XML в windows-1251 (собственный кодек CP1251, без внешних зависимостей)
- internal/m2m/messages_test.go: round-trip тесты на 6 примерах + 2 эталонах из DOC/

Покрытие: m2m 73.9%, nsdxml 92.5%. make ci зелёный.

Отклонение от спеки: вместо golang.org/x/text/encoding/charmap собственная
таблица CP1251 на ~60 строк, потому что прокси zetit блокирует
proxy.golang.org, goproxy.cn и redirect-хосты Go-модулей.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
fontvielle
2026-05-14 00:30:46 +03:00
parent 3437590d44
commit 1d6ab86a57
11 changed files with 1795 additions and 25 deletions
+42 -15
View File
@@ -1,24 +1,51 @@
# internal/m2m — доменные модели сообщений M2M
Go-модели, генерируемые/выровненные по XSD из `DOC/M2MSchemas_260408/`
Go-модели, выровненные по XSD из `DOC/M2MSchemas_260408/`
(namespace `http://nsd.ru/schemas/m2m/...`, version `2026-04-08`).
Состав:
## Что реализовано
- `M2MTransferRequest` — запрос на перевод.
- `M2MTransferDecision` — решение принимающей стороны.
- `M2MTransferResponse` — тех. ответ НРД (`StatusCode ∈ {INFO, ERROR}`).
- `M2MTransferHandbook(+Request)` — справочник участников.
- `M2MTransferParticipantForm` — карточка участника.
- Все 6 типов сообщений M2M (`messages.go`):
- `M2MTransferRequest` — запрос на перевод.
- `M2MTransferDecision` — решение принимающей стороны.
- `M2MTransferResponse` — тех. ответ НРД (`StatusCode ∈ {INFO, ERROR}`).
- `M2MTransferHandbook` + `M2MTransferHandbookRequest` — справочник
участников.
- `M2MTransferParticipantForm` — карточка участника.
- Simple-типы и enum'ы из XSD (`types.go`):
`DeponentCode`, `ReferenceID`, `ISIN`, `OrganizationINN`, `UUID`,
`AccountID`, `SecurityCode`, `IdentityDocSerial`,
`StatusCode`, `IIAContractType`, `SecurityClassification`,
`SecurityCategory`, `IdentityDocumentCode`, `IsolationStatus`.
- Метод `Validate() error` на всех типах (`validators.go`).
- Choice-типы реализованы как структуры с указателями на
взаимоисключающие поля: `CostInfo`, `Quantity`, `SecurityDetails`,
`IdentificationDetails`, `DecisionTransfer`. Метод `Validate`
проверяет «ровно одно поле задано» (ошибка `ErrChoice`).
- `IsM2M=true` проставляется автоматически в `RequestData.MarshalXML`
и не выносится в структуру.
Точные ограничения (валидаторы):
## Точные ограничения валидаторов
- `ReferenceId` — длина 16, pattern `M2M[A-Z0-9]{13}`.
- `DeponentCode`до 12 символов, `[A-Z0-9]*`.
- `ISIN` — длина 12, `[A-Z]{2}[A-Z0-9]{9}[0-9]`.
- `ReferenceID` — длина 16, `^M2M[A-Z0-9]{13}$`.
- `DeponentCode`1..12 символов, `^[A-Z0-9]+$`.
- `ISIN` — длина 12, `^[A-Z]{2}[A-Z0-9]{9}[0-9]$`.
- `OrganizationINN` — ровно 10 цифр.
- `IIAContractType``T12 | T03`.
- `SecurityClassification``BOND | SHAR | MFUN`.
- `IsolationStatus` — единственное значение `SGDN`.
- `UUID` — 8-4-4-4-12 hex-символов с дефисами (XSD НРД не требует
битов версии/варианта по RFC).
- `SecurityCode` — длина 12, `^[0-9A-Z_/-]+$`.
- `IdentityDocSerial``^\S+$` (от 1 символа, без пробельных).
- `AccountID` — 1..50 символов.
- Перечисления валидируются как принадлежность к множеству значений
из XSD.
Реализация — задача M1 (см. план).
## Тесты
- Round-trip на всех XML из `DOC/Примеры/` и
`DOC/Эталонные сообщения/` (`messages_test.go`).
- Юнит-тесты валидаторов на позитив и негатив (`TestValidatorsPositive`,
`TestValidatorsNegative`, `TestChoiceValidators`).
- Покрытие — 73.9%.
Сериализация и парсинг — пакет `internal/nsdxml` (XML windows-1251 и
`NSDDateTime`).