Здравствуйте! Подскажите, пожалуйста, можно ли добавить на страницу Контрагенты в модуль "Действия" свой БП, при этом выбрать несколько записей - несколько контрагентов, и передать ID выбранных записей в бизнес-процесс. Если это можно, то каким образом это можно реализовать.

Нравится

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

Добрый день, Юлия!

Процесс в действие можно добавить. Варианты реализации описаны по ссылкам:
http://www.community.terrasoft.ru/forum/topic/10554
http://www.community.terrasoft.ru/forum/topic/12414

Id выбранных записей хранятся в GridData в атрибуте SelectedRow. Это значение необходимо передавать в бизнес процесс.

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

Создал для контрагента действие:

              getActions: function() {
                  var actionMenuItems = this.callParent(arguments);
                  actionMenuItems.addItem(this.getActionsMenuItem({
                      "Caption": { "bindTo": "Resources.Strings.SxActionOpportunity" },
                      "Enabled":  { bindTo: "isClient" },
                      methodName: "runOpportunityManagement"
                  }));
                  return actionMenuItems;
              },

Действие должно быть активно только для контрагента с типом Клиент или Потенциальный клиент. Написал метод:

              isClient: function() {
                  var type = this.get("Type");
                  if(type) {
                      type = type.value;
                  }
                  if(type === Home32Constants.Account.Type.Client || type === Home32Constants.Account.Type.PotencialClient){
                      return true;
                  }else{
                      return false;
                  }
              },

Функция возвращает "true" а действие всё-равно не активно. А вот если закрыть левую панель(там где список записей раздела) и обновить страничку - всё отрабатывает как нужно.

Та же ошибка наблюдается и с Caption. Если открыта панель, то Caption пустой, а если закрыта - всё ок.
Я так понимаю если открыта эта панель система считает, что пользователь находится в разделе...

Вопрос с Caption решается добавлением Strings в Section раздела, а вот как быть с Enabled не понятно.

Нравится

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

Добрый день, Вячеслав!

Код должен отрабатывать, на первый взгляд ошибок нет.
Скорее всего ошибка в чем-то другом.
Я Вам написал личное сообщения для продолжения анализа возникшей ошибки.

В версии 7,4 удалось решить проблему таким образом:

              initCardActionHandler: function() {
                  this.callParent(arguments);
                  var propertyNames = [
                      "isClient"
                  ];
                  this.Terrasoft.each(propertyNames, function(propertyName) {
                      this.on("change:" + propertyName, function(model, value) {
                          this.sandbox.publish("CardChanged", {
                              key: propertyName,
                              value: value
                          }, [this.sandbox.id]);
                      }, this);
                  }, this);
              },

В следующем проекте уже на версии 7.5 стоит похожая задача, но данное решение уже не помогает.

В версии 7.5 такое решение тоже будет работать если isClient будет свойством, а не функцией. Для того, чтоб все работало, нужно в Карточке сделать isClient и уже к нему байндить "Enabled" действия.

Да. Действительно если биндиться на свойство всё отрабатывает. Спасибо!

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

Добрый вечер, коллеги. Не подскажите как сделать чтобы при скачивании отчета Word изменить имя файла.
Пробовал на InvoiceSection переопределить метод из PrintReportUtilities

downloadReport: function(caption, key) {
        var report = document.createElement("a");
        report.href = "../rest/ReportService/GetReportFile/" + key;
        report.download = "123.docx";
        document.body.appendChild(report);
        report.click();
      document.body.removeChild(report);
}

Но почему-то имя файла всё равно дефолтное, которое указано в справочнике Печатные формы.

Нравится

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

