Часто при разработке структуры таблиц нам не хватает поля, которое формируется автоматически. Например, возрастает при добавлении новой записи. Обычно производители СУБД предусматривают простенький механизм – счетчик (counter), который представляет собой числовое поле, автоматически увеличивающее значении при добавлении новой записи. В MBS Axapta к реализации данного механизма подошли довольно серьезно – простенький счетчик заменили номерные серии. Теперь - это уже текстовое поле, с возможностью изменения шаблонов автоматического формирования следующего значения и поддерживаний свойства непрерывности серий. Однако возросшие возможности повлекли за собой и трудности при использовании и настройке и данного механизма. Как правильно использовать номерные серии, и посвящена данная статья.

Нанеишвили Георгий (George Nordic), george_nordic@hotmail.com

Герань и нумераторы

Не надо бояться номерных серий в своих разработках – напротив, их надо активно использовать. Это очень удобный и легкий механизм, заменяющий в Axapta то, что в других системах обычно подразумевают под типом «counter», т.е. счетчик. Надо заметить, что в Axapta он:

Нумерация закупок

Серии документов представляют собой интервалы порядковых номеров документов, и при оформлении каждого нового документа (например, чека или накладной) его номер генерируется на основании шаблона из соответствующей номерной серии и последнего присвоенного значения.

Определение серий документов – это одна из первых задач, с которой придется столкнуться при настройке новой базы. Конечно, поначалу, бывает непонятно, почему при такой, казалось бы, невинной операции, как ввод нового клиента (или поставщика) возникает ошибка:

Текст ошибки

Но экстренное изучение документации и настроек системы обычно быстро раскрывают тайну и зачастую приводят к правильному решению - настройке номерной серии в «CRM» - «Настройки» - «Параметры» - «Номерные серии» - «Отношения» и «Код отношений». Вот так обычно и начинается наше знакомство с данным функционалом.

 

Серии документов

Серии задаются в форме: Серии документов. Вы можете найти эту форму в «Основное» - «Настройки» - «Серии документов».

Серии документов

Перечень полей в таблице номерных серий:

Поле Описание

Код серии документов

Здесь задается код серии документов. О правилах формирования кода– немного ниже.

Название

Название серии документов

Минимум

С этого номера начнется автоматическое увеличение номера серии. По умолчанию предлагается 1.

Максимум

Максимальный номер серии документов. Очень важно распланировать различные серии документов так, чтобы номера документов не перекрывались, по крайней мере, в течение нескольких лет.

 

Следующий

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

Формат

Укажите формат номера. Например, вы можете использовать буквы в качестве префикса

Используется

Данное поле отмечено, если номерная серия уже используется

Вручную

Запретить автоматическое нумерацию. Пользователь должен вводить номер документа вручную

Непрерывная

Признак непрерывной серии. При данной настройке система следит за тем, что бы серия документов использовалась без разрывов в нумерации.

Уменьшение номера

Допустить изменения номера пользователем в сторону уменьшения

Увеличения номера

Допустить изменения номера пользователем в сторону увеличения. Для обеспечения полного доступа пользователя к изменению автоматически сгенерированных номеров установите два последних флага.

Вы можете посмотреть, где используется данная серия документов, по кнопке «Ссылки».

В Microsoft Axapta существуют общие серии для различных документов. Например, можно задать единую нумерацию для счетов-фактур и кредитовых авизо, однако чаще применяется раздельная нумерация.

 

Настройка номерных серий

Для первоначальной настройки всех номерных серий Вы можете использовать мастер создания номерных серий («Основное» - «Настройки» - «Серии документов» - «Мастер»), он автоматически создаст все необходимые номерные серии, но назовет их, на мой взгляд, неудачно. Он формирует код по принципу [4символа модуля, для которого происходит настройка]_[порядковый номер серии]. Таким образом, для номерной серии Сводного Плана получается код «свод_107». Не очень информативно, не так ли? То же он делает и с форматом ввода – просто дописывает к числовому шаблону «_[порядковый номер серии]». Что может сказать шаблон ########_107?

Так что я предпочитаю настраивать все серии вручную. На самом деле, это не столь сложная работа, как кажется. Есть несколько методологий по настройке шаблонов: например, ставить суффикс, обозначающий принадлежность шаблона к той или иной серии, или префикс. Или и то, и другое сразу. Я сторонник школы, ратующий за префиксы.

