03.04.2012, 23:15 | #1 |
Участник
|
Получение строк спецификации в X++
Здравствуйте.
Пытаюсь написать функцию, которая выведет список спецификаций и номенклатур, входящих в какую-то конкретную спецификацию. Получить просто список всех спецификаций удалось так: while select inventTable where inventTable.itemType == ItemType::BOM info(inventTable.itemId) Связать же эту таблицу с собой через itemId, чтобы узнать, какие строки входят в спецификацию с конкретным itemId, не выходит. Подскажите, пожалуйста, куда копать. |
|
03.04.2012, 23:23 | #2 |
Участник
|
Таблицы bom*, в частности, bomtable, завязка через bomid и bomversion, обращайте внимание, какая спецификация активная.
Последний раз редактировалось Удвой Покуров; 03.04.2012 в 23:33. |
|
|
За это сообщение автора поблагодарили: 1349 (1). |
04.04.2012, 09:30 | #3 |
Участник
|
Уточню терминологию. Таким образом вы получили список номенклатур с типом спецификаця. Т.е. таких номенклатур, которые могут иметь спецификацию.
Дело в том что в аксапте термин "Спецификация" используется для обозначения не номенклатуры со списком входящих, а для обозначения непостредственно самого списка составляющих номенклатуры. Спецификации в аксапте имеют отдельные коды, вообще говоря отличные от кодов номенклатурных. Причём связь между номенклатурными кодами и спецификациями - многие ко многим. Это сделано, например, для того чтобы одну и туже аксаптовскую спецификацию можно было назначить одновременно нескольким номенклатурам. Это будут разные номенклатурные коды, но состав у них будет одинаковым, и если потом внести изменения в такую спецификацию, то эти изменения отразятся на всех номенклатурах использующих эту спецификацию. Иногда это бывает полезно. И наоборот чтобы на один и тот же номенклатурный код можно было назначить несколько разных спецификаций. Теперь о структуре таблиц. Сами спецификации хранятся в двух таблицах. Заголовки спецификаций (BOMTable) и строки спецификаций (BOM). Связь между ними один ко многим по полю BOMId. Связь между таблицей спецификаций (BOMTable) и таблицей номенклатур (InventTable), как я уже говорил - многие ко многим. Реализуется она через таблицу версий спецификации (BOMVersion). В случае когда одному ItemId в таблице BOMVersion соответствует несколько BOMId возникает необходимость в определении какой именно состав номенклатуры нужно использовать в данный момент для текущей задачи. Для этого в таблице BOMVersion присутствуют дополнительные атрибуты, которые помогают идентифицировать искомую версию спецификации. В зависимости от версии аксапты набор этих признаков может различаться. Как минимум, это период действия версии спецификации и её активность. Помимо этих характеристик в составной ключ могут входить номенклатурные аналитики, складская аналитика сайт и размер партии. Подробности смотрите в методе BOMVersion::findActive() Цитата:
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 |
Участник
|
Кроме структуры таблиц нужно еще помнить о том, что могут быть конфигурационные группы (тогда для разных конфигураций могут быть разные спецификации), сроки действия строки спецификации, строки с фантомными позициями (тогда вопрос, нужно ли их разворачивать), нужно ли разворачивать только для первого уровня или до самых нижних и т.п.
Поэтому лучше не использовать прямой поиск по таблицам, а воспользоваться классом BOMSearch и, если нужен не только список номенклатур а и количество (которое может зависеть от формулы расчета, настроек отходов), то еще и BOMCalcData. |
|
|
За это сообщение автора поблагодарили: S.Kuskov (2), 1349 (1). |
04.04.2012, 18:02 | #5 |
Участник
|
Спасибо за развернутый ответ.
С получением списка номенклатур напрямую из таблиц стало понятно. Тем не менее, количество входящих номенклатур через BOM.BOMQty почему-то возвращает 0, хотя в таблице оно указано. Raven Melancholic, Цитата:
если нужен не только список номенклатур а и количество (которое может зависеть от формулы расчета, настроек отходов), то еще и BOMCalcData.
|
|
04.04.2012, 20:10 | #6 |
Участник
|
в своём примере я не выбираю данные из строк спецификации. Если они вам нужны, то замените
X++: //join TableId from BOM join BOM Как минимум ещё стоит учесть значение "В серии" (BOMSeries), а в более сложных случаях может использоваться формула для расчёта нормы. |
|
06.04.2012, 11:41 | #7 |
Участник
|
Можно поискать по перекрестным ссылкам его использование. Например, он используется при создании складского журнала "Спецификация" из карточки номенклатуры в классе 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); } } } } |
|
|
|