Доброго дня!

Возникла следующая ситуация...

В мобильном приложении за невозможностью сформировать печатную форму, был реализован механизм ее сохранения в деталь Файлы и ссылки. Для этого был добавлен пункт в меню Действия, по нажатию на который запускается на бэкенде веб-сервис, который формирует docx-файл и сохраняет его в деталь Файлы и ссылки.

Проблема в том, что сейчас, чтобы увидеть этот прикрепленный файл, приходится релогиниться в приложении. Как обновить деталь, чтобы подтянулись актуальные данные из базы?

Сервис возвращает коллбэк после своей работы. Оттуда в идеале нужно вызвать какой-то метод для обновления, но все это происходит в схеме этого самого действия, которое было добавлено в меню действий. Там доступна запись Активности (этот функционал реализуется в активностях), из которой было совершено действие по формированию ПФ.

Ниже привожу фрагмент кода для наглядности

Ext.define("Terrasoft.ActionContactNote", {
	extend: "Terrasoft.ActionBase",
	config: {
		useMask: false,
		title: "MobileActionContactNoteTitle",
		iconCls: "atc-action-contact-note"
	},
	execute: function(record, config) {
        this.callParent(arguments);
 
		var serviceName = "AtcPrintablesAttachmentService";
		var	methodName = "Attach";
 
		Terrasoft.ServiceHelper.issueRequest({
			serviceName: serviceName,
			methodName: methodName,
			success: function(response) {
				// Здесь необходимо обновить деталь "Файлы и ссылки"
			},
			failure: function(response) {
				Terrasoft.MessageBox.showMessage("Error in webservice");
			},
			scope: this
		});
 
        this.executionEnd(true);
	}
});

 

Нравится

2 комментария

Есть похожее дополнение для бизнес-процессов

https://marketplace.creatio.com/template/refresh-active-page-process-el…

Здраствуйте,



Можно попробовать добавить следующий код в тело экшена:

var embeddedDetailId = Terrasoft.util.getColumnSetId(record.modelName, "detailName", pageConfig.viewMode);

var embeddedDetail = Ext.getCmp(embeddedDetailId);

embeddedDetail.setIsCollapsed(false);

var f = CaseFile.create({

    Case: record,

    Name: "xxx"

});

f.phantom = false;

embeddedDetail.addRecord(f);

Показать все комментарии

Добрый день, коммьюнити,



Дисклеймер: Всё, что описано в этом посте для многих будет просто и знакомо. Вместе с тем, я оставлю это здесь, чтобы впервые столкнувшиеся с подобной задачей не ломали голову зря, т.к. разные посты на коммьюнити при решении этой задачи меня самого ввели в легкое заблуждение)



Задача:

Как есть: при возвращении на предыдущую карточку после сохранения записи, детали в ней не обновляются. Пример: в карточке [Лид] есть деталь [Продукт в лиде], в которой есть кнопка "+". После нажатия на кнопку появляется окно, в котором мы можем открыть страницу добавления продукта (кнопка "Добавить"). После заполнения продукта и нажатия "Сохранить" логика добавляет запись с новым продуктом в деталь [Продукт в лиде]. При этом для того чтобы увидеть новую запись при возвращении на карточку [Лид] деталь нужно обновлять вручную.

Как должно быть: при возвращении на карточку [Лид] деталь должна обновляться автоматически.

Ограничения: крайне нежелательно реализовывать обновление с помощью reloadEntity, для того чтобы избежать случайной потери несохраненных изменений.



Решение:

При возврате не работают методы init и onEntityInitialized, а срабатывает только onRender, поэтому нам придется отлавливать момент когда рендерится деталь. Сразу скажу, что пытался сделать проще и обновлять деталь при onRender карточки, но не сработало. Видимо из-за того, что сама деталь в этот момент еще не отрендерена. Может такой способ прокатит в вашем случае :)



Порядок логики:

1. наступает onRender детали

2. деталь шлет сообщение карточке

3. карточка вызывает updateDetail



Выглядит просто) но обратите внимание на один нюанс: коммьюнити пестрит советами о применении метода this.reloadEntity('имя детали'). Он не работает! Это устаревшая логика, она пытается получить this.entitySchemaInfo, которая не существует. Вместо этого мы будем использовать this.updateDetail.

