GIL's LAB

[예제 3] 연봉 계약서 자동 생성하기 본문

파이썬/업무 자동화

[예제 3] 연봉 계약서 자동 생성하기

GIL~ 2022. 1. 14. 11:57

문제

A사는 연봉 협상을 구두로 진행한 뒤 연봉 계약서에 서명을 받는 방식으로 연봉 계약을 진행합니다. 

2022년 올해도 직원들과 연봉 계약을 구두로 진행했으며, 연봉을 다음과 같이 엑셀 파일(직원연봉.xlsx)에 저장했습니다.  

직원연봉.xlsx
0.01MB
직원연봉.xlsx

이제 직원연봉.xlsx에 있는 데이터를 docx 확장자인 연봉계약서 양식에 옮겨 연봉 계약서를 작성하려 합니다. 그 양식은 아래와 같으며, 옮겨야 하는 부분은 노란색으로 표시했습니다.

2022 연봉계약서_양식.docx
0.02MB

현재까지는 네 명의 직원과만 연봉 협상이 이뤄져서 직접 옮겨도 크게 부담이 없지만, 추후 연봉 협상이 완전히 마무리되면 수천명의 데이터를 옮겨야 합니다. 그래서 파이썬을 이용하여 자동으로 데이터를 옮기고자 합니다.

 

환경 세팅: python-docx

워드 파일을 생성하거나 수정하려면 python-docx라는 패키지가 필요합니다. 이 패키지는 다음과 같이 설치할 수 있습니다. 

$ pip install python-docx

 

자동화 계획 수립

워드 문서를 파이썬(정확히는 python-docx)을 이용하여 수정하려면 docx 파일이 어떻게 구성되어 있는지, 어느 부분을 수정해야 하는지 확인해야 합니다.

먼저 연봉계약서.docx 파일은 총 11개의 문단과 2개의 테이블로 구성되어 있습니다. 참고로 엔터를 치면 문단이 구분되므로 사람이 판단하는 문단과는 좀 다를 수 있습니다. 실제로 이 작업은 파이썬으로 확인하는게 더 효율적이니, 문단 구성을 출력해보겠습니다.

doc = Document('2022 연봉계약서_양식.docx')
for i, para in enumerate(doc.paragraphs):
    print(i, para.text)

[실행 결과]

0 연 봉 계 약 서
1 
2 
3  A사(이하 ‘갑’이라 한다)와 근로자     (이하 ‘을’이라 한다)은(는) 아래와 같이 ‘갑’이 ‘을’에게 1년간 지급할 연봉계약을 체결한다.
4 
5 1. 계약기간 : 2022년  1 월  1일부터 2022년  12 월  31 일까지
6 
7 2. 연봉금액 
8 2-1. 연봉총액 : 금    원(₩        )
9 2-2. 연봉구성
10 

 

코드에서 보다시피, "2022 연봉계약서_양식.docx"를 불러와 doc에 저장하고, 이 doc에 있는 paragraphs의 각 요소인 para의 text[:20]를 출력한 것입니다. 

실제 문서와 비교해보면, 수정해야 할 내용은 다음과 같습니다.

  • 문단 3: 근로자 이름 추가
  • 문단 8: 연봉 추가 (금____원에는 한글로, \ 뒤에는 숫자로)

테이블은 두 개가 있으며, 수정할 내용은 아래와 같습니다.

 

0번째 테이블

  • 1번째 행의 0번째 셀의 1번째 문단: 날짜 수정
  • 1번째 행의 0번째 셀의 2번째 문단: 서약인 뒤 직원 이름 추가

 

 

1번째 테이블

  • 1번째 행 2번째 셀 0번째 문단: 기본금 금액 추가
  • 2번째 행 2번째 셀 0번째 문단: 시간 외 근무수당 금액 추가
  • 2번째 행 3번째 셀 0번째 문단: 추가 근무시간 추가
  • 3번째 행 2번째 셀 0번째 문단: 중식대 보조금 금액 추가
  • 4번째 행 2번째 셀 0번째 문단: 합계 금액 추가

 

파이썬 코드

모듈 불러오기

필요한 모듈인 docx와 pandas를 불러오겠습니다. 

# 모듈 불러오기
from docx import Document
import pandas as pd

 

필요 함수 정의

직원연봉.xlsx에 있는 각 레코드에서 필요한 정보를 추출하는 extract_info 함수를 다음과 같이 정의합니다.

def extract_info(record):
    name = record["성명"]
    total = int(record["연봉총액"])
    base = int(record['기본급'])
    overtime_pay = int(record['시간외 근무수당'])
    lunch = int(record['식대'])
    overtime_month = int(record['연장시간(월)'])
    overtime_year = int(record['연장시간(연)'])
    return name, total, base, overtime_pay, lunch, overtime_month, overtime_year

다음으로 숫자를 글자로 바꿔주는 (예: 1230 -> 천이백삼십) digit2txt 함수를 정의하겠습니다. 이 함수는 네이버 블로그에서 그대로 가져왔습니다. 

