내부회계관리제도_김형남 회계사

내부회계관리제도와 AI의 활용 (저널엔트리테스트)

내부회계관리제도와 AI의 활용 (저널엔트리테스트)
2026-03-26
김형남 회계사_한서회계법인 파트너
 

김형남 회계사는 한서회계법인의 파트너이며 한국공인회계사이자 공인부정조사사(CFE)이다. 연세대학교 경제학 석사이며 홍익대학교에서 경제학을 전공하였다. Deloitte 안진회계법인에서 기업구조조정 프로젝트를 경험한 후, 삼정KPMG의 금융사업본부에서 내부회계관리제도 구축 및 평가, 은행내부통제 진단, M&A, 국제회계기준 도입 등 다양한 금융회사에 대한 컨설팅과 회계감사를 담당하였다. 특히, 국내에 내부회계관리제도 도입당시 내부감사 및 내부통제 전문컨설팅 그룹인 Protiviti에서 전문적인 지식을 습득하고 다양한 프로젝트 경험을 쌓았다. 현재는 다양한 금융회사, 부동산자산운용회사, 기업체, 정부기관 등에서 강연과 공인회계사 전문 컨설팅을 제공하고 있다.

 

망했어요.” 임요환의 드랍쉽이 상대의 본진에 떨어지자 중계진은 흥분하며 환호를 쏟아냈다. 스타크래프트의 1세대 프로게이머 임요환은 본인의 트레이드마크인 드랍쉽을 상대 본진에 떨궈 승리를 잡아내곤 했다.

상대의 본진을 공격하기 위한 전법은 역사상 전투에서도 많이 사용되었는데 기원전 218 카르타고의 한니발 장군은 코끼리 37마리와 총병력 46,000명을 데리고 스페인을 지나 알프스 산맥을 넘어 로마의 본진을 공략했다. 알프스를 넘어 이탈리아에 도착했을 26,000 뿐이었다고 하니 막대한 희생을 치렀음에도 불구하고 로마의 허를 찔러 본진 안에서 15년간 유린했다.

이를 이겨낸 로마의 스키피오 장군도 상대 장수인 한니발의 전법을 그대로 답습했다. 스키피오는 한니발을 이탈리아에서 끌어내기 위해 카르타고의 본진인 심장부를 공격함으로써 한니발의 발을 묶었다.

이처럼 본진을 공격하는 전법은 전투에서 자주 사용되었으며 승리로 이끄는 매우 효과적인 전법이다. 그렇다면 마찬가지로 회계부정을 막아내기 위해 본진에 해당하는 부분을 공격함으로써 마찬가지로 효과적인 결론을 가져올 있다. 본진에 해당하는 부분이 바로 분개장(Journal Entry)이라고 있는데, 이에 대한 직접적인 점검, 테스트의 과정을 저널엔트리테스트(Journal Entry Test, JET) 부른다.

이번 연재에서는 AI 활용하여 저널엔트리테스트(JET) 검토하는 방법에 대해 알아본다.

 

1. 감사기준서 240

감사기준서240에서는 경영진의 통제 무력화 위험에 대응하기 위해 저널엔트리테스트 수행을 필수적인 절차로 규정하고 있다. 이는 아무리 좋은 내부통제 장치가 있다고 하더라도 포괄적 권한을 가진 경영진이 마음만 먹으면 이를 무력화 시킬 있으며, 다양한 회계부정의 기법이 있을 있지만 표현형에 있어서는 분개(Journal entry)라는 형식을 반드시 지나치기 때문이다.

특히, 평가 보고 기준 문단7.다에서는 경영진은 회계정보의 작성 공시과정에서 부당하게 개입하여 내부회계관리규정이나 통제를 무시할 위험을 평가하여야 한다고 규정하고 있는데, 이는 감사기준서 240 문단320 일치하므로 저널엔트리테스트를 내부회계관리제도에서도 수행하여야 하는 것으로 해석하는 것이 타당하다. 미국의 U.S.SoX 마찬가지로 내부회계관리제도에서도 기본중의 기본인 저널엔트리테스트를 수행하는 것이 반드시 권고된다.

 