Важно, что имя детали в методе this.updateDetail нужно получить не из карточки. Это должно быть имя из this.details. В режиме отладки карточки [Лид] (в нашем случае) нужно вызвать в консоли this.details, найти нужную нам деталь и скопировать значение свойства "detailName".



Пример реализации:

В схеме детали:

messages: {
	"ReloadLeadProductDetailV2": {
		mode: Terrasoft.MessageMode.PTP,
		direction: Terrasoft.MessageDirectionType.PUBLISH
	}
},
methods: {
	onRender: function() {
		var args = {};
		this.sandbox.publish("ReloadLeadProductDetailV2", args, ["reloadLeadProduct"]);
		console.log("ReloadLeadProductDetailV2 message sent");
		this.callParent(arguments);
	}
}

В схеме карточки:



 

		messages: {
			"ReloadLeadProductDetailV2": {
				mode: Terrasoft.MessageMode.PTP,
				direction: Terrasoft.MessageDirectionType.SUBSCRIBE
			},
		},
init: function() {
 this.sandbox.subscribe("ReloadLeadProductDetailV2", this.onReloadLeadProductDetailV2, this, ["reloadLeadProduct"]);
			},
onReloadLeadProductDetailV2: function() {
	if (this.details) //на всякий случай проверяем загрузились ли детали
	{
		this.updateDetail({"detail": "LeadProduct279471775c00"});
	}
	console.log("ReloadLeadProductDetail Success");
}

Спасибо!

Нравится

Поделиться

0 комментариев
Показать все комментарии

Добрый день.

Проблема с обновлением грида детали после добавления элемента в деталь. Элемент не появляется в гриде сразу после выбора.

1. Выбор элементов в детали реализован с помощью LookupUtilities:

        var lookupConfig = {
                entitySchemaName: "BankingService",
                columnName: "Name",
                columns: ["ClientType"],
                multiSelect: true,
                filters: filters
        };
           
        LookupUtilities.ThrowOpenLookupMessage(
            sandbox,
            lookupConfig,
            this.addBankingServiceItemsCallback,
            this,
            this.getCardModuleSandboxId()
        );

2. Собственно callback-функция для обработки выбора пользователя:

                this.methods.addBankingServiceItemsCallback = function(args) {
                        if (!args || args.selectedRows.getCount() === 0) {
                                return;
                        }
                       
                        var selectedIds = args.selectedRows.getKeys();
                        var synchronizedRule = this.filterValue;
                        var batchQuery = Ext.create('Terrasoft.BatchQuery');
                        Terrasoft.each(selectedIds, function(item) {
                                var insert = Ext.create('Terrasoft.InsertQuery', {
                                        rootSchemaName: this.entitySchema.name
                                });
                                var newGuid = Terrasoft.generateGUID();
                                insert.setParameterValue(
                                        'Id',
                                        newGuid,
                                        Terrasoft.DataValueType.GUID
                                );
                                insert.setParameterValue(
                                        'BankingService',
                                        item,
                                        Terrasoft.DataValueType.GUID
                                );
                                insert.setParameterValue(
                                        'SynchronizedRule',
                                        synchronizedRule,
                                        Terrasoft.DataValueType.GUID
                                );
                                batchQuery.add(insert);
                        }, this);
                        batchQuery.execute();
                        sandbox.publish('DetailChanged', {detailName: this.entitySchema.name}, [this.getSenderSandboxId()]);
                };

3. Обработчик события DetailChanged на странице редактирования объекта с деталью:

                this.methods.detailChangedSubscriber = function(args) {
                        viewModel.reloadDetail(args.detailName + 'Detail');
                };

Однако, после нажатия кнопки "Выбрать", выбранные записи в гриде детали не отображаются. Если нажать "Сохранить" на странице редактирования объекта и потом открыть заново этот объект для редактирования, то в детали выбранные записи видны.

Как обновить грид детали, чтобы выбранные элементы отображались непосредственно после выбора?

Заранее благодарен за помощь!

Нравится

3 комментария

Добрый день Артем!!!

уточните пожалуйста версию и конфигурацию BPMOnline. Спасибо!!!

"Власов Михаил Викторович" написал:

Добрый день Артем!!!

уточните пожалуйста версию и конфигурацию BPMOnline. Спасибо!!!

