서론
다른 회사도 다 그러는진 모르겠는데,, 이 회사에선 회사에서 진행하는 업무들을 '프로젝트' 로 구분하고, 프로젝트별로 매출/비용 등을 인지한다.
이를 위해선 하나의 법인 안에 합쳐져있는 예금, 카드, 세금계산서/계산서(이하 편의상 그냥 세금계산서.) 등에 대해 장부를 작성하면서 또한 각각 어떤 프로젝트에 속한지도 기록이 필요하다.
원랜 재무 직원이 진행을 했는데,, 회사가 커지고 프로젝트가 많아지니 감당이 안되어서, 각 부서별로 일단 세금계산서에 대해서만이라도 선처리를 해달라고 요청을 하게 되었다.
요청 내용은 대략 아래와 같다.
1. 세금계산서 목록을 홈택스에서 엑셀로 내려받는다
2. 엑셀에서 내 부서에 해당하는 항목들을 찾아 필터링 한다
3. 장부 작성용 계정과목도 분류한다. (eg, 가스수도비, 용역비, ...)
4. 회계 프로그램에 각 내용을 하나씩 입력한다. (전표 생성)

홈택스와 엑셀과 회계 프로그램을 오가야하고, 없던 일이 생기는데다가 계정이니 뭐니 회계 용어도 알아야하고,,
게다가 본사 밖에선 회계 프로그램 이용을 위해서 VPN 까지 사용해야하니,,
그냥 포기해버리더라....ㅋㅋㅋㅋ
재무에선 점점 많아지는 일에 깔려 죽을라하고,, 각 부서에선 교육한다고 불러도 모르겠다고 멍 때리고 있고...
이렇게 삽질하고 있는걸 우연히 발견해서 해결해보기로 했다.
시스템 배경
이 회사에서 그룹웨어는 내가 만든 시스템을 사용하고 있는데, 그 기능 중 하나로 전자결재가 있고, 전자결재 이용 편의를 위해 홈택스 계산서 스크래핑 및 이를 첨부하는 기능이 있다.
단순히 가져와서 표시에 추가로 검색이나 수정 등 연관 계산서의 간편한 조회, 전자결재에 사용되었는지 여부 표시 등 이런저런 편의 기능이 들어가 있다. (좀만 다듬으면 다른 회사에도 팔아먹을 수 있지 않을까 생각했는데,, 팔기 위한 서비스 개발은 늘 어렵다ㅠㅜ)

아무튼 세금계산서 기능은 이미 있으니, 여기서 각 세금계산서에 대해 [프로젝트 설정, 과세 구분, 계정과목 설정] 기능을 지원해주고,
이렇게 입력된 정보를 [회계 프로그램에 밀어 넣어주기] 를 하는게 이번 프로젝트의 완성⭐️
그리고 블로그에서 이 카테고리의 취지가 그렇듯, 이 글을 쓰게 된 이유는 [회계 프로그램에 밀어 넣어주기] 와 관련되어 있다.
[프로젝트 설정, 과세 구분, 계정과목 설정]를 위한 프로젝트별 계정 과목 제약, 일괄 처리 등은 그냥 웹서비스로 만들면 되는거니까 대충 적당히 만들었다. 실무자들 불러다가 교육하고 피드백 정도가 남은 상황.
회계 프로그램
이 회사는 더X 사의 아이큐X 라는 시스템을 이용 중이다. (이름을 숨길 생각은 없지만 그렇다고 검색으로 떠서 좋을 것도 없으니 적당히 마스킹)
사내 PC 한대에 서버 프로그램 및 SQL Server 를 깔아두고, 각 작업자 PC 에선 이 서버로 접속해서 사용하는 구조이다.
최초 도입비를 좀 비싸게 받고, 이후엔 유지보수 비용으로 약간씩 받으며, 카드 등 스크래핑 모듈 정도는 주기적으로 업데이트 해주는 듯?
이전 지문 인식 소프트웨어가 그렇듯, 로컬에 설치된 서비스니까 접속 정보는 어떻게든 획득할 수 있다. 아니 그 이전에 그냥 인터넷에 공유가 되어 있더라.
다른 일로 이 회사 영업사원과 통화할 일이 있었는데, DB 직접 접속으로 활용하는건 다른 곳에서도 자주 있는 것 같더라. 회사 차원에서 반기진 않지만 그렇다고 막을 순 없으니 어쩔 수 없다,, 정도의 느낌? 차세대 서비스는 이런 문제가 좀 더 방어가 되어 있다고 하는데,,,
아무튼 이 서비스는 서버 PC에 대한 방화벽을 제대로 설정해두지 않으면, 비밀번호도 공개되어 있겠다 권한이 없는 직원도 데이터를 훔쳐갈 수 있는 상당히 취약한 구조이다. 물론 후술할 복잡한 작업을 다 했다는 가정하에. 현실적으론 일어나기 힘들 것 같긴 하다.
그래서 개인적으론 꽁꽁 막아두는 것 보단 이렇게 적당히 열려있어서 내가 손을 댈 수 있는 여지가 있는 환경을 선호한다 ㅎ
막아야 한다면 내가 막아도 되고...

