Здравствуйте, при выполнении процесса перевода продажи в заказ вылетает ошибка на переносе продуктов

"Terrasoft.Common.DbOperationException: Конфликт инструкции INSERT с ограничением FOREIGN KEY "FKPU5pFJW1zR5qrqXfCC4TQdQNI". Конфликт произошел в базе данных "BPMonline", таблица "dbo.Pricelist", column 'Id'."

Подскажите, с чем может быть связана эта ошибка.
Спасибо!

Нравится

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

Ошибка значит, что в поле Pricelist некоего продукта был записан Id, которого не существует в таблице прайс-листов. Наиболее частая ситуация: попадание в поле значения пустого Guid {00000000-0000-0000-0000-000000000000}.

 

Исходя из того, что вы переносите продукты из продажи в заказ, скорее всего произошёл такой сценарий: 

- у какого-то копируемого продукта не был проставлен прайс-лист;

- в результат выборки соответственно пришло значение {00000000-0000-0000-0000-000000000000};

- при создании нового продукта устанавливается полученное значение пустого Guid;

- при попытке сохранить запись возникает ошибка.

 

Чтобы избегать подобных ошибок, нужно перед установкой справочных полей проверять используемую переменную на значение Guid.Empty.

Ошибка значит, что в поле Pricelist некоего продукта был записан Id, которого не существует в таблице прайс-листов. Наиболее частая ситуация: попадание в поле значения пустого Guid {00000000-0000-0000-0000-000000000000}.

 

Исходя из того, что вы переносите продукты из продажи в заказ, скорее всего произошёл такой сценарий: 

- у какого-то копируемого продукта не был проставлен прайс-лист;

- в результат выборки соответственно пришло значение {00000000-0000-0000-0000-000000000000};

- при создании нового продукта устанавливается полученное значение пустого Guid;

- при попытке сохранить запись возникает ошибка.

 

Чтобы избегать подобных ошибок, нужно перед установкой справочных полей проверять используемую переменную на значение Guid.Empty.

Vyacheslav Lipatkin,

Спасибо, разобрался. В поле была установлена константа (id теперь уже несуществующего объекта).

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

Добрый день, Коллеги!
В Sales в разделе Заказы есть подбор продуктов. Стандартная логика позволяет в карточке контрагента в поле прайс-лист выбрать прайс-лист и тогда, при подборе товаров в заказ будет видна цена согласно этого прайс-листа. Система как-то пробрасывает его туда. Я бы хотел подменить эту логику на передачу туда прайс-листа из карточки самого заказа (я поле создал справочное). Где искать? Какой метод подменить или использовать?

Нравится

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

Прайс-лист из таблицы контрагента используется в С#-схеме AccountPriceListPicker (там обычный Select), её вызывает тоже С#-схема веб-сервиса PriceListService:

/// <summary>
/// Get Price List using account. Took from account, if there is no Price List,
/// then took it from partnership
/// </summary>
/// <param name="accountId">Account identifier.</param>
/// <returns>PriceList identifier</returns>
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
	ResponseFormat = WebMessageFormat.Json)]
public Guid GetPriceList(Guid accountId) {
	var priceListPicker = ClassFactory.Get<IPriceListPicker>(new ConstructorArgument("userConnection",
UserConnection));
	var	preSetPriceList = priceListPicker.GetPriceList(accountId);
	return preSetPriceList != default(Guid)
? preSetPriceList
: priceListPicker.GetPriceList(UserConnection.CurrentUser.AccountId);
}

А уже к нему обращаются из JS в странице заказа BaseOrderPage пакета Order:

/**
 * Sets predefined price list.
 * @protected
 * @virtual
 */
initializePredefinedPriceList: function() {
	if (this.isPredefinedPriceListsEnabled()) {
		this.$PredefinedPriceList = this.$Account && this.$Account.PriceList;
		if (this.isEmpty(this.$PredefinedPriceList)) {
			const config = this.getPriceListServiceConfig();
			this.callService(config, this.onPredefinedPriceListInitialized, this);
		}
	}
},
...
/**
 * Sets predefined price list.
 * @protected
 * @virtual
 */
initializePredefinedPriceList: function() {
	if (this.isPredefinedPriceListsEnabled()) {
		this.$PredefinedPriceList = this.$Account && this.$Account.PriceList;
		if (this.isEmpty(this.$PredefinedPriceList)) {
			const config = this.getPriceListServiceConfig();
			this.callService(config, this.onPredefinedPriceListInitialized, this);
		}
	}
},

 

 

Прайс-лист из таблицы контрагента используется в С#-схеме AccountPriceListPicker (там обычный Select), её вызывает тоже С#-схема веб-сервиса PriceListService:

/// <summary>
/// Get Price List using account. Took from account, if there is no Price List,
/// then took it from partnership
/// </summary>
/// <param name="accountId">Account identifier.</param>
/// <returns>PriceList identifier</returns>
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
	ResponseFormat = WebMessageFormat.Json)]
public Guid GetPriceList(Guid accountId) {
	var priceListPicker = ClassFactory.Get<IPriceListPicker>(new ConstructorArgument("userConnection",
UserConnection));
	var	preSetPriceList = priceListPicker.GetPriceList(accountId);
	return preSetPriceList != default(Guid)
? preSetPriceList
: priceListPicker.GetPriceList(UserConnection.CurrentUser.AccountId);
}

А уже к нему обращаются из JS в странице заказа BaseOrderPage пакета Order:

/**
 * Sets predefined price list.
 * @protected
 * @virtual
 */