Михаил, версия 7.2; конфигурация вроде "lending"

Здравствуйте, я не воссоздавал на тестовом примере batchQuery, это не суть вопроса, сразу менял данные детали в базе данных, через sql management studio. Самое главное здесь в вашем вопросе, это вызов «viewModel.reloadDetail(args.detailName + 'Detail');»

Во-первых, выполните отладку, и убедитесь что метод вызывается, если нет, копайте в сторону песочницы, и того что бы ваши id песочницы совпадали. И добейтесь того что бы в функцию detailChangedSubscriber все же заходило.

Во-вторых, почему viewModel? Данный метод же есть прямо в главном скоупе страницы. Я закешировал для теста скоуп страницы в инит методе:

structure.userCode = function() {
   this.methods.init = function() {
      document.scp = this;
   };
};

И вот видно наш метод для обновления детали:

Во вторых, имя, передаваемое как аргумент должно соответствовать именно «name» свойству детали, а не «schemaName». Вот, к примеру, деталь опыта работы контакта:

И вот такой её вызов, отлично обновляет содержимое грида:

document.scp.reloadDetail("contactCareer");

где «document.scp» по сути this скоуп страницы контакта.

Вывод: Отладьте метод, проверьте имена.

Показать все комментарии

Добрый день!
Нужно при выборе продажи в счете подтягивать все оборудование из продажи в счет.
Деталь «Оборудование» создана по аналогии с деталью «Продукты».
Оборудование сохраняю вот так:

this.methods.InsertEquipment = function(Equipment, Invoice) {
var insert = Ext.create('Terrasoft.InsertQuery', {
rootSchemaName: 'InvoiceEquipment'
});
insert.setParameterValue('Equipment', Equipment, Terrasoft.DataValueType.GUID);
insert.setParameterValue('Invoice', Invoice, Terrasoft.DataValueType.GUID);
return insert;
};
Но на странице счета оборудование в детали сразу не появляются (только после обновления страницы).

Как можно решить эту проблему?

Нравится

1 комментарий

Здравтсвуйте, Елена!
Для обновления детали необходимо вызвать после update'a в БД соответсвующую функцию:

this.reloadDetail('detailName');

Или можно в глобальную переменную сохранить this в методе "init", а затем через эту переменную вызывать уже reloadDetail.

Показать все комментарии

В разделе Контрагенты добавляю новую вкладку в нее добавляю PageContainer2 со страницей "Страница реестра контрагентов" и опубликовываю.

Открываю раздел Контрагенты, перехожу на новую вкладку и выделаю различных Контрагентов, блок "Детали" не обновляется, если тоже самое делать на вкладке "Данные" (исходная вкладка) то "Детали" обновляются.

И если зайти отладчиком то видно следующее:
в модуле BaseGridPage в процедуре

public virtual bool DataSourceActiveRowChangedScriptTaskExecute(ProcessExecutingContext context) {
  ActivateButtons(true);
  if(IsDetailGrid) {
        return true;
  }
  ListenerThrowEvent(ListenerPageProcessUId, "GridActiveRowChanged");
  return true;
}

ListenerPageProcessUId равен null
соответственно Event дальше не передается.

Вопрос, что я делаю не так, и как заставить обновляться детали?

Нравится

3 комментария

"Илья Т." написал:В разделе Контрагенты добавляю новую вкладку в нее добавляю PageContainer2 со страницей "Страница реестра контрагентов" и опубликовываю.

Как Вы это делаете?

Я бы рекомендовал выполнять эту процедуру пользовательскими средствами, через раздел Рабочие места.

Maxim Gritsenko

