Named user license报表是用来统计各种授权类型用户数的,这里来看看报表数据具体是如何来的。这是一个SSRS的报表,最主要的数据源是来自于类SysUserLicenseCountReport定义的RDP,在SysUserLicenseCountReport的方法processReport中使用SysUserLicenseMiner::fillUserLicenseCountTmpTbl()填充一个临时表,最核心的部分就是这个方法:

public static void fillUserLicenseCountTmpTbl(SysUserLicenseCountTmp _userLicCountTblTmp, date _reportStateDate)
{
SysUserLicenseCount sulcTbl;
SysUserLicenseList sullTbl;
SecurityUserRole surTbl;
SecurityRole rTbl;
SysRoleLicenseType userRoleLicense;
delete_from _userLicCountTblTmp; ttsbegin; while select validTimeState(_reportStateDate, _reportStateDate) * from sulcTbl
outer join sullTbl
outer join User, SecurityRole from surTbl
join SecurityRole, UserLicenseType from userRoleLicense
join RecId, Name from rTbl
order by sulcTbl.UserLicenseType desc
where (sulcTbl.RecId == sullTbl.SysUserLicenseCount
&& sullTbl.UserName == surTbl.User
&& userRoleLicense.SecurityRole ==surTbl.SecurityRole
&& rTbl.RecId == surTbl.SecurityRole)
{
_userLicCountTblTmp.UserLicenseType = sulcTbl.UserLicenseType;
_userLicCountTblTmp.LicensedCount = sulcTbl.LicensedCount;
_userLicCountTblTmp.ActualCount = sulcTbl.ActualCount;
_userLicCountTblTmp.ValidFor = sulcTbl.ValidFrom;
_userLicCountTblTmp.NetworkDomain =sullTbl.NetworkDomain;
_userLicCountTblTmp.NetworkAlias =sullTbl.NetworkAlias;
_userLicCountTblTmp.Username =sullTbl.UserName;
_userLicCountTblTmp.SecurityRole = rTbl.Name;
_userLicCountTblTmp.SecurityRoleLicenseType = userRoleLicense.UserLicenseType;
_userLicCountTblTmp.insert();
} ttscommit;
}

这里用到好几个表,SysUserLicenseCount保存的是四种用户授权类型(枚举UserLicenseType:Enterprise,Functional,Task,Self serve)相应的用户数;SysUserLicenseList保存的是每个用户的授权记录,其SysUserLicenseCount记录的是表SysUserLicenseCount的recId;SecurityUserRole表不在AOT中,查看数据库得知保存的是每个用户对应的Role,如果一个用户被指定了多个Role,每个Role在这表中对应一条记录,列SecurityRole保存的是具体Role的ID;SecurityRole既不在AOT,连SQL数据库中也没有这个表,好在上面的代码中可以推测是AOT中所有Security roles的列表,这里用到的只是Role的名称;SysRoleLicenseType也不在AOT,但是在SQL数据库中,重要的是SecurityRole和UserlicenseType两个字段,前者记录的是每种Role的ID,后者则是这个Role相应的用户授权类型,每个Role只有一种用户授权类型。

因此上面的代码完成的就是构建一个临时表来记录每个用户的名称、网络别名、对应的每个角色、角色对应的用户授权类型、用户授权类型的授权用户数、用户授权类型的当前使用数。需要注意的是角色“System administrator”和“System user”在表SysRoleLicenseType是没有记录的,如果一个用户只有这两种角色,这个用户不会出现在报表中,但是System administrator仍然会占用一个Enterprise授权,仅仅是System user是不会影响到授权数的。

运行报表总是得到空白的结果,仔细查看发现上面的代码中有一行是有问题的(R3 CU8的系统),“&& sullTbl.UserName == surTbl.User”,查看数据库表SecurityUserRole,User一列实际上保存的是用户的网络别名,更改为“&& sullTbl.NetworkAlias == surTbl.User”后运行报表得到结果,类似:

还需要注意必须切换到DAT公司下才会有数据,用到的表SysUserLicenseCount等等是不保存公司信息的,按照我的理解应该不管在哪个公司下都应该得到相同的结果,可实际上只有切换到DAT公司报表才有数据。

接下来的问题相关表中的数据又是哪里来的呢?在部署系统的时候系统会自动为我们创建一个名为“Named user license count reports processing”的批处理任务,由它更新数据到这些表中,默认一周运行一次。这个批处理任务具体执行的是SysUserLicenseMiner类,run方法调用SysUserLicenseMiner::GenerateUserLicenseCountReportInfo(),我们直接调用这个方法也是可以更新授权数数据的。如果你在批处理列表中找不到这个job,可以调用SysUserLicenseMiner::createBatchJob()为你创建一个。而具体是如何更新的呢?答案自然也是在 SysUserLicenseMiner中,这里就不翻代码了,就别的地方看到的总结一下。AOT中打开一个Menu item,有两个属性是和授权相关的,ViewUserLicense和MaintainUserLicense,前者是查看需要的授权,后者是维护数据需要的授权,它们的值都是前面提到的枚举UserLicenseType。SysUserLicenseMiner的工作就是遍历所有Menu item,找出相应的用户授权,接着遍历用户用户角色,找出每个用户角色对应的用户授权类型,最后遍历每个用户,找出用户的最高用户授权类型(Enterprise最高)。所以问题的核心在于菜单项的用户授权类型,如果我们新建一个自己的菜单项会怎样?默认ViewUserLicense和MaintainUserLicense都是NONE,是不影响授权数的,当然你可以闲着没事修改这两个属性成其他数值。我们可以duplicate系统自带的菜单项,然后修改这两个属性为NONE,后面就不细说了。

