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

Пробовал два метода описанные тут https://community.terrasoft.ua/questions/zakrytie-zapisi-pri-sohranenii и https://community.terrasoft.ua/questions/thissave-prervat-zakrytie-kartocki-vozvrat-k-predydusei-kartocke-v-shain тут, но не один из них не помог

Нравится

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

Александр, обратите ещё внимание на более новую статью по теме:

«Как сохранять, не закрывая, открытую бизнес-процессом страницу редактирования».

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

Видел статью, пробовал, не работает. Видимо что-то не туда пишу

Нужно отлаживаться, без подробностей никто не угадает, что не так.

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

Добрый день!

Столкнулся с проблемой публикации данных из секции в модуль.

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

....
afterFiltersUpdated: function() {
				this.callParent(arguments);
				debugger;
				var previousDate = new Date();
				previousDate.setDate(previousDate.getDate() - 1);
 
				var StartDate = "";
				var StopDate = "";
 
				var fixedFilters = this.get("SectionFiltersValue").collection.get("FixedFilters");
				var customFilters = this.get("SectionFiltersValue").collection.get("CustomFilters");
				StartDate = fixedFilters.PeriodFilter.startDate === null ? 
					Ext.Date.format(previousDate, "Y-m-d") :
					typeof (fixedFilters.PeriodFilter.startDate) === "string" ? 
					Ext.Date.format(new Date((new Date(fixedFilters.PeriodFilter.startDate.substr(0, 10))))) : 
					Ext.Date.format(new Date(), "Y-m-d");
				StopDate = fixedFilters.PeriodFilter.dueDate === null ? 
					Ext.Date.format(previousDate, "Y-m-d") :
					typeof (fixedFilters.PeriodFilter.dueDate) === "string" ? 
					Ext.Date.format(new Date((new Date(fixedFilters.PeriodFilter.dueDate.substr(0, 10))))) : 
					Ext.Date.format(new Date(), "Y-m-d");
 
					var dataSend = {
						StartDate: StartDate,
						StopDate: StopDate
					};
 
					this.sandbox.publish("UpdateInsurerAnalyticWidget", dataSend, ["AbInsurerAnalyticWidgetUpdated"]);
			},
....

 

