7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

クソアプリAdvent Calendar 2023

Day 11

【クソアプリ】江戸時代もDX!?上様への納品物の領収証をPDFで発行してもらえるサービス

Last updated at Posted at 2023-12-11

この記事は「クソアプリ Advent Calendar 2023 その2」の11日目の記事です。

作ったもの

image.png

image.png

  • 上様に何か納品したときにお使いください
  • 領収書(覚書)をPDFでダウンロードできます
  • ※注意事項
    • 金額はランダムです
    • 日付は空です

モチベーション

PDFで書類を生成するシステムってよくあると思うのですが、地味に大変ですよね。
各言語で各種便利なPDF操作ライブラリがあって、それにデータを埋め込みつつ書類を作って、いざ書き出してみたら盛大にずれてたとか、デプロイした環境に日本語フォントがないだとか。

なんかもっと簡単にできないかなと思ってたのですが、HTMLで書類を作ってブラウザで印刷プレビューして、その内容がそのままPDFになればいろいろ楽なのではないかと思いました。

書類のHTMLのURLさえあれば、そのURLをヘッドレスChromeあたりが見に行ってくれてPDF保存してくれるといったことが可能ではないかなと。
そうすると、今後書類の種類が増えたとしても、HTMLベースの書類システムを作ってデプロイするだけでよく、特別なライブラリもフォントも何も要らずに誰でもささっと作ってしまえるといったことが実現できるのではないかなと。

アーキテクチャ

上様アーキテクチャ.drawio (1).png

PDF化システム

  • AWS Serverless application (SAM)
  • ランタイムはPython 3.9
  • Docker Imageで起動できるやつ
  • ヘッドレスChromeとChrome DriverとSeleniumをインストール
  • Lambdaのメモリは多めに(2048とか)
  • API GatewayのAPI設定で「バイナリメディアタイプ」を設定しないとダウンロードしたPDFが壊れて開けないので注意

SAMでHelloWorldを新規作成して、適当にこんな感じ

app.py
import base64
import json
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import subprocess
import os

def lambda_handler(event, context):
    options = webdriver.ChromeOptions()
    options.binary_location = '/opt/chrome/chrome'
    options.add_experimental_option("prefs", {
        "download.default_directory": "/tmp/download/"
    })
    options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    options.add_argument("--disable-gpu")
    options.add_argument("--single-process")
    options.add_argument("--disable-dev-shm-usage")
    options.add_argument("--disable-dev-tools")
    
    service = Service(executable_path="/opt/chromedriver")
    driver = webdriver.Chrome(options=options, service=service)

    # driver.get("https://goosysapp.net/")
    driver.get("https://uesama-print.goosys.workers.dev/")

    print(driver.title)
    
    parameters = {
        "printBackground": False,
        "paperWidth": 8.27,
        "paperHeight": 11.69,
        # "displayHeaderFooter": True,
    }

    pdf_base64 = driver.execute_cdp_cmd("Page.printToPDF", parameters)
    content = pdf_base64["data"]
    
    return {
        "statusCode": 200,
        "headers": {
            'Content-Length': len(content),
            'Content-Type': 'application/pdf',
            'Content-disposition': 'attachment;filename=uesama.pdf'
        },
        "isBase64Encoded": True,
        "body": content
    }

サービスアプリケーション

書類生成システム

所感

結構いい感じに出来たと思います。 :raised_hands:
(認証一切してないし、金額もランダムでDBも使ってないですが、その辺は実際にちゃんと作るときに考えればよいということで)

作っていて気付いたのですが、これ、印刷対象のHTML内で普通にJSが動きました。(金額をJSでランダム生成している)
なのでVueでもReactでも使ってデータを埋め込んでしまうことができるので、ReactToPDFとかやるよりワンステップ少なくて良いんじゃないかなと。

書類のレイアウトを作るのにも特殊技能が不要(HTMLだけ)なので、非エンジニアがExcelとかFigmaとかで作ったレイアウトをHTML変換したものにエンジニアがデータ埋め込みだけ作ればいいみたいな作業分担も可能なのかなと。

また、書類生成システムの方をCloudflare workersにしたのが天才的でした。
Web上のQuiq editで直接編集して即反映できるので、レイアウトの微調整も非エンジニア(HTMLちょっとわかる)の担当にしてしまえるかも。

あとは、これを基盤にして、作りたい書類が増えたらまたCloudflare workersでもpagesでもamplifyでもNetlifyでも好きなところにデプロイ(ちゃんと認証は作るんやで)して書類URLさえ作ってしまえば、同様にいくらでもPDFが作れるかなと。

おわり

冒頭でアドカレの11日目ですと言っていましたが、
只今、12日目の日付になってしまいました。(12日02時19分)

・・・遅刻すみません :bow:

7
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?