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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 14.08.2012, 10:39   #1  
Ace of Database is offline
Ace of Database
Участник
Аватар для Ace of Database
 
877 / 649 (23) +++++++
Регистрация: 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
 
877 / 649 (23) +++++++
Регистрация: 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,732 / 406 (17) +++++++
Регистрация: 23.03.2006
вызвать после работы с проводками
X++:
Appl.ttsNotifyPreCommit();
тогда в остатках будут актуальные данные
Старый 14.08.2012, 12:03   #4  
fed is offline
fed
Moderator
Аватар для fed
Ex AND Project
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
2,909 / 5730 (197) ++++++++++
Регистрация: 13.03.2002
Адрес: Hüfingen,DE
Цитата:
Сообщение от ice Посмотреть сообщение
вызвать после работы с проводками
X++:
Appl.ttsNotifyPreCommit();
тогда в остатках будут актуальные данные
Рискованый совет. После этого вызова, обновленные остатки будут заблокированы, и любая другая пользовательская сессия, которая что-то попытается по данной номенклатуре сделать (да хотя бы списать по склада), окажется заблокирована до конца нашей транзакции.
Вариант из блога dynamicsaxtraning, он - сложный, но единственно применимый в многопользовательской среде.
Старый 14.08.2012, 12:30   #5  
ice is offline
ice
Участник
Аватар для ice
Лучший по профессии 2014
 
1,732 / 406 (17) +++++++
Регистрация: 23.03.2006
нормальный совет использовать класс InventOnHand
За это сообщение автора поблагодарили: Logger (3).
Старый 14.08.2012, 12:44   #6  
Omeo is offline
Omeo
Участник
 
129 / 50 (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), FrolovAndy (2).
Старый 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,732 / 406 (17) +++++++
Регистрация: 23.03.2006
поиск остатков с помощью двух таблиц конечно хорош, но вот если нужно, например, разнести в одной транзакции приход и расход, вот тут начинаются сложности
Старый 14.09.2012, 14:22   #9  
Ace of Database is offline
Ace of Database
Участник
Аватар для Ace of Database
 
877 / 649 (23) +++++++
Регистрация: 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.
За это сообщение автора поблагодарили: Logger (3).
Старый 14.09.2012, 14:34   #10  
Ace of Database is offline
Ace of Database
Участник
Аватар для Ace of Database
 
877 / 649 (23) +++++++
Регистрация: 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
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,494 / 1065 (38) ++++++++
Регистрация: 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
 
375 / 562 (19) +++++++
Регистрация: 08.08.2007
Записей в блоге: 1
Цитата:
Сообщение от ice Посмотреть сообщение
поиск остатков с помощью двух таблиц конечно хорош, но вот если нужно, например, разнести в одной транзакции приход и расход, вот тут начинаются сложности
А в чем принципиальная разница поиска по двум таблицам и использования класса InventOnHand - он же делает те же самые 2 select'а, по тем же таблицам. Кстати о какой сложности идет речь ?

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

В реальной жизни приходится еще делать сортировку\фильтрацию\группировку во всяким дополнительным полям в складах, ячейках, палетах, партиях. Подцеплять побочные таблицы.
Так используйте стандартные методы InventSum::newQuery(...) и InventSumDelta::newQueryAggregated(...) - они вернут вам Query, а дальше какие хотите условия такие и добавляйте.
__________________
Sergey Nefedov
Старый 17.09.2012, 13:09   #13  
someOne is offline
someOne
Участник
Аватар для someOne
 
174 / 432 (15) +++++++
Регистрация: 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
 
877 / 649 (23) +++++++
Регистрация: 14.10.2004
Спасибо большое Raz и SomeOne!

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

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

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

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

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

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

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

вообще говоря, косяк в стандартном InventDimOnHand (Ax2009), или я чего-то не понимаю?
Может быть, это исправлено в каком-то SP?
Это не косяк, а так спроектировано. Если сразу добавлять запись (пусть и с пустыми остатками) в InventSum одновременно с созданием InventSumDelta, то можно нарваться на блокировки/конфликт уникального ключа. А InventSumDelta как раз и делали, чтобы этого избежать.
Старый 19.05.2017, 19:37   #17  
Ярослав Щекин is offline
Ярослав Щекин
Участник
 
