AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 14.08.2012, 10:39   #1  
Ace of Database is offline
Ace of Database
Участник
Аватар для Ace of Database
 
667 / 507 (18) +++++++
Регистрация: 14.10.2004
Остатки по номенклатуре в разрезе складов внутри транзакции
Привет всем!
Помогите пожалуйста найти быстрый способ решения следующей задачи:
1) Перебор остатков без привязки к номенклатуре в разрезе складов (или других складских аналитик). Чтобы на выходе я мог группировать по складу, номенклатуре, ячейке и так далее.

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

В Аксапте 3.0 с этим не было проблем - таблица InventSum всегда содержала актуальную информацию.
В Аксапте 2009 таблица InventSum не содержит актуальную информацию до завершения транзакции.

Посмотрел класс InventOnHand и манипуляции с таблицей InventSumDelta. Но не понял, как из этого класса взять набор остатков в виде [Склад 1 - остаток 3 штуки, Склад 2 - остаток 5 штук, и т.д.]
Но чтобы не изобретать велосипед, может у кого-то уже есть шаблон кода для выполнения этой задачи?

На одном проекте видел "велосипед", когда остатки вычислялись хранимой процедурой на SQL, а из Аксапты потом считывались.

Можно потратить пару дней и самому разобраться, но если уже у кого-то есть готовый шаблон кода?
Старый 14.08.2012, 10:45   #2  
Ace of Database is offline
Ace of Database
Участник
Аватар для Ace of Database
 
667 / 507 (18) +++++++
Регистрация: 14.10.2004
Вот наверное ответ на мой вопрос:
dynamicsaxtraining: Get “available physical” values for specific item+dimensions per batch

Да, громоздкие получаются конструкции.
Старый 14.08.2012, 11:06   #3  
ice is offline
ice
Участник
Аватар для ice
Лучший по профессии 2014
 
1,432 / 312 (13) ++++++
Регистрация: 23.03.2006
вызвать после работы с проводками
X++:
Appl.ttsNotifyPreCommit();
тогда в остатках будут актуальные данные
Старый 14.08.2012, 12:03   #4  
fed is offline
fed
Участник
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
Ex AND Project
Соотечественники
 
2,028 / 3731 (129) ++++++++++
Регистрация: 13.03.2002
Адрес: İstanbul
Цитата:
Сообщение от ice Посмотреть сообщение
вызвать после работы с проводками
X++:
Appl.ttsNotifyPreCommit();
тогда в остатках будут актуальные данные
Рискованый совет. После этого вызова, обновленные остатки будут заблокированы, и любая другая пользовательская сессия, которая что-то попытается по данной номенклатуре сделать (да хотя бы списать по склада), окажется заблокирована до конца нашей транзакции.
Вариант из блога dynamicsaxtraning, он - сложный, но единственно применимый в многопользовательской среде.
Старый 14.08.2012, 12:30   #5  
ice is offline
ice
Участник
Аватар для ice
Лучший по профессии 2014
 
1,432 / 312 (13) ++++++
Регистрация: 23.03.2006
нормальный совет использовать класс InventOnHand
За это сообщение автора поблагодарили: Logger (3).
Старый 14.08.2012, 12:44   #6  
Omeo is offline
Omeo
Участник
 
126 / 48 (2) +++
Регистрация: 18.03.2004
Адрес: Moscow
если я правильно понял задачу то примерно такой код
X++:
    hand = InventDimOnHand::newAvailPhysical('', inventDim, inventDimParm, InventDimOnHandLevel::TotalQty, inventDimParm);
    
    iterator = hand.onHandIterator();
    
    while (iterator.more())
    {
        member = iterator.value();
    
        iterator.next();
    }
За это сообщение автора поблагодарили: Logger (5), Ace of Database (4).
Старый 14.08.2012, 13:31   #7  
Alexanderis.ua is offline
Alexanderis.ua
Участник
 
53 / 40 (2) +++
Регистрация: 25.12.2008
Адрес: Киев, Украина
Посмотрите реализацию стандартных методов
X++:
InventSum::findSum()
InventSumDelta::findSumDelta()
Там все макросами сделано. На вид не так уж и громоздко будет
__________________
If it ain't broke, take it apart and find out why (с)
Старый 14.08.2012, 13:55   #8  
ice is offline
ice
Участник
Аватар для ice
Лучший по профессии 2014
 