| 감사기준서240과 저널엔트리테스트 |

감사기준서240

 


 

2. 회계부정의 본진 공격

저널엔트리테스트는 분개장을 대상으로 수행되게 되는데 어떻게 수행하면 될까?

분식회계가 발생하는 패턴이나 예상을 통해 저널엔트리테스트 항목을 생각해 있겠다.

결산을 해보니 당기에 손실이 발생하여 이익을 만들기 위해 경영진의 명령에 의해 가공의 매출을 거액으로 입력할 수도 있다. 또한, 기말에 대손충당금 조정이라는 적요와 함께 정상적으로 입력된 대손충당금을 과소계상하기 위한 역분개를 입력할 수도 있다.

어떤 경우에는 재무팀장이 연휴에 회사의 ERP 몰래 접속하여 회사의 예비비 계좌에서 본인이 몰래 관리하는 페이퍼컴퍼니(shell company) 컨설팅 비용 지급이라는 적요와 함께 자금을 이체할 수도 있다. 마찬가지로 이러한 분개는 연휴뿐만 아니라 심야에 감시를 피해서 이루어질 수도 있으며 심야에 입력된 분개는 승인자의 검토가 정상적으로 이루어지기 어려운 환경이라는 것은 쉽게 짐작할 있다.

이외에도 여러가지의 상황을 생각해 있는데, 실제 분개가 입력되어 총계정원장에서 산출된 재무제표가 아니라, 출력된 재무제표를 그대로 고쳐서 임원이나 외부감사인에게 제시하는 경우도 있으며, 작성자가 승인권한까지 모두 보유하고 있어 앞선 모두 부정행위 아니라 더욱 창의적인 분식회계를 수행할 있는 환경도 존재한다.

회사 조직에서 가용한 데이터의 형태에 따라 달라지겠지만 일반적으로 다음의 항목을 검토하면 경영진의 내부통제무력화(internal controls override) 적발할 있는 목적을 만족할 것으로 생각된다.

 
  • 비정상적 금액 (수행중요성 금액이 초과하는 분개)
  • 조정, 수정, 정정, 오류 키워드를 포함하는 분개
  • 작성자와 승인자가 동일한 거래
  • 휴일에 입력된 거래
  • 근무시간 야간근무시간이외에 입력된 분개
  • 벤포드 법칙에 위배되는 분개
  • 중복된 거래(분개)
  • 합산금액이 총계정원장과 일치하는지 대사

 


 

3. ChatGPT와 Gemini가 수행하는 저널엔트리테스트

분개장을 검토하는 저널엔트리테스트는 기본적인 데이터 분석 작업이므로 AI 매우 효율적으로 있는 분야이다. 이런 데이터 분석기법은 질적인 판단을 요하지 않으므로 결과를 쉽게 도출해 있다. 분석된 결과를 해석할 때는 사람에 의한 판단이 필요한 부분이다. 이렇듯 인간과 AI 협업을 통해 내부회계관리제도의 질을 향상시킨다.

저널엔트리테스트를 수행하기 위해 SAP, Oracle NetSuite이나 더존iCUBE, 영림원소프트랩 KSystem 회계ERP에서 분개장을 다운로드하여 Gemini ChatGPT 프롬프트 입력창에 드래그앤드롭을 통해 업로드하고 프롬프트만 입력하면 모두 끝난다.

아래는 프롬프트를 입력하여 AI 도움을 받아 ①~저널엔트리테스트를 수행한 내용의 사례를 하나씩 기재하였다.

 

①  비정상적 금액 (수행중요성 금액이 초과하는 분개)

비정상적 금액

