1С: проверка поручений МНП перед отправкой в НРД
Часть модуля onec-back, по умолчанию выключена, включается в настройках («Проверка поручений в 1С»). Исходящий перевод после блокировки бумаг в МНП ждёт решения 1С и в НРД не уходит, пока 1С не подтвердит каждое поручение; при отказе bj снимает поручения в QUIK с причиной из 1С и отклоняет перевод в журнале и кабинете клиента. - onec.instr / onec.instr_queue / onec.set_decision в базе bj: 1С читает очередь и пишет решение под логином onec_bj (только эти права); чтение очереди отмечает связь с 1С. - bj-onec-admin (root, через bj-keymedia): логин onec_bj, вход только с IP 1С по TLS (pg_hba.conf), listen_addresses, ufw; revoke закрывает вход. - onecLoop: отправка подтверждённых, отказы, снятие клиентом в QUIK, поручения из терминала, сроки решения и потеря связи — оповещения. - Карточка заявки: блок «Проверка 1С», решение оператора вместо 1С. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
This commit is contained in:
@@ -45,7 +45,10 @@
|
||||
<b>Перевод не доставлен в НРД</b> — {{sendFailText .}}.<br>
|
||||
<span class="muted">Попытка {{.At.Format "02.01.2006 15:04:05"}}{{if .PackageID}}, пакет {{.PackageID}}{{end}}{{if gt .Attempts 1}}, попыток: {{.Attempts}}{{end}}. Отправка в DEPO не отмечена, блокировка в QUIK МНП сохраняется. {{if .GaveUp}}Сутки прошли — автоповтор остановлен: отправьте вручную или удалите заявку.{{else}}Ничего нажимать не нужно: как только НРД снова ответит, bj сам отправит тот же запрос с тем же GUID (повтор — в течение суток). Кнопка «Отправить повторно» — если нужно попробовать прямо сейчас.{{end}}</span>
|
||||
</div>{{end}}
|
||||
{{if and .Claim.RequestRawXML (not .SentToNSD) (not .Fail)}}<div class="card" style="background:var(--warn-weak,#fbf3d9);margin:8px 0">
|
||||
{{if and .OneCWaiting (not .SentToNSD)}}<div class="card" style="background:var(--warn-weak,#fbf3d9);margin:8px 0">
|
||||
<b>⏳ Перевод ждёт решения 1С.</b><br>
|
||||
<span class="muted">Бумаги заблокированы в QUIK МНП. В НРД перевод уйдёт сам, как только 1С подтвердит поручения; при отказе bj снимет поручения в QUIK с причиной из 1С. Решить вместо 1С — в блоке «Проверка 1С» ниже.</span>
|
||||
{{else if and .Claim.RequestRawXML (not .SentToNSD) (not .Fail)}}<div class="card" style="background:var(--warn-weak,#fbf3d9);margin:8px 0">
|
||||
<b>⛔ В НРД ничего не отправлено — отмена до отправки.</b><br>
|
||||
<span class="muted">Пакет <code>M2MTransferRequest</code> сформирован, но в НРД <b>не направлялся</b>: заявка остановлена на проверке перед отправкой{{if .QuikFailReply}} — в QUIK МНП не удалось заблокировать бумаги{{if .QuikFailISIN}} ({{.QuikFailISIN}}){{end}}{{if .QuikNoSec}}: на счёте клиента нет/недостаточно бумаг для списания{{end}}{{end}}. Регистрация «Вывод ЦБ (M2M)» и блокировка идут в QUIK МНП <u>до</u> отправки в НРД, поэтому поручение 16 и запрос перевода в НРД не создавались. Устраните причину{{if .QuikNoSec}} (зачислите бумаги на счёт клиента){{end}} и отправьте заявку повторно.{{if .QuikFailReply}}<br>Ответ модуля QUIK: <code>{{.QuikFailReply}}</code>{{end}}</span>
|
||||
</div>{{end}}
|
||||
@@ -114,6 +117,32 @@
|
||||
|
||||
{{/* ===== QUIK МНП: поручение «Вывод ЦБ (M2M)» ===== */}}
|
||||
{{$back := printf "/admin/claims/%s" .Claim.ID}}
|
||||
{{if .OneC}}
|
||||
<div class="card">
|
||||
<h2 style="margin:0">Проверка 1С</h2>
|
||||
{{range .OneC}}
|
||||
<div style="border:1px solid var(--border);border-radius:10px;padding:10px 12px;margin-top:10px;font-size:13.5px">
|
||||
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap">
|
||||
<b><code>{{.ISIN}}</code>{{if .Qty}} × {{.Qty}}{{end}}</b>
|
||||
<span class="muted" style="font-size:12px">{{if .InstrNo}}поручение МНП <b>№{{.InstrNo}}</b>{{else}}поручения МНП нет — 1С проверить нечего{{end}}</span>
|
||||
<span class="qk-state {{if eq .Status "CONFIRMED"}}signed{{else if eq .Status "REJECTED"}}error{{else if eq .Status "CANCELLED"}}denied{{else}}registered{{end}}">{{.StatusRu}}</span>
|
||||
<span class="muted" style="font-size:12px">bj: {{.BJStateRu}}</span>
|
||||
</div>
|
||||
{{if .Reason}}<div style="font-size:12.5px;margin-top:4px;color:#b3261e">Причина: {{.Reason}}</div>{{end}}
|
||||
{{if .CheckedBy}}<div class="muted" style="font-size:12px;margin-top:2px">{{.CheckedBy}}{{if not .CheckedAt.IsZero}}, {{msk .CheckedAt}}{{end}}{{if .OneCDoc}} · {{.OneCDoc}}{{end}}</div>{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{if and .OneCWaiting (can "operate")}}
|
||||
<form method="post" action="/admin/onec/decide" style="margin:10px 0 0;display:flex;gap:8px;flex-wrap:wrap;align-items:center">
|
||||
<input type="hidden" name="guid" value="{{.Claim.M2MGUID}}"><input type="hidden" name="back" value="{{$back}}">
|
||||
<button class="btn btn-ok" name="decision" value="confirm" style="font-size:12px" onclick="return confirm('Подтвердить вместо 1С? Перевод уйдёт в НРД.')">✓ Подтвердить вместо 1С</button>
|
||||
<input type="text" name="reason" maxlength="255" placeholder="причина отказа — её увидит клиент" style="font-size:12px;width:260px">
|
||||
<button class="btn" name="decision" value="reject" style="font-size:12px" onclick="return confirm('Отклонить перевод? Поручения в QUIK будут сняты, клиент увидит причину.')">✕ Отклонить</button>
|
||||
</form>
|
||||
<p class="muted" style="font-size:12px;margin:6px 0 0">Решение оператора окончательное: 1С по этому поручению уже ничего не изменит.</p>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="card">
|
||||
<style>
|
||||
.qk-steps{display:flex;gap:8px;flex-wrap:wrap;margin:8px 0}
|
||||
|
||||
@@ -811,7 +811,7 @@
|
||||
{{if mod "onec-back"}}
|
||||
<section class="settings-section" id="sec-onec">
|
||||
<h1>1С: база бэк-офиса</h1>
|
||||
<p class="muted" style="margin:-8px 0 16px">Связь bj с базой 1С бэк-офиса. Модуль в разработке: сейчас здесь задаётся и проверяется подключение к базе, обмен данными появится в следующих выпусках.</p>
|
||||
<p class="muted" style="margin:-8px 0 16px">Связь bj с базой 1С бэк-офиса: подключение к базе через OData и проверка поручений на вывод бумаг в 1С перед отправкой в НРД.</p>
|
||||
<div class="card">
|
||||
<h2><span class="dot {{if .Settings.OneC.CheckOK}}ok{{else}}warn{{end}}"></span>Подключение к базе 1С</h2>
|
||||
<p class="muted">bj обращается к базе через стандартный интерфейс OData. Его включают при публикации базы: конфигуратор 1С → Администрирование → Публикация на веб-сервере → «Публиковать стандартный интерфейс OData».</p>
|
||||
@@ -830,6 +830,44 @@
|
||||
</form>
|
||||
{{with .Settings.OneC}}{{if not .CheckedAt.IsZero}}<p style="margin:14px 0 0;font-size:13.5px"><b style="color:var(--{{if .CheckOK}}ok{{else}}err{{end}})">{{if .CheckOK}}✓ Подключение работает{{else}}✗ Подключение не работает{{end}}</b> — {{.CheckMsg}} <span class="muted">(проверено {{.CheckedAt.Format "02.01.2006 15:04"}})</span></p>{{end}}{{end}}
|
||||
</div>
|
||||
{{$oc := .Settings.OneC.Check}}
|
||||
<div class="card" id="onec-check">
|
||||
<h2><span class="dot {{if not $oc.Enabled}}off{{else if $oc.AccessOK}}ok{{else}}warn{{end}}"></span>Проверка поручений в 1С</h2>
|
||||
<p class="muted">Исходящий перевод уходит в НРД только после того, как 1С подтвердила поручение МНП «Вывод ЦБ (M2M)». 1С забирает поручения из базы bj и записывает решение; при отказе bj снимает поручение в QUIK с причиной из 1С, клиент видит её в терминале. По умолчанию выключено.</p>
|
||||
{{if and $oc.Enabled (not .OneCCheck.QuikOK)}}<div class="alert alert-warn" style="margin-top:10px">QUIK МНП сейчас не регистрирует поручения на вывод сам (цикл QUIK выключен или вывод не автоматический). Переводы без поручения МНП 1С проверить не может — их подтверждает или отклоняет оператор в карточке заявки.</div>{{end}}
|
||||
<form method="post" action="/admin/setup/onec/check" style="margin-top:12px;display:grid;gap:12px;max-width:640px">
|
||||
<label style="font-size:14px"><input type="checkbox" name="enabled" value="1" {{if $oc.Enabled}}checked{{end}}> Включить проверку поручений в 1С</label>
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px">
|
||||
<div class="fld"><label>IP-адрес сервера 1С</label><input type="text" name="client_ips" value="{{$oc.ClientIPs}}" placeholder="10.0.0.15" autocomplete="off" style="margin-top:4px"><span class="muted" style="font-size:12px">Вход в базу bj — только с этого адреса; несколько — через запятую.</span></div>
|
||||
<div class="fld"><label>Срок решения 1С, минут</label><input type="number" name="timeout_min" min="5" max="1440" value="{{with $oc.TimeoutMin}}{{.}}{{else}}30{{end}}" style="margin-top:4px"><span class="muted" style="font-size:12px">Дольше — оповещение оператору (в рабочее время). Клиенту по сроку не отказываем.</span></div>
|
||||
</div>
|
||||
<div><button type="submit" class="btn">Сохранить</button></div>
|
||||
</form>
|
||||
{{if $oc.Enabled}}
|
||||
<div style="margin-top:16px;padding-top:12px;border-top:1px solid var(--border)">
|
||||
<h3 style="margin:0 0 6px;font-size:14px">Вход 1С в базу bj</h3>
|
||||
<p class="muted" style="margin:0 0 8px;font-size:12.5px">bj заводит в PostgreSQL логин <code>onec_bj</code> с правом только читать очередь и записывать решение, открывает вход с IP сервера 1С по TLS.</p>
|
||||
{{if not $oc.AccessAt.IsZero}}<p style="margin:0 0 8px;font-size:13.5px"><b style="color:var(--{{if $oc.AccessOK}}ok{{else}}err{{end}})">{{if $oc.AccessOK}}✓ Вход открыт{{else}}✗ Вход закрыт{{end}}</b> — {{$oc.AccessMsg}} <span class="muted">({{$oc.AccessAt.Format "02.01.2006 15:04"}})</span></p>{{end}}
|
||||
{{with .OneCCheck}}{{if .Password}}<div style="margin:0 0 10px;padding:10px 12px;border-radius:9px;background:var(--card-2);font-size:13.5px">
|
||||
Передайте программисту 1С — пароль показан <b>один раз</b>:<br>
|
||||
сервер <code>{{.Host}}</code>, порт <code>5432</code>, база <code>bj</code>, логин <code>onec_bj</code>, пароль <code>{{.Password}}</code>, <code>sslmode=require</code>
|
||||
</div>{{end}}{{end}}
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap">
|
||||
<form method="post" action="/admin/setup/onec/access" style="margin:0"><button class="btn" onclick="return confirm('Выдать логину onec_bj новый пароль и открыть вход в базу bj с IP сервера 1С? Прежний пароль перестанет работать. Если PostgreSQL слушал только этот сервер, он перезапустится — это несколько секунд.')">{{if $oc.AccessOK}}Выдать новый пароль{{else}}Открыть вход и выдать пароль{{end}}</button></form>
|
||||
{{if $oc.AccessOK}}<form method="post" action="/admin/setup/onec/revoke" style="margin:0"><button class="btn" style="background:var(--card);color:var(--err,#c0392b);border:1px solid var(--err,#c0392b)" onclick="return confirm('Закрыть вход логином onec_bj? 1С перестанет получать поручения, переводы будут ждать.')">Закрыть вход</button></form>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{with .OneCCheck}}
|
||||
<div style="margin-top:16px;padding-top:12px;border-top:1px solid var(--border);font-size:13.5px">
|
||||
{{if .DBErr}}<div class="alert alert-warn">База bj: {{.DBErr}}</div>{{end}}
|
||||
<p style="margin:0 0 8px">Ждут решения: <b>{{.Waiting}}</b> · 1С последний раз забирала поручения: <b>{{if .LastRead.IsZero}}ни разу{{else}}{{msk .LastRead}}{{end}}</b></p>
|
||||
{{if .Rows}}<div style="overflow-x:auto"><table style="font-size:12.5px"><thead><tr><th>Поручение МНП</th><th>Клиент</th><th>Бумага</th><th>Решение</th><th>bj</th></tr></thead><tbody>
|
||||
{{range .Rows}}<tr><td>{{if .InstrNo}}№{{.InstrNo}}{{else}}—{{end}}{{if eq .Source "terminal"}} <span class="muted">(терминал)</span>{{end}}</td><td>{{.Client}}</td><td><code>{{.ISIN}}</code> × {{.Qty}}</td><td>{{.StatusRu}}{{if .Reason}}: {{.Reason}}{{end}}{{if .CheckedBy}} <span class="muted">— {{.CheckedBy}}</span>{{end}}</td><td>{{.BJStateRu}}</td></tr>{{end}}
|
||||
</tbody></table></div>{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user