Публикация

Коллеги здравствуйте! Записали видео-презентацию возможностей нашего продукта

"Storekeeper for bpm`online"

Кратко о решении

Автоматизация учета товара на складе с функционалом CRM системы. В одной базе удобно вести учет лидов, клиентов, заявок, и отгрузок.

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

Узнайте в небольшом видео-обзоре основные возможности системы для управления товарооборотом компании. 

https://youtu.be/9PbfU70fhK0 

 

Поделиться

0 комментариев
Войдите или зарегистрируйтесь, чтобы комментировать
Вопрос

Добрый день!

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

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

 

У меня такой же вопрос

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

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

Таким образом вы сможете видеть, кто когда что изменил. Ну например на складе остаток по товару был 100, сегодня 80, завтра будет 60. 
И вы эту динамику сможете посмотреть в отдельной детали в разделе.

 

Ну или если вас не устраивает дополнение, можно создать деталь с полями.

Дата изменения, кол-во на складе. Ну и т.д. и заполнять данную деталь через БП стартом которого будет изменение раздела. 

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

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

В карточке продукта есть закладка "Движение по складу" и у меня она не работает.
Я закрыла периоды, выбираю наиболее активный из всех и продукт, который точно был отгружён\куплен в тот же период.
Вопрос как наконец увидеть этот график?(

У меня такой же вопрос

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

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

Здравствуйте, Наталия!

Посмотрите, пожалуйста, условия отображения той или иной линии графика в соответствии с данными в Вашей системе.

Информация описана в разделе 3.5.2 на с.191-192:
http://tsrdp.tscrm.com/support/downloads/manuals/TS_XRMDistribution_UG_…

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

Здравствуйте, Наталия.

Есть предположение, что в Вашей версии допущена ошибка.

Попробуйте сделать резервную копию сервиса Offerings\Details\Analytic\sq_OfferingAnalytic из конфигурации, а затем поверх него загрузить обновленный сервис из архива во вложении.

Сообщите, пожалуйста, результат.

sq_offeringanalytic.zip

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

Добрый день, уважаемое сообщество.
Проявилась такая проблема в этом году. Возможно связано с большим количеством записей в базе данных. Но не факт.
Описание:
Terrasoft XRM 3.3.2.304.
Существует несколько расходных накладных.
Скрипт вызывает стандартную функцию ConductSelectedOfferingMovements:
В Data.OfferingMovementIDs передается массив ID складских документов.

                Data.IsRecalcPrimeCost = false;
                Data.IsConduct = true;
                Data.OfferingMovementStatus = omsCompleted;
                Data.IsRecalcOfferingPrices = false;
                Data.IsUpdateShipmentState = false;
                Data.IsUpdatePurchaseState = false;
                Data.IsReserveOfferingsFromOrders=false;
                Data.IsAddSupplierInOffering = false;
                var Result = ConductSelectedOfferingMovements(Data);

Все выполняется правильно, но пока идет выполнение этой функции на одном из рабочих мест, у других пользователей, работающих с разделами Склад (деталь Продукты)
или Продукты(деталь Складские документы), появляется ошибка "Ошибка открытия источника данных ds_MovementInOffering. Превышено время ожидания запроса на блокировку".
Изменений в функцию и хранимые процедуры не вносили.
Ошибка повторяется на 100 процентов.
Во время выполнения хранимой процедуры ошибка открытия может быть и для ds_Account и других
источников данных.
Сталкивался ли кто-нибудь с такой проблемой и в чем ее причина?

У меня такой же вопрос

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

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

Максим, добрый день.
Мы тут примерно в эту сторону и копаем. Похоже ХП блокирует tbl_MovementInOM. Мы убрали подзапросы в разделах и деталях, которые ее использовали. Но в том же ds_Offering поле Remain это подзапрос к этой таблице. Отсюда и ошибки.
По индексации: я правильно понимаю, что нужно добиваться того, чтобы ХП быстрее обрабатывала блокируемую таблицу?

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

Возможно, эти статьи будут полезными:
http://technet.microsoft.com/ru-ru/library/ms189081.aspx
http://samag.ru/archive/article/797

Во время выполнения ХП закрытия документа SQL сервер грузит процессор на 100%. Это нормально?

Виктор, видимо обработка больших данных несет большую нагрузку. Может быть мощности не хватает.
Как долго выполняется хранимка?

Проверял на тестовой базе.
Всего в этой базе 87 складских документов, т.е. нет больших данных на мой взгляд. Выполняется закрытие практически мгновенно. Но делаем закрытие в цикле нескольких расходных, и на это время загрузка процессора 100%.
И еще один момент. К моей радости он пока проявляется только на тестовом сервере. Любая конфигурация от самых старых до текущей копии рабочей базы. Закрытие документа с недостаточным количеством продукта в остатках(т.е. остаток 100, а списываю 101) приводит не к сообщению о недостаточном количестве, а полностью вешает клиента. Процессор на сервере загружен на 100%, пока аварийно не завершу клиента. Часами я конечно не ждал результата. Думаю, что-то с SQL сервером (2008). Будем разбираться.
С другой стороны анализируем ХП, чтобы понять в каком месте мы зависаем.

Новые данные. Виснет если по продукту указан метод списания Средневзвешенный и есть несколько приходов по ним.
зацикливается в tsp_OfferingDistribute
не может закончится цикл:

while (@ARemainQuantity >= @AUnitDivision)
begin
	OPEN Consignment_Cursor
	FETCH NEXT FROM Consignment_Cursor INTO @ConsignmentID, @ConsignmentQuantity
	WHILE @@FETCH_STATUS = 0
	BEGIN
		if (@ARemainQuantity < @AUnitDivision) 
			break
		update #ListQuantity 
		set Quantity=Quantity + @AUnitDivision 
		where ConsignmentID=@ConsignmentID
			and Quantity < @ConsignmentQuantity
		if (@@ROWCOUNT > 0) 
			set @ARemainQuantity = @ARemainQuantity - @AUnitDivision
		FETCH NEXT FROM Consignment_Cursor INTO @ConsignmentID, @ConsignmentQuantity
	END
	CLOSE Consignment_Cursor
end

Похоже выяснили причину зависания.
Пример:
Два прихода по продукту с количествами 1000 и 100.
Проводим.
Расходная с количеством 3500.
Зависание.
Дело в том что 3500 делится на части пропорционально остаткам по партиям.
Т.е получаем 3181,818 и 318,1818. И если правильно округлить, то 3182 и 318, что в сумме даст 3500.

Причина в ХП tsp_RoughOfferingDistribute

DECLARE Consignment_Cursor CURSOR FOR
....
 
WHILE @@FETCH_STATUS = 0
BEGIN
	....
	set @PartQuantity = floor(@PartQuantity / @AUnitDivision) * @AUnitDivision;
	insert into #ListQuantity 
		(ConsignmentID, Quantity, BasicPrice, ConsignmentQuantity) 
	values 
		(@ConsignmentID, @PartQuantity, @BasicPrice, @ConsignmentQuantity)
	set @RemainQuantity = @RemainQuantity - @PartQuantity;
	FETCH NEXT FROM Consignment_Cursor INTO @ConsignmentQuantity, @ConsignmentID, @BasicPrice
 
END
CLOSE Consignment_Cursor
DEALLOCATE Consignment_Cursor

Таким образом floor отбрасывает дробную часть и мы получаем в ListQuantity 3181, 318 и 1. А вот эта единичка и зацикливает tsp_OfferingDistribute, т.к. значений три, а партий только две.

меняем floor на round и все работает

set @PartQuantity = round((@PartQuantity / @AUnitDivision),0) * @AUnitDivision;

В любом случае по методу Средневзвешенный списание происходит неверно и возникают неверные остатки. Поэтому видимо сменим метод.

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

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

Господа!
Вопрос по резервам Продуктов на Cкладе:

  1. Кто как организует: А) хранение в таблицах, Б) просмотр доступных товаров и В) контроль резервирования продуктов?

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

    В голове плавают способа четыре реализации, но у каждого свои минусы. — но, повторюсь, кто что посоветует?

  2. Кстати, а кто знает, что и как используют наши коллеги в различных WMS (Warehouse management system)?