우리에겐 DB스키마 정보가 없으니,, DB 에 접속하면 불친절한 테이블명과 컬럼명들을 한가득 마주하게 된다.
사용량으로 테이블을 선별하고, 이름을 추론하고 데이터와 비교하면서 나에게 필요한 정보를 하나씩 찾는 지루한 작업...
컬럼을 하나 찾으면, 아래와 같은 쿼리로 동일 컬럼이 있는 다른 테이블을 찾을 수도 있다. 이 생각을 못해서 처음엔 하나하나 한참을 헤맸었다ㅠ
SELECT
t.name AS table_name,
c.name AS column_name
FROM sys.tables AS t
JOIN sys.columns AS c ON c.object_id = t.object_id
WHERE c.name = N'찾으려는컬럼명' AND EXISTS (
SELECT 1
FROM sys.dm_db_partition_stats AS ps
WHERE ps.object_id = t.object_id AND ps.reserved_page_count > 0
)
헤매다보니 대충 DB 내에서 현재 수집된 세금계산서, 등록된 전표, 전표의 승인 여부 등 필요한 데이터는 얼추 찾았다.
완벽한건 아니지만,, 필요한 정보만 어떻게든 가져오면 되고 당장 정확성이 엄청 중요하지 않기 때문에, 문제 발생시 수정해주면 되고..
데이터 입력
문제는 데이터 밀어넣기.
어떤 테이블과 어떤 컬럼에 정확한 값을 넣어주지 않으면 프로그램이 오작동을 할 수도 있다.
이번에도 프로그램의 작동 로직을 분석하면 되는데,, 지금은 결국 DB에 기록되는거니, SQL 쿼리만 잘 찾으면 된다.
MSSQL 에는 Extended Events 란게 있다. 활성화해두면 실행된 쿼리 등에 대한 정보에 대한 로그가 설정한 경로에 기록되고, 이 파일에 대해 다시 쿼리로 이벤트를 조회할 수 있다.
다만 이걸 활성화하려면 sysadmin 권한이 있는 계정이어야 하는데, 위에서 말한 기본 계정은 해당 권한이 없다.
어차피 로컬 시스템이니까, 어찌저찌 생성해주면 된다. 이 과정은 생략.
-- 이벤트 생성
CREATE EVENT SESSION [TempSqlLog] ON SERVER
ADD EVENT sqlserver.rpc_completed( -- 프로시저 실행
ACTION(sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_name, sqlserver.username)
),
ADD EVENT sqlserver.sql_batch_completed( -- SQL 쿼리 실행
ACTION(sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_name, sqlserver.username)
)
ADD TARGET package0.event_file(
SET filename = N'C:\SqlLog\SqlLog.xel',
max_file_size = 100,
max_rollover_files = 10
);
-- 시작/종료
ALTER EVENT SESSION [ShoSqlLog] ON SERVER STATE = START;
ALTER EVENT SESSION [ShoSqlLog] ON SERVER STATE = STOP;
sql_statement_completed 란 이벤트도 있었는데 유의미한 데이터가 없었던 것 같아서 제외, 오래전에 한거라 기억이 잘 나진 않는다.
action 에서 client_app_name, database_name, username 은 큰 의미는 없지만, 그냥 넣어뒀다. client_hostname 정도는 분석 과정에서 다른 사용자의 실 사용이 혼동되니 필터를 위해 사용했고..
로그를 켜두고, 전표 등록을 하고, 로그를 끄고, 이벤트를 질의한다.
WITH x AS (
SELECT CAST(event_data AS xml) AS xe FROM sys.fn_xe_file_target_read_file('C:\SqlLog\SqlLog*.xel', NULL, NULL, NULL)
)
SELECT
xe.value('(event/@name)[1]', 'nvarchar(60)') AS event_name,
DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), GETDATE()), xe.value('(event/@timestamp)[1]', 'datetime2(3)')) AS ts,
COALESCE(
xe.value('(event/data[@name="batch_text"]/value)[1]', 'nvarchar(max)'), -- sql_batch_completed
xe.value('(event/data[@name="statement"]/value)[1]', 'nvarchar(max)') -- rpc_completed (환경에 따라)
) AS sql_text
FROM x
WHERE
xe.value('(event/action[@name="client_hostname"]/value)[1]', 'nvarchar(128)') = 'DESKTOP-....'
ORDER BY ts DESC;
이러면 실제 회계 프로그램이 실행하는 쿼리들을 확인할 수 있다.
내가 필요한 전표 입력엔 특정 프로시저를 호출하는걸 확인했다. 프로시저의 내부 쿼리는 암호화 저장되어 확인할 수 없었지만, 나도 똑같이 실행만 하면 되니까 프로시저의 내용물까진 필요없긴 하다.
이제 종류별로 전표 발행을 해보면서, 프로시저 호출시의 각 필드가 어떤 값인지 파악하고, 나도 동일하게 호출해주면 된다.
이렇게 데이터를 다루다보면 아래와 같은 재무제표들도 이것저것 만들어볼 수 있을 것 같긴 한데,,,
이건 아직 필요성을 못 느끼는 것 같기도 하고 나도 공부해야될게 많아져서 일단은 보류...
(아래 화면은 개발 중 시스템의 일부이긴 한데 값은 모두 AI 가 생성한 더미데이터이다.)

'프로젝트 모음' 카테고리의 다른 글
| SUPREMA 지문 출입/근태기 연동 (0) | 2026.09.21 |
|---|---|
| 전자책(EPUB) DRM 해제 (0) | 2026.02.22 |
| 카테고리 프롤로그 (0) | 2026.02.22 |
