Частой задачей при разработке решения на платформе DocsVision является выделение номера. В данной публикации будет продемонстрировано, как можно выделить полный номер, вместе с префиксами и суффиксами, програмно.
Итак будем делать скрипт для версии DocsVision 4.1. Это будет дополнительная команда Навигатора, которая будет назначена на контекстное меню карточек документов. Т.е. пользовать сможет нажать правой кнопкой мыши на карточку в Навигаторе и назначить полный номер, не открывая карточку.
Скрипт:
Для получения номера используем объект TOHelperObject.NumeratorObject.
Sub DoEvent(UserSession, CardHost, FolderType, FolderID, SelectionIDs)
Dim sDetails, bFlag
bFlag = True
sDetails = "Номера присвоены следующим карточкам: "
' Создаем объект "Нумератор"
Set oNumerator = CreateObject("TOHelperObjects.NumeratorObject")
' Для каждой карточки из коллекции
For Each sID In SelectionIDs
' Получаем карточку
Set oCard = UserSession.CardManager.CardData(sID)
' Получаем основную секцию
Set oMainRow = oCard.Sections(oCard.Type.Sections.GetByAlias("MainInfo").ID).FirstRow
If IsNull(oMainRow.Value("NumberRef")) Then
' Если номера нет
Set oNumerator.CardData = oCard
Set oNumerator.UserSession = UserSession
sNumID = ""
sFullNum = ""
If oNumerator.GetNewNumber(sNumID, sFullNum) Then
oMainRow.Value("FullNumber") = sFullNum
oMainRow.Value("NumberRef") = sNumID
sDetails = sDetails + oMainRow.Value("Name") + ","
Else
CardHost.ShowMessage "Комманда Навигатора", "Не найден нумератор для '" + oMainRow.Value("Name") + "'", , 3
End If
End If
Next
CardHost.ShowMessage "Комманда Навигатора", "Номера выделены успешно", sDetails, 4
Set oNumerator = Nothing
End Sub
11 коммент.:
Выложите, пожалуйста, пример создания номера для карточки универсального документа.
И что Вы можете посоветовать для использования пользовательского поля типа "нумератор"? Если использовать стандартный способ настройки нумератора, такое поле получает только числовое значение, хотя назначается на него нумератор со сложной структурой. Все остальное "отбрасывается".
Приведенный выше скрипт можно использовать и для универсального документа, с небольшими изменениями:
1. В универсальном документе номер можно присвоить либо свойству типа "строка", либо свойству типа "нумератор".
2. Если используется свойство типа "строка", то нужно записать полученный номер в значения свойства. Полю Value и DisplayValue присвоить значение sFullNum.
3. Если свойство типа "нумератор", то нужно заполнить поля Value и DisplayValue значением sFullNum и дополнительно заполнить поле NumberID значением sNumID
В текущей версии свойство типа "нумератор", действительно заполняется только номером, без префиксов и суффиксов.
Вы можете использовать приведенный выше скрипт.
А можно скриптом переназначить некое стандартное действие на другую кнопку?
Например, чтобы добавить задачу, мне нужно использовать кнопку в панели навигатора или правую кнопку мыши во вкладке задачи.
А я хочу сделать кнопку в пользовательской вкладке, по которой открывалась бы форма создания задачи определенного типа.
Или у меня есть пользовательские свойства табличного типа, и я хочу сама нарисовать кнопку, по которой открывалась бы форма добавления строки в таблицу. Можно такое сделать?
Полагаю, речь идет о вызове стандартных окон карточки создания задачи и добавления строки в таблицу.
В текущих версиях этого сделать нельзя. Но ничего не мешает реализовать это другими способами
1. Если создается один и тот же тип задачи, то в скрипте создавать именно его, без вызова окон.
2. Если же пользователю нужно предоставить выбор, т.е. показать форму, то можно сделать следующим образом.
Создаете отдельный ActiveX компонент (*.dll), который рисует форму и отображает варианты выбора.
Вызываете эту форму из скрипта через CreateObject.
Минус - нужно регистрировать данный dll компонент на клиенте.
У нас есть подобный пример, после того, как приведу его в порядок выложу.
Функционал, безусловно, очень полезный. Жаль, что появился только в 4.1
Однако, выдать номер в сценарии БП "кубиками" до сих пор нельзя :(
Поэтому, недавно, появилась необходимость адаптировать вышеприведённый скрипт к сценарию БП на C#.
// подключение системных библиотек
using System;
using System.Xml;
// подключение библиотек СУБП
using DocsVision.Workflow.Objects;
using DocsVision.Workflow.Runtime;
using DocsVision.Workflow.Gates;
using DocsVision.Platform.ObjectManager;
using DocsVision.Platform.HelperAPI;
namespace DVScriptHost
{
class DVScript
{
object oNum;
private DVGate m_oDVGate;
private const string cIncMainInfo = "{8C77892A-21CC-4972-AD71-A9919BCA8187}";
public void Execute (DocsVision.Workflow.Runtime.ProcessInfo process, PassState passInfo)
{
try
{
DVGate m_oDVGate = (DVGate)process.Gates[DVGate.GateID];
UserSession oSession = m_oDVGate.Session;
// Карточка договора
ProcessVariable oCard = process.GetVariableByName("DVCard");
// получение данных карточки
CardData oCardData = oSession.CardManager.get_CardData(((DVCard)oCard.Value).ID);
// получение секции Основная инфа
RowData oRowMainInfo = oCardData.Sections[cIncMainInfo].FirstRow;
string appProgID = "TOHelperObjects.NumeratorObject";
// Получаем ссылку на интерфейс IDispatch
Type NumeratorType = Type.GetTypeFromProgID(appProgID);
// Создаём экземляр объекта нумератора
oNum = Activator.CreateInstance(NumeratorType);
// Устанавливаем свойства объекта: сессия и данные карточки для которой нужен номер
oNum.GetType().InvokeMember("UserSession", System.Reflection.BindingFlags.SetProperty, null, oNum, new object[1]{oSession});
oNum.GetType().InvokeMember("CardData", System.Reflection.BindingFlags.SetProperty, null, oNum, new object[1]{oCardData});
// Инициализируем массив ParameterModifier
System.Reflection.ParameterModifier p = new System.Reflection.ParameterModifier(2);
// Первый и второй параметры передаются по ссылке
p[0] = true; p[1] = true;
System.Reflection.ParameterModifier[] mods = { p };
object[] args = new object[2];
args[0] = ""; // NumberID
args[1] = ""; // NumberText
oNum.GetType().InvokeMember("GetNewNumber", System.Reflection.BindingFlags.InvokeMethod, null, oNum, args,mods,null,null);
//process.LogMessage("NumberID = " + args[0].ToString());
//process.LogMessage("NumberText = " + args[1].ToString());
oRowMainInfo.set_Value("NumberRef",args[0].ToString());
oRowMainInfo.set_Value("FullNumber",args[1].ToString());
// Уничтожение объекта oNum.
System.Runtime.InteropServices.Marshal.ReleaseComObject(oNum);
oNum = null;
// Вызываем сборщик мусора для немедленной очистки памяти
GC.GetTotalMemory(true);
}
catch (Exception ex)
{
// Уничтожение объекта oNum.
System.Runtime.InteropServices.Marshal.ReleaseComObject(oNum);
oNum = null;
// Вызываем сборщик мусора для немедленной очистки памяти
GC.GetTotalMemory(true);
// запись в журнал ошибки исполнения
process.LogMessage("Ошибка выполнения скрипта:" + ex.Message);
}
return;
}
}
}
Не получается выделить номер по нажатию кнопки таким скриптом в карточке универсального документа. Выходит в условие Else, "не найден нумератор для..." Сам нумератор в справочнике создан (с типом "внутренний", т.к. универсальный отсутствует). Полю "Полный номер документа" присвоен. Вручную номер выделяется (но в виде только одной цифры, без заданного формата). Хотелось бы по нажатию собственной кнопки выделять. Подскажите, что делаю не так? (версия DV 4.1)
Function DoEvent(UserSession, CardFrame, CardData, ActivateFlags, ModeID, FolderID)
Set secProp = CardData.Sections(CardData.Type.Sections.GetByAlias("Properties").ID)
Set oNumerator = CreateObject("TOHelperObjects.NumeratorObject")
Set oNumerator.CardData = CardData
Set oNumerator.UserSession = UserSession
sNumID = ""
sFullNum = ""
Set num = secProp.FindRow("@Name='Полный номер документа'")
If oNumerator.GetNewNumber(sNumID, sFullNum) Then
num.Value("Value")=sFullNum
num.Value("DisplayValue")=sFullNum
num.Value("NumberID")=sNumID
DoEvent=18
Else
CardFrame.ShowMessage "Команда Навигатора", "Не найден нумератор для '" + num.Value("Name") + "'", , 3
End If
Set oNumerator = Nothing
End Function
Происходит это потому, что в справочнике нумераторов нет типа "Универсальный документ". И NumeratorObject не может найти нумератор по типу.
Единственный вариант - не передавать CardData в NumeratorObject, а задать параметры напрямую свойства DocumentDate, DocTypeID, RegisterID и т.д.
Хм... Понятно. Я тут долго бился и уже реализовал решение через способ, описанный тут:
http://forum.idoc.ru/viewtopic.php?t=2498
Теперь бьюсь над получением списка подразделений в нумераторе. Путем подбора различных окончаний (типа .Rows) пока не удалось заставить уйти дальше вот этой строчки:
Set oDeptRows=oRefNumerators.Sections(cNumeratorsDept)
Пробую подставлять различные методы после последней скобки, кроме FindRow ничего не работает... :(
CardData.Sections возвращает объект типа SectionData. У SectionData есть свойство Rows - список строк секции. .Sections(...).Rows должно работать.
Михаил, а вы можете сказать, почему может возникать ошибка при вызове метода
int lNumber = oZone.GetNumber(emp.ID.ToString(), true, out sNID);
Ошибка: Карточка с указанным идентификатором не существует.
Совершенно непонятно что ему не нравится..
"antoon"
Надо проверить значение emp.ID.ToString()
Так же мне непонятно что это за переменная "out sNID". Может нужно просто sNID?
Отправить комментарий