Суть вопроса заключается в следующем.

Создан запрос:
Деталь 1 - Основная таблица Договор (одна запись, два поля)
Деталь 2 - Связная таблица Продукты в договоре (две записи, пять полей)

Рис.1. Вот что получается:

Рис.2. А вот как должно выглядить.

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

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

Вопрос
: Есть ли возможность добиться результата как на Рис.2 без применения FastReport?

Нравится

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

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

"Агутин Алексей" написал:Возможность есть, но придется попариться и вручную вставлять данные. Без изменения скриптов не обойтись.

*с интересом потирая ладоши*

А не подскажите что менять? или хотя бы какие скрипты содержат необходимые функции? Дело в том что мне проще один раз помучится со скриптами чем потом всему отделу продаж объяснять что есть Фастрепорт...

---
Конфигурация:
TSCRM 3.3.1.59
Firebird 2.0 (v.2.0.3.12981)

"Швец Александр" написал:*с интересом потирая ладоши*

приятно слышать.
Менять придется scr_UserReportCommon. Необходимо переписать ProcessWordSelection таким образом, что когда выделение устанавливается на нужной Вам метке(проверить что это именно та метка можно с помощью GetExpressionObject(Selection.Text)) вызывается функция, которая будет вставлять данные в необходимом формате.
Будьте внимательны, так как Вам придется менять базовую функцию.

function ProcessWordSelection(Selection, DocumentRange, RecordsCountObject,	WorkspaceWindow) {
	if (Selection.Tables.Count == 1) {
		if (EvaluateDetailExpression(Selection, DocumentRange, RecordsCountObject, WorkspaceWindow)) {	
			ProcessWordSelection(Selection, DocumentRange, RecordsCountObject, WorkspaceWindow);
		}	
	} else {
		Selection.Text = EvaluateRootExpression(Selection);
	}	
}
 
function EvaluateRootExpression(Selection) {
	var RootDataset = MSWordUserReport.RootDataset;
	var ExpressionObject = GetExpressionObject(Selection.Text);
	var Result = GetFieldValueByCaption(RootDataset, ExpressionObject.FieldName);
	if (IsEmptyValue(Result)) {
		Result = '';
	}
	return Result;
}
 
function EvaluateDetailExpression(Selection, DocumentRange, RecordsCountObject, WorkspaceWindow) {
	if (IsRootSectionTag(Selection, MSWordUserReport.RootDataset.Caption)) {
		Selection.Text = EvaluateRootExpression(Selection);
		return false;
	}
	var ExpressionObject = GetExpressionObject(Selection.Text);
	var DetailDataset = GetDetailDatasetByName(ExpressionObject.DatasetName);
	if (!Assigned(DetailDataset)) {
		return false;
	}
	if (DetailDataset.IsEmptyPage) {
		var Table = Selection.Tables.Item(1);
		var RowIndex = Selection.Rows.Item(1).Index;
		if (DetailDataset.Attributes('IsSummaryEnabled')) {
			if (Table.Rows.Count > RowIndex) {
				Table.Rows(RowIndex + 1).Delete();
			}
		}		
		Table.Rows(RowIndex).Delete();
		return false;	
	}
	return ProcessDetail(Selection, DetailDataset, DocumentRange, RecordsCountObject, WorkspaceWindow);
}

*спустя 3 часа размышлений оптимизм стал угасать*

"Агутин Алексей" написал:когда выделение устанавливается на нужной Вам метке(проверить что это именно та метка можно с помощью GetExpressionObject(Selection.Text)) вызывается функция, которая будет вставлять данные в необходимом формате.

Не могу понять как это практически реализовать...
Точнее что есть ExpressionObject? В SDK не нашёл...
По примеру выше вижу свойства DatasetName и DatafieldName.
Но что тогда должна содержать GetExpressionObject(Selection.Text)?

---
Конфигурация:
TSCRM 3.3.1.59
Firebird 2.0 (v.2.0.3.12981)

Как Вы правильно заметили, ExpressionObject - это объект у которого есть всего два поля DatasetName и DatafieldName. Таким образом Вы в тексте делаете метку вида <#MyLabel.First> (конкретный вид метки зависит от версии). Далее в ProcessWordSelection Вы делаете