define("AbInsurerAnalyticByZoneModule", ["ext-base", "terrasoft", "sandbox", "BaseFiltersGenerateModule", "AbInsurerAnalyticByZoneModuleResources", "ChartModuleHelper", "css!AbInsurerAnalyticByZoneModuleCSS", "ServiceHelper"],
	function(Ext, Terrasoft, sandbox, BaseFiltersGenerateModule, resources, ChartModuleHelper, css, ServiceHelper, ConfigurationConstants) {
		function getViewModel() {
			return Ext.create("Terrasoft.BaseViewModel", {
				entitySchema: "AbInsurance",
				methods: {
					init: function() {},
					getChart: function(key) {
						sandbox.publish("GenerateChart", key);
 
					},
					load: function() {}
				}
			});
		}
		var result = "";
		function generateMainView(renderTo) {
 
			var resultConfig = Ext.create("Terrasoft.Container", {
				id: "tableInsurerAnalyticByZoneParamContainer",
				selectors: {
					wrapEl: "#tableInsurerAnalyticByZoneParamContainer"
				},
				renderTo: renderTo
			});
			return resultConfig;
		};
		function getAnalyticByZone(parameters) {
			var serviceData = {
				startDate: parameters[0].toString(),
				stopDate: parameters[1].toString()
			};
 
			ServiceHelper.callService("AnalyticsProcessingService", "GetAnalyticDashboardData",
				function (response) {
					debugger;
					var htmlAdded = resources.localizableStrings.HeaderTable;
					if (response.status === 404 || response.status === 500 || response.status === 400) {
						Terrasoft.showErrorMessage("\t Error: \n" + response.message);
					}
					else if(response.GetAnalyticDashboardDataResult.length > 0){
						result = response.GetAnalyticDashboardDataResult;
						for(var i = 0; i < result.length; i++){
							var segment = result[i].Segment;
							var avgRevenue = result[i].AvgRevenue;
							var salesCount = result[i].SalesCount;
							var cpa = result[i].Cpa;
							var sumCtr = result[i].SumCtr;
							var cr = result[i].Cr;
							var roas = result[i].Roas;
							var tableBody = resources.localizableStrings.TableBody;
							htmlAdded += Ext.String.format(tableBody,segment,avgRevenue,salesCount,cpa,sumCtr,cr,roas);
						}
					} else {
						result = null;
					}
					htmlAdded += "</table>";
					Ext.get("tableInsurerAnalyticByZoneParamContainer").setHTML(htmlAdded);
				}, serviceData, this);
		}
		function getReplaceString(str, separator){
		var arSt = str.split(separator);
			var res = arSt[2] + separator + arSt[1] + separator + arSt[0];
			while(res.indexOf(separator) > 0){
				res = res.replace(separator,"-");
			}
			return res;
		}
 
		var render = function(renderTo) {
			var viewConfig = generateMainView(renderTo);
			var viewModel = getViewModel();
			var getStartD = Ext.get("fixedFilterCreatedAtView-wrap").dom.innerText;
			var getEndD = Ext.get("fixedFilterCreatedAtDueView-wrap").dom.innerText;
			var date = new Date();
			var startD = getStartD.indexOf("Начало") > 0 ? Ext.Date.format(date, "Y-m-d") : getReplaceString(getStartD, ".");
			var endD = getEndD.indexOf("Завершение") > 0 ? Ext.Date.format(date, "Y-m-d") : getReplaceString(getEndD, ".");
			var ar = [];
			ar.push(startD);
			ar.push(endD);
			getAnalyticByZone(ar);
			viewConfig.bind(viewModel);
		};
		return {
			schema: "AbInsurance",
			mesages: {
				"UpdateInsurerAnalyticWidget": {
				mode: Terrasoft.MessageMode.PTP,
				direction: Terrasoft.MessageDirectionType.SUBSCRIBE
			},
			},
			methods: {
 
			},
			userCode: function() {},
			init: function() {
				debugger;
				sandbox.subscribe("UpdateInsurerAnalyticWidget", function(arg) {
 
					var arArg = [];
					arArg.push(arg.StartDate);
					arArg.push(arg.StopDate);
					getAnalyticByZone(arArg);
				}, this, ["AbInsurerAnalyticWidgetUpdated"]);
			},
			render: render
		};
	}
);

в данном модуле в init сделал подписку, но она не отрабатывает при изменении фильтров.

Кто нибудь сталкивался с такой проблемой?

Нравится

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

Алексей, не вижу в примерах кода вызова sandbox.registerMessages(messageConfig) для регистрации сообщений модуля. Проверьте, всё ли правильно в Ваших разработках, ориентируясь на инструкцию «Обмен сообщениями между модулями» в академии.

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

Добрый день!

Установил расширение https://marketplace.terrasoft.ru/template/email-extension-creatio. Осваиваю его функционал, обнаружил одну особенность - все письма отображаются в одном списке. Захотел навести порядок - создать динамические группы в которых группировались бы входящие и исходящие сообщения по пользователю, подумал руками делать не совсем правильно, решил через БП. Но, не могу в списке объектов найти объекты этого пакета. Например, "Группа Email":

Изображение удалено.

Изображение удалено.

Приложение компилировал.

В чем может быть дело?

 

Нравится

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

Руслан, возможно, тот пакет, где Вы ведёте доработку, находится в иерархии пакетов не ниже, чем пакет дополнения, а сбоку или выше.

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

Спасибо за рекомендацию, буду разбираться.

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

Всем доброго времени суток. Кто нибудь сталкивался с разработкой пользовательского виджета в аналитике. Не могу разобраться, как реализовать в виде списка? У меня есть ХП которая возвращает нужный результат. 

Можете скинуть пару примеров?

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

Нравится

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

Добрый вечер, Алексей.

 

Результат хранимой процедуры возвращайте в представление, например:

 

