Совет =A=L=X= будет крайне полезен для понимания работы со складской аналитикой в Аксапте.

=A=L=X=

Загрузить

InventDimOverview.zip (39Кб, Внутри: InventDimTest.xpo и эта статья в формате Microsoft Word. Для загрузки требуется регистрация на форуме у Mazzy)

 

Складские аналитики в Аксапте 3.0.
Руководство программиста

Так как я сам программирую в Аксапте немногим больше четырёх месяцев, на безупречность данного руководства не претендую – буду рад любым исправлениям и дополнениям.

Введение

Для понимания данного руководства нужно быть знакомым с принципами изложенными в стандартной документации по Аксапте «Управление логистикой и торговлей» раздел «Управление складскими запасами \ Настройка склада и складских единиц \ Основные настройки \ Складская аналитика».

Для нас самыми важными моментами из этого документа являются следующие вещи:

Выбор складской аналитики

Не выбранные в этом диалоге складские аналитики не должны отображаться в форме.

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

 

Основы программной реализации механизма складских аналитик

Первым делом заострим внимание на настройках складской аналитики. Настройки определяют многие стандартные параметры аналитик, такие как включена она в текущей конфигурации или нет, первична она или вторична и т.п. Мы должны поддерживать все эти стандартные «фичи» и потому обязаны обращать на них внимание. Настройка аналитик привязана к каждой номенклатурной единице (таблица InventTable) посредством привязки к т.н. «Группе складской аналитики» - таблице InventDimGroup (через поле dim GroupId типа InventDimGroupId). Таблица InventDimGroup является лишь «шапкой» для самих настроек. Строки с параметрами для каждой конкретной аналитики находятся в таблице InventDimSetup. Каждая конкретная аналитика в InventDimSetup представлена своим fieldId в таблице InventDim (которая и является хранилищем всех аналитик, о чём позже). Здесь уместна будет диаграмма показывающая связи между 3-мя вышеупомянутыми таблицами:

Схема таблиц

Настройки настройками, но теперь перейдем к самому главному.

Итак, предположим что перед вами стоит задача создания некой таблицы и формы для неё, где бы нужно было вводить/просматривать номенклатуру и те или иные складские аналитики для неё. Предположим что в этой нашей таблице предполагается хранить кол-во номенклатур в разрезе каких либо складских аналитик, соответственно в ней должны содержаться поля ItemId и Qty. Возникает вопрос – как правильно ввести в эту таблицу стандартные складские аналитики Аксапты?

Сами значения складских аналитик хранятся в 9-ти таблицах, ключевыми полями в которых являются следующие EDT:

Примечание: таблицы для этих EDT как правило названы точно так же как и сами EDT, только без окончания Id

По первому (и разумеется неправильному) соображению в таблицу, в которой нужно указывать некоторые из этих аналитик вместе с ItemId номенклатуры нужно включить поля с нужными EDT и пользоваться ими. При таком варианте набор столбцов в нашей таблице в худшем случае включал бы в себя ItemId, Qty и все вышеперечисленные коды аналитик.

Однако такой метод использования аналитик поставил бы крест на той гибкости и расширяемости, которая реализована в Аксапте. При добавлении к примеру новой аналитики пришлось бы «перепахивать» все таблицы, их использующие. Да и степень нормализованности таблиц в БД использующих аналитики в этом случае пострадала бы в какой то степени.

На самом деле в Аксапте значения аналитик не хранятся непосредственно в таблицах, использующих аналитики, а вместо этого комбинации всех когда либо созданных складских аналитик хранятся в таблице InventDim , а в использующих их таблицах хранится только одно поле InventDimId (типа одноимённого EDT, ключевое в InventDim), ссылающееся на конкретную строчку этих комбинаций в ней.

Таблица InventDim содержит следующие поля:

Т.е., другими словами, структура нашей гипотетической таблицы должна описываться следующими столбцами: ItemId, InventDimId, Qty, где InventDimId – ссылка на строку в InventDim, где хранится введенный нами набор складских аналитик.

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

Из вышесказанного вытекает одно важное правило: записи в InventDim никогда не должны удаляться или изменяться, т.к. на них может ссылаться неизвестное количество таблиц! Чтобы неявно поддерживать это правило методы insert, update и delete в InventDim переопределены таким образом, чтобы без специального подтверждения (в виде дополнительного параметра) не выполнять никаких действий.

 

Принципы программной работы с таблицей InventDim

  1. Если вам нужно найти запись в InventDim с уже известным InventDimId вы используете классический метод InventDim::find(InventDimId inventDimId, boolean _forupdate = false), и просматриваете полученный набор аналитик (модифицировать его не следует). Для этой же цели можно использовать метод InventDim::findDim(InventDim _inventDim, boolean _forupdate = false), который ищет запись не по InventDimId, а по конкретному набору аналитик в табличной переменной-параметре.
  2. Если вам нужно создать новый набор аналитик, для того чтобы в дальнейшем ссылаться на него, вы должны использовать метод InventDim::findOrCreate(InventDim _inventDim). Данный метод находит в InventDim запись подобно методу findDim, но если не находит – создаёт новую строчку и возвращает её.
  3. Крайне не рекомендуется модифицировать или удалять записи в InventDim.
  4. Таблицы, в которых нужно хранить складские аналитики должны иметь в себе поле InventDimId (типа EDT InventDimId ) и для задания складских аналитик использовать примерно следующий код:
