1,自定义工资项
定义工资公式的功能是企业工资计算中常见的做法,这其实就像Excel系统中的公式一样的普通。但某位技术员在要自己开发的程序中增加公式系统,那就要开发一个像样的公式解释逻辑了,该工作我们在之前已经介绍过。
不过实际的工作生活中,工资项目常常不是固定不变的,对于某个企业而言,其考核办法也是随时变化的,如果技术员没理解清楚工资业务的变化并进行抽象,那常常导致程序反复修改,客户也很不满意。如奖金发放这个业务逻辑中,原来就只有奖金点数和每点奖金两种部分:
1  | 奖金点数  | 各个员工级别设置不同的资金点数。  | 
2  | 每点奖金  | 根据每个月的业绩和资金点数和落实的每点奖金。  | 
但某天客户新制定的奖金方案要增加部门这个项目,如部门是销售部的才发奖金,这样系统就会有很多变化。
上述例子只是一个客户的情况,但软件开发,一般都想做成产品,要有很多客户,那变化就更多了。
序号  | 客户类型  | 说明  | 
1  | 小单位-销售类  | 销售计提方案复杂,考勤简化。  | 
2  | 小单位-研发类  | 无多少提成方案,考勤严谨。  | 
3  | 大单位-综合类  | 有研发式计提,有销售式计提,有复杂的考勤类生产工资计算公式。  | 
于是,简单定义有多少个工资项目,似乎是非常不明智的做法。让客户来定义工资项目是最好的办法。这也大大降低了开发的成本和实施维护的工作量。
2,技术实现
自定义工资项和公式在技术上需要做如下设计:
序号  | 类型  | 设计项目  | 说明  | 
1  | 对象设计  | 工资字段定义  | 如月工作天数,周末日加班天数,奖金点数,病假小时,餐补,多种类型补贴等。  | 
2  | 对象设计  | 实发工资项目  | 如实发基本工资,实发餐补,实扣请假,实收奖金等等。  | 
3  | 对象设计  | 主类  | 能够引用字段和工资项的内容。  | 
4  | 逻辑设计  | 公式解释  | 解释器使用CKRule的.Net解释逻辑。  | 
5  | 逻辑设计  | 调度模型  | 设计业务程序与CKRule规则引擎的调用逻辑。  | 
6  | 数据库设计  | 允许工资字段设置,实发工资项目设置  | 允许在数据库中定义字段及工资项目。  | 
7  | 界面设计  | 员工工资数据加载  | 可以加载员工的基本工资信息和工资字段信息。  | 
8  | 界面设计  | 工资公式编辑  | 允许用户对工资公式进行编辑。编辑过程要使用到自定义的字段和工资项。  | 
2.1 界面效果图
工资计算界面

界面与原来固定工资项时,有明显分别,如下内容值得注意:
序号  | 项目  | 说明  | 
1  | 数据库  | 每个员工的工资字段信息都是从数据库加载的。  | 
2  | 周期性  | 应该有一个地方定义某个工资周期的字段,如3月份使用这一批字段。  | 
3  | 有效性  | 每个员工使用到的工资字段是不相同的,虽然字段有很多,但该员工使用到的才会被设置。  | 
注意第2点,公式设置时,也有周期性的问题,即有新字段了,就要编辑新的公式。当然对于某个公司而言,有新工资方案才可以有新的公式的。
工资公式编辑界面

公式设置界面也与原来的非常不同,注意如下变化:
序号  | 项目  | 说明  | 
1  | 数据库  | 计算名称那里的信息都是从数据库加载的。(代码偷懒了,没实现)  | 
2  | 资源  | 资源那里基本上没什么关键词了。因为基本上找不到直接定义的字段内容。  | 
3  | 动态取字段  | P(…)是一个动态取字段值的方法,在CKRule中定义的,可返回double类型参数,所以可以使用如下的编写方法。 Round(IIF(状态=="转正",1310/P("月工作天数")*P("转正前天数") + 基本工资/P("月工作天数")*P("转正后天数"),基本工资/P("月工作天数")*P("实际出勤天数")),2)  | 
2.2代码
对象定义
    [Serializable]    public class SalaryCond    {        public string Id { get; set; }        public double 基本工资 { get; set; }        public string 状态 { get; set; }        public string 员工性质 { get; set; }        public string 计薪方式 { get; set; }        public string 姓名 { get; set; }                PRivate 结果定义 _结果 = new 结果定义();        public 结果定义 结果        {            get { return _结果; }            set { _结果 = value; }        }        private List<字段定义> _字段集合 = new List<字段定义>();        public List<字段定义> 字段集合        {            get { return _字段集合; }            set { _字段集合 = value; }        }    }    [Serializable]    public class 字段定义    {        public string 名称 { get; set; }        public double 值 { get; set; }    }    [Serializable]    public class 工资项定义    {        public string 名称 { get; set; }        public bool 正向 { get; set; }        public double 值 { get; set; }    }    [Serializable]    public class 结果定义    {        public double 实发工资 { get; set; }        List<工资项定义> _工资项集合 = new List<工资项定义>();        public List<工资项定义> 工资项集合        {            get { return _工资项集合; }            set { _工资项集合 = value; }        }}加载设置数据
var _table = _access.GetTable("select * from 工资基本信息 order by id").ToList<SalaryCond>(); var _projs = _access.GetTable("select 名称,正向,0 as 值 from 工资项").ToList<工资项定义>(); foreach (var item in _table) { var _subList = _access.GetTable("select 名称,值 from 工资字段 where baseid ='" + item.Id + "'").ToList<字段定义>(); item.字段集合.AddRange(_subList); item.结果.工资项集合.AddRange(_projs); } dgvLst.DataSource = _table; dgvLst.AllowUserToAddRows = false;
规则引擎中定义
在本项目中,公式解释与模型设计工作是由CKRule规则引擎处理的,其调用关系图如下:

(该工具相关信息请访问:www.ckrule.com)
需要设置的内容如下:
序号  | 模块  | 内容  | 代码  | 
1  | 客户规则池定义  | P方法  | double _result = 0; Loop(字段集合,x=>{ if(x.名称 == 字段名称){ _result = x.值; } }); return _result;  | 
2 学习交流 
热门图片 
猜你喜欢的新闻 
新闻热点 2019-10-23 09:17:05 
2019-10-21 09:20:02 
2019-10-21 09:00:12 
2019-09-26 08:57:12 
2019-09-25 08:46:36 
2019-09-25 08:15:43 
疑难解答  |