위와 같이 수행중요성을 초과하는 분개를 분석하기 위한 프롬프트를 입력하였다면, 다음과 같은 ChatGPT Gemini 수행중요성 이상 분개 추출에 대한 답변을 기대할 있다. 물론 파이썬 코드를 함께 제공하기 때문에 Audit trail 남기게 되므로 검증이 가능하고, 인공지능의 환각(hallucination)없이 결론을 도출할 있다.

 ChatGPT   Gemini 

 차변금액 기준으로 ₩500,000,000 이상인 거래는 총 173건이 검출되었습니다.

이 데이터는 보통예금·발행어음 등 대규모 자금이동 중심으로 이루어져 있으며, 대부분 재무회계팀 소속 거래입니다.

원하신다면 이 173건을 엑셀 파일로 저장(export) 하거나 계정과목별/거래유형별 요약 통계표로 정리해드릴 수도 있습니다.

어떤 형식으로 내보내드릴까요? (예: “엑셀로 저장해줘” 또는 “계정과목별 합계표 만들어줘”) 

 '차변금액'을 기준으로 500,000,000 이상인 거래를 모두추출했습니다.결과는high_value_transactions.csv 파일로 저장되었습니다. 추출된 데이터의 처음 5개 행은 다음과 같습니다: 
 

import pandas as pd

 

# 파일 경로

file_path = "/mnt/data/샘플용 분개장_20250630.xlsx"

 

# 엑셀 파일 불러오기

excel_file = pd.ExcelFile(file_path)

excel_file.sheet_names

 

# 첫 번째 시트 읽기

df = pd.read_excel(file_path, sheet_name='Sheet1')

 

# 상위 10행 미리보기

df.head(10)

 

# 차변금액이 500,000,000 이상인 거래 필터링

filtered_df = df[df['차변금액'] >= 500_000_000]

 

# 결과 미리보기

filtered_df.head(10), filtered_df.shape

 
 

import pandas as pd

 

# Load the CSV file into a DataFrame

file_path = '샘플용 분개장_20250630.xlsx - Sheet1.csv'

df = pd.read_csv(file_path)

 

# Display the first 5 rows to understand the data

print("First 5 rows of the DataFrame:")

print(df.head().to_markdown(index=False, numalign="left", stralign="left"))

 

# Display the DataFrame's info to check column names and data types

print("\nDataFrame Info:")

df.info()

 

 고액 분개는 다양한 의도적인 위험을 포함할 있다. 마감직전에 특수관계자를 대상으로 6억원의 매출을 발생시켰다거나, CFO 아직 배송되지도 않은 제품 10억원 어치를 매출로 인식하라고 회계팀에 압력을 넣을 수도 있다. 영업이익 등을 부풀리기 위해 당기 비용으로 처리해야할 거액의 비용을 자산화 있다. 또한, 대규모의 의심스러운 자금 지출이 발생하기도 한다.

 수행중요성을 초과하는 분개에 대한 저널엔트리테스트는 고액 분개는 위와 같은 위험을 내포할 수도 있다는 전제하에 진행되며 결과를 분석하여야 한다.

 



 

조정, 수정, 정정, 오류 키워드를 포함하는 분개

ai 활용이미지

주요 키워드를 포함하는 분개를 분석하기 위해 위와 같이 프롬프트를 입력한다. 키워드 수정 경우에는분당 수정구 같이 필요없는 정보가 함께 추출될 있으므로 수정구는 제외하고 추출할 있도록 하는 것이 좋다.

 ChatGPT   Gemini 
 

적요(설명)란에 ‘오류’, ‘수정’, ‘정정’, ‘조정’ 등의 키워드를 포함하되,

**‘수정구’**는 제외한 거래가 총 108건 발견되었습니다. 하신다면 이 108건을

① 엑셀 파일로 저장하거나

② 오류/조정 사유별 분류표(예: “오류”, “정정”, “조정”별 건수 요약)

형태로 만들어드릴 수 있습니다.

어떤 형식으로 정리해드릴까요?

 
 

'적요' 칼럼을 기준으로 '오류', '수정', '정정', '조정' 키워드를 포함하고, '수정구'를 제외한 거래를 모두 추출했습니다.

결과는 keyword_filtered_transactions.csv 파일로 저장되었습니다.

