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

Столкнулся с такой незадачей.

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

Продукт "Вода питьевая негаз. 19 л" имеет прайс под названием "Клиентский" с ценой на продукт 100 руб.

Контрагенту создан персональный прайс по этому продукту на основе "Клиентского" прайса с дополнительной скидкой 20%.

При создании счета для этого клиента по этому продукту, мы видим, что продукт попадает в счет с учетом скидки 20% с итоговой суммой 80 руб.

Итоговая сумма счета также учитывает скидку 20% и равна 80 руб.

Однако, когда мы создаем по счету складской документ, то в него продукт из счета попадает с ценой не 80 руб, а с ценой 100 руб, т.е. скидка из продукта в счете игнорируется.

Сумма всей расходной накладной также равна 100 руб.

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

Оно конечно можно, руками исправить цену в складском документе, но поскольку доставка воды на дом - это "частые" продажи, то это придется делать слишком часто..

Я полез в код, генерирующий складской документ по счету (CreateBillPayment), но, как я понял, непосредственно копированием продуктов счета в продукты складского документа занимается процедура EnableDatasetFields, вызываемая из процедуры HaveOfferingsInInvoice.
Но изменить процедуру EnableDatasetFields так, чтобы она решила мою задачу и не нарушила функционирование остальной программы, я не не смог. Да и боязно курочить процедуры из скрипта scr_DB.

Подскажите, как лучше и с меньшей кровью решить мою проблему?

P.S. Terrasoft XRM Distribution 3.3.2.173

Нравится

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

Здравствуйте Егор!
Спасибо за подробное описание задачи.

"Егор Николаевич" написал:Однако, когда мы создаем по счету складской документ, то в него продукт из счета попадает с ценой не 80 руб, а с ценой 100 руб, т.е. скидка из продукта в счете игнорируется.

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

Я предлагаю следующий вариант решения. Доработаем карточку продукта в Складском документе (wnd_OfferingInMovementEdit). Сделаем привязку к полю Счет
1
Для реализации логики, необходимо внести изменения в скрипт wnd_OfferingInMovementEditScript , а именно в функцию UpdateValuesByOfferingID.
Изменения внесены между комментариев "//26.03.2012" .

function UpdateValuesByOfferingID(Dataset) {
 
	var OfferingID = Dataset('OfferingID');
	Dataset('UnitName') = GetOfferingFieldValue(OfferingID, 'DefaultUnit'); 
	var Quantity = Dataset.ValAsFloat('Quantity');
	if (!Quantity) {
		Dataset('Quantity') = GetOfferingFieldValue(OfferingID, 'UnitDivision');
	}
	var OfferingMovementTypeID = Self.Attributes('TypeID');	
	//26.03.2012
 
		if (!IsEmpty(Dataset('InvoiceID'))) {   //проверка заполнено ли поле Счет, если нет не выполняем действия
		var accountID = GetDatasetFieldValueByID('ds_Invoice',Dataset('InvoiceID'),'CustomerID')
		//открываем датасет Счетов, и получаем поле Клиент (это будет идентификатор контрагента)
		var PriceDataset = Services.GetNewItemByUSI('ds_AccountPrice');
		ApplyDatasetFilter(PriceDataset,'AccountID',accountID,true);
		//фильтруем таблицу детали Прайс-Лист контрагентов
		ApplyDatasetFilter(PriceDataset,'OfferingID',OfferingID,true);
		//фильтруем детать Прайс-Лист контрагентов по интересующему нас продукту 
		PriceDataset.Open();
		var discount = PriceDataset('DiscountPercent'); 		//получаем значение скидки
 
		Dataset('BasicPrice') = Dataset('BasicPrice')+ Dataset('BasicPrice') * discount/100 ;
		PriceDataset.Close();
 
		}	
	//26.03.2012
	if (OfferingMovementTypeID == omtReceipt) {
		Dataset('BasicPrice') = GetSupplierOfferingBasicPrice(
			Dataset('OfferingID'),
			Dataset('SupplierID'));
	}
	SetConsignmentID(Dataset);
}

После данных действий общая сумма расходной накладной, будет формироваться с учетом скидки.
Хочу заметить что функция UpdateValuesByOfferingID отрабатывает сразу после выбора продукта в карточке, т.е сначала необходимо будет выбрать счет, после чего сам продукт.

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

Здравствуйте, Алексей!
Алимова Анна подсказала еще одно решение.
Оно оставляет складской документ так же отвязанным от счета, как и в коробочной версии, учет скидки происходит при формировании складского документа по счету.

Изменяется в скрипте scr_InvoiceWorkspace функция CopyOfferingsFromInvoice, создающая складской документ по счету.
В строки, копирующие значения цены и стоимости, добавляется учет скидки:
OfferingInOMDataset('Price') = OfferingDataset('Price') * (1 - OfferingDataset('DiscountPercent')/100);
OfferingInOMDataset('BasicPrice') = OfferingDataset('BasicPrice') * (1 - OfferingDataset('DiscountPercent')/100);
OfferingInOMDataset('Amount') = OfferingDataset('Amount') * (1 - OfferingDataset('DiscountPercent')/100);
OfferingInOMDataset('BasicAmount') = OfferingDataset('BasicAmount') * (1 - OfferingDataset('DiscountPercent')/100);

