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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 03.04.2012, 23:15   #1  
1349 is offline
1349
Участник
 
6 / 10 (1) +
Регистрация: 03.04.2012
Получение строк спецификации в X++
Здравствуйте.

Пытаюсь написать функцию, которая выведет список спецификаций и номенклатур, входящих в какую-то конкретную спецификацию.
Получить просто список всех спецификаций удалось так:
while select inventTable
where inventTable.itemType == ItemType::BOM
info(inventTable.itemId)

Связать же эту таблицу с собой через itemId, чтобы узнать, какие строки входят в спецификацию с конкретным itemId, не выходит. Подскажите, пожалуйста, куда копать.
Старый 03.04.2012, 23:23   #2  
Удвой Покуров is offline
Удвой Покуров
Участник
 
461 / 228 (8) ++++++
Регистрация: 03.04.2011
Таблицы bom*, в частности, bomtable, завязка через bomid и bomversion, обращайте внимание, какая спецификация активная.

Последний раз редактировалось Удвой Покуров; 03.04.2012 в 23:33.
За это сообщение автора поблагодарили: 1349 (1).
Старый 04.04.2012, 09:30   #3  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,429 / 1772 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от 1349 Посмотреть сообщение
Получить просто список всех спецификаций удалось так: ...
Уточню терминологию. Таким образом вы получили список номенклатур с типом спецификаця. Т.е. таких номенклатур, которые могут иметь спецификацию.

Дело в том что в аксапте термин "Спецификация" используется для обозначения не номенклатуры со списком входящих, а для обозначения непостредственно самого списка составляющих номенклатуры. Спецификации в аксапте имеют отдельные коды, вообще говоря отличные от кодов номенклатурных. Причём связь между номенклатурными кодами и спецификациями - многие ко многим. Это сделано, например, для того чтобы одну и туже аксаптовскую спецификацию можно было назначить одновременно нескольким номенклатурам. Это будут разные номенклатурные коды, но состав у них будет одинаковым, и если потом внести изменения в такую спецификацию, то эти изменения отразятся на всех номенклатурах использующих эту спецификацию. Иногда это бывает полезно. И наоборот чтобы на один и тот же номенклатурный код можно было назначить несколько разных спецификаций.

Теперь о структуре таблиц.
Сами спецификации хранятся в двух таблицах. Заголовки спецификаций (BOMTable) и строки спецификаций (BOM). Связь между ними один ко многим по полю BOMId. Связь между таблицей спецификаций (BOMTable) и таблицей номенклатур (InventTable), как я уже говорил - многие ко многим. Реализуется она через таблицу версий спецификации (BOMVersion).

В случае когда одному ItemId в таблице BOMVersion соответствует несколько BOMId возникает необходимость в определении какой именно состав номенклатуры нужно использовать в данный момент для текущей задачи. Для этого в таблице BOMVersion присутствуют дополнительные атрибуты, которые помогают идентифицировать искомую версию спецификации. В зависимости от версии аксапты набор этих признаков может различаться. Как минимум, это период действия версии спецификации и её активность. Помимо этих характеристик в составной ключ могут входить номенклатурные аналитики, складская аналитика сайт и размер партии. Подробности смотрите в методе BOMVersion::findActive()

Цитата:
Сообщение от 1349 Посмотреть сообщение
Связать же эту таблицу с собой через itemId, чтобы узнать, какие строки входят в спецификацию с конкретным itemId, не выходит. Подскажите, пожалуйста, куда копать.
Учитывая всё вышесказанное, решения вашей задачи может выглядеть примерно так:
X++:
    while select InventTable
    where
        InventTable.itemType == ItemType::BOM
    join TableId from BOMVersion
    where
        BOMVersion.ItemId == InventTable.ItemId
        && BOMVersion.Active == NoYes::Yes
        && BOMVersion.FromDate <= _date
        && BOMVersion.ToDate >= _date
    join TableId from BOM
    where
        BOM.BOMId == BOMVersion.BOMId
    join InventTableChild
    where
        InventTableChild.ItemId == BOM.ItemId
    {
        info(strfmt("%1, %2", InventTable.ItemId, InventTableChild.ItemId));
    }
