使用 VBA 似乎适合我。这让您可以编写一个处理所有各种格式选项的宏,并且希望它足够简单,让您的财务人员自己运行。
您说您需要在 Excel 中使用工作表或范围的东西。第一列永远不会改变,因此我们可以将其存储在宏中,第 3-7 列来自电子表格,第 8 列只是空白。这使得第 2 列(季度/年为 QYY)成为一个问题。如果在工作簿中的某处指定了季度/年份(例如,存储在单元格中,作为工作表名称,作为工作簿标题的一部分),那么我们可以将其读入。否则您将需要找到一些指定季度的方法/年宏运行时(例如弹出一个对话框并要求用户输入)
一些简单的代码(我们稍后会担心如何调用它):
Sub ProduceStatePayrollReportFile(rngPayrollData As Range, strCompanyNo As String, _
strQuarterYear As String, strRecordCode As String, strOutputFile As String)
参数相当明显:保存数据的范围、第 1 列的公司编号、第 2 列的季度/年、第 7 列的固定代码以及我们要将结果输出到的文件
' Store the file handle for the output file
Dim fnOutPayrollReport As Integer
' Store each line of the output file
Dim strPayrollReportLine As String
' Use to work through each row in the range
Dim indexRow As Integer
要输出到 VBA 中的文件,我们需要获取文件句柄,因此我们需要一个变量来存储它。我们将在报告行字符串中构建报告的每一行并使用行索引来处理范围
' Store the raw SSN, last name, first name and wages data
Dim strRawSSN As String
Dim strRawLastName As String
Dim strRawFirstName As String
Dim strRawWages As String
Dim currencyRawWages As Currency
' Store the corrected SSN, last name, first name and wages data
Dim strCleanSSN As String
Dim strCleanLastName As String
Dim strCleanFirstName As String
Dim strCleanWages As String
这些变量集分别存储工作表中的原始数据和要输出到文件的清理数据。将它们命名为“原始”和“干净”可以更容易地发现您意外输出原始数据而不是清理数据的错误。我们需要将原始工资从字符串值更改为数值以帮助格式化
' Open up the output file
fnOutPayrollReport = FreeFile()
Open strOutputFile For Output As #fnOutPayrollReport
FreeFile() 获取下一个可用的文件句柄,我们使用它链接到文件
' Work through each row in the range
For indexRow = 1 To rngPayrollData.Rows.Count
' Reset the output report line to be empty
strPayrollReportLine = ""
' Add the company number to the report line (assumption: already correctly formatted)
strPayrollReportLine = strPayrollReportLine & strCompanyNo
' Add in the quarter/year (assumption: already correctly formatted)
strPayrollReportLine = strPayrollReportLine & strQuarterYear
在遍历每一行的循环中,我们首先清除输出字符串,然后添加第 1 列和第 2 列的值
' Get the raw SSN data, clean it and append to the report line
strRawSSN = rngPayrollData.Cells(indexRow, 1)
strCleanSSN = cleanFromRawSSN(strRawSSN)
strPayrollReportLine = strPayrollReportLine & strCleanSSN
.Cells(indexRow, 1) 部分仅表示由 indexRow 指定的行中范围的最左侧列。如果范围从 A 列开始(不一定是这种情况),那么这只是意味着 A。我们稍后需要自己编写 cleanFromRawSSN 函数
' Get the raw last and first names, clean them and append them
strRawLastName = rngPayrollData.Cells(indexRow, 2)
strCleanLastName = Format(Left$(strRawLastName, 10), "!@@@@@@@@@@")
strPayrollReportLine = strPayrollReportLine & strCleanLastName
strRawFirstName = rngPayrollData.Cells(indexRow, 3)
strCleanFirstName = Format(Left$(strRawFirstName, 8), "!@@@@@@@@")
strPayrollReportLine = strPayrollReportLine & strCleanFirstName
Left$(string, length) 将字符串截断为给定长度。格式图片!@@@@@@@@@@ 将字符串格式化为正好十个字符长,左对齐(! 表示左对齐)并用空格填充
' Read in the wages data, convert to numeric data, lose the decimal, clean it and append it
strRawWages = rngPayrollData.Cells(indexRow, 4)
currencyRawWages = CCur(strRawWages)
currencyRawWages = currencyRawWages * 100
strCleanWages = Format(currencyRawWages, "000000000")
strPayrollReportLine = strPayrollReportLine & strCleanWages
我们将其转换为货币,以便乘以 100 将美分值移到小数点左侧。这使得使用Format 生成正确的值变得更加容易。对于 >= 1000 万美元的工资,这不会产生正确的输出,但这是用于报告的文件格式的限制。 0 格式画板中的 0 就够惊人了
' Append the fixed code for column 7 and the spaces for column 8
strPayrollReportLine = strPayrollReportLine & strRecordCode
strPayrollReportLine = strPayrollReportLine & CStr(String(29, " "))
' Output the line to the file
Print #fnOutPayrollReport, strPayrollReportLine
String(number, char) 函数产生一个变体,其中包含指定char 的number 序列。 CStr 将 Variant 转换为字符串。 Print # 语句输出到文件,没有任何额外的格式
Next indexRow
' Close the file
Close #fnOutPayrollReport
End Sub
循环到范围内的下一行并重复。当我们处理完所有行后,关闭文件并结束宏
我们仍然需要两件事:一个 cleanFromRawSSN 函数和一个使用相关数据调用宏的方法。
Function cleanFromRawSSN(strRawSSN As String) As String
' Used to index the raw SSN so we can process it one character at a time
Dim indexRawChar As Integer
' Set the return string to be empty
cleanFromRawSSN = ""
' Loop through the raw data and extract the correct characters
For indexRawChar = 1 To Len(strRawSSN)
' Check for hyphen
If (Mid$(strRawSSN, indexRawChar, 1) = "-") Then
' do nothing
' Check for space
ElseIf (Mid$(strRawSSN, indexRawChar, 1) = " ") Then
' do nothing
Else
' Output character
cleanFromRawSSN = cleanFromRawSSN & Mid$(strRawSSN, indexRawChar, 1)
End If
Next indexRawChar
' Check for correct length and return empty string if incorrect
If (Len(cleanFromRawSSN) <> 9) Then
cleanFromRawSSN = ""
End If
End Function
Len 返回一个字符串的长度,Mid$(string, start, length) 从string 返回从start 开始的length 字符。此功能可以改进,因为它目前不检查非数字数据
调用宏:
Sub CallPayrollReport()
ProduceStatePayrollReportFile Application.Selection, "1234560007", "109", "01", "C:\payroll109.txt"
End Sub
这是最简单的调用方式。范围是用户在活动工作簿的活动工作表上选择的任何内容,其他值是硬编码的。用户应该选择他们想要输出到文件的范围,然后转到工具>宏>运行并选择CallPayrollReport。为此,宏需要成为包含数据的工作簿的一部分,或者位于用户调用宏之前已加载的不同工作簿中。
在生成每个季度的报告之前,有人需要更改季度/年度的硬编码值。如前所述,如果季度/年度已经存储在工作簿中的某个地方,那么最好将其读入而不是硬编码
希望这是有道理且有用的