【ServiceNow】スクリプトを使用してHTMLでフォーマットした形式でPDFを出力する方法

:::note info
この記事はServiceNow Advent Calendar 2023の16日目の記事です。
:::

https://qiita.com/advent-calendar/2023/servicenow

### 概要
この記事では、出力するPDFをHTMLでフォーマットを作成し、レコードの内容に合わせて出力できるようにするためのスクリプトを作成できる方法を解説します。

# はじめに
ServiceNowには素晴らしい機能が備わっています。OOTB（Out of the Box）機能で提供されるPDF出力オプションもその１つになります。
これはフォームやリスト画面など、さまざまな場面で利用できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425100/edff3c2b-5323-ec75-7f70-2bb5364d979e.png)

クライアントから寄せられる質問の中で、

**「レコードの内容をPDFで出力したいのですが、可能ですか？」**

という声が絶えません。私は喜んでこの機能を紹介するのですが、よく寄せられる質問があります。

**「出力されるフォーマット（項目の配置や見た目）はカスタマイズできますよね？」**

すると、一般的な回答はこうです。

**「いえいえ、この見た目は標準で定まっていて、カスタマイズで変更することはできないんですよ。」**

となるわけです。そうすると、相手からは

**「今まで通りじゃなきゃ嫌だ」**

**「なんでカスタマイズできないの？」**

**「使えない機能だね」**

といった反応が返ってくることも珍しくありません。

確かに見た目にこだわりたい気持ちは理解できますが、「使えない機能」とまで言われるのは心外です。必要最低限の機能は備わっており、今注力すべきは別のところだと説明したくなりますが、ここでの議論は容易に紛糾していくことでしょう。

当時の私は、PDF出力は機能OOTBしか知りませんでしたが、ここで代替策がないか調べるとPDF出力用のAPIがあることが分かりました。
ならば、カスタムなアプローチで、理想的なPDF出力機能を実装できるようにし、新たな提案ができるようにしたいです。

では早速、ServiceNowでオリジナルなPDF出力の処理を実装していきます。

:::note alert
ServiceNowに限らずSaaS全般に言えることですが、現行踏襲のようなカスタマイズは非推奨であると考えています。SaaSのパッケージ製品がイケテないのでカスタマイズするというのは、SaaSを選定した意味を損なってしまいます。今回紹介するAPIはあくまで様々な形式のPDFを出力できるように用意されたAPIなので、標準機能のPDF出力の代替としてあるものではない事をご理解していただければと思います。
:::


# PDFGenerationAPIを使用する
ServiceNowにはHTMLで作成したフォーマットをPDFで出力するための[API](https://developer.servicenow.com/dev.do#!/reference/api/tokyo/server/sn_pdfgeneratorutils-namespace/PDFGenerationAPIBothAPI?navFilter=prefill)が存在します。このAPIは2021年には存在していたようです。
このAPIの説明は以下になります。
> PDF 変換と PDF フィールドの処理をサポートします。
この API は ServiceNow PDF の一部です 生成ユーティリティプラグイン(com.snc.apppdfgenerator)であり、 名前空間sn_pdfgeneratorutils。プラグインはデフォルトで有効になっています。
> 
> これらのメソッドは、カタログ以外のアイテムで作成されたドキュメントにも使用できます。
このクラスにより、次のタスクが可能になります。
> - HTML 文字列から PDF を動的に生成し、レコードに添付する
> - PDF のフィールドへの入力
> - PDF に署名する
> - フラット化しない、フラット化してる、または部分的にフラット化されている
> - PDF フィールドデータの取得

[※PDFのフラット化って？](https://pdf.wondershare.jp/pdf-tips/flatten-pdf.html)

このAPIを利用すると、PDFを生成するだけでなく、PDFをフラット化せずに編集可能なポイントを含めて出力することや、逆にPDFからフラット化されていない情報を取得することも可能です。さらに、画像の挿入、ヘッダー・フッダーの追加、サイズの定義なども簡単に行えます。

基本的な使用方法は以下のコードです。

```javascript
//PDFGenerationAPI オブジェクトをインスタンス化します
var v = new sn_pdfgeneratorutils.PDFGenerationAPI;

/*PDFを出力します
引数1: PDFに変換するHTMLソース 
引数2: PDFを添付するテーブル,
引数3: PDFを添付するレコードのsys_id,
引数4: PDFの名前
*/
var result = v.convertToPDF("<html_source>", "<target_Table>", "<target_sys_id>", "<PDF_name>");
```
フォーマットの元になるHTMLコードを事前に用意し、そこにはダミーの値を仕込んでおきます。このダミーの値は、後で対象のレコードのフィールド情報で置換され、ServiceNowに登録された情報をもとにPDFを生成します。

# 実際に構築する
さて、実際に構築に取り組んでみましょう。以下が事前に用意するべき事項です：

-  タスクテーブルを継承した"Generate PDF"テーブルを作成する
- "HTMLソース"[u_html]フィールドを追加する
-  フォームを以下のように構成する

これらのステップを踏んで、次に進んでいきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425100/7692e6ce-3a7c-baba-24fd-6b06c699e022.png)

HTMLソースに以下のコードを"ソースコード"としてコピペする。
※[</>]のようなソースコードボタンを押し、表示されたウィンドウにコピペしてください。
```html
<table style="border-collapse: collapse; width: 100%; height: 76px;" border="1">
<tbody>
<tr>
<td style="width: 12.9979%;"><strong>番号</strong></td>
<td style="width: 87.0021%;">AAA</td>
</tr>
<tr style="height: 22px;">
<td style="width: 12.9979%; height: 22px;"><strong>件名</strong></td>
<td style="width: 87.0021%; height: 22px;">BBB</td>
</tr>
<tr style="height: 22px;">
<td style="width: 12.9979%; height: 22px;"><strong>ユーザー</strong></td>
<td style="width: 87.0021%; height: 22px;">CCC</td>
</tr>
<tr style="height: 22px;">
<td style="width: 100%; height: 22px;" colspan="2"><strong>説明</strong></td>
</tr>
<tr style="height: 0px;">
<td style="width: 100%; height: 10px;" colspan="2" rowspan="2">DDD</td>
</tr>
</tbody>
</table>
```


HTMLで作成されたフォーマットができたら、次はAAAなどのダミーの値を対象のレコードの実際の情報に差し替えていきます。これによって、動的でカスタマイズされたPDFを生成することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425100/23464944-2c4a-dbc4-7c9e-a5e0ff20abfb.png)