За это сообщение автора поблагодарили: 1349 (1).
Старый 04.04.2012, 10:26   #4  
Raven Melancholic is offline
Raven Melancholic
Участник
Аватар для Raven Melancholic
Самостоятельные клиенты AX
Лучший по профессии 2015
 
2,158 / 1286 (47) ++++++++
Регистрация: 21.03.2005
Адрес: Москва-Петушки
Кроме структуры таблиц нужно еще помнить о том, что могут быть конфигурационные группы (тогда для разных конфигураций могут быть разные спецификации), сроки действия строки спецификации, строки с фантомными позициями (тогда вопрос, нужно ли их разворачивать), нужно ли разворачивать только для первого уровня или до самых нижних и т.п.
Поэтому лучше не использовать прямой поиск по таблицам, а воспользоваться классом BOMSearch и, если нужен не только список номенклатур а и количество (которое может зависеть от формулы расчета, настроек отходов), то еще и BOMCalcData.
За это сообщение автора поблагодарили: S.Kuskov (2), 1349 (1).
Старый 04.04.2012, 18:02   #5  
1349 is offline
1349
Участник
 
6 / 10 (1) +
Регистрация: 03.04.2012
Спасибо за развернутый ответ.

С получением списка номенклатур напрямую из таблиц стало понятно. Тем не менее, количество входящих номенклатур через BOM.BOMQty почему-то возвращает 0, хотя в таблице оно указано.

Raven Melancholic,
Цитата:
если нужен не только список номенклатур а и количество (которое может зависеть от формулы расчета, настроек отходов), то еще и BOMCalcData.
Получается, получить количество можно только через BOMCalcData? У меня на данный момент только одна конфигурационная группа (изучаю язык в учебных целях, поэтому пока заполнено все как можно проще). Не могли бы вы привести самый простой пример использования этого класса?
Старый 04.04.2012, 20:10   #6  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,429 / 1772 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от 1349 Посмотреть сообщение
количество входящих номенклатур через BOM.BOMQty почему-то возвращает 0
в своём примере я не выбираю данные из строк спецификации. Если они вам нужны, то замените
X++:
//join TableId from BOM
join BOM
В простейших случаях вам будет достаточно BOMQty, но в общем случае лучше воспользоваться советом Raven Melancholic.
Как минимум ещё стоит учесть значение "В серии" (BOMSeries), а в более сложных случаях может использоваться формула для расчёта нормы.
Старый 06.04.2012, 11:41   #7  
Raven Melancholic is offline
Raven Melancholic
Участник
Аватар для Raven Melancholic
Самостоятельные клиенты AX
Лучший по профессии 2015
 