function ProcessWordSelection(Selection, DocumentRange, RecordsCountObject,     WorkspaceWindow) {
        if (Selection.Tables.Count == 1) {
var TextLabel = GetExpressionObject(Selection.Text);
if (TextLabel.DatasetName == 'MyLabel'&&TextLabel.DatafieldName == 'First'){
DoSomething(Selection);
return;
}
                if (EvaluateDetailExpression(Selection, DocumentRange, RecordsCountObject, WorkspaceWindow)) {  
                        ProcessWordSelection(Selection, DocumentRange, RecordsCountObject, WorkspaceWindow);
                }       
        } else {
                Selection.Text = EvaluateRootExpression(Selection);
        }       
}

В функции DoSomething(Selection) Вы прописываете операции по необходимому добавлению данных.

Спасибо, с метками более менее стало понятно...

"Агутин Алексей" написал:В функции DoSomething(Selection) Вы прописываете операции по необходимому добавлению данных.

По аналогии с базовыми функциями написал свою, но не могу понять как она отличается от оригинала...

function DoSomething(Selection){
 var EO = GetExpressionObject(Selection.Text);
 var RootDataset = MSWordUserReport.RootDataset
 try {
 if (Dataset.State == dstInactive) {
     return null;
 }
 var DataFields = RootDataset.DataFields;
 var DField = null;
 for (var i=0;i<DataFields.Count;i++) {
   if(ReplaceDots(DataFields.Items(i).Caption) == EO.FieldName) {
   DField = DataFields.Items(i);
   break;
  }
 Selection.Text = DField.Value;
}
}

Перебор идёт по датасету пока не будет найдено поле = ExpressionObject.DatafieldName, после чего получается Value.
Но где же перебор по записям при количестве записей > 1?

Пройдясь отладчиком по функциям отвечающим за вывод в ворд...определил что, скорее всего для решения моей задачи, нужно переписать функцию ProcessDetail, которая как раз и отвечает за вывод детали при количестве записей больше 1ой.

На данный момент вывод проходит так:
Выводится первая запись Datafield`a вместо метки <#Деталь1.П>
"BBA in Hotel, Restaurant and Resort Management"

	Dataset.GotoFirst();
	var RowCount = Dataset.PageRecordsCount;
    PrepareDetailTable(Selection, RowCount);
	var StartIndex = Selection.Rows.Item(1).Index;
	var EndIndex = StartIndex + RowCount - 1;
	var NewIndex = StartIndex;
	var Table = Selection.Tables.Item(1);
	Table.ID = 'Proceed';
	var DataField = GetDataFieldFromTag(Selection, Dataset);
	debugger; 
	if (Assigned(DataField)) {
		var FieldValue = GetDataFieldValueByFieldType(DataField);
		if (IsEmptyValue(FieldValue)) {
			FieldValue = '';
		}
		Selection.Text = FieldValue;

Потом выводится вторая запись DataField`a вместо той же метки <#Деталь1.П>
"Foundation (16 weeks)"

while (DocumentRange.Find.Execute()) {
		DocumentRange.Select();
		if (Selection.Tables.Count == 0) {
			return true;
		}
		if (Selection.Tables.Item(1).ID != 'Proceed') {
			return true;
		}
		if (Selection.Rows.Item(1).Index > EndIndex) {
			break;
		}
		if (Selection.Rows.Item(1).Index > NewIndex) {
			Dataset.GotoNext();
			RecordsCountObject.ChildRecordNumber++;
			if (RecordsCountObject.ChildRecordNumber % 3 == 0) {
				UpdateProcessPosition(RecordsCountObject, WorkspaceWindow);
				if (RecordsCountObject.CancelledByUser) {
					return false;
				}
			}
			NewIndex = Selection.Rows.Item(1).Index;
			debugger;
		}
		DataField = GetDataFieldFromTag(Selection, Dataset); 
		if (Assigned(DataField)) {
			var FieldValue = GetDataFieldValueByFieldType(DataField);
			if (IsEmptyValue(FieldValue)) {
				FieldValue = '';
			}
			Selection.Text = FieldValue;
			debugger;	
		}

Для наглядности так же привожу шаблон отчёта:

Таблица(цы) "Программы обучения" должны отображать данные по каждой записи "Продукты в Договоре"...

Количество записей "Продукты в Договоре" должно соответствовать количеству

---
Конфигурация:
TSCRM 3.3.1.59
Firebird 2.0 (v.2.0.3.12981)

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