Оба варианта решают задачу.
Спасибо!

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

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

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

Нравится

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

Здравствуйте,
Проверка на дубли проходит по нажатию кнопки Ок, в карточке счета
Код с в XRM 3.4.0.49

...
function btnOKOnClick(Control) {
var Dataset = dlData.Dataset;
var DefaultValues = GetAttribute(Self, 'DefaultValues');
/* MODULE WORKFLOW */
var WorkflowItemID = Dataset.ValAsStr('WorkflowItemID');
/* ENDMODULE WORKFLOW */
if (!CheckItemNumberDuplicate('Invoice', Dataset, 'InvoiceNumber',
"Счет")) {
return;
}

...

Предлагаю доработать функцию CheckItemNumberDuplicate с scr_CommonActions
1) Добавим в нее функцию сравнения года

function IsInvoiceSameYear(date_1,date_2)
{
var res1 = new Date(date_1).getFullYear();
var res2 = new Date(date_2).getFullYear();
if (res1 == res2)
return true;
else
return false;
}

2) Подредактируем CheckItemNumberDuplicate

function CheckItemNumberDuplicate(ItemName, Dataset, DataFieldName,
ItemCaption) {
var ParameterName = FormatStr('Check%1NumberDuplicates', ItemName);
var CheckDuplicates = GetSystemParameterValueEx(ParameterName, true);
var RecordID = Dataset.Values('ID');
if (CheckDuplicates) {
var Value = Dataset.Values(DataFieldName);
var TableName = FormatStr('tbl_%1', ItemName);
var FieldArray = new Array (DataFieldName, 'ID');
var ValuesArray = new Array (Value, RecordID);
var TypeArray = new Array (sdtUnicodeString, sdtIdentity);
var CompareOperatorTypeArray = new Array (cotEqual, cotNotEqual);
var DuplicatesRecordID = GetRecordIDByFilter(TableName, TypeArray,
FieldArray, ValuesArray, CompareOperatorTypeArray);
if (!IsEmptyValue(DuplicatesRecordID)){

if (ItemName == 'Invoice' && !IsEmpty(Dataset.Values('InvoiceDate')))
{
if ( IsInvoiceSameYear(Dataset.Values('InvoiceDate'),
GetDatasetFieldValuesByID('ds_Invoice',DuplicatesRecordID,'InvoiceDate').Item('InvoiceDate')))
{
var Message = FormatStr("%1 с номером %2 уже существует." + ' ' +
"Сохранить данную запись?", ItemCaption, Value);
Message = PrepareDialogMessage(Message);
return (ShowConfirmationDialog(Message) == wmrYes)
}
else
return true;
}
else

{
var Message = FormatStr("%1 с номером %2 уже существует." + ' ' +
"Сохранить данную запись?", ItemCaption, Value);
Message = PrepareDialogMessage(Message);
return (ShowConfirmationDialog(Message) == wmrYes)
}

}
}
return true;
}

Алексей, спасибо за помощь.

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

Не могли бы Вы помочь доработать этот вопрос.

Согласен, предлагаю следующий вариант
1)В scr_DB добавить функцию

function GetRecordsIDByFilter(TableName, TypeArray, FieldArray, ValueArray,
	CompareOperatorTypeArray){
	var Table = GetSingleItemByCode(TableName);
	var Query = CreateSelectQueryByTable(Table, TypeArray, FieldArray,
		ValueArray, CompareOperatorTypeArray); //получим все записи, (! не только первую)
	var Dataset = Query.Open();	
 
    var arrval = new Array();
 		Dataset.GotoFirst();
	while (!Dataset.IsEOF) {
		arrval.push(Dataset.Values('ID'));
		Dataset.GotoNext();		
		} 	
	Dataset.Close();
	return arrval;
}

2) В scr_CommonActions определить свою функцию CheckInvoiceNumberDuplicate, котороя есть по сути CheckItemNumberDuplicate с модифицированной проверкой

function CheckInvoiceNumberDuplicate(ItemName, Dataset, DataFieldName,
	ItemCaption) {
	var ParameterName = FormatStr('Check%1NumberDuplicates', ItemName);
	var CheckDuplicates = GetSystemParameterValueEx(ParameterName, true);
	var RecordID = Dataset.Values('ID');
	if (CheckDuplicates) {
		var Value = Dataset.Values(DataFieldName);
		var TableName = FormatStr('tbl_%1', ItemName);
		var FieldArray = new Array (DataFieldName, 'ID');
		var ValuesArray = new Array (Value, RecordID);
		var TypeArray = new Array (sdtUnicodeString, sdtIdentity);
		var CompareOperatorTypeArray = new Array (cotEqual, cotNotEqual);
		var DuplicatesRecordIDs = GetRecordsIDByFilter(TableName, TypeArray,
			FieldArray, ValuesArray, CompareOperatorTypeArray);
  		if (!IsEmptyValue(DuplicatesRecordIDs)){
 
		var showMessage = false;  		  		
 
  		if (ItemName == 'Invoice' && !IsEmpty(Dataset.Values('InvoiceDate')))
  		{
  		    for (var i = 0; i < DuplicatesRecordIDs.length; i++) 		  	  		  
  		    {
			var InvoiceDuplicID = DuplicatesRecordIDs[i];
 
			if (IsInvoiceSameYear(Dataset.Values('InvoiceDate'),
			GetDatasetFieldValuesByID('ds_Invoice',InvoiceDuplicID,'InvoiceDate').Item('InvoiceDate')))	
	        {
 
			var Message = FormatStr("%1 с номером %2 уже существует." + ' ' +
			"Сохранить данную запись?", ItemCaption, Value);
			Message = PrepareDialogMessage(Message);
			return (ShowConfirmationDialog(Message) == wmrYes)
		    }
 
			}
 
		}
 
		}
	}
	return true;
}