78 / 174 (6) ++++++
Регистрация: 16.03.2009
Цитата:
Сообщение от Logger Посмотреть сообщение
Это не косяк, а так спроектировано. Если сразу добавлять запись (пусть и с пустыми остатками) в InventSum одновременно с созданием InventSumDelta, то можно нарваться на блокировки/конфликт уникального ключа. А InventSumDelta как раз и делали, чтобы этого избежать.
Подождите, причём тут внесение записи в InventSum? Мне было непонятно, почему InventSumDelta не обрабатывается в классе InventDimOnHand.
Старый 19.05.2017, 21:39   #18  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,952 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Я отвечал не на первое ваше сообщение, а на вот это:
Цитата:
Цитата:
Так как в InventSumDelta могут быть остатки по аналитикам, которых нет в inventSum.
вообще говоря, косяк в стандартном InventDimOnHand (Ax2009), или я чего-то не понимаю?
Может быть, это исправлено в каком-то SP?
Наверно какое то недопонимание.
Старый 02.06.2017, 01:31   #19  
Maxim Gorbunov is offline
Maxim Gorbunov
Administrator
Соотечественники
Лучший по профессии 2009
 
2,483 / 645 (26) +++++++
Регистрация: 27.11.2001
Адрес: Dubai, UAE
Цитата:
Сообщение от Ярослав Щекин Посмотреть сообщение
Мне было непонятно, почему InventSumDelta не обрабатывается в классе InventDimOnHand.
Обрабатывается. См. InventOnhand.addInventSumDelta().

someOne имел в виду, что надо быть аккуратным, когда не используется InventDimOnHand, а остатки выбираются прямыми запросами к InventSum/InventSumDelta.

Кстати, в AX 2012 R3 появились View (InventSumAggrDeltaView и InventSumUnionDeltaPhysicalQty), в которых InventSum и InventSumDelta уже связаны. Идея была в том, чтобы читать остатки из этих View, и не заморачиваться с классами InventOnhand. Идея, вероятно, была неплохая, но реализация подкачала: во View забыли добавить TTSId, и теперь любые запросы к ним блокируют и InventSum, и InventSumDelta целиком. Используются эти View в новом Warehouse Management. В блогах и на форумах есть несколько статей, в которых люди пытаются что-то шаманить с индексами на InventSumDelta, чтобы блокировки уменьшить, но корень проблемы в том, что InventSumDelta просто неправильно используется в стандартном коде.
__________________
Not registered yet? Register here!
Have comments, questions, suggestions or anything else regarding our web site? Don't hesitate, send them to me
За это сообщение автора поблагодарили: Logger (10).
Старый 02.06.2017, 09:01   #20  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,952 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от Maxim Gorbunov Посмотреть сообщение
Кстати, в AX 2012 R3 появились View (InventSumAggrDeltaView и InventSumUnionDeltaPhysicalQty), в которых InventSum и InventSumDelta уже связаны. Идея была в том, чтобы читать остатки из этих View, и не заморачиваться с классами InventOnhand.
Вот именно! Схожие идеи возникают у разных людей.

Цитата:
Сообщение от Maxim Gorbunov Посмотреть сообщение
Идея, вероятно, была неплохая, но реализация подкачала: во View забыли добавить TTSId, и теперь любые запросы к ним блокируют и InventSum, и InventSumDelta целиком.
Похоже не забыли, а поимели сложности с фильтрацией по TTSid. И в итоге пронадеялись на то что можно без фильтрации обойтись - все равно в табличке только незакоммиченные данные лежат, а сессия по идее должна увидеть только свои данные.
(у меня в отношении этого были опасения по блокировкам и они подтвердились )

Вы видите способ штатными средствами аксапты (без редактирования вьюхи в SQL) достичь заявленной цели ?

Цитата:
Сообщение от Maxim Gorbunov Посмотреть сообщение
В блогах и на форумах есть несколько статей, в которых люди пытаются что-то шаманить с индексами на InventSumDelta, чтобы блокировки уменьшить,
Не поделитесь ссылочками ? Интересно посмотреть.

Цитата:
Сообщение от Maxim Gorbunov Посмотреть сообщение
но корень проблемы в том, что InventSumDelta просто неправильно используется в стандартном коде.
Ого ! А как же правильно тогда ? Что там не так ?
Теги
ax2009, inventsumaggrdeltaview, inventsumdelta, inventsumuniondeltaphysicalqty, как правильно, остатки, транзакции

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
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, время: 22:59.