P.P.S. Вопрос безотносительный к версии продукта, но конкретно интересует XRM или XRM Distribution
P.P.P.S. Есть, кстати, у клиента и несколько критериев использования, чуть позже попробую адаптировать для форума и кинуть.

У меня такой же вопрос

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

Добрый день, Глеб.

В TS_XRM резервов нет. Но они реализованы в базовой версии TS_XRM_Disctribution.
Реализована служебная табличка tbl_ReservedOffering, в которой хранятся идентификаторы зарезервированного продукта, количество и прочая необходимая информация.
Отследить резерв можно в композитной детали Продукт_в_Счете (версия 3.4.1+) или выводя в реестр раздела продуктов колонку Зарезервировано.
Также, есть системная настройка "Период резервирования продукта", в которой указывается количество дней, после которых резерв снимается.

"Maxim Gritsenko" написал:

В TS_XRM резервов нет. Но они реализованы в базовой версии TS_XRM_Disctribution.
Реализована служебная табличка tbl_ReservedOffering, в которой хранятся идентификаторы зарезервированного продукта, количество и прочая необходимая информация.
Отследить резерв можно в композитной детали Продукт_в_Счете (версия 3.4.1+) или выводя в реестр раздела продуктов колонку Зарезервировано.

Да, Максим, сталкивался в версиях 3.3.х с данной конфигурацией от IT-СФЕРА, но кажется, по складу был ряд несовершенностей.

