基于C#的企业工资条自动分发功能的实现

2020-12-14 04:37张柯刘晓光李正雄李金旗贾静
电脑知识与技术 2020年28期
关键词:电子邮件

张柯 刘晓光 李正雄 李金旗 贾静

摘要:以涵盖企业所有员工薪酬信息的Excel文件为输入,结合电子邮件,利用C#编程语言,设计开发企业工资条自动分发程序,解决了开发过程中的一些关键问题,实现了精准便捷的分发功能,大大提升财务人员工作效率,对同类软件的开发具有一定的参考作用。

关键词:C#;Excel;工资条;电子邮件;自动分发

中图分类号:TP391.13      文献标识码:A

文章编号:1009-3044(2020)28-0077-04

Abstract: With the input of an Excel file covering all employee salary information of the enterprise, and combined with E-mail,the enterprise salary bill dispatching program based on C# was designed, which solved some key points in the program development, achieved accurate and convenient dispatching, and greatly improved the efficiency of financial staff. Meanwhile, it provided the idea for further development of a similar system.

Key words: C#; Excel; salary bill; E-mail; dispatching

1 背景簡介

出于方便、及时、私密性的考虑,现如今多数企业选择银行代发的方式来支付员工薪酬。通过银行网上代付业务,可从企业结算账户直接向员工个人结算账户(借记卡、存折)自助发放工资[1]。

受部分企业薪酬保密制度的制约,为使员工及时了解当月薪酬的详细组成,无论是采用手工打印、人工分发工资条的方式,还是利用网络实现远程逐一发放的方式,效率都很低下,且容易出现人为失误导致泄密。当企业人数较多时,采用上述方式,若因工作失误发生遗漏问题,会大大增加核对的时间成本和人工成本,不利于企业降本增效。

财务管理中经常会用到微软Office办公软件套装中的Excel电子表格软件,而包含企业所有员工的工资条文件正是由集中部署ERP系统导出的Excel(.xlsx)文件,那么如何避免上述分发工资条方式的弊端,使工资条文件在导出后能够及时地、准确无误地分发到每位员工手中,是我们要思考的问题[2-4]。

2 设计思路

以存储当月企业所有员工薪酬信息的工资条文件作为输入(下文以“总工资条.xlsx”文件为例,如图1所示,数据为测试数据),以每位员工获取自己的薪酬信息作为输出,考虑到时效性、准确性要求,设计编写工资条自动分发程序,对输入文件进行筛选,从中提取员工姓名、邮箱、薪酬组成等信息,以电子邮箱为媒介,达到短时间内精准分发的效果。

2.1 编程语言选择

C#是一种安全的、稳定的、简单的,由C和C++衍生出来的面向对象的编程语言。它在继承C和C++强大功能的同时去掉了一些复杂特性,它综合了VB简单的可视化操作和C++的高运行效率,使得其在开发运行在.NET平台上的应用程序时极为方便[5-6]。

该工资条自动分发程序采用C#编程语言,操作简单,可读性好,编程环境采用Visual Studio 2019。

2.2 功能设计

参考电子邮箱附件发送的模式,该程序主流程如图2所示,其主要功能如下[7]:

1)处理发件人信息,可一键配置,可手动输入;

2)处理输入文件信息,提取所需数据保存成附件;

3)发送邮件;

4)显示发送成功或失败的信息;

5)显示处理进度。

2.3 界面设计

程序主界面如图3所示,出于方便操作的考虑,设计时将主要功能以按钮的形式体现,通过位置的合理摆放将主界面划分为四个区域,即发件人信息配置区、输入文件读取区、发送成功显示区(上显示窗口)和发送失败显示区(下显示窗口)。

用户只需四步即可完成每月工资条分发:

1)单击“刷新”按钮,浏览并选择“发件信息设置.xml”文件,可在主界面自动配置好用户信息,如图4所示。

2)单击“浏览”按钮,浏览并选择“总工资条.xlsx”文件,当主界面底部进度条加载完毕后,表明已经在后台处理好输入文件,此时在输入文件的同级目录下,会生成“tempDir”文件夹来存储临时文件,文件名格式为“姓名_邮箱.xls”,即一个个待发送的附件,如图5所示。

3)单击“发送”按钮,后台自动遍历“tempDir”文件夹中的所有附件,提取邮箱信息并逐一发送,已发送成功的邮件,将会在主界面的上显示窗口输出信息,发送失败的邮件,将会在主界面的下显示窗口输出信息,如图6所示。若不存在该邮箱,会收到系统退信,如图7所示,该信息不会在下显示窗口输出。此时在输入文件同级目录下,会生成以年月命名的文件夹(如“2020-07”)来存储已发送成功的附件,会生成“errorDir”文件夹来存储发送失败的附件,会删除临时文件夹“tempDir”。