1,432 / 312 (13) ++++++
Регистрация: 23.03.2006
поиск остатков с помощью двух таблиц конечно хорош, но вот если нужно, например, разнести в одной транзакции приход и расход, вот тут начинаются сложности
Старый 14.09.2012, 14:22   #9  
Ace of Database is offline
Ace of Database
Участник
Аватар для Ace of Database
 
667 / 507 (18) +++++++
Регистрация: 14.10.2004
Omeo, спасибо большое!
Наконец-то научили меня считать остатки самым правильным способом за 8 лет работы

X++:
static void Job11(Args _args)
{
    InventDimOnHand    hand;
    inventDim          inventDim;
    inventDimParm      inventDimParm;
    InventDimOnHandIterator iterator;
    InventDimOnHandMember   member;
 ;

    inventDim.InventLocationId = "Общий";
    inventDimParm.initFromInventDim(inventDim);
    hand = InventDimOnHand::newAvailPhysical('', inventDim, inventDimParm, InventDimOnHandLevel::TotalQty, inventDimParm);

    iterator = hand.onHandIterator();

    while (iterator.more())
    {
        member = iterator.value();
        info(strfmt("%1 = %2", member.parmItemId(), member.parmInventQty()));

        iterator.next();
    }
}

Последний раз редактировалось Ace of Database; 14.09.2012 в 14:25.
Старый 14.09.2012, 14:34   #10  
Ace of Database is offline
Ace of Database
Участник
Аватар для Ace of Database
 
667 / 507 (18) +++++++
Регистрация: 14.10.2004
Правда все равно остаются ограничения у такого механизма по сравнению с прямым запросом к InvenSum-InventDim.

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

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

Последний раз редактировалось Ace of Database; 14.09.2012 в 14:45.
Старый 14.09.2012, 15:13   #11  
raz is offline
raz
NavAx
Аватар для raz
Лучший по профессии 2014
Лучший по профессии 2009
NavAx Club
 
1,242 / 739 (27) +++++++
Регистрация: 22.07.2003
Адрес: МО
Цитата:
Сообщение от Ace of Database Посмотреть сообщение
Правда все равно остаются ограничения у такого механизма по сравнению с прямым запросом к InvenSum-InventDim.
А сравни результат через класс и так:
X++:
    queryRun = new QueryRun(InventSum::newQuery(null, itemId, inventDimCriteriaLocal, inventDimParmLocal, inventDimParmGroupByLocal));

    while (queryRun.next())
    {
        inventSumLocal = queryRun.get(tableNum(InventSum));
        inventDimLocal = queryRun.get(tableNum(InventDim));

        if (InventUpdateOnhandGlobal::mustAddInventSumDeltaOnhand(itemId))
        {
            select #inventSumFields from inventSumDeltaLocal
                where inventSumDeltaLocal.ItemId        == itemId    &&
                      inventSumDeltaLocal.IsAggregated  == NoYes::No &&
                      inventSumDeltaLocal.TTSId         == appl.inventUpdateOnhandGlobal().inventUpdateOnhand().tTSId()
                #InventDimExistsJoin(inventSumDeltaLocal.inventDimId,inventDim2Local,inventDimLocal,inventDimParmLocal);

            inventSumLocal.addInventSumDelta(inventSumDeltaLocal);
        }

        .......

    }
За это сообщение автора поблагодарили: Ace of Database (2), SRF (1).
Старый 14.09.2012, 15:17   #12  
SRF is offline
SRF
Участник
MCBMSS
Axapta Retail User
 
258 / 311 (11) ++++++
Регистрация: 08.08.2007
Цитата:
Сообщение от ice Посмотреть сообщение
поиск остатков с помощью двух таблиц конечно хорош, но вот если нужно, например, разнести в одной транзакции приход и расход, вот тут начинаются сложности
А в чем принципиальная разница поиска по двум таблицам и использования класса InventOnHand - он же делает те же самые 2 select'а, по тем же таблицам. Кстати о какой сложности идет речь ?

Цитата:
Сообщение от Ace of Database Посмотреть сообщение
Правда все равно остаются ограничения у такого механизма по сравнению с прямым запросом к InvenSum-InventDim.

