16
3

More than 1 year has passed since last update.

Gem prown を使用して請求書を作成する。

Last updated at Posted at 2022-07-05

はじめに

本記事は オリジナルアプリ Kiyoraの続編となります。
プログラミングスクールで作成したオリジナルアプリケーションで作成した
Ruby on Railsでのpdf出力について取り上げます。


実行環境
rails 6.0.3
ruby 3.0.1
psql (PostgreSQL) 14.2

前提
rails newでアプリ作成
rails db:create を実行済み。

prawnの導入

gemファイルに以下を追加します。
テーブルも表示させたいのでprawn-tableもインストールします。

gem 'prawn'
gem 'prawn-table'

実行コマンド

bundle install

モデル作成

rails g model invoice_pdf

コントローラーを作成

rails g controller invoice_pdfs

ルーティングの設定

showの画面でPDFを表示

resources :invoice_pdfs, only: %i[show]

pdfを実装させる

invoice_pdf.rb
class InvoicePdf < Prawn::Document
  FONT_PATH = Rails.root + '/Users/workspace/kiyora/app/assets/fonts/ipaexg.ttf'

  def initialize(record,customer)

    super(
      page_size: 'A4',
      top_margin: 40,
      bottom_margin: 30,
      left_margin: 20,
      right_margin: 20
    )

    @record = record
    @customer = customer
   
    font 'app/assets/fonts/ipaexg.ttf'
    header
    move_down 50
    contents
  end

  # コンポーネント作成
  def header
    text '請求書', size: 20, align: :center
    move_down 20

    text "作成日: #{Date.today}",align: :right, size: 10
    text "株式会社 良好建築設備",align: :right, size: 10
    text "住所 東京都台東区花川戸3丁目1-1-1",align: :right, size: 10
    text "電話: 03-333-3333",align: :right, size: 10
    text "info: contact@center.com",align: :right, size: 10
    image 'app/assets/images/sqe_rei.jpeg',align: :right, width: 40, height: 40,at: [400, 700]
    
    text "#{@customer.name} 様",align: :left, size: 12
    text "郵便番号: #{@customer.zip} ",align: :left, size: 12
    text "住所: #{@customer.address} ",align: :left, size: 12
  end

  def contents
    move_down 10
    text "作業日:#{@record.support_at.strftime("%Y年%m月%d日").to_s}"
    text '下記の通りご請求申し上げます。',align: :center
 
      bounding_box([0, 555], width: 310, height: 65) do
       move_down 10
      text "合計金額 #{@record.sales+(@record.sales*0.1).round}", size: 16, align: :left
      end

      rows = [['詳細', '数量', '単価', '金額'], 
      ["#{@record.category}", '1',"#{@record.sales}", "#{@record.sales+(@record.sales*0.1).round}"]
      ]
      #テーブルの作成。カラムが4つ。それぞれの幅を指定。
      table(rows, column_widths: [370, 30, 60, 60], position: :center) do |table|
      table.cells.size = 10
      table.row(0).align = :center
      end

      bounding_box([373, 300], width: 150, height: 100) do
        table [['小計', "#{@record.sales}"], ['消費税', "#{(@record.sales*0.1).round}"], 
        ['合計金額', "#{@record.sales+(@record.sales*0.1).round}"]],
        column_widths: [50, 100], position: :right do |table|
        table.cells.size = 10
        end
      move_down 10
      text "お振込期日  #{Date.today+14}", size: 12, align: :left
      end
  end
end 

フォントのダウンロード

クラス名にはPrawn::Documentを継承させます。

フォントをダウンロードします。prawnは日本語には対応していない為。
こちらのページからダウンロード。

ダウンロードしたファイルを /app/assets/fonts以下に配置。

コードの説明

def initialize

pdfには顧客情報に紐づいた情報とタスク情報を出力したいので
(下記に説明あり)
def initialize(record,customer)と記述。

superで外枠となるサイズを指定。
引数にrecord customerを設定。

controller show
@record = Task.find(params[:id])
@customer = @customers.find_by(task_id: @record.id)

コントローラーファイルで上記をあらかじめ設定し、recordにはTaskモデル、
customerにはcustomerモデルの情報が格納される。

move_down 50

headerとcontentsの間にどれくらい余白を入れるかmove_downによって数値設定。
値が大きいほど、空間ができる

名前の表示

text "#{@customer.name} 様",align: :left, size: 12

@customerのnameカラムに入っている情報を取得したい場合、"#{}"で展開させる。
sizeはフォントサイズのこと

bounding_box([0, 555], width: 310, height: 65)

pdfの中にボックスを作成します。始点となる座標点を指定します。
[横, 縦]、単位はポイント(pt)になります。そこから、幅310高さ65のボックスを作ります。

公式ドキュメント

table(rows, column_widths: [370, 30, 60, 60], position: :center) do |table|
      table.cells.size = 10
      table.row(0).align = :center
end

セルのサイズと文字の大きさ

 table.cells.size = 10 

枠線を特定箇所のみ付けることも可能。

 table.cells.borders = %i[right top]

今日の請求書発行日から14日後に日付を設定。

text "お振込期日  #{Date.today+14}", size: 12, align: :left

コントローラーファイル

invoice_pdfs_controller.rb
class InvoicePdfsController < ApplicationController
  def show
    @records = Task.all # pdf上で使用するレコードのインスタンスを作成
    @record = Task.find(params[:id])
    @customers = Customer.all
    @customer = @customers.find_by(task_id: @record.id)

    respond_to do |format|
      format.html
      format.pdf do

        # pdfを新規作成。引数にインスタンス変数を渡す。
        pdf = InvoicePdf.new(@record, @customer)
        send_data pdf.render,
          filename:    "invoice.pdf",
          type:        "application/pdf",
          disposition: "inline" # 画面に表示。外すとダウンロードされる。
      end
    end
  end
  private
  def set_show
    params.permit(:name,:dispatch,
      properties_attributes:[:name, :zip, :prefecture, :city , :address, :tel,:_destroy ],
      partners_attributes:[{id:[]},:name,:worker,:contact,:sales,:_destroy],
      agents_attributes:[:id,:manager_name, :name, :zip, :prefecture, :city, :address,:_destroy],
      customer_attributes:[:id,:name,:zip,:address,:tel,:_destroy]
    )
  end
end

新規作成を行う。

pdf = InvoicePdf.new(@record, @customer)
disposition: "inline"

PDFをブラウザ上に出力する際に必要なオプション。外すとダウンロードになる。

他にもprawnには図形を出力したりする機能もあり、公式ドキュメントを見ると
利用用途が広がりそうです。

ブラウザでの表示

PDF版マニュアル

参考にさせて頂いた記事

https://techtechmedia.com/prawn-pdf-rails/
https://qiita.com/yacci/items/61a26ddd3f6eb2494121
https://qiita.com/ayies128/items/7262b771fdae5b7f0098


エンジニアのスタートラインにようやく立てたところです。
未熟な点が多々あるかとは思いますが、温かく見守って頂ければと思います。

16
3
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
16
3