Для получения названия файла необходимо попробовать переопределить метод фабричного класса ReportHelper следующим образом (обратите внимание на report.Caption):

                   public virtual Stream GetReportFile(string key) {
                             var userConnection = (UserConnection)HttpContext.Current.Session["UserConnection"];
                             var reportObj = userConnection.SessionData[key];
                             userConnection.SessionData.Remove(key);
                             ReportData report = reportObj as ReportData;
                             if (report.Format == "pdf") {
                                      WebOperationContext.Current.OutgoingResponse.ContentType = "application/pdf";
                             } else {
                                      WebOperationContext.Current.OutgoingResponse.ContentType = "application/octet-stream";
                             }
                             var reportStream = new MemoryStream(report.Data);
                             WebOperationContext.Current.OutgoingResponse.ContentLength = reportStream.Length;
                             WebOperationContext.Current.OutgoingResponse.Headers.Add("Content-Disposition", "attachment; filename=\"" +
Показать все комментарии

Подскажите пожалуйста, запутался совсем.
Есть сущности UsrVacancies, UsrCandidates и UsrVacancyCandidates. На основе UsrVacancyCandidates сделана деталь. Заходишь на вакансию, и можешь ассайнить кандидатов, одного или нескольких. Если кандидат УЖЕ добавлен для вакансии, то должно быть невозможно добавить этого же кандидата дважды или более.
Когда нажимаешь "Add" в детали, там есть лукапное поле Candidate (имя - UsrCandidates). Что я хочу сделать - чтобы в этом лукапе НЕ отображались те кандидаты, что УЖЕ добавлены для ЭТОЙ вакансии, т.е. отфильтровать его.
Для этого я должен получить список тех кандидатов, что уже добавлены для этой вакансии, и наложить фильтр на лукап - показывать всех кандидатов, КРОМЕ уже добавленных.

Вот как должно быть. Обратите внимание на переменную "candidates", где я захардкодил айдишники.

attributes: {
        "UsrCandidates": {
                dataValueType: Terrasoft.DataValueType.LOOKUP,
                lookupListConfig: {
                        filter: function() {
                                var candidates = ["5d4d6b06-4de2-4d23-8e6e-f2ab624af5d0", "3c6f72a7-3218-4f23-b96a-e344bac099f4", "a9b68651-d313-4c83-9007-31a659547bd5"];
                                var filterGroup = new Terrasoft.createFilterGroup();
                                var filter1 = Terrasoft.createColumnInFilterWithParameters(
                                        "Id",
                                        candidates);
                                filter1.comparisonType = Terrasoft.ComparisonType.NOT_EQUAL;
                                filterGroup.add("filter1", filter1);
                                return filterGroup;
                        }
                }
        }
},

Однако, мне нужно получить эти айдишники, зная Id текущуй вакансии. Вот ESQ запрос, который возвращает эти айдишники.

getCurrentlyAssignedCandidates: function(vacancyId, callback) {
        var esq = this.Ext.create("Terrasoft.EntitySchemaQuery", {
                rootSchemaName: "UsrVacancyCandidates"
        });
        esq.addColumn("UsrCandidates", "CandidateId");
        esq.filters.add(
                "filter1",
                this.Terrasoft.createColumnFilterWithParameter(
                        Terrasoft.ComparisonType.EQUAL,
                        "UsrVacancies",
                        vacancyId
                )
        );
        esq.getEntityCollection(function(result) {
                var candidates = [];
                if (result.success) {
                        result.collection.each(function(item) {
                                candidates.push(item.get("CandidateId"));
                        });
                        callback.call(this, candidates);
                }
        });
}

Однако, если вызывать callback в "filter", то он выполняется асинхронно, и сама функция выполняется асинхронно. Получается, что функция "filter" возвращает фильтр (который включает в себя ВСЕХ кандидатов) раньше, чем выполняется callback. Т.е. ничего не фильтруется.

Подскажите, пожалуйста, как это реализовать.

Заранее благодарю!

Нравится

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

На самом деле вариантов несколько:
1. Через filterMethod, добавляете на деталь ссылку на метод, а в самом методе добавляете в фильтр уже добавленные записи
Как пример UIv2/AccountPageV2 только здесь без фильтрации по существующим

                                                               details: /**SCHEMA_DETAILS*/{
                                                                              EmailDetailV2: {
                                                                                              schemaName: "EmailDetailV2",
                                                                                              filter: {
                                                                                                              masterColumn: "Id",
                                                                                                              detailColumn: "Account"
                                                                                              },
                                                                                              filterMethod: "emailDetailFilter"
                                                                              }
…
 
                                                                              /**
                                                                              * Функция создания фильтров детали email
                                                                              * @protected
                                                                              * @returns {createFilterGroup}
                                                                              */
                                                                              emailDetailFilter: function() {
                                                                                              var recordId = this.get("Id");
                                                                                              var filterGroup = new this.Terrasoft.createFilterGroup();
                                                                                              filterGroup.add("AccountNotNull", this.Terrasoft.createColumnIsNotNullFilter("Account"));
                                                                                              filterGroup.add("AccountConnection", this.Terrasoft.createColumnFilterWithParameter(
                                                                                                                             this.Terrasoft.ComparisonType.EQUAL, "Account", recordId));
                                                                                              filterGroup.add("ActivityType", this.Terrasoft.createColumnFilterWithParameter(
                                                                                                                             this.Terrasoft.ComparisonType.EQUAL, "Type", ConfigurationConstants.Activity.Type.Email));
                                                                                              return filterGroup;
                                                                              },

Но здесь возникнут сложности в асинхронностью, но Вы можете формировать первоначальную коллекцию например в методе init, а затем актуализировать эту коллекцию при изменении детали через подписку на сообщение updateDetail
2. Через правила
Как пример UIv2/ContactAddressPageV2

                               rules: {
                                               "AddressType": {
                                                              "FiltrationAddressTypeByOwner": {
                                                                              ruleType: BusinessRuleModule.enums.RuleType.FILTRATION,
                                                                              autocomplete: true,
                                                                              baseAttributePatch: "ForContact",
                                                                              comparisonType: Terrasoft.ComparisonType.EQUAL,
                                                                              type: BusinessRuleModule.enums.ValueType.CONSTANT,
                                                                              value: true
                                                              }
                                               }
                               },
или NUI/ActivityPage

3. Через один из методов Lookup, как пример loadVocabulary или prepareLookupList

                                                              /**
                                                              * Подготовка параметров для открытия окна выбора из пользователей.
                                                              * @return {Object} Config настроек окна выбора из справочника.
                                                              */
                                                              prepareLookupConfig: function() {
                                                                              var filters = this.getLookupFilter();
                                                                              var config = {
                                                                                              entitySchemaName: "SysAdminUnit",
                                                                                              multiSelect: true,
                                                                                              columns: ["Contact", "Name"],
                                                                                              hideActions: true,
                                                                                              filters: filters
                                                                              };
                                                                              return config;
                                                              }
 
 
                                                              getLookupFilter: function(isDelegate) {
                                                                              var filters = this.Terrasoft.createFilterGroup();
                                                                              var parentFilter =  this.Terrasoft.createColumnFilterWithParameter(
                                                                                              this.Terrasoft.ComparisonType.EQUAL,
                                                                                              isDelegate ? "GrantorSysAdminUnit.Id" : "GranteeSysAdminUnit.Id",
                                                                                              this.get("MasterRecordId"));
                                                                              var sameIdFilter =  this.Terrasoft.createColumnFilterWithParameter(
                                                                                              this.Terrasoft.ComparisonType.NOT_EQUAL,
                                                                                              "Id",
                                                                                              this.get("MasterRecordId"));
...
                                                                              filters.addItem(sameIdFilter);
                                                                              return filters;
                                                              },

Подобный вопрос задавали http://www.community.terrasoft.ru/forum/topic/11658

Мне нужно сформировать в javascript подобный запрос для фильтрации

declare @vacancyId uniqueidentifier = '3984d4b1-de5d-405b-b7c6-320b03b0a8ec';
select distinct
	vc.UsrCandidatesId
from UsrVacancyCandidates vc
where
	vc.UsrCandidatesId not in(
		select vc.UsrCandidatesId from UsrVacancyCandidates vc 
		where vc.UsrVacanciesId = @vacancyId
	);

Пока не могу понять, как..

1. SELECT DISTINCT vc.UsrCandidatesId

реализуется так:

esq.isDistinct = true;
esq.addColumn("UsrCandidatesId");

2. vc.UsrCandidatesId NOT IN(

                SELECT vc.UsrCandidatesId FROM UsrVacancyCandidates vc 
                WHERE vc.UsrVacanciesId = @vacancyId
        );
 
Реализуется через NOT_EQUAL
 
Пример NUI/InFolderDetail
 
var filterGroup = Terrasoft.createFilterGroup();
if (inFolders.length > 0) {
var notInFilter = Terrasoft.createColumnInFilterWithParameters('Id', inFolders);
notInFilter.comparisonType = Terrasoft.ComparisonType.NOT_EQUAL;
filterGroup.addItem(notInFilter);
}

Можете переделать NOT IN на Not Exists тогда, как пример фильтр в модуле

LeadContactsInFolderDetailV2
 
                                                               /**
                                                               * Метод действия "Добавить группу контактов".
                                                               * @private
                                                               */
                                                               addContactFolder: function() {
                                                                              var masterColumnValue = this.get("MasterRecordId");
                                                                              var config = {
                                                                                              entitySchemaName: "ContactFolder",
                                                                                              multiSelect: true,
                                                                                              columns: ["FolderType", "Id"]
                                                                              };
                                                                              var existsFilterGroup = this.Terrasoft.createFilterGroup();
                                                                               existsFilterGroup.addItem(this.Terrasoft.createColumnFilterWithParameter(
                                                                                              this.Terrasoft.ComparisonType.EQUAL, "Contact", masterColumnValue));
                                                                              var existsFilter = this.Terrasoft.createNotExistsFilter("[ContactInFolder:Folder:Id].Contact",
                                                                                              existsFilterGroup);
                                                                              var filterGroup = this.Terrasoft.createFilterGroup();
                                                                              filterGroup.addItem(existsFilter);
                                                                              var folderFilter = this.Terrasoft.createColumnFilterWithParameter(
                                                                                              this.Terrasoft.ComparisonType.EQUAL, "FolderType", ConfigurationConstants.Folder.Type.General);
                                                                              filterGroup.addItem(folderFilter);
                                                                              config.filters = filterGroup;
                                                                              this.openLookup(config, this.addContactCallback, this);
                                                               },

Теория по Exists
http://www.terrasoft.ua/bpmonlinesdk/Terrasoft.Core~Terrasoft.Core.Enti…

Спасибо, разобрался. Сделал так:

attributes:
{
	"UsrCandidates":
	{
		dataValueType: Terrasoft.DataValueType.LOOKUP,
		lookupListConfig:
		{
			filter: function()
			{
				var vacancy = this.get("UsrVacancies");
				if (!this.Ext.isEmpty(vacancy))
				{
					var filterGroup1 = this.Terrasoft.createFilterGroup();
					var filter1 = this.Terrasoft.createColumnFilterWithParameter(
						this.Terrasoft.ComparisonType.EQUAL,
						"[UsrVacancyCandidates:UsrCandidates].UsrVacancies", vacancy
						.value);
					filterGroup1.addItem(filter1);
					var filterGroup2 = this.Terrasoft.createFilterGroup();
					var filter2 = this.Terrasoft.createNotExistsFilter(
						"[UsrCandidates:Id].Id", filterGroup1);
					filterGroup2.addItem(filter2);
					return filterGroup2;
				}
			}
		}
	},
},
Показать все комментарии

Добрый день!

Подскажите, почему при создании Счета из Продажи не срабатывает событие InvoiceSaving из объекта счета?
Версия 7.3

Нравится

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

Александра, добрый день!

В продолжение удаленного подключения, выяснили, что событие InvoiceSaving не срабатывало по причине того, что все три процесса стартовали из одного стартового сигнала. Для того, чтобы событие срабатывало их необходимо разместить последовательно, либо поместить в один блок.

Спасибо.

Да, верно.
Так ж я использовала не то событие, надо было пользоваться InvoiceSaved.
У меня в процессе есть еще событие InvoiceInserted.
Подскажите какое из событий срабатывает раньше?
InvoiceInserted или InvoiceSaved?
Можете кратко написать порядок срабатывания событий объектов?

Александра, просмотреть данную информацию можно, если перейти на свойства схемы.

Пример прикрепляю к данному письму.

Спасибо.

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

Доброго дня!

BPM 7.5. У нас в данный момент два кастомных пакета. Когда заходишь в конфигурацию, то автоматически выделяется (фокус) не тот пакет, что нужно, люди могут по ошибке создать сущности там, да и раздражает это. Как сделать, чтобы нужный автоматически выделялся нужный пакет?

Спасибо!

Нравится

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

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

При переходе в раздел "Конфигурация" на вкладку "Пакеты", фокус устанавливается на первый пользовательский пакет в списке. Возможности изменять принцип фокусировки на пакете нет. Но, Вы можете с помощью именования пакетов добиться необходимого результата. Требуемый пакет должен отображаться в списке выше всех остальных. Сортировка в списке выполняется по алфавиту.

Спасибо за ответ!

Понял. Кстати, я не знаю, откуда взялся этот первый пакет, был создан до меня, и там никто ничего не создаёт (не должен создавать). Однако, из-за неверной фокусировки такие инциденты происходят.

Вопрос - могу ли я удалить такой неиспользуемый пакет без последствий?

Вероятнее всего, имя неиспользуемого Вами пакета "Custom+номер сборки" - в таком случае, в версии 7.5 - это предварительно созданный пользовательский пакет.

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

Также, если Вы на постоянной основе работаете со своим (уже созданным) пакетом, укажите его в системной настройке "Текущий пакет".

Да, это именно такой пакет. Проверю и удалю, спасибо.

У меня тоже Custom всегда по умолчанию выбран, несмотря на то, что текущий пакет указан другой

Владимир, системная настройка с пакетом по умолчанию не влияет на фокус на пакете в списке.

Как я и писал ранее - при переходе на вкладку "Пакеты" фокус устанавливается на верхний в списке пользовательский пакет.

"Владимир Соколов" написал:

У меня тоже Custom всегда по умолчанию выбран, несмотря на то, что текущий пакет указан другой


Тоже в настройках шарился, устанавливал этот параметр, безрезультатно :lol:

А запланировано ли когда-нибудь такое удобство, как указание пакета по умолчанию, при открытии конфигурации? :-) каждый раз при входе в конфигурацию - лишний клик мышкой.. За день набегает на пару минут... И это только на одного разработчика... А в масштабах планеты? Месяцы трудозатрат в трубу. ;-)

Здравствуйте, Алексей!

Это же сколько нужно сделать кликов мышкой, чтобы пару минут времени за день набежало? И сколько времени при этом уходит на загрузку конфигурации?:smile:

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

"Демьяник Алексей" написал:

Здравствуйте, Алексей!

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


Давайте сойдемся на 3х секундах на то, чтобы открыть конфигурацию, увидеть, что пакет не тот, что надо, довести указатель мышки до нужного пакета (если он виден на экране сразу, и не нужно использовать скролл), нажать, и дождаться обновления экрана на новый список модулей :)
Итого 120/3 = 40 раз открыть конфигуратор в течение дня... вполне реально :cool:

