В этом блоге вы узнаете, как разработать собственный рабочий процесс (Workflow), который не входит в комплект поставки D365 for Finance. Для этого я создам рабочий процесс для утверждения журналов инвентаризации (Управление запасами >> Журналы >> Учет номенклатур>>Инвентаризация), потому что в системе нет такого процесса для модуля управления запасами. Ниже приведены шаги, которые необходимо выполнить.
Шаги:
- Создать базовое перечисление для статуса документа
2. Создать расширение таблицы и добавление перечисления в таблицу.
3. Добавить поле статуса документа в расширение формы
4. Создать Query для рабочего процесса
5. Создать категорию рабочего процесса
6. Создать тип рабочего процесса
7. Добавить методы can submit workflow и updateworkflow в расширение класса таблицы.
8. Обновить класс submitmanager
9. Обновить класс EventHandler
10. Создать одобрение рабочего процесса
11. Добавить элемент в тип рабочего процесса
12. Добавить форму настройки рабочего процесса в модуль управления запасами.
Сейчас мы выполним все шаги детально:
1. Создать базовое перечисление для статуса документа
Убедитесь, что вы создали решение и проект, а также назначили вашу модель для проекта. Теперь добавьте новый элемент и выберите Base Enum. Добавьте базовое перечисление и назовите его CFS_InventoryCountingWorkflow
2. Создать расширение таблицы и добавление перечисления в таблицу
Мы создаем рабочий процесс для управления запасами, поэтому нам нужно создать расширение для таблицы InventoryJournalTable и перетащить созданное базовое перечисление на него, дабы создать новое поле с типом Enum.
3. Добавить поле статуса документа в расширение формы
Теперь нам нужно создать расширение формы InventJournalCount и добавить созданное поле на форму, перетащив его из источника данных в элемент управления формы и назначив ему значение LabelId.
4. Создать запрос
Добавьте новый запрос к проекту и назовите его CFS_InventoryCountingWorkflow, затем добавьте в него таблицу InventJournalTable и установите свойства следующим образом:
Я текстовый блок. Нажмите кнопку редактирования, чтобы изменить этот текст. Разнообразный и богатый опыт постоянный количественный рост и сфера нашей активности требуют от нас анализа позиций.
5. Создать категорию рабочего процесса
Теперь мы добавим категорию рабочего процесса в проект и назовем ее CFS_InventJournalCounting, установив свойства следующим образом
6. Создать тип рабочего процесса
После добавления категории рабочего процесса нам пора добавить тип рабочего процесса. Давайте назовем его CFS_InventoryJournalCounting и установим свойства следующим образом.
Это позволит нам создать новые элементы, такие как классы и пункты меню для выполнения всех действий рабочего процесса.
7. Добавить методы can submit workflow и updateworkflow в расширение класса таблиц.
Чтобы добавить метод в таблицу, нам нужно создать расширение класса таблицы, для этого добавим новый класс и назовем его InventJournalTable_CFSExtension, а также добавим методы updateWorkflow и canSubmitWorkflow. Вы можете использовать следующий код
Extensionof(tableStr(InventJournalTable))]
final class InventJournalTable_Extension
{
public boolean canSubmitToWorkflow(str _workflowType)
{
boolean ret = next cansubmitToWorkflow(_workflowType);
ret = this.CFS_InventoryCountingWorkflow == CFS_InventoryCountingWorkflow::Draft;
return ret;
}
public static void updateWorkflowStatus(RecId _documentRecId, CFS_InventoryCountingWorkflow _status)
{
ttsbegin;
InventJournalTable document;
update_recordset document
setting CFS_InventoryCountingWorkflow = _status
where document.RecId == _documentRecId;
ttscommit;
}
}
8. Обновить класс submitmanager
Убедитесь, что у вас аналогичное имя для класса-менеджера, если нет, то переименуйте его следующим образом и добавьте к нему следующий код:
public class CFS_InventoryJournalCountingSubmitManager
{
private InventJournalTable document;
private WorkflowVersionTable versionTable;
private WorkflowComment comment;
private WorkflowWorkItemTable workItem;
private SysUserId userId;
private boolean isSubmission;
private WorkflowTypeName workflowType;
public static void main(Args args)
{
// TODO: Write code to execute once a work item is submitted.
if (args.record().TableId != tableNum(InventJournalTable))
{
throw error(‘Error attempting to submit document’);
}
InventJournalTable document = args.record();
FormRun caller = args.caller() as FormRun;
boolean isSubmission = args.parmEnum();
MenuItemName menuItem = args.menuItemName();
CFS_InventoryJournalCountingSubmitManager manager = CFS_InventoryJournalCountingSubmitManager::construct();
manager.init(document, isSubmission, caller.getActiveWorkflowConfiguration(), caller.getActiveWorkflowWorkItem());
if (manager.openSubmitDialog(menuItem))
{
manager.performSubmit(menuItem);
}
caller.updateWorkflowControls();
}
/// <summary>
/// Construct method
/// </summary>
/// <returns>new instance of submission manager</returns>
public static CFS_InventoryJournalCountingSubmitManager construct()
{
return new CFS_InventoryJournalCountingSubmitManager();
}
/// <summary>
/// parameter method for document
/// </summary>
/// <param name = “_document”>new document value</param>
/// <returns>current document</returns>
public Inventjournaltable parmDocument(Inventjournaltable _document = document)
{
document = _document;
return document;
}
/// <summary>
/// parameter method for version
/// </summary>
/// <param name = “_versionTable”>new version table value</param>
/// <returns>current version table</returns>
public WorkflowVersionTable parmVersionTable(WorkflowVersionTable _versionTable = versionTable)
{
versionTable = _versionTable;
return versionTable;
}
/// <summary>
/// parameter method for comment
/// </summary>
/// <param name = “_comment”>new comment value</param>
/// <returns>current comment value</returns>
public WorkflowComment parmComment(WorkflowComment _comment = comment)
{
comment = _comment;
return comment;
}
/// <summary>
/// parameter method for work item
/// </summary>
/// <param name = “_workItem”>new work item value</param>
/// <returns>current work item value</returns>
public WorkflowWorkItemTable parmWorkItem(WorkflowWorkItemTable _workItem = workItem)
{
workItem = _workItem;
return workItem;
}
/// <summary>
/// parameter method for user
/// </summary>
/// <param name = “_userId”>new user value</param>
/// <returns>current user value</returns>
public SysUserId parmUserId(SysUserId _userId = userId)
{
userId = _userId;
return userId;
}
/// <summary>
/// parameter method for isSubmission flag
/// </summary>
/// <param name = “_isSubmission”>flag value</param>
/// <returns>current flag value</returns>
public boolean parmIsSubmission(boolean _isSubmission = isSubmission)
{
isSubmission = _isSubmission;
return isSubmission;
}
/// <summary>
/// parameter method for workflow type
/// </summary>
/// <param name = “_workflowType”>new workflow type value</param>
/// <returns>current workflow type</returns>
public WorkflowTypeName parmWorkflowType(WorkflowTypeName _workflowType = workflowType)
{
workflowType = _workflowType;
return workflowType;
}
/// <summary>
/// Opens the submit dialog and returns result
/// </summary>
/// <returns>true if dialog closed okay</returns>
protected boolean openSubmitDialog(MenuItemName _menuItemName)
{
if (isSubmission)
{
return this.openSubmitDialogSubmit();
}
else
{
return this.openSubmitDialogResubmit(_menuItemName);
}
}
/// <summary>
/// Open submission dialog
/// </summary>
/// <returns>true if dialog closed okay</returns>
private boolean openSubmitDialogSubmit()
{
WorkflowSubmitDialog submitDialog = WorkflowSubmitDialog::construct(this.parmVersionTable());
submitDialog.run();
this.parmComment(submitDialog.parmWorkflowComment());
return submitDialog.parmIsClosedOK();
}
/// <summary>
/// Open resubmit dialog
/// </summary>
/// <returns>true if dialog closed okay</returns>
private boolean openSubmitDialogResubmit(MenuItemName _menuItemName)
{
WorkflowWorkItemActionDialog actionDialog = WorkflowWorkItemActionDialog::construct(workItem, WorkflowWorkItemActionType::Resubmit, new MenuFunction(_menuItemName, MenuItemType::Action));
actionDialog.run();
this.parmComment(actionDialog.parmWorkflowComment());
this.parmUserId(actionDialog.parmTargetUser());
return actionDialog.parmIsClosedOK();
}
/// <summary>
/// initializes manager
/// </summary>
/// <param name = “_document”>document</param>
/// <param name = “_menuItem”>calling menu item</param>
/// <param name = “_versionTable”>workflow version</param>
/// <param name = “_workItem”>workflow item</param>
protected void init(InventJournalTable _document, boolean _isSubmission, WorkflowVersionTable _versionTable, WorkflowWorkitemTable _workItem)
{
this.parmDocument(_document);
this.parmIsSubmission(_isSubmission);
this.parmVersionTable(_versionTable);
this.parmWorkItem(_workItem);
this.parmWorkflowType(this.parmVersionTable().WorkflowTable().TemplateName);
}
/// <summary>
/// perform workflow submission
/// </summary>
protected void performSubmit(MenuItemName _menuItemName)
{
if (isSubmission)
{
this.performSubmitSubmit();
}
else
{
this.performSubmitResubmit(_menuItemName);
}
}
/// <summary>
/// perform workflow submit
/// </summary>
private void performSubmitSubmit()
{
if (this.parmWorkflowType() && document.CFS_InventoryCountingWorkflow == CFS_InventoryCountingWorkflow::Draft)
{
Workflow::activateFromWorkflowType(workflowType, document.RecId, comment, NoYes::No);
InventJournalTable::updateWorkflowStatus(document.RecId, CFS_InventoryCountingWorkflow::Submitted);
}
}
/// <summary>
/// perform workflow resubmit
/// </summary>
private void performSubmitResubmit(MenuItemName _menuItemName)
{
if (this.parmWorkItem())
{
WorkflowWorkItemActionManager::dispatchWorkItemAction(workItem, comment, userId, WorkflowWorkItemActionType::Resubmit, _menuItemName);
InventJournalTable::updateWorkflowStatus(document.RecId, CFS_InventoryCountingWorkflow::Submitted);
}
}
}
Поскольку мы добавляем код для повторной отправки только здесь, нам нужно изменить свойство пункта меню resubmit action menu на значение CFS_InventoryJournalCountingSubmitManager, и после этого вы можете удалить данный класс, т.к. мы используем класс-менеджер для повторной отправки документов.
9. Обновить класс EventHandler
Добавьте следующий код в класс обработчика событий и назовите его CFS_InventoryJournalCountingEventHandler
public class CFS_InventoryJournalCountingEventHandler implements WorkflowCanceledEventHandler,
WorkflowCompletedEventHandler,
WorkflowStartedEventHandler
{
public void started(WorkflowEventArgs _workflowEventArgs)
{
RecId documentRecId = _workflowEventArgs.parmWorkflowContext().parmRecId();
InventJournalTable::updateWorkflowStatus(documentRecId, CFS_InventoryCountingWorkflow::Submitted);
// TODO: Write code to execute once the workflow is started.
}
public void canceled(WorkflowEventArgs _workflowEventArgs)
{
RecId documentRecId = _workflowEventArgs.parmWorkflowContext().parmRecId();
InventJournalTable::updateWorkflowStatus(documentRecId, CFS_InventoryCountingWorkflow::Rejected);
// TODO: Write code to execute once the workflow is canceled.
}
public void completed(WorkflowEventArgs _workflowEventArgs)
{
RecId documentRecId = _workflowEventArgs.parmWorkflowContext().parmRecId();
InventJournalTable::updateWorkflowStatus(documentRecId, CFS_InventoryCountingWorkflow::Approved);
// TODO: Write code to execute once the workflow is completed.
}
}
10. Создание утверждения рабочего процесса
Добавьте элемент Workflow Approval и назовите его CFS_InventoryJournalCountingApproval. Он также добавит новые элементы и установит свойства следующим образом.
Теперь нам нужно добавить фрагмент кода в обработчики событий утверждения рабочего процесса , а также задать имя как CFS_InventoryJournalCountingApprovalEventHandler
public final class CFS_InventoryJournalCountingApprovalEventHandler implements WorkflowElementCanceledEventHandler,
WorkflowElemChangeRequestedEventHandler,
WorkflowElementCompletedEventHandler,
WorkflowElementReturnedEventHandler,
WorkflowElementStartedEventHandler,
WorkflowElementDeniedEventHandler,
WorkflowWorkItemsCreatedEventHandler
{
public void started(WorkflowElementEventArgs _workflowElementEventArgs)
{
// TODO: Write code to execute once the workflow is started.
}
public void canceled(WorkflowElementEventArgs _workflowElementEventArgs)
{
RecId documentRecId = _workflowElementEventArgs.parmWorkflowContext().parmRecId();
InventJournalTable::updateWorkflowStatus(documentRecId, CFS_InventoryCountingWorkflow::Rejected);
}
// TODO: Write code to execute once the workflow is canceled.
public void completed(WorkflowElementEventArgs _workflowElementEventArgs)
{
RecId documentRecId = _workflowElementEventArgs.parmWorkflowContext().parmRecId();
InventJournalTable::updateWorkflowStatus(documentRecId, CFS_InventoryCountingWorkflow::Rejected);
}
// TODO: Write code to execute once the workflow is completed.
public void denied(WorkflowElementEventArgs _workflowElementEventArgs)
{
// TODO: Write code to execute once the workflow is denied.
}
public void changeRequested(WorkflowElementEventArgs _workflowElementEventArgs)
{
// TODO: Write code to execute once change is requested for the workflow.
}
public void returned(WorkflowElementEventArgs _workflowElementEventArgs)
{
RecId documentRecId = _workflowElementEventArgs.parmWorkflowContext().parmRecId();
InventJournalTable::updateWorkflowStatus(documentRecId, CFS_InventoryCountingWorkflow::Rejected);
// TODO: Write code to execute once the workflow is returned.
}
public void created(WorkflowWorkItemsEventArgs _workflowWorkItemsEventArgs)
{
// TODO: Write code to execute once work items are created.
}
}
11. Добавить элемент в тип рабочего процесса
После создания утверждения нам нужно прикрепить этот элемент к типам рабочего процесса, для этого мы добавим новый элемент к существующим типам и установим свойства следующим образом.
12. Теперь добавьте форму настройки рабочего процесса в модуль управления запасами.
Поскольку в управлении запасами нет формы рабочего процесса, нам нужно выполнить определенные шаги, которые вы можете найти по этой ссылке, и у вас будет все готово для настройки рабочего процесса одобрения журналов инвентаризации. Эту процедуру также можно использовать для разработки других пользовательских рабочих процессов.
Добавить комментарий
Для отправки комментария вам необходимо авторизоваться.