추출된 데이터의 처음 5개 행은 다음과 같습니다:

 
 

# '적요' 컬럼에서 특정 키워드를 포함하되, '수정구'는 제외한 거래 필터링

keywords = ['오류', '수정', '정정', '조정']

 

# 문자열로 변환 후 필터링

mask = df['적요'].astype(str).apply(

lambda x: any(k in x for k in keywords) and '수정구' not in x

)

 

filtered_notes_df = df[mask]

 

# 결과 미리보기 및 건수 확인

filtered_notes_df.head(10), filtered_notes_df.shape

 
 

# Define the inclusion keywords

include_keywords = ['오류', '수정', '정정', '조정']

 

# Define the exclusion keyword

exclude_keyword = '수정구'

 

# Create the inclusion mask: rows containing any of the include_keywords

# The regex `|`.join(include_keywords) creates a pattern like '오류|수정|정정|조정'

include_mask = df['적요'].str.contains('|'.join(include_keywords), na=False, regex=True)

 

# Create the exclusion mask: rows NOT containing the exclude_keyword

exclude_mask = ~df['적요'].str.contains(exclude_keyword, na=False, regex=True)

 

# Combine the masks

combined_mask = include_mask & exclude_mask

 

# Filter the DataFrame

filtered_by_keyword_df = df[combined_mask].copy()

 

# Save the filtered DataFrame to a new CSV file

keyword_output_file_path = 'keyword_filtered_transactions.csv'

filtered_by_keyword_df.to_csv(keyword_output_file_path, index=False, encoding='utf-8-sig')

 

키워드를 통한 저널엔트리테스트는 의도적인 손익을 조정하거나, 회계오류를 은폐하기 위한 위험을 적발하는데 유용하다. 특히, 오류나 정정, 수정과 같은 문구는 자체가 최초에 올바르게 처리하는 1차적인 통제가 실패하였다는 것을 내포한다. 또한, 부정행위자가 만약 자금을 횡령하였다면 사실을 숨기기 위해서도선급금 오류 정정 같은 흔적을 남길 있다.

 

작성자와 승인자가 동일한 거래

ai 활용이미지

분개를 작성한 자가 스스로 승인을 한다는 것은 업무분장(SoD) 위반하였으므로 내부통제의 실패상황을 의미한다. 업무분장은 내부통제의 통제범주중 가장 강력한 것으로 받아들여지는데 기본적으로 보관-기록-승인(custody-approval-record) 분리하는 것이다. 이러한 내부통제 실패상황을 발견하기 위해 위와 같은 프롬프트를 입력하면 잘못된 내부통제 활동이 있었는지 검토가 가능하다.

ChatGPT

Gemini

기표자와 승인자가 동일한 거래는 존재하지 않습니다.

즉, 이번 분개장 파일에서는 모든 거래가 서로 다른 인원에 의해 기표와 승인이 이루어졌습니다.

이는 내부통제 관점에서 **Segregation of Duties(SoD, 업무분리 통제)**가 적절히 작동하고 있음을 의미합니다.

특히 “기표자=승인자” 거래가 없다는 것은 **4-eyes principle(4안 원칙)**이 잘 준수되고 있다는 신호로 해석할 수 있습니다.

 

'기표자'와 '승인자'가 동일한 거래를 추출한 결과, 해당하는 거래가 없는 것으로 확인되었습니다.

 

비교 결과가 저장된 same_person_transactions.csv 파일이 생성되었으나, 내용은 비어있습니다.

# 기표자와 승인자가 동일한 거래 필터링

same_person_df = df[df['기표자'] == df['승인자']]

 

# 결과 미리보기 및 건수 확인

same_person_df.head(10), same_person_df.shape

# Step 1: Filter the DataFrame

# Find rows where '기표자' (preparer) and '승인자' (approver) are the same

same_person_mask = df['기표자'] == df['승인자']

same_person_df = df[same_person_mask].copy()

 

# Step 2: Save the results

# Save the filtered DataFrame to a new CSV file