2,158 / 1286 (47) ++++++++
Регистрация: 21.03.2005
Адрес: Москва-Петушки
Цитата:
Сообщение от 1349 Посмотреть сообщение
Не могли бы вы привести самый простой пример использования этого класса?
Можно поискать по перекрестным ссылкам его использование. Например, он используется при создании складского журнала "Спецификация" из карточки номенклатуры в классе BOMReportFinish.
Если для учебных целей, то простой пример будет примерно следующим (это для DAX4, в 2009 нужно еще учесть возможность иметь разные спецификации для разных сайтов).
Создаем класс, в нем реализуем метод:
X++:
public void expandBOM( 
                        ItemId              _itemId,
                        ConfigId            _configId,
                        TransDate           _baseDate,
                        InventQty           _qtySeries,
                        Counter             _level,
                        BOMId               _bomId = '',
                        boolean             _expandPhantom = true
                      )
{
    InventTable         inventTable;
    InventTable         childInventTable;
    BOMSearch           search;
    BOMCalcData         calcData;
    BOMCalcConsumption  calcConsump;
    BOMId               bomId;
    ItemId              childItemId;
    ConfigId            childConfigId;
    BOMId               childBOMId;
    CompanyId           companyId;
    boolean             expandChild;
    Qty                 qty;
    ;

    if (_level > bomMaxLevel)
    {
        return;
    }

    select firstOnly inventTable
        where inventTable.ItemId    == _itemId
    ;

    if (!inventTable.inventItemType().canHaveBOM())
    {
        return;
    }

    bomId       = (_bomId && BOMTable::exist(_bomId)) ? _bomId : inventTable.BOMId(_baseDate, _qtySeries);
    search      = BOMSearch::newBOMExplode_OVK(bomId, _baseDate, _itemId, _configId);

    calcData    = BOMCalcData::newInventTable(_qtySeries, inventTable);

    while (search.next())
    {
        childItemId     = search.BOM().itemId;

        if (!childItemId || !InventTable::exist(childItemId))
        {
            continue;
        }

        childInventTable = search.BOM().inventTable();

        calcConsump     = BOMCalcConsumption::construct(search.BOM().formula, calcData);
        qty             = calcConsump.calcConsumption(search.BOM()) * _qtySeries;
        qty             = UnitConvert::qty(
                                            qty,
                                            search.BOM().unitId,
                                            childInventTable.inventUnitId(),
                                            childItemId,
                                            false);

        if (!qty)
        {
            continue;
        }

        childConfigId   = search.BOM().configId();
        childBOMId      = search.BOM().itemBOMId(_baseDate, qty);

        expandChild     = false;
        
        if (search.BOM().BOMType == BOMType::Phantom)
        {
            if (_expandPhantom)
            {
                expandChild = true;
            }
        }
        else if (childInventTable.inventItemType().canHaveBOM() && !childInventTable.StopExplode)
        {
            expandChild = true;
        }
        
        if (!_expandPhantom || search.BOM().BOMType != BOMType::Phantom)
        {
            info(strFmt("%1Уровень = %2 Номенклатура = %3, конфигурация = %4, количество = %5", strRep(" ", _level*4), _level, childItemId, childConfigId, qty));
        }

        if (!expandChild)
        {
            continue;
        }
        
        select firstOnly childInventTable
            where childInventTable.ItemId    == childItemId
        ;

        if (childInventTable.inventItemType().canHaveBOM())
        {
            this.expandBOM(
                            childItemId,
                            childConfigId,
                            _baseDate,
                            qty,
                            _level + (search.BOM().BOMType != BOMType::Phantom ? 1 : 0),
                            childBOMId,
                            _expandPhantom
                          );
        }
    }

}
Вызов делаем примерно таким:
X++:
static void TestExpandBOM_job(Args _args)
{
    InventTable     inventTable;
    ConfigTable     configTable;
    TestExpandBOM   testExpandBOM;
    Counter         maxLevel;
    TransDate       baseDate;
    InventQty       qtySeries;
    boolean         expandPhantom;
    ;
    
    baseDate        = systemDateGet();
    expandPhantom   = true;
    qtySeries       = 1;
    maxLevel        = 1;    // BOMParameters::find().BOMMaxLevel();
    
    testExpandBOM   = TestExpandBOM::newBlank(maxLevel);
    
    while select inventTable
        where inventTable.ItemId    == "140782"
    {
        if (!inventTable.configActive())
        {
            info(strFmt("Основная номенклатура %1", inventTable.ItemId));
            testExpandBOM.expandBOM(inventTable.ItemId, '', baseDate, qtySeries, 1, '', expandPhantom);
        }
        else
        {
            while select configTable
                where configTable.ItemId    == inventTable.ItemId
            {
                info(strFmt("Основная номенклатура %1, конфигурация %2", inventTable.ItemId, configTable.ConfigId));
                testExpandBOM.expandBOM(inventTable.ItemId, configTable.ConfigId, baseDate, qtySeries, 1, '', expandPhantom);
            }
        }
    }
    
}
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Открытие формы строк журнала спецификации AGRESSOR DAX: Программирование 16 13.05.2010 11:18
Amand: Видео: Спецификации (BOM) в Microsoft Dynamics AX 4.0 Часть 1-3 Этапы создания спецификации. Blog bot DAX Blogs 0 25.01.2010 22:05
Amand: Видео: Спецификации (BOM) в Microsoft Dynamics AX 4.0 Часть 1-2 Настройка - Типы строк спецификаций. Blog bot DAX Blogs 0 24.01.2010 19:05
Проверка цикличности в спецификации vey DAX: Функционал 2 24.03.2005 11:03
Резервирование строк спецификации basanko DAX: Функционал 7 15.07.2003 22:06

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

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

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