Тестирование DEPO: сценарии перевода (клиент и бумаги из DEPO, исход по каждой бумаге) с имитацией ответов НРД, пошаговая запись в FTV_M2M* и показ результата джобы; без отправки куда-либо, кроме базы DEPO; оповещения по тестовым GUID не рассылаются

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
zuevav
2026-09-24 12:01:33 +03:00
parent b2f8652381
commit f4f11dd583
9 changed files with 526 additions and 6 deletions
@@ -0,0 +1,78 @@
{{define "content"}}
<style>
.dt-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:10px 14px}
.dt-grid label,.dt-lines label{display:block;font-size:12px;color:var(--muted);margin-bottom:3px}
.dt-grid select,.dt-grid input,.dt-lines select,.dt-lines input{width:100%;padding:7px 9px;border-radius:8px;border:1px solid var(--border);background:var(--card);color:var(--text);font-size:13.5px;box-sizing:border-box}
.dt-lines{display:grid;grid-template-columns:2fr 0.8fr 2fr 2fr;gap:8px 10px;margin-top:10px}
.dt-mode{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 12px}
.dt-mode label{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;border-radius:9px;border:1.5px solid var(--border);background:var(--card);cursor:pointer;font-weight:600;font-size:13px}
.dt-mode label:has(input:checked){border-color:var(--accent)}
.st{display:inline-block;padding:1px 8px;border-radius:999px;font-size:12px;font-weight:700}
.st.SUCCESS{background:var(--ok-weak,#e6f4ea);color:var(--ok,#12813f)}
.st.ERROR{background:var(--err-weak,#fbe9e7);color:var(--err,#b3261e)}
.st.TODO,.st.running{background:var(--warn-weak,#fff4e0);color:var(--warn,#9a6b12)}
.st.done{background:var(--ok-weak,#e6f4ea);color:var(--ok,#12813f)}
.st.error{background:var(--err-weak,#fbe9e7);color:var(--err,#b3261e)}
table.dt{width:100%;border-collapse:collapse;font-size:13px}
table.dt td,table.dt th{padding:5px 8px;border-bottom:1px solid var(--border);text-align:left;vertical-align:top}
.emu{color:var(--muted);font-size:12px}
@media (max-width:760px){.dt-lines{grid-template-columns:1fr 1fr}}
</style>
{{if .Flash}}<div class="card" style="border-color:var(--warn)">{{.Flash}}</div>{{end}}
<div class="card">
<h2>Тестирование DEPO — сценарии с имитацией НРД</h2>
<p class="muted" style="font-size:13px;margin-top:0">Перевод собирается из реальных данных DEPO и проигрывается по шагам так, как шёл бы в бою: bj пишет записи в трансферные таблицы
<code>FTV_M2M</code> / <code>FTV_M2M_LINES</code> / <code>FTV_M2M_EVENTS</code>, ответы НРД (решение контрагента, приём и исполнение поручения 16/16.1, отказ, истечение срока) имитируются.
После каждого шага bj ждёт, пока джоба обработки DEPO пометит запись, и показывает её STATE и комментарий.
<strong>В НРД, контрагенту, QUIK МНП и ЛК ничего не уходит. Документы в DEPO создаются настоящие</strong> — используйте тестового клиента.</p>
<p class="muted" style="font-size:12px">База: {{.DB}} · обработка DEPO: {{if .JobMode}}{{.JobMode}}{{else}}не настроена{{end}}</p>
<form method="post" action="/admin/depo-test/run">
<div class="dt-mode">
<label><input type="radio" name="direction" value="in" checked> ↘ Зачисление к нам (16/1)</label>
<label><input type="radio" name="direction" value="out"> ↗ Списание от нас (16)</label>
</div>
<div class="dt-grid">
<div><label>Контрагент (справочник участников НРД)</label>
<select name="cp" required>{{range .Parts}}<option value="{{.Code}}" {{if eq .Code "MC0034900000"}}selected{{end}}>{{.Name}} · {{.Code}}</option>{{end}}</select></div>
<div><label>Клиент из DEPO (открытый торговый счёт)</label>
<select name="client" required><option value="">— выбрать —</option>{{range .Clients}}<option value="{{.Name}}|{{.Ser}}|{{.Num}}" {{if eq .Num "289090"}}selected{{end}}>{{.Name}} · {{.Ser}} {{.Num}} · {{.Account}}</option>{{end}}</select></div>
<div><label>Пауза между шагами (имитация задержек НРД)</label>
<select name="pace"><option value="0">без пауз — по готовности джобы</option><option value="5">5 с</option><option value="15">15 с</option><option value="60">1 мин</option></select></div>
<div><label>&nbsp;</label><label style="display:flex;gap:8px;align-items:center;color:var(--text);font-size:13px"><input type="checkbox" name="stop" value="1" checked style="width:auto"> остановиться на первой ошибке джобы</label></div>
</div>
<datalist id="dt-secs">{{range .Secs}}<option value="{{.ISIN}}">{{.Name}}</option>{{end}}</datalist>
<div class="dt-lines">
<label>Бумага (ISIN)</label><label>Кол-во</label><label>Исход (ответ НРД)</label><label>Код отказа (для «отказ по M2M»)</label>
{{$o := .Outcomes}}{{$c := .Codes}}
{{range $i, $n := (slice "1" "2" "3" "4" "5")}}
<input name="isin{{$n}}" list="dt-secs" placeholder="{{if eq $n "1"}}RU0009029540{{else}}— не обязательно —{{end}}" {{if eq $n "1"}}value="RU0009029540"{{end}}>
<input name="qty{{$n}}" value="1" inputmode="decimal">
<select name="out{{$n}}">{{range $o}}<option value="{{.Code}}">{{.Title}}</option>{{end}}</select>
<select name="code{{$n}}"><option value="">—</option>{{range $c}}<option value="{{.Code}}">{{.Title}}</option>{{end}}</select>
{{end}}
</div>
<p class="muted" style="font-size:12px">Разные исходы у разных бумаг = частичное исполнение. «Отказ по M2M» при зачислении — наш отказ (BJ_DECISION_REJECT), при списании — отказ контрагента (BJ_CP_REJECT).</p>
<button type="submit" class="btn btn-ok">Запустить сценарий</button>
</form>
</div>
{{range .Runs}}
<div class="card" id="run-{{.ID}}">
<h2 style="margin-bottom:4px"><span class="st {{.Status}}">{{if eq .Status "running"}}идёт{{else if eq .Status "done"}}завершён{{else}}ошибка{{end}}</span>
{{if eq .Direction "out"}}↗ Списание{{else}}↘ Зачисление{{end}} · {{.Client}} · {{.CPName}} ({{.CP}})</h2>
<p class="muted" style="font-size:12px;margin-top:0">Прогон {{.ID}} · {{.Created.Format "02.01.2006 15:04:05"}} · GUID <code>{{.GUID}}</code> · документ DEPO {{if .Doc}}№ {{.Doc}}{{else}}—{{end}} · шапка <span class="st {{.HeaderState}}">{{.HeaderState}}</span>{{if .Errors}} · <span class="st ERROR">ошибок: {{.Errors}}</span>{{end}}</p>
<table class="dt"><tr><th>Бумага</th><th>Кол-во</th><th>Сценарий</th><th>Строка DEPO</th></tr>
{{range .Lines}}<tr><td>{{.ISIN}}<br><span class="emu">{{.Ref}}</span></td><td>{{.Qty}}</td><td>{{.Outcome}}{{if .Code}} {{.Code}}{{end}}</td><td>{{if .State}}<span class="st {{.State}}">{{.State}}</span> {{if .DOL}}№ {{.DOL}}{{end}} {{.Comment}}{{else}}—{{end}}</td></tr>{{end}}
</table>
<details {{if eq .Status "running"}}open{{end}} style="margin-top:8px"><summary>Шаги ({{len .Steps}})</summary>
<table class="dt"><tr><th>Время</th><th>Шаг</th><th>Событие / строка</th><th>Джоба DEPO</th></tr>
{{range .Steps}}<tr><td>{{.At.Format "15:04:05"}}</td><td>{{.Title}}{{if .Emulated}}<br><span class="emu">имитация — {{.Emulated}}</span>{{end}}</td><td><code>{{.Event}}</code><br><span class="emu">{{.Ref}}</span></td><td>{{if .State}}<span class="st {{.State}}">{{.State}}</span>{{end}} {{.Comment}}</td></tr>{{end}}
</table></details>
</div>
{{end}}
{{if .Running}}<script>setTimeout(function(){location.reload()},4000)</script>{{end}}
{{end}}
+1 -1
View File
@@ -329,7 +329,7 @@ label { font-size:13px; font-weight:500; }
<a href="/admin/incoming">Входящие<span id="nav-incoming-badge" style="display:none;margin-left:5px;background:var(--err);color:#fff;border-radius:10px;padding:1px 7px;font-size:11px;font-weight:700"></span></a>
</span>
</span>
{{end}}{{if can "view"}}<a href="/admin/manual" class="{{if eq .Active "manual"}}active{{end}}">Ручной ввод M2M</a>{{end}}{{if and devOn (can "operate")}}<a href="/admin/m2m-testing" class="{{if eq .Active "m2mtest"}}active{{end}}">Тестирование M2M</a>{{end}}
{{end}}{{if can "view"}}<a href="/admin/manual" class="{{if eq .Active "manual"}}active{{end}}">Ручной ввод M2M</a>{{end}}{{if can "settings"}}<a href="/admin/depo-test" class="{{if eq .Active "depotest"}}active{{end}}">Тест DEPO</a>{{end}}{{if and devOn (can "operate")}}<a href="/admin/m2m-testing" class="{{if eq .Active "m2mtest"}}active{{end}}">Тестирование M2M</a>{{end}}
{{if and .NPR (can "npr")}}<a href="/admin/npr" class="{{if eq .Active "npr"}}active{{end}}">НПР / УДС</a>{{end}}
{{if or (can "view") (can "quik")}}<span class="dd{{if or (eq .Active "fancy") (eq .Active "quik") (eq .Active "news") (eq .Active "handbook")}} active{{end}}">
<span class="ddbtn">Обмен ▾</span>