Docurain Labo

Docurainサービス開発日記

帳票の設計、作成をDocurainにまるっとお任せください

業務システムをはじめとして、データを蓄積するシステムは最終的に何らかのレポートや帳票を出力します。特に業務システムにおいては、多くの帳票が作成されます。たとえば納品書、発注書、請求書などは有名な帳票ですが、各企業のワークフローに合わせてもっと多数の帳票が作成されるでしょう。

システム開発時において、帳票作成は若干独特なポジションになります。その多くがPDFやExcelファイルなどバイナリファイルとして出力されるため、一般的なGUIアプリケーションやWebシステムへの出力とは作法が異なるからです。その結果、次のような課題が生まれます。

  • 選任の担当者が不在
  • コーディング量が増える
  • 数ヶ月、数年後のメンテナンスが難しい
  • 帳票デザインに関する専門知識が限られた要員に偏ってしまう

f:id:moongift:20211221100122j:plain
Docurain利用前後の開発イメージ

選任の担当者が不在

昨今ではエンジニア不足が話題に上がることが増えています。自社開発のシステムで帳票出力を行う場合はもちろん、SIerにおいても専門知識を持った帳票デザインを行える人材を確保するのに苦労しているようです。PDFなどで出力される帳票はHTMLやJSONを出力するのに比べると複雑であり、専門的な知識が必要です。反面、常時帳票開発に関わるのは難しく、帳票に関する開発に関わる度に過去の経験であったり、新しい技術へのキャッチアップが必要になります。

コーディング量が増える

PDFやExcelファイルなどに出力を行うシステムを開発する際には、一般的なHTMLやJSONで出力する場合と比べて煩雑になりがちです。専用のライブラリを使ったとしても、位置調整や細かな設定をプログラミングで行う必要があり、コーディング量が増えてしまいます。帳票のパターンは多いため、一つ一つの帳票に対して固有のコーディングが必要になります。そのため仕様変更に伴う修正が難しく、工数も増えやすくなります。

数ヶ月、数年後のメンテナンスが難しい

帳票出力に関わる開発はシステム開発の中でも中盤〜終盤になりやすいでしょう。そのごく一部の期間(全体の工数の1/10程度と言われます)だけ学んでコーディングを行っても、次の機会にはすでに忘れ去ってしまいます。その上、過去に記述した長大なコードだけが残されていると、それを思い出すのにも時間がかかります。技術も進歩しており、ライブラリがバージョンアップしていれば、ほぼ学び直しに等しい工数がかかる可能性があります。

帳票デザインに関する専門知識が限られた要員に偏ってしまう

一般的にこうした帳票システムの開発に携わった経験は、特定の要員に限られてしまいます。知識を共有するのが難しかったり、不定期に発生する作業では、引き継ぎも難しいでしょう。そのため、修正が必要になった時には特定の人しか作業できなかったり、その担当者が転職や転籍してしまうと知識が途絶えてしまいます。その結果、場当たり的な対応になったり、変更に大きな工数がかかるようになります。

帳票開発をやりたがる人がいない

そもそもDocurainは、開発者たちが過去に基幹系業務システム開発時に感じていた「帳票開発は退屈」であるという課題を解決するために生まれたという背景があります。帳票開発はきめ細かな配慮が必要な反面、技術的な面白みは少ないとされています。開発者によっては苦痛すら感じるでしょう。しかし、誰かがやらねばなりません。

帳票開発の課題を解決するためにDocurainができること

前述の通り、一つの業務システム開発プロジェクトにおいて、その工数の1/10程度が帳票開発に使われると言われています。そこには帳票のデザイン、生成プロセスの選定、コーディング、テストなどが含まれます。帳票では商品名の長さや数字などに表示上の制限がある中で、あらゆるパターンに対応しなければなりません。99.999%のデータは問題なくとも、たまたま発生したイレギュラーなデータによって帳票が崩れてしまった経験を持つ方も多いでしょう。そうした問題にあらかじめ対応する必要があるため、帳票の開発フェーズは工数が増えがちです。

とはいえ、大多数なシステム開発において帳票開発はメイントピックではありません。開発リソースを集中させるべきは、バックエンドシステムやフロントエンドの開発になるでしょう。帳票は最終的なアウトプットになるので、開発工程の最後部に回されやすく、限られたリソースで対応されることが多いようです。

