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

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

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