InventDim dim;
MyTable tbl;
....
ttsbegin;
dim.clear();
dim.InventLocationId = ...;
dim.InventColorId = ...;
....
tbl.InventDimId = InventDim::findOrCreate(dim).InventDimId
tbl.update();
ttscommit; 
  1. Для обновления лишь некоторых из уже заданных аналитик в существующей записи с сохранением остальных использовать примерно следующий код:
InventDim dim;
MyTable tbl;
...
ttsbegin;
dim = InventDim::find(tbl.InventDimId);
dim.InventLocationId = ...;
dim.InventColorId = ...;
...
tbl.InventDimId = InventDim::findOrCreate(dim).InventDimId
tbl.update();
ttscommit ; 
  1. Следует еще добавить что в InventDim существует метод findOrCreateBlank, который возвращает InventDim с полностью незаполненными аналитиками (пустой). Эта запись с пустыми полями имеет специальный код "Axapta" и используется в некоторых местах как особенное значение.

В добавление к вышесказанному следует добавить что во многих алгоритмах и методах в качестве параметров кроме таблицы InventDim используется вспомогательный параметр - временная таблица InventDimParm, в которой каждому полю в InventDim соответствует поле типа NoYes с окончанием Flag + эта таблица содержит еще несколько вспомогательных полей. Эта таблица используется как структура из полей – флагов, определяющих режим использования той или иной аналитики из общего набора.

 

Работа с InventDim в формах

Опять исходя из вышесказанного, чтобы создать форму, поддерживающую ввод и/или вывод складских аналитик нужно выполнить ряд требований. Для облегчения работы программисту в Аксапте существует класс InventDimCtrl_Frm, который берет на себя основную работу по поддержке стандартной функциональности. Но так как каждая конкретно взятая форма может по своему работать со складскими аналитиками (например форма штрих-кодов должна запрещать вводить аналитики хранения, т.к. бессмысленно привязывать штрих-код к местоположению товара), то как правило реальной работой занимаются многочисленные наследники этого класса, слегка или не очень модифицирующие «поведение по умолчанию».

Итак, опишу известные мне шаги, которые нужно выполнить чтобы правильно встроить в свою форму складские аналитики. Исходным условием является то, что основная таблица которую мы выводим в этой форме содержит поле InventDimId – ссылку на запись в InventDim.

Object inventDimSetupObject()
{
   return inventDimFormSetup;
}
void updateDesign(InventDimFormDesignUpdate mode)
{
   InventTable inventTable;
;
   switch ( mode )
   {
      case InventDimFormDesignUpdate::Init :
         if ( !inventDimFormSetup )
            inventDimFormSetup = new InventDimCtrl_Frm_*( element );
         inventDimFormSetup.parmSkipOnHandLookUp( true );
         // do continue
      case InventDimFormDesignUpdate::Active :
         inventTable = InventTable::find( MyTable.itemId );
         inventDimFormSetup.formActiveSetup( inventTable.dimGroupId );
         inventDimFormSetup.formSetControls( true );
         break;
      case InventDimFormDesignUpdate::FieldChange :
         inventTable = InventTable::find( MyTable.itemId );
         inventDimFormSetup.formActiveSetup( inventTable.dimGroupId );
         inventDim.clearNotSelectedDim( inventDimFormSetup.parmDimParmEnabled() );
         inventDimFormSetup.formSetControls( true );
         break; 
      default : throw error(strfmt("@SYS54195",funcname())); 
   }
} 

Красным выделены: InventDimCtrl_Frm_* - класс - наследник от InventDimCtrl_Frm; MyTable – ваша ведущая для InventDim таблица , к дата - соурсу которой подчинён дата - соурс InventDim.

element.updateDesign( InventDimFormDesignUpdate::Init ); 
int active() { int ret; ret = super(); element.updateDesign(InventDimFormDesignUpdate::Active); inventDim_DS.active(); return ret; } public boolean validateWrite() { boolean ret; ; InventDimTest.InventDimId = inventDim::findOrCreate( inventDim ).inventDimId; ret = super(); return ret; } public void write() { ttsbegin; InventDimTest.inventDimId = InventDim::findOrCreate( inventDim ).inventDimId; super(); if ( InventDimTest.inventDimId != inventDim.inventDimId ) { inventDim.data( InventDim::find( InventDimTest.inventDimId ) ); inventDim_ds.setCurrent(); } ttscommit; }

Примечание: обратите внимание на то что происходит в методах write и validateWrite.

Что можно сказать про класс InventDimCtrl_Frm и его наследников? Одним из самых заметных и важных методов, которые наверняка придется переопределять является NoYes mustEnableField(fieldId dimFieldId) – который по заданному fieldId (это fieldId поля-аналитики в таблице InventDim) должен вернуть NoYes ::Yes, если поле аналитики можно редактировать в форме и NoYes::No иначе. По умолчанию InventDimCtrl_Frm всегда возвращает No.

 

Заключение

Как уже было сказано я не претендую не только на полноту изложения, но и даже на корректность кое чего из изложенного здесь – моё видение InventDim довольно неполно. Например совсем не сказано в этом документе про класс InventDimSearch, который позволяет упростить анализ настроек складских аналитик и используется во многих стандартных алгоритмах.

На самом деле я надеюсь что у вас и у меня не будет необходимости создавать свои таблицы и формы со складскими аналитиками :D, но данный думаю что данный introduction будет крайне полезен для понимания уже существующих форм и таблиц.

В качестве приложения к этому документу я прилагаю тестовый проект InventDimTest, в котором содержится таблица и форма поддерживающие складские аналитики как я описал выше.

=A=L=X=