3) В скрипте карточки счета wnd_InvoiceEditScript вызывать CheckInvoiceNumberDuplicate вместо CheckItemNumberDuplicate

//  	if (!CheckItemNumberDuplicate('Invoice', Dataset, 'InvoiceNumber',
//	  	"Счет")) {
//	  	return;
//	}
  	if (!CheckInvoiceNumberDuplicate('Invoice', Dataset, 'InvoiceNumber',
	  	"Счет")) {
	  	return;
	}

4) Не забыть про IsInvoiceSameYear моего сообщения выше

Спасибо большое, Алексей, всё получилось.

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

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

Нравится

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

Здравствуйте, Максим.

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

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

Инна Безверхняя,
II линия службы поддержки Terrasoft

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

Коробочная версия XRM...

1) Пытаюсь распечатать один единственный счет, а вылезает целая распашёнка счетов.
Где поправить чтобы отчеты-счета были - только "для выбранных записей" ?

2) Кто-нибудь может поделиться отчетом -ТОРГ-12 (товарная накладная)? Во избежание изобретения велосипеда.

Спасибо!

Нравится

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

HELP!!! Работы стоит :cry:

Для того, чтобы отчет формировался для выделенных записей, необходимо в окне настроек отчета ([Инструменты] - [Отчеты]) установить значение в поле «Тип фильтрации» равным «Для выделенных записей».

Моя благодарность Вам... не когда бы не подумал, что там нужно искать =) Спасибо...

А ТОРГ-12 кто-нибудь поделится?)

Как подключить готовый FastReport-отчет читай здесь:
http://www.community.terrasoft.ru/forum/topic/4391

Качай разметку для ТОРГ-12 отсюда (там и другие унифицированные формы имеются):
http://www.reportingfor.info/ru/download.php?view.49

Fast Report Studio чтобы открыть скачанный шаблон здесь:
http://www.fast-report.com/ru/download/fast-report-studio-download.html

А выгруженный непосредственно из Terrsoft ТОРГ-12 (со всей требухой типа источников данных) к тебе в конфигурацию вряд ли встроится без проблем, ибо у всех разные конфигурации + каждый еще допиливает свою конфигурацию как хочет.

нужна разметка ТОРГ-12 для террасофта, у меня версия 3.3.1.31