CREATE FUNCTION [dbo].[tsf_PathReportData]()
RETURNS @ExaminationBlocksByObject TABLE (
		[Number] nvarchar(50),
		[ExaminationId] uniqueidentifier,
		[ObjectId] uniqueidentifier,
		[MacroscopicDescription] nvarchar(max),
		[BlocksDescription] nvarchar(max))
AS
BEGIN
 
	DECLARE
		@Number nvarchar(50),
		@ExaminationId uniqueidentifier,
		@ObjectId uniqueidentifier,
		@MacroscopicDescription nvarchar(max),
		@BlocksDescription nvarchar(max)
 
	DECLARE ExaminationDetailCursor CURSOR STATIC LOCAL FOR
	SELECT
			O.Number,
			O.MacroscopicDescription,
			O.ExaminationId,
			O.Id as ObjectId
	FROM ABExaminationObject O
 
	OPEN ExaminationDetailCursor
 
	FETCH NEXT FROM ExaminationDetailCursor INTO @Number, @MacroscopicDescription, @ExaminationId, @ObjectId
 
	WHILE @@FETCH_STATUS = 0 BEGIN
 
		SET @BlocksDescription = ''
 
		SELECT @BlocksDescription = @BlocksDescription + B.Number + ' ' + B.[Description] + CHAR(13) + CHAR(10)
		FROM ABExaminationBlock B
		WHERE B.ExaminationObjectId = @ObjectId
 
		INSERT INTO @ExaminationBlocksByObject (
			Number,
			ExaminationId,
			ObjectId,
			MacroscopicDescription,
			BlocksDescription
		)
		VALUES (
			@Number,
			@ExaminationId,
			@ObjectId,
			@MacroscopicDescription,
			@BlocksDescription)
 
		FETCH NEXT FROM ExaminationDetailCursor INTO @Number, @MacroscopicDescription, @ExaminationId, @ObjectId
 
	END 
 
	CLOSE ExaminationDetailCursor 
	DEALLOCATE ExaminationDetailCursor
 
	RETURN
 
END
 
 
create view VwExaminationReport
as
select
	newid() as Id,
	Number as Number,
	MacroscopicDescription as MacroscopicDescription,
	ExaminationId as Examination,
	BlocksDescription as BlocksDescription
from [tsf_PathReportData]()

На основании этого представления создайте схему таблицы-представления в конфигурации и используйте этот объект в стандартном элементе итогов 'Список'.

Алла Савельева,

добрый! Мне в ХП нужно передавать параметры даты из фильтров, на сколько я знаю, то представление нельзя сделать с принимаемыми параметрами.

CREATE PROCEDURE [dbo].[absp_GetProductAnalyticByZone] @startDate varchar(10), @stopDate varchar(10)
AS
SELECT 
	T.Segment [Segment], 
	ROUND(SUM(T.[AvgRevenue]), 2, 1) [AvgRevenue],
	SUM(T.[SalesCount]) [SalesCount],	
	ROUND(SUM(T.[CPA]), 2, 1) [CPA],	
	SUM(T.[SumCtr]) [SumCtr],	
	ROUND(SUM(T.[ROAS]), 2, 1) [ROAS]
FROM
	(SELECT 
		[IABZ].[Date],
		[IABZ].ZoneId,
		[IZ].Segment,
		SUM([IABZ].Ctr) [SumCtr],
		SALES_QUERY.SalesCount [SalesCount],
		SALES_QUERY.AvgRevenue [AvgRevenue],
		IIF(SALES_QUERY.SalesCount = 0 , 0,([CpcCost].[AdsCost]/SALES_QUERY.SalesCount))[CPA],
		(SALES_QUERY.SalesCount * SALES_QUERY.AvgRevenue / [CpcCost].[AdsCost]) * 100 [ROAS],
		[CpcCost].[AdsCost]
 
	FROM [InsurerAnalyticByZone] [IABZ] WITH(NOLOCK)
	LEFT OUTER JOIN [InsurerZone] [IZ] WITH(NOLOCK) ON [IABZ].ZoneId = [IZ].Id
	INNER JOIN [CpcCost] [CpcCost] WITH(NOLOCK) ON [IABZ].[Date] = [CpcCost].[Date]
	OUTER APPLY (SELECT COUNT([I].[Id]) [SalesCount],
						AVG([I].[Revenue]) [AvgRevenue]
					FROM [AbInsurance] [I] WITH(NOLOCK) 
					INNER JOIN [CityByEwa] [CBE] WITH(NOLOCK) ON [I].EwaCityId = [CBE].Id
					WHERE [I].StatusId = '195CD1AD-37B3-4F0A-B4FC-70E2BF0B3F06' 
					AND [CBE].ZoneCode = [IZ].Code 
					AND CONVERT(varchar(10), [I].CreatedAt, 120) = [IABZ].[Date]
				) SALES_QUERY
	GROUP BY [IABZ].ZoneId, [IZ].Segment, [IABZ].[Date],  [IZ].Code, [CpcCost].AdsCost, SALES_QUERY.SalesCount, SALES_QUERY.AvgRevenue	
	) AS T