4)根据主界面的下显示窗口中的输出信息,可判断出邮件发送失败的原因,通过检查“errorDir”文件夹中的附件来修正错误(如发现邮箱有误,可直接修改附件名称中的邮箱信息),错误修正后单击“选择errorDir发送失败邮件” 按钮,浏览并选择“errorDir”文件夹,后台自动遍历“errorDir”文件夹中的所有附件,提取邮箱信息并逐一发送,已发送成功的附件会保存在以年月命名的文件夹内,发送失败的邮件会保存在“errorDir”文件夹内。

3 具体实现

3.1 发件人信息的配置与读取

用户可直接在主界面填写发件人、发件服务器、授权码等信息,或者在“发件信息设置.xml”文件中提前配置,后经程序自动读取,避免了在主界面填写时人为错误导致邮件发送失败。读取配置文件的关键代码如下:

string path = "";

if (dialog.ShowDialog() == DialogResult.OK)

{

path = dialog.FileName;

//读取路径下的配置文件并将其中信息显示在相应位置

XmlDocument document = new XmlDocument();

document.Load(path);

XmlNode xmlNode = document.DocumentElement;//获取根节点

XmlNodeList xmlNodeList = xmlNode.ChildNodes;//获取子节点

for (int i = 0; i < xmlNodeList.Count; i++)

{

string name = xmlNodeList[i].Name.ToString();

switch (name)

{

case "addresser":

textBox发件人.Text = xmlNodeList[i].InnerText;

textBox發件人.BackColor = SystemColors.Window;

break;

case "server":

textBox发件服务器.Text = xmlNodeList[i].InnerText;

textBox发件服务器.BackColor = SystemColors.Window;

break;

case "authorization":

textBox授权码.Text = xmlNodeList[i].InnerText;

textBox授权码.BackColor = SystemColors.Window;

break;

case "#comment":

break;

default:

MessageBox.Show("请检查配置文件是否损坏");

break;

}

}

}

3.2 处理输入文件

“总工资条.xlsx”文件作为程序的输入文件,其中包含了企业所有员工的薪酬信息。因为需要对Excel文件进行读取、复制、保存、关闭等一系列操作,考虑使用Microsoft.Office.Interop.Excel程序集较为方便,且容易实现。

首先,需要添加对Microsoft.Office.Interop.Excel的引用。在解决方案资源管理器中找到该项目,右键菜单选择“管理NuGet程序包(N)...”,搜索Excel关键字,找到并选中Microsoft.Office.Interop.Excel进行安装。安装完毕后需在命名空间中添加引用。

利用app. Workbooks的Open()方法打开输入文件,此时是在该文档上进行修改,因此任何的改动都会生效,这里只对该文件进行内容识别、复制等操作,不会对其数据和格式进行改动。该函数返回一个Workbook对象,即要操作的Excel文档对象。关键代码如下:

_Application app;

……

app = new Microsoft.Office.Interop.Excel.Application();

app.SheetsInNewWorkbook = 1;//设定新建工作簿当中默认工作表

Workbook oldWorkbook = app.Workbooks.Open(path);//打开输入文件

Worksheet oldWorksheet = oldWorkbook.Worksheets[1];//获取输入文件第一个工作表

int iMax = 1;//最大行

int jMax = 1;//最大列

string column = "";

for (int i = 0; i < letter.Length; i++)

{

if (oldWorksheet.Range[$"{letter[i]}1"].Value == null)

{

break;

}

column = letter[i].ToString();

jMax = i + 1;

}

int row = 1;

while (!(oldWorksheet.Range[$"A{row}"].Value == null))

{

iMax = row;

row++;

}

中间变量iMax和jMax分别代表输入文件的最大行数和最大列数,以此确定姓名、邮箱的所在列及附件个数,为后续提取信息生成附件做准备。

循环遍历输入文件,每次利用Worksheet. Range.Copy()方法复制输入文件中指定范围的信息到新建Excel文件中的指定范围,将该新建的Excel文件以“姓名_邮箱.xls”的格式命名,作为附件待后续邮件发送时使用。关键代码如下:

……

Workbook newWorkbook = app.Workbooks.Add();//新建一个workbook对象

Worksheet newWorksheet = newWorkbook.Worksheets[1];//获新建工作簿当中第一个工作表

oldWorksheet.Range[$"A1:{column}1"].Copy(newWorksheet.Range["A1"]);oldWorksheet.Range[$"A{i}:{column}{i}"].Copy(newWorksheet.Range["A2"]);

……

name = oldWorksheet.Range[$"B{i}"].Text.Trim();//提取姓名

email = oldWorksheet.Range[$"{column}{i}"].Text.Trim();//提取邮箱地址

string savePath = tempDir + "\\" + name + "_" + email + ".xls";

newWorkbook.SaveAs(savePath, XlFileFormat.xlExcel7);//保存成.xls文件

当输入文件数据量过多时,遍历一次需要新建很多个workbook对象,当操作完毕后选择释放对象,保证内存不受影响;当输入文件遍历完成后,释放输入文件对象,关键代码如下:

……

System.Runtime.InteropServices.Marshal.ReleaseComObject(newWorksheet);

System.Runtime.InteropServices.Marshal.ReleaseComObject(newWorkbook);

……

System.Runtime.InteropServices.Marshal.ReleaseComObject(oldWorksheet);