Здравствуйте.
Что касается пакетов с одинаковыми именами, то в конфигурации Вы видите, пакеты только своей конфигурации, Если Вы смотрите в базе, то пакеты отличаются значением поля WorkSpaceID. Если Вы смотрите в файловой системе (SVN), то у каждого пакета указан номер репозитория (0, 1, 2...). По вопросу фокуса на нужном пакете при открытии конфигурации - можно, конечно, зарегистрировать пожелание на реализацию в одной из следующих версий, но эта задача, скорее всего, будет иметь невысокий приоритет.

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

Доброго дня!

BPM 7.5. Может глупый вопрос задаю. Как я понял, и поддержка вроде подтвердила, имя лукапной колонки в объекте должно 1 в 1 совпадать с именем того объекта, на который эта колонка ссылается, иначе не будут работать некоторые штуки - например, не будет возможность сделать EntitySchemaQuery запрос - будет ошибка, что таблица не найдена.

А что делать в случае, когда несколько колонок объекта ссылаются на один и тот же объект, как их именовать?

Заранее благодарю!

Нравится

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

Добрый день!

Вы сами ответили на свой вопрос.
В приложении bpm'online такая реализация не возможна, когда «несколько колонок объекта ссылаются на один и тот же объект» .
Выход: только через создание нескольких view, но с разными именами или дублирующих справочников.

