Ручной ввод: без обязательных галок, удаление черновика, запрет количества больше остатка; отказ НРД по поручению — красным
- ручных отметок перед отправкой нет: автор виден по учётной записи, клиент/счёт/остаток/
бумага проверены сверкой с DEPO при сохранении; блокировка в QUIK — необязательно,
по умолчанию не требуется (модуль неторговых поручений сейчас не используется)
- «Удалить черновик» в карточке (POST /admin/manual/{id}/delete), только для черновиков
- количество не больше остатка на торговом разделе: проверка в форме (по выбранной бумаге)
и на сервере при сохранении (по счёту DEPO) — поручение с превышением не сохраняется
- отчёт MS010 с отказом: orderResponse.Rejected, OutgoingDeal.Rejected; шаг «Операция
завершена отказом» и бейдж — красные в карточках исходящего и входящего; онлайн-статус
«поручение 16 завершено отказом НРД»
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
This commit is contained in:
@@ -6,6 +6,7 @@ package lkgateway
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -195,3 +196,62 @@ func registerManualDepo(mux *http.ServeMux, rc *RuntimeConfig) {
|
||||
reply(w, items, errS)
|
||||
})
|
||||
}
|
||||
|
||||
// manualDepoClientByAccount — OD_CLIENTS.ID открытого торгового счёта по его номеру.
|
||||
func manualDepoClientByAccount(rc *RuntimeConfig, number string) (int64, string) {
|
||||
number = strings.TrimSpace(number)
|
||||
if number == "" || !manualDepoConfigured(rc) {
|
||||
return 0, ""
|
||||
}
|
||||
db, ctx, cancel, errS := depoOpen(rc.Snapshot().Fancy)
|
||||
if errS != "" {
|
||||
return 0, errS
|
||||
}
|
||||
defer cancel()
|
||||
defer db.Close()
|
||||
var id int64
|
||||
err := db.QueryRowContext(ctx, `SELECT TOP 1 ID FROM OD_CLIENTS WHERE NUMBER=@n AND STATE=0 AND D_CLOSE IS NULL ORDER BY ID`,
|
||||
sql.Named("n", number)).Scan(&id)
|
||||
if err != nil {
|
||||
return 0, ""
|
||||
}
|
||||
return id, ""
|
||||
}
|
||||
|
||||
// manualQtyOverAvailable — количество в поручении больше остатка на торговом разделе.
|
||||
// Пусто — всё в порядке или остаток проверить нельзя (DEPO не подключена, счёт не найден):
|
||||
// тогда решает сверка при сохранении. Смысл: поручение на 111 бумаг при 110 на счёте не
|
||||
// должно даже сохраниться — дальше по цепочке ему всё равно идти некуда.
|
||||
func manualQtyOverAvailable(rc *RuntimeConfig, depoClient string, o *ManualOrder) string {
|
||||
if !manualDepoConfigured(rc) || o == nil {
|
||||
return ""
|
||||
}
|
||||
id, _ := strconv.ParseInt(strings.TrimSpace(depoClient), 10, 64)
|
||||
if id <= 0 {
|
||||
id, _ = manualDepoClientByAccount(rc, o.Account)
|
||||
}
|
||||
if id <= 0 {
|
||||
return ""
|
||||
}
|
||||
pos, errS := manualDepoPositions(rc, id)
|
||||
if errS != "" {
|
||||
return ""
|
||||
}
|
||||
for _, sec := range o.Securities {
|
||||
isin := strings.ToUpper(strings.TrimSpace(sec.ISIN))
|
||||
if isin == "" {
|
||||
continue
|
||||
}
|
||||
q, err := strconv.ParseFloat(strings.ReplaceAll(strings.TrimSpace(sec.Qty), ",", "."), 64)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, p := range pos {
|
||||
if p.ISIN == isin && q > p.Qty+1e-9 {
|
||||
return fmt.Sprintf("По бумаге %s на торговом разделе счёта %s доступно %s шт., а в поручении %s — сохранить нельзя: укажите не больше доступного.",
|
||||
isin, o.Account, strconv.FormatFloat(p.Qty, 'f', -1, 64), strings.TrimSpace(sec.Qty))
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user