私たちDocurainでは帳票システムをSaaSとして提供する中で、数多くのお客さま、そして開発現場からご意見を伺ってきました。ここで挙げたような課題は、多くのお客さまから聞いています。そこで私たちはサービス提供からさらに一歩踏み込み、帳票作成に関わるプロセスをまるごとアウトソースいただける体制を整えました。

提供する内容について

Docurainを用いた帳票作成について、テンプレートの作成を含めてお任せいただけます。システム開発プロセスにおける帳票作成フェーズをすべてお任せいただくイメージです。実際のDocurainの呼び出し、データ生成に関するシステム開発はお客さまになります。

メリット

ここでDocurainチームを頼っていただくメリットを紹介します。

アウトソース

私たちのサービスを利用することで、システム開発における帳票システムの設計、帳票デザインの部分が丸々アウトソースできます。後はあらかじめ規定したフォーマットに合わせて、バックエンドシステムからDocurainのAPIを呼び出すだけで、PDFやExcel、画像といった様々なフォーマットで帳票を取得できます。

人材不足、エンジニア不足への対応

システム開発において帳票設計、出力に関する工数を削減できます。空いた工数をメインのシステム開発に回すことができます。現代のシステム開発ではクラウドを利用することが増えていますが、これはハードウェアの管理業務からエンジニアを解放し、そのリソースをさらに有益な面に当てることを可能にしました。1社でシステム開発の全フェーズに対応するのは前時代的とさえ言えるでしょう。帳票に関する開発はDocurainに任せてしまいましょう。

中長期的なメンテナンスが実現

私たちは日々Docurainの開発を通じて、ドッグフーディングを続けています。不定期に発生する帳票のメンテナンス、新しい帳票の追加と言ったタスクに対して適切に対応可能です。教育や、Docurainの使い方を思い出すような作業は不要なので、スムーズな帳票更新が実現できます。

Docurainの専門家に任せる安心感

当たり前ですが、私たちはDocurainの専門家です。Docurainの仕様を知り尽くし、できることとできないことはもちろん、その使い方も熟知しています。Docurainは高い帳票開発効率を提供しますが、慣れるまでにある程度の工数がかかるのも事実です。そうした教育にかかる工数もなく、すぐに実用的な帳票設計に入ることが可能です。

不定期に発生する帳票の修正にも対応できますので、帳票開発の担当者が辞めてしまった、部署異動になってしまったといったリスクもありません。

まとめ

新規のシステム開発はもちろん、既存の帳票ソリューションからの載せ替えでも問題ありません。帳票の専門家として、皆様のシステム開発における帳票システムの課題を解決いたします。ぜひお問い合わせください。

条件付き書式を使って色の出し分けを実現する

帳票では一部を目立たせたい時に、色を利用します。たとえば赤字やマイナスといった目を配るべきデータがあれば、赤文字の出力にするでしょう。同じように明細行で1行ずつ色を変えることで、見間違いを防いだりできます。

Docurainでこのように帳票の中での色付けを行いたい時には、条件付き書式を使うと便利です。今回は条件付き書式を使って、ガントチャート風の表示を実現してみました。

できあがった帳票

まずは完成版から紹介します。

f:id:moongift:20211126154525j:plain

仕様は次のようになっています。

  • 色は赤、青、黄色、緑が利用可能。色は行毎にJSONデータで指定します。
  • タスクの開始日、終了日に合わせてラインが引かれます。
  • 日付は基準日(最初の日付)から2週間分を対象とします。

実際のJSONデータは次のようになります。colorキーでr/g/b/yを使って色指定しています。startDateキーがタスクの開始日、endDateがタスクの終了日になります。

{
  "baseDate": "2021/11/26",
  "tasks": [
    {"title": "DB設計", "startDate": "2021/11/26", "endDate": "2021/11/30", "color": "r"},
    {"title": "クラウド選定", "startDate": "2021/11/26", "endDate": "2021/12/02", "color": "b"},
    {"title": "リポジトリ作成", "startDate": "2021/11/28", "endDate": "2021/11/28", "color": "y"},
    {"title": "概要設計", "startDate": "2021/11/26", "endDate": "2021/12/03", "color": "g"},
    {"title": "フレームワーク選定", "startDate": "2021/11/27", "endDate": "2021/11/29", "color": "r"}
  ]
}

