Docurain Labo

Docurainサービス開発日記

Docurainを使って年賀状作成にチャレンジ!

もうすぐ年賀状の季節です(2021年09月執筆)。企業ではだいたい12月頭くらいから、年賀状作成の作業に入るのではないでしょうか。多くの企業では外部のサービスを使ったり、年賀状作成ソフトウェアを使ったりしていますが、今年はDocurainを使って年賀状作成に挑戦してみるのはいかがでしょうか。

今回はハガキ向けに作成できる特殊なテンプレートをベースに、年賀状作成に挑戦してみます。

データ作成について

年賀状を作るにあたって、多くの企業では送付先の住所や宛名を表計算ソフトウェア(Excelなど)で管理しているかと思います。今回は次のような項目で準備したと想定します。

項目 内容
zipcode 郵便番号。7桁の数字
address1 住所1。都道府県 + 市区
address2 住所2。番地まで
address3 住所3。ビルなど
company 会社名 + 部署名
name 宛先のお名前

この項目に沿って、データを作成していきます。この内容を address.csv として、保存します。なお、この画像に記載されている住所、会社名、名前はすべてダミーデータで生成したものです。

f:id:moongift:20210928185702p:plain

自社情報について

自社情報はJSONで記述します。 entity.json というファイル名で、次のような内容になります。

{
  "company": "会社名",
  "name": "名前",
  "zipcode": "郵便番号(7桁の数字)",
  "address": "住所"
}

テンプレートについて

今回はハガキにぴったり印刷できる、特殊なテンプレートを使っています。 (このような用途にご興味があるDocurainユーザの方はご連絡ください)

このテンプレートでは、各列、行の幅が1mmになるように設計されており、位置合わせが容易になっています。

f:id:moongift:20210928185939p:plain

そして、こちらのテンプレートに合わせて、各項目を埋めていきます。年賀状なので、基本的に各項目は縦書きに設定しています。

配置について

年賀状では送付先の郵便番号、住所、宛名に加えて、自社の郵便番号、住所、宛名の位置が重要になります。今回は既存の年賀状の寸法に合わせて、次のように設計しています。

項目 開始位置(左上の位置) 高さ
郵便番号 上12mm 左45mm 48mm 9mm
住所1 上23mm 左85mm 8mm 100mm
住所2 上23mm 左77mm 8mm 100mm
住所3 上23mm 左69mm 8mm 100mm
会社名 上23mm 左55mm 10mm 100mm
担当者名 上23mm 左45mm 10mm 100mm

自社情報の配置は次の通りです。

項目 開始位置(左上の位置) 高さ
住所1 上67mm 左18mm 10mm 55mm
会社名 上67mm 左13mm 5mm 55mm
担当者名 上67mm 左8mm 5mm 55mm
郵便番号 上123mm 左6mm 29mm 7mm

各項目は必要に応じて均等割り付け(郵便番号)や下配置(名前)としています。郵便番号を各桁ごとに分けて設計することできますが、1mm以下での調整が必要になるので、今回は均等割り付けとしています。

そして同じ大きさのページを1つ作成し、ハガキの文面として作成します。今回はEB0182022寅ベーシック年賀状・018 | 年賀状2022(令和4年・寅年・とら) 素材 | 年賀状・無料ダウンロード | 年賀状ならブラザーの画像を使わせてもらいました。

f:id:moongift:20210928185959p:plain

テンプレートの繰り返し処理

ハガキは奇数ページが宛名面、偶数ページが文面という形になります。そこで、奇数ページがはじまる行の上の行、A列に次のように記述します。

A
#set($e=$ROOT)
#foreach ($c in $e.clients)

このように書くことで $!{e.company} とすれば自社の会社名が取得できたり、 $!{c.address1} とすれば送付先の住所1が取得できます(下記データ構造について、も参照してください)。また、偶数ページの最終行の下、A列には次のように記述します。

A
#end

これは上記の #foreach に対応する記述になります。このように書くことで、送付先ごとに宛名面および文面が生成されます。

テンプレートでの文字出力

テンプレートでは $!{〜} のように記述しています。!を入れることで、もし変換するキーワードがなかったとしても、$!{〜} のようなプログラマブルな文字列が消える仕組みです。

様を付ける

送付先の名前には「様」を末尾に付けています。これは $!{c.name} 様 のようにセルに記述するだけで対応できます。

データ構造について

今回は送付先の住所が複数存在します。そして、送付元(自社情報)が1つという形です。そこで、次のようなJSONを作成して、DocurainのAPIに送信します。

{ // 自社情報
  "company": "会社名",
  "name": "名前",
  "zipcode": "郵便番号",
  "address": "住所",
  "clients": [  // 送付先情報(配列)
    {
      "company": "会社名",
      "name": "名前",
      "zipcode": "郵便番号",
      "address1": "住所1",
      "address2": "住所2",
      "address3": "住所3",
    },
    {
      "company": "会社名",
      "name": "名前",
      "zipcode": "郵便番号",
      "address1": "住所1",
      "address2": "住所2",
      "address3": "住所3",
    },
    // 繰り返し
  ]
}