Примечание: См. также обсуждение суффиксов и префиксов в номерных сериях на axforum.info

Так как серии генерируются автоматически, то отпадает необходимость вводить префикс вручную, зато при поиске документа достаточно будет ввести лишь несколько последних цифр: *1234 – откроет все документы данной серии, оканчивающиеся на 1234. При использовании суффикса на пришлось бы писать «*1234_107» или «*1234_*». А при вводе заключительной «*» в некоторых поисковых формах (lookup'ax) сразу открывается список и автоматически подставляется первое значение. Так что не удивляйтесь, если поиск будет идти по значению «*1234_*00000001_107».

Выпадающий список

Результат выбора из выпадающего списка

Ссылки на номерные серии

При разработке префикса я рекомендую использовать следующее правило его формирования: использовать 4х символьный префикс. Первые 2 символа - обозначение модуля. Например, «ГК» – если настройка этой серии производиться из модуля «Главная Книга», «РК» (Расчеты с клиентами), «РП» (Расчеты с поставщиками), «ОС» (Основные Средства), «ОН» (Основное - Настройки). Следующие 2 символа - Код серии КП (код поставщика), РП (разовый поставщик) и т.д. По крайней мере, при использовании данного метода все понятно и наглядно.

Пример: когда разносится Накладная на услуги, используется 2 номерные серии: одна попадет в товарную накладную, а вторая в Главную книгу. Как бы вы назвали, например, Накладную на услуги, номер которой выводится в товарной накладной и Накладную на услуги, номер которой формируется при разноске в главную книгу? Так как первая серия настраивается из модуля «Расчеты с Клиентами», то её имеет смысл назвать РКНУ (И шаблон, соответственно РКНУ#######). Ту же накладную, которая настраивается из модуля «Главная Книга», имеет смысл назвать ГКНУ (шаблон - ГКНУ#######). И главное – давайте подробное описание в поле «Название». Имя «Главная Книга – Накладная на Услуги» очень, я думаю, подойдет нашему коду «ГКНУ».

Что бы завести новую серию документов, надо задать код серии, наименование, а так же минимальное / максимальное значение номерной серии и формат. Код и Название мы сформировали. Минимальное / Максимальное значение – здесь, я полагаю, сложностей не должно быть. Осталось сформировать формат шаблона, по которому будут формироваться номера документов. Формат задается с помощью символов, которые можно использовать не только в качестве префикса или суффикса, но даже и в середине шаблона, а так же спецсимволов, вместо которых будут подставляться числа или символы.

Спецсимвол «#» указывает место в строке формата, где нужно расположить цифры номера. Так например, если для нумерации счетов-фактур используется формат «РКСФ#####», то счет-фактура с номером 1978 в качестве номера получит строку «сф-01978». Специальные символы можно произвольно чередовать с обычными символами. Так, например, вполне допустим формат «###_РКСФ_##». Тогда та же самая счет-фактура в качестве номера получит строку «019_РКСФ_78». Спецсимвол «&» (только для Axapta 3.0) Он работает аналогично #, только для кодирования используются не цифры, а латинские буквы. Т.е. вместо цифры 0 используется символ A , вместо цифры 1 – B, вместо 2 - С и т.д. Также как и # специальный символ & можно использовать вперемешку с другими символами. Сами символы # и & также можно использовать вперемешку. Так, если указать формат «&&_РКСФ_78», счет-фактура с номером 1978 после форматирования получит в качестве номера строку «AR_сф_78».

Подробнее об использовании спецсимволов я рекомендую почитать на ресурсе, посвященном Axapta http://axapta.mazzy.ru/lib/numbersequenceformat/

 

Создание новой номерной серии

Теперь о том, как создать собственную номерную серию.

Первое, у Вас должно быть четкое представление, зачем нужна номерная серия и как Вы собираетесь её использовать. Детально расписанное техническое задание не обязательно (хотя, конечно, и очень желательно), но общий план действий должен быть уже сформирован. Дело в том, что номерные серии настраиваются из разных модулей. Для пользователя это выглядит следующим образом: он заходит в модуль, например, «Расчеты с клиентами», выбирает «Настройки», потом «Параметры», и на вкладке «Номерные серии» видит ссылки на номерные серии и привязанные к ним серии документов. Иногда путь может и отличаться, например «Основное» - «Настройки» - «Данные о компании». И за каждую такую настройку отвечает свой класс – наследник от NumberSeqReference. Так что, если Вы собираетесь добавлять настройку основной серии в «Расчетах с клиентами» - то Вам надо будет править класс «NumberSeqReference_Customer», а если в «Основном» - то «NumberSeqReference_General». Если же Вы собираетесь писать в своем модуле… Что ж… Все возможно. Вам только придется подправить enum « NumberSeqModule », добавить в него новый элемент. Только, пожалуйста, не надо давать ему номер 88 (Речь идет об Axapta 3.0 SP 3 HF 2, в данной версии у последнего элемента номер 87), а то любой очередной сервис-пак / хотфикс, в котором будет реализовано нечто подобное, то Ваш элемент элементарно, простите за каламбур, накроет ваш элемент своим с тем же номером, но к нему будут подвязаны уже совсем другие задачи. Так что обязательно оставляйте диапазон пустых значений, если Вы дополняете системное перечисление. Дайте ему номер 188, например.

Итак, Ваш класс должен

Но если вы просто добавляете новую номерную серию к существующим, то нет надобности писать свой класс – достаточно немного подправить уже имеющийся. Внимание! У Вас уже должна быть разработана таблица с полем, в которое и будет записываться очередное значение номерной серии. Для этого обязательно создайте свой строковый «Extended Data Type», с длинной не менее 30 символов, хотя рекомендуется просто наследовать его от стандартного типа для номерных серий – типа «Num». Для примера сделаем небольшой пример – разработаем маленькую таблицу, например, с кодами групп менеджеров. Заведем новый тип SalesManagersGroupId и унаследуем его от Num , потом сделаем таблицу с группами менеджеров, которое будет содержать наш новый тип – номер группы и поле – описание группы.

Давайте для примера возьмем уже упоминавшийся NumberSeqReference_General. Обратите внимание на метод loadModule – именно его нам и придется править. Вот пример уже имеющегося кода:

// EGLA, Officials -->
numRef.DataTypeId = typeid2extendedtypeid(typeid(OffSessionId_RU));
numRef.ReferenceHelp = literalStr("@DIS7575");
numRef.ReferenceLabel = literalStr("@DIS7574");
numRef.WizardContinuous = false;
numRef.WizardManual = NoYes::No;
numRef.WizardAllowChangeDown = NoYes::No;
numRef.WizardAllowChangeUp = NoYes::No;
numRef.SortField = 3;
this.create(numRef);
// EGLA, Officials <-- 

Теперь пишем и наш код:

// M 000_ GNRD _ SalesManagersGroupsNumSeq --->
// Укажем, какой тип мы хотим использовать.
// Разумеется, здесь должен быть наш тип – тот,что мы использовали в таблице. numRef.DataTypeId = typeid2extendedtypeid(typeid(SalesManagersGroupId)); // Это будет в подсказке numRef.ReferenceHelp = literalStr("Уникальный идентификатор групп менеджеров"); // А это само имя – его мы видим в графе «Ссылка» при настройке номерных серий. numRef.ReferenceLabel = literalStr("Идентификатор группы менеджеров"); // Настройка мастера. // Если мы решим запустить стандартны мастер, то он // по-умолчанию сформирует нашу серию как «Непрерывную» numRef.WizardContinuous = false; // Допускать изменения пользователем «Вручную» numRef.WizardManual = NoYes::No; // … только на понижении серии numRef.WizardAllowChangeDown = NoYes::No; // … только на повышение номера. numRef.WizardAllowChangeUp = NoYes::No; // Максимальный номер. // Здесь мы предполагаем, что у нас не будет больше 9999 групп менеджеров. numRef.WizardHighest = 9999; numRef.SortField = 3; // Создаем this.create( numRef); //M000_GNRD_SalesManagersGroupsNumSeq <---

К слову сказать, у NumberSequenceReference есть еще пара свойств, типа

numRef.WizardLowest = 1; // Минимальный номер, с которого и начнется отсчет 

но они не так часто используются и их уже легко выучить самостоятельно.

Как грамотно дописать форму с нашей таблицей в виде источника данных, что бы она могла использовать нашу номерную серию? Очень просто!

NumberSeqFormHandler SalesManagersNumberSeqFormHandler; 
public NumberSeqFormHandler SalesManagersNumberSeqFormHandler(
                               FormRun _element,
                               FormDataSource _Form_ds)
{
;
   if (! SalesManagersNumberSeqFormHandler)
   {
      // если не инициализирован, то запускаем конструктор
      // для этого типа данных нашего источника данных
      // в данной таблице, именно для поля, куда будет писатся эта серия
      SalesManagersNumberSeqFormHandler = numberSeqFormHandler::newForm(
         NumberSequenceReference::find(
            TypeId2extendedTypeId(typeid(SalesManagersGroupId))
         ).NumberSequence,
         _element,
         _Form_ds,
         fieldNum(SalesManagersGroups, GroupId)
      );
   }
   return SalesManagersNumberSeqFormHandler;
} 

Потом мы должны не забывать вызывать определенные методы нашего класса по изменению данных в нашем источнике. Эти изменения отрабатываются методами create, validateWrite, write и linkActive (создание нового номера), и delete по удалении записи. Часть этих методов должна быть вызвана до super, часть – после. Вот их реализация, применительно к нашему примеру:

//Create
public void create(boolean _append = false)
{
;
   element.SalesManagersNumberSeqFormHandler(
   	 element, SalesManagersGroups_ds).formMethodDataSourceCreatePre();
     // Обратите внимание, что до SP3 данная строчка не нужна!
   super(_append);
   element.SalesManagersNumberSeqFormHandler(
     element, SalesManagersGroups_ds).formMethodDataSourceCreate();
} 
//ValidateWrite
public boolean validateWrite()
{
   boolean ret;
   ;
   ret = super();
   ret = ret && element.SalesManagersNumberSeqFormHandler(
     element, SalesManagersGroups_ds).formMethodDataSourceValidateWrite();
   return ret;
} 
//Write
public void write()
{
;
   ttsbegin;
   super();
   element.SalesManagersNumberSeqFormHandler(
     element, SalesManagersGroups_ds).formMethodDataSourceWrite();
   ttscommit;
} 
//LinkActive
public void linkActive()
{
;
   element.SalesManagersNumberSeqFormHandler(
     element, SalesManagersGroups_ds).formMethodDataSourceLinkActive();
   super();
} 
//Delete
public void delete()
{
;
   ttsbegin;
   element.SalesManagersNumberSeqFormHandler(
     element, SalesManagersGroups_ds).formMethodDataSourceDelete();
   super();
   ttscommit;
}

В принципе, присвоить новый номер переменной можно и в коде.

NumberSeq SalesManagersNumberSeq;
SalesManagersGroups SalesManagersGroups;
;
 
ttsbegin;
SalesManagersGroups.clear();
SalesManagersGroups.initValue();
SalesManagersNumberSeq = NumberSeq::newGetNum(NumberSequenceReference::find(
     TypeId2extendedTypeId(typeid(SalesManagersGroupId)))
                         );
SalesManagersGroups.GroupId = SalesManagersNumberSeq.num();
SalesManagersGroups.GroupName = "Test Name";
SalesManagersGroups.insert();
ttscommit; 

Отменить создание нового номера можно методом SalesManagersNumberSeq.abort(). Вот, в принципе, и все.

Осталась сделать самую малость – настроить нашу номерную серию!

Настройка нового нумератора

Итак, заходим в «Основное» - «Настройки» - «Данные о компании», закладка «Номерные серии». Вот она – наша серии с гордым названием «Идентификатор группы менеджеров».

Щелкаем правой клавишей и переходим к основной таблице. Вот здесь как раз и заводятся все серии документов, которые в последствии можно привязать к номерной серии той или иной группы документов. Создаем свой шаблон нашей номерной серии, называем его, подвязываем к нашей серии документов и – все! Наш нумератор готов к использованию!

 

Автор выражает благодарность Sonny Wibawa Adi (SonnyWibawaAdi@yahoo.com) за документ How To Add A New Number Sequence Reference in Axapta.

Нанеишвили Георгий (George Nordic), george_nordic@hotmail.com