Приятного дня!

"Вильшанский Дмитрий" написал:

Добрый день!

Вы сами ответили на свой вопрос.

В приложении bpm'online такая реализация не возможна, когда «несколько колонок объекта ссылаются на один и тот же объект» .

Выход: только через создание нескольких view, но с разными именами или дублирующих справочников.

Приятного дня!

Если я правильно понял вопрос, то и поддержке и Вам можно поставить двойку.
Интересно, как Вы объясните наличие и работоспособность полей "Контрагент" и "Поставщик" в карточке "Счет". Они вполне успешно ссылаются на контрагентов.

Спасибо за ответ!

Жаль..
По моему такая возможно должна быть из коробки каким-то образом реализована. Например, есть сущность "Candidate", у него поля "Assigned recruited", "Assigned searcher", оба должны брать значения из объекта "Employees" (или "Contacts"). Получается я должен создавать вьюшки для рекрутёров и сёрчеров, а в "Employees" добавлять признаки "Is recruiter", "Is searcher" ? Как-то не по феншую :(

"Валерий Андрусик" написал:Если я правильно понял вопрос, то и поддержке и Вам можно поставить двойку.
Интересно, как Вы объясните наличие и работоспособность полей "Контрагент" и "Поставщик" в карточке "Счет". Они вполне успешно ссылаются на контрагентов.

Вопрос поняли правильно. И, действительно, возможно создать колонки с произвольными именами, ссылающимися на таблицу с другим именем, и они будут вполне работоспособны.

Однако, я ранее сталкивался с проблемой, когда необходимо было выполнить EntitySchemeQuery запрос из JS такого вида:

var esqCand = this.Ext.create("Terrasoft.EntitySchemaQuery",
{
		rootSchemaName: "UsrVacancyCandidates"
});
esqCand.addAggregationSchemaColumn("UsrCandStat.Value", Terrasoft.AggregationType.MAX, "Value");

При этом колонка UsrCandStat (ссылка на таблицу UsrCandStat ) таблицы UsrVacancyCandidates называлась не так, как таблица, а, например, UsrCandSt. И запрос падал с ошибкой, пока я не переименовал (по совету поддержки) поле 'UsrCandSt' на такое же имя, как таблица, на которую она ссылается ('UsrCandStat').

Понятно, спасибо за уточнение, была непонятна категоричность в совете "создавать несколько view" просто при наличии ссылочных полей на одну таблицу.

"trickbz" написал:При этом колонка UsrCandStat (ссылка на таблицу UsrCandStat ) таблицы UsrVacancyCandidates называлась не так, как таблица, а, например, UsrCandSt. И запрос падал с ошибкой, пока я не переименовал (по совету поддержки) поле 'UsrCandSt' на такое же имя, как таблица, на которую она ссылается ('UsrCandStat').

Надеюсь это исправят в одном из обновлений бинарников, ибо это скорее проблема платформы, а не Ваша.

"trickbz" написал:
Валерий Андрусик пишет:

Если я правильно понял вопрос, то и поддержке и Вам можно поставить двойку.

Интересно, как Вы объясните наличие и работоспособность полей "Контрагент" и "Поставщик" в карточке "Счет". Они вполне успешно ссылаются на контрагентов.

Вопрос поняли правильно. И, действительно, возможно создать колонки с произвольными именами, ссылающимися на таблицу с другим именем, и они будут вполне работоспособны.

Однако, я ранее сталкивался с проблемой, когда необходимо было выполнить EntitySchemeQuery запрос из JS такого вида:

var esqCand = this.Ext.create("Terrasoft.EntitySchemaQuery",

{

                rootSchemaName: "UsrVacancyCandidates"

});

esqCand.addAggregationSchemaColumn("UsrCandStat.Value", Terrasoft.AggregationType.MAX, "Value");

При этом колонка UsrCandStat (ссылка на таблицу UsrCandStat ) таблицы UsrVacancyCandidates называлась не так, как таблица, а, например, UsrCandSt. И запрос падал с ошибкой, пока я не переименовал (по совету поддержки) поле 'UsrCandSt' на такое же имя, как таблица, на которую она ссылается ('UsrCandStat').

Первоначальный вопрос был не до конца понят.
Ответ:
1. Имя лукапной колонки должно совпадать 1 в 1 со справочником – да
2. Если необходимо, что бы несколько колонок ссылалось на один и тот-же справочник, необходимо в конфигурации добавить новое поле, типа справочник и указать нужную сущность
Как пример действительно подойдет Invoice (поля Account и Supplier).
3. Все используемые имена должны совпадать в конфигурации и на карточке 1:1 c учетом реестра
4. Пример агрегирующего вызова:

var select = Ext.create("Terrasoft.EntitySchemaQuery", {
                rootSchemaName: "Invoice"     
});
select.addAggregationSchemaColumn("Supplier.Name", Terrasoft.AggregationType.COUNT, "Count");
select.filters.add(select.createColumnFilterWithParameter(
                Terrasoft.ComparisonType.EQUAL, "Supplier.Name", "Test"));
select.getEntityCollection(function(result) {
                if (result.success) {
                               var collection = result.collection;
                               collection.each(function(item) {
                                               console.log(item.get("Count"));
                               }, this);
                }
}, this);
Показать все комментарии

Добрый день.

При замещении базового объекта возникает следующая ошибка:

Ошибка сохранения: Введение ограничения внешнего ключа (FOREIGN KEY) "FK2J2iqfKkMp0jtMuJaM78caLDQY" для таблицы "DocumentProduct" может привести к появлению циклов или множественных каскадных путей. Укажите ON DELETE NO ACTION или ON UPDATE NO ACTION либо измените другие ограничения внешнего ключа (FOREIGN KEY).
Нельзя создать ограничение. См. предыдущие ошибки.

Нашла аналогичный топик:

https://community.terrasoft.ru/forum/topic/11534

Там предлагается делать следующее:

ALTER TABLE DocumentProduct
DROP CONSTRAINT FK2J2iqfKkMp0jtMuJaM78caLDQY

Но у меня в sql возникает другая ошибка:

Сообщение 3728, уровень 16, состояние 1, строка 1
FK2J2iqfKkMp0jtMuJaM78caLDQY не является ограничением.
Сообщение 3727, уровень 16, состояние 0, строка 1
Нельзя удалить ограничение. См. предыдущие ошибки.

Нравится

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

Здравствуйте Александра,

обычно такая ошибка в SQL Server Management Studio возникает при втором и больше выполнении срипта на удаление объекта. После первого выполнения скрипта соостветстсвующее ограничение удаляется из системной таблицы sys.foreign_keys. Если выполнить тот же скрипт еще раз, то система не сможет больше найти нужную запись в sys.foreign_keys, поэтом скажет, что данный объект не является ограничением. Пожалуйста перекомпилируйте объект еще раз.

"Александр Ведмидь" написал:

Здравствуйте Александра,

обычно такая ошибка в SQL Server Management Studio возникает при втором и больше выполнении срипта на удаление объекта. После первого выполнения скрипта соостветстсвующее ограничение удаляется из системной таблицы sys.foreign_keys. Если выполнить тот же скрипт еще раз, то система не сможет больше найти нужную запись в sys.foreign_keys, поэтом скажет, что данный объект не является ограничением. Пожалуйста перекомпилируйте объект еще раз.

Компилировала несколько раз, перезапускала IIS, все то же самое.

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

Здравствуйте Александра,

Разобрался с причиной проблемы на похожем примере с таблицей AccountBillingInfo, дело в том, что базовый AccountBillingInfo содержит поле AccountId, которое ссылается на таблицу Account с каскадным удалением. При замещении объекта система пытается создать такую же каскадную связь для этого поля, что приводит к ошибке, которую мы видим в дизайнере.
Чтобы найти это ограничение выполняем скрипт:

SELECT fk.name [constraint name], obj.name [parent table name], o.name [referenced table name]
FROM sys.foreign_keys fk
INNER JOIN sys.objects o
ON fk.referenced_object_id = o.object_id
INNER JOIN sys.objects obj
ON fk.parent_object_id = obj.object_id
WHERE (fk.delete_referential_action_desc = 'CASCADE' or fk.update_referential_action_desc = 'CASCADE') and obj.name IN ('Account', 'AccountBillingInfo', 'Contact', 'Country')

После чего можем либо удалить найденное ограничение (подставьте найденное имя ограничения)
ALTER TABLE [dbo].[AccountBillingInfo]
drop CONSTRAINT [FKMEzS5qAz0Eo3Zxv0YomqG1h6Js]

либо убрать каскадную связь на удаление

--drop constraint at first
ALTER TABLE [dbo].[AccountBillingInfo]
drop CONSTRAINT [FKMEzS5qAz0Eo3Zxv0YomqG1h6Js]
--create again without cascade actions
ALTER TABLE [dbo].[AccountBillingInfo] WITH CHECK ADD CONSTRAINT [FKMEzS5qAz0Eo3Zxv0YomqG1h6Js] FOREIGN KEY([AccountId])
REFERENCES [dbo].[Account] ([Id])
--ON DELETE CASCADE
GO

И перекомпилировать объект.
Больше ошибка на моей конфигурации не воспроизводилась.

Работает! Огромное спасибо!

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

Всем добрый день!

Спустя n-ое количество времени надоело вносить изменения в справочники вручную из одной системы в другую + апдейть файл констант / менять значения в процессах и т.п. (база MS SQL)

Для упрощения работы была написана небольшая хранимая процедура, которая позволяет генерировать соотв. запросы (при желании можно модифицировать так, чтобы скрипты автоматически выполнялись, на данный момент предпочитаю просматривать глазами, что сгенерируется). Может кому-то пригодится. Файл с текстом во вложении.

Вызов хранимки:
declare @txt varchar(max)
exec dbo.usp_SynchronizeDictionaries '2015-05-14', 'Terrasoft_Source', 'Terrasoft_Target', null, null, @txt output

1) '2015-05-14' –дата с какой нужно затащить изменения (обычно это дата, на которую снята копия базы)
2) 'Terrasoft_Source' – имя базы-источника
3) 'Terrasoft_Target' – имя целевой базы (можно добавить сервер типа [srv].Terrasoft_Target если есть linked server)
4) Null первый – можно задать имя конкретной одной таблицы (не обязательно, используется в рекурсии)
5) Null второй – строка имен таблиц в формате «;tbl_1;tbl_2;» (разделители ;) которые «Обработаны», т.е. которые не нужно трогать (не обязательно, используются в рекурсии)
6) @txt параметр для передачи списка таблиц в рекурсии