Переонвертировать fr3 не получилось (нечем, программа с официального сайта фастрепорт не понимает fr3. Если у кого есть, прошу дать ТОРГ-12. Данные я уж как-нибудь привяжу, просто нужна разметка.

Разметка ТОРГ-12 в формате Terrasoft.
В данной разметке не предусмотрена корректная печать многостраничных отчетов.

"Егор Николаевич" написал:

Разметка ТОРГ-12 в формате Terrasoft.

В данной разметке не предусмотрена корректная печать многостраничных отчетов.

Прикрепленный файлРазмер

fr_reporttorg12.zip
8.76 кб

спасибо, то что надо

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

Возникла такая проблема при попытке выбора "проект/стадия/работа" в счете, договоре, операции возникает исключение: "несоответствие типа".
Версия: 3.3.2.116 XRM Professional Services + обновления сервисов для интеграции с 1С (131010)

Нравится

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

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

// wnd_ProjectDictionaryScript
 
function InitializeGridButtons() {
	var ProjectsfrmButtons = Projects.Window.ComponentsByName('frmButtons');
	ProjectsfrmButtons.IsVisible = Self.Attributes('ShowEditButtons'); // в этой стороке

Self.Attributes('ShowEditButtons') значение дебаггером посмотрите наверняка undefined или null попадает

Замените эту строчку на такую:

ProjectsfrmButtons.IsVisible = !!Self.Attributes('ShowEditButtons');
Показать все комментарии

Добрый день!
Подскажите пожалуйста как модифицировать функцию копирования продуктов при копировании счета таким образом чтобы не копировались определенные поля продукта(например стоимость).
Если я правильно понимаю следует модифицировать след. ф-цию, добавив проверку на имя поля:

function CopyTreeDetail(SourceDataset, DestinationDataset,
        SourceParentItemIDFieldName, DestinationParentItemIDFieldName,
        DestinationParentItemID) {
        SourceDataset.Open();
        if (IsDatasetEmpty(SourceDataset)) {
            SourceDataset.Close();
            return;
        }
        var ParentIDFieldName = 'ParentID';
        var DestinationID;
        var DestinationIDs = GetNewDictionary();
        var SourceID;
        var SourceParentID;
        var DestinationParentID;
        var SourceIDDataField = SourceDataset.DataFields('ID');
        var DestinationIDDataField = DestinationDataset.DataFields('ID');
        var SourceParentIDDataField = SourceDataset.DataFields(ParentIDFieldName);
        var DestinationParentIDDataField = DestinationDataset.DataFields(ParentIDFieldName);
        var DestinationParentItemIDDataField = DestinationDataset.DataFields(DestinationParentItemIDFieldName);
        var SourceParentIDs = GetNewDictionary();
        var ExcludedFieldsList = GetNewDictionary();
        ExcludedFieldsList('ID') = true;
        ExcludedFieldsList(SourceParentItemIDFieldName) = true;
        ExcludedFieldsList(ParentIDFieldName) = true;
        while (!SourceDataset.IsEOF) {
                SourceID = SourceIDDataField.Value;
                DestinationID = Connector.GenGUID();
                DestinationIDs(SourceID) = DestinationID;
                SourceParentID = SourceParentIDDataField.Value;
                SourceParentIDs(DestinationID) = SourceParentID;
                DestinationDataset.Append();
                CopyRowDataEx(SourceDataset, DestinationDataset, ExcludedFieldsList);
                DestinationIDDataField.Value = DestinationID;
                DestinationParentItemIDDataField.Value = DestinationParentItemID;
                DestinationDataset.Post();
                SourceDataset.GotoNext();
        }
        SourceDataset.Close();
        DestinationDataset.Close();
        ApplyDatasetFilter(DestinationDataset, DestinationParentItemIDFieldName,
                DestinationParentItemID, true);
    DestinationDataset.Open();
        while (!DestinationDataset.IsEOF) {
            DestinationID = DestinationIDDataField.Value;
                SourceParentID = SourceParentIDs(DestinationID);
                if (SourceParentID != null) {
                        DestinationParentID = DestinationIDs(SourceParentID);
                        DestinationDataset.Edit();
                        debugger;
                        DestinationParentIDDataField.Value = DestinationParentID;
                        DestinationDataset.Post();
                }
                DestinationDataset.GotoNext();
        }
        DestinationDataset.Close();
}

Но не могу разобрать где именно.
Версия 3.1.0.23
Заранее спасибо!

Нравится

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

Добавьте после блока

        ExcludedFieldsList('ID') = true;
        ExcludedFieldsList(SourceParentItemIDFieldName) = true;
        ExcludedFieldsList(ParentIDFieldName) = true;

такой код:

if (SourceDataset.USI.indexOf('ds_OfferingInInvoice') != -1) {
        ExcludedFieldsList(<Название поля1>) = true;
        ...
        ExcludedFieldsList(<Название поляN>) = true;
}

Спасибо!
А как запретить копирование поля в самом счете, например состояние счета, пробовал:

 if (SourceDataset.USI.indexOf('ds_Invoice') != -1) {
        ExcludedFieldsList('BillStatusID') = true;
     }

не прошло.
заранее спасибо!

Пробую в срипте scr_DB в функции:

function SetDefaultValuesByDataset(Dictionary, Dataset) {
	var DatasetCopy = Services.GetNewItemByUSI(Dataset.USI);
	ApplyDatasetFilter(DatasetCopy, 'ID', Dataset.ValAsStr('ID'), true);
	DatasetCopy.Open();
	for (var i = 0; i < DatasetCopy.DataFields.Count; i++) {
        var DataField = DatasetCopy.DataFields.Items(i);
 
	var Name = DataField.Name;
	if (!IsSystemField(Name) && (DataField.FieldType != dftCalc) && (DataField.Value != null)) {
	var Key = Name;
	Dictionary.Add(Key, DataField.Value);
			}
 
	}
	DatasetCopy.Close();
}

заменить

	if (!IsSystemField(Name) && (DataField.FieldType != dftCalc) && (DataField.Value != null))

на

	if (!IsSystemField(Name) && (DataField.FieldType != dftCalc) && (DataField.Value != null) && (DataField.Name != 'BillStatusID'))

но тоже не помогает (

Отвечу себе сам, нашел решение:

if (Name == 'BillStatusID'){
   Dictionary.Add(Key, null);
}
else{
   Dictionary.Add(Key, DataField.Value);
}
Показать все комментарии

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

Столкнулся с проблемой:

В разделе счета добавил новое поле, которое вычисляется путем вычитания из поля "сумма оплаты" поле "сумма в б.в."

Суть проблемы:

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

Подскажите куда копать?

ПС: Я этот вопрос задавал тех. поддержке, по e-mail, но они не отвечают. Входит ли такой вопрос в пакет тех. поддержки?

Нравится

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

"Михнюк Иван" написал:новое поле, которое вычисляется путем вычитания из поля "сумма оплаты" поле "сумма в б.в."

в скрипте датасета/карточки написали расчет значения?

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

см функцию function DataChange(DataField) в ds_InvoiceScript

Иван, добрый день.

Реализация зависит от того, каким образом Вы добавили поле: с помощью механизма пользовательских полей или вручную создали его в таблице, запросе и датасете раздела. Если Вы его создали с помощью механизма пользовательских полей или вручную как поле типа "Дробное число", изменять его значение необходимо при обработке события OnDatasetDataChange датасета раздела, или же при обработке аналогичного события в даталинке окна редактирования. Посмотрите, как это реализовано для других полей в скриптах ds_InvoiceScript и wnd_InvoiceEditScript.

Если Вы добавили это поле в датасет как вычисляемое, устанавливать ему значение необходимо при обработке события OnDatasetCalcFields. А вызвать это событие можно в том же обработчике OnDatasetDataChange при изменении полей, влияющих на Ваше поле. Например, так:

switch (FieldName) {
    ...
    case 'PaymentAmount':
        Dataset.CalcDataFields();
        break;
    ...
}

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

Я его создал вручную, как поле типа "дробное число".
В ds_InvoiceScript / DataChange(DataField) вписал:

case ('PaymentDiff'):
			InvoiceScript.OnDataChangeDisabled = true;
			try {				
		  	    var BA = DataFields.ItemsByName('BasicAmount').Value;
		  	    var PA = DataFields.ItemsByName('PaymentAmount').Value;
				var PaymentDiff = CalcPD(PA, BA);
				SetFloatDataFieldWithRound(DataFields.ItemsByName('PaymentDiff'),
					PaymentDiff);
			}
			finally{
				InvoiceScript.OnDataChangeDisabled = false;
			}
			break;  

В scr_CurrencyUtils вписал:

function CalcPD(PA, BA) {
	var Result = PA - BA;
	return Result;
}

Написал в scr_CurrencyUtils ():

function RecalcBPDInDataset (Dataset, BasicFieldName, PAFieldName,
	BAFieldName) {
	var BasicAmount = Dataset.Values(BAFieldName);
	var PaymentAmount = Dataset.Values(PAFieldName);
	var PaymentDiff = CalcPD(PA, BA);
	var DataField = Dataset.DataFields(BasicFieldName);
	SetFloatDataFieldWithRound(DataField, PaymentDiff);
}

Я делал по аналогии с другими полями и в

function SelfOnDatasetDataChange(DataField) {
	DataChange(DataField);
}

Ничего не дописано или я перемешал 2 варианта выше?

Немного не понял, где Вы используете функцию RecalcBPDInDataset. В остальном вроде всё нормально.

Аналогично нужно сделать и для поля BasicAmount, так как при его изменении поле PaymentDiff тоже должно изменяться.

"Лабьяк Олег Игоревич" написал:

Спасибо, натолкнули на ошибку, нужно было написать не case ('PaymentDiff'), а case ('PaymentAmount')! Функцию RecalcBPDInDataset наверно нигде не использую, просто в scr_CurrencyUtils () были ещё похожие функции, сделал по аналогии.

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

Добрый день.

Подскажите как сделать?

Скриншот карточки контрагента
first

Скриншот карточки счета
second

Скриншот выходной формы в Excel
third

Может уже кто реализовывал такую задачу.

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

Нравится

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

Создаете пользовательский запрос на выборку данных. По нему добавляете Word отчет, в шаблоне, которого прописываете в какие ячейки необходимо записывать данные.

Если я не ошибаюсь, то задача, как и написал Алексей, решается пользовательскими инструментами. А вот реквизиты я бы вынес в закладку, зачем в карточке реквизиты ;) ? Ведь у одной компании могут быть несколько компаний-плательщиков и, соответственно, реквизитов плательщиков.

А можно более подробно, я не проходил обучение данному продукту. Что-то мне понятно, но не все. Можете показать в картинках?

"Шевченко Юрий" написал:Ведь у одной компании могут быть несколько компаний-плательщиков и, соответственно, реквизитов плательщиков.

Директор сказал не нужно. В целом вы правы.

"Агутин Алексей" написал:Создаете пользовательский запрос на выборку данных. По нему добавляете Word отчет, в шаблоне, которого прописываете в какие ячейки необходимо записывать данные.

А есть статейка, как это делать?

"Синяев Валерий" написал:А есть статейка, как это делать?

Посмотрите тут
http://community.terrasoft.ua/usr/video_faq

[quote="Кулак Олег"]Посмотрите тут
http://community.terrasoft.ua/usr/video_faq[/quote]

Вы сами видели на, что даете ссылку. Это мне известно и доступно без видео инструкции. Я хочу получить выходную форму как в 1С 8.1. И меня интересует счет, а не отчет... :confused:

"Синяев Валерий" написал: И меня интересует счет, а не отчет...

Возможно я Вас не верно понял, но чем, указанная Вами печатная форма, отличается от отчета в Excel по текущему счету в Terrasoft? Либо вопрос вообще не в печатной форме?

Просто хочу понять как сделать такую печатную форму, принцип понятен. Но все же есть вопросы:

Для начала я захожу в Террасофт
Вкладка "Инструменты"
Скриншот

Следующие действие, это запрос


вот на этом этапе и много вопросов, мне нужно сделать в выходную форму данные, которые берутся разных таблиц

Вот это что означает? Из какого раздела?

"Синяев Валерий" написал:Вот это что означает? Из какого раздела?

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

Вот только я еще не могу открыть форму изменения шаблона.

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

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

"Кулак Олег" написал:Вот только я еще не могу открыть форму изменения шаблона.

Какая у Вас версия Terrasoft?

"Кулак Олег" написал:Какая у Вас версия Terrasoft?

3.2.0.56

"Кулак Олег" написал:Таблица счет связана с таблицей контрагенты(Клиент). Если Вы раскроете "плюс" на против данной таблице, то сможете вытянуть данные таблицы контрагенты.

Это я тормознул, понял уже и сделал. Нужно excel ставить так как ща на open-office работаю ща. У Террасофт идет привязка именно к библиотекам офиса.

"Синяев Валерий" написал:Это я тормознул, понял уже и сделал.

Т.е. вопросов по созданию запроса и соответствующего отчета нет?

Не совсем, завтра буду с утра трудится над этим. Хотелось бы все таки получить информацию от технической службы Террасофт. Мне просто не понятно как открыть редактор выходной формы.

nine

Вот так я создаю запрос
ten
Выбираем компоновку данных для запроса
eleven
Фильтры нужны?
twelve

После я перехожу на вкладу отчеты.

Но все тоже окно, выберите раздел

Что я делаю не так?

Я рекомендую Вам ознакомится с видео материалом, а именно "Как создать отчёт в Excel-формате на основе пользовательского запроса к базе данных Terrasoft CRM?". В нем рассмотрен пример создания пользовательского запроса и отчета на его основе.
И если Вы хотите видеть печатную форму конкретного счета, то стоит разместить отчет в разделе "Счета", если же вы хотите видеть все счета по конкретному контрагенту - в разделе "Контрагенты".

Олег я послушал вашего совета посмотрел материал еще вчера. Я просто указал вам пример. Я так понимаю сообщение "этот отчет можно просматривать только из раздела" выскакивает, потому что стоит тип фильтрации "Для выделенных записей". Подскажите как я могу его открыть данный отчет, с кажем для просмотра на определенном счете? И как я могу открыть редактор выходной формы, а открыть я ее не могу потому что не присвоен "сервис отчета" или к отчетам формируемым в excel нельзя задать выходную форму.

Просмотреть отчет Вы можете из раздела, который указали при создании отчета, при помощи меню "Отчеты". Но отчет построенный в Excel не будет соответствовать внешнему виду указанной Вами печатной формы. Если для Вас кретично использование Excel, то придется строить данную печатную форму в скрипте, используя ActiveXObject.

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

Дело в том, что у одного контрагента может быть несколько счетов,именно по данной причине рекомендуется делать отчет для раздела [Счета], а не [Контрагенты].

Если же необходимо создавать именно такую печтаную форму (как Вы указали на первом скриншоте), то мне кажется, что лучше сделать ее не средствами пользовательских отчетов, а в виде формы Fast Report.

Хорошо, сейчас займемся. И посмотрим. Техническая служба сказала тоже что и ваши последние сообщения

Для того чтобы создать отчет, нужный мне придется создать новый сервис. Так как при создании отчета fast reports, не возможности выбора ранее созданного мною запроса. Есть еще какие варианты?

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

"Синяев Валерий" написал:Так как при создании отчета fast reports, не возможности выбора ранее созданного мною запроса.

Запрос в клиентском приложении отличается от того запроса, sq_*, который создается в административной части приложения, на основании которого мы можем построить отчет Fast Report.

"Татьяна Адамчук" написал:
Запрос в клиентском приложении отличается от того запроса, sq_*, который создается в административной части приложения, на основании которого мы можем построить отчет Fast Report.

Какой выход? Можно пример, скорее всего уже решалась такая задача!

Валерий, так есть уже готовый запрос для отчета. Задача только или существующую форму отчет fr_ReportInvoiceWithNDS или fr_ReportInvoiceWithoutNDS задизайнить под Вашу форму (установить логотип, вытянуть нужные поля). Если тех полей в датасете не достаточно, чтобы решить задачу, то можете добавить в запросы и датасеты.

14

Подскажите, может я не туда смотрю?

Все разобрался пока, но вопросы все рано будут.

И прошу на заметку возьмите, что счет - это invoice. Но под этим понимается большое количество значений.

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

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

Поэтому было принято решение о рассылке уведомлений при поступлении оплаты по счету. Собственно, механизм следующий: если у счета меняется статус оплаты на "Оплачен" или "Оплачен частично", то отсылается уведомление. Уведомление отсылается либо ответственному по сделку, если счет прицеплен к сделке, либо ответственному по счету. Отсылка сделана по образу и подобию уведомлений, которые отсылаются при создании Задачи.

В скрипт wnd_InvoiceEditScript в функцию wnd_InvoiceEditOnPrepare в самый конец добавил строчку одну строку. Теперь эта функция выглядит вот так:

function wnd_InvoiceEditOnPrepare(Window) {

        Initialize(Window);
        wnd_BaseDBEditOnPrepare(Window);
/* MODULE WORKFLOW */
        var RequestFromWorkflow = false;
/* ENDMODULE WORKFLOW */
        InvoiceEdit.IsCompleting = false;
/* MODULE WORKFLOW */
        var DefaultValues = GetAttribute(Window, 'DefaultValues');
        var Dataset = BaseDBEdit.Dataset;
        if (Assigned(DefaultValues)) {
                // Post WorkflowItemID anyway because for this Invoice new
                // workflow item was created
                var NewWorkflowItemID = DefaultValues('WorkflowItemID');
                var RequestFromWorkflow = (!IsEmptyValue(NewWorkflowItemID));
                if ((RequestFromWorkflow) &&
                        (Dataset.Values('WorkflowItemID') != NewWorkflowItemID)) {
                        Dataset.Values('WorkflowItemID') = NewWorkflowItemID;
                        if (Dataset.State == dstEdit) {
                                Dataset.Post();
                                Dataset.Edit();
                        }
                }
        }
        if (RequestFromWorkflow && (Dataset.State == dstInsert)) {
                InvoiceEdit.CanCancel = false;
                dlData.Dataset.Values('BillStatusID') = null;
        } else {
                InvoiceEdit.CanCancel = true;
        }
        btnCancel.IsEnabled = InvoiceEdit.CanCancel;
/* ENDMODULE WORKFLOW */
        EnableNumberEdit();
    InvoiceEdit.BillStatusID = Dataset('BillStatusID');
}

Также были внесены изменения в функцию btnOKOnClick:

function btnOKOnClick(Control) {
        var Dataset = dlData.Dataset;
        var DefaultValues = GetAttribute(Self, 'DefaultValues');
/* MODULE WORKFLOW */
        var WorkflowItemID = Dataset.ValAsStr('WorkflowItemID');
/* ENDMODULE WORKFLOW */
        InvoiceEdit.IsCompleting = true;
        if (CheckItemNumberDuplicate('Invoice', Dataset, 'InvoiceNumber')){
                scr_BaseDBEdit.btnOKOnClick(Control);
        }
        Dataset.Open();
        var BillStatusID = Dataset('BillStatusID');
        if (!(InvoiceEdit.BillStatusID == BillStatusID)){
                if ((BillStatusID == GetInvoicePaidStatus())||
                        (BillStatusID == GetInvoicePartialPaidStatus())) {
                        var OpportunityID = Dataset('OpportunityID');
                        if (!IsEmptyGUID(OpportunityID)){
                                var ContactID = GetDatasetFieldValueByID('ds_Opportunity',OpportunityID,'OwnerID');
                        }else{
                            var ContactID = Dataset('OwnerID');
                        }
                        ProcessSendInvoiceEmailByContactID(Dataset, ContactID);
                }
        }
/* MODULE WORKFLOW */
        if (Self.IsVisible) {
                return;
        }
        ProcessWorkflowItem(WorkflowItemID);
/* ENDMODULE WORKFLOW */
}

Затем в скрипт scr_InvoiceUtils после строки
var InvoiceUtils = new Object();

была добавлена вот эта строка:
InvoiceUtils.PartialPaidStatusCode = 'PartialPaid';

А также был добавлен ряд функций:
function GetInvoicePartialPaidStatus() {
        if (IsEmptyGUID(InvoiceUtils.PaidStatusID)) {
                GetInvoiceStatusIDs();
        }
        return InvoiceUtils.PartialPaidStatusID;
}

function GetInvoiceNotifyMessageHTMLBody(Dataset) {
        var DataFields = Dataset.DataFields;
        var HTMLBody = '
\n'
;
        HTMLBody = HTMLBody + 'Вы получили данное уведомление об оплате счета, так как являетесь ответственным лицом.\n
'
;
        HTMLBody = HTMLBody + GetDatasetFieldHTMLView(DataFields.ItemsByName('InvoiceNumber')) + ' от ' + Dataset.ValAsStr('InvoiceDate') + '\n';
        HTMLBody = HTMLBody + '
\n'
;
        HTMLBody = HTMLBody + GetDatasetFieldHTMLView(DataFields.ItemsByName('OpportunityID')) + '\n';
        HTMLBody = HTMLBody + '
\n'
;
    HTMLBody = HTMLBody + '' + DataFields.ItemsByName('BasicAmount').Caption + ': ' + Dataset.ValAsStr('BasicAmount') + '\n';
        HTMLBody = HTMLBody + '
\n'
;
        HTMLBody = HTMLBody + GetDatasetFieldHTMLView(DataFields.ItemsByName('CustomerID')) + '\n';
        HTMLBody = HTMLBody + '
\n'
;
        HTMLBody = HTMLBody + GetDatasetFieldHTMLView(DataFields.ItemsByName('SupplierID')) + '\n';
        HTMLBody = HTMLBody + '

\n'
;
        HTMLBody = HTMLBody + GetDatasetFieldHTMLView(DataFields.ItemsByName('BillStatusID')) + '\n';
        HTMLBody = HTMLBody + '
\n'
;
    HTMLBody = HTMLBody + '' + DataFields.ItemsByName('PaymentAmount').Caption + ': ' + Dataset.ValAsStr('PaymentAmount') + '\n';
        HTMLBody = HTMLBody + '        ';
        HTMLBody = HTMLBody + GetDatasetFieldHTMLView(DataFields.ItemsByName('PaymentDate')) + '\n';
        HTMLBody = HTMLBody + '

\n'
;
        HTMLBody = HTMLBody + '\n';
        HTMLBody = HTMLBody + GetDatasetFieldHTMLView(DataFields.ItemsByName('ID')) + '\n';
        HTMLBody = HTMLBody + '

Нравится

Поделиться

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

Хороший вариант решения.

А мы - просто автоматически добавляем напоминания (оплачен или частично оплачен - ответственному за счет; счет готов к отгрузке товара со склада - ответственному за склад и т.д.)

--
www.it-sfera.com.ua
Terrasoft Solution Partner

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

Может быть создать динамическую папку, "счета, оплаченные сегодня(вчера, за последнюю неделю)"? Можно добавить соответствующее поле И (что-то типа - ознакомлен, не отработано и т.д.) С созданием соответствующих фильтров есс-но?

Динамические группы и так сделаны, правда без разбивки по времени, просто по статусу оплаты. Однако это тоже работает только когда сам заглядываешь в Террасофт. А уже создание дополнительных полей "Ознакомлен, не ознакомлен" это еще сложение. Кто будет менять значение этого поля? Лишний раз редактировать карточку.

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

Коллеги,
все зависит от регламентов работы менеджеров и их заинтересованности.
1) Поддерживаю динамические группы как инструмент. Любой уважающий себя менеджер начинает работу с просмотра оплат. Таким образом он открывает раздел и знает куда ему бежать.

2) Если менеджер пергружен или его он немотивирован на оплату счетов :) ( что вряд ли), тогда в помощь ему напоминания:
а) напоминания в Terrasoft - для всех пользователей системы,
б) если надо информировать и других сотрудников, то эффективнее e-mail рассылки.