最后要说的是这个报表的格式,无论我是否选中“show list of users per access license type ”结果都是一样,Report的design也只有上面图中的一个,有知道原因的朋友请告诉我为什么...

[AX2012 R3]关于Named user license report的更多相关文章

  1. AX2012 R3升级CU8的一些错误

    AX2012 R3安装升级包CU8后进入系统,系统会提示打开软件升级清单“Software update checklist”,清单列出了升级要做的一系列动作. 在进行到编译应用时“Compile a ...

  2. AX2012 R3 Data upgrade checklist sync database step, failed to create a session;

    最近在做AX2012 R3 CU9 到CU11的upgrade时 (用的Admin帐号), 在Date upgrade 的 synchronize database 这步 跑了一半,报出错误 说“fa ...

  3. [AX2012 R3]在SSRS报表中使用QR二维码

    AX2012是自带生成QR二维码的类,可以很方便的用在SSRS报表中,下面演示如何在RDP的报表中使用二维码,首先从定义临时表开始: 字段URL是要用于二维码的字符串,QrCode是container ...

  4. [AX2012 R3]关于Alerts

    AX2012提供两种类型的Alert,Change-based alert和Due-date-based alert,前者用于在对新建记录.删除记录.记录的某个指定字段被改变的时候发出提醒,后者则是用 ...

  5. Squish License

    https://www.froglogic.com/squish/gui-testing/prices-and-licensing/index.php Prices and Licensing Who ...

  6. Maven Build Life Cycle--reference

    What is Build Lifecycle? A Build Lifecycle is a well defined sequence of phases which define the ord ...

  7. GDAL——命令使用专题——gdalinfo命令

    GDAL——命令使用专题——gdalinfo命令  前言 GDAL(Geospatial Data Abstraction Library)是一个在X/MIT许可协议下的开源栅格空间数据转换库.它利用 ...

  8. GDAL——命令使用专题——ogrinfo命令

    GDAL——命令使用专题——ogrinfo命令 前言 GDAL(Geospatial Data Abstraction Library)是一个在X/MIT许可协议下的开源栅格空间数据转换库.它利用抽象 ...

  9. [AWS vs Azure] 云计算里AWS和Azure的探究(2)

    Amazon EC2是Elastic Compute Cloud的简称,翻译成中文就是弹性计算云.它是Amazon云里面最基础的内容,也是发展到今天最成熟的部分,通过EC2, 你可以在Amazon的云 ...

随机推荐

  1. 在myeclipse文件中如何创建properties类型的文件,从而连接数据库

     File->New->File->点击->在编辑处出输入:文件名.properties  文件的主要功能连接数据库,例如: driver=oracle.jdbc.Oracle ...

  2. angular-ui-bootstrap的进度条问题及解决

    在测试angular-ui-bootstrap中的进度条的时候,用的是官方的示例代码,但是跑不起来. 经过代码比对之后,发现官方用的是0.14.3, 而我本地用的是0.13.3 (2015-08-09 ...

  3. [J2ME] 基本框架框架

    import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import jav ...

  4. [JS3] 立即执行JS

    <html> <head> <title>立即执行</title> <SCRIPT TYPE="text/JavaScript" ...

  5. 浅谈压缩感知(二十六):压缩感知重构算法之分段弱正交匹配追踪(SWOMP)

    主要内容: SWOMP的算法流程 SWOMP的MATLAB实现 一维信号的实验与结果 门限参数a.测量数M与重构成功概率关系的实验与结果 SWOMP与StOMP性能比较 一.SWOMP的算法流程 分段 ...

  6. Java程序员的日常——《编程思想》一切都是对象

    今天终于看完了第一章,哈哈,万事开头难....刚开始被编程思想的第一章给蒙住了,讲一堆理论,没什么意思.从第二章开始,真正的开始讲解Java相关的内容,有了一定的开发经验后,再次阅读起来,感觉收获良多 ...

  7. iOS-APP发布应注意要点

    Android和IOS的app发布的流程有一个相同之处,就是都需要先将编译好的app签名,然后上传到market里,但两者的复杂度是冰火两重天.Android可以手动通过集成在eclipse里的工具进 ...

  8. 前端框架layui

    可以了解下jQuery组件layer layui开始使用Layui兼容除IE6/7以外的全部浏览器,并且绝大多数结构支持响应式 弹出层如果你使用的是Layui,那么你直接在官网下载layui框架即可, ...

  9. Codeforces Round #379 (Div. 2) 总结分享

    前言 初入acm的新手,打算在cf混.这几天没有比赛,就做了个最新的Virtual participation.虽然说div2比较简单,但还是被虐得体无完肤...Orz.两个小时,共6道题.最后只AC ...

  10. 在VC项目中附加包含目录

    1.VC2010项目中附加包含目录 上图项目中附加了两个文件夹,一个是上级目录下的CommonClass,一个是下级目录下的invengo. 使用这两个目录下的类时直接在include后面写头文件名即 ...