System.Runtime.InteropServices.Marshal.ReleaseComObject(oldWorkbook);

输入文件处理完毕后,需要及时清除Excel进程,引入public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID)关闭进程,关键代码如下:

[DllImport("User32.dll", CharSet = CharSet.Auto)]

public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);

……

//释放Excel资源,杀死相关进程

IntPtr t = new IntPtr(app.Hwnd);

int k = 0;

GetWindowThreadProcessId(t, out k);

System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(k);

p.Kill();

3.3 郵件发送

使用SmtpClient类的send(MailMessage message)方法实现带附件的发送。获取“tempDir”文件夹中的所有附件,分别读取附件名称,提取其中的姓名和邮箱信息,为后续邮件发送及窗口信息显示做准备,主界面上下显示窗口分别用richTextBox1、richTextBox2来表示,发送成功信息将显示在richTextBox1中,发送失败信息及原因将显示在richTextBox2中。关键代码如下:

richTextBox1.Clear();

richTextBox2.Clear();

……

using (SmtpClient client = new SmtpClient(textBox发件服务器.Text))

{

client.EnableSsl = true;

client.UseDefaultCredentials = false;

client.DeliveryMethod = SmtpDeliveryMethod.Network;

client.Credentials = new NetworkCredential(textBox发件人.Text, textBox授权码.Text);

string[] files = Directory.GetFiles(tempDir);//获取临时文件夹中所有的文件名

int countSuccess = 0;//记录发送成功的次数

int countFail = 0;//记录发送失败的次数

foreach (string item in files)

{

string file = Path.GetFileNameWithoutExtension(item);

string fileName = file.Substring(0, file.IndexOf("_"));

string fileEmail = file.Substring(file.IndexOf("_") + 1, file.Length - file.IndexOf("_") - 1);

using (MailMessage msg = new MailMessage(new MailAddress(textBox发件人.Text), new MailAddress(fileEmail)))

{

msg.Subject = textBox主题.Text;

msg.SubjectEncoding = Encoding.UTF8;

msg.Body = textBox内容.Text;

msg.BodyEncoding = Encoding.UTF8;

msg.Priority = MailPriority.High;

string sfile = item;//添加附件

msg.Attachments.Add(new Attachment(sfile));

try

{

client.Send(msg);

countSuccess++;

richTextBox1.Text += countSuccess + "." + fileName + ":邮件已发送" + "\r\n";

msg.Dispose();

File.Copy(item, saveDir + "\\" + file + ".xls", true);//将发送成功的附件从“tempDir”复制到“saveDir”

}

catch (Exception ex)

{

countFail++;

richTextBox2.Text += countFail + "." + fileName + ":邮件发送失败" + "\r\n";

richTextBox2.Text += "失败原因:" + ex.Message + "\r\n";

File.Copy(item, errorDir + "\\" + file + ".xls", true);//将发送失败的附件从“tempDir”复制到“errorDir”

}

}

}

}

3.4 失败邮件的发送

邮件发送失败后的附件将保存在“errorDir”文件夹内,这一部分的代码与3.3小节类似,不同之处在于所遍历的文件夹不同,这里不再赘述。

4 结论及展望

通过对输入Excel文件的简单处理,提取其中每位企业员工的薪酬信息作為附件,采用发送邮件的方式实现了企业工资条的自动分发,目前已完成11个月的实际工资条分发工作,程序运行准确无误。工资条邮件的附件内容采用Excel文件格式,清晰美观,方便查看。使用本程序,操作简单、可视性强、便于统计,避免了人工操作可能导致的失误,大大提高了工作效率,使企业财务人员可以方便快捷正确地完成每月工资条分发工作。此外,通过对本程序的简单修改,还可以用于养老保险数据、考勤记录、考试成绩等的自动分发,实现更广泛的用途[8]。

参考文献:

[1] 王志军.两种方法批量生成工资条[J].电脑知识与技术(经验技巧),2019(5):34-35.

[2] 曾慧.Excel制作工资条方法探析——针对不同基础人群[J].辽宁高职学报,2020,22(5):84-87.

[3] 邓祖芬.Excel工资条制作方法探析[J].信息与电脑(理论版),2018(19):28-30.

[4] 邹传树.运用Excel_VBA编程实现一键批量发送工资条[J].电脑知识与技术,2019,15(28):58-59.

[5] Watson K,Hammer J V,Reid J D,等.C#入门经典[M]. 6版.北京:清华大学出版社,2014.

[6] 王小科,徐薇.C#从入门到精通[M].2版.北京:清华大学出版社,2010.

[7] 吴波.工资条邮件群发系统的分析和研究[D].成都:电子科技大学,2013.

[8] 张君.采用C#实现工资条自动分发[J].电脑编程技巧与维护,2011(14):43-44,52.

【通联编辑:谢媛媛】

猜你喜欢
电子邮件
有关旅行计划的电子邮件
民事诉讼电子邮件送达制度的司法适用
小测试:你对电子邮件上瘾了吗?
有奖问答
有奖问答
用PDA无线收发电子邮件