Good luck in the life!

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

Почта - это личная напоминаловка по каждому событию.
Она пинает менеджера, что было событие, на которое надо обратить внимание.

Если же надо посмотреть ситуацию в целом, то группы помогают лучше.
Таким образом группы дополняют напоминания (любого способа).

Я бы сделал и то, и другое. Но начинал все же с динамических групп.

Good luck in the life!

"a.shekhovtsov" написал:Я бы сделал и то, и другое. Но начинал все же с динамических групп.

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

У нас упор сделан на оперативность работы. За состоянием счета следят постоянно, а не как у большинства компаний - "У нас выписки снимают только два раза в день и все". В таком случае менеджер может знать, что информация об оплате может появится только в четко оговоренное время. Это как бы работа по таймеру.
А у нас ближе к событийной системе. :) Не сидеть же менеджеру и через каждые 5 минут мониторить счета. Он тогда все свое время только на это будет тратить. А так, произошло событие "деньги от клиент", сразу же после этого все пошло в работу.

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

Good luck in the life!

"Барабанов Алексей Александрович" написал:А у нас ближе к событийной системе. :) Не сидеть же менеджеру и через каждые 5 минут мониторить счета.

Совершенно поддерживаю... а если менеджер в командировке и не имеет возможности запускать приложение и его средства комуникации ограничиваются телефоном и максимум нотбуком и тем же телефонным интернетом? В бою сапог надежнее(с) :-)))

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

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