Поясните, если не трудно, а как поведет себя данная система (XRM Distribution)
в следующих кейсах:

1) Уменьшение перечня/кол-ва товара:
1. Продукт "А" в Документе, 10 шт.
2. Резервируем. (Резерв "А" = 10 шт.)
3. Продукт "А" в Документе, уменьшаем до 9 шт.
4. Резервируем.
ВОПРОС: Резерв "А" будет "10 шт." или "9 шт."?

2) Дробление резерва
1. Продукт "Б" в Документе, 10 ед.
2. Резервируем. (Резерв "Б" = 10 ед.)
3. Продукт "Б" в Документе, увеличиваем до 12 ед.
4. Резервируем.
ВОПРОС: Резерв "Б" будет из двух записей (=10 ед. и =2 ед.) или одной (= 12 ед.)?

Кстати, коллеги из ИТ-Сферы, тоже подключайтесь к обсуждению! :wink:

Глеб, доброе утро.

Вертикаль XRM Distribution разработана компанией Terrasoft ;)

Вопрос 1: Резерв будет уменьшен на единицу при уменьшении количества продукта в счете/договоре/продукте (не документе).

Вопрос 2: Резерв будет из двух записей.

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

Отправил вопрос в службу поддержки. Дублирую вопрос здесь.
-----------------------------------------------------------------------------------------------
Речь пойдет о разделе Склад (накладные).

В скрипте ds_OfferingMovementScript
в обработчке
ds_OfferingMovementOnDatasetBeforePost(Dataset, DoPost)
есть строки
if (!ConductOfferingMovements(Dataset)) {
DoPost.Value = false;
}

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

С другой стороны, в этом же скрипте есть обработчик

function ds_OfferingMovementOnDatasetAfterPost(Dataset) {
GiveRightsToRecordOwner(Dataset);
var StatusID = Dataset('StatusID');
SaveMovements(Dataset, StatusID);
if (OfferingMovementScript.DoRecalc) {
RecalcOfferingInMovementPrices(OfferingMovementScript.ID,
OfferingMovementScript.Rate);
}
}

Функция SaveMovements(Dataset, StatusID) в свою очередь вызывает
RemoveOfferingReserve(OfferingMovementDataset, true), которая делает
точно то же, что и хранимая процедура tsp_RemoveOfferingReserve.

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

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

У меня такой же вопрос

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

Тоже очень интересует этот вопрос.

Добрый день, коллеги!

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

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

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

Расммотрим что происходит при проведении расходной накладной.
Для этого подготоимся следующим образом:
1) Создадим складской документ на закрытие.
3) Запустим MS Visual Studio и подключимся к окну проведения документа.
4) Нажмем кнопку ОК на окне закрытия документа

По клику на ОК в OfferingMovement\General\Main Grid\wnd_OfferingMovementCloseScript отправляется уведомление реестру OfferingMovement\General\Main Grid\wnd_OfferingMovementGridArea

