ASTERIA Warp RecordGroupでPDF帳票をつくってみる

## はじめに
またもやRecordGroupです。PDFとの相性が良いのでは？という事で2312にて新しくなったPDFコンポーネントで、伝票の様なものを作るサンプルです。
一からフォーマット作るのは面倒なので、こちらのサイトの帳票を明細を５行に詰めて利用しています。
[ビジネステンプレート 発注書エクセルテンプレート(無料)_タテ型_001](https://template.the-board.jp/order_templates/article/order_template_001/)

今回の処理で不要な箇所はそのまま固定値で出力しています。数字のカンマ、日付の変換のみ行います。CSVデータはchatGPTでEXCELの出力項目に従った内容で生成したものを利用しています。

## RecordGroups使用　処理内容
下記CSVファイル（ヘッダ、明細）をPDFコンポーネントで発注番号ごとにPDF化します。

```header.csv
発注NO,発注日,取引先,件名,納期,納品場所,支払条件
12345,2024年02月10日,株式会社ABC商事,商品の納品に関する件,2024年02月20日,東京都中央区,30日ネット
23456,2024年02月11日,株式会社XYZ商店,納品依頼書,2024年02月25日,大阪市北区,45日払い
34567,2024年02月12日,株式会社123商事,納品のお願い,2024年02月18日,名古屋市中区,銀行振込
45678,2024年02月13日,株式会社456商店,商品のご注文,2024年02月28日,福岡市西区,60日ネット
56789,2024年02月14日,株式会社789商事,納品書のお知らせ,2024年02月22日,札幌市中央区,銀行振込
```

```meisai.csv
発注NO,明細NO,品名,数量,単位,単価,金額
12345,1,商品A,10,個,1000,10000
12345,2,商品B,5,個,2000,10000
12345,3,商品C,3,個,1500,4500
12345,4,商品D,2,個,1800,3600
12345,5,商品E,8,個,1200,9600
12345,6,商品F,4,個,700,2800
12345,7,商品G,6,個,3000,18000
12345,8,商品H,7,個,2500,17500
23456,1,商品I,15,個,900,13500
23456,2,商品J,10,個,1600,16000
23456,3,商品K,6,個,1800,10800
23456,4,商品L,4,個,500,2000
34567,1,商品M,12,個,800,9600
34567,2,商品N,5,個,1500,7500
34567,3,商品O,8,個,1700,13600
34567,4,商品P,10,個,1200,12000
45678,1,商品Q,7,個,2000,14000
45678,2,商品R,5,個,1300,6500
45678,3,商品S,9,個,1100,9900
45678,4,商品T,8,個,1800,14400
56789,1,商品U,6,個,700,4200
56789,2,商品V,9,個,1600,14400
56789,3,商品W,3,個,2000,6000
56789,4,商品X,5,個,900,4500
```

発注NO毎のPDFに出力します。
![発注書_23456.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/607103dd-c840-511d-d135-a7bd1427dea3.png)


## 処理フロー
![6-mRecordGroup5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/80544be8-5688-0d28-7844-086bfa9f6089.jpeg)


#### フロー変数
|フロー変数 | データ型 | 初期値 |
|-----------|-----------|-----------|
| vWorkFolder      | String      |wk       |
| v発注NO      | String      |       |


【処理概要】
1. ワークフォルダの削除
1. header、meisaiのCSVファイルの読み込みをし発注NOでJOINする
1. RecordGroupのループ（発注NO）
1. 明細NOでソートを行い、PDFのレコードに合わせてマッピング、発注NOをフロー変数に格納
1. PDF生成
1. フロー変数に保存された発注NOを利用しファイルの出力
ワークフォルダを先頭で削除する方法は、筆者が好んで行う初期処理です。処理の作業情報が１世代だけフォルダに残るため異常時の初期調査のためにその様にしています。他にもMutexを先頭に入れますが今回は省略しています。
フロー自体はRecordGroupで発注NO毎のストリームに分解し、集計やPDFの改ページ等気にせずそのまま移送できるので非常に単純な構成となっています。

### PDFコンポーネント
PDFコンポーネントでPDFビルダーを起動し単一セル、レコードを指定します。
ページ選択は、単票、複票ともに行います。

#### 単票・単一セル
<img title="単票・単一セル" width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/66b54095-e619-9ff6-5e16-796a8b6aa5db.png"/>

#### 単票・レコード
<img title="単票・レコード" width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/bcf4a3f3-10d4-3a7a-e207-d5f68ac717c5.png"/>

#### 複票（先頭）・単一セル
<img title="複票（先頭）・単一セル" width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/470aa409-9d33-aea6-0338-075030e629c4.png"/>

#### 複票（先頭）・レコード
<img title="複票（先頭）・レコード" width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/8d3da124-4290-7ba8-ca88-bf6ed19ea286.png"/>

#### 複票（中間）・単一セル
<img title="複票（中間）・単一セル" width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/c21243c2-b0ef-ec73-db90-529e1da9f5b0.png"/>

#### 複票（中間）・レコード
<img title=" 複票（中間）・レコード" width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/3ed2b05f-ba3c-5d20-dc3c-252905076b87.png"/>

#### 複票（末尾）・単一セル
<img title="複票（末尾）・単一セル" width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/eba87b81-76c3-5747-6fa6-763076a02a0e.png"/>

#### 複票（末尾）・レコード
<img title=" 複票（末尾）・レコード" width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/4ce07b78-8f3d-a35c-b9c2-d470002c7d1a.png"/>


### Mapper
Mapperではレイヤーを３つ指定していますが、明細と集計は同一レイヤーでも問題ありません。
普通のデータであれば、明細データに税区分や税額など入っていると思いますが、今回はマッパー内で10％で強制的に算出しています。
条件なしレイヤーで明細と集計を行い、レコードの最終行でヘッダ部や明細合計などにまとめて移送します。

![6-Mapper5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/a13232a8-12f4-ba39-4fb0-0ae85d9d0907.jpeg)

#### マッパー変数
| マッパー変数 | データ型 | 初期値 |
|-----------|-----------|-----------|
| 小計      | Decimal      |       |
| 消費税      | Decimal      |       |

#### レイヤー
| レイヤー名 | レイヤー条件 |
|-----------|-----------|
| 明細      | なし      |       |
| 集計      | なし      |       |
| 最終行      |＄stream.RecordNo = \$stream.RecordCount  |

### FilePut
FilePutではPDFのバイナリを
＄{flow.vWorkFolder}/発注書_${flow.get("v発注NO")}.pdf
に出力しています。


## RecordGroups未使用　処理内容
RecordGroupを使用しない場合にどの様なフローとなるかを比較のために構築してみました。といってもPDFコンポーネントの特性を考えると、入力ストリームが１発注NO毎の明細とヘッダ部、集計という構成自体は変わりません。いかにその形のストリームをPDFコンポーネントに入れるか、という事が必要な要素です。
入力データはRecordGroupを利用したもと同一とします。

## 処理フロー
![7-mRecordGroup6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/448212a4-55bf-bf29-274c-7ba7d3cd649d.jpeg)

#### フロー変数
|フロー変数 | データ型 | 初期値 |
|-----------|-----------|-----------|
| vWorkFolder      | String      |wk2       |
| v発注NO      | String      |       |


【処理概要】
1. ワークフォルダの削除
1. headerCSVファイルの読み込みをループする
1. headerレコードの発注NOをフロー変数に保存
1. meisaiCSVを読み込みし、Mapperでフロー変数発注NOと同じレコードだけを移送
1. 明細NOでソートを行い、HeaderCSVのストリームと合流しPDFのレコードに合わせてマッピング
1.  PDF生成
1. フロー変数に保存された発注NOを利用しファイルの出力

最終的に明細を発注NO毎のストリームに分割する事が目的のため、今回はMapperでフィルターしてみましたが、通常のFillterコンポーネントも問題ないでしょう。PDF直前のMapperでは、Headerのストリームと明細のストリームを合流させています。

### Mapper（フィルター）
このMapperでは、判定レイヤーでフロー変数「v発注NO」とレコードの発注NOを比べ、マッパー変数「判定」に移送し、移送レイヤーでは、マッパー変数「判定」がTrueのものだけを移送します。通常であればFillterコンポーネントで問題はありませんが、この方法は複雑条件やFillterコンポーネントでは指定できない条件でも簡単にフィルターできます。

![7-Mapper5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/94d35f81-17ba-eb92-a0c9-e3d7a65ce436.jpeg)

#### マッパー変数
|マッパー変数 | データ型 | 初期値 |
|-----------|-----------|-----------|
| 判定      | Boolean      |false       |

#### レイヤー
| レイヤー名 | レイヤー条件 |
|-----------|-----------|
| 判定      | なし      |       |
| 移送      |$local.Boolean = true |

### Mapper（PDF移送）
このMapperではPDFに移送するストリームと、単一セルへの移送を行います。この様な複数入力があるMapperでは、２つの情報のストリームのレコードがそのまま参照されます。Headerストリームには１行ですので、１行目のみ、明細ストリームは明細行分参照できます。そのため、単一セルのヘッダ要素はHeaderストリームの１行目、集計後の金額などは、最終行で単一セルに移送しています。Headerストリームを合流させない場合は、発注NOと同様にヘッダーレコードのカラムをフロー変数に格納し、最終行でPDFの単一セルに移送します。
今回はヘッダーのみ存在し明細が存在しない、というケースは考慮していません。

![8-Mapper5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/3e006f4b-c3af-fa6d-5e1d-c8e1e22c9fae.jpeg)

#### マッパー変数
| マッパー変数 | データ型 | 初期値 |
|-----------|-----------|-----------|
| 小計      | Decimal      |       |
| 消費税      | Decimal      |       |

#### レイヤー
| レイヤー名 | レイヤー条件 |
|-----------|-----------|
| 明細      | なし      |       |
| 集計      | なし      |       |
| １行目      |＄stream.RecordNo = 1  |
| 最終行      |＄stream.RecordNo = \$stream.RecordCount  |

PDFコンポーネントの設定値、ファイル出力はRecordGroupフローと同一です。

## 最後に
2306までは、今回の様な明細をPD化する場合、キーブレイクを行いPDFコンポーネントへの入力ストリームのコントロールを行う必要がありましたが、RecordGroupコンポーネントの登場により、伝票毎のキーで分割したストリームになりますので相性は非常に良いでしょう。また従来よりもPDFコンポーネントの処理が高速になっている様な気もしますのでメモリ消費するこのコンポーネントでも構築を単純化する事で、処理負担の少ない処理が構築できるのではないかと思います。

## 蛇足
<img title=" EXCEL.EXE指定" width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680444/d3cd57eb-3d0d-4778-be09-4de23186817e.png"/>

フローデザイナーのバージョンアップ後の最初のPDFコンポーネント利用でしたので、この画面が出てきました。また危うくテンプレートのEXCELファイルを指定してしまうところでした。危ない・・・
バージョンアップの際にはインストール直後のクライアント側作業として「EXCEL.EXE指定しておく」を忘れないうちにしておきましょう。ここで指定を間違えるとかなり面倒なので。

[Excelビルダーが起動できなくなりました](https://support.asteria.com/hc/ja/articles/229077087)