テンプレートの記述

ではここからテンプレート側の記述について解説します。まず一番左の日付はJSONデータのbaseDateをそのまま出力しています。そして、そのセルに BASEDATE という名前を付けています。

${e.baseDate}

そしてその右側のセルから、順番に =BASEDATE + 1=BASEDATE + 2 … といった具合に式を定義していきます。表示上は14日分で足りるのですが、計算処理の都合上、最後は =BASEDATE + 15 とします。

変数の定義と繰り返し処理

A1セルではJSONデータを扱いやすくするために $e を定義します。

#set($e = $ENTITY)

さらに数式の自動シフト(簡易)を利用するために #EASY_SHIFT_FORMULA も定義します。

#EASY_SHIFT_FORMULA

チャート部分は繰り返し処理になりますので、foreach を使います。

#foreach($task in $e.tasks)
  // この間の行でチャート部分を作成します
#end

チャート(明細)の処理

チャート部分はまず単純な出力を行います。色情報も出力していますが、画面の表示上は不要なので、白文字で出力しています。

B C D E
${task.title} ${task.startDate} ${task.endDate} ${task.color}

計算式の定義

チャート部分では、次のような計算式を定義しています。

  • ある日付がタスクの開始日よりも後
  • ある日付がタスクの終了日よりも前
  • 上記2つの条件にマッチする場合に色情報のテキストを出力する

実際の記述は次のようになります。 $ を使うことで縦方向(または横方向)コピーした際に計算式が別なセルを参照するのを防いでいます。

=IF(AND($C6<=F4,$D6>=F4),$E6,"")

こうすると、データを適用した結果が次のようになります。

11月26日 11月27日 11月28日 11月29日 11月30日 12月1日 12月2日
DB設計 2021/11/26 2021/11/30 r r r r r r
クラウド選定 2021/11/26 2021/12/2 b b b b b b b b
リポジトリ作成 2021/11/28 2021/11/28 b b
フレームワーク選定 2021/11/27 2021/11/29 r r r r

条件付き書式の設定

ではいよいよ条件付き書式を設定します。条件付き書式のルールの管理を選択します。

f:id:moongift:20211126154329p:plain

そして、次のように設定をします。

項目 内容
スタイル クラシック
対象 指定の値を含むセルだけを書式設定
特定の文字列
次の値を含む
y

この時の書式設定をユーザ設定の書式とします。上記例のようなyであれば黄色で出力したいので、塗りつぶしとフォントカラーを同じ黄色に指定します。r(赤)/b(青)/g(緑)も同じように定義します。

f:id:moongift:20211126154346p:plain

書式設定の適用先として $F$5:$T$7 のようにしてforeachループの含まれる範囲を指定します。そうすると、先ほどのr/b/g/yといった文字列が入ったセルが、それぞれの色に置き換わって表示されます。

f:id:moongift:20211126154408p:plain

PDFで出力する

この条件付き書式はExcelだけでなく、PDFにも適用されます。PDFで出力すると、設定した通りにガントチャートが出力されるはずです。

f:id:moongift:20211126154421p:plain

まとめ

条件付き書式を設定することで、配色の伴うレポートでも自在に出力できるようになります。なお、Excel上で細かく計算処理を行うと複雑度が増す可能性があるのであまりお勧めしません。出力するか否かを含めてデータ側で指定できるようにすると、テンプレートをシンプルに維持できるでしょう。

CSVファイルを使ってDocurainの帳票を作成してみよう

DocurainはExcelファイルをテンプレートとし、さらに描画するデータを与えて帳票やレポートを作成します。与えるデータフォーマットはJSONが一般的なのですが、CSVやTSVも利用可能です。

今回はCSVファイルを使った請求書作成について解説します。

CSVファイルについて

今回利用するCSVファイルは次のようになっています(抜粋です)。企業名、個人名、住所、郵便番号はダミーで生成したものになります。

