似乎 NAV 的基本性质是抵制要求填充字段是强制性的。对于我们的业务逻辑,必须填充某些字段才能使数据有效。例如,客户记录必须至少有姓名和电话号码。我搜索了很多地方,但没有找到合适的解决方案。那么如何实现呢?
3 回答
在努力寻找一种简洁的方法来要求填充卡片上的某些字段之后,我想出了以下内容,并且它(到目前为止)对我有用。我开始感觉到 NAV 并不意味着必须有必填字段,但我需要它们用于我们的业务逻辑。无论如何,我们走吧……
第一步: - 我们有一个用于各种验证逻辑的代码单元,我在其中添加了读取自定义表格的功能,该表格列出了必填表格及其字段。该函数采用表号、关键字段和“创建模式”。它返回一个文本“完成状态”值。我找到了我正在验证的记录的表格。我遍历必填字段,如果未填充该字段,我将其添加到不完整字段列表中。如果未完成字段列表为空,则完成状态为“完成”。如果填充了不完整字段的列表,则会显示一条消息,指示缺少的字段,并允许用户选择取消创建新记录或保留在(新的或现有的)记录上并输入缺少的数据,并且完成状态设置为“删除” 取消创建,或“返回”以保留记录。逻辑如下:
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);