same_person_output_file = 'same_person_transactions.csv'

same_person_df.to_csv(same_person_output_file, index=False, encoding='utf-8-sig')

 

# Step 3: Inform the user

print(f"Filtered data saved to: {same_person_output_file}")

print("\nFirst 5 rows of transactions where preparer and approver are the same:")

if same_person_df.empty:

print("No transactions found where the preparer and approver are the same person.")

else:

# Display the first 5 rows of the new filtered DataFrame

print(same_person_df.head().to_markdown(index=False, numalign="left", stralign="left"))

사례에서는 기표자(작성자) 승인자가 동일한 거래가 발생되지 않았다. 하지만, 작성자와 승인자의 업무분장이 이루어지지 않는다면 입력, 삭제, 변경 등의 모든 회계조작이 가능하므로 반드시 검토할 것을 권고한다.

 

 

휴일에 입력된 거래

ai 활용이미지

휴일에 입력된 거래를 분석하는 이유는 정상 근무시간을 벗어난 분개는 부정을 숨기기 위한 가능성이 높다는 것을 전제로 하는 것이다. 실제로 오랫동안 한가지 업무를 수행한 담당자가 주말에 출근하여 체계적인 횡령을 발생시킨 사례가 많이 발견되기도 한다. 아래 사례에서는 분개장에는 분개가 최초에 입력된 시간 날짜 칼럼이 없어, 최초분개일시 칼럼이 포함된 데이터를 추출하여 분석하였다.

ChatGPT

Gemini

요청하신 대로 “최초기표일시” 기준으로 대한민국의 토요일·일요일·공휴일(대체공휴일 포함)에 입력된 거래만 깔끔하게 추출해 엑셀로 저장했습니다. 파일에는 원본 열 전체와 함께 보조열(요일, 휴일여부, 공휴일명)이 추가되어 있습니다.

결과 파일: 다운로드 (토일공휴일_거래_추출_20251111.xlsx)

필요하면 평일·정상근무시간 외(예: 20:00–08:00) 필터, 특정 공휴일만(예: 설·추석·선거일 등) 필터, 월별/사용자별 집계 피벗 테이블도 바로 만들어 드릴게요.

'최초기표일시'를 기준으로 토요일과 일요일에 입력된 거래 216건을 추출했습니다.

추출된 데이터는 주말_기표_거래.csv 파일로 저장되었습니다.

    • 분석된 총 거래 수: 53,885건
    • 추출된 주말(토/일) 거래 수: 216건
    • 저장 파일: 주말_기표_거래.csv

 

# -*- coding: utf-8 -*-

from pathlib import Path

from datetime import datetime, date

 

from openpyxl import load_workbook, Workbook

 

src_path = Path("/mnt/data/전표조회입력시간_20250805.xlsx")

 

wb = load_workbook(src_path, read_only=True, data_only=True)

ws = wb.active

 

rows_iter = ws.iter_rows(values_only=True)

header = next(rows_iter)

header = [h if h is not None else "" for h in header]

 

try:

dt_idx = header.index("최초기표일시")

except ValueError:

raise KeyError(f"'최초기표일시' 칼럼을 찾을 수 없습니다. 현재 칼럼들: {header}")

 

# Holidays

try:

import holidays

kr_holidays = holidays.KR(years=range(1990, 2036), observed=True)

except Exception:

kr_holidays = None

 

weekday_map = {0:"월요일",1:"화요일",2:"수요일",3:"목요일",4:"금요일",5:"토요일",6:"일요일"}

 

def to_datetime(val):

if isinstance(val, datetime):

return val

# Excel stores dates as datetime via openpyxl in most cases;

# if it's a date object, convert to datetime

if isinstance(val, date):

return datetime(val.year, val.month, val.day)

# Otherwise, skip parsing to keep things fast

return None

 

# Output workbook

out_path = Path("/mnt/data/토일공휴일_거래_추출_20251111.xlsx")

out_wb = Workbook(write_only=False)

out_ws = out_wb.active