プログラミングコードについて

今回はRubyを使ってAPIを呼び出します。

利用するライブラリのインストール

HTTP用のライブラリを含め、次のライブラリを使っています。

  • faraday
  • faraday_middleware
  • ruby-filemagic

適当なディレクトリでGemfileを作成します。

$ bundle init
Writing new Gemfile to /path/to/dir/Gemfile

このファイルを編集します。今回は次のように変更しています。

# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

# gem "rails"
gem "faraday"
gem "faraday_middleware"
gem "ruby-filemagic"

そしてライブラリをインストールします。

$ bundle install

スクリプトの作成

適当なファイル(今回はupload.rbとしています)を作成し、ライブラリを読み込みます。CSV、JSONを扱うライブラリもインストールします。

require 'faraday'
require 'faraday_middleware'
require 'ruby-filemagic'

require 'json'
require 'csv'

DocurainのAPIを実行する処理

まず、Docurainの実行部分を作成します。ここからは api_call 関数の内容です。

# 帳票レンダリング(インスタント)APIコール
def api_call
  # この中に書きます
end

まず必要な変数を準備します。

token = 'YOUR_API_TOKEN'                  # Docurain API トークン
out_type = 'pdf'                          # 出力形式
template_path = './template.xlsx'         # テンプレートファイルパス
entity_json = JSON.parse(open('./entity.json').read)  # テンプレート置き換え文字列のJSON
path = "/api/instant/#{out_type}"         # APIのパス

住所を記述した address.csv を読み込みます。

# 住所用のCSVを読み込む
body = File.open('./address.csv').read
csv = CSV.new(body, headers: true, header_converters: :symbol, force_quotes: true)

Excel内にて縦書きを行う際の注意点と解決策して、以下が挙げられます。

  • -(ハイフン)が縦にならない
    -| に変換します
  • 数字は均等割り付けしても広がらない
    数字の間に (半角スペース)を入れます

この2つの処理を住所、郵便番号に対して行います。ちょっと冗長的なので、関数にまとめても良いでしょう。今回はわかりやすさのために、そのまま記述しています。