Большое спасибо. Сделал через рабочие места и все заработало. Но почему не работает через конфигурацию? Непонятно (.

Скорее всего, необходимо вручную инициализировать детали. Это долго, однотипно, но часто необходимо, поэтому данный функционал был автоматизирован и оформлен в удобном, пользовательском представлении.

Показать все комментарии

Данные в детали изменяются не только посредством карточки редактирования, поэтому по завершении редактирования и нажатии кнопки ОК мы не видим изменений, пока деталь не обновить. Окно редактирования унаследовано от wnd_BaseDBEdit, подскажите как правильно обновить делать в данном случае.

(кнопку ОК в окне редактирования не трогал, пробовал найти решения в постах но пока безуспешно)

из последних идей нашел в постах:

function wnd_...GridAreaOnNotify(ScriptableService, Sender, Message, Data) {
        if ((Message == MSG_OK) &&
            (Sender.Name = Self.Attributes('EditWindowUSI'))) {
            var WorkspaceWindow = Self.Attributes('WorkspaceWindow');
            WorkspaceWindow.Notify(Self, MSG_REFRESHDETAIL, System.EmptyValue);
        };
        wnd_BaseGridAreaOnNotify(ScriptableService, Sender, Message, Data);
}

но не знаю как воспользоваться правильно в моем случае

Нравится

15 комментариев

В Вашем случае function wnd_...GridAreaOnNotify - это функция OnNotify для сервиса окна реестра того раздела, детали которого Вы хотите обновлять по закрытию карточки редактирования. Указанный код проверяет, было ли сообщение о закрытии, действительно ли его послала карточка редактирования, а затем посылает разделу сообщение об обновлении деталей.

отладчик показал:
ScriptableService = wnd_SubContactPeriodsGridArea
Sender = wnd_SubContactPeriodsEdit
Message = MSG_OK
Data = undefined
Self= "wnd_SubContactPeriodsGridArea"

далее по условию должно быть
var WorkspaceWindow = Self.Attributes('WorkspaceWindow');
после этого шага WorkspaceWindow = null, ошибка видимо здесь, почему null?

Это созданный Вами раздел? Обычно в скрипте раздела в функции инициализации окну реестра в атрибут WorkspaceWindow записывается раздел. Если такого не происходит, то Вам нужно в скрипте раздела в функции Initialize (если нет такой, то на OnPrepare) присвоить атрибут таким образом:

SetAttribute(wndGridArea.Window, 'WorkspaceWindow', Self);

тут wndGridArea - это контейнер (создан в окне раздела), который содержит окно реестра.

wnd_SubContactPeriodsGridArea созданный мной раздел

выдержки кода из wnd_SubContactPeriodsGridAreaScript:

function Initialize(Window) {
    SetAttribute(Window, 'WorkspaceWindow', Self); <- добавил по вашему совету
    SetAttribute(Window, 'EditWindowUSI', 'wnd_SubContactPeriodsEdit');
    SetAttribute(Window, 'ParentItemFieldName', 'ContactID'); // id of main grid
    SubContactPeriodsGridArea.DatasetUSI = GetAttribute(Window, 'DatasetUSI');
    SubContactPeriodsGridArea.WorkspaceDataset = GetAttribute(Window, 'WorkspaceDataset'); 
}
...
function wnd_SubContactPeriodsGridAreaOnNotify(ScriptableService, Sender, Message, Data) {
    if ((Message == MSG_OK) && (Sender.Name = Self.Attributes('EditWindowUSI'))) {
        var WorkspaceWindow = Self.Attributes('WorkspaceWindow');
        WorkspaceWindow.Notify(Self, MSG_REFRESHDETAIL, System.EmptyValue);
    };
    wnd_BaseGridAreaOnNotify(ScriptableService, Sender, Message, Data);
}

не работает :(
В BeforePost для изменения данных, помимо основного датасета детали я использую динамически созданный. Изменения, произведенные в нем всеравно отображаются после обновления руками (как и было)

Нужно же не
SetAttribute(Window, 'WorkspaceWindow', Self)
а
SetAttribute(wndGridArea.Window, 'WorkspaceWindow', Self);
Вы сейчас в атрибуты окна раздела пишете, а не в атрибуты окна грида!
Перейдите в окно раздела, посмотрите, как у Вас называется контейнер окна, содержащий грид.

в сервисе wnd_ContactWorkspace деталь выглядит так:

pcDetails - вкладки деталей
 pgSubContactPeriodsDetail - вкладка моей детали
  fmSubContactPeriodsDetailWindow - фрейм на вкладке моей детали
   wndSubContactPeriodsDetail - контейнер для окна раздела моей детали
 
wnd_SubContactPeriodsGridArea - окно раздела моей детали

было так: SetAttribute(Window, 'WorkspaceWindow', Self);
в функцию подается Window = wnd_SubContactPeriodsGridArea

Что вы подразумеваете под окном грида?
wnd_BaseGridArea?
где взять wndGridArea и зачем брать если он подается.

Я имел ввиду, что Вам нужно внести изменения в функцию инициализации скрипта Вашего раздела, а не в скриптw nd_SubContactPeriodsGridAreaScript.
Действительно, в последний приходит окно реестра (он же, грид) детали. Но Вам нужно заполнить атрибут WorkspaceWindow именно разделом, поэтому нужно именно в функции инициализации в скрипте раздела прописать строчку

SetAttribute(wndSubContactPeriodsDetail.Window, 'WorkspaceWindow', Self);

Здесь я уже поставил контейнер для Вашего случая.

раздел - контакты, => инициализация раздела происходит здесь:

// ----------------------------------------------------------------------------
// scr_ContactsGridArea
// ----------------------------------------------------------------------------
var Contacts = new Object();
 
function Initialize(Window) {
	debugger; <- в эту точку система не приходит вообще
	SetAttribute(wndSubContactPeriodsDetail.Window, 'WorkspaceWindow', Self);
...

Эта функция должна вызываться из обработчика OnPrepare. Проверьте функцию wnd_ContactsWorkspaceOnPrepare, есть ли там вызов Initialize? Обязательно должен быть этот вызов и возможно еще что-нибудь (не обязательно) для дополнительной функциональности. Проверил у себя -- инициализация проходит, как положено, при переходе на раздел, т.е. при отработке OnPrepare окна раздела.

исправил ошибки с функцией инициализации, параметр передался

function wnd_SubContactPeriodsGridAreaOnNotify(ScriptableService, Sender, Message, Data) {
debugger;
    if ((Message == MSG_OK) && (Sender.Name == Self.Attributes('EditWindowUSI'))) {
        var WorkspaceWindow = Self.Attributes('WorkspaceWindow');
        WorkspaceWindow.Notify(Self, MSG_REFRESHDETAIL, System.EmptyValue);
    };
    wnd_BaseGridAreaOnNotify(ScriptableService, Sender, Message, Data);
}

По приходу сообщения MSG_OK, WorkspaceWindow принимает wnd_ContactsWorkspace.

Деталь не обновилась.

Хорошо, теперь проверьте обработчик OnNotify скрипта раздела (scr_ContactsWorkspace.wnd_ContactsWorkspaceOnNotify), там должен быть (хотя у Вас наверное нет, так как не обновляет) фрагмент кода

	if (Message == 'MSG_REFRESHDETAIL') {
		RefreshDetails();
	}

Действительно, такого фрагмента не было, попробовал добавить фрагмент в самое начало функции, деталь не обновилась.

Отрабатывает ли при этом функция RefreshDetails? Т.е. выполняется ли условие, переходит ли на ее выполнение? Если да, то очень странно, что после рефреша деталей они не обновились.
Если вызов все же отрабатывает и деталь не обновляется, то могу порекомендовать программно сменить активную деталь раздела, тогда автоматически задействуется механизм обновления.

В функции RefreshDetails доходит до момента который ручками в в эту функцию вписывается для каждой детали и вызывает RefreshCommonDetail

} else 
	if (pcDetails.ActivePage.Name == pgSubContactPeriodsDetail.Name) {
		RefreshCommonDetail(BaseWorkspace, wndSubContactPeriodsDetail, 'ContactID',
			'ContactID');//ok
	}

в RefreshCommonDetail вызывается RefreshDetailDataByParentID только при запуске системы. При добавлении новой записи в датасет происходит выход из RefreshCommonDetail по условию

if ((ParentID == Window.Attributes('ParentItemID')) && !(AlwaysRefresh)) {
		return;
	}

решил попробовать сделать вот так:

} else 
	if (pcDetails.ActivePage.Name == pgSubContactPeriodsDetail.Name) {               //debugger;
		RefreshCommonDetail(BaseWorkspace, wndSubContactPeriodsDetail, 'ContactID',
			'ContactID',null,null,null,true);//ok
	}

и получилось :),
скажите, не приведет ли это к непредвиденным последствиям

А, так Вы просто указали, что нужно обновлять деталь при каждом вызове RefreshDetail. В данной ситуации это выход, который ничему не навредит, а только решит проблему.

Показать все комментарии