AX2012提供两种类型的Alert,Change-based alert和Due-date-based alert,前者用于在对新建记录、删除记录、记录的某个指定字段被改变的时候发出提醒,后者则是用于监视记录日期类型的某个字段,在超期指定的日期后发出提醒。在记录的编辑form或者list page上右键菜单中咱们能找到“Create alert rule”菜单项,经过它打开alert规则建立窗口。规则建立窗口里咱们能够选择alert要发给谁,只能是一个特定的用户,不能是一个用户组,若是通知须要发送给多个用户只能建立多个alert规则了。另外在咱们能够勾选“Send email”将通知经过邮件的方式发送给用户,要使用这个功能必须设置好Alert邮件模板,首先在Organization administration>Setup>Email-template建立一个Alert的邮件模板(非系统邮件模板),邮件模板中能够添加占位符变量,在生成具体的邮件时指向真实的数据。Alert邮件模板的例子能够在https://technet.microsoft.com/en-us/library/aa834376.aspx找到。建立好邮件模板后,咱们还须要到Organization administration>Setup>Alerts>Alert parameter选择这个邮件模板为咱们的Alert邮件模板。全部的通知规则咱们能够在Organization administration>Setup>Alerts>Alert rules找到,在这里能够管理建立好的通知规则,使能或者删除规则等。通知规则列表有一列叫作Organiztion-wide,这个不是能手工修改的,若是咱们对公司无关的表(好比workers、products)添加规则时会自动打勾。html
通知规则建立好后不等于在记录改变时你就能收到Alert消息,咱们还须要配置两个Batch job,由它们来处理发出通知消息。一个是 System administration>Periodic>Alerts> Change based alerts,由它处理change-based通知。另外一个是 System administration>Periodic>Alerts>Due date alerts,由它出来due-date-based通知。ide
先来看Change-based的批处理任务,它运行的类是EventJobCUD,它只是判断EventCUD表中是否要处理的Alert事件,若是有则交由EventJobCUDTask处理。EventJobCUDTask读取EventCUD须要处理的记录的用户ID,经过runas切换到该用户运行EventJobCUDTask.runCudEventsForUser(),runCudEventsForUser依次读取该用户相关的EventCUD记录,而后交由EventProcessorCUD处理。EventProcessorCUD针对事件的类型(更新、删除、建立、主键更改)作不一样的处理,好比更新事件,它从EventCUD的Data字段(Container类型)剥离出被监视记录字段的字段ID、新老值,建立EventTypeCUD对象,保存更新字段的新老值,随后根据通知规则中的通知类型建立相应的EventAction,最后生成相应的事件通知保存在EventInbox表中。若是指定了使用邮件通知,会建立EventActionEmail对象,它负责生成占位符对象数据映射,交由SysEmailTable或者SysEmailSystemTable生成实际的邮件放到SysOutgoingEmailTable等候发送。处理成功后相关记录在EventCUD中被删除。这里只是对处理过程作了简单的陈述,实际的过程要复杂得多,须要处理表继承已经通知规则中指定的记录过滤查询等。函数
能够看出change-based通知的核心是处理EventCUD的记录,那么这个表中的数据是从哪里来的呢?微软的解释是使用database log来检测记录更改,alert模块在xApplication类的EventInsert、EventUpdate、EventDelete注册本身的回调函数,若是通知规则中涉及到的表发生变化将更改记录到EventCUD表。能够看到的是若是咱们添加一个通知规则,在表DatabaseLog中会相应增长一条记录,记录对哪一个表作EventXXX类型的log。System administration > Setup > Database > Database log setup看不到这些记录,这个form不显示和EventXXX类型的DatabaseLog。在通知规则监视的表记录修改后,其修改记录在System administration > Inquries > Database > Database log也是看不到的,可是在EventCUD中会增长相关记录。xApplication是系统类,看不到具体是如何实现的。ui
再来看Due-Date-based的批处理任务,它运行的是EventJobDueDate,它读取EventRule表中Due-date类型的通知规则的用户ID,也是runas切换到该用户执行runDueDateEventsForUser(),在runDueDateEventsForUser中调用EventProcessorDueDate.processRule()来处理当前的EventRule,从EventRule中读取记录过滤Query,读取Query中的记录,调用EventProcessorDueDate.processRecord()处理记录,若是日期字段超期,也是根据通知规则中的通知类型建立相应的EventAction,后面的过程和change-based相似了。若是通知规则已经触发并成功处理,该通知规则会被添加到表EventRuleIgnore中,后续再也不触发(在EventTypeDue.canExecute()判断)。spa
在了解了Alert如何工做的后,咱们能够添加自定义的事件类型(EventType)和自定义的事件处理动做(EventAction),能够参见https://msdn.microsoft.com/en-us/library/aa673670.aspx。code
通知消息是保存在表EventInbox中的,在user options的Notification一节咱们能够设置接受通知的时间间隔,客户端按照时间间隔读取通知消息,若是通知设置了须要显示弹窗,AX client会弹出弹窗。能够想见的是直接操做EventInbox来建立用户通知,网上有不少例子,这里截取一个(http://daxldsoft.blogspot.com/2012/10/create-custom-alert-for-ax-with-go-to.html):orm
public static void CreateAlert(str message, str subject, UserId userId = curUserId(), NoYes showPopup = NoYes::Yes, NoYes sendEmail = NoYes::No, Common record = null, str dataSourcename = '', MenuFunction menuFunction = null) { EventInbox inbox; DictTable table; EventContextInformation eci; EventInboxData inboxData; Args args = new Args(); List list; EventInboxId inboxId = EventInbox::nextEventId(); FormRun formRun; WorkflowRecordCaptionGenerator recordCaptionGenerator; UserInfo userInfo; inboxId = EventInbox::nextEventId(); inbox.initValue(); inbox.ShowPopup = showPopup; inbox.Subject = subject; inbox.Message = message; inbox.SendEmail = sendEmail; inbox.EmailRecipient = SysUserInfo::find().Email; inbox.UserId = userId; inbox.InboxId = inboxId; inbox.AlertCreatedDateTime = DateTimeUtil::getSystemDateTime(); if (record) { table = new DictTable(record.TableId); eci = new EventContextInformation(); if (!menuFunction) { menuFunction = new MenuFunction(table.formRef(),MenuItemType::Display); if (!menuFunction) throw error(strFmt("@SYS104114",table.formRef())); } //Build the data to drill down to from the notification args.menuItemName(menuFunction.name()); args.menuItemType(MenuItemType::Display); args.name(menuFunction.object()); eci.parmPackedArgs(args); eci.parmAlertBuffer(record); eci.parmAlertFormDsName(dataSourceName); //eci.parmDontUseFormRunFromMenuItem(true); inboxData.InboxId = inboxId; inboxData.DataType = EventInboxDataType::Context; inboxData.Data = eci.pack(); inboxData.insert(); inbox.AlertTableId = table.id(); inbox.ParentTableId = table.id(); recordCaptionGenerator = WorkflowRecordCaptionGenerator::construct(record); inbox.AlertedFor = recordCaptionGenerator.caption(); list = SysDictTable::getUniqueIndexFields(table.id()); if (list) { inbox.keyFieldList(list.pack()); inbox.keyFieldData(SysDictTable::mapFieldIds2Values(list,record).pack()); } inbox.CompanyId = record.company(); } inbox.insert(); }
使用上面的函数来建立Alert:htm
static void Job155(Args _args) { InventTable inventTable; select firstOnly inventTable; DEVUtils::CreateAlert("message", "subject", curUserId(), true, false, inventTable, "InventTable", new MenuFunction(menuitemDisplayStr(EcoResProductDetailsExtended), MenuItemType::Display)); }
上面的CreateAlert函数有个sendEmail参数,对应EventInbox的字段SendEmail,把这个参数设置为true,咱们也不会收到邮件,由于咱们只是标记了这个字段,我没有找到系统中有好比batch job来将EventInbox经过邮件发送出去。对象