Данное уведомление обрабатывается по событию wnd_OfferingMovementGridAreaOnNotify условие:

	if ((Message == MSG_OK) && 
		(SenderUSI == 'wnd_OfferingMovementClose')) {
		CloseOfferingMovement(Data);
		return;
	}

Что происходит в function CloseOfferingMovement(Data) вызывается ConductSelectedOfferingMovements(Data).

В ConductSelectedOfferingMovements собирается CustomQuery
В случае его успешное выполнения (в scr_MovementUtils) возвращаем true;

		var Result = CustomQuery.Execute();
		if (Result < 0) {
			return false;
		}
		return true;

Получатель - OfferingMovement\General\Main Grid\wnd_OfferingMovementGridAreaScript
В случае True действия по блоку условия:

	if (SelectedIDs.Count == 1) {
		dlData.Dataset.RefreshRecord(SelectedIDs[0], true);
	} else {
		RefreshDatasetAndRestorePosition(dlData.Dataset)
	}

Затем возвращаемся к обработчику SendNotify и проверяем кого нам еще оповестить:

var NotifyObjectList = Window.Attributes('NotifyObjectList');
if (!NotifyObjectList) {
return;
}

Если все выше сказанное и вывполненное вернуло True - NotifyObjectList = null;

Возвращаемся в wnd_OfferingMovementCloseScript на Self.Close();
Окно закрывается, документ проведен.

ds_OfferingMovementScript
--------------------------------------
function ds_OfferingMovementOnDatasetBeforePost(Dataset, DoPost) {
	SetItemSystemNumber('OfferingMovement', Dataset, 'Number');
	OfferingMovementScript.TypeID = 
		Dataset.DataFields.ItemsByName('TypeID').OldValue;
	OfferingMovementScript.StatusID =
		Dataset.DataFields.ItemsByName('StatusID').OldValue;
	OfferingMovementScript.OfferingID = 
		Dataset.DataFields.ItemsByName('OfferingID').OldValue;
 
	if ((Dataset('TypeID') != omtComplete) &&
		(Dataset('TypeID') != omtDecomplete)) {
		Dataset('OfferingID') = null;
		Dataset('Quantity') = null;
		Dataset('UnitID') = null;
		Dataset('ConsignmentID') = null;
	}
	if (!ConductOfferingMovements(Dataset)) {</strong>
		DoPost.Value = false;
       /*
Если я даже изменю в карточке накладной валюту, вызовется метод СonductOfferingMovements(Dataset),
который проведет накладную точно так же, как если бы я нажал на кнопку "Закрыть"
 
Почему и зачем?! 
*/
	}
	OfferingMovementScript.DoRecalc = (Dataset.DataFields('CurrencyRate').OldValue != Dataset.DataFields('CurrencyRate').Value);
	if (OfferingMovementScript.DoRecalc) {
		OfferingMovementScript.ID = Dataset('ID');
		OfferingMovementScript.Rate = CalcBasicPrice(1, Dataset('CurrencyID'), Dataset('CurrencyRate'));
	}
}

Далее

function ds_OfferingMovementOnDatasetAfterPost(Dataset) {
	GiveRightsToRecordOwner(Dataset);
	var StatusID = Dataset('StatusID');
	SaveMovements(Dataset, StatusID);
	if (OfferingMovementScript.DoRecalc) {
		RecalcOfferingInMovementPrices(OfferingMovementScript.ID, OfferingMovementScript.Rate);
	}
}
 
function SaveMovements(OfferingMovementDataset, StatusID) {
	var OfferingMovementID = OfferingMovementDataset('ID');
	if (GetIsMovementEnable(StatusID)) {
		ApplyAddMovements(OfferingMovementID);			
		RemoveOfferingReserve(OfferingMovementDataset, false);
	} else {
		ApplyDeleteMovements(OfferingMovementID);
		RemoveOfferingReserve(OfferingMovementDataset, true);
	}
}

RemoveOfferingReserve вызывается каждый раз, после изменения датасета.