#no,date,companyname,accountname,address,zipcode,tel,note,item,price,total,tax,totalPrice
1,2021/11/30,有限会社 渚,吉田 浩,岐阜県藤本市斉藤町鈴木3-9-7,215-9066,080-8054-8454,"いつもお世話になります。
2021年11月分の請求書になります。",製品1,4000,14500,1450,15950
1,2021/11/30,有限会社 渚,吉田 浩,岐阜県藤本市斉藤町鈴木3-9-7,215-9066,080-8054-8454,"いつもお世話になります。
2021年11月分の請求書になります。",製品2,6000,14500,1450,15950
  :
3,2021/11/30,有限会社 木村,青田 香織,山形県加藤市吉田町加藤9-6-7,167-2711,090-2125-2506,お世話になります。よろしくお願いいたします。,アイテム1,1300,9000,900,9900
3,2021/11/30,有限会社 木村,青田 香織,山形県加藤市吉田町加藤9-6-7,167-2711,090-2125-2506,お世話になります。よろしくお願いいたします。,アイテム2,1000,9000,900,9900
3,2021/11/30,有限会社 木村,青田 香織,山形県加藤市吉田町加藤9-6-7,167-2711,090-2125-2506,お世話になります。よろしくお願いいたします。,アイテム3,6700,9000,900,9900b

ここで注意して欲しい点は以下になります。

  • ヘッダー行を定義する場合には # を最初に記述する
  • 帳票をまとめるユニークキー(今回はno)を用意する
  • すべての明細行に帳票のヘッダー情報を記述する

ヘッダー行を定義する場合には # を最初に記述する

