О создании новой номерной серии подробно написано в Developer's Best Practice Handbook и в совете Номерные серии в Microsoft Axapta. В этом совете Максим Горбунов останавливается на работе с непрерывными номерными сериями.

Максим Горбунов, maxim@mazzy.ru

Как программисту работать с непрерывной номерной серией?

Вариант 1. Неудачный.

Первое, что обычно приходит в голову, перекрыть метод initValue() на таблице, в которой будет использоваться номерная серия, и написать в нем что-то вроде:

numSeq = NumberSeq::newGetNum(
MyModuleParameters::numRefMyId(), false, true);
if (numSeq)
    this.MyId = numSeq.num(); 

После первых экспериментов обнаружим, что все, вроде бы, работает, номера выделяются, счетчик номерной серии увеличивается. Казалось бы, что еще нужно?

Настроим номерную серию, на которую ссылается наша ссылка, так, что допускается увеличение номера, но не допускается уменьшение. Попробуем заполнить нашу таблицу. В этот момент мы обнаружим, что настройку номерной серии Axapta полностью игнорирует. Что делать? Очевидный ответ – контролировать настройку самостоятельно. А каким образом проводить контроль? Как только мы задумаемся об этом, станет ясно, что такую проверку невозможно осуществить, перекрывая методы таблиц. Дело в том, что между созданием записи (вызовом метода initValue ()) и ее сохранением (вызовом методов validate*() и write ()) необходимо где-то хранить значение, которое вернул счетчик номерной серии (то есть значение до пользовательского вмешательства), а методы таблиц работают каждый в своем пространстве переменных.

Примечание: Вариант с использованием фиктивного поля в таблице в качестве общей переменной я не рассматриваю в связи с его (а) сложностью и, вследствие этого, (б) непрозрачностью и (в) «неиспользованием» в стандартной Axapta.

 

Вариант 2. Сложный.

Итак, будем перекрывать методы Data Source в форме. В initValue () появится примерно такой код:

numSeq = NumberSeq::newGetNum(
MyModuleParameters::numRefMyId(), false, true);
if (numSeq) {
    lastNum = numSeq.num();
    MyMainTable.MyId = lastNum;
} 

В validateWrite () добавим проверки, соответствующие настройке.


NumberSequenceTable numSeqTable = 
MyModuleParameters::numRefMyId().numberSequenceTable();
;
ok = true;
if (numSeqTable) { 
    ok = ok && numberSeq::checkChangeNumber(numSeqTable, 
      tableNum(MyMainTable), 
      fieldNum(MyMainTable, MyId),
      lastNum,
      MyMainTable.MyId);
}

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

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

 

Вариант 3. Простой и понятный.

Итак, за проверку допустимости изменения номера, а так же за поддержку непрерывности номерных серий отвечает класс NumberSeqFormHandler. Как его использовать? Очень просто, нужно всего лишь выполнить шесть простых шагов:

  1. Добавьте в classDelcaration формы переменную типа NumberSeqFormHandler .
  2. Создайте get-метод numberSequenceFornHandler(), в котором напишите примерно следующее:
if (!numberSeqFormHandler) { 
    numberSeqFormHandler = numberSeqFormHandler::newForm( 
      MyModuleParameters::numRefMyId().NumberSequence, 
      element, 
      MyMainTable_DS, 
      fieldNum(MyMainTable, MyId));
}
return numberSeqFormHandler; 

Альтернативным, и не менее правильным вариантом может быть инициализация объекта в методе init() формы или Data Source, однако в стандартном функционале Axapta чаще используется именно get-метод.

  1. В методе close() формы добавьте следующие строки до вызова super():
if (numberSeqFormHandler)
    numberSeqFormHandler.formMethodClose(); 
  1. В метод create() Data Source формы добавьте до вызова super():
element.numberSeqFormHandler().formMethodDataSourceCreatePre();  

А после super():

element.numberSeqFormHandler().formMethodDataSourceCreate();
  1. До вызова super() добавьте в методы Data Source:
    • В linkActive():
      element.numberSeqFormHandler().formMethodDataSourceLinkActive();
    • В delete():
      element.numberSeqFormHandler().formMethodDataSourceDelete();
    • В write():
      element.numberSeqFormHandler().formMethodDataSourceWrite();
  1. И, наконец, в метод validateWrite() после вызова super() добавьте:
ret = element.numberSeqFormHandler().
formMethodDataSourceValidateWrite(ret) && ret; 

А можно просто перетащить весь этот код из, например, формы CustTable, разумеется, заменив при этом название таблицы и имя поля в вызове конструктора NumberSeqFormHandler.

Максим Горбунов, maxim@mazzy.ru