Суть работы хранимой процедуры:
1) пробегаем по всем таблицам, которые находятся в нужных группах (Справочники + у нас, например, еще 2 доп. группы.). В каждой таблице смотрим, есть ли внешние ключи (если есть, то нужно вначале провести манипуляции с таблицами, на которые они ссылаются). Для таблиц из внешних ключей хранимая процедуры вызывается рекурсивно. Есть защита от "зацикливания" (список обработанных таблиц) в случае если в справочниках есть перекрестные ссылки друг на друга. К счастью, у нас такого нет. + Если референсные таблицы не являются справочниками, их не трогаем.
2) для каждой таблицы вытаскиваем набор столбцов и формируем запросы на адпейт (для записей у которых ModifiedOn > даты из параметра запуска), запросы на вставку для новых записей (для которых CreatedOn > даты из параметра запуска)

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

TO-DO: можно контролировать, что в целевой системе не было апдейтов параметров начиная с даты, переданной в хранимку (чтобы случайно не перетереть настройки, сделанные на продакшене за это время вручную).

Текст процедуры прикрепил "as is", не обессудьте, прилизывать текст некогда... кому понадобится думаю легко сделает это + конечно же возможны улучшения, но на них тоже нет времени :)

Нравится

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

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

Спасибо за полезный пример.

