Кажется, что основная природа NAV состоит в том, чтобы сопротивляться обязательному заполнению поля. В случае нашей бизнес-логики некоторые поля должны быть заполнены, чтобы данные были действительными. Например, запись о клиенте должна содержать как минимум имя и номер телефона. Я искал несколько мест, но не нашел подходящего решения. Итак, как это можно сделать?
Как сделать поле обязательным на странице NAV?
Ответы (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;
Я думаю, что об этом. Детали пользовательской таблицы действительно зависят от того, как вы хотите ее закодировать. Блок кода проверки может быть таким, каким вы хотите его видеть. Использование таблицы позволяет добавлять или удалять обязательные поля без изменения какой-либо логики, и эта «общая» логика проверки может быть размещена на любой странице. Ключом являются два триггера на карте и наличие общей процедуры проверки для вызова.
Я использовал этот код в форме (классический клиент), но в коде 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);
В функции 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);