Цель обложки — предоставить быстрый доступ к основному функционалу модуля. Одна из таких функциональностей - поиск документов по некоторым заданным критериям. Проще всего расположить ссылку для открытия окна, в котором пользователь указывает критерии поиска. После чего отобразить список найденных документов.
Простые пути — не наш выбор. Поэтому попробуем обойтись без дополнительного окна, а сразу расположим поля для ввода критериев поиска на обложке. Это не слишком сложная задача, с учетом того, что аналог перед глазами — поиск РКК с обложки. Вот только одно дело — открыть список с фильтрацией. По документам реализация немного отличается.
Мы эту реализацию сделали. Спешу поделиться опытом с сообществом.
Предположим, есть у нас модуль Финансовый архив. И хотим мы реализовать поиск первичных учетных документов. В стандартной версии есть прикладной поиск (запись справочника Поиски) — Поиск первичных учетных документов:
Перенесем его на обложку.
Учитываем следующее:
Расположение полей на обложке нагло стащим с обложки того самого модуля Канцелярия. В итоге в htm будет такой большой узел:
<table class="table">
<tr>
<td class="ParameterName">
Наименование:
</td>
<td class="ParameterValue">
<input type="text" id="DocName" />
</td>
</tr>
<tr>
<td class="ParameterName">
Тип карточки:
</td>
<td class="ParameterValue">
<select id="DocType" style="width: 100%">
<option value=""></option>
<option value="DFAActsWaybills">Передаточные документы</option>
<option value="DFASourceFinanceDocument">Платежные документы</option>
<option value="DFAInvoices">Счета-фактуры</option>
</select>
</td>
</tr>
<tr>
<td class="ParameterName">
Вид документа:
</td>
<td class="ParameterValue">
<select id="DocKind" style="width: 100%">
<option value=""></option>
<option value="DFAIncomingActDocKind">Входящий акт</option>
<option value="DFAIncomingWaybillDocKind">Входящая накладная</option>
<option value="DFAIncomingInvoiceDocKind">Входящий счет-фактура</option>
<option value="DFAIncomingUTDDocKind">Входящий УПД</option>
<option value="DFAIncomingUTDInvDocKind">Входящий УПД со счетом-фактурой</option>
<option value="DFAOutgoingActDocKind">Исходящий акт</option>
<option value="DFAOutgoingWaybillDocKind">Исходящая накладная</option>
<option value="DFAOutgoingInvoiceDocKind">Исходящий счет-фактура</option>
<option value="DFAOutgoingUTDDocKind">Исходящий УПД</option>
<option value="DFAOutgoingUTDInvDocKind">Исходящий УПД со счетом-фактурой</option>
</select>
</td>
</tr>
<tr>
<td class="ParameterName">
Номер:
</td>
<td class="ParameterValue">
<input type="text" id="DocNumber" />
</td>
</tr>
<tr>
<td class="ParameterName">
Дата:
</td>
<td class="ParameterValue">
<input type="text" class="DatePicker" id="DocDateBgn" /> - <input type="text" class="DatePicker" id="DocDateEnd" />
</td>
</tr>
<tr>
<td class="ParameterName">
Контрагент:
</td>
<td class="ParameterValue">
<input type="text" id="Counterparty" />
</td>
</tr>
<tr>
<td class="ParameterName">
Наша организация:
</td>
<td class="ParameterValue">
<input type="text" id="OurFirm" />
</td>
</tr>
<tr>
<td class="ParameterName">
Договор:
</td>
<td class="ParameterValue">
<input type="text" id="Contract" />
</td>
</tr>
<tr>
<td class="ParameterName">
ИД:
</td>
<td class="ParameterValue">
<input type="text" id="DocID" />
</td>
</tr>
<tr>
<td colspan="2" style="text-align: right">
<input type="button" id="Find" onclick="DFADocSearch()" value=" Поиск " />
</td>
</tr>
</table>
Который будет выглядеть так:
Сам функционал вынесем в сценарий и на обложке останется реализовать лишь вызов сценария с параметрами, что довольно тривиально:
/**
* Поиск первичных документов
* @method DFADocSearch
* @param {string} UserID - ид текущего пользователя
*/
function DFADocSearch(UserID) {
var DocName = document.getElementById("DocName").value;
var DocType = document.getElementById("DocType").value;
var DocKind = document.getElementById("DocKind").value;
var DocNumber = document.getElementById("DocNumber").value;
var DocDateBgn = document.getElementById("DocDateBgn").value;
var DocDateEnd = document.getElementById("DocDateEnd").value;
var Counterparty = document.getElementById("Counterparty").value;
var OurFirm = document.getElementById("OurFirm").value;
var Contract = document.getElementById("Contract").value;
var DocID = document.getElementById("DocID").value;
ComponentExecuteInNewProcess("Script", "DFADocSearch",
"DocName=" + DocName +
"|DocType=" + DocType +
"|DocKind=" + DocKind +
"|DocNumber=" + DocNumber +
"|DocDateBgn=" + DocDateBgn +
"|DocDateEnd=" + DocDateEnd +
"|Counterparty=" + Counterparty +
"|OurFirm=" + OurFirm +
"|Contract=" + Contract +
"|DocID=" + DocID, "COMMON");
}
Завершающей стадией будет реализовать собственно поиск.
Что нужно учитывать? Чтобы по кнопке "Изменить критерии" в списке документов были только поля, важные для первички, поиск мы подгружаем из справочника "Поиски".
Search = Searches.Load("Поиск первичных учетных документов")
Search.Description = LoadString('DIRSCRIPT_4E192A2C_4A22_4D6F_A9EB_5EC74549E1B8'; 'DFA')
Номер документа — обычное строковое поле. И номер "15" при невнимательном поиске будет искать документы, в номере которых конструкция эта содержится. Например, отыщется документ с номером 150 и 115. Отсечем это так:
/* Критерий по номеру документа */
DocNumber = GetComponentLaunchParam('DocNumber'; '')
if DocNumber <<>> ''
Criterion = Search.SearchCriteria.Add("String2")
Criterion.SetCompleteValue("РАВНО " & DocNumber)
endif
Для того чтобы заполнить критерий по справочникам (в нашем случае это Контрагент, Наша организация, Договор), надо сначала найти их в справочнике. Поисков таких несколько, поэтому шаблон запроса вынесем в переменную LikeQueryTmpl. Запрос простенький, типа такого:
LikeQueryTmpl = "-- Сценарий DFADocSearch
select
rec.Kod
from
dbo.MBVidAn ref
inner join dbo.MBAnalit rec on
rec.Vid = ref.Vid
-- Тут будет критерий для поиска по наименованию
and %s
where
-- Код справочника будет меняться в зависимости от поля
ref.Kod = '%s'"
Поскольку нужно обеспечить, чтобы порядок слов не учитывался, можно найти каждое слово и поставить его в качестве одного из условий like-поиска. Сделать это можно, например, так:
// Поиск по контрагенту
RefLikeValue = GetComponentLaunchParam('Counterparty'; '')
if RefLikeValue <<>> ''
DEL = " " // Слова обычно разделяются пробелами
RefLikeValueList.Delimiter = DEL
ReqName = "Организация"
RefCode = "ОРГ"
// Учитываем возможные SQL-иньъекции
RefLikeValue = Replace(RefLikeValue; "'"; "''")
// Уберем лишние пробелы на случай если у пользователя дрогнула рука
RefLikeValue = Replace(RefLikeValue; " "; " ")
if SubStringCount(RefLikeValue; DEL) = 1
RefLikeValue = "NameAn like '%" & RefLikeValue & "%'"
else
RefLikeValue = Replace(RefLikeValue; DEL & DEL; DEL)
RefLikeValueList.DelimitedText = RefLikeValue
RefLikeValueList.Delimiter = "%') and (NameAn like '%"
RefLikeValue = "(NameAn like '%" & RefLikeValueList.DelimitedText & "%')"
endif
Criterion = Search.SearchCriteria.Add(ReqName)
Query = Format(LikeQueryTmpl; ArrayOf(RefLikeValue; RefCode))
Values = SQL(Query;; CONST_ELEMENT_DELIMITER; CONST_VALUE_DELIMITER)
foreach Code in CSubString(Values; CONST_ELEMENT_DELIMITER)
Criterion.Add(Code)
endforeach
Criterion.ValuesBuildType = btOr
endif
Этот вариант вполне себе рабочий, вот только при попытке изменить критерии видим ужасное:
Почему в типах карточках красивое и читабельное название, а в другом поле коды с пробелами? Нехорошо. Но решаемо. Из всех вариантов заполнения критериев используем AddWithPhysical. Для этого метода одного кода записи не достаточно, поэтому запросом достанем ИД и Наименование записи:
LikeQueryTmpl = "-- Сценарий DFADocSearch
select
rtrim(ltrim(rec.NameAn)), rec.xRecID
from
dbo.MBVidAn ref
inner join dbo.MBAnalit rec on
rec.Vid = ref.Vid and %s
where
ref.Kod = '%s'"
И используем полученные данные:
Query = Format(LikeQueryTmpl; ArrayOf(RefLikeValue; RefCode))
Values = SQL(Query;; CONST_ELEMENT_DELIMITER; CONST_VALUE_DELIMITER)
foreach Value in CSubString(Values; CONST_ELEMENT_DELIMITER)
Criterion.AddWithPhysical(SubString(Value; CONST_VALUE_DELIMITER; 1); SubString(Value; CONST_VALUE_DELIMITER; 2))
endforeach
Получаем вполне себе читабельный вариант:
Ну и в завершение посмотрим, как мы искали виды документов по имени константы: на обложке в выпадающем списке 10 значений, соответствующих не самим видам, а константам:
// Поиск по виду документа
DocKind = GetComponentLaunchParam('DocKind'; '')
if DocKind <<>> ''
RefCode = "ВЭД"
ReqName = 'ISBEDocKind'
// Получить виды документов из константы
RefLikeValueList.Delimiter = ','
RefLikeValueList.DelimitedText = Replace(GetConstant(DocKind); " "; '')
Criterion = Search.SearchCriteria.Add(ReqName)
if RefLikeValueList.Count = 1
Criterion.SetCompleteValue(RefLikeValueList.DelimitedText)
else
RefLikeValueList.Delimiter = "','"
RefLikeValue = "rtrim(ltrim(rec.Kod)) in ('" & RefLikeValueList.DelimitedText & "')"
Query = Format(LikeQueryTmpl; ArrayOf(RefLikeValue; RefCode))
Values = SQL(Query;; CONST_ELEMENT_DELIMITER; CONST_VALUE_DELIMITER)
foreach Value in CSubString(Values; CONST_ELEMENT_DELIMITER)
Criterion.AddWithPhysical(SubString(Value; CONST_VALUE_DELIMITER; 1); SubString(Value; CONST_VALUE_DELIMITER; 2))
endforeach
Criterion.ValuesBuildType = btOr
endif
endif
Таким образом мы получаем пример, как легко и непринужденно встроить на обложку поиск документов на примере поиска первичных учетных документов.
В следующий раз посмотрим, как реализовать множественный выбор из справочников для полей типа справочник и сохранение введенных данных при повторном открытии обложки.
Анна, интересная статья.
Есть несколько вопросов и предложений по коду:
Тут, скорее, не защита от инъекций (звучит громковато), а обычное экранирование кавычек для поиска по значениям вида <ООО 'Рога и копыта'>
Вот тут:
И сразу же чуть ниже
?
В итоге получится условие вида
P.S. Вопрос номер №3 неактуален :)
Александр, спасибо за дельные предложения. С которыми я бесспорно соглашусь
Авторизуйтесь, чтобы написать комментарий