设置预订规则

Field Service 中的预订规则创建用户在基于自定义条件创建或编辑资源预订记录时看到的警告或错误消息。 例如,预订规则可以创建以警告用户他们在其中尝试创建资源的工作订单的日程安排板没有该作业所需的技能。

预订规则是自定义的 JavaScript 方法,它们将在创建或编辑可预订资源预订记录之前执行。 JavaScript 方法可以接受包含正在创建的可预订资源预订记录的信息的参数,并且必须返回具有必需属性的 JavaScript 对象。

设置预订规则可以在预订创建或修改时对其进行验证。

备注

  • 预订规则仅适用于每小时视图,而不适用于日程安排板和日程安排助理的每天、每周或每月视图。 当通过可预订资源预订窗体创建或更新预订时,它们也可用。
  • 如果在窗体上启用了业务流程流,则预订规则不适用于可预订资源预订窗体。
  • 预订规则不适用于日程安排板上的重新分派功能。
  • 每个自定义预订规则只能返回一个错误/警告。 要返回多条消息,为每个验证设置单独的预订规则。

创建解决方案

设置预订规则的第一步是创建自定义 JavaScript Web 资源。 我们建议您在 CRM 中创建一个解决方案来添加自定义 JavaScript Web 资源,或使用您可能要用来自定义的现有解决方案。

创建 CRM 解决方案

  1. 设置>解决方案,为您的预订规则 JavaScript Web 资源创建一个新解决方案。

下面的屏幕截图显示了一个新创建的解决方案。 建议您的解决方案使用唯一发布者,而不是默认发布者。

Field Service 预订规则的屏幕截图。

  1. 创建解决方案后,选择 Web 资源组件,创建新的 Web 资源。
  2. 在新 Web 资源窗体上,输入以下信息:a. 名称 b. 显示名称 c. 类型选择脚本(Jscript)
  3. 选择文本编辑器选项为预订规则输入 JavaScript 代码。
  4. 选择保存保存 Web 资源。
  5. 选择发布以确保预订规则 Web 资源已发布。

新 Web 资源的屏幕截图。

设置预订规则

  1. 从主菜单,转到 Field Service>资源,然后选择预订设置下的预订规则

    Field Service 中可用预订规则列表的屏幕截图。

  2. 选择 +新建创建新的预订规则。

  3. 在预订规则窗体,输入以下信息:a. 名称 b. Web 资源(选择最近创建的 Web 资源)。 c. 输入您在 JavaScript 中定义的方法名称。

    预订规则的屏幕截图。

  4. 保存您的预订规则。 保存预订规则后,它将由日程安排板和日程安排助理的每小时视图或实体窗体使用。 您可以停用预订规则记录,以阻止日程安排板、日程安排助理或预订实体窗体执行规则。

备注

预订规则当前仅在日程安排板和日程安排助理的每小时视图中受支持。 当使用可预订资源预订窗体创建或更新预订时,也支持预订规则。 预订规则在删除预订记录时执行。 使用多重编辑时,预订规则在窗体上不起作用。

创建 CRM 操作

在本节中,我们将查看一个示例,其中演示了如何使用自定义 CRM 操作在预订规则过程中执行验证。

当使用 CRM 操作进行预订规则验证时,您仍然需要按照上面定义的步骤创建自定义 Web 资源。 您将在自定义 Web 资源中定义的 JavaScript 将调用自定义 CRM 操作,并评估来自自定义 CRM 操作的结果。 有关可用于调用自定义 CRM 操作的示例代码,请参阅本文档末尾的附件 A。

需要在 CRM 中创建自定义 CRM 操作。 我们建议您使用已为自定义 Web 资源定义的 CRM 解决方案来添加您的自定义 CRM 操作。

自定义 CRM 操作应具有以下输入和输出参数。 您可以根据需要添加更多输入和输出参数。 您需要确保为调用自定义 CRM 操作而定义的 JavaScript 进行更新,以支持您的其他输入和输出参数。

输入参数:

  • originalScheduleStart – 日期/时间
  • originalScheduleEnd – 日期/时间
  • originalBookableResource – EntityReference
  • originalScheduleSource – 选择列表
  • newScheduleStart – 日期/时间
  • newScheduleEnd – 日期/时间
  • isCreate – 布尔
  • isUpdate – 布尔

输出参数:

  • isError – 布尔
  • isWarning – 布尔
  • errorMessage – 字符串
  • warningMessage - 字符串