たとえば次のようなCSVファイルがあったとします(#がないパターンです)。

no,date,name
1,2021-04-01,テスト 太郎
2,2021-05-01,テスト 花子
3,2021-06-01,テスト 次郎

これをDocurainのデータファイルとして適用した場合 $ENTITIES は次のように送られてきます。

[
  ["no", "date", "name"],
  ["1", "2021-04-01", "テスト 太郎"],
  ["2", "2021-05-01", "テスト 花子"],
  ["3", "2021-06-01", "テスト 次郎"]
]

それに対して、最初に # を付けた場合の $ENTITIES は次のようになります。

[
  {
    "no": 1, "date": "2021-04-01", "name": "テスト 太郎",
  },
  {
    "no": 2, "date": "2021-05-01", "name": "テスト 花子",
  },
  {
    "no": 3, "date": "2021-06-01", "name": "テスト 次郎",
  },
]

後者のヘッダーを設定した場合、 $ENTITIES[0].no のようにアクセスできます。CSVにはヘッダーのような概念がないので、注意してください。

帳票をまとめるユニークキー(今回はno)を用意する

この後のテンプレート側の処理で紹介しますが、どこからどこまでが同じ帳票であるか区別できる必要があります。今回は no という列を持たせて、そこで次の帳票になった時に数字を変更しています。

すべての明細行に帳票のヘッダー情報を記述する

CSVは多段構造は表現できません。そのため帳票ヘッダー、明細のように出力する際には、どちらの情報も一行の中に入れてしまうのがお勧めです。明細行の中に、ヘッダー情報も繰り返し入れてしまうことで、一部を取り出してヘッダー行情報として利用できます。つまり次のような形です。

#set($header = $ENTITIES[0])

テンプレートについて

今回はMicrosoft Officeで提供されている請求書テンプレートを利用します。

f:id:moongift:20211126144435p:plain

テンプレートの実装

f:id:moongift:20211126144530p:plain

まずA1セルにて、テンプレートで利用するデータの変数を定義し、さらに帳票ごとにグルーピングします。

#set($e = $ENTITIES)
#set($pages = $e.chunk('no'))

$e.chunk('no') を実行すると、ある特定のカラム(今回はno)が同じデータは同じ配列グループになります。元データは $e は次のようになっていると考えてください。

[
  {
    "no": 1, "date": "2021-04-01", "name": "テスト 太郎",
  },
  {
    "no": 1, "date": "2021-05-01", "name": "テスト 太郎",
  },
  {
    "no": 2, "date": "2021-06-01", "name": "テスト 花子",
  },
  {
    "no": 2, "date": "2021-07-01", "name": "テスト 花子",
  },
  {
    "no": 2, "date": "2021-08-01", "name": "テスト 花子",
  },
  {
    "no": 3, "date": "2021-09-01", "name": "テスト 次郎",
  },
  {
    "no": 3, "date": "2021-10-01", "name": "テスト 次郎",
  },
]

このデータに対して $e.chunk('no') を実行すると、次のように変換されます。

[
  [
    {
      "no": 1, "date": "2021-04-01", "name": "テスト 太郎",
    },
    {
      "no": 1, "date": "2021-05-01", "name": "テスト 太郎",
    }
  ],
  [
    {
      "no": 2, "date": "2021-06-01", "name": "テスト 花子",
    },
    {
      "no": 2, "date": "2021-07-01", "name": "テスト 花子",
    },
    {
      "no": 2, "date": "2021-08-01", "name": "テスト 花子",
    }
  ],
  [
    {
      "no": 3, "date": "2021-09-01", "name": "テスト 次郎",
    },
    {
      "no": 3, "date": "2021-10-01", "name": "テスト 次郎",
    }
  ]
]

このようにグルーピングされれば、後はこのグループ毎に帳票を作成するだけです。

グループ毎の繰り返し

グルーピングできたら、そのグループ毎に処理を行います。つまり foreach を使います。$pageにはグルーピングされたCSV行が入ります。

#foreach($page in $pages)
  // この中で帳票の処理
#end

つまり最初の $page は以下のようになっていると考えてください。

[
  {
    "no": 1, "date": "2021-04-01", "name": "テスト 太郎",
  },
  {
    "no": 1, "date": "2021-05-01", "name": "テスト 太郎",
  }
]

ヘッダーの定義

帳票のヘッダーとして利用するデータを抽出します。1行目は必ず存在しますので、添え字として [0] を利用します。

#set($h = $page[0])

ヘッダー行に関するデータ、たとえば会社名などは ${h.companyname} で出力できます。

f:id:moongift:20211126144730p:plain

明細行の処理

明細行も繰り返しになりますので、foreachを使います。

#foreach($item in $page)
  // この中で明細処理
#end

f:id:moongift:20211126144803p:plain

これで帳票のできあがりです。今回はデータの出力のみで、集計計算などは入れていません(CSVデータに元々入れています)。

まとめ

CSVはJSONとはデータ構造が異なるので、その扱いに多少の工夫がいります。しかし、JSONよりも使い慣れている人が多いので、業務システムとの連携ではCSVの方が活躍するかも知れません。

皆さんの帳票作りの参考にしてください。

外部サービスと組み合わせて、帳票の内容を動的に変更する

Docurainを使って帳票を出力する場合、そのデータの多くは社内データベースからの出力になるでしょう。しかし、外部サービスと組み合わせることで、データをよりダイナミックに変更できます。プログラムから帳票生成を実行すれば、そういった操作も簡単です。

今回はごく簡単な例として、住所をジオコーディングして位置情報に変換し、さらにその位置情報を使って静的な地図画像を取得します。帳票に限りませんが、PDFの中に外部サービスの情報を埋め込む際のテクニックの1つとして参考にしてください。

続きを読む

Docurainテンプレートとデータ構造のバランス

DocurainではExcelファイルのA列を使って、変数を定義したり、ロジックを記述できます。それらを使うことで、細かな体裁や出力の制御が可能です。構造化プログラミング相当のことができるため、ある意味「何でもできてしまいます」。

しかし、あまりDocurainのロジックを記述しすぎると、メンテナンス性に問題が出たり、デザインがプログラマブルになってしまうといった問題があります。

今回は1枚目と中間、最終ページで異なる帳票を例として、テンプレートとデータのバランスを解説します。

続きを読む

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-ドキュレイン-」|帳票開発エンジン

Docurainを使って動的にグラフを作成する

Docurainを使えばExcelファイルをテンプレートとして、多彩な帳票やレポートを出力できます。報告書やレポートなどでは、グラフが使われることが多いです。Excelでレポートを作成したことがあれば、そのデータを使ってグラフを埋め込んだことがある方も多いでしょう。

今回はDocurainを使って動的に値を変更したグラフを作成します。グラフを使うことでビジュアル的にも、訴求力が向上したレポートを作成できるでしょう。

続きを読む