В реальной жизни приходится еще делать сортировку\фильтрацию\группировку во всяким дополнительным полям в складах, ячейках, палетах, партиях. Подцеплять побочные таблицы.
Так используйте стандартные методы InventSum::newQuery(...) и InventSumDelta::newQueryAggregated(...) - они вернут вам Query, а дальше какие хотите условия такие и добавляйте.
__________________
Sergey Nefedov,
IT Magnet
Старый 17.09.2012, 13:09   #13  
someOne is offline
someOne
Участник
Аватар для someOne
 
165 / 389 (13) ++++++
Регистрация: 11.12.2008
Адрес: Москва
Была подобная задача - получить список ячеек хранения на складе с указанием свободного количества по каждой из ячеек
(по какой то отдельное номенклатуре) внутри транзакции.

Пвтался использовать метод с использованием класса "inventDimParmOnHandLevel".
Остался пример кода.
X++:
    inventDim.InventLocationId = "Склад";
    inventDim = inventDim::findDim(inventDim);

    inventDimParm.InventLocationIdFlag = true;

    inventDimParmOnHandLevel.ItemIdFlag = true;
    inventDimParmOnHandLevel.InventLocationIdFlag = true;
    inventDimParmOnHandLevel.WMSLocationIdFlag = true;

    hand = InventDimOnHand::newAvailPhysical('29530', inventDim, inventDimParm, InventDimOnHandLevel::DimParm, inventDimParmOnHandLevel);

    iterator = hand.onHandIterator();

    while (iterator.more())
    {
        member = iterator.value();


        info(member.parmInventQty());

        info(InventDim::find(member.parmInventDimId()).wMSLocationId);

        iterator.next();
    }
Но такой способ работает очень медленно. (у меня по крайней мере...). Запрос по каждой номенклатуре длится более секунды!!!.
Может в настройках классов указал что то не правильно ?

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

В общем переделал все на прямые запросы к таблицам
- InventSum
- InventSumDelta

(Что то на подобие того как предложил raz). Так все "летает".

Только нужно учесть что вариант с циклом по текущим остаткам (inventSum) с прибавлением к нему InventSumDelta по аналитикам
группкировки inventSum может дать искаженный результат.

Так как в InventSumDelta могут быть остатки по аналитикам, которых нет в inventSum.

Правильный результат будет если:

1. Получить остатки в разрезе ячеек по InventSum, например так (для моей задачи):
X++:
    inventDimParm.initFromInventDim(inventDim);
    inventDimParm.ItemIdFlag = NoYes::Yes;
    inventDimParm.ClosedQtyFlag = NoYes::Yes;

    inventDimParmGroupBy.WMSLocationIdFlag = NoYes::Yes;

    query = inventSum::newQuery(query, itemId, inventDim, inventDimParm, inventDimParmGroupBy);

    queryRange = query.dataSourceTable(tableNum(inventSum)).addRange(FieldNum(InventSum, ClosedQty));
    queryRange.value(queryValue(0));

    queryRun = new QueryRun(query);

    while (queryRun.next())
    {
        inventSum = queryRun.get(tableNum(inventSum));
        inventDimLoc = queryRun.get(tableNum(inventDim));

        if (inventSum.AvailPhysical != 0)
        {
		//Тут текущий остаток в ячейках хранения
        }
    }

2. Получить остатки в разрезе ячеек InventSumDelta, например так (для моей задачи)


X++:
    while select sum(AvailPhysical) from inventSumDelta
    where inventSumDelta.ItemId         == itemId    &&
          inventSumDelta.IsAggregated   == NoYes::No &&
          inventSumDelta.ttsId          == appl.inventUpdateOnhandGlobal().inventUpdateOnhand().ttsId()
    join inventDimLoc
    group by WMSLocationId
    where (inventDimLoc.inventDimId      == inventSumDelta.InventDimId) &&
          (inventDimLoc.InventLocationId == "Склад")
    {
        if (inventSumDelta.AvailPhysical != 0)
        {
		//Тут изменнный остаток в ячейках хранения в данной транзакции
        }
    }

3. Объеденить два этих набора записей ("сложить" результат).