WHERE T.[Date] BETWEEN @startDate AND @stopDate
GROUP BY T.ZoneId, T.Segment
 
UNION ALL 
 
SELECT 
[CBE].[Name] [Segment],
[R].[AvgRevenue] [AvgRevenue],
COUNT([I].[Id]) [SalesCount],
SUM(IIF(R.[Count] = 0, 0, [CpcCost].[AdsCost]/R.[Count])) [CPA],
 0 [SumCtr],
ROUND(SUM((R.[Count] * R.[AvgRevenue]) / [CpcCost].[AdsCost]) * 100, 2, 1) [ROAS]
FROM [AbInsurance] [I] WITH(NOLOCK) 
INNER JOIN [CityByEwa] [CBE] WITH(NOLOCK) ON [I].EwaCityId = [CBE].Id AND [CBE].Id = '9a008f3a-f865-4e74-b1f2-530f54711f2b'
INNER JOIN [CpcCost] [CpcCost] WITH(NOLOCK) ON CONVERT(varchar(10), [I].CreatedAt, 120) = [CpcCost].[Date]
OUTER APPLY ( SELECT COUNT([I].Id) [Count],
						AVG([I].[Revenue]) [AvgRevenue]
				FROM [AbInsurance] [I] WITH(NOLOCK) 
				INNER JOIN [CityByEwa] [CBE] WITH(NOLOCK) ON [I].EwaCityId = [CBE].Id AND [CBE].Id = '9a008f3a-f865-4e74-b1f2-530f54711f2b'
				INNER JOIN [CpcCost] [CpcCost] WITH(NOLOCK) ON CONVERT(varchar(10), [I].CreatedAt, 120) = [CpcCost].[Date]
				WHERE [I].StatusId = '195CD1AD-37B3-4F0A-B4FC-70E2BF0B3F06' AND CONVERT(varchar(10), [I].CreatedAt, 120) BETWEEN @startDate AND @stopDate
) R
WHERE [I].StatusId = '195CD1AD-37B3-4F0A-B4FC-70E2BF0B3F06' AND CONVERT(varchar(10), [I].CreatedAt, 120) BETWEEN @startDate AND @stopDate
GROUP BY [CBE].[Name], [R].[AvgRevenue]

вот моя ХП, возвращает мне нужную информацию

Нигрескул Алексей,

А если попробовать реализовать Ваш виджет, как наследник от базового списка итогов?

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

Добрый день!

 

У нас стоит Oktell Call-Centre и стандартный коннектор Oktell от террасофт. 

У нас есть сотрудники, которые используют и стац. телефоны и отдельно софтверный телефон Oktell. 

Но софтфон Oktell не позволяет переносить звонки в bpm. 

Каким образом это можно сделать с помощью других sip-телефонов Microsip, 3CX и др. SIP-телефоны?

Нравится

1 комментарий
Лучший ответ

Так в сценарии пост-обработки звонка ложите его в базу bpm! Если надо будет помощь, напишите в скайп dima-tashohlo

Так в сценарии пост-обработки звонка ложите его в базу bpm! Если надо будет помощь, напишите в скайп dima-tashohlo

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

Добрый день!

При запуске команды ExecuteScript, утилита отваливается с ошибкой «Не удается найти файл».