out_ws.title = "토일·일요일·공휴일"

out_ws.append(list(header) + ["요일", "휴일여부", "공휴일명"])

 

total = 0

kept = 0

 

for row in rows_iter:

total += 1

dt = to_datetime(row[dt_idx])

if dt is None:

continue

wd = dt.weekday()

is_weekend = (wd in (5, 6))

if kr_holidays is not None:

d = dt.date()

is_holiday = d in kr_holidays

holiday_name = kr_holidays.get(d)

else:

is_holiday = False

holiday_name = None

if is_weekend or is_holiday:

kept += 1

yoil = weekday_map.get(wd, "")

label = holiday_name if holiday_name else ("주말" if is_weekend else None)

out_ws.append(list(row) + [yoil, True, label])

 

# Meta sheet

meta_ws = out_wb.create_sheet(title="정보")

meta_ws.append(["키", "값"])

meta_ws.append(["원본파일", src_path.name])

meta_ws.append(["총 행수(헤더제외)", total])

meta_ws.append(["추출 행수", kept])

meta_ws.append(["공휴일 라이브러리", "holidays.KR 사용" if kr_holidays is not None else "미사용(주말만)"])

 

out_wb.save(out_path)

 

out_path.as_posix()

import pandas as pd

 

# Load the dataframe

file_path = '전표조회입력시간_20250805.xlsx - Sheet1.csv'

try:

df = pd.read_csv(file_path)

except Exception as e:

print(f"Error reading file: {e}")

exit()

 

# --- Data Inspection (Optional but recommended) ---

# print("Data Info:")

# df.info()

# print("\nData Head:")

# print(df.head())

# -------------------------------------------------

 

# Define the key column

date_column = '최초기표일시'

 

if date_column not in df.columns:

print(f"Error: Column '{date_column}' not found in the file.")

print(f"Available columns: {df.columns.tolist()}")

exit()

 

# Convert the '최초기표일시' column to datetime objects

# errors='coerce' will turn unparseable dates into NaT (Not a Time)

original_count = len(df)

df[date_column] = pd.to_datetime(df[date_column], errors='coerce')

 

# Drop rows where the date conversion failed (became NaT)

df = df.dropna(subset=[date_column])

converted_count = len(df)

dropped_rows = original_count - converted_count

 

if dropped_rows > 0:

print(f"Warning: {dropped_rows}개 행의 '{date_column}' 형식이 잘못되어 분석에서 제외되었습니다.")

 

# --- Weekend (Saturday/Sunday) Extraction ---

# Get the day of the week (Monday=0, Sunday=6)

df['요일'] = df[date_column].dt.dayofweek

 

# Filter for Saturday (5) or Sunday (6)

is_weekend = df['요일'].isin([5, 6])

df_weekends = df[is_weekend].copy()

 

# Clean up the temporary column

df_weekends = df_weekends.drop(columns=['요일'], errors='ignore')

 

# Save the weekend data to a new CSV

weekend_output_file = '주말_기표_거래.csv'

df_weekends.to_csv(weekend_output_file, index=False, encoding='utf-8-sig')

 

print(f"\n--- 결과 ---")

print(f"총 {original_count}개의 행 중 {converted_count}개의 유효한 날짜 데이터를 분석했습니다.")

print(f"토요일 또는 일요일에 기표된 거래 {len(df_weekends)}건을 추출했습니다.")

print(f"결과 파일: {weekend_output_file}")

 

# --- Holiday (공휴일) Limitation Note ---

print("\n[중요 알림]")

print("요청하신 '공휴일' 데이터 추출은 현재 환경의 제약으로 인해 실행할 수 없습니다.")

print("정확한 대한민국 공휴일을 식별하려면 'workalendar'와 같은 별도의 라이브러리 설치가 필요하지만, 여기서는 라이브러리를 추가로 설치할 수 없습니다.")

print(f"따라서, {weekend_output_file} 파일에는 '토요일'과 '일요일' 거래만 포함되어 있으며, 평일인 공휴일은 포함되지 않았습니다.")