TO-DO: генерировать наименования столбцов нужно в скобках [] т.к. они могут совпадать со служебными словами... например одна из колонок у нас называлась Order, соотв. нужно чтобы скрипт генерировал t.[Order] = s.[Order]

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

Здравствуйте, уважаемая поддержка и пользователи BPM 7.5 (и других версий тоже)!

Изучаем BPM, и пока что работаем без SVN.
Работа происходит очень топорно:
1. На тестовом сервере имплементируется решение путём изменения объектов, схем, и т.п.
2. Решение работает.
3. На будущем продакшн сервере повторяется та же последовательность действий...

1. В итоге делается double work
2. В процессе повторения действий на будущем продакшн сервере легко ошибиться.
3. Не видно, кто и что менял. Да и что сам менял.
4. Нельзя откатить часть того, что менял, кроме как ресторить бэкап БД.
5. Нельзя сравнить старое с новым.
6. И т.п. и т.д.

Не смог найти нормальной документации по теме - как прикрутить SVN к BPM 7.5.
С BPM знаком пару недель, поэтому голова кругом от других задач, дык еще и SVN нет.

Возможно, есть какая-то подробная документация у поддержки или пользователей, которые уже подняли SVN для BPM 7.5. Поделитесь, пожалуйста!

Доброго дня!