Команда RebuildWorkspace выполняется успешно:

Изображение удалено.

В мониторе процессов видно что не удается найти файл Terrasoft.Tools.Common.resources.dll:

Изображение удалено.

Кто нибудь сталкивался с такой проблемой? В чем может быть дело? Спасибо!

Нравится

2 комментария
Лучший ответ

Добрый день!

Лично мне помогла следующая строка в IExecutor-классе:



userConnection.Workspace.WorkspaceAssembly = Assembly.Load("Terrasoft.Configuration");



Еще дополнительно можно попробовать обновить папку DesktopBin\WorkspaceConsole данными из папки Terrasoft.Configuration\bin после полной компиляции приложения

Добрый день!

Лично мне помогла следующая строка в IExecutor-классе:



userConnection.Workspace.WorkspaceAssembly = Assembly.Load("Terrasoft.Configuration");



Еще дополнительно можно попробовать обновить папку DesktopBin\WorkspaceConsole данными из папки Terrasoft.Configuration\bin после полной компиляции приложения

Alex Kalnitskiy, добрый день!

Вы мой спаситель, помогло следующее - скопировал из папки Terrasoft.Configuration\bin  файл Terrasoft.Configuration.dll и на всякий случай Terrasoft.Configuration.pdb. И вуаля, все заработало. Тех поддержка не смогла предоставить решение.

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

Поле ответственный в карточке контрагента заполняется автоматически текущим контактом пользователя. При импорте из Excel происходит тоже самое.

Вопрос. Как заставить систему оставить данное поле пустым?

Пробовал оставить пустое поле в Ecxel - не помогло. Все равно заполнилось текущим пользователем. Стоит задача загрузки контрагентов со стороны администратора, поле ответственный должно содержать менеджера по продажам, но на текущий момент нет достоверной информации и надо оставить его пустым.

Нравится

3 комментария
Лучший ответ

Можно сделать импорт, а затем с помощью БП очистить это поле. По тэгу легко найдете заимпортированные записи

Алексей, это задано тут:

При желании, можно в своём пакете переопределить пустым.

Но нужно учесть негативные последствия, если где-то на это завязана логика, например, та же раздача прав.

Можно сделать импорт, а затем с помощью БП очистить это поле. По тэгу легко найдете заимпортированные записи

Спасибо за ответы. Вариант с БП для моего кейса лучше. Удивляюсь что сам не додумался. Импорт контрагентов когда нибудь закончится и менеджеры начнут создавать сами. Тогда и пригодится автозаполнение.

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

Добрый день. Вопрос не по решению проблемы а о том - как узнать что глобальный поиск подключен и работает корректно?

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

Нравится

10 комментариев
Лучший ответ

В поддержке должна быть 2.0.2, если не новее.

Очистить редис и перезапустить сайт пробовали? У меня версия 1.7 заработала только после этих манипуляций.

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

 

Если предложение Алексея не поможет, первое, что можно проверить, это доступность эластика из сервера, где развернут глобальный поиск (ГП). Это можно сделать следующим образом:

1. Зайти на сервер, где развернут ГП.

2. Зайти внутрь любого контейнера ГП, например gs-web-api. Для этого необходимо выполнить команду

docker exec -it gs-web-api bash

3. Оправить запрос на эластик

curl -v http://{elastic}:9200

где {elastic} надо заменить на ip_адрес сервера, где развернут эластик

Результат выполнения последней команды покажет, есть доступ (вернет ответ 200 ОК) или нет (будет ошибка)

Если же есть ошибка, то возможно, нет доступа с сервиса, где развернут ГА на сервис, где развернут эластик, или например закрыт порт 9200 на сервере, где развернут эластик. Подобные проблемы устраняются администраторами на стороне клиента.

 

Также нужно проверить правильность значения системных настроек: “GlobalSearchUrl”, “GlobalSearchConfigServiceURL” и “GlobalSearchIndexingApiUrl”.

 

 А также проверить, включены ли фичи  'GlobalSearch', 'GlobalSearch_V2' и 'GlobalSearchRelatedEntityIndexing' у текущего пользователя , это можно узнать запросами:

 

