AKARI Tech Blog

燈株式会社のエンジニア・開発メンバーによる技術ブログです

@react-pdf/rendererライブラリを活用した請求書pdfの自動生成について

1. はじめに

こんにちは! 今週のテックブログは、AI SaaS 事業本部でDigital Billder請求書開発を担当している伊藤が担当します。

Digital Billderは、建築業界における多岐にわたるバックオフィス業務を効率化するSaaS型Webアプリケーションで、工事金額の見積もりから請求書の受領まで、一連の業務プロセスを効率化することを目指しています。

我々はお客様の業務効率化を支援する中で、請求書提出業務に依然として多くの手間と課題があることに着目しました。

本記事では、その課題を深掘りし、@react-pdf/rendererとDigital Billderに蓄積された業務データを活用することで、PDF自動生成を可能にし、これらの課題をどのように解決したのか、そのアプローチをご紹介します。

(なおreact-pdfというライブラリが複数存在するため 本記事では@react-pdf/rendererに表記を統一しております。)

2. Digital Billderにおける請求書PDF自動生成の背景

Digital Billder請求書は、すでに請求書処理業務全体の劇的な効率化を実現しています。 しかし、その処理を開始するにあたり、以下の課題点が依然として残っていました。

紙媒体による管理の非効率性

協力会社様から提出される請求書は、その多くが元々紙媒体で作成されていました。これらをデータとして処理するためには、一度スキャンして電子化する手間が発生していました。

Excel書式からのPDF作成の煩雑さ

指定されたExcel書式での請求書作成が求められる場合、手作業で入力し、PDFに変換するプロセスが必要でした。これは入力ミスや書式崩れのリスクを伴い、非常に非効率でした。

上記の課題を解決し、よりスムーズで効率的な業務フローを実現するため、Digital Billderに蓄積されたデータを活用した請求書PDFの自動生成機能は不可欠でした。

3. @react-pdf/renderer選定理由

そこで私たちは@react-pdf/renderer をPDF自動生成のライブラリとして用いることに決めました。

@react-pdf/rendererを選んだ理由としては以下の2点が挙げられます。

Reactとの親和性

Digital BillderのフロントエンドはReactで構築されています。@react-pdf/rendererはReactコンポーネントの記述方法でPDFを作成できるため、既存のReact開発スキルやコンポーネント設計の知見をそのまま活かすことができました。これにより、学習コストを抑え、開発スピードを向上させることが可能でした。

柔軟なレイアウトとスタイリング

請求書は非常に多様なレイアウトやデザインが求められます。@react-pdf/rendererは、WebのCSS Flexboxに近いレイアウトシステムを提供しており、複雑な表組みやテキスト配置も直感的に記述できます。これにより、顧客の多様なニーズに応じた柔軟な請求書デザインを実現できると判断しました。

4. @react-pdf/rendererの特徴

@react-pdf/rendererは、Reactの機能を用いながらReactの構文でPDF描画できるようになっています。

基本的な構造

PDFの各要素は、特定のコンポーネントを使って表現されます。主要なコンポーネントは以下の通りです。

  • <Document>:PDF全体のルート要素です。
  • <Page>:PDFの各ページを表します。サイズや余白などのプロパティを設定できます。
  • <View>:HTMLの<div>のような役割を持ち、要素のグループ化やレイアウトの調整に使用します。Flexboxのプロパティを適用できます。
  • <Text>:テキストを表示するためのコンポーネントです。
  • <Image>:画像を表示するためのコンポーネントです。

これらのコンポーネントを組み合わせて、請求書のレイアウトを構築していきます。

簡単な実装例

以下は、@react-pdf/rendererを使ってシンプルな請求書を作成する際の基本的なコードスニペットです。

import React from 'react'
import { Document, Page, Text, View, StyleSheet } from '@react-pdf/renderer'

// スタイルの定義
const styles = StyleSheet.create({
 page: {
  flexDirection: 'column',
  backgroundColor: '#E4E4E4',
  padding: 30,
 },
 section: {
  margin: 10,
  padding: 10,
  flexGrow: 1,
 },
 title: {
  fontSize: 24,
  textAlign: 'center',
  marginBottom: 20,
 },
 text: {
  fontSize: 12,
  marginBottom: 5
 }
})

// 請求書コンポーネント
const InvoicePdf = ({ invoiceData }) => (
 <Document>
  <Page size="A4" style={styles.page}>
   <View style={styles.section}>
    <Text style={styles.title}>請求書</Text>
    <Text style={styles.text}>請求書番号: {invoiceData.invoiceNumber}</Text>
    <Text style={styles.text}>発行日: {invoiceData.issueDate}</Text>
    <Text style={styles.text}>請求元: {invoiceData.billingFrom}</Text>
    <Text style={styles.text}>請求先: {invoiceData.billingTo}</Text>
   </View>
  </Page>
 </Document>
)

export default InvoicePdf

