ふるさと納税 ワンストップ特例制度の寄付金税額控除に係る申告特例申請書をPythonで記入する

# ふるさと納税 ワンストップ特例制度の寄付金税額控除に係る申告特例申請書をPythonで記入する
ふるさと納税ワンストップ特例制度を使う場合の申請書は1/10必着です。
手書きで記入するのが大変だったので、配布されているpdfに必要項目を記入するスクリプトを作成しました。

google Colaboratory で動かしています。

## ライブラリの準備
```Python
# pdf編集に必要なライブラリ
!pip install PyPDF2 reportlab
# 日本語をpdfに書き込むためのフォント
!apt-get -y -q install fonts-ipaexfont

import io
from PyPDF2 import PdfFileWriter
from reportlab.lib.colors import Color
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.cidfonts import UnicodeCIDFont
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas
from reportlab.lib.units import mm
from reportlab.lib.pagesizes import A4, portrait

# フォントを登録
pdfmetrics.registerFont(
    TTFont(
        'IPAexPMincho',
        '/usr/share/fonts/opentype/ipaexfont-mincho/ipaexm.ttf'
    )
)

# 書き込む情報
address = ["東京都〇〇区〇〇町", "123-123", "コーポ303"]
tel = "03-0000-0000"
hurigana = "ヤマダ タロウ"
name = "山田 太郎"
number = "000000000000"
sex = "male"
birth = ("令", "1", "1" ,"1")
wareki = "2"

data = [
    ("〇〇市", 2, 12, 1,100000),
    ("△△町", 2, 12, 1,50000),
]
```

## 文字を書き込む処理
```Python
def write_common(can):
    font_size = 10

    left = 49*mm
    right = 113*mm
    can.setFont('IPAexPMincho', font_size)
    can.setFillColor(Color(0, 0, 0, alpha=1))

    # 住所
    for i, row in enumerate(address):
        can.drawString(left, (37*mm + (font_size + 5) * i), row)

    # 電話番号
    can.drawString(left, 59*mm, tel)

    # フリガナ
    can.drawString(right, 33*mm, hurigana)

    # 氏名
    can.drawString(right, 39.5*mm, name)

    # 個人番号
    for i, num in enumerate(number):
        can.drawString(right - 2.1*mm + (i * 4.1)*mm, 47*mm, num)

    # 性別
    if sex == "male":
        maru = right + 13*mm
    else:
        maru = right + 27.4*mm
    can.drawString(maru, 52.7*mm, "○")

    # 生年月日
    if birth[0] == "明":
        nengou = (right - 1.5*mm, 58*mm)
    elif birth[0] == "大":
        nengou = (right + 2.7*mm, 58*mm)
    elif birth[0] == "昭":
        nengou = (right + 6.6*mm, 58*mm)
    elif birth[0] == "平":
        nengou = (right + 1.5*mm, 61*mm)
    elif birth[0] == "令":
        nengou = (right + 2.7*mm, 61*mm)
    can.drawString(*nengou, "○")
    birth_height = 60*mm
    can.drawString(right + 16*mm, birth_height, birth[1])
    can.drawString(right + 27*mm, birth_height, birth[2])
    can.drawString(right + 37*mm, birth_height, birth[3])

    # 和暦
    can.drawString(45*mm, 14*mm, wareki)

    # チェック
    can.drawString(151*mm, 161*mm, "✓")
    can.drawString(151*mm, 200*mm, "✓")

    # 記入日
    can.setFont('IPAexPMincho', 8)
    date_height = 26*mm
    can.drawString(40*mm, date_height, "2")
    can.drawString(51*mm, date_height, "12")
    can.drawString(63*mm, date_height, "31")
```

```Python
def write_kifu(can, kifu_data):
    can.setFont('IPAexPMincho', 10)
    can.drawRightString(68*mm, 29*mm, kifu_data[0] + "長")
    kifu_height = 134.5*mm
    can.drawString(51*mm, kifu_height, str(kifu_data[1]))
    can.drawString(62*mm, kifu_height, str(kifu_data[2]))
    can.drawString(74*mm, kifu_height, str(kifu_data[3]))
    can.drawRightString(139*mm, kifu_height, f"{kifu_data[4]:,}")
```

## ファイルに書き込み
```Python
from PyPDF2 import PdfFileReader
# 配布されている申請書のpdfを読み込む
pdf_path = "./onestop_myNumber_form.pdf"

width, height = portrait(A4)
output = PdfFileWriter()

for row in data:
    packet = io.BytesIO()
    can = canvas.Canvas(packet, pagesize=(width, height), bottomup=False)
    write_common(can)
    write_kifu(can, row)
    can.showPage()
    can.save()

    packet.seek(0)
    new_pdf = PdfFileReader(packet)

    pdf = PdfFileReader(pdf_path)
    page = pdf.getPage(0)

    page.mergePage(new_pdf.getPage(0))
    output.addPage(page)


with open(f"./kifu.pdf", "wb") as fout:
    output.write(fout)
```

## 完成!
![kifu_〇〇市.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67107/99d97c97-7abd-20c5-afe7-44b7b74f9df4.png)


# 参考になった記事
https://buildersbox.corp-sansan.com/entry/2020/06/09/110000
https://news.mynavi.jp/article/zeropython-70/