帳票開発は面倒くさい!
業務系システムにおける帳票出力は、令和になってもまだまだ必要とされる機能の一つです。この背景としては、日本の商慣習にて紙文化が根強く残っていることが挙げられるでしょう。それに加え、紙という媒体の「軽量」「折りたたみ可能」「容易に書き込みできる」「読みやすい(高解像度で印刷可能)」「低コスト」などの利点はまだタブレット端末やディスプレイでは代替し難いという背景もあります。従って紙文化が早期に無くなることは考えにくく、我々はまだまだ帳票出力機能の開発を行っていく必要があります。
帳票出力機能を実装するためには、「帳票テンプレートのデザイン」と「テンプレートへのデータを適用して描画する処理」そして「その出力処理をシステムとして実現」する必要があります。ここでは、これらをまとめて「帳票開発」と呼ぶこととします。
帳票開発は、グラフやバーコード、画像などを含んだグラフィカルな帳票を作ることがそもそも技術的には困難な部類であるということに起因して、その開発工数や保守コストが増大しがちです。
ただでさえ、IT業界で働いている方々は「ペーパーレス化したい」という要求が強いはずです。それに、ほとんどのシステムでは帳票自体が主目的ではなく、付帯的な機能であることがほとんどです。
そんな中で、システムの本質的な目的ではなく、手間だけかかる帳票開発はやりたくない、という認識を持つエンジニアは多いのではないでしょうか。私が今まで会った人に聞いても、経験者はみなさん口をそろえて「帳票はやりたくない」と言います(実際、その通りだと思います)。
こうした背景が相まってか、帳票開発では大きなイノベーションが発生してきませんでした。それがさらに帳票開発を面倒で困難なものにするという負のスパイラルに陥っています。
我々は紙文化が世界から完全に消える日が来るまで、ずっと暗い顔で帳票を作成していかなければならないのでしょうか? いや、そんなことでいいはずがありません。少しでも楽に開発できる方法を考えるべきです。
開発方法の色々
では実際には、どのようにして帳票開発が行われているのでしょうか? 大まかには、以下3つの方法が挙げられます。
- 帳票開発ツールの利用
- 完全に自作する
- Excel操作ライブラリの利用
帳票開発ツールの利用
帳票を開発する際に第一の選択肢になり得るのは「餅は餅屋」、つまり専門の帳票開発ツールを導入して開発することです。具体的には「SVF」「JasperReports」「Active Reports」といった製品が挙げられます。
これらには、エンタープライズ用途での帳票開発に必要な機能が盛り込まれています。ミリメートル単位で正確に文字や罫線を表現可能で、プリンター等と連携して帳票を高速に出力できます。製品によっては、RDBMSと連携してSQLを記述するだけで必要なデータを取得するなどの機能も包含します。
しかしながら、「細かいことにはこだわらないので、とりあえずPDFやExcelで帳票がダウンロードできればそれでいい」といったライトユースでは、いささか高機能すぎる面があり、そのライセンス費用を回収する程度の効果を得ることが難しいケースも多いでしょう。
また、多くの帳票開発ツールはその高度な機能を使いこなすために、相応の学習コストを要求することも事実です。帳票エディタはDTPソフトの使い方を覚えるのに近い学習時間を要求しますし、データ連携のための各種機能もマニュアルを参照しつつデバッグを重ね、使い方を覚えていく必要があります。デザインした帳票をプログラム上から扱うにも、高度な機能を扱うための重厚なAPIやイベント処理を使いこなすことが必要とされます。
私もこういった製品を何度か使用したことがありますが、個人的な感覚では基本的な帳票を作れるようになるまで1カ月、そこからどんな帳票でも実装できるという自信が湧いてくるまで、さらに2~3カ月を要したと記憶しています。プリンター制御やデータ連携などの高度な機能を使いこなすには、またさらに学習を重ねる必要があります。
完全に自作する
「帳票開発ツールは自システムに適さないのでは」という場合は、第二の選択肢として一から自作することが挙げられます。必要な機能だけを有するシンプルな帳票出力機能を実装するといった方針です。
この場合、帳票出力に応用できる方法としてはさまざまなものがありますが、代表的には以下2つが挙げられると思います。
- 「PDFBox」などのPDF操作ライブラリを使用する
- HTML+CSSを用いた帳票レンダリング
PDF操作ライブラリを利用した帳票開発には困難が伴います。なぜならば、PDF操作ライブラリはあくまでもPDFファイルを構成するテキストや線、イメージといった要素を操作するための低レベルなAPIを提供しているだけで、帳票を出力するための高度なAPIは用意されていないからです(当然ですが)。
このため、罫線やテキストを配置するにも絶対座標をポイントやミリメートルといった単位に変換した上で、一つずつの要素に対しそれぞれAPIをコールしていく必要があります。このような方法によって構成された帳票はその後の仕様変更で多くの修正が生じてしまいやすく、コードから完成した帳票をイメージするのが難しいため、開発者本人しかメンテナンスできない状況に陥りがちです。
任意の図表やテキストを思い通りの書式で出力するための有名な言語としては、HTMLとCSSがあります。HTMLとCSSで帳票を構成し、ブラウザによってレンダリングした結果を何らかの方法によってPDF等に出力すれば、任意の帳票を作成することができます。特にHTMLは世の中にたくさんのテンプレートエンジンがあり、一般的なWebの開発手法が流用できる利点もあります。
しかしながら、IT系エンジニアの基礎知識のように語られることも多いHTMLやCSSは奥が深く、帳票開発という視点では、狙ったところに罫線で囲まれたボックス1つを出力するのにもそれなりの知識が要求されます。具体的には、帳票開発ではz-indexとスタックコンテキストの理解、メディアクエリ、改ページ制御等に関する知識が必要になってくるでしょう。専門的にフロントエンジニアとして取り組んできた方であれば苦もなくできる作業ではありますが、必要に応じてHTMLやCSSを学習してきた方はいささか戸惑うかもしれません。
また、クライアント側で生成した帳票を印刷したりPDFとして出力したりすることは比較的簡単ではありますが、サーバーサイドでPDF等々に出力するためには多少の工夫が必要になります。具体的には、Seleniumなどのテスト自動化ツールを使用したり、バックエンドにWebページのレンダリングエンジンを利用したHTML to PDF変換ツールなどを使ったりする必要があります。ブラウザ(レンダリングエンジン)の立ち上げや終了で消費するリソースは少なくなく、サーバー上で長期にわたって安定して稼働させるためにはそれなりのノウハウを必要とするでしょう。
筆者もこの方法を試みたことがありますが、100回に1回ほどの頻度で帳票出力処理がハングアップしてしまう現象に悩まされた記憶があります。おそらく、何らかのリソースを取得しようとしてデッドロックに陥ったのだと予想していますが、最後まで原因は分かりませんでした。ブラウザやレンダリングエンジンはサーバー上で頻繁に起動と終了を並行して繰り返すような用途は想定して作られていないでしょうし、仕方のないことかもしれません。
自作する場合と帳票開発ツールを利用した場合の注意点
これまでの経験上「出力された帳票をエンドユーザーが編集したい」というご要望は多数受けたことがあります。
PDFやHTMLをベースとした開発方法を採用すると、システムのユーザーが編集する運用は難しくなります。これは「帳票開発ツールを利用する」というパターンでも、帳票開発ツールが対応している出力形式によっては同様の問題が発生します。
そもそもなぜ出力後にユーザーが手作業で編集する必要があるかというと、例えば現場での帳票の運用方法があまりにも多岐にわたるため、それらすべてをカバーしたシステムを構築するのは費用対効果の面から現実的でないといった背景があります。
すでにDocurainを導入・運用していただいている、建築業界向けSaaSサービスを提供する某社を例にすると、作成した帳票は建築現場や細分化された組織ごとに修正を加えて独自の運用をされているケースが多いそうです。そのほかにも、その日の作業内容によって帳票の項目(例えば、KY・危険予知実施項目など)やレイアウトを変更して入力欄のサイズ調整や説明文を修正する場合もあるとのことでした。
従って、帳票はExcel形式で出力して現場・組織ごとに修正した上で印刷し、全員に配って現場で参照できるようにしています。この手作業の運用をシステム化するには開発工数の増加という問題もさることながら、エンドユーザーである作業者、職長のITリテラシーを考えてもExcelで出力した結果を修正するような運用が望ましいとして、このような結論に達しました。
この例に限らず、ユーザーが出力された帳票を手作業で修正したいケースにおいては、多くの人が手軽に編集できるExcel形式での出力を求められることが非常に多いのです。
Excel操作ライブラリの利用
前述の通り、Excelを帳票出力のためのツールとして利用しているケースはとても多いのです。グリッド形式のエディタで手軽に罫線を組み合わせることができ、かつ大抵のPCにインストールされており、多くの人が扱えるExcelを、帳票出力のための簡易的なDTPソフトとして利用することは悪くない方法です。
ところで近年は「ネ申エクセル」なるものが批判の対象となっています。これは「Excelでそこまでやるか」と思わせる重厚で複雑な機能をExcelで実現させたものです。ただ、このサイトの読者であればご存じの通り、「データ」「ビジネスロジック」「ビュー」は分割するのが通常のアーキテクチャです。Excelを単に最終的な出力形態であるビューとして使うだけで責務を明確に切り分けていれば、「ネ申エクセル」問題は発生しません。
そして、おそらくこの事実に気づいた人のほとんどが、一度はApache POI(Java)やOpen XML SDK (C#)といったExcelファイル操作ライブラリを利用して帳票出力機能を実装しようと試みたことがあるのではないでしょうか。しかし残念ながら、この方法もすでに述べたPDF操作ライブラリやHTMLを使った方法の課題を解決できるものではありません。
まず、Excelファイル操作ライブラリを使用し、まっさらのシートにゼロから帳票レイアウトを構築していくのであれば、PDFライブラリを使用するのとの違いはほとんどありません。従って、次にたどり着く手法は「Excelで作成した帳票テンプレートに独自のプレースホルダを埋め込んでおき、生成するときにそれを置換すればコーディングレスで帳票が作成できるはずだ」というものになります。しかしながらこれは想像以上に大変な作業だと気づくはずです。「動的に行が増えていく場合は?」「条件によってレイアウトが変わる場合は?」どのようにそれを実装すればいいのでしょうか。
Excelを帳票テンプレートとして実用的なものにするためには、Excelの内部仕様をよく理解する必要があります。Excelを操作するために提供されているAPIはExcel(OpenXML)フォーマットを操作するための低レベルなAPIなので、それ自体を前提知識として要求しています。例えば、スタイルを適用した行を動的に追加していき値を挿入するといった処理を一つとっても、詳しく知らない人が扱うと簡単にOutOfMemoryエラーを引き起こします(筆者は過去、実際の業務で何度か経験したことがあります)。
そのほか、Excel操作ライブラリを使用する場合にはサーバーサイドでのPDF出力が難しいといった問題もあります。
そういったことを考慮すると、1人のエンジニアが他の作業と並行して片手間で取り組むのは現実的ではなく、専門のチームを抱える必要があるでしょう。ただし、我々は帳票を作りたいのであって、高い開発工数を支払ってExcelで帳票エンジンを作ることが目的ではないのです。一般的な帳票開発ツールの一部分を独自に実装するために、帳票開発ツールを利用するためのコスト以上を支払っては本末転倒です。
Docurainを使うと何がうれしいのか
Docurainを簡単に説明するならば、その「Excelで帳票用のテンプレートエンジンを作ろう」という、多くの人がたどり着くが、その開発工数の多さや技術的困難さから諦めざるを得なかったことを愚直にやりきり、それをクラウドサービス化したものです。
Docurainの開発にあたっては「面倒な帳票開発をさっさと済ませ、本来やるべきビジネスに集中できる方法を提供したい」という強い思いがあります。Docurainは専用の帳票開発ツールでは提供されているが、ライトユースでは不要な機能(高度なプリンター連携、正確な描画、データ連携など)を削ぎ落とし、代わりに帳票開発の生産性を最大化することに注力しました。
Docurainの主な特長として、以下5つが挙げられます。
- ExcelとJSONで完結する
- クラウドサービスである
- コーディング量を低減
- 帳票に必要とされる多数の追加機能
- 低コストで開始可能
ExcelとJSONで完結する
Docurainでは、帳票テンプレートはExcelで作成できます。Excelで印刷した状態がそのまま帳票として出力されるため、Excelを扱える人なら誰でもDocurainのテンプレートを作成することができます。後述するようにいくつかの特殊なマクロを記入する場合もありますが、直観的には初めてDocurainを扱う人でも理解は容易です。
この、Excelで作った帳票テンプレートに任意の構造で記述されたJSON形式のデータを挿入し、最終的に画像やPDF、Excelファイルとして出力するのがDocurainのすべてです。
また、Excelで帳票テンプレートを作成するということは、プログラマでなくとも帳票の作成や修正が容易に可能であることを意味します。これを活かして、システム利用部門の方が直接、帳票レイアウトを修正するという導入事例も存在します。
クラウドサービスである
クラウドサービスのため、サーバーの購入や保守は一切不要で、ライセンスを購入して開発環境をインストールするといったことも必要なく、ExcelがインストールされたPCがあれば今すぐ使ってみることが可能です。
既存のシステムと連携させる場合にも、使用するJSON形式のデータを出力してDocurainの公開APIにHTTPリクエストとして送信するだけで、帳票の出力結果(PDFファイル、Excelファイル、画像ファイル)がバイナリデータとして返却されます。
また、Docurainは十分なスケーラビリティを有しており、多数のリクエストでも大量のページを出力するリクエストでも現実的な応答速度で処理することができ、およそ4000ページ/秒までは容易にスケール可能であることを確認しています。
コーディング量を低減
すでに述べた通り、各帳票に依存したコーディング量が増えるほど保守性に問題が生じます。
Docurainでは固定のレイアウトで済む帳票であれば、コーディングは完全に不要です。レイアウトの動的な変更を含む場合であっても、簡単なコード(マクロ)を記述することで対応可能です。このコードはスタイルやレイアウトを変更したり、画像やバーコードを挿入したりするなど、Excelの機能だけでは表現できないことを記述するために用いられます。
これはApache Velocity互換の記法であり、直観的に理解することができます。おそらく、プログラマであれば前提知識がなくても見ただけで何をしているか理解できるほどに簡単なものです。つまり、テンプレートエンジンとしての機能を構築するために独自の構文を利用するのですが、その記法は特殊ではなく一般的かつ直観的なものです。
帳票に必要とされる多数の追加機能
DocurainではExcelの機能のうち、帳票デザインで必要と思われる大部分を利用できます。これには、グラフや図表、シェイプの表示、数式、書式設定、条件付き書式も含まれます。これに加えて、Excelで不足している幾つかの機能を独自に追加しています。具体的には以下が挙げられます。
- 制御構造(if、foreachなど)
- Excelの印刷範囲設定を応用した直観的な改ページ制御
- Excelスタイル指定
- バーコード、QRコード挿入
- 画像の動的な挿入
低コストで開始可能
Docurainを利用するのにイニシャルコストは不要です。すぐに使用を開始することができ、1帳票あたり5円から出力することが可能です。出力したファイルのデータサイズに応じて料金は増加しますが、大きな画像データ等を含まない帳票ならば、ほとんどが5円で出力できます。
Docurainが苦手とすること
DocurainではテンプレートをExcelとしているため、帳票中のテキストや図表といった要素や余白をミリメートル単位で制御するのは苦手です。そのような要求がある場合は、一般の帳票エンジンを使用するか、PDF操作ライブラリを利用するなど、表示位置を厳密に制御できる手法を選択することになります。
サンプルとして納品書を作成する
それでは、ここからDocurainを利用した帳票の開発例を説明します。比較対象として、Apache POI(とJava)を応用して作った場合も説明します。
作成する帳票
今回は、このようなシンプルな納品書を作成することとします。両者の住所氏名と、明細行と合計金額を動的に出力してみます。
Apache POIを使用した場合
まず、静的な部分のみを記述した以下のExcelテンプレートを用意しました。
動的にテキストを入れていく部分に、目印となる適当なテキストを入れています。
挿入するデータを表現するために、ここでは次のようなPOJOオブジェクトを使用することとしました(Lombokを使用して、コンストラクタとアクセサを自動生成しています)。
@Data @AllArgsConstructor public class InvoiceData { private ContactInfo customer; private ContactInfo shop; private List<OrderLine> orderLineList; private LocalDate issueDate; } @Data @AllArgsConstructor public class ContactInfo { private String name; private String address; private String zip; private String phone; } @Data @AllArgsConstructor public class OrderLine { private String productName; private int productPrice; private int count; }
このデータを使用して実際に帳票を出力するためのコードは以下です。
public class PoiInvoiceRenderer { public static void renderAndSave(String outputPath, InvoiceData data) throws IOException { // 帳票テンプレートExcelファイルの読み込み Workbook wb = WorkbookFactory.create(PoiInvoiceRenderer.class.getResourceAsStream("/nouhinsho-poi.xlsx")); Sheet sheet = wb.getSheetAt(0); // 顧客 cellAt(sheet, 4, 2).setCellValue(data.getCustomer().getName() + " 様"); cellAt(sheet, 5, 2).setCellValue("〒" + data.getCustomer().getZip()); cellAt(sheet, 6, 2).setCellValue(data.getCustomer().getAddress()); cellAt(sheet, 7, 2).setCellValue("TEL: " + data.getCustomer().getPhone()); // 発行日 cellAt(sheet, 4, 8).setCellValue(Date.from(data.getIssueDate().atStartOfDay(ZoneId.systemDefault()).toInstant())); // ショップ cellAt(sheet, 6, 11).setCellValue(data.getShop().getName()); cellAt(sheet, 7, 11).setCellValue("〒" + data.getShop().getZip()); cellAt(sheet, 8, 11).setCellValue(data.getShop().getAddress()); cellAt(sheet, 9, 11).setCellValue("TEL: " + data.getShop().getPhone()); // 明細 int rowIdx = 12; CellStyle currencyStyle = wb.createCellStyle(); DataFormat format = wb.createDataFormat(); currencyStyle.setDataFormat(format.getFormat("¥#,###")); for(OrderLine line : data.getOrderLineList()) { sheet.createRow(rowIdx); Row row = sheet.getRow(rowIdx); row.createCell(2, CellType.STRING).setCellValue(line.getProductName()); row.createCell(8, CellType.NUMERIC).setCellValue(line.getProductPrice()); row.createCell(9, CellType.NUMERIC).setCellValue(line.getCount()); row.createCell(10, CellType.FORMULA).setCellFormula("I" + (rowIdx + 1) + "*J" + (rowIdx + 1)); // style cellAt(sheet, rowIdx, 8).setCellStyle(currencyStyle); cellAt(sheet, rowIdx, 10).setCellStyle(currencyStyle); sheet.addMergedRegion(new CellRangeAddress(rowIdx, rowIdx, 10, 11)); rowIdx++; } // 合計 sheet.createRow(rowIdx++); Row row = sheet.createRow(rowIdx); row.createCell(9, CellType.STRING).setCellValue("合計"); row.createCell(10, CellType.FORMULA).setCellFormula("SUM(K13:K" + (13 + data.getOrderLineList().size() - 1) + ")"); sheet.addMergedRegion(new CellRangeAddress(rowIdx, rowIdx, 10, 11)); CellStyle currencyAndBorder = wb.createCellStyle(); currencyAndBorder.setBorderBottom(BorderStyle.MEDIUM); currencyAndBorder.setDataFormat(format.getFormat("¥#,###")); cellAt(sheet, rowIdx, 9).setCellStyle(currencyAndBorder); cellAt(sheet, rowIdx, 10).setCellStyle(currencyAndBorder); row.createCell(11, CellType.STRING); cellAt(sheet, rowIdx, 11).setCellStyle(currencyAndBorder); // 例外スロー時のリソースの開放処理などは簡単のために省いています wb.write(new FileOutputStream(new File(outputPath))); wb.close(); } private static Cell cellAt(Sheet sheet, int row, int col) { return sheet.getRow(row).getCell(col); } } public class Main { public static void main(String[] args) throws IOException { LinkedList<OrderLine> orderLines = new LinkedList<>(); orderLines.add(new OrderLine("128GB Micro SDカード", 3800, 2)); orderLines.add(new OrderLine("5インチ ガラス液晶フィルム", 1200, 1)); orderLines.add(new OrderLine("ノンフロン ダストブロワー 2パック", 800, 1)); InvoiceData invoice = new InvoiceData( new ContactInfo( "田中 太郎", "東京都港区X-Y-Z 1-2-3", "123-46587", "091-2568-4514" ), new ContactInfo( "CYBER SHOP ABC", "山形県酒田市A-B-C 1-2-3", "598-123654", "098-15468-41114" ), orderLines, LocalDate.of(2018, 11, 20) ); PoiInvoiceRenderer.renderAndSave("./output.xlsx", invoice); } }
単純な内容であっても、値を一つずつ挿入していく必要があるために行数が増え、さらにそのほとんどがセルの行番号・列番号を指定するような可読性の低いコードになってしまっていることが分かると思います。例えば、先頭にもう1行何かを追加したいという要求があったとき、どう修正すればいいのでしょうか……あまり考えたくはないですね。
Docurainを使用した場合
Docurainを使用した場合は、帳票出力に必要なことはすべてExcelファイルに記述でき、コードを書く必要はありません。
まずは、差し込むデータの構造を定義しましょう。Docurainでは任意の構造のJSONデータを使用できますが、ここでは以下のような構造のデータを使うことにします。
{ "customer": { "name": "田中 太郎", "address": "東京都港区X-Y-Z 1-2-3", "zip": "123-46587", "phone": "091-2568-4514" }, "shop": { "name": "CYBER SHOP ABC", "address": "山形県酒田市A-B-C 1-2-3", "zip": "598-123654", "phone": "098-15468-41114" }, "orderLineList": [ { "productName": "128GB Micro SDカード", "productPrice": 3800, "count": 2 }, { "productName": "5インチ ガラス液晶フィルム", "productPrice": 1200, "count": 1 }, { "productName": "ノンフロン ダストブロワー 2パック", "productPrice": 800, "count": 1 } ], "issueDate": "2018-11-20" }
このデータを出力するためのExcel帳票テンプレートは以下のようになります。
それぞれ、見慣れない記法がありますが、ほとんどは直観的に理解できるのではないでしょうか。簡単に説明すると、以下の通りになります。
-
$
から始まるプレースホルダで値を挿入していく -
$ENTITY
が与えられたJSONオブジェクトのルートとなる - A列に特殊なマクロを記述していく
-
#set()
は新しい変数の定義 -
#foreach
が配列要素の繰り返し処理 -
#foreach
などの構文が書かれた行は削除される -
#ROW()
はそのセルの行番号に置換されるマクロ
このようなExcelテンプレートを作成し、JSONデータを用意してDocurainサービスのREST APIにリクエストを送信すれば、PDFやExcelといった形式のバイナリデータが返却されます。
今回作成した帳票は登録不要ですぐにお試しすることもできます。こちらのExcelテンプレートとJSONファイルをダウンロードし、以下のページにアクセスして「テンプレート」にExcelファイルを、「JSONデータ」にJSONファイルを指定して実行してみてください。指定した形式(PDFもしくはExcel)で帳票がダウンロードできるはずです。
そのほかの帳票
そのほか、Docurainから出力した帳票の例を紹介します。
自動車検査証(車検証)の例です。こういったたくさんの罫線で構成される帳票は多いですが、Excelであればそこまで苦もなく作ることができます。この帳票ならば、1~2時間もあれば十分に実装可能です。
バーコードやQRコードを含む例です。バーコードやQRコードは#QRCODE()
、#EAN8()
といったマクロをテキストとして矩形のシェイプに記述する方法で出力します。バーコード/QRコード出力も通常のテキスト出力と同程度の作業で出力することができます。
こちらの時刻表は弊社開発ブログ記事「私が本物のExcel時刻表ってやつを見せてあげますよ」にて詳しい作り方を解説しています。
時刻表をExcelで作るのは一見大変そうですが、行と列のグリッドを基礎にして編集していけるので通常のDTPソフトウェアで記述するよりむしろ簡単かもしれないと個人的には考えています。
ガントチャートの例です。条件付き書式をうまく利用することで、土日の背景色を設定したり、作業期間のバーを着色したりすることもできます。ガントチャート部分の描画にはDocurain独自の機能は使っていません。Excelの表現方法としてはややトリッキーな部類になるかと思いますが、しかしこの程度であれば開発者以外でも容易にメンテナンス可能なレベルだと思われます。
まとめ
長い記事でしたが、お読みいただきありがとうございました。
長年、さまざまなプロジェクトで帳票開発に携わってきた私ですが、Docurainは一つの理想形であると個人的には思っています。
弊社の開発メンバーの多くがDocurainのヘビーユーザーでもあります。我々が現場で帳票開発を行い、真に必要とされる機能を日々追加し、より便利なサービスへと成長を遂げています。もちろん、ユーザーの方々から受け取ったフィードバックを新しい機能として実装することも日々行っています。
Docurainはすぐに使い始めることができ、支払い方法を登録しない限りは何らかの請求が発生することはありません。もし、現在帳票開発に苦労している、もしくは、これから帳票開発を行う予定があるという方は、Docurainもお試しいただき、選択肢の一つに加えてもらえるとうれしく思います。