Здравствуйте. Возникла небольшая задача, которую не удалось решить сразу.

Надо добавить в датасет контрагентов поле с общей суммой его договоров определенного типа.
Решал так -

1. В sq_Account добавил параметр с ID типа договора.
2. Сделал JOIN таблицы договоров по AccountID.
3. В фильтры добавил постоянно включенный "compare" фильтр на поле с ID типа договора таблицы из п.2. и параметра из п.1.
4. Добавил основную колонку, выбираюшую поле с суммой договора из таблицы п.2, c типом итога = Сумма.

Далее поле в датасете на эту колонку, и прочее. Рассчитывал в этом поле получить общую сумму контрагента по договорам определенного типа.

В итоге получаю общую сумму по всем договорам, то есть почему-то не отрабатывает фильтр из пункта 3. Подскажите, может я где в логике ошибся?

Нравится

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

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

Для этого лучше использовать вычисляемые поля - CalcDataFields.

Пример использования подобных полей можно посмотреть в скрипте датасета Инциденты

function ds_IncidentOnDatasetCalcFields

Алгоритм таков: в датасет добавляется вычисляемое поле. В функцию CalcDataFields добавляется расчет значения по полю:

dsContract = Services.GetSingleItemByUSI('ds_Contract');
ApplyDatasetFilter(dsContract, 'CustomerID', Self('ID'), true);
ApplyDatasetFilter(dsContract, 'ContractStatusID', '{--ID--}', true);
Dataset('сумма договоров') = CalculateActualSales(dsContract, 'BasicAmount');

Пример функции CalculateActualSales взят из ds_CampaignScript:

function CalculateActualSales(Dataset, CalculateByValue) {
	if (CalculateByValue == ccs_DontCalculate) {
		return;
	}
	var Summ = 0;
	var CampaignID = Dataset.ValAsGUID('ID');
	switch (CalculateByValue) {
		case (ccs_ByContracts):
			Summ = CalculateActualSalesByContracts(Dataset, CampaignID);
			break;
		case (ccs_ByInvoices):
			Summ = CalculateActualSalesByInvoices(Dataset, CampaignID);
			break;
		case (ccs_ByContractsInvoices):
			Summ = CalculateActualSalesByContracts(Dataset, CampaignID, true) +
				CalculateActualSalesByInvoices(Dataset, CampaignID)
			break;			
	}
	var ActualSales = GetFieldValueFromDisabledField(Dataset, 'ActualSales');
	if (ActualSales != Summ) {
		Dataset.Values('ActualSales') = Summ;
	}
	return Summ;
}

Фариз,
Ваш фильтр действительно отключается, причем принудительно. Происходит это в базовых скриптах перед открытием датасета реестра. Отключаются все фильтры, а включается только тот, который отвечает за выбранное представление (вверху реестра).
Чтобы обойти этот момент Анна предложила рабочий пример из конфигурации, который проводит вычисления с помощью механизма вычисляемых полей.
Однако можно пойти путем подсчета суммы именно в запросе на выборку, как Вы и хотели. Это предпочтительнее с двух причин - меньше кода в конфигурации (легче писать) и вычисления проводит сервер, а не процессор Вашего ПК.
Удалите join на таблицу договоров и созданный фильтр сравнения.
Вместо колонки с итогом создайте колонку подзапроса.
В ней делайте выборку из таблицы договоров, выбирая итог-сумму по требуемому полю.
Теперь самое главное - в блок условий колонки подзапроса необходимо добавить два фильтра сравнения: один - по типу договора, как Вы уже делали, а второй -- это фильтр-связка с главной таблицей tbl_Account. Он имеет вид tbl_Contract.AccountID = tbl_Account.ID. Его задача - отсекать те договора, которые не привязаны к текущей записи контрагентов, для которой происходит вычисление суммы.
Таким образом, для каждой записи контрагента в новом поле Вы получите сумму нужного показателя по определенному типу.
Если выберете такой вариант реализации и что-нибудь будет непонятно -- спрашивайте.
Удачи!

О как, это же намного инетреснее, так как вычисляемые поля не совсем юзабельны - сортировка и прочее. Я правда уже успел сделать по методу Анны с некоторыми доработками, но сейчас переделаю - спасибо!

Почти все вычисляемые поля можно сделать через колонки подзапроса (простой способ) или через поля типа SQL (если логика сложнее). В крайнем случае - вызвать предварительно созданную функицию базы данных (если уж очень запутанная логика). Таким образом ускоряется работа с клиентским приложением, потому что ему уже приходят вычисленные данные и он не тратит время на формирование вычисляемых колонок.
Я не говорю о том, что необходимо отказаться от вычисляемых полей, но для больших объемов данных или больших вычислений делать это на стороне сервера предпочтительнее.
Удачи!

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