select * from feature where code = 'GlobalSearch' or code = 'GlobalSearch_V2' or code = 'GlobalSearchRelatedEntityIndexing'
 
select * from AdminUnitFeatureState where Featureid in (select id from feature where code = 'GlobalSearch' or code = 'GlobalSearch_V2' or code = 'GlobalSearchRelatedEntityIndexing')

Ещё дело может быть в более старой версии самого поиска, сейчас последняя 2.0.2, может помочь обновление на неё.

Мотков Илья,

Выполнил запрос из контейнера

root@714fe8324321:/app# curl -v http://172.28.116.165:9200
* Rebuilt URL to: http://172.28.116.165:9200/
*   Trying 172.28.116.165...
* TCP_NODELAY set
* Connected to 172.28.116.165 (172.28.116.165) port 9200 (#0)
&gt; GET / HTTP/1.1
&gt; Host: 172.28.116.165:9200
&gt; User-Agent: curl/7.52.1
&gt; Accept: */*
&gt;
&lt; HTTP/1.1 200 OK
&lt; content-type: application/json; charset=UTF-8
&lt; content-length: 327
&lt;
{
  "name" : "bxNTqjU",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "hhGU9yAwR0iD4gCb5CrKrw",
  "version" : {
    "number" : "5.6.9",
    "build_hash" : "877a590",
    "build_date" : "2018-04-12T16:25:14.838Z",
    "build_snapshot" : false,
    "lucene_version" : "6.6.1"
  },
  "tagline" : "You Know, for Search"
}
* Curl_http_done: called premature == 0
* Connection #0 to host 172.28.116.165 left intact

Показывает 200, значит ОК.

 

select * from "AdminUnitFeatureState" where "FeatureId" in (select "Id" from "Feature" where "Code" = 'GlobalSearch' or "Code" = 'GlobalSearch_V2' or "Code" = 'GlobalSearchRelatedEntityIndexing')

Выдает что все "FeatureState" стоит "1". "GlobalSearch_V2" и "GlobalSearch" привязаны к "All employees" а "GlobalSearchRelatedEntityIndexing" к "Supervisor"

 

select * from "Feature" where "Code" = 'GlobalSearch' or "Code" = 'GlobalSearch_V2' or "Code" = 'GlobalSearchRelatedEntityIndexing'

Выводит все три "GlobalSearch_V2", "GlobalSearch" и "GlobalSearchRelatedEntityIndexing"

Алексей Следь,

Не помогло

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

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

Мотков Илья,

А где его взять? На сайте академии только 2.0 там и скачал на прошлой недели

В поддержке должна быть 2.0.2, если не новее.

Мотков Илья,

Если версия на сайте академии была не рабочей и не протестированной то зачем бы ее там выкладывали и так долго не заменяли на более новую?

Александр, если дело не в версии, то, вероятно, при установке что-то не так настроили.

Мотков Илья,

Спасибо, дело было в версии. Версия 2.0.0 не работала, поставил 2.0.2 и все работает теперь

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

Добрый день,

 

если я настроил синхронизация почты через Exchange(в Загружать почту из выбранных папок настроил несколько папок), то как я могу(в CRM) увидеть, из какой папке пришла данная письмо??

 

Нравится

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

Здравствуйте, Владимир!



На данный момент в приложении нет функционала по разграничению входящей почты по папкам (для удобства отображения).

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

 

Также, на Маркетплейс есть решение Email extension for Creatio, которое позволяет организовать почтовую корреспонденцию в отдельном разделе и обрабатывать как отдельные письма, так и группы писем. 

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

Коллеги добрый день!

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

Суть в том что кнопка нужна только на одной из страниц.

Код кнопки добавлен в схему этой страницы и в схему секции раздела.

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

Как можно красиво побороть?

Спасибо.

Нравится

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

Александр, речь о кнопке в реестре рядом со стандартными добавлением, копированием, удалением?

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

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

Александр, речь о кастомной кнопке внутри записи, справа от кнопки действий. Ну или внутри действий (так же только внутри записи).

Ваши ссылки изучу. Спасибо)

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