diff --git a/internal/lkgateway/admin.go b/internal/lkgateway/admin.go index 28bb043..067e265 100644 --- a/internal/lkgateway/admin.go +++ b/internal/lkgateway/admin.go @@ -566,6 +566,10 @@ func RegisterAdmin(mux *http.ServeMux, svc *Service, rc *RuntimeConfig, getOpts a.renderClaim(w, r, svc, id) case p == "status": a.renderStatus(w, r, getOpts()) + case p == "handbook/export.json": + a.exportHandbook(w, "json") + case p == "handbook/export.xml": + a.exportHandbook(w, "xml") case p == "handbook": a.renderHandbook(w, r) case p == "help": diff --git a/internal/lkgateway/handbook_export.go b/internal/lkgateway/handbook_export.go new file mode 100644 index 0000000..cd3b80f --- /dev/null +++ b/internal/lkgateway/handbook_export.go @@ -0,0 +1,87 @@ +package lkgateway + +// handbook_export.go — выгрузка справочника участников M2M со страницы +// /admin/handbook в файлах JSON и XML. Данные — самый свежий справочник +// (readHandbook): полученный от НРД #M2MTH, копия с сервера лицензий или +// встроенный снимок. Только чтение, доступ — под админ-авторизацией /admin/*. + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "net/http" + "time" +) + +// hbEntryXML — запись справочника в XML (атрибутами, как плоский JSON). +type hbEntryXML struct { + INN string `xml:"inn,attr,omitempty"` + Code string `xml:"code,attr,omitempty"` + Kind string `xml:"kind,attr,omitempty"` + Name string `xml:"name,attr,omitempty"` + FullName string `xml:"fullName,attr,omitempty"` + DisplayName string `xml:"displayName,attr,omitempty"` + EngName string `xml:"engName,attr,omitempty"` +} + +// hbExportXML — корень XML-выгрузки справочника. +type hbExportXML struct { + XMLName xml.Name `xml:"M2MHandbook"` + At string `xml:"at,attr,omitempty"` + Participants []hbEntryXML `xml:"Participants>Participant"` + Places []hbEntryXML `xml:"SettlementPlaces>Place"` +} + +func hbEntryToXML(e HandbookEntry) hbEntryXML { + return hbEntryXML{INN: e.INN, Code: e.Code, Kind: e.Kind, Name: e.Name, + FullName: e.FullName, DisplayName: e.DisplayName, EngName: e.EngName} +} + +// exportHandbook отдаёт сохранённый справочник участников M2M файлом JSON или XML. +func (a *admin) exportHandbook(w http.ResponseWriter, format string) { + raw, err := readHandbook() + if err != nil || len(raw) == 0 { + http.Error(w, "Справочник ещё не загружен — запросите его у НРД.", http.StatusNotFound) + return + } + var hb struct { + At string `json:"at"` + Participants []HandbookEntry `json:"participants"` + Places []HandbookEntry `json:"settlement_places"` + } + if err := json.Unmarshal(raw, &hb); err != nil { + http.Error(w, "Справочник повреждён: "+err.Error(), http.StatusInternalServerError) + return + } + day := time.Now().Format("2006-01-02") + if format == "xml" { + doc := hbExportXML{At: hb.At} + for _, p := range hb.Participants { + doc.Participants = append(doc.Participants, hbEntryToXML(p)) + } + for _, p := range hb.Places { + doc.Places = append(doc.Places, hbEntryToXML(p)) + } + out, err := xml.MarshalIndent(doc, "", " ") + if err != nil { + http.Error(w, "Не удалось сформировать XML: "+err.Error(), http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/xml; charset=utf-8") + w.Header().Set("Content-Disposition", `attachment; filename="m2m-handbook-`+day+`.xml"`) + w.Header().Set("Cache-Control", "no-store") + _, _ = w.Write([]byte(xml.Header)) + _, _ = w.Write(out) + return + } + // JSON — отдаём сохранённый справочник как есть, с отступами для читаемости. + var buf bytes.Buffer + if json.Indent(&buf, raw, "", " ") != nil { + buf.Reset() + buf.Write(raw) + } + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Disposition", `attachment; filename="m2m-handbook-`+day+`.json"`) + w.Header().Set("Cache-Control", "no-store") + _, _ = w.Write(buf.Bytes()) +} diff --git a/internal/lkgateway/web/templates/admin_handbook.html b/internal/lkgateway/web/templates/admin_handbook.html index 3f1fb14..6e022e9 100644 --- a/internal/lkgateway/web/templates/admin_handbook.html +++ b/internal/lkgateway/web/templates/admin_handbook.html @@ -45,6 +45,8 @@ + JSON + XML