rows = csv.to_a.map do |row|
  # 郵便番号(数字7桁)を分解して、間にスペースを挿入
  row[:zipcode] = row[:zipcode].split(//).join(' ')
  # 住所に含まれる - を | に変換
  row[:address1] = row[:address1].gsub(/-/, '|')
  row[:address2] = row[:address2].to_s.gsub(/-/, '|')
  row[:address3] = row[:address3].to_s.gsub(/-/, '|')
  row.to_hash
end
# 郵便番号(数字7桁)を分解して、間にスペースを挿入
entity_json['zipcode'] = entity_json['zipcode'].split(//).join(' ')
# 住所に含まれる - を | に変換
entity_json['address'] = entity_json['address'].gsub(/-/, '|')
# JSONの clients の中に送付先顧客情報を追加
entity_json['clients'] = rows

次にテンプレートファイルのコンテンツタイプを取得します。

# テンプレートファイルのContent-Typeを取得
template_content_type = FileMagic.new(FileMagic::MAGIC_MIME).file(template_path, true)

これらの情報を使ってリクエストボディを作ります。

# リクエストボディの作成
params = {
  template: Faraday::FilePart.new(template_path, template_content_type),
  entity:  Faraday::ParamPart.new(entity_json, 'application/json')
}

後はFaraday(HTTPクライアント)を使って、APIを実行します。

# APIを実行する
conn = Faraday.new(:url => 'https://api.docurain.jp') do |builder|
  builder.request :multipart
  builder.adapter :net_http
end
# 認証ヘッダーの設定
conn.headers['Authorization'] = "token #{token}"
# 実行結果(レスポンス)を返す
conn.post(path, params)

これでAPI呼び出し処理の完成です。関数全体の内容は次のようになります。

require 'faraday'
require 'faraday_middleware'
require 'ruby-filemagic'

require 'csv'
require 'json'

# 帳票レンダリング(インスタント)APIコール
def api_call
  token = 'YOUR_API_TOKEN'                  # Docurain API トークン
  out_type = 'pdf'                          # 出力形式
  template_path = './template.xlsx'         # テンプレートファイルパス
  entity_json = JSON.parse(open('./entity.json').read)  # テンプレート置き換え文字列のJSON
  path = "/api/instant/#{out_type}"         # APIのパス
  # 住所用のCSVを読み込む
  body = File.open('./address.csv').read
  csv = CSV.new(body, headers: true, header_converters: :symbol, force_quotes: true)
  rows = csv.to_a.map do |row|
    # 郵便番号(数字7桁)を分解して、間にスペースを挿入
    row[:zipcode] = row[:zipcode].split(//).join(' ')
    # 住所に含まれる - を | に変換
    row[:address1] = row[:address1].gsub(/-/, '|')
    row[:address2] = row[:address2].to_s.gsub(/-/, '|')
    row[:address3] = row[:address3].to_s.gsub(/-/, '|')
    row.to_hash
  end
  # 郵便番号(数字7桁)を分解して、間にスペースを挿入
  entity_json['zipcode'] = entity_json['zipcode'].split(//).join(' ')
  # 住所に含まれる - を | に変換
  entity_json['address'] = entity_json['address'].gsub(/-/, '|')
  # JSONの clients の中に送付先顧客情報を追加
  entity_json['clients'] = rows
  # テンプレートファイルのContent-Typeを取得
  template_content_type = FileMagic.new(FileMagic::MAGIC_MIME).file(template_path, true)
  # リクエストボディの作成
  params = {
    template: Faraday::FilePart.new(template_path, template_content_type),
    entity:  Faraday::ParamPart.new(entity_json, 'application/json')
  }
  # APIを実行する
  conn = Faraday.new(:url => 'https://api.docurain.jp') do |builder|
    builder.request :multipart
    builder.adapter :net_http
  end
  # 認証ヘッダーの設定
  conn.headers['Authorization'] = "token #{token}"
  # 実行結果(レスポンス)を返す
  conn.post(path, params)
end

レスポンスを判定する

次にレスポンスの内容を判定して、レポートをファイル出力します。ここからは res_handle 関数の内容です。

# レスポンスハンドリング(適宜必要なハンドリングを行ってください)
def res_handle(res)
  # この中に書きます
end

まずHTTPステータスが200(正常終了)以外の場合はエラーメッセージを出して終了します。

if res.status != 200 # エラー判定
  puts res.body # エラーメッセージを返して終了
  return
end

次にレスポンスのContent-Typeから、出力するファイルの拡張子を指定します。

# 正常時、カレントディレクトリにファイル保存
# content-typeから拡張子に変換
extensions = {
  'application/pdf' => 'pdf',
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx',
  'application/vnd.ms-excel' => 'xls',
  'image/svg+xml' => 'svg',
  'image/png' => 'png',
  'image/jpeg' => 'jpg',
  'image/gif' => 'gif',
}
content_type = res.headers['content-type']
ext = extensions[content_type]

後はファイル名(今回は test に固定)を決めて、ファイル書き出しします。

# ファイル名を決めて書き出し
file_name = "test.#{ext}"
filePath = "#{Dir.pwd}/#{file_name}";
File.binwrite(filePath, res.body)
# メッセージを出力
puts "saved : #{filePath}"

この関数の全体像は次のようになります。

# レスポンスハンドリング(適宜必要なハンドリングを行ってください)
def res_handle(res)
  if res.status != 200 # エラー判定
    puts res.body # エラーメッセージを返して終了
    return
  end
  # 正常時、カレントディレクトリにファイル保存
  # content-typeから拡張子に変換
  extensions = {
    'application/pdf' => 'pdf',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx',
    'application/vnd.ms-excel' => 'xls',
    'image/svg+xml' => 'svg',
    'image/png' => 'png',
    'image/jpeg' => 'jpg',
    'image/gif' => 'gif',
  }
  content_type = res.headers['content-type']
  ext = extensions[content_type]
  # ファイル名を決めて書き出し
  file_name = "test.#{ext}"
  filePath = "#{Dir.pwd}/#{file_name}";
  File.binwrite(filePath, res.body)
  # メッセージを出力
  puts "saved : #{filePath}"
end

実行する

ではこの2つの関数をつないで実行します。

res = api_call  # APIコール
res_handle(res) # レスポンスハンドリング

実行すると、次のように結果が出力されます。

$ ruby upload.rb 
saved : /path/to/test.pdf

できあがったPDFの内容です。奇数ページが宛名、偶数ページが文面になります。

f:id:moongift:20210928190148p:plain

印刷する

後は両面印刷対応のプリンターや複合機で印刷します。まだ年賀状が販売される時期ではないので、Word 2019 for Mac:はがきの宛名印刷テンプレートを作成するにはの年賀状テンプレートを利用して、年賀状風に印刷してみました。

宛名側です。

f:id:moongift:20210928183014j:plain

文面側です。

f:id:moongift:20210928183041j:plain

まとめ

Docurainを使うことで、年賀状のような印刷物もExcelでデザインして作成できます。特殊なテンプレートが必要にはなりますが、1mm単位での正確な配置も指定できます。往復ハガキのような特殊な形式でも利用できます。

DocurainはWeb APIを介して利用するので、対象の宛先があっても素早く作成して、印刷が可能です。ぜひご利用ください!

帳票開発を、もっと簡単に「Docurain-ドキュレイン-」|帳票開発エンジン