def digit2txt(strNum):
    # 만 단위 자릿수
    tenThousandPos = 4
    # 억 단위 자릿수
    hundredMillionPos = 9
    txtDigit = ['', '십', '백', '천', '만', '억']
    txtNumber = ['', '일', '이', '삼', '사', '오', '육', '칠', '팔', '구']
    txtPoint = '쩜 '
    resultStr = ''
    digitCount = 0
    #자릿수 카운트
    for ch in strNum:
        # ',' 무시
        if ch == ',':
            continue
        #소숫점 까지
        elif ch == '.':
            break
        digitCount = digitCount + 1

    digitCount = digitCount-1
    index = 0

    while True:
        notShowDigit = False
        ch = strNum[index]
        if ch == ',':
            index = index + 1
            if index >= len(strNum):
                break;
            continue

        if ch == '.':
            resultStr = resultStr + txtPoint
        else:
            #자릿수가 2자리이고 1이면 '일'은 표시 안함.
            # 단 '만' '억'에서는 표시 함
            if(digitCount > 1) and (digitCount != tenThousandPos) and  (digitCount != hundredMillionPos) and int(ch) == 1:
                resultStr = resultStr + ''
            elif int(ch) == 0:
                resultStr = resultStr + ''
                # 단 '만' '억'에서는 표시 함
                if (digitCount != tenThousandPos) and  (digitCount != hundredMillionPos):
                    notShowDigit = True
            else:
                resultStr = resultStr + txtNumber[int(ch)]

        # 1억 이상
        if digitCount > hundredMillionPos:
            if not notShowDigit:
                resultStr = resultStr + txtDigit[digitCount-hundredMillionPos]
        # 1만 이상
        elif digitCount > tenThousandPos:
            if not notShowDigit:
                resultStr = resultStr + txtDigit[digitCount-tenThousandPos]
        else:
            if not notShowDigit:
                resultStr = resultStr + txtDigit[digitCount]

        if digitCount <= 0:
            digitCount = 0
        else:
            digitCount = digitCount - 1
        index = index + 1
        if index >= len(strNum):
            break;
            
    return(resultStr)

 

메인

이제 메인 코드를 라인별로 살펴보겠습니다. 

 1 data = pd.read_excel("직원연봉.xlsx")
 2 for _, record in data.iterrows():
 3     doc = Document('2022 연봉계약서_양식.docx')
 4     name, total, base, overtime_pay, lunch, overtime_month, overtime_year = extract_info(record) # 직원 정보 가져오기
 5     
 6     # 이름 추가
 7     para = doc.paragraphs[3]
 8     para.text = para.text.replace("근로자     ", "근로자 {} ".format(' '.join(name)))
 9     
10     # 연봉 총액 추가
11     para = doc.paragraphs[8]
12     para.text = para.text.replace("(₩        )", "(₩{:,})".format(total))
13     para.text = para.text.replace('금    원', '금 {}원'.format(digit2txt(str(total))))
14     
15     # 날짜 추가
16     para = doc.tables[0].rows[1].cells[0].paragraphs[1]
17     para.text = para.text.replace("2022.    .    .", "2022.01.14")
18     
19     # 서약인 추가
20     para = doc.tables[0].rows[1].cells[0].paragraphs[2]
21     para.text = para.text.replace(":        (인)", ": {} (인)".format(' '.join(name)))
22     
23     # 기본급 추가
24     doc.tables[1].rows[1].cells[2].paragraphs[0].text = "₩" + "{:,}".format(base)
25     
26     # 시간 외 근무 수당 추가
27     doc.tables[1].rows[2].cells[2].paragraphs[0].text = "₩" + "{:,}".format(overtime_pay)
28     
29     # 연장 시간 추가
30     para = doc.tables[1].rows[2].cells[3].paragraphs[0]
31     para.text = para.text.replace("월    시간, 연     시간 근로", "월 {}시간, 연 {}시간 근로".format(overtime_month, overtime_year))
32     
33     # 중식대 보조금 추가
34     doc.tables[1].rows[3].cells[2].paragraphs[0].text = "₩" + "{:,}".format(lunch)
35     
36     # 합계 추가
37     doc.tables[1].rows[4].cells[2].paragraphs[0].text = "₩" + "{:,}".format(total)
38     doc.save("연봉계약서_{}.docx".format(name))
39
  • 라인 1: 직원연봉 데이터를 불러와 data에 저장합니다.
  • 라인 2: iterrows 메서드를 이용하여 data의 행을 record로 순회합니다.
  • 라인 3: 같은 위치에 있는 파일인 "2022 연봉계약서_양식.docx"를 불러옵니다.
  • 라인 4: extract_info 함수를 사용하여 record에 있는 주요 정보를 가져옵니다.
  • 라인 7 - 8: 3번째 문단의 텍스트에 "근로자    " 부분을 "근로자 김철수"와 같은 형태로 바꿉니다.
  • 라인 11 - 13: 8번째 문단의 텍스트에 금액을 추가합니다. 라인 12에서 "{:,}".format(total)은 total을 콤마를 포함한 숫자(예: 123,456)과 같이 쓰는 것입니다.
  • 라인 15 - 17: 0번째 테이블의 1번째 행의 0번째 셀의 1번째 문단에 날짜를 2022년 1월 14일로 추가합니다.

 

전체 소스코드는 아래에서 다운로드받을 수 있습니다.

 

연봉계약서 자동화.ipynb
0.01MB


포스팅에 대한 질문은 댓글과 이메일(gils-lab@naver.com)을 통해 받고 있습니다.

자동화하고 싶은 업무가 있다면 이메일로 남겨주시기 바랍니다. 

난이도에 따라 외주 / 교육 / 포스팅 모두 가능합니다. 

해당 포스팅이 도움되었다면 공감버튼 클릭부탁드립니다! 



Comments