initializePredefinedPriceList: function() {
	if (this.isPredefinedPriceListsEnabled()) {
		this.$PredefinedPriceList = this.$Account && this.$Account.PriceList;
		if (this.isEmpty(this.$PredefinedPriceList)) {
			const config = this.getPriceListServiceConfig();
			this.callService(config, this.onPredefinedPriceListInitialized, this);
		}
	}
},
...
/**
 * Sets predefined price list.
 * @protected
 * @virtual
 */
initializePredefinedPriceList: function() {
	if (this.isPredefinedPriceListsEnabled()) {
		this.$PredefinedPriceList = this.$Account && this.$Account.PriceList;
		if (this.isEmpty(this.$PredefinedPriceList)) {
			const config = this.getPriceListServiceConfig();
			this.callService(config, this.onPredefinedPriceListInitialized, this);
		}
	}
},

 

 

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

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

Нравится

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

Не знаю, насколько оптимален такой путь, но иногда я просто делаю VIEW с логикой внутри, затем регистрирую объект по этому VIEW, регистрирую деталь и уже использую на всю катушку.

Логика VIEW гораздо больше подаётся пониманию, к тому же её можно одновременно использовать в коде JS, в БП и в печатных формах.

Путь интересный.. а он возможен on-Demand? :) SqlExecutor позволяет создавать view?
На данный момент я разглядываю логику аналогичной детали с продажами, и пытаюсь понять ее логику, чтобы воспроизвести.. Но там как-то все нелинейно.. Подумаю насчет view.

"Шестаков Алексей Владимирович" написал:Путь интересный.. а он возможен on-Demand?

в bpm'online есть SQL-сценарии, которые позволяют в том числе создавать VIEW

Спасибо, такой вариант устраивает.

"Шестаков Алексей Владимирович" написал:SqlExecutor позволяет создавать view?

Он все позволяет, хоть drop :cool:

"Александр Кудряшов" написал:

Он все позволяет, хоть drop


А вот это уже настораживает :)

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

Здравствуйте.
При оформлении заказа, изменяя процентную ставку, к примеру, на 5% расчёт идёт только итоговой суммы. Однако, сама цена продукта остаётся неизменной.
Подскажите пожалуйста, как можно настроить систему, чтобы пересчёт так же осуществлялся и на саму цену продукта, а не только на итог?
Благодарю.

Нравится

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

Лучше сделать дополнительное поле "Цена с налогом", нежели менять саму цену

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

Лучше сделать дополнительное поле "Цена с налогом", нежели менять саму цену

Тогда для расчёта этой цены нужно будет создавать отдельный бизнес-процесс

"Ануфриев Дмитрий Юрьевич" написал:Тогда для расчёта этой цены нужно будет создавать отдельный бизнес-процесс

лучше прямо на странице считать, чтобы пользователь сразу при вводе видел изменение этой цены

"Владимир Соколов" написал:
Ануфриев Дмитрий Юрьевич пишет:

Тогда для расчёта этой цены нужно будет создавать отдельный бизнес-процесс

лучше прямо на странице считать, чтобы пользователь сразу при вводе видел изменение этой цены

Вы имеете в виду вручную менять?

"Ануфриев Дмитрий Юрьевич" написал:Вы имеете в виду вручную менять?

нет, java script надо написать

Привет всем!!!

я в своих конфигурациях везде исправил и ввел понятие Сумма, Налог, Сумма налога, Сумма без налога. Все как хотят бухгалтера, договорники, продажники. Чтобы торг-12, счет-фактуры формировались корректно. В отдельный модуль сам алгоритм конечно не выносил, хотя нужно уже сделать. А так если кому нужно могу стандартной логикой поделиться. Ничего сложного там нет.

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

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

Нравится

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

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

Из "дочернего" окна можно узнать, есть ли у него родительское:

Self.Attributes('NotifyObject')

Из "родительского" посчитать кол-во "дочерних" окон в коробке нельзя.
Но ничто Вам не мешает при нажатию на кнопку создания нового заказа записывать в атрибут окна "Звонок" окно "Заказа":

ZakazWindow.Prepare();
ZakazWindow.Show();
Self.Attributes('ChildForms').push(ZakazWindow);

где

Self.Attributes('ChildForms') = [];

Вроде бы получилось.
Используется аттрибут окна заказа PerformedForms
При открытии окна заказа
wndSandBurn = ShowEditWindowEx(EditWindowUSI, Attributes, DefaultValues);
присваивается +
wndSandBurn.Attributes('PerformedForms') ='+';
При закрытии окна заказа присваивается -
Self.Attributes('PerformedForms') = '-';
...
wnd_BaseDBEditOnCloseQuery(Window, CanClose);

В окне звонка со своими дочерними окнами можно связаться:

в wnd_CallEditScript
var Skolko = getPermission('wnd_OpportunityOrderEdit','wnd_CallEdit',Self.InstanceID);
if(Skolko > 0)
......

function getPermission(USI, USI2, RecordID) {
var Item;
for (var i = 0; i < WinCache_Windows.length; i++) {
Item = WinCache_Windows[i];
if (Item.USI == USI && Item.Instance.Attributes('NotifyObject').InstanceID == RecordID && Item.Instance.Attributes('PerformedForms') == '+')
return 1;

}
return 0;
}

Несколько модифицировав функцию, можно получать количество дочерних окон или конкретные данные из объекта.
Вопрос в чем: нет ли в таком подходе каких-то "подводных камней". При тестировании все нормально - окно видит свои дочерние окна и правильно реагирует, но мало ли...

Добрый день.

Сложно сказать. Такого функционала как сделали Вы в "коробке" нет, а значит он не тестировался.
Чисто визуально - вроде бы всё ок, проблем быть не должно.

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