## ビジネスルールを作成する
今回は、PDFを出力するためのスクリプトを簡単に作成し、ビジネスルールに記述していきます。これを行うために使用するテーブルは"Generate PDF"テーブルです。もちろん、より実用的な運用を目指すのであれば、フローの中で構築するか、メールインバウンドアクションと組み合わせることも考慮されるでしょう。

ビジネスルールの定義は以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425100/ee0effa6-5c18-f4f7-b0af-ecc5e4f61b76.png)


ビジネスルールのスクリプト
※// Add your codeの中にコピペしてください。function関数の中にコピぺしてください。
```javascript
    //PDFGenerationAPI オブジェクトをインスタンス化します
    var v = new sn_pdfgeneratorutils.PDFGenerationAPI;

    //変数
    var targetTable = current.getRecordClassName();
    var recordId = current.getUniqueValue();
    var docName = "My_PDF";
	
    //HTMLソースをレコードの情報に合わせて置換
    var html = current.getValue('u_html');
    html = html.replace('AAA', current.getValue('number'));
    html = html.replace('BBB', current.getValue("short_description"));
    html = html.replace('CCC', current.getDisplayValue("assigned_to"));
    html = html.replace('DDD', current.getValue("description"));

    /*PDFを出力します
    引数1: PDFに変換するHTMLソース 
    引数2: PDFを添付するテーブル,
    引数3: PDFを添付するレコードのsys_id,
    引数4: PDFの名前
    */
    var result = v.convertToPDF(html, targetTable, recordId, docName);

    gs.info(JSON.stringify(result));
```

# ビジネスルールを実行し、結果を確認する。
テーブルに[番号]、[アサイン先]、[簡単な説明]、[説明]フィールドに任意の情報を入力し、ステータスを[完了して終了]に変更してレコードを更新します。

上記の手順が成功すると、以下のメッセージが表示されます。添付されたPDFをダウンロードし、内容を確認してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425100/125da9aa-5622-dd5e-e56e-ce61da98e90e.png)

以下のように元のHTMLソースの値が置換されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425100/7052daa3-70b3-5fb5-c224-78f114ef17e3.png)


HTMLのレイアウトを準備することで、そのレイアウトに合わせてレコードの内容をPDFとして出力できるようになりました。カスタマイズには開発工数がかかりますが、プロジェクトやユーザーにメリットがある場合は、実際に開発してみることを検討しても良いでしょう。


# 参考
**API Reference**
- [PDFGenerationAPI](https://developer.servicenow.com/dev.do#!/reference/api/tokyo/server/sn_pdfgeneratorutils-namespace/PDFGenerationAPIBothAPI?navFilter=prefill)
​
​
**コミュニティ**
- [Fill PDF using GeneralPDFUtils(GeneralPDFUtilsを使用してPDFを埋める)](https://www.servicenow.com/community/developer-articles/fill-pdf-using-generalpdfutils/ta-p/2567525)
- [How to edit the PDF attachmet with record details, while calling in the mail script.(メールスクリプトを呼び出しながら、レコードの詳細を含むPDF添付ファイルを編集する方法)](https://www.servicenow.com/community/developer-forum/how-to-edit-the-pdf-attachmet-with-record-details-while-calling/m-p/2567499#M999199)
- [Generating Custom PDFs - using the new PDFGenerationAPI(カスタムPDFの生成 - 新しいPDFGenerationAPIを使って)](https://www.servicenow.com/community/developer-articles/generating-custom-pdfs-using-the-new-pdfgenerationapi/ta-p/2318979)
​
**Youtube**
- [PDF Generator API - Live Coding Happy Hour for 2021-04-23](https://www.youtube.com/watch?v=IMtEKBxJt0A)
- [ServiceNow PDF Generation API Magic | Learn the power of ServiceNow PDF Generation API | PDF API](https://www.youtube.com/watch?v=3uBVeDamzuA)