Как сделать поле обязательным на странице NAV?

Кажется, что основная природа NAV состоит в том, чтобы сопротивляться обязательному заполнению поля. В случае нашей бизнес-логики некоторые поля должны быть заполнены, чтобы данные были действительными. Например, запись о клиенте должна содержать как минимум имя и номер телефона. Я искал несколько мест, но не нашел подходящего решения. Итак, как это можно сделать?


person Doug J. Huras    schedule 19.12.2012    source источник
comment
Чем ваше решение отличается от базового приложения NAV? Другими словами, базовое приложение обычно проверяет действительность основных данных после того, как эти основные данные используются в данных процесса; почему этот подход невозможен для вашего решения? Посмотрите, сколько кода вам нужно, чтобы не следовать обычным шаблонам? Я считаю, что это должно вам что-то сказать?!   -  person Jan Hoek    schedule 20.12.2012
comment
Кроме того, если вы собираетесь переопределить OnNextRecord, не должны ли вы также переопределить OnFindRecord? Я думаю, что это будет выполнено, когда пользователи решат перейти непосредственно к первой или последней записи?   -  person Jan Hoek    schedule 20.12.2012
comment
Проблема, с которой мы столкнулись, заключалась в том, что вы могли создать нового клиента (товары и поставщики также имеют эту проблему, насколько нам известно), если вы закрываете ключевое поле, создается запись клиента. Тогда вы можете закрыть страницу, даже не вводя имя или номер телефона, и иметь пустую запись клиента, которую нужно будет удалить вручную. Логика, которую я здесь описываю, была способом, который я придумал, чтобы остановить это. Существуют и другие способы проверки/валидации полей, но нам нужна была единая проверка, когда страница закрывается или пользователь уходит с нее.   -  person Doug J. Huras    schedule 20.12.2012


Ответы (3)


После попыток найти краткий способ потребовать заполнения определенных полей на карточке, я придумал следующее, и это (пока) работает для меня. Я начал понимать, что в NAV не должно быть обязательных полей, но они нужны мне для нашей бизнес-логики. В любом случае, поехали...

Шаг первый. У нас есть codeunit для различной логики проверки, в который я добавил функцию для чтения пользовательской таблицы со списком обязательных таблиц и их полей. Эта функция принимает номер таблицы, ключевое поле и «режим создания». Он возвращает текстовое значение «статус завершения». Я нахожу таблицу для записи, которую я проверяю. Я перебираю обязательные поля, если поле не заполнено, я добавляю его в список незаполненных полей. Если список незавершенных полей пуст, статус завершения «выполнено». Если список неполных полей заполнен, отображается сообщение с указанием отсутствующих полей и дает пользователю возможность отменить создание новой записи или остаться на (новой или существующей) записи и ввести недостающие данные, а также Статус завершения установлен на «удалить», чтобы отменить создание, или «вернуться», чтобы остаться в записи. Логика следующая:

CheckMadatoryFields(TableNumber : Integer;KeyField : Code[10];CreateMode : Boolean)   Completion Status : Text[30]

// Read the 'LockoutFields' table to find the manditory fields for the table passed in.
LockoutFields.RESET;
LockoutFields.SETRANGE("Table No.", TableNumber);
LockoutFields.SETFILTER("Filter ID", 'MANDITORY_FIELD');

// Get a record reference for the table passed in
RecRef.OPEN(TableNumber);
RecRef.SETVIEW('WHERE("No." = FILTER(' + KeyField + '))');

// Set this to done, i.e. data is complete (don't delete by mistake).
CompletionStatus := 'done';

IF RecRef.FINDFIRST THEN BEGIN

// Check the record's manditory field(s) listed in the 'LockoutFields' table to see if they're blank.
  IF LockoutFields.FINDSET THEN BEGIN
    REPEAT
    FldRef := RecRef.FIELD(LockoutFields."Field No.");

    IF FORMAT(FldRef.VALUE) = '' THEN
      FldList := FldList + ' - ' + FldRef.CAPTION + '\';

  UNTIL LockoutFields.NEXT = 0;

END;