Продолжая тему нашего решения для дистрибьюторов http://www.it-sfera.com.ua/ru/crm-reshenija/distribution/distribution-fu... ... :)

Представьте, что у Вас порядка 10 складов (или 5) по всей Украине... Ваш менеджер формирует счет клиенту, выбирает продукт и... проблема - как увидеть сколько доступно данного продукта на нашем, локальном складе (без лишних телодвижений по системе)?

А очень просто:

До новых встреч!

Нравится

Поделиться

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

Виталий, решения Вашей компании радуют все более и более!!!

Предложенный Вами вариант весьма хорош.
Маленький вопрос:
Отобразить "Склад магазина г.Львов" "1 013.0000" в гриде (реестре записей) не получиться?
Например, добавляя столбец "Доступно локально" и "Сумма локально".

Спасибо, Владимир!

"Присяжнюк Владимир" написал:Отобразить "Склад магазина г.Львов" "1 013.0000" в гриде (реестре записей) не получиться?
Например, добавляя столбец "Доступно локально" и "Сумма локально".

Пробовали и так :)
Не наилучший вариант (в смысле построения запроса к базе... к тому же веб-сервисы)
+ менеджеры хотят смотреть доступно и на других складах

--
www.it-sfera.com.ua
Terrasoft Solution Partner

А сделать внизу реестр в котором будут отображаться склады в которых есть товар с указанием кол-ва?

"Попов Александр" написал:А сделать внизу реестр в котором будут отображаться склады в которых есть товар с указанием кол-ва?

Можно, Отличный вариант! :)
Придется переделать стандартное окно выбора продукта...
Попробуем поэкспериментировать...

--
www.it-sfera.com.ua
Terrasoft Solution Partner

Хотя, Александр, есть один "минус" Вашей идеи...
Если, как в моем примере, больше 10 складов, тогда дополнительный реестр:

1. Отвлекает (менеджеры не любят лишней информации)
2. Лишние запросы на сервер

А так, он видит только свой склад (который устанавливается в его карточке), при необходимости выбирает альтернативный...

В разделе "Продукты" мы добавили деталь "Доступно", где отображается именно так, как Вы предлагаете...

--
www.it-sfera.com.ua
Terrasoft Solution Partner

Можно сделать галочку - отображать все или "свой".

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

Для этого можно в нижней части окна, под реестром Продуктов, сделать 2 закладки: "Доступно на складе" и "Все склады".

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

Можно...
Но, посоветовался с нашим Клиентом - оставляем так :)

--
www.it-sfera.com.ua
Terrasoft Solution Partner

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