[DOCX 3종 생성 (UTF-8, 편집 가능)] - 01_소프트웨어_저작권_등록_신청서.docx (37KB) 한국저작권위원회 제출용 / 맑은 고딕 / 색상 섹션 - 02_소프트웨어사업자_신고서.docx (37KB) 과학기술정보통신부/KOSA 제출용 - 03_조달청_나라장터_물품_등록_신청서.docx (38KB) 공공기관 납품용 나라장터 등록 [generate_docx.py 특징] - python-docx 기반 (한글 UTF-8 완전 지원) - 검정 박스 없음 (맑은 고딕 직접 적용) - 편집 가능: Word / 한글(HWP) / LibreOffice - 섹션별 색상 배너 (파란/빨간/주황 테마) - 서명란, 첨부서류, 수수료 안내 포함 [certification/source/ 저작권 등록용 소스코드] - 01_core_ssh_agentless.py (450줄) - 에이전트리스 SSH 핵심 - 02_core_license_engine.py (455줄) - AES-256-GCM 라이선스 - 03_router_sr_management.py(501줄) - SR 관리 API - 04_core_ai_classifier.py (90줄) - AI 티켓 분류 - 05_frontend_dashboard.js (200줄) - 대시보드 프론트 - README.md - 제출 안내 및 독창성 설명 - 모든 파일: 영업비밀(암호화키) 마스킹 처리 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
668 lines
32 KiB
Python
668 lines
32 KiB
Python
"""
|
|
GUARDiA ITSM 프로그램 등록 신청서 — 3종 개별 PDF 생성기
|
|
실행: python generate_each_pdf.py
|
|
"""
|
|
import os, sys
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
from reportlab.lib import colors
|
|
from reportlab.lib.pagesizes import A4
|
|
from reportlab.lib.units import mm
|
|
from reportlab.lib.styles import ParagraphStyle
|
|
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
|
|
from reportlab.platypus import (
|
|
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
|
|
HRFlowable, PageBreak, KeepTogether
|
|
)
|
|
from reportlab.pdfbase import pdfmetrics
|
|
from reportlab.pdfbase.ttfonts import TTFont
|
|
|
|
# ── 폰트 등록 ─────────────────────────────────────────────────
|
|
def reg_fonts():
|
|
for p in ["C:/Windows/Fonts/malgun.ttf",
|
|
"/usr/share/fonts/truetype/nanum/NanumGothic.ttf"]:
|
|
if os.path.exists(p):
|
|
try: pdfmetrics.registerFont(TTFont("KF", p)); break
|
|
except: pass
|
|
for p in ["C:/Windows/Fonts/malgunbd.ttf",
|
|
"/usr/share/fonts/truetype/nanum/NanumGothicBold.ttf"]:
|
|
if os.path.exists(p):
|
|
try: pdfmetrics.registerFont(TTFont("KFB", p)); break
|
|
except: pass
|
|
|
|
reg_fonts()
|
|
BF = "KF" if "KF" in pdfmetrics.getRegisteredFontNames() else "Helvetica"
|
|
BBF = "KFB" if "KFB" in pdfmetrics.getRegisteredFontNames() else "Helvetica-Bold"
|
|
W, H = A4
|
|
MARGIN = 18*mm
|
|
WC = W - 2*MARGIN
|
|
|
|
# ── 공통 색상 ──────────────────────────────────────────────────
|
|
C = {
|
|
"navy": colors.HexColor("#1e3a5f"),
|
|
"blue": colors.HexColor("#0051A2"),
|
|
"lblue": colors.HexColor("#EBF3FB"),
|
|
"red": colors.HexColor("#DC2626"),
|
|
"lred": colors.HexColor("#FEE2E2"),
|
|
"orange": colors.HexColor("#C2410C"),
|
|
"lorg": colors.HexColor("#FED7AA"),
|
|
"green": colors.HexColor("#065F46"),
|
|
"lgrn": colors.HexColor("#D1FAE5"),
|
|
"gray": colors.HexColor("#64748B"),
|
|
"lgray": colors.HexColor("#F3F4F6"),
|
|
"white": colors.white,
|
|
"black": colors.black,
|
|
"border": colors.HexColor("#CBD5E1"),
|
|
}
|
|
|
|
def S(nm, **kw):
|
|
d = dict(fontName=BF, fontSize=9.5, leading=15, textColor=C["black"])
|
|
d.update(kw); return ParagraphStyle(nm, **d)
|
|
|
|
# ── 공통 컴포넌트 ──────────────────────────────────────────────
|
|
def banner(main_title, sub_title, accent_color):
|
|
"""문서 최상단 컬러 배너."""
|
|
data = [
|
|
[Paragraph(main_title, S("bt", fontName=BBF, fontSize=20, textColor=C["white"], alignment=TA_CENTER, leading=26))],
|
|
[Paragraph(sub_title, S("bs", fontName=BF, fontSize=10, textColor=colors.HexColor("#BDE3FF"), alignment=TA_CENTER))],
|
|
]
|
|
t = Table(data, colWidths=[WC])
|
|
t.setStyle(TableStyle([
|
|
("BACKGROUND", (0,0), (-1,-1), accent_color),
|
|
("TOPPADDING", (0,0), (-1,-1), 16),
|
|
("BOTTOMPADDING", (0,0), (-1,-1), 16),
|
|
("ROUNDEDCORNERS",(0,0), (-1,-1), [8]),
|
|
]))
|
|
return t
|
|
|
|
def sec(title, color):
|
|
t = Table([[Paragraph(f" {title}", S("sc", fontName=BBF, fontSize=11, textColor=C["white"], leading=16))]], colWidths=[WC])
|
|
t.setStyle(TableStyle([
|
|
("BACKGROUND", (0,0), (-1,-1), color),
|
|
("TOPPADDING", (0,0), (-1,-1), 6),
|
|
("BOTTOMPADDING", (0,0), (-1,-1), 6),
|
|
("ROUNDEDCORNERS",(0,0), (-1,-1), [5]),
|
|
]))
|
|
return t
|
|
|
|
def kv(rows, lbg, cw=None):
|
|
"""키-값 테이블."""
|
|
if cw is None: cw = [40*mm, WC-40*mm]
|
|
cells = []
|
|
for r in rows:
|
|
if len(r) == 2:
|
|
cells.append([Paragraph(r[0], S("kl", fontName=BBF, textColor=C["black"], alignment=TA_CENTER)),
|
|
Paragraph(r[1], S("kv"))])
|
|
elif len(r) == 3: # 키, 값, 필수여부
|
|
cells.append([Paragraph(r[0], S("kl", fontName=BBF, textColor=C["black"], alignment=TA_CENTER)),
|
|
Paragraph(r[1], S("kv")),
|
|
Paragraph(r[2], S("kr", fontName=BBF, fontSize=8, textColor=C["red"], alignment=TA_CENTER))])
|
|
t = Table(cells, colWidths=cw)
|
|
t.setStyle(TableStyle([
|
|
("BACKGROUND", (0,0), (0,-1), lbg),
|
|
("FONTSIZE", (0,0), (-1,-1), 9.5),
|
|
("ALIGN", (0,0), (0,-1), "CENTER"),
|
|
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
|
|
("TOPPADDING", (0,0), (-1,-1), 5),
|
|
("BOTTOMPADDING", (0,0), (-1,-1), 5),
|
|
("LEFTPADDING", (0,0), (-1,-1), 7),
|
|
("GRID", (0,0), (-1,-1), 0.5, C["border"]),
|
|
]))
|
|
return t
|
|
|
|
def empty_kv(rows, lbg, cw=None):
|
|
"""입력 란 (빈 칸 강조)."""
|
|
if cw is None: cw = [40*mm, WC-40*mm]
|
|
cells = [[Paragraph(k, S("ek", fontName=BBF, alignment=TA_CENTER)),
|
|
Paragraph(v, S("ev", textColor=C["gray"]))] for k, v in rows]
|
|
t = Table(cells, colWidths=cw)
|
|
t.setStyle(TableStyle([
|
|
("BACKGROUND", (0,0), (0,-1), lbg),
|
|
("FONTSIZE", (0,0), (-1,-1), 9.5),
|
|
("ALIGN", (0,0), (0,-1), "CENTER"),
|
|
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
|
|
("TOPPADDING", (0,0), (-1,-1), 7),
|
|
("BOTTOMPADDING", (0,0), (-1,-1), 7),
|
|
("LEFTPADDING", (0,0), (-1,-1), 7),
|
|
("GRID", (0,0), (-1,-1), 0.5, C["border"]),
|
|
]))
|
|
return t
|
|
|
|
def sign_area(date_label="신청일"):
|
|
rows = [
|
|
[Paragraph(date_label, S("sl", fontName=BBF, alignment=TA_CENTER)),
|
|
Paragraph("2026년 월 일", S("sv", fontSize=10.5))],
|
|
[Paragraph("회 사 명", S("sl", fontName=BBF, alignment=TA_CENTER)),
|
|
Paragraph("(주)지오정보기술", S("sv", fontSize=10.5))],
|
|
[Paragraph("대 표 자", S("sl", fontName=BBF, alignment=TA_CENTER)),
|
|
Paragraph(" (인)", S("sv", fontSize=10.5))],
|
|
]
|
|
t = Table(rows, colWidths=[35*mm, WC-35*mm])
|
|
t.setStyle(TableStyle([
|
|
("BACKGROUND", (0,0), (0,-1), C["lgray"]),
|
|
("FONTNAME", (0,0), (0,-1), BBF),
|
|
("FONTSIZE", (0,0), (-1,-1), 10),
|
|
("ALIGN", (0,0), (0,-1), "CENTER"),
|
|
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
|
|
("TOPPADDING", (0,0), (-1,-1), 8),
|
|
("BOTTOMPADDING", (0,0), (-1,-1), 8),
|
|
("LEFTPADDING", (0,0), (-1,-1), 8),
|
|
("LINEBELOW", (1,2), (1,2), 1, C["black"]),
|
|
("GRID", (0,0), (-1,-1), 0.5, C["border"]),
|
|
]))
|
|
return t
|
|
|
|
def footer(org_name):
|
|
return [
|
|
Spacer(1, 8*mm),
|
|
HRFlowable(width=WC, color=C["blue"], thickness=1.5),
|
|
Spacer(1, 3*mm),
|
|
Paragraph(f"{org_name} | (주)지오정보기술 | GUARDiA ITSM v2.0 | Copyright © 2026",
|
|
S("ft", fontSize=7.5, textColor=C["gray"], alignment=TA_CENTER, leading=11)),
|
|
]
|
|
|
|
def on_page_num(pname):
|
|
def fn(canvas, doc):
|
|
canvas.saveState()
|
|
canvas.setFont("Helvetica", 7)
|
|
canvas.setFillColor(C["gray"])
|
|
canvas.drawRightString(W-MARGIN, 9*mm, f"- {doc.page} -")
|
|
canvas.drawString(MARGIN, 9*mm, pname)
|
|
canvas.restoreState()
|
|
return fn
|
|
|
|
def note(text):
|
|
return Paragraph(f"※ {text}", S("nt", fontSize=8, textColor=C["gray"], leading=12, leftIndent=8))
|
|
|
|
def make_doc(path, title):
|
|
return SimpleDocTemplate(path, pagesize=A4,
|
|
leftMargin=MARGIN, rightMargin=MARGIN,
|
|
topMargin=MARGIN, bottomMargin=MARGIN,
|
|
title=title, author="(주)지오정보기술")
|
|
|
|
|
|
# ══════════════════════════════════════════════════════════════
|
|
# PDF 01: 소프트웨어 저작권 등록 신청서
|
|
# ══════════════════════════════════════════════════════════════
|
|
def make_copyright_pdf(out):
|
|
doc = make_doc(out, "소프트웨어 저작권 등록 신청서")
|
|
story = []
|
|
AC = C["blue"]
|
|
LBG = C["lblue"]
|
|
|
|
story.append(banner(
|
|
"소프트웨어 저작권 등록 신청서",
|
|
"컴퓨터프로그램저작물 등록 | 한국저작권위원회 | www.copyright.or.kr",
|
|
AC
|
|
))
|
|
story.append(Spacer(1, 5*mm))
|
|
story.append(Paragraph("컴퓨터프로그램저작물 등록신청서",
|
|
S("h1", fontName=BBF, fontSize=16, textColor=AC, alignment=TA_CENTER, leading=22)))
|
|
story.append(Paragraph(
|
|
"「저작권법」 제53조 및 「저작권법 시행규칙」 제24조에 따라 다음과 같이 등록을 신청합니다.",
|
|
S("ref", fontName=BF, fontSize=9, textColor=C["gray"], alignment=TA_CENTER, leading=14)))
|
|
story.append(Spacer(1, 6*mm))
|
|
|
|
# 1. 저작물 정보
|
|
story.append(sec("1. 저작물 정보 (필수 기재)", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
story.append(kv([
|
|
["저 작 물 명", "GUARDiA ITSM (가이더)"],
|
|
["영 문 명", "GUARDiA ITSM Platform"],
|
|
["저작물 종류", "컴퓨터프로그램저작물"],
|
|
["프로그램 언어","Python 3.11, JavaScript (React 18)"],
|
|
["창 작 연 도", "2026년"],
|
|
["공 표 여 부", "공표 (2026년 / 인터넷 웹사이트 www.zioinfo.co.kr)"],
|
|
["등록 목적", "양도 및 이용허락"],
|
|
["버 전", "v2.0.0"],
|
|
], LBG))
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
# 2. 저작자 / 저작권자
|
|
story.append(sec("2. 저작자 및 저작권자 정보", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
story.append(kv([
|
|
["구 분", "법인 저작권자"],
|
|
["저 작 자 명", "(주)지오정보기술"],
|
|
["저 작 권 자", "(주)지오정보기술 (저작자와 동일)"],
|
|
["법인등록번호", "000000-0000000"],
|
|
["사업자등록번호", "000-00-00000"],
|
|
["주 소", "서울특별시 (상세주소)"],
|
|
["대 표 자", "(대표이사명)"],
|
|
["전 화", "02-000-0000"],
|
|
["이 메 일", "copyright@zioinfo.co.kr"],
|
|
], LBG))
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
# 3. 저작물 설명
|
|
story.append(sec("3. 저작물 설명 (200자 이내)", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
desc_box = Table([[Paragraph(
|
|
"GUARDiA ITSM은 공공기관의 레거시 IT 인프라를 AI로 자율 운영하는 온프레미스 통합 관리 플랫폼입니다. "
|
|
"메신저 한 줄 명령으로 에이전트 설치 없이 SSH/SFTP를 통해 WAS 배포·운영을 자동화하며, "
|
|
"SR 관리, 인시던트 대응, 변경관리, CMDB, PMS 등 ITSM 전 기능과 "
|
|
"AI 자동화(티켓분류·RCA·이상탐지·예측)를 단일 플랫폼에서 제공합니다.",
|
|
S("db", leading=16, alignment=TA_JUSTIFY)
|
|
)]], colWidths=[WC])
|
|
desc_box.setStyle(TableStyle([
|
|
("BACKGROUND", (0,0), (-1,-1), LBG),
|
|
("TOPPADDING", (0,0), (-1,-1), 12),
|
|
("BOTTOMPADDING", (0,0), (-1,-1), 12),
|
|
("LEFTPADDING", (0,0), (-1,-1), 14),
|
|
("RIGHTPADDING", (0,0), (-1,-1), 14),
|
|
("ROUNDEDCORNERS",(0,0), (-1,-1), [6]),
|
|
]))
|
|
story.append(desc_box)
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
# 4. 첨부 서류
|
|
story.append(sec("4. 첨부 서류", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
attach_h = [["번호", "서류명", "비고"]]
|
|
attach_d = [
|
|
["1", "저작물 설명서", "본 신청서 3항 활용 가능"],
|
|
["2", "소스코드 일부 출력물", "핵심 기능 200줄 이상 (영업비밀 마스킹 후 제출)"],
|
|
["3", "법인등기부등본", "최근 3개월 이내 발급본"],
|
|
["4", "대리인 위임장", "대리신청 시에만 제출"],
|
|
]
|
|
at = Table(
|
|
[[Paragraph(v, S(f"a{i}", alignment=TA_CENTER if i==0 else TA_LEFT, fontSize=9)) for i,v in enumerate(r)] for r in attach_h+attach_d],
|
|
colWidths=[12*mm, 72*mm, WC-84*mm]
|
|
)
|
|
at.setStyle(TableStyle([
|
|
("BACKGROUND", (0,0), (-1,0), AC),
|
|
("TEXTCOLOR", (0,0), (-1,0), C["white"]),
|
|
("FONTNAME", (0,0), (-1,0), BBF),
|
|
("ROWBACKGROUNDS",(0,1), (-1,-1), [C["white"], LBG]),
|
|
("FONTSIZE", (0,0), (-1,-1), 9),
|
|
("ALIGN", (0,0), (0,-1), "CENTER"),
|
|
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
|
|
("TOPPADDING", (0,0), (-1,-1), 5),
|
|
("BOTTOMPADDING", (0,0), (-1,-1), 5),
|
|
("LEFTPADDING", (0,0), (-1,-1), 7),
|
|
("GRID", (0,0), (-1,-1), 0.5, C["border"]),
|
|
]))
|
|
story.append(at)
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
# 5. 수수료 안내
|
|
story.append(sec("5. 등록 수수료", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
fee = Table([
|
|
[Paragraph("구분", S("fh", fontName=BBF, alignment=TA_CENTER)),
|
|
Paragraph("금액", S("fh", fontName=BBF, alignment=TA_CENTER)),
|
|
Paragraph("비고", S("fh", fontName=BBF, alignment=TA_CENTER))],
|
|
[Paragraph("컴퓨터프로그램저작물 등록", S("fd")),
|
|
Paragraph("40,000원", S("fd", alignment=TA_CENTER)),
|
|
Paragraph("온라인 신청 시 카드/계좌이체", S("fd"))],
|
|
], colWidths=[70*mm, 30*mm, WC-100*mm])
|
|
fee.setStyle(TableStyle([
|
|
("BACKGROUND", (0,0), (-1,0), AC),
|
|
("TEXTCOLOR", (0,0), (-1,0), C["white"]),
|
|
("BACKGROUND", (0,1), (-1,1), LBG),
|
|
("FONTSIZE", (0,0), (-1,-1), 9.5),
|
|
("ALIGN", (1,1), (1,1), "CENTER"),
|
|
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
|
|
("TOPPADDING", (0,0), (-1,-1), 6),
|
|
("BOTTOMPADDING", (0,0), (-1,-1), 6),
|
|
("LEFTPADDING", (0,0), (-1,-1), 8),
|
|
("GRID", (0,0), (-1,-1), 0.5, C["border"]),
|
|
]))
|
|
story.append(fee)
|
|
story.append(Spacer(1, 3*mm))
|
|
story.append(note("신청 방법: 한국저작권위원회 홈페이지(www.copyright.or.kr) → 저작권 등록 → 온라인 신청"))
|
|
story.append(note("처리 기간: 약 2주 (보완 요청 시 추가 소요)"))
|
|
story.append(Spacer(1, 6*mm))
|
|
|
|
story.append(Paragraph("위와 같이 컴퓨터프로그램저작물 등록을 신청합니다.",
|
|
S("pledge", fontName=BF, fontSize=10, alignment=TA_CENTER, leading=16)))
|
|
story.append(Spacer(1, 6*mm))
|
|
story.append(sign_area("신 청 일"))
|
|
|
|
for item in footer("한국저작권위원회 제출용"):
|
|
story.append(item)
|
|
|
|
doc.build(story, onFirstPage=on_page_num("소프트웨어 저작권 등록 신청서 | 한국저작권위원회"),
|
|
onLaterPages=on_page_num("소프트웨어 저작권 등록 신청서 | 한국저작권위원회"))
|
|
print(f"[OK] 01_소프트웨어_저작권_등록_신청서.pdf ({Path(out).stat().st_size//1024}KB)")
|
|
|
|
|
|
# ══════════════════════════════════════════════════════════════
|
|
# PDF 02: 소프트웨어사업자 신고서
|
|
# ══════════════════════════════════════════════════════════════
|
|
def make_bizreg_pdf(out):
|
|
doc = make_doc(out, "소프트웨어사업자 신고서")
|
|
story = []
|
|
AC = C["red"]
|
|
LBG = C["lred"]
|
|
|
|
story.append(banner(
|
|
"소프트웨어사업자 신고서",
|
|
"소프트웨어진흥법 제24조 | 과학기술정보통신부 / 한국SW산업협회(KOSA)",
|
|
AC
|
|
))
|
|
story.append(Spacer(1, 5*mm))
|
|
story.append(Paragraph("소프트웨어사업자 신고서",
|
|
S("h2", fontName=BBF, fontSize=16, textColor=AC, alignment=TA_CENTER, leading=22)))
|
|
story.append(Paragraph(
|
|
"「소프트웨어진흥법」 제24조 및 같은 법 시행규칙 제14조에 따라 다음과 같이 신고합니다.",
|
|
S("ref2", fontName=BF, fontSize=9, textColor=C["gray"], alignment=TA_CENTER, leading=14)))
|
|
story.append(Spacer(1, 6*mm))
|
|
|
|
# 1. 신고인 정보
|
|
story.append(sec("1. 신고인(사업자) 정보", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
story.append(kv([
|
|
["상 호", "(주)지오정보기술"],
|
|
["대 표 자", "(대표이사명)"],
|
|
["사업자등록번호", "000-00-00000"],
|
|
["법인등록번호", "000000-0000000"],
|
|
["소 재 지", "서울특별시 (상세주소)"],
|
|
["전 화", "02-000-0000"],
|
|
["팩 스", "02-000-0001"],
|
|
["이 메 일", "sw@zioinfo.co.kr"],
|
|
["설 립 일", "2000년 월 일"],
|
|
["자 본 금", " 원"],
|
|
["종업원 수", " 명 (정규직 기준)"],
|
|
], LBG))
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
# 2. 소프트웨어사업 종류
|
|
story.append(sec("2. 소프트웨어사업의 종류 (해당 항목 모두 선택)", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
biz = [
|
|
["[V]", "소프트웨어 개발업", "GUARDiA ITSM 등 소프트웨어 개발·판매"],
|
|
["[V]", "소프트웨어 공급업", "GUARDiA ITSM 라이선스 공급"],
|
|
["[V]", "소프트웨어 유지관리업", "GUARDiA ITSM 기술지원·유지보수"],
|
|
["[V]", "소프트웨어 자문·평가·진단업", "IT인프라 컨설팅·진단"],
|
|
["[ ]", "정보기술서비스업", "—"],
|
|
["[ ]", "기타 ( 업)", "—"],
|
|
]
|
|
bh = [["선택", "사업 종류", "세부 내용"]]
|
|
bd = [[Paragraph(v, S(f"bv{i}", textColor=AC if "V" in v else C["gray"],
|
|
fontName=BBF, fontSize=10, alignment=TA_CENTER)),
|
|
Paragraph(n, S(f"bn{i}", fontSize=9.5)),
|
|
Paragraph(d, S(f"bd{i}", fontSize=8.5, textColor=C["gray"]))]
|
|
for i,(v,n,d) in enumerate(biz)]
|
|
bt = Table(bh+bd, colWidths=[16*mm, 65*mm, WC-81*mm])
|
|
bt.setStyle(TableStyle([
|
|
("BACKGROUND", (0,0), (-1,0), AC),
|
|
("TEXTCOLOR", (0,0), (-1,0), C["white"]),
|
|
("FONTNAME", (0,0), (-1,0), BBF),
|
|
("ROWBACKGROUNDS",(0,1), (-1,-1), [C["white"], LBG]),
|
|
("FONTSIZE", (0,0), (-1,-1), 9),
|
|
("ALIGN", (0,0), (0,-1), "CENTER"),
|
|
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
|
|
("TOPPADDING", (0,0), (-1,-1), 5),
|
|
("BOTTOMPADDING", (0,0), (-1,-1), 5),
|
|
("LEFTPADDING", (0,0), (-1,-1), 7),
|
|
("GRID", (0,0), (-1,-1), 0.5, C["border"]),
|
|
]))
|
|
story.append(bt)
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
# 3. 기술인력
|
|
story.append(sec("3. 기술인력 현황", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
story.append(empty_kv([
|
|
["총 직원 수", " 명"],
|
|
["SW 기술인력", " 명 (전체의 %)"],
|
|
["정보처리기사", " 명"],
|
|
["정보처리산업기사"," 명"],
|
|
["기타 SW 관련 자격", " 명"],
|
|
], LBG))
|
|
story.append(Spacer(1, 3*mm))
|
|
story.append(note("소프트웨어사업자 신고 기준: 상시근로자 1명 이상 또는 SW기술인력 1명 이상"))
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
# 4. 주요 제품/서비스
|
|
story.append(sec("4. 주요 소프트웨어 제품 및 서비스", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
prod_h = [["제품/서비스명", "분류", "출시연도", "연매출(백만원)"]]
|
|
prod_d = [
|
|
["GUARDiA ITSM", "IT서비스관리 플랫폼", "2026", ""],
|
|
["IT인프라 컨설팅", "컨설팅 서비스", "2000", ""],
|
|
["SI 구축 서비스", "정보화사업", "2000", ""],
|
|
]
|
|
ph = Table(prod_h+prod_d, colWidths=[50*mm, 40*mm, 22*mm, WC-112*mm])
|
|
ph.setStyle(TableStyle([
|
|
("BACKGROUND", (0,0), (-1,0), AC),
|
|
("TEXTCOLOR", (0,0), (-1,0), C["white"]),
|
|
("FONTNAME", (0,0), (-1,0), BBF),
|
|
("ROWBACKGROUNDS",(0,1), (-1,-1), [C["white"], LBG]),
|
|
("FONTSIZE", (0,0), (-1,-1), 9),
|
|
("ALIGN", (0,0), (-1,0), "CENTER"),
|
|
("ALIGN", (2,1), (-1,-1), "CENTER"),
|
|
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
|
|
("TOPPADDING", (0,0), (-1,-1), 5),
|
|
("BOTTOMPADDING", (0,0), (-1,-1), 5),
|
|
("LEFTPADDING", (0,0), (-1,-1), 7),
|
|
("GRID", (0,0), (-1,-1), 0.5, C["border"]),
|
|
]))
|
|
story.append(ph)
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
# 5. SW사업 실적
|
|
story.append(sec("5. 소프트웨어사업 실적 (최근 3년)", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
perf_h = [["연도", "발주기관", "사업명", "계약금액\n(백만원)", "기간"]]
|
|
perf_d = [
|
|
["2024", "", "GUARDiA ITSM 구축사업", "", ""],
|
|
["2025", "", "인프라 자동화 컨설팅 사업", "", ""],
|
|
["2026", "", "GUARDiA ITSM 고도화 사업", "", ""],
|
|
]
|
|
pt = Table(perf_h+perf_d, colWidths=[14*mm, 40*mm, 58*mm, 22*mm, WC-134*mm])
|
|
pt.setStyle(TableStyle([
|
|
("BACKGROUND", (0,0), (-1,0), AC),
|
|
("TEXTCOLOR", (0,0), (-1,0), C["white"]),
|
|
("FONTNAME", (0,0), (-1,0), BBF),
|
|
("ROWBACKGROUNDS",(0,1), (-1,-1), [C["white"], LBG]),
|
|
("FONTSIZE", (0,0), (-1,-1), 8.5),
|
|
("ALIGN", (0,0), (-1,0), "CENTER"),
|
|
("ALIGN", (0,1), (0,-1), "CENTER"),
|
|
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
|
|
("TOPPADDING", (0,0), (-1,-1), 5),
|
|
("BOTTOMPADDING", (0,0), (-1,-1), 5),
|
|
("LEFTPADDING", (0,0), (-1,-1), 5),
|
|
("GRID", (0,0), (-1,-1), 0.5, C["border"]),
|
|
]))
|
|
story.append(pt)
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
story.append(note("신고 방법: 한국SW산업협회(swit.or.kr) 온라인 신고 또는 과학기술정보통신부 제출"))
|
|
story.append(note("처리 기간: 약 2주 | 수수료: 없음"))
|
|
story.append(note("확인서 발급: 신고 완료 후 '소프트웨어사업자 신고확인서' 발급 (GS인증 신청 시 필요)"))
|
|
story.append(Spacer(1, 6*mm))
|
|
|
|
story.append(Paragraph("위와 같이 소프트웨어사업자 신고를 합니다.",
|
|
S("pledge2", fontName=BF, fontSize=10, alignment=TA_CENTER, leading=16)))
|
|
story.append(Spacer(1, 6*mm))
|
|
story.append(sign_area("신 고 일"))
|
|
|
|
for item in footer("과학기술정보통신부 / 한국SW산업협회(KOSA) 제출용"):
|
|
story.append(item)
|
|
|
|
doc.build(story, onFirstPage=on_page_num("소프트웨어사업자 신고서 | 과학기술정보통신부"),
|
|
onLaterPages=on_page_num("소프트웨어사업자 신고서 | 과학기술정보통신부"))
|
|
print(f"[OK] 02_소프트웨어사업자_신고서.pdf ({Path(out).stat().st_size//1024}KB)")
|
|
|
|
|
|
# ══════════════════════════════════════════════════════════════
|
|
# PDF 03: 조달청 나라장터 물품 등록 신청서
|
|
# ══════════════════════════════════════════════════════════════
|
|
def make_g2b_pdf(out):
|
|
doc = make_doc(out, "조달청 나라장터 물품 등록 신청서")
|
|
story = []
|
|
AC = C["orange"]
|
|
LBG = C["lorg"]
|
|
|
|
story.append(banner(
|
|
"조달청 나라장터 물품 등록 신청서",
|
|
"국가종합전자조달시스템 | 조달청 | www.g2b.go.kr",
|
|
AC
|
|
))
|
|
story.append(Spacer(1, 5*mm))
|
|
story.append(Paragraph("소프트웨어 물품 등록 신청서 (나라장터)",
|
|
S("h3", fontName=BBF, fontSize=16, textColor=AC, alignment=TA_CENTER, leading=22)))
|
|
story.append(Paragraph(
|
|
"공공기관 납품을 위한 소프트웨어 물품을 국가종합전자조달시스템(나라장터)에 등록합니다.",
|
|
S("ref3", fontName=BF, fontSize=9, textColor=C["gray"], alignment=TA_CENTER, leading=14)))
|
|
story.append(Spacer(1, 6*mm))
|
|
|
|
# 1. 공급업체 정보
|
|
story.append(sec("1. 공급업체 정보", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
story.append(kv([
|
|
["업 체 명", "(주)지오정보기술"],
|
|
["대 표 자", "(대표이사명)"],
|
|
["사업자등록번호", "000-00-00000"],
|
|
["소 재 지", "서울특별시 (상세주소)"],
|
|
["대 표 전 화", "02-000-0000"],
|
|
["팩 스", "02-000-0001"],
|
|
["담 당 자", "(담당자명) / 02-000-0000 / g2b@zioinfo.co.kr"],
|
|
["계 좌 번 호", "은행명 000-000-000000 (주)지오정보기술"],
|
|
], LBG))
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
# 2. 물품 기본 정보
|
|
story.append(sec("2. 물품 기본 정보", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
story.append(kv([
|
|
["물 품 명", "GUARDiA ITSM (AI 기반 IT서비스관리 플랫폼)"],
|
|
["규격 / 모델명", "GUARDiA ITSM v2.0"],
|
|
["물품 분류코드", "소프트웨어 > 시스템관리 > IT서비스관리 (ITSM)"],
|
|
["원 산 지", "국내산 (대한민국)"],
|
|
["제 조 사", "(주)지오정보기술"],
|
|
["브 랜 드", "GUARDiA"],
|
|
["단 위", "식 (라이선스)"],
|
|
["품 목 번 호", "(나라장터 등록 후 부여)"],
|
|
], LBG))
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
# 3. 가격 정보
|
|
story.append(sec("3. 가격 정보 (에디션별 라이선스)", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
price_h = [["에디션", "대상 규모", "기준 단가 (원)", "연간 유지보수율", "비고"]]
|
|
price_d = [
|
|
["COMMUNITY", "소규모 / 검토용", "0 (무료)", "—", "기관 1개·사용자 10명·서버 20대"],
|
|
["STANDARD", "중형 기관 (50기관 이하)", "별도 협의", "15%", "사용자 200명·서버 200대"],
|
|
["ENTERPRISE", "대형 관공서 / 광역기관", "별도 협의", "15%", "무제한 (전용 지원 포함)"],
|
|
]
|
|
pt = Table(price_h+price_d, colWidths=[24*mm, 36*mm, 30*mm, 22*mm, WC-112*mm])
|
|
pt.setStyle(TableStyle([
|
|
("BACKGROUND", (0,0), (-1,0), AC),
|
|
("TEXTCOLOR", (0,0), (-1,0), C["white"]),
|
|
("FONTNAME", (0,0), (-1,0), BBF),
|
|
("ROWBACKGROUNDS",(0,1), (-1,-1), [C["white"], LBG]),
|
|
("FONTSIZE", (0,0), (-1,-1), 8.5),
|
|
("ALIGN", (0,0), (-1,0), "CENTER"),
|
|
("ALIGN", (0,1), (1,-1), "CENTER"),
|
|
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
|
|
("TOPPADDING", (0,0), (-1,-1), 5),
|
|
("BOTTOMPADDING", (0,0), (-1,-1), 5),
|
|
("LEFTPADDING", (0,0), (-1,-1), 5),
|
|
("GRID", (0,0), (-1,-1), 0.5, C["border"]),
|
|
]))
|
|
story.append(pt)
|
|
story.append(Spacer(1, 3*mm))
|
|
story.append(note("나라장터 등록 단가는 실제 계약 시 협의를 통해 결정됩니다."))
|
|
story.append(note("중소기업 직접생산확인증명서 제출 시 중소기업제품 우선구매 적용 가능합니다."))
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
# 4. 제품 규격서
|
|
story.append(sec("4. 제품 규격서 (설치 환경 및 요구 사양)", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
story.append(kv([
|
|
["운영체제(서버)", "Ubuntu 20.04+ / CentOS 7+ / RHEL 8+ / Windows Server 2019+"],
|
|
["최소 CPU", "4코어 이상 (Intel / AMD x86_64)"],
|
|
["최소 RAM", "16GB 이상 (Ollama AI 엔진 포함)"],
|
|
["필요 디스크", "50GB 이상"],
|
|
["네트워크", "내부망 전용 지원 — 인터넷 연결 불필요 (완전 폐쇄망 운영 가능)"],
|
|
["클라이언트", "Chrome 90+ / Firefox 88+ / Edge 90+ (브라우저 기반, 설치 불필요)"],
|
|
["DB 지원", "SQLite (내장) / PostgreSQL 15+ (선택)"],
|
|
["AI 엔진", "Ollama 온프레미스 LLM (외부 클라우드 API 미사용)"],
|
|
], LBG))
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
# 5. 주요 기능
|
|
story.append(sec("5. 주요 기능 요약", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
func_h = [["기능 영역", "주요 기능 내용", "공공기관 필수 여부"]]
|
|
func_d = [
|
|
["SR / ITSM", "서비스요청 접수·처리, 인시던트, 변경관리, SLA, CMDB", "필수"],
|
|
["AI 자동화", "Ollama 온프레미스 AI — 티켓분류, RCA, 이상탐지, 예측", "선택"],
|
|
["ChatOps", "카카오워크·네이버웍스·슬랙 25개 봇 명령어 지원", "선택"],
|
|
["에이전트리스", "SSH/SFTP 기반 WAS 자동 배포·운영 (서버 설치 불필요)", "필수"],
|
|
["PMS", "WBS, 산출물 관리, 일간/주간/월간 보고서 자동 생성", "필수"],
|
|
["보안", "JWT+MFA+AES-256+PAM+감사로그+취약점스캔+시큐어코딩", "필수"],
|
|
["공공기관 준수", "행안부 체크리스트 19개, 웹접근성(KWCAG 2.1), PIPA", "필수"],
|
|
]
|
|
ft = Table(func_h+func_d, colWidths=[28*mm, 95*mm, WC-123*mm])
|
|
ft.setStyle(TableStyle([
|
|
("BACKGROUND", (0,0), (-1,0), AC),
|
|
("TEXTCOLOR", (0,0), (-1,0), C["white"]),
|
|
("FONTNAME", (0,0), (-1,0), BBF),
|
|
("ROWBACKGROUNDS",(0,1), (-1,-1), [C["white"], LBG]),
|
|
("FONTSIZE", (0,0), (-1,-1), 9),
|
|
("ALIGN", (0,0), (-1,0), "CENTER"),
|
|
("ALIGN", (0,1), (0,-1), "CENTER"),
|
|
("ALIGN", (2,1), (2,-1), "CENTER"),
|
|
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
|
|
("TOPPADDING", (0,0), (-1,-1), 5),
|
|
("BOTTOMPADDING", (0,0), (-1,-1), 5),
|
|
("LEFTPADDING", (0,0), (-1,-1), 7),
|
|
("GRID", (0,0), (-1,-1), 0.5, C["border"]),
|
|
]))
|
|
story.append(ft)
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
# 6. 인증 및 실적
|
|
story.append(sec("6. 인증 현황 및 납품 실적", AC))
|
|
story.append(Spacer(1, 3*mm))
|
|
story.append(kv([
|
|
["GS인증(TTA)", "GS 1등급 취득 예정 — 2026년 12월"],
|
|
["SW저작권 등록", "C-2026-XXXXXX (등록 후 기입)"],
|
|
["SW사업자 신고", "제XXX호 (신고 후 기입)"],
|
|
["주요 납품 실적", "(공공기관 납품 실적 기입 — 계약서 사본 첨부)"],
|
|
["중소기업 확인", "중소기업 직접생산확인증명서 첨부"],
|
|
], LBG))
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
story.append(note("등록 방법: 조달청 나라장터(g2b.go.kr) → 공급업체 로그인 → 물품 등록 신청"))
|
|
story.append(note("필요 서류: 사업자등록증, 법인등기부등본, SW저작권등록증, 제품 규격서, 가격확인서"))
|
|
story.append(note("처리 기간: 약 1~2주 | 수수료: 없음"))
|
|
story.append(Spacer(1, 6*mm))
|
|
|
|
story.append(Paragraph("위와 같이 물품 등록을 신청합니다.",
|
|
S("pledge3", fontName=BF, fontSize=10, alignment=TA_CENTER, leading=16)))
|
|
story.append(Spacer(1, 6*mm))
|
|
story.append(sign_area("신 청 일"))
|
|
|
|
for item in footer("조달청 나라장터 제출용"):
|
|
story.append(item)
|
|
|
|
doc.build(story, onFirstPage=on_page_num("조달청 나라장터 물품 등록 신청서 | 조달청"),
|
|
onLaterPages=on_page_num("조달청 나라장터 물품 등록 신청서 | 조달청"))
|
|
print(f"[OK] 03_조달청_나라장터_물품_등록_신청서.pdf ({Path(out).stat().st_size//1024}KB)")
|
|
|
|
|
|
# ══════════════════════════════════════════════════════════════
|
|
# MAIN
|
|
# ══════════════════════════════════════════════════════════════
|
|
if __name__ == "__main__":
|
|
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
base = Path(__file__).parent
|
|
|
|
print("GUARDiA ITSM 프로그램 등록 신청서 3종 PDF 생성 중...")
|
|
print()
|
|
|
|
make_copyright_pdf(str(base / "01_소프트웨어_저작권_등록_신청서.pdf"))
|
|
make_bizreg_pdf( str(base / "02_소프트웨어사업자_신고서.pdf"))
|
|
make_g2b_pdf( str(base / "03_조달청_나라장터_물품_등록_신청서.pdf"))
|
|
|
|
print()
|
|
print("3종 PDF 생성 완료:")
|
|
for f in sorted(base.glob("0*.pdf")):
|
|
print(f" {f.name} ({f.stat().st_size//1024}KB)")
|