IF FldList <> '' THEN BEGIN
  // If creating the record, add the 'Cancel Create' message, otherwise don't.
  IF CreateMode THEN
    DeleteRecord := CONFIRM(Text_ManditoryField + '\' + FldList + '\' + Text_CancelCreate, FALSE)
  ELSE BEGIN
    DeleteRecord := FALSE;
    MESSAGE(Text_ManditoryField + '\' + FldList, FALSE);
  END;

  // Return a 'delete' status when deleting, or a 'return' status to stay on the record.
  IF DeleteRecord THEN
    CompletionStatus := 'delete'
  ELSE
    CompletionStatus := 'return';
  END;
END;

RecRef.CLOSE;`

Шаг 2: - На карточке, которую вы хотите проверить на наличие обязательных полей, в моем случае на карточке клиента, я добавил функцию для вызова функции проверки в кодовом модуле, описанном выше. Я также добавил логику в триггер OnQueryClosePage для вызова моей локальной функции. Все это работало нормально, так как пользователь не мог закрыть карточку клиента, не заполнив обязательные поля или не отменив создание клиента, кроме, если бы пользователь использовал Ctrl+PgUp или Ctrl+PgDn, что снял их с учета. Хитрость заключалась в том, чтобы поместить правильную логику в триггер OnNextRecord, чтобы проверка выполнялась, а Ctrl+PgUp или Ctrl+PgDn все еще функционировали (примечание: я нашел этот бит где-то на mibuso, большое спасибо!). Логика следующая:

OnNextRecord(...)
IF CheckManditoryFields = TRUE THEN BEGIN
  Customer := Rec;
  CurrentSteps := Customer.NEXT(Steps);
  IF CurrentSteps <> 0 THEN
    Rec := Customer;
  EXIT(CurrentSteps);
END;

OnQueryClosePage(...)
EXIT(CheckManditoryFields);

CheckMandatoryFields() ExitValue : Boolean
// Check for manditory fields on this table.  If there are missing manditory
// fields, the user can cancel this create, in which case, a 'TRUE' value is
// returned and we'll delete this record.

ExitValue := TRUE;

IF Rec."No." <> '' THEN BEGIN  // This is blank if user quits immediately after page starts.
  CompletionStatus := HHValidation.CheckManditoryFields(18,Rec."No.",CreateMode);

  IF (CompletionStatus = 'delete')
  AND (CreateMode = TRUE) THEN  // User cancelled create (not edit), delete the record and exit.
    Rec.DELETE(TRUE)
  ELSE
    IF CompletionStatus = 'done' THEN  // User completed manditory fields, OK to exit.
      ExitValue := TRUE
    ELSE
      ExitValue := FALSE;  //User did not complete manditory fields and wants to return and add them.
END;

Я думаю, что об этом. Детали пользовательской таблицы действительно зависят от того, как вы хотите ее закодировать. Блок кода проверки может быть таким, каким вы хотите его видеть. Использование таблицы позволяет добавлять или удалять обязательные поля без изменения какой-либо логики, и эта «общая» логика проверки может быть размещена на любой странице. Ключом являются два триггера на карте и наличие общей процедуры проверки для вызова.

person Doug J. Huras    schedule 19.12.2012

Я использовал этот код в форме (классический клиент), но в коде OnNextRecord есть одна ошибка.

OnNextRecord(...)
IF CheckManditoryFields = TRUE THEN BEGIN
  Customer := Rec;
  CurrentSteps := Customer.NEXT(Steps);
  IF CurrentSteps <> 0 THEN
    Rec := Customer;
  EXIT(CurrentSteps);
END;

Вы также должны охватить ситуацию, когда CheckMandatoryFields возвращает FALSE. В противном случае, когда я запрашиваю следующую запись, она показывает мне пустую запись. Это должно быть так:

OnNextRecord(...)
IF CheckManditoryFields = TRUE THEN BEGIN
  Customer := Rec;
  CurrentSteps := Customer.NEXT(Steps);
  IF CurrentSteps <> 0 THEN
    Rec := Customer;
  EXIT(CurrentSteps);
END ELSE
  EXIT(Steps);
person user3041475    schedule 27.11.2013
comment
OK. Хорошо знать. Я буду иметь это в виду в следующий раз, когда я буду в этой логике. - person Doug J. Huras; 27.11.2013

В функции OnNextRecord есть еще одна ошибка:


    OnNextRecord(...)
    IF CheckManditoryFields = TRUE THEN BEGIN
      Customer := Rec;
      CurrentSteps := Customer.NEXT(Steps);
      IF CurrentSteps  0 THEN
        Rec := Customer;
      EXIT(CurrentSteps);
    END ELSE
      EXIT(Steps);

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

Вместо того, чтобы назначать Rec клиенту, вы должны скопировать его:


    OnNextRecord(...)
    IF CheckManditoryFields THEN BEGIN
      Customer.COPY(Rec);
      CurrentSteps := Customer.NEXT(Steps);
      IF CurrentSteps  0 THEN
        Rec := Customer;
      EXIT(CurrentSteps);
    END ELSE
      EXIT(Steps);

person Shedman    schedule 23.06.2017