上記のコードでは、まずStyleSheet.createというメソッドを使ってスタイルを定義しています。これはJavaScriptオブジェクトとしてスタイルを記述し、各コンポーネントのstyleプロパティに適用する方法です。例えば、pageスタイルでは背景色やパディング、レイアウトの方向(flexDirection: 'column')を指定し、titleスタイルでは文字の大きさや位置などを設定しています。

その後、定義したスタイルをPageコンポーネントViewTextコンポーネントstyleプロパティに渡すことで、それぞれの要素にスタイルが適用され、最終的なPDFの見た目が構築されます。invoicePdfコンポーネントは、渡されたinvoiceDataを使って請求書の具体的な情報をPDF上に表示しています。

このように、@react-pdf/rendererはReactのコンポーネントベースの考え方とFlexboxを活用することで、宣言的にPDFの構造と見た目を記述できるため、Web開発の延長線上でPDF生成に取り組めるのが大きな特徴です。

5. 開発における課題と解決策

@react-pdf/rendererは非常に強力なライブラリですが、実際の開発においてはいくつかの課題に直面し、それらを解決しながら開発を進めました。

複雑なテーブルレイアウトの実現

請求書には、明細を記載するテーブルが不可欠です。このテーブルレイアウトの実現は、特に行の高さの自動調整やページ跨ぎの処理において工夫が必要でした。具体的には、固定幅のテーブルではレイアウトが崩れやすく、動的な行数に対応しにくい、そしてページを跨ぐ際のヘッダーの繰り返し表示といった課題がありました。

これらの課題に対し、私は主に以下の3つのアプローチで解決を図りました。

まず、Flexboxの活用です。ViewコンポーネントFlexboxプロパティを組み合わせることで、グリッド状のテーブル構造を構築しました。flexGrowwidthを適切に設定することで、各列の幅を柔軟に制御し、動的なコンテンツにも対応できるレイアウトを実現しました。

次に、データ駆動のレンダリングを採用しました。テーブルの行は、請求データに基づいて動的にマッピングして生成することで、データの増減に柔軟に対応できる構造としました。

最後に、カスタムコンポーネントの作成です。テーブルのヘッダー、フッター、そして各行をそれぞれ独立したReactコンポーネントとして作成し、再利用性と保守性を高めました。

デバッグとテスト

PDF生成はUIのレンダリングとは異なり、ブラウザのDevToolsのような直接的なデバッグツールがないため、試行錯誤が必要でした。特に、レイアウトの崩れや表示の不具合の原因特定が難しいという課題に直面しました。

こちらは地道に各要素の境界線を目視で確認しながらレイアウトを調整することで、問題が起きている箇所を特定し、解消を図りました。

6. 実装のポイント

Digital Billderでの請求書PDF自動生成機能の実装において、特に重要だと感じたポイントをいくつかご紹介します。

データの渡し方

請求書の内容は、外部から動的に渡されるデータによって決まります。このデータの受け渡し方を適切に設計することが重要です。

Reactコンポーネントと同じように、最上位の請求書コンポーネントにすべての請求データをPropsとして渡しました。

請求先情報、請求元情報、明細行、合計金額など、請求書の内容を明確に定義したデータ構造を作り、それに合わせてコンポーネント内でデータを展開しました。これにより、コードの可読性と保守性が向上しました。

共通コンポーネント化とスタイル管理

請求書内の共通要素は、独立したReactコンポーネントとして切り出すことで、コードの重複を避け、再利用性を高められます。

たとえば、<CompanyHeader /><InvoiceTable />といったコンポーネントを作成しました。

共通のスタイルはStyleSheet.createで定義し、必要に応じて各コンポーネントに継承・適用することで、デザインの一貫性を保ちました。

7. 開発完了

これらの取り組みの結果、お客様の課題解決に直結する請求書PDFの自動生成機能が完成しました。複雑なテーブルレイアウトや多様な請求書書式への対応に試行錯誤を重ねましたが、Digital Billderに蓄積されたデータを最大限に活用することで、業務効率を劇的に向上させる成果を達成できました。

この機能により、協力会社様が紙媒体で請求書を作成したり、Excelから手作業でPDFに変換したりする手間が不要になりました。結果として、請求書提出業務にかかる時間と労力を大幅に削減し、入力ミスや書式崩れのリスクも軽減されています。

8. まとめ

本記事では、Digital Billderにおける請求書PDF自動生成機能の開発で、

@react-pdf/rendererを採用した経緯、基本的な使い方、そして開発中に直面した課題とその解決策、さらに実装のポイントについてご紹介しました。

@react-pdf/rendererは、Reactエコシステム内でPDFを扱う強力なツールであり、その柔軟性と開発のしやすさは目を見張るものがあります。

今回の開発を通じて得た知見は、今後もDigital Billderのさらなる価値向上に活かしていきたいと考えております。 今後もAI SaaS 事業本部では、お客様の業務をより効率化し、価値あるサービスを提供できるよう、技術的な挑戦を続けてまいります。

We’re Hiring!

燈では、フルスタックで開発するソフトウェアエンジニアを募集しています。

興味がある方は、ぜひカジュアル面談でお話しましょう!🔥 https://akariinc.co.jp/recruit