Отправил вопрос в службу поддержки. Дублирую вопрос здесь.
-----------------------------------------------------------------------------------------------
Речь пойдет о разделе Склад (накладные).
В скрипте 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.
Проясните, пожалуйста, логику работы механизма резервирования и
ответьте на вопрос, для чего нужно дублировать один и тот же
функционал в системе.
-----------------------------------------------------------------------
Буду благодарен за любую помощь, ибо логика работы с резервами и накладными пока не укладывается в моей голове.
Нравится
Добрый день, коллеги!
Наличие похожей логики и в конфигурации и в хранимой процедуре обусловлено тем, чтоб изначально все происходило только в конфигурации. Со временем от этого решили отказаться, т.к. сбор и обработка данных сразу по многим сущностям (продукты, счета, складские документы) значительно нагружало клиентское прилоежение.
Логику перенесли в хранимые процедуры, но для совместимости кода с предыдущими версиями в конфигурации сделли незначительные изменения.
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.
По вопросу обновления - нужно согласовывать с менеджером нашей компании.