公司的中控指紋考勤機使用多年了,天天簽到簽出,從未想過它與IT何干(可能不喜歡被考勤機約制?),這天負責考勤的小夥說:可否用USB線將其8樓的電腦與一樓的考勤機連接,以便隨時掌握考勤情況。
用USB連接?異想天開:他的電腦與考勤機直線距離十幾米,就算可以連接還要穿牆打洞的,工程預算可以買好幾個考勤機了。但是可能有其他辦法,如網絡接口...,網上一查果然其中一項參數爲:
通訊方式:USB Device,RS232/485,TCP/IP
我們的考勤機爲中控U260指紋考勤機,考勤機安裝在一樓大廳,大廳內敷設有網線連至公司局域網。基本條件已具備,開始考勤機開發第一步。
1 考勤機入網
從聯網角度說,考勤機就是一臺簡陋的電腦(啞終端),只要正確地設置了IP,別人就能訪問它。
1.1 考勤機設置
在考勤機鍵盤上按 Menu 鍵進入機器的菜單項,液晶屏上顯示信息如下:
1.2 設置考勤管理軟件
考勤軟件爲中控《ZKTime5.0考勤管理系統》,中控考勤管理軟件有好幾個版本,核心部件(數據庫結構、考勤機驅動、接口)都相同,只是升級改進了報表。考勤管理軟件要取得考勤數據(簽到、簽出)需要取得考勤機IP地址。
嘗試連接考勤機:
連接成功。
閒着沒事,看着考勤員操作考勤管理軟件,當看到請假單處理過程時,我很意外:它不恰當地綜合了多種數據處理方式:
員工在OA上錄入假單-->考勤員打印紙質假單-->考勤員在考勤軟件上手工錄入假單
還要打印紙質假單?爲什麼不直接導入假單數據?退一步,用複製粘貼也行呀!
無奈,考勤軟件錄入請假單過程全部爲導向式鼠標操作,複製粘貼碎片太多,不提供導入功能,杜絕了數據錄入錯誤,也杜絕了大家"投機取巧"的念頭。
觀察了一下考勤管理系統,雖然其處理程序已封裝編譯,但其數據庫是access,決定從access入手,探索將OA電子假單導入途徑。
2. 假單導入
2.1 考勤管理系統數據結構
《ZKTime5.0考勤管理系統》access數據結構見上圖,《部門編碼》、《員工資料》、《假別編碼》爲靜態數據。《簽到簽出》爲來自於考勤機的考勤記錄,是《考勤報表》的主要數據,《假單》來自於考勤管理員手工錄入,是《考勤報表》的輔助數據。
2.2考勤假單結構
user_spedat《假單》是我們關注的主要對象,只要將OA電子假單導入user_spedat即大功告成。下面我們考察一下user_spedat的數據在考勤系統中是怎樣產生的。
在考勤系統我們錄入下面兩條原始假單:
姓名 | 假別 | 起始時間 | 結束時間 | 請假原因 |
劉工 | 補休 | 2013-07-08 08:30 | 2013-07-12 17:30 | 00170 |
嚴工 | 事假 | 2013-07-15 08:30 | 2013-07-15 09:30 | 00171 |
表1 原始假單
在access下觀察user_spedat表增加了6條記錄:
USER_SPEDAY假單
員工ID | 起始時間 | 結束時間 | 假別ID | 原因 | 制單日期 |
USERID | STARTSPECDAY | ENDSPECDAY | DATEID | YUANYING | DATE |
53 | 2013-07-08 08:30 | 2013-07-08 23:59 | 5 | 00170 | 2013/7/22 |
53 | 2013-07-09 00:00 | 2013-07-09 23:59 | 5 | 00170 | 2013/7/22 |
53 | 2013-07-10 00:00 | 2013-07-10 23:59 | 5 | 00170 | 2013/7/22 |
53 | 2013-07-11 00:00 | 2013-07-11 23:59 | 5 | 00170 | 2013/7/22 |
53 | 2013-07-12 00:00 | 2013-07-12 17:30 | 5 | 00170 | 2013/7/22 |
35 | 2013-07-15 08:30 | 2013-07-15 09:30 | 4 | 00171 | 2013/7/22 |
表2 user_spedat假單
這6條記錄代表什麼意義?
先說簡單的,user_spedat的最後一行表示:
嚴工(員工號35)2013-07-15 08:30至2013-07-15 09:30請事假(假別號4)原因00171
與原始假單結構基本相同。
user_spedat的1-5行表示:
劉工(員工號52)2013-07-08 08:30至2013-07-12 17:30請補休假(假別號5)原因00170
user_spedat用5行表示了劉工的5天(8-12日)請假資料,我們看到對於有跨日的請假,考勤系統按日自動拆分請假日期,並自動填充每日的起始時間、結束時間(見表2的藍色區域),並基本保持填充時間無縫連接(23:59--00:00只差一分鐘)。
2.3 假單導入方案
至此請假單導入方案呼之欲出:
(a)在OA系統,將請假單導出至Excle表
(b)在access,將Excle表導入至臨時表
(c)在access,將臨時表整理到user_spedat表
瞭解OA、acces者都知道,步驟(a)、(b)只是舉手之勞,對於步驟(c)還需進一步規劃:
(1) access中的臨時表命名爲《請假單》,結構同原始假單,另增加姓名id、假別id兩個字段。
字段名稱 | 數據類型 |
請假單號 | 文本 |
姓名id | 數字 |
姓名 | 文本 |
假別id | 數字 |
假別 | 文本 |
起始時間 | 日期/時間 |
結束時間 | 日期/時間 |
表3 臨時表《請假單》結構
(2)《請假單》整理到user_spedat《假單》的大致算法
打開《請假單》as Q
聲明 tcb 填充起始時間
聲明 tce 填充結束時間
do where Q.eof()
tcb = Q.起始日期+00:00
tce = Q.起始日期+23:59
do where tce < Q.結束時間
(Q.姓名id,tcb,tce,Q.假別id,Q.請假單號)追加至user_spedat
tcb日期增加1日
tce日期增加1日
enddo
Q.下一記錄
enddo
2.4 假單導入在access中的實現
假單導入在access中的開發包括3項內容:
(2)假單導入程序
假單導入程序採用了access宏,命名爲[導入假單],綁定於窗口[導入假單]按鈕。
不是所有原始假單都能夠被考勤管理系統接受,例如在考勤系統未定義的員工、假別等。[導入假單]宏對除了導入原始假單,還對原始假單做了預處理,對不符合條件的原始假單[導入假單]宏向考勤員提示,然將其刪除,以便於假單整理。
(3)假單整理過程
由於需要逐條處理《請假單》,假單導入程序採用了access過程,綁定於窗口[整理假單]按鈕。該過程的難點在於整理到user_spedat表的過程中,假單第一天爲原始起始時間--填充結束時間;假單最後一天爲填充起始時間--原始結束時間,參見表2。
Private Sub Command4_Click()
'本程序將形如下表的【請假單】
'請假單號 姓名id 姓名 假別id 假別 起始時間 結束時間
'30716-00168 53 劉工 4 補休 2013-07-17 8:30:00 2013-07-19 17:30:00
'
'整理到【USER_SPEDAY】,對於假期超過1日的假單,需要按日拆分填充
'USERID STARTSPECDAY ENDSPECDAY DATEID YUANYING
'53 2013-07-17 8:30:00 2013-07-17 23:59:00 4 30716-00168
'53 2013-07-18 0:00:01 2013-07-18 23:59:00 4 30716-00168
'53 2013-07-19 0:00:01 2013-07-19 17:30:00 4 30716-00168
'
Dim varSource As String
Dim cnn As New ADODB.Connection '設置連接對象實例
Dim rs1 As New ADODB.Recordset '設置記錄集對象實例,用於《請假單》
Dim rs2 As New ADODB.Recordset '設置記錄集對象實例,用於user_spedat
cnn.Open "provider=microsoft.jet.oledb.4.0;data source=D:\Program Files\att2000.mdb;" '連接數據源
rs1.Open "SELECT * FROM 請假單", cnn '打開來源記錄集,遊標只能向前移動
rs2.Open "SELECT * FROM USER_SPEDAY", cnn, , adLockOptimistic '打開目標記錄集,遊標只能向前移動,可更新
Dim bdt, edt As Date '填充起始時間,填充結束時間
Dim i As Integer '日數計數
Do While Not rs1.EOF
i = 1
bdt = rs1!起始時間
edt = CDate(Left(CStr(rs1!起始時間), 10) + " 23:59:00") '第一個填充結束時間
Do While edt < rs1!結束時間
rs2.MoveLast
rs2.AddNew
rs2!userid = rs1!姓名id
rs2!STARTSPECDAY = bdt
rs2!ENDSPECDAY = edt
rs2!dateid = rs1!假別id
rs2!YUANYING = rs1!請假單號
rs2("date") = Date
If i = 1 Then
bdt = CDate(Left(CStr(bdt), 10) + " 00:00:01") '第一個中間起始時間
End If
bdt = DateAdd("d", 1, bdt)
edt = DateAdd("d", 1, edt)
Loop
rs2.MoveLast
rs2.AddNew
rs2!userid = rs1!姓名id
rs2!STARTSPECDAY = bdt
rs2!ENDSPECDAY = rs1!結束時間
rs2!dateid = rs1!假別id
rs2!YUANYING = rs1!請假單號
rs2!Date = Date
rs1.MoveNext
Loop
MsgBox "假單導入完成"
rs2.Update
rs2.Close
rs1.Close
cnn.Close
End Sub