Нравится

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

Добрый день!

На данный момент Вы можете воспользоваться документацией по установке и настройке SVN, перейдя по следующей ссылке:

http://academy.terrasoft.ru/documents/?product=SDK&ver=7.5.0 ,

раздел "Разработка конфигураций на платформе" -> "Работа с системой управления версиями" -> "Система управления версиями: назначение, установка, настройка"

SVN documentation

Если Вы не найдете ответы на свои вопросы, сообщите нам. Всегда рады помочь!

А я правильно понимаю, что к on-demand SVN не прикручен?

"Мамедов Фариз Эльдарович" написал:А я правильно понимаю, что к on-demand SVN не прикручен

Если у вас нет действий, связанных с свн в настройке конфигурации - запросите техподдержку, чтобы они вам включили поддержку свн (это пара параметров в webconfig'ах)
Если же действия ("Открыть список хранилищ", "Обновить пакет из хранилища" и т.д.) есть - просто следуйте статье в академии
Но учтите, что привязать к свн вы сможете только новые пакеты - если надо фиксировать уже созданные элементы, придется их пересоздавать в пакете, привязанном к свн

"Андросов Дмитрий" написал:Но учтите, что привязать к свн вы сможете только новые пакеты - если надо фиксировать уже созданные элементы, придется их пересоздавать в пакете, привязанном к свн

А перенести элементы в новый пакет нельзя?

Владимир, уточните задачу и версию приложения. Зачем переносить схемы в новый пакет? Для синхронизации с SVN?

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