매년 12월이면 연말정산 작업을 시작하는 시기입니다.
한번 개발해 놓으면 지속적으로 사용할 수 있으면 좋겠지만 매년 국세청이 제공하는 지급명세서 전산매체 제출 양식이 변경되다 보니 그에 맞게 연말정산을 처리하는 프로그램도 함께 수정을 해 주어야 합니다.
연말정산간소화 서비스를 통해 많은 부분이 자동적으로 처리가 가능해서 예전에 비해 업무가 많이 줄어든 것은 사실입니다. 그리고 규모가 작은 회사에서는 별도의 연말정산 프로그램을 자체적으로 개발하지 않아도 국세청 연말정산 간소화 서비스를 통해 쉽게 연말정산 작업을 진행할 수도 있습니다.
이번에 설명할 내용은 자체적으로 연말정산 프로그램을 개발할 때 첫 번째 단계인 국세청 제공 PDF 파일을 XML로 변환하고 변환된 XML 파일을 C#의 DataTable로 가져와서 처리하는 방법에 대한 설명입니다.
국세청에서 제공하는 PDF 파일의 세부 항목은 매년 조금씩 변경될 수 있습니다. 하지만 PDF 파일의 세부 내용을 DataTable로 가져오는 방법은 매년 동일하니 그대로 참고해서 사용해도 될 것이라 생각됩니다.
C# 연말정산 국세청자료 PDF를 XML로 변환하기 위한 API 사용을 위 YesoneAPISetup 설치
국세청에서 제공하는 연말정산 PDF 파일을 XML 형식으로 변환하기 위해서는 전용 API가 먼저 설치되어져 있어야 합니다.
YesoneAPISetup 파일을 다운 받아 Winform용 또는 ASP.NET용으로 설치해서 사용할 수 있습니다.
32비트용과 64비트용으로 구분되어 설치 파일이 제공되고 있습니다.
- exe 실행 파일을 더블 클릭하면 바로 설치가 이루어집니다.
- 설치가 완료된 경우 C:\Windwos\System32 폴더 또는 C:\Windows\SysWOW64 폴더에 ‘DSTSPDFSig_C.dll‘, ‘ExportCustomFile.dll‘ 두 개의 파일이 추가되게 됩니다.(파일 이름은 조금 달라질 수 있습니다.)
※ 파일을 구하기 어려우신 분은 댓글에 메일 주소를 남겨주시면 보내드리도록 하겠습니다.
연말정산간소화 서비스에서 내려받은 PDF 파일을 DataTable로 가져오는 프로그램 간단 설명
1. 국세청 연말정산간소화 서비스에서 내려받은 PDF을 검증하고 Xml로 변환하기 위해 YesoneAPISetup을 먼저 설치해야 합니다. 웹 환경인 경우 IIS 서버에 설치해줘야 합니다.
2. ExportCustomFile.dll, DSTSPDFSig_C.dll 두개의 DLL(동적 연결 라이브러리) 파일을 프로그램에서 Import 해서 사용하게 됩니다.
3. 검증에 문제가 없고 Xml로 오류 없이 변환이 되었다면 XML을 DataSet으로 가져왔을 때 총 7개의 Table이 포함되게 됩니다.(연말정산 년도에 따라 변경될 수 있습니다.)
– doc, form, man, data, sum_data, sum, amt
C# 연말정산 국세청자료 PDF를 XML 변환 및 DataTable로 가져오기 – 프로그램 소스
▶ Class를 정의해 주는 부분 입니다.
using System.Runtime.InteropServices;
namespace Yesone
{
public class YesoneClass
{
// 국세청 PDF 변환과 관련한 클래스
public class EXPFile
{
[DllImport(“ExportCustomFile.dll”)]
public static extern int GetFileSize([MarshalAs(UnmanagedType.LPStr)] string szIn, [MarshalAs(UnmanagedType.LPStr)] string szPassword, [MarshalAs(UnmanagedType.LPStr)] string szName, int bAnsi);
[DllImport(“ExportCustomFile.dll”)]
public static extern int GetFileBuf([MarshalAs(UnmanagedType.LPStr)] string szIn, [MarshalAs(UnmanagedType.LPStr)] string szPassword, [MarshalAs(UnmanagedType.LPStr)] string szName, [In, Out] byte[] pcBuffer, int bAnsi);
[DllImport(“ExportCustomFile.dll”)]
public static extern int NTS_GetFileSize([MarshalAs(UnmanagedType.LPStr)] string szIn, [MarshalAs(UnmanagedType.LPStr)] string szPassword, [MarshalAs(UnmanagedType.LPStr)] string szName, int bAnsi);
[DllImport(“ExportCustomFile.dll”)]
public static extern int NTS_GetFileBuf([MarshalAs(UnmanagedType.LPStr)] string szIn, [MarshalAs(UnmanagedType.LPStr)] string szPassword, [MarshalAs(UnmanagedType.LPStr)] string szName, [In, Out] byte[] pcBuffer, int bAnsi);
}
public class TstUtil
{
[DllImport(“DSTSPDFSig_C.dll”)]
public static extern int DSTSPdfSigVerifyF([MarshalAs(UnmanagedType.LPStr)] string pram1, byte[] pram2, byte[] pram3, byte[] pram4, byte[] pram5);
}
}
}
|
▶ C# 연말정산 국세청자료 PDF를 XML 변환 및 DataTable로 가져오기 전체 프로그램 Source 입니다.
using System; using System.Data; using System.Web.UI; using System.Text; using System.Xml; namespace Yesone { public partial class Yesone : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void btnUpload_Click(object sender, EventArgs e) { if (txtYear.Text.Length != 4) { ClientScriptManager cs = Page.ClientScript; cs.RegisterClientScriptBlock(this.GetType(), “Information”, “<script>alert(‘정산 작업년도가 올바르지 않습니다.’);</script>”); return; } if (FileUpload1.HasFile) { FileUpload1.SaveAs(“c:\\temp\\” + FileUpload1.FileName); } else { ClientScriptManager cs = Page.ClientScript; cs.RegisterClientScriptBlock(this.GetType(), “Information”, “<script>alert(‘파일이 선택되지 않았습니다.’);</script>”); return; } // 연말정산 간소화 서비스에 내려받은 PDF 파일 검증 if (!Pdf_Verify()) return; // PDF파일을 XML로 변환 string filePath = “c:\\temp\\” + FileUpload1.FileName; const string password = “”; const string strXML = “XML”; if (string.IsNullOrEmpty(filePath)) { return; } int fileSize = YesoneClass.EXPFile.NTS_GetFileSize(filePath, password, strXML, 0); if (fileSize > 0) { byte[] buf = new byte[fileSize]; fileSize = YesoneClass.EXPFile.NTS_GetFileBuf(filePath, password, strXML, buf, 0); if (fileSize > 0) { string strBuf = Encoding.UTF8.GetString(buf); strBuf.Replace(“\n”, “\r\n”); txtXml.Text = strBuf; XmlDocument doc = new XmlDocument(); doc.LoadXml(txtXml.Text); doc.Save(filePath + “.xml”); } } if (fileSize == –10) { lblDesc.Text = “파일이 없거나 손상된 PDF 파일입니다.”; } else if (fileSize == –11) { lblDesc.Text = “국세청에서 발급된 전자문서가 아닙니다.”; } else if (fileSize == –13) { lblDesc.Text = “추출용 버퍼가 유효하지 않습니다.”; } else if (fileSize == –200) { lblDesc.Text = “비밀번호가 틀립니다.”; } try { // XML 파일을 DataSet으로 넣기 DataSet dataSet = new DataSet(); XmlReader xmlFile = XmlReader.Create(filePath + “.xml”, new XmlReaderSettings() { CloseInput = true }); dataSet.ReadXml(xmlFile); xmlFile.Close(); // 원본 PDF파일과 변환용 XML 파일 삭제 System.IO.File.Delete(filePath); System.IO.File.Delete(filePath + “.xml”); // DataSet의 Tables로 로직 구현 if (dataSet.Tables.Count > 0) { // // 각각의 DataTable을 처리하는 로직을 구현 // // DataTable dtDoc = dataSet.Tables[“doc”]; // DataTable dtForm = dataSet.Tables[“form”]; // DataTable dtMan = dataSet.Tables[“man”]; // DataTable dtData = dataSet.Tables[“data”]; // DataTable dtDataSum = dataSet.Tables[“sum”]; } } catch //(Exception ex) { ClientScriptManager cs = Page.ClientScript; string script = “<script>alert(‘국세청 PDF파일을 제대로 불러오지 못하였습니다.” + “\\n” + “확인 후 재 업로딩 하세요.’);</script>”; cs.RegisterClientScriptBlock(this.GetType(), “Information”, script); lblDesc.Text = “국세청 PDF파일을 제대로 불러오지 못하였습니다.”; } } |
private bool Pdf_Verify() { lblDesc.Text = “”; bool bReturn = true; long result = 0; string filePath = “c:\\temp\\” + FileUpload1.FileName; string strMsg = string.Empty; byte[] baGenTime = new byte[1024]; byte[] baHashAlg = new byte[1024]; byte[] baHashVal = new byte[1024]; byte[] baCertDN = new byte[1024]; result = YesoneClass.TstUtil.DSTSPdfSigVerifyF(filePath, baGenTime, baHashAlg, baHashVal, baCertDN); String sGenTimeTemp = Encoding.Unicode.GetString(baGenTime); String sHashAlgTemp = Encoding.Unicode.GetString(baHashAlg); String sHashValTemp = Encoding.Unicode.GetString(baHashVal); String sCertDNTemp = Encoding.Unicode.GetString(baCertDN); String sGenTime = sGenTimeTemp.Replace(‘\0’, ‘ ‘).Trim(); String sHashAlg = sHashAlgTemp.Replace(‘\0’, ‘ ‘).Trim(); String sHashVal = sHashValTemp.Replace(‘\0’, ‘ ‘).Trim(); String sCertDN = sCertDNTemp.Replace(‘\0’, ‘ ‘).Trim(); switch (result) { case 0: strMsg = “파일이 변조 되지 않았습니다.”; bReturn = true; break; case 2101: strMsg = “문서가 변조되었습니다.”; bReturn = false; break; case 2102: strMsg = “TSA 서명 검증에 실패하였습니다.”; bReturn = false; break; case 2103: strMsg = “지원하지 않는 해쉬알고리즘 입니다.”; bReturn = false; break; case 2104: strMsg = “해당 파일을 읽을 수 없습니다.”; bReturn = false; break; case 2105: strMsg = “서명검증을 위한 API 처리 오류입니다.”; bReturn = false; break; case 2106: strMsg = “타임스탬프 토큰 데이터 파싱 오류입니다.”; bReturn = false; break; case 2107: strMsg = “TSA 인증서 처리 오류입니다.”; bReturn = false; break; case 2108: strMsg = “타임스탬프가 적용되지 않은 파일입니다.”; bReturn = false; break; case 2109: strMsg = “인증서 검증에 실패 하였습니다.”; bReturn = false; break; default: strMsg = String.Format(“에러코드 미정의 error – [%d]”, result); bReturn = false; break; } lblDesc.Text = strMsg; return bReturn; } } } |
연말정산 국세청 PDF 파일을 DataSet으로 가져오는 ASP.NET 화면 설명 및 테이블 캡쳐 화면
– 아래 화면은 ASP.NET 프로젝트의 실행 화면입니다.
– 파일을 선택하고 [PDF 파일 변환]을 클릭해 주면 됩니다.
– 연말정산 PDF 파일을 XML로 변환하고, XML을 DataSet으로 가져오는 방식으로 구현되어져 있습니다.
– 앞 단락의 예제를 보면 알 수 있듯이 프로그램 소스는 무척 간단하게 되어 있습니다. 별도의 설명이 없어도 쉽게 이해할 수 있을 듯 합니다.
▼ doc Table
▼ form Table : form_id와 form_cd(서식코드)가 들어 있는 테이블입니다.
▼ man Table : 부양가족에 대한 정보와 서식코드가 연결된 테이블 입니다.
▼ sum_data Table : 전체 합계가 들어 있는 테이블 입니다.
▼ data Table : 서식코드 항목별 상세 데이터가 들어 있는 테이블 입니다.
▼ sum Table : 합계 값이 들어 있는 테이블 입니다.
▼ amt Table : 월별 상세 데이터가 들어 있는 테이블 입니다.
※ 실제 연말정산 자료 집계에 주로 사용되는 테이블은 form, man, data, sum_data 입니다.
※ 함께 읽으면 도움이 될 만한 다른 포스팅 글입니다.
♥ 이 글이 도움이 되었기를 바랍니다. ^-^
댓글로 흔적을 남겨 주세요.