diff --git a/app.py b/app.py index c42edcd..8c2ca44 100644 --- a/app.py +++ b/app.py @@ -164,7 +164,9 @@ def step5(): # 워드 문서 생성 try: cult_name = all_data['basic_info'].get('cult', '기타') - output_path = word_processor.generate_document(all_data, cult_name) + # 이단별 상세점검 문항 가져오기 + cult_questions = app.config.get('CULT_DETAIL_QUESTIONS', {}).get(cult_name, []) + output_path = word_processor.generate_document(all_data, cult_name, cult_questions) # 구글 드라이브 업로드 if drive_uploader and app.config['GOOGLE_DRIVE_FOLDER_ID']: diff --git a/utils/word_processor.py b/utils/word_processor.py index f56787a..5ed99d6 100644 --- a/utils/word_processor.py +++ b/utils/word_processor.py @@ -1,6 +1,8 @@ from docx import Document -from docx.shared import Pt +from docx.shared import Pt, RGBColor from docx.enum.text import WD_ALIGN_PARAGRAPH +from docx.oxml.ns import qn +from docx.oxml import OxmlElement import os from datetime import datetime @@ -10,109 +12,210 @@ class WordProcessor: self.output_dir = 'output' os.makedirs(self.output_dir, exist_ok=True) - def generate_document(self, data, cult_name='기타'): + def generate_document(self, data, cult_name='기타', cult_questions=None): """데이터를 워드 문서로 생성""" - # 템플릿 파일 경로 - template_file = os.path.join(self.template_dir, f'{cult_name}_template.docx') + doc = Document() - # 템플릿이 없으면 기본 템플릿 사용 - if not os.path.exists(template_file): - template_file = os.path.join(self.template_dir, 'default_template.docx') - - # 템플릿이 있으면 사용, 없으면 새 문서 생성 - if os.path.exists(template_file): - doc = Document(template_file) - else: - doc = Document() - self._create_default_template(doc) - - # 데이터 채우기 - self._fill_document(doc, data) - - # 출력 파일명 - timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') - name = data.get('basic_info', {}).get('name', '무명') - output_filename = f'교리점검표_{name}_{timestamp}.docx' - output_path = os.path.join(self.output_dir, output_filename) - - doc.save(output_path) - return output_path - - def _create_default_template(self, doc): - """기본 템플릿 생성""" - # 제목 - title = doc.add_heading('이단 탈퇴자 교리점검표', 0) - title.alignment = WD_ALIGN_PARAGRAPH.CENTER - - # 기본 정보 섹션 - doc.add_heading('1. 기본 정보', level=1) - doc.add_paragraph('이름: {name}') - doc.add_paragraph('교구: {district}') - doc.add_paragraph('이단교단: {cult}') - - # 기독교대한감리회 신앙고백 - doc.add_heading('2. 기독교대한감리회 신앙고백 교리 점검', level=1) - doc.add_paragraph('{methodist_doctrine}') - - # 이단 일반 교리 점검 - doc.add_heading('3. 이단 일반 교리 점검', level=1) - doc.add_paragraph('{general_cult_doctrine}') - - # 출신 이단별 교리 점검 - doc.add_heading('4. 출신 이단별 교리 점검', level=1) - doc.add_paragraph('{specific_cult_doctrine}') - - # 간증문 - doc.add_heading('5. 간증문', level=1) - doc.add_paragraph('{testimony}') - - doc.add_paragraph('') - doc.add_paragraph(f'작성일: {datetime.now().strftime("%Y년 %m월 %d일")}') - - def _fill_document(self, doc, data): - """문서에 데이터 채우기""" + # 기본 정보 basic_info = data.get('basic_info', {}) methodist = data.get('methodist_doctrine', {}) general = data.get('general_cult_doctrine', {}) specific = data.get('specific_cult_doctrine', {}) testimony = data.get('testimony', {}) - # 모든 단락을 순회하며 플레이스홀더 교체 - replacements = { - '{name}': basic_info.get('name', ''), - '{district}': basic_info.get('district', ''), - '{cult}': basic_info.get('cult', ''), - '{methodist_doctrine}': self._format_answers(methodist), - '{general_cult_doctrine}': self._format_answers(general), - '{specific_cult_doctrine}': self._format_answers(specific), - '{testimony}': testimony.get('content', '') - } + self.cult_questions = cult_questions or [] - for paragraph in doc.paragraphs: - for key, value in replacements.items(): - if key in paragraph.text: - paragraph.text = paragraph.text.replace(key, str(value)) + # 1. 첫 번째 단락: 별첨 목록 + doc.add_paragraph('*별첨1 : 감리교 신앙고백서 확인점검') + doc.add_paragraph('*별첨2 : 이단 일반 점검') + doc.add_paragraph('*별첨3 : 이단 상세 점검') + doc.add_paragraph('*별첨4 : 간증문') + doc.add_paragraph('') # 빈 줄 - # 테이블도 처리 - for table in doc.tables: - for row in table.rows: - for cell in row.cells: - for key, value in replacements.items(): - if key in cell.text: - cell.text = cell.text.replace(key, str(value)) + # 2. 두 번째 단락: [별첨1] 감리교 신앙고백서 확인점검 + self._add_section_title(doc, '[별첨1] 감리교 신앙고백서 확인점검 (각 문항에 대해 예, 아니오 또는 필요시 서술형으로 답변해 주시면 됩니다)') + self._add_methodist_table(doc, methodist) + doc.add_paragraph('') # 빈 줄 + + # 3. 세 번째 단락: [별첨2] 이단 일반 점검 + self._add_section_title(doc, '[별첨2] 이단 일반 점검 (각 문항에 대해 예, 아니오 또는 필요시 서술형으로 답변해 주시면 됩니다)') + self._add_general_cult_table(doc, general) + # 기타의견 + if general.get('other_opinions'): + doc.add_paragraph('기타의견:') + doc.add_paragraph(general.get('other_opinions', '')) + doc.add_paragraph('') # 빈 줄 + + # 4. 네 번째 단락: [별첨3] 이단 상세 점검 (기타가 아닌 경우만) + if cult_name and cult_name != '기타 (위 선택지에 없을 경우)' and specific: + self._add_section_title(doc, f'[별첨3] 이단 상세 점검 ({cult_name}) (각 문항에 대해 예, 아니오 또는 필요시 서술형으로 답변해 주시면 됩니다)') + self._add_specific_cult_table(doc, specific, self.cult_questions) + # 기타의견 + if specific.get('other_opinions'): + doc.add_paragraph('기타의견:') + doc.add_paragraph(specific.get('other_opinions', '')) + doc.add_paragraph('') # 빈 줄 + + # 5. 다섯 번째 단락: [별첨4] 간증문 + self._add_section_title(doc, '[별첨4] 간증문 (상담 소감을 간략히 서술해 주시면 됩니다)') + testimony_content = testimony.get('content', '') + if testimony_content: + doc.add_paragraph(testimony_content) + else: + doc.add_paragraph('(간증문 없음)') + + # 출력 파일명 + timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') + name = basic_info.get('name', '무명') + output_filename = f'교리점검표_{name}_{timestamp}.docx' + output_path = os.path.join(self.output_dir, output_filename) + + doc.save(output_path) + return output_path - def _format_answers(self, answers_dict): - """답변 딕셔너리를 텍스트로 포맷팅""" - if not answers_dict: - return '답변 없음' + def _add_section_title(self, doc, title_text): + """섹션 제목을 굵은 글씨로 추가""" + para = doc.add_paragraph() + run = para.add_run(title_text) + run.bold = True + run.font.size = Pt(12) + + def _add_methodist_table(self, doc, methodist_data): + """감리교 신앙고백서 확인점검 표 추가""" + # 문항 목록 + questions = [ + '1. 우주 만물을 창조하시고 섭리하시며 주관하시는 거룩하시고 자비하시며 오직 한 분이신 아버지 하나님을 믿습니까?', + '2. 말씀이 육신이 되어 우리 가운데 오셔서 하나님의 나라를 선포하시고 십자가에 달려 죽으셨다가 부활승천 하심으로 대속자가 되시고 구세주가 되시는 예수 그리스도를 믿습니까?', + '3. 우리와 함께 계셔서 우리를 거듭나게 하시고 거룩하게 하시며 완전하게 하시며 위안과 힘이 되시는 성령을 믿습니까?', + '4. 성령의 감동으로 기록된 하나님의 말씀인 성경이 구원에 이르는 도리와 신앙생활에 충분한 표준이 됨을 믿습니까?', + '5. 하나님의 은혜로 믿음을 통해 죄사함을 받아 거룩해지며 하나님의 구원의 역사에 동참하도록 부름받음을 믿습니까?', + '6. 예배와 친교, 교육과 봉사, 전도와 선교를 위해 하나가 된 그리스도의 몸인 교회를 믿습니까?', + '7. 만민에게 복음을 전파함으로 하나님의 정의와 사랑을 나누고 평화의 세계를 이루는 모든 사람들이 하나님 앞에 형제됨을 믿습니까?', + '8. 예수 그리스도의 재림과 심판 우리 몸의 부활과 영생 그리고 의의 최후 승리와 영원한 하나님 나라를 믿습니까?' + ] - result = [] - for key, value in answers_dict.items(): - if isinstance(value, dict): - # 중첩된 구조 처리 - result.append(f"{key}: {self._format_answers(value)}") + # 표 생성 (2컬럼: 문항 | 응답) + table = doc.add_table(rows=1, cols=2) + table.style = 'Light Grid Accent 1' + + # 헤더 행 + header_cells = table.rows[0].cells + header_cells[0].text = '문항' + header_cells[1].text = '응답' + # 헤더 굵게 + for cell in header_cells: + for paragraph in cell.paragraphs: + for run in paragraph.runs: + run.bold = True + + # 데이터 행 추가 + for i, question in enumerate(questions, 1): + key = f'q{i}_' + ['father_god', 'jesus_christ', 'holy_spirit', 'bible', 'salvation', 'church', 'mission', 'second_coming'][i-1] + answer = methodist_data.get(key, '') + row = table.add_row() + row.cells[0].text = question + row.cells[1].text = str(answer) if answer else '' + + def _add_general_cult_table(self, doc, general_data): + """이단 일반 점검 표 추가""" + # 문항 목록 + questions = [ + '1. 우리의 구원을 위해서 성경 이외의 가르침이 필요하다고 생각하십니까?', + '2. 어떤 특별한 성경 번역본만이 진리이고 다른 번역본에는 문제가 있다고 생각하십니까?', + '3. 성경의 진리 가운데 그동안 숨겨져 온 부분이 있고, 그 내용을 계시 받은 특별한 사람이 있다고 믿고 있습니까?', + '4. 성경을 해석하기 위해서 비유가 매우 중요하다고 생각하십니까? 비유를 깨닫기 위해서 별도의 성경공부가 필요하다고 생각하십니까?', + '5. 성경의 내용들 가운데 모든 것이 서로 짝이 있습니까?', + '6. 구세주 되시는 예수님은 모든 인류의 구원을 위해서 죽으셨는데 아직도 특별한 사람을 대리자로 세워서 구원사역을 이루실 필요가 있습니까?', + '7. 나는 죄인이라고 생각하십니까? 나의 구원은 확실하십니까? 그 이유는 무엇입니까?', + '8. 우리는 구원 받았을 때 회개했습니다. 그리고 이후에 다시 회개가 필요합니까?', + '9. 우리가 주일을 성수하는 것은 성경적입니까?', + '10. 안식일을 지키는 것이 구원의 조건입니까?', + '11. 성탄절은 예수님이 탄생한 날입니다. 12월 25일에 기념해도 되는 겁니까?', + '12. 예수 그리스도의 재림의 때가 구체적으로 언제인지 정해져 있다고 믿으십니까?', + '13. 성경에서 말하는 동방은 한국을 말하는 것이 맞습니까?', + '14. 당신의 종교적 신념을 지키는 것이 가정을 지키는 것보다 더 중요합니까?', + '15. 당신이 믿는 바를 전하고 사명을 감당하기 위해서 모략을 사용하는 것이 바람직합니까?', + '16. 주일성수, 새벽기도, 십일조 등 기존의 교회제도는 율법의 산물이기에 지킬 필요가 없다고 생각하십니까?', + '17. 사람이 질병에 걸리는 이유는 귀신의 영향 때문입니까?' + ] + + # 표 생성 + table = doc.add_table(rows=1, cols=2) + table.style = 'Light Grid Accent 1' + + # 헤더 행 + header_cells = table.rows[0].cells + header_cells[0].text = '문항' + header_cells[1].text = '응답' + # 헤더 굵게 + for cell in header_cells: + for paragraph in cell.paragraphs: + for run in paragraph.runs: + run.bold = True + + # 데이터 행 추가 + for i, question in enumerate(questions, 1): + key_map = { + 1: 'q1_additional_teaching', + 2: 'q2_special_bible', + 3: 'q3_hidden_truth', + 4: 'q4_parable', + 5: 'q5_pairs', + 6: 'q6_mediator', + 7: 'q7_sin_salvation', # 기타의견란에 작성 + 8: 'q8_repentance', + 9: 'q9_sunday', + 10: 'q10_sabbath', + 11: 'q11_christmas', + 12: 'q12_second_coming_date', + 13: 'q13_east', + 14: 'q14_family', + 15: 'q15_deception', + 16: 'q16_church_system', + 17: 'q17_disease' + } + key = key_map.get(i, f'q{i}') + answer = general_data.get(key, '') + # 7번은 기타의견란에 작성하므로 표에는 기타의견 참조로 표시 + if i == 7: + answer = '(기타의견란 참조)' if general_data.get('other_opinions') else '(답변 없음)' else: - result.append(f"{key}: {value}") + answer = str(answer) if answer else '' + row = table.add_row() + row.cells[0].text = question + row.cells[1].text = answer + + def _add_specific_cult_table(self, doc, specific_data, questions_list): + """이단 상세 점검 표 추가""" + if not questions_list: + doc.add_paragraph('(이단 상세 점검 답변 없음)') + return - return '\n'.join(result) - + # 표 생성 + table = doc.add_table(rows=1, cols=2) + table.style = 'Light Grid Accent 1' + + # 헤더 행 + header_cells = table.rows[0].cells + header_cells[0].text = '문항' + header_cells[1].text = '응답' + # 헤더 굵게 + for cell in header_cells: + for paragraph in cell.paragraphs: + for run in paragraph.runs: + run.bold = True + + # 문항 목록과 답변 매칭 + q_index = 1 # 실제 답변 키 인덱스 + for i, question in enumerate(questions_list, 1): + # 기타의견란에 작성하는 문항은 건너뛰기 + if '기타의견란' in question or '기타의견' in question: + continue + + key = f'q{q_index}' + answer = specific_data.get(key, '') + row = table.add_row() + # 문항 텍스트 그대로 사용 (번호 포함) + row.cells[0].text = question.strip() + row.cells[1].text = str(answer) if answer else '' + q_index += 1