휴일에 입력된 거래를 추출하기 위해서는 대한민국의 공휴일 라이브러리가 필요한데 공휴일 라이브러리를 호출하지 못하는 경우도 있으므로 주의하여야 한다.


 

⑤ 근무시간 및 야간근무시간이외에 입력된 분개

 ai 활용이미지 5

휴일에 입력된 거래와 마찬가지로 정상적인 업무시간 이외에 발생한 거래도 유사한 위험을 내포하고 있다. 이러한 패턴은 해외나 국내에서 매번 발생하고 반드시 Red flag 다루어져야 하는 것으로 PCAOB, COSO, AICPA, 금융감독원 모두 동일한 공통적이 의견을 표명하고 있다.

특히 야간에 입력된 분개의 경우에는 회사의 내부통제가 적절하게 작동할 없는 환경이라고 예상할 있다. 시간까지 누가 자리에 남아서 검토를 열심히 있었겠는가?

ChatGPT

Gemini

요청하신 “최초기표일시” 기준 오전 02:00 이상 ~ 오전 07:00 미만에 입력된 거래만 추출해 엑셀로 저장했습니다.

모든 원본 열을 유지했고, 마지막에 입력시간대 보조열을 추가했습니다.

결과 파일: 새벽입력거래_02시~07시_추출_20251111.xlsx

원하시면 같은 로직으로 시간대를 바꿔서(예: 20:00~08:00 야간) 추가 추출하거나, 사용자·계정과목·월별로 빈도/금액 집계 피벗을 만들어드릴게요.

'최초기표일시'를 기준으로 오전 2시부터 7시 사이에 입력된 거래를 분석했습니다.

총 53,885건의 데이터 중 해당 시간에 입력된 거래는 0건이었습니다.

결과는 새벽_기표_거래_02_07시.csv 파일로 저장되었으며, 파일 내용은 비어있습니다.

    • 분석된 총 거래 수: 53,885건
    • 추출된 거래 수 (02:00 ~ 07:00): 0건
    • 저장 파일: 새벽_기표_거래_02_07시.csv

 

# -*- coding: utf-8 -*-

from pathlib import Path

from datetime import datetime, date, time

from openpyxl import load_workbook, Workbook

 

# ---------- Settings ----------

SRC = Path("/mnt/data/전표조회입력시간_20250805.xlsx")

DT_COL_NAME = "최초기표일시"

START_T = time(2, 0, 0) # inclusive

END_T = time(7, 0, 0) # exclusive

OUT = Path("/mnt/data/새벽입력거래_02시~07시_추출_20251111.xlsx")

 

# ---- Stream read (no pandas) ----------

wb = load_workbook(SRC, read_only=True, data_only=True)

ws = wb.active

 

rows = ws.iter_rows(values_only=True)

header = next(rows)

header = [h if h is not None else "" for h in header]

try:

dt_idx = header.index(DT_COL_NAME)

except ValueError:

raise KeyError(f"'{DT_COL_NAME}' 칼럼을 찾을 수 없습니다. 현재 칼럼들: {header}")

 

# ---------- Write-only output ----------

out_wb = Workbook(write_only=True)

out_ws = out_wb.create_sheet(title="새벽02~07시")

out_ws.append(header + ["입력시간대"])

 

def to_datetime(val):

# Expecting openpyxl to give datetime for date/time cells.

if isinstance(val, datetime):

return val

if isinstance(val, date):

# No time info; treat as 00:00 and it won't match 02~07

return datetime(val.year, val.month, val.day)

# Fallback: try fast limited parsing for common text formats

if isinstance(val, str):

# Try ISO-like formats quickly

for fmt in ("%Y-%m-%d %H:%M:%S", "%Y/%m/%d %H:%M:%S",

"%Y-%m-%d %H:%M", "%Y/%m/%d %H:%M",

"%Y%m%d %H:%M:%S", "%Y%m%d%H%M%S"):

try:

return datetime.strptime(val.strip(), fmt)