以下屏幕截图显示了自定义 CRM 操作的示例。 此示例在检查 newBookableResource 是否与工作订单上的“首选资源”匹配,以及 newScheduleStart 是否在承诺开始时间承诺结束时间之内。 假定承诺窗口日期为单个日期。 示例:承诺开始时间:2016 年 1 月 1 日上午 8:00/承诺结束时间:2016 年 1 月 1 日中午 12:00。

自定义 CRM 操作的屏幕截图。

示例代码

您创建的 JavaScript 函数可以接受单个参数,此参数被视为预订上下文。 传递的预订上下文参数不是客户端脚本编写中使用的典型 CRM 上下文。

预订上下文架构:

export type BookingRuleContext = {
    oldValues: BookingRuleBookingRecord;
    newValues: BookingRuleBookingRecord;
    isCreate: boolean;
    isUpdate: boolean;
};
 
export type BookingRuleBookingRecord = {
    ResourceRequirementId?: string;
    ResourceId?: string;
    StartTime?: Date;
    EndTime?: Date;
    ResourceScheduleSource?: string;
};

预订上下文参数将具有以下 JavaScript 定义。

备注

没有必要在预订规则的自定义 Web 资源中包含此 JavaScript 代码。

ResourceScheduleSource 的可能值来自资源计划源全局选项集。 您可以利用此属性来了解预订规则是从日程安排板还是从日程安排助理触发的。

    var sbContext = {
    oldValues: {
        StartTime: "01/01/2016 08:00AM",
        EndTime: "01/01/2016 05:00PM",
        ResourceId: "00000000-0000-0000-0000-00000000",
        ResourceScheduleSource: 690970001
    },
    newValues: {
        StartTime: "01/01/2016 08:00AM",
        EndTime: "01/01/2016 05:00PM",
        ResourceId: "00000000-0000-0000-0000-00000000",
        ResourceScheduleSource: 690970001
    },
    isCreate: true,
    isUpdate: false
    };

您的验证方法必须返回具有以下定义的 JavaScript 对象。

备注

没有必要在预订规则的自定义 Web 资源中包含此 JavaScript 代码。

    var ruleResult = {
    IsValid: false,
    Message: "Some Message Here",
    Type: "error" // this can be either "error" or "warning"
};

示例 JavaScript 函数定义。 下面的 JavaScript 代码是您需要包含在自定义 Web 资源中的唯一 JavaScript 代码。


    function Validate(ctx) {
      var url = Xrm.Page.context.getClientUrl();
      var ruleResult = {
  	IsValid: false,
       Message: '',
       Type: 'error'
      };

      //
      // perform some lookups or other validation logic here.
      //
  
      ruleResult.IsValid = false;
      ruleResult.Message = 'Some Error Message Here.';
      ruleResult.Type = 'error';

      return ruleResult;
    }

以下 JavaScript 可用于调用具有与上一示例相同的输入和输出参数的自定义 CRM 操作。