Это кроме того и самый производительный способ - всего два запроса к БД.
За это сообщение автора поблагодарили: Logger (5), Ace of Database (4).
Старый 17.09.2012, 13:46   #14  
Ace of Database is offline
Ace of Database
Участник
Аватар для Ace of Database
 
667 / 507 (18) +++++++
Регистрация: 14.10.2004
Спасибо большое Raz и SomeOne!

Метод с получением двух query для InventSum и InventSumDelta с последубщими добавлениями в них дополнительных источников данных универсален для всех задач. С последующим суммированием результата через inventSum.addInventSumDelta(inventSumDelta);

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

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

В общем, подсчет остатков - деликатная и объемная тема, достойная диссертации.
Старый 10.03.2016, 13:50   #15  
Ярослав Щекин is offline
Ярослав Щекин
Участник
 
77 / 161 (6) ++++++
Регистрация: 16.03.2009
Извините, что поднимаю старую тему...

Коллеги, а Вам не кажется, что вот это:
Цитата:
Сообщение от someOne Посмотреть сообщение
Только нужно учесть что вариант с циклом по текущим остаткам (inventSum) с прибавлением к нему InventSumDelta по аналитикам
группкировки inventSum может дать искаженный результат.

Так как в InventSumDelta могут быть остатки по аналитикам, которых нет в inventSum.
вообще говоря, косяк в стандартном InventDimOnHand (Ax2009), или я чего-то не понимаю?
Может быть, это исправлено в каком-то SP?
Старый 18.05.2017, 13:50   #16  
Logger is offline
Logger
Участник
Лучший по профессии 2014
 
2,764 / 1399 (52) ++++++++
Регистрация: 12.10.2004
Цитата:
Сообщение от Ярослав Щекин Посмотреть сообщение
Извините, что поднимаю старую тему...

Коллеги, а Вам не кажется, что вот это:

вообще говоря, косяк в стандартном InventDimOnHand (Ax2009), или я чего-то не понимаю?
Может быть, это исправлено в каком-то SP?
Это не косяк, а так спроектировано. Если сразу добавлять запись (пусть и с пустыми остатками) в InventSum одновременно с созданием InventSumDelta, то можно нарваться на блокировки/конфликт уникального ключа. А InventSumDelta как раз и делали, чтобы этого избежать.
Старый 19.05.2017, 19:37   #17  
Ярослав Щекин is offline
Ярослав Щекин
Участник
 
77 / 161 (6) ++++++
Регистрация: 16.03.2009
Цитата:
Сообщение от Logger Посмотреть сообщение
Это не косяк, а так спроектировано. Если сразу добавлять запись (пусть и с пустыми остатками) в InventSum одновременно с созданием InventSumDelta, то можно нарваться на блокировки/конфликт уникального ключа. А InventSumDelta как раз и делали, чтобы этого избежать.
Подождите, причём тут внесение записи в InventSum? Мне было непонятно, почему InventSumDelta не обрабатывается в классе InventDimOnHand.
Старый 19.05.2017, 21:39   #18  
Logger is offline
Logger
Участник
Лучший по профессии 2014
 
2,764 / 1399 (52) ++++++++
Регистрация: 12.10.2004
Я отвечал не на первое ваше сообщение, а на вот это:
Цитата:
Цитата:
Так как в InventSumDelta могут быть остатки по аналитикам, которых нет в inventSum.
вообще говоря, косяк в стандартном InventDimOnHand (Ax2009), или я чего-то не понимаю?
Может быть, это исправлено в каком-то SP?
Наверно какое то недопонимание.
Теги
ax2009, inventsumdelta, как правильно, остатки, транзакции

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Epic Fail Остатки на дату InventSumDateValueReportDim Evgeniy2020 DAX: Программирование 15 13.08.2014 19:22
Проблемы с обновлением записи, выбранной для обновления внутри транзакции Oz DAX: Программирование 13 02.07.2008 16:24
Учёт остатков в разрезе фин. аналитики miklenew DAX: Программирование 11 06.11.2007 20:01
Остатки dog37 DAX: Программирование 6 02.06.2005 11:25
Сверка остатков по счетам учета материалов и складские остатки tolstjak DAX: Функционал 5 05.04.2005 13:51
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 10:50.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.