except Exception:

pass

return None

 

kept = 0

total = 0

 

for row in rows:

total += 1

dt = to_datetime(row[dt_idx])

if dt is None:

continue

tt = dt.time()

if (tt >= START_T) and (tt < END_T):

kept += 1

out_ws.append(list(row) + [tt.strftime("%H:%M:%S")])

 

# Save

out_wb.save(OUT)

 

OUT.as_posix()

 

import pandas as pd

import datetime

 

# Load the dataframe

file_path = '전표조회입력시간_20250805.xlsx - Sheet1.csv'

try:

df = pd.read_csv(file_path)

except Exception as e:

print(f"Error reading file: {e}")

exit()

 

# Define the key column

date_column = '최초기표일시'

 

if date_column not in df.columns:

print(f"Error: Column '{date_column}' not found in the file.")

print(f"Available columns: {df.columns.tolist()}")

exit()

 

# Convert the '최초기표일시' column to datetime objects

original_count = len(df)

df[date_column] = pd.to_datetime(df[date_column], errors='coerce')

 

# Drop rows where the date conversion failed (became NaT)

df = df.dropna(subset=[date_column])

converted_count = len(df)

dropped_rows = original_count - converted_count

 

if dropped_rows > 0:

print(f"Warning: {dropped_rows}개 행의 '{date_column}' 형식이 잘못되어 분석에서 제외되었습니다.")

 

# Define the time range

start_time = datetime.time(2, 0, 0)

end_time = datetime.time(7, 0, 0)

 

# Extract the time component from the datetime column

df_time = df[date_column].dt.time

 

# Create the filter mask

# Check if the time is between 02:00:00 and 07:00:00 (inclusive)

is_between_02_and_07 = (df_time >= start_time) & (df_time <= end_time)

 

# Apply the filter

df_filtered = df[is_between_02_and_07].copy()

 

# Save the filtered data to a new CSV

output_file = '새벽_기표_거래_02_07시.csv'

df_filtered.to_csv(output_file, index=False, encoding='utf-8-sig')

 

print(f"\n--- 결과 ---")

print(f"총 {original_count}개의 행 중 {converted_count}개의 유효한 날짜 데이터를 분석했습니다.")

print(f"오전 02:00:00 부터 07:00:00 사이에 기표된 거래 {len(df_filtered)}건을 추출했습니다.")

print(f"결과 파일: {output_file}")


 
5. 결론: Measure, don’t guess

 

AI(인공지능) 활용하여 저널엔트리테스트를 한다는 것은 어떤 의미를 가질까? 이는 마치 내가 똥손이라 임요환이 아닌데도 불구하고 그와 같은 드랍쉽 작전으로 본진을 공격하는 것과 유사하다.

AI 활용의 첫번째 장점은 속도와 생산성을 높이는데 일품이다. 대량 분개에 대해 짧은 시간내에 코드를 생성할 있는 장점이 있다. 두번째로 파이썬 코드를 모르는 비전문가도 자연어로 요구하면 코드를 자동 생성해 주므로 접근성이 좋다. 마지막으로 사용하는 회계 Application 따라 데이터 형태가 다를 수도 있는데 새로운 포맷과 규칙에 빠르게 적용할 있다.

AI 만능이 아니다. 하지만, “감에 의존하지 말고 측정하라 “Measure, don’t guess 원칙 잊지말자.

 

#내부회계관리제도 #AI #내부회계관리제도와AI #Z-Score #벤포트법칙 #관측치와 기대치
 

Legal Disclaimer
해당 자료의 내용은 집필자의 개인적인 의견으로 삼일피더블유씨솔루션(주)의 공식적인 의견이 아님을 밝힙니다.

 

Copyright(C) 삼일피더블유씨솔루션㈜ All right reserved.
본 사이트에 게재된 자료들은 저작권법에 의하여 보호 받는 저작물로 그 저작권은 삼일피더블유씨솔루션(주)에 있으므로 무단 복제 및 배포를 금합니다.