在预订规则记录中,方法名称必须为:MSFSAENG.ScheduleBoard.Validate。 如需参考,请参见本文的“设置预订规则”一节中的屏幕截图。


    /// <reference path="xrm.d.ts" />
    function brErrorCallback(sb) {
    // Add custom error handeling here if desired.
     return;
    }
    function brWarningCallback(sb) {
    // Add custom warning handeling here if desired.
    return;
    }
    function brSuccessCallback(sb) {
    // add custom sucess handeling here if desired.
    return;
    }
    var MSFSAENG;
    (function (MSFSAENG) {
    MSFSAENG.ScheduleBoard = {
        url: Xrm.Page.context.getClientUrl() + "/api/data/v8.1/",
        actionName: "msfsaeng_MSFSAScheduleBoardRuleActionSample",
        actionInputParameters: function (ctx) {
            var inputParameters = {};
            if (ctx.isUpdate) {
                inputParameters = {
                    "originalScheduleStart": ctx.oldValues.StartTime,
                    "originalScheduleEnd": ctx.oldValues.EndTime,
                    "originalBookableResource": {
                        "@odata.type": "Microsoft.Dynamics.CRM.bookableresource",
                        "bookableresourceid": ctx.oldValues.ResourceId,
                        "name": ""
                    },
                    "originalScheduleSource": ctx.oldValues.ResourceScheduleSource,
                    "newScheduleStart": ctx.newValues.StartTime,
                    "newScheduleEnd": ctx.newValues.EndTime,
                    "newBookableResource": {
                        "@odata.type": "Microsoft.Dynamics.CRM.bookableresource",
                        "bookableresourceid": ctx.newValues.ResourceId,
                        "name": ""
                    },
                    "newScheduleSource": ctx.newValues.ResourceScheduleSource,
                    "isCreate": ctx.isCreate,
                    "isUpdate": ctx.isUpdate
                };
            }
            else {
                inputParameters = {
                    "newScheduleStart": ctx.newValues.StartTime,
                    "newScheduleEnd": ctx.newValues.EndTime,
                    "newBookableResource": {
                        "@odata.type": "Microsoft.Dynamics.CRM.bookableresource",
                        "bookableresourceid": ctx.newValues.ResourceId,
                        "name": ""
                    },
                    "newScheduleSource": ctx.newValues.ResourceScheduleSource,
                    "isCreate": ctx.isCreate,
                    "isUpdate": ctx.isUpdate
                };
            }
            return JSON.stringify(inputParameters);
        },
        ctx: null,
        ruleResult: {
            IsValid: true,
            Message: "",
            Type: ""
        },
        outputParameters: {
            isError: false,
            isWarning: false,
            errorMessage: "",
            warningMessage: ""
        },
        Validate: function (context) {
            this.ctx = context;
            ScheduleBoardHelper.callActionWebApi(this);
            return this.ruleResult;
        },
        errorCallback: brErrorCallback,
        warningCallback: brWarningCallback,
        successCallback: brSuccessCallback
    };
    var ScheduleBoardHelper = (function () {
        function ScheduleBoardHelper() {
        }
        ScheduleBoardHelper.callActionWebApi = function (sb) {
            var oDataEndpoint = sb.url + sb.actionName;
            var req = new XMLHttpRequest();
            req.open("POST", oDataEndpoint, false);
            req.setRequestHeader("Accept", "application/json");
            req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
            req.setRequestHeader("OData-MaxVersion", "4.0");
            req.setRequestHeader("OData-Version", "4.0");
            req.onreadystatechange = function () {
                if (req.readyState == 4) {
                    req.onreadystatechange = null;
                    if (req.status == 200) {
                        sb.outputParameters = JSON.parse(req.response);
                        if (sb.outputParameters.isError) {
                            sb.ruleResult.IsValid = false;
                            sb.ruleResult.Message = sb.outputParameters.errorMessage;
                            sb.ruleResult.Type = 'error';
                            if (sb.errorCallback)
                                sb.errorCallback(sb);
                            return;
                        }
                        else if (sb.outputParameters.isWarning) {
                            sb.ruleResult.IsValid = false;
                            sb.ruleResult.Message = sb.outputParameters.warningMessage;
                            sb.ruleResult.Type = 'warning';
                            if (sb.warningCallback)
                                sb.warningCallback(sb);
                            return;
                        }
                        else {
                            sb.ruleResult.IsValid = true;
                            sb.ruleResult.Message = '';
                            sb.ruleResult.Type = '';
                            if (sb.successCallback)
                                sb.successCallback(sb);
                            return;
                        }
                    }
                    else {
                        alert('Error calling Rule Action. Response = ' + req.response + ', Status = ' + req.statusText);
                    }
                }
            };
            req.send(sb.actionInputParameters(sb.ctx));
        };
        return ScheduleBoardHelper;
    }());
    })(MSFSAENG || (MSFSAENG = {}));

其他注释

可预订资源预订已启用以使用预订规则创建用户在基于自定义条件创建或编辑资源预订记录时看到的警告或错误消息。 系统使用预订规则中的 preventDefault。 因此,绑定到 onSaveevent 的业务流程流和其他自定义脚本不能在启用预订规则的可预订资源预订实体上使用。

但是,在保存预订窗体时,可以通过启用下面的设置禁用预订规则的处理,这将允许用户使用业务流程流。 客户端 API 可用于在环境级别启用此设置。

读取设置 msdyn_DisableProcessBookingRulesOnSaveBookingForm 的当前值。

Xrm.Utility.getGlobalContext().getCurrentAppSettings()["msdyn_DisableProcessBookingRulesOnSaveBookingForm"]

启用设置 msdyn_DisableProcessBookingRulesOnSaveBookingForm

Xrm.Utility.getGlobalContext().saveSettingValue("msdyn_DisableProcessBookingRulesOnSaveBookingForm",true,).then(() => {a = "success"}, (error) => {a = error})

禁用设置 **msdyn_DisableProcessBookingRulesOnSaveBookingForm**

Xrm.Utility.getGlobalContext().saveSettingValue("msdyn_DisableProcessBookingRulesOnSaveBookingForm",false,).then(() => {a = "success"}, (error) => {a = error})