Таким образом, при изменении датасета, НЕ при нажатии на кнопку "Закрыть" мы получаем вызов хранимой процедуры (как минимум одной из Custom Query ) и вызов RemoveOfferingReserve из скрипта и все это друг за другом.

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

"Фильковский Павел" написал:
RemoveOfferingReserve отрабатывает запись скалдского документа, но не затрагивает резервы.

Вы не правы:

function RemoveOfferingReserve(OfferingMovementDataset, IsRollback) {
	var TypeID = GetDatasetFieldValue(OfferingMovementDataset, 'TypeID');
	switch (TypeID) {
	case omtMove:
		MoveReservedOfferings(OfferingMovementDataset, IsRollback);
		break;
	case omtShipment:
	case omtBillPayment:
		ShipmentReservedOfferings(OfferingMovementDataset);
		break;
	}
}
 
function ShipmentReservedOfferings(OfferingMovementDataset) {
	var TypeID = GetDatasetFieldValue(OfferingMovementDataset, 'TypeID');
 
	if ((TypeID != omtShipment) && (TypeID != omtBillPayment)) {
		return;
	}
 
	var OfferingMovementID = OfferingMovementDataset('ID');
	var StoreID = GetDatasetFieldValue(OfferingMovementDataset, 'StoreID');
	var OfferingID;
	var DocumentID;
	var ContractID;
	var InvoiceID;
	var ReservedQuantity;
	var Quantity;
 
	var OfferingInMovementDataset = 
		GetSingleItemByCode('ds_OfferingInMovement', 'MovementUtils');
	ApplyDatasetFilter(OfferingInMovementDataset, 'OfferingMovementID', 
		OfferingMovementID, true);
	OfferingInMovementDataset.Open();
	try {
		var ReservedOfferingDataset = GetSingleItemByCode('ds_ReservedOffering', 
			'CheckReservedProducts');
..........................................................................
ReservedOfferingDataset.Open();
            try {
            	ReservedQuantity = 
					ReservedOfferingDataset.ValAsFloat('Quantity');
				Quantity = 
					OfferingInMovementDataset.ValAsFloat('Quantity');
            	if (ReservedQuantity <= Quantity) {
            		ReservedOfferingDataset.Delete();
            	} else {
            		ReservedOfferingDataset.Edit();
            		ReservedOfferingDataset('Quantity') = 
						ReservedQuantity - Quantity;
					ReservedOfferingDataset.Post();
            	}
            } finally {
            	ReservedOfferingDataset.Close();
            }
..............................................................
ALTER  procedure [dbo].[tsp_RemoveOfferingReserve] 
	@AOfferingMovementID uniqueidentifier,
  @ATypeID uniqueidentifier,
  @AStoreID uniqueidentifier,
  @AStoreRecipientID uniqueidentifier,
  @AMoveBack int,
  @AUserID uniqueidentifier
as
begin
  set XACT_ABORT on
  set NOCOUNT on
 
  declare @Result int
  set @Result = 0;
  if (@ATypeID = '{D2B35B4E-571C-44A7-87AB-456A1F4D1C2D}') -- omtMove
  begin
    exec @Result = tsp_MoveReservedOfferings
	    @AOfferingMovementID = @AOfferingMovementID,
      @ATypeID = @ATypeID,
      @AStoreID = @AStoreID,
      @AStoreRecipientID = @AStoreRecipientID,
      @AMoveBack = @AMoveBack,
      @AUserID = @AUserID
  end else
  if (@ATypeID IN ('{A48368CD-E28D-458D-8AE8-E2A314186C5C}',   /*omtShipment*/ 
                   '{F6E5A2E6-A2D6-4C2F-99A7-7FEE75FF76F6}'))  /*omtBillPayment*/ 
  begin
    exec @Result = tsp_ShipmentReservedOfferings
	    @AOfferingMovementID = @AOfferingMovementID,
      @ATypeID = @ATypeID,
      @AStoreID = @AStoreID,
      @AUserID = @AUserID  
  end
 
  return (@Result)
end
GO
 
 
 
ALTER procedure [dbo].[tsp_ShipmentReservedOfferings] 
	@AOfferingMovementID uniqueidentifier,
  @ATypeID uniqueidentifier,
  @AStoreID uniqueidentifier,
  @AUserID uniqueidentifier
as
begin
  set XACT_ABORT on
  set NOCOUNT on
 
  if (not @ATypeID IN ('{A48368CD-E28D-458D-8AE8-E2A314186C5C}',   /*omtShipment*/ 
                       '{F6E5A2E6-A2D6-4C2F-99A7-7FEE75FF76F6}'))  /*omtBillPayment*/ 
  begin
    return (-1)
  end  
 
  declare @OfferingID uniqueidentifier
  declare @DocumentID uniqueidentifier
  declare @ContractID uniqueidentifier
  declare @InvoiceID uniqueidentifier
  declare @Quantity decimal(15,4)
  declare @ReservedQuantity decimal(15,4)
 
  declare OM_Cursor cursor for
  select
    [tbl_OfferingInMovement].[OfferingID],
    [tbl_OfferingInMovement].[DocumentID],
    [tbl_OfferingInMovement].[ContractID],
    [tbl_OfferingInMovement].[InvoiceID],
    [tbl_OfferingInMovement].[Quantity]
  from
	  [dbo].[tbl_OfferingInMovement] AS [tbl_OfferingInMovement]
  where [tbl_OfferingInMovement].[OfferingMovementID] = @AOfferingMovementID
 
  open OM_Cursor
  fetch next from OM_Cursor
  into @OfferingID, @DocumentID, @ContractID, @InvoiceID, @Quantity
  while @@fetch_status = 0
  begin            
    if (@DocumentID is null and @ContractID is null and @InvoiceID is null) 
    begin
      fetch next from OM_Cursor
      into @OfferingID, @DocumentID, @ContractID, @InvoiceID, @Quantity
      continue
    end    
 
    select
      @ReservedQuantity = isnull([tbl_ReservedOffering].[Quantity], 0)
    from
	    [dbo].[tbl_ReservedOffering] AS [tbl_ReservedOffering]
    where ([tbl_ReservedOffering].[OfferingID] = @OfferingID)
      and ([tbl_ReservedOffering].[ExpirationDate] >= getdate())
      and ([tbl_ReservedOffering].[DocumentID] = @DocumentID or @DocumentID is null)
      and ([tbl_ReservedOffering].[ContractID] = @ContractID or @ContractID is null)
      and ([tbl_ReservedOffering].[InvoiceID] = @InvoiceID or @InvoiceID is null)
      and ([tbl_ReservedOffering].[StoreID] = @AStoreID or @AStoreID is null)
    if (@@rowcount = 0)
    begin
     set @ReservedQuantity = 0
    end
 
    if (@ReservedQuantity <= @Quantity)
    begin
      delete from [dbo].[tbl_ReservedOffering]
      where ([OfferingID] = @OfferingID)
        and ([DocumentID] = @DocumentID or @DocumentID is null)
        and ([ExpirationDate] >= getdate())
        and ([ContractID] = @ContractID or @ContractID is null)
        and ([InvoiceID] = @InvoiceID or @InvoiceID is null)
        and ([StoreID] = @AStoreID or @AStoreID is null)
    end else
    begin
      update [dbo].[tbl_ReservedOffering]
      set [Quantity] = @ReservedQuantity - @Quantity,
          [ModifiedOn] = getdate(),
          [ModifiedByID] = @AUserID
      where ([OfferingID] = @OfferingID)
        and ([ExpirationDate] >= getdate())
        and ([DocumentID] = @DocumentID or @DocumentID is null)
        and ([ContractID] = @ContractID or @ContractID is null)
        and ([InvoiceID] = @InvoiceID or @InvoiceID is null)
        and ([StoreID] = @AStoreID or @AStoreID is null)  
    end
 
    fetch next from OM_Cursor
    into @OfferingID, @DocumentID, @ContractID, @InvoiceID, @Quantity
  end
 
  close OM_Cursor
  deallocate OM_Cursor
 
  return (1)
end
GO

Добрый день. Проконсультировался с разработчиками.

Действительно, точечные ошибки в конфигурауции имеются.
В частности вызов SaveMovements(Dataset, StatusID); из ds_OfferingMovementOnDatasetAfterPost(Dataset) можно отключить.

function ds_OfferingMovementOnDatasetAfterPost(Dataset) {
        GiveRightsToRecordOwner(Dataset);
        var StatusID = Dataset('StatusID');
//      SaveMovements(Dataset, StatusID);
        if (OfferingMovementScript.DoRecalc) {
                RecalcOfferingInMovementPrices(OfferingMovementScript.ID, OfferingMovementScript.Rate);
        }
}

Логика резервирвания была полностью переработана в версии 3.4.1.
Также добавлен жарнал резервов. "Спуск" всех изменений в 3.4.0 очень трудоемкая задача, пока еще планировалась.

По журналу резервированя: в Terrasoft Distribution 3.4.1 резервы не удаляются, а вместо этого добавляются записи с отрицательным значением количества. Для реализации журнала в Terrasoft Distribution 3.4.0 без проведения глобальных пеерработок раздела, разработка рекомендует построить журнал на триггерах, которые бы вносили записи о действиях в отдельную таблицу, которая и будет представлять собою журнал.

При необходимости самостоятельно изучить отличия и исправления в Terrasoft Distribution 3.4.1 обратитесь, пожалуйста, к нам за Демо версией.

Спасибо, Павел. Наконец-таки ситуация прояснилась.
Я уже обращался позавчера за последней демо-версией и мне предоставили ссылку на архив TS_XRM_Demo_RUS_MSSQL_3.4.0.130.rar - это пока еще 3.4. Может все таки можно получить 3.4.1?

Существует ли способ обновить мою уже доработанную 3.4 XRMD до 3.4.1?
Так или иначе, поставленную задачу мне придется решить, ввиду совершенно четких требований организации.

Добрый день, Павел.
Ссылка на архив с демо выслан Вам на e-mail, в рамках обращения №0133904.
По вопросу обновления - нужно согласовывать с менеджером нашей компании.

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

Здравствуйте, уважаемые форумчане.

Буду очень признателен за советы. Стоит задача реализовать в конфигурации CRM простой складской учет: остаток по продуктам и приход/расход.

Т.е. необходимо создать раздел Складские документы с типами Приход/Расход, деталь Движение продуктов, обеспечить возможность привязки данных документов к Продаже, Договору, Счету.

Добавить поле Остаток в карточку Продукты, создать раздел Складские документы (с типами приходные/расходные накладные) и деталь Движение продуктов для подвязки продуктов с количественными характеристиками понятно как.

1. Вопрос в реализации функционала обновления поля Остаток в карточке Продукты при занесении записи в деталь Движение продуктов раздела Складские документы (+ для документов Приход/ - для Расход)

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

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

У меня такой же вопрос

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

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

Для конкретного раздела, этот остаток вычисляют так: берется сумма поля «Количество» по всем движениям этого продукта. Необходимо при этом отрицательные движения брать со знаком «минус», приход – со знаком «плюс». В итоге мы получим остаток по данному продукту. Если нам нужен остаток на каком-либо складе, необходимо включить фильтрацию по складу.

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

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

Коллеги, с наступившим Новым 2012 годом и грядущим РОЖДЕСТВОМ!

Отдых на работе - это грех! Грешим все праздники...Где: в Террасофт Дистрибьюшн 3.4.078.

Поскольку давно и искренне увлечены ЕРП функционалом вообще и его складской ипостасью в указанном продукте в частности, собственно юзаем РЕСУРСЫ и все их составляющие в Дистрибьюшн. "Нарыли" много чего, часть уже просто послали в Техподдержку, т.к. явно разработка забыла/пропустила часть ДЕТАЛЕЙ :-). Ниже обозначим то, что, на наш взгляд, надо иметь функционалу Терррасофт, связанному с товародвижением + складским документооборотом. Данный пост НЕ последний. Обещаем!

1. В логике прихода на склад надо ЧЁТЧЕ обозначить связь между товаром (ПРОДУКТ), его партией оприходования, его Стоимостью (по бухучету это есть сформированная цена закупки, кот. = цена закупки от Поставщика + ТЗР) и ценой продажи (прайс-листа):
- у 1 товара (ПРОДУКТ) от 1 поставщика может быть МНОГО цен закупки, равные ТЗР и... разные ТЗР (сколько "цен" получается!)
- каждая поставка и, тем более, новая цена нашей закупки/ТЗР = новая партия (ПАРТИИ надо видеть в 1 месте, а не только в разных документах, не user friendly)
- один и тот же товар можно закупить и у РАЗНЫХ поставщиков и это ОПЯТЬ новая партия.

В ЕРП реализовано через учет документа ПРИХОДНЫЙ СКЛАДСКОЙ ОРДЕР и партионный учет. Именно здесь мы вводим в Систему Стоимость (цена закупки + ТЗР). ТЗР вообще одной цифрой сложно обозначить, т.е. эти ТЗР надо собирать по каждой партии ОТДЕЛЬНО, а потом в ТЗР поле подтягивать цифру.

В логике расхода со склада в/у логика работает в противоположном направлении:
- в зависимости от учетной политики идет расходование партий с созданием ряда документов (РАСХОДНЫЙ складской ордер, Накладная на внутреннее перемещение, АКТ на списание, Инвентаризационная ведомость и т.д).
- при расходе нужно виде цену закупки + ТЗР (вместе они дают СТОИМОСТЬ, в терминах ТС = поле "Себестоимость") и цену продажи с тем, чтобы настроить "защиту от дурака", т.е. ЗАПРЕТ продажи по цене ниже, чем "Стоимость+минимальная маржа".

2. Итак, в ходе движения по складу у Товара возникает, как минимум, 2 "цены": прихода (цена поставщика меняется на термин "стоимость"=цена поставки+ ТЗР) и расхода (стоимость, цена: термин в зависимости от типа складской операции/корреспондирующего складского документа).

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

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

По Продукту разные партии прихода можно увидеть только через разные приходные складские документы, что затрудняет и работу логиста, и бухгалтера. Может добавить деталь ПАРТИЯ, куда брать данных из приходных накладных?

Что делать? Будем смотреть как "это" уже сделано в др. системах и пытаться повторить. В том числе для целей контроля маржинальности по товарной продаже, для списания, возврата поставщику, возврата от покупателя, списания в производство, перемещения и пр.

Знаем что к концу 1 кв. 2012 года будет выпуск обновленного Дистрибьюшн от ВЕНДОРА. Очень бы хотелось учесть вышеуказанные нюансы (готовы общаться с разработкой ТС до "упора"):
- партионный учет по товару (ПРОДУКТ/Деталь "Поставщик" сейчас видим 1 цену поставщика, а надо видеть ВСЕ партии или ИСТОРИЮ)
- наглядность Стоимости с детализацией ТЗР (закупка/списание/возврат) и Цены (продажи)
- защиту от "дурака"

Повторю, это НЕ идеи и НЕ новации. Это все давно есть и используется.

А сейчас/пока просил бы:

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

Будем признательны за комментарии и советы, а лучше - настройки, кто делал! :cool:

Поделиться

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

Не первый раз в блоге я описываю интересные моменты нашего проектного решение для дистрибуции.

Сегодня, я хочу рассказать о новом функционале решения – Управление поставками.

Идея такова: в товарообороте учитывать не только себестоимость товара (FIFO, LIFO, средневзвешенный), но и все связанные с поставками расходы.
Мы создали новый раздел «Поставки», который служить оберткой для накладных с типом «Ожидание» (Деталь «Накладные»).

Есть возможность вносить расходы, связанные с поставкой (Деталь «Операции»). И разные дополнительные параметры :wink:
После получения товара, мы одним действием оприходуем (автоматически создаются приходные накладные) товар на склад. Таким образом, кроме закупочной стоимости товара, мы получаем еще значение дополнительных расходов. Способ расчета предусмотрены по цене или по массе продукта.

Данный подход помог нашему клиенту более точно «понимать» реальную себестоимость товаров и учитывать полученную информацию вовремя формирование цен и скидок.

Какие будут Ваши комментарии, идеи? :biggrin:

Ссылки на предыдущие записи:
http://community.terrasoft.ua/blogs/3221
http://community.terrasoft.ua/blogs/3590
http://community.terrasoft.ua/blogs/3678

Поделиться

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

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

Продолжая тему нашего решения для дистрибьюторов 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

Войдите или зарегистрируйтесь, чтобы комментировать