対象: メーカー・問屋の受注処理、在庫管理、出荷処理など業務システムの設計パターン
基本文法は RPG 文法基礎、モジュール化は RPG モジュール設計 を参照
COBOL版は COBOL 業務ロジック実装 を参照
目次
1. メーカー・問屋の業務フロー全体像
メーカー・問屋の基幹業務:
受注 在庫 出荷 請求
─────── ─────── ─────── ───────
得意先から 在庫引当 ピッキング 月次締め
受注入力 └→不足なら 出荷指図 請求書発行
│ 発注起票 送り状印刷 入金消込
│ │ │
↓ ↓ ↓
┌─────────────────────────────────────────┐
│ DB2 for i(物理ファイル群) │
│ ORDHDR / ORDDTL / CUSTPF / ITMPF │
│ INVPF / SHPPF / BILPF │
└─────────────────────────────────────────┘
典型的なプログラム構成
| プログラム | 種別 | 内容 | 実行タイミング |
|---|---|---|---|
| ORD001R | 対話型 | 受注入力画面 | 日中随時 |
| ORD002R | バッチ | 受注データチェック | 日次夜間 |
| INV001R | バッチ | 在庫引当処理 | 日次夜間 |
| INV002R | バッチ | 発注点チェック→自動発注 | 日次夜間 |
| SHP001R | バッチ | 出荷指図作成 | 日次朝 |
| SHP002R | バッチ | 送り状印刷 | 日次朝 |
| BIL001R | バッチ | 月次締め→請求書作成 | 月次 |
| MST001R | 対話型 | 得意先マスタメンテ | 随時 |
2. 受注処理(オンライン)
5250画面から受注データを入力する対話型プログラム。
ファイル構成
**free
ctl-opt dftactgrp(*no) actgrp(*caller);
// 画面ファイル
dcl-f ORDDSP workstn(*ext) usage(*input:*output);
// マスタファイル(参照)
dcl-f CUSTPF disk(*ext) usage(*input) keyed;
dcl-f ITMPF disk(*ext) usage(*input) keyed;
// トランザクションファイル(書込)
dcl-f ORDHDR disk(*ext) usage(*output) keyed;
dcl-f ORDDTL disk(*ext) usage(*output);
メインロジック
// 画面表示ループ
dou *inkc; // F3キーで終了
exfmt ORDSCR; // 画面表示&入力待ち
if *inkc; // F3 = 終了
leave;
endif;
// 得意先チェック
chain custId CUSTPF;
if not %found(CUSTPF);
errMsg = '得意先が存在しません';
iter;
endif;
// 与信チェック
if custRec.balance + orderAmt > custRec.creditLimit;
errMsg = '与信限度額を超えています';
iter;
endif;
// 受注ヘッダ書込
exsr writeOrderHeader;
// 受注明細書込(配列ループ)
for i = 1 to lineCount;
exsr writeOrderDetail;
endfor;
enddo;
*inlr = *on;
// ──────────────────────────────────
begsr writeOrderHeader;
ordHdrRec.ordNo = nextOrderNo();
ordHdrRec.custId = custId;
ordHdrRec.ordDate = %date();
ordHdrRec.status = 'N'; // New
ordHdrRec.totalAmt = orderAmt;
write ORDHDRFMT ordHdrRec;
endsr;
begsr writeOrderDetail;
ordDtlRec.ordNo = ordHdrRec.ordNo;
ordDtlRec.lineNo = i;
ordDtlRec.itemCd = detail(i).itemCd;
ordDtlRec.qty = detail(i).qty;
ordDtlRec.price = detail(i).price;
write ORDDTLFMT ordDtlRec;
endsr;
AI解析での注目点
workstnファイル = 5250画面。モダナイゼーション時にAngular UIに変換する対象chain+%found()= マスタ検証パターン。API化時にバリデーションロジックとして抽出exfmt= 画面の表示&入力待ち。このループ構造がWebアプリのリクエスト/レスポンスに対応
3. 在庫引当処理(バッチ)
日次夜間バッチで、受注データに対して在庫を引き当てる。メーカー・問屋の基幹業務の中核。
**free
ctl-opt dftactgrp(*no) actgrp(*caller);
dcl-f ORDDTL disk(*ext) usage(*input) keyed;
dcl-f INVPF disk(*ext) usage(*update) keyed;
dcl-f ALCLOG disk(*ext) usage(*output);
dcl-s allocQty packed(7:0);
dcl-s shortQty packed(7:0);
dcl-s allocCount int(10) inz(0);
dcl-s shortCount int(10) inz(0);
// 未引当の受注明細を順次処理
setll *loval ORDDTL;
read ORDDTL;
dow not %eof(ORDDTL);
// 該当商品の在庫を検索
chain ordDtlRec.itemCd INVPF;
if %found(INVPF);
// 有効在庫 = 在庫数量 - 引当済数量
dcl-s available packed(7:0);
available = invRec.onHand - invRec.allocated;
if available >= ordDtlRec.qty;
// 全数引当可能
allocQty = ordDtlRec.qty;
invRec.allocated += allocQty;
update INVFMT invRec;
allocCount += 1;
else;
// 一部引当(在庫不足)
allocQty = available;
shortQty = ordDtlRec.qty - available;
invRec.allocated += allocQty;
update INVFMT invRec;
shortCount += 1;
// 不足分を発注起票(別プログラムで処理)
exsr writeShortageLog;
endif;
// 引当ログ書込
exsr writeAllocLog;
endif;
read ORDDTL;
enddo;
// 集計出力
dsply ('引当完了: ' + %char(allocCount) + '件');
dsply ('在庫不足: ' + %char(shortCount) + '件');
*inlr = *on;
AI解析での注目点
onHand - allocated = available→ 在庫引当の基本公式。AI在庫最適化の入力データshortQty→ 欠品データ。AI需要予測で削減可能な部分- このバッチの実行順序(受注取込→引当→出荷指図)はCLプログラムで制御されている
4. 出荷指図処理(バッチ)
引当済の受注明細から出荷指図データを作成し、ピッキングリストを印刷する。
**free
ctl-opt dftactgrp(*no) actgrp(*caller);
dcl-f ORDHDR disk(*ext) usage(*update) keyed;
dcl-f ORDDTL disk(*ext) usage(*input) keyed;
dcl-f SHPPF disk(*ext) usage(*output);
dcl-f PICKPRT printer(*ext) oflind(overflow);
dcl-s overflow ind;
dcl-s shipNo char(10);
// 引当済受注を検索
setll *loval ORDHDR;
read ORDHDR;
dow not %eof(ORDHDR);
if ordHdrRec.status = 'A'; // Allocated(引当済)
// 出荷番号採番
shipNo = nextShipNo();
// 出荷ヘッダ作成
exsr createShipment;
// 明細をピッキングリストに印刷
setll ordHdrRec.ordNo ORDDTL;
read ORDDTL;
dow not %eof(ORDDTL) and ordDtlRec.ordNo = ordHdrRec.ordNo;
exsr printPickLine;
if overflow;
write PAGEBREAK;
overflow = *off;
endif;
read ORDDTL;
enddo;
// 受注ステータスを「出荷済」に更新
ordHdrRec.status = 'S'; // Shipped
update ORDHDRF ordHdrRec;
endif;
read ORDHDR;
enddo;
*inlr = *on;
AI解析での注目点
overflowインジケータ = 帳票のページ送り。PDF生成に変換する際のポイントnextShipNo()= 採番処理。データ区域(DTAARA)で管理されていることが多いstatus = 'A' → 'S'= ステータス遷移。業務フローの状態マシンとして抽出可能
5. 月次締め処理(バッチ)
月末に実行する請求データ作成・帳票出力バッチ。
**free
ctl-opt dftactgrp(*no) actgrp(*caller);
dcl-f CUSTPF disk(*ext) usage(*input) keyed;
dcl-f SHPPF disk(*ext) usage(*input) keyed;
dcl-f BILPF disk(*ext) usage(*output);
dcl-f BILPRT printer(*ext) oflind(overflow);
dcl-s prevCust char(8) inz('');
dcl-s custTotal packed(11:2) inz(0);
// 出荷データを得意先順に読む
setll *loval SHPPF;
read SHPPF;
dow not %eof(SHPPF);
// ブレイク処理(得意先が変わったら小計出力)
if shpRec.custId <> prevCust and prevCust <> '';
exsr outputCustBill;
custTotal = 0;
endif;
// 売上加算
custTotal += shpRec.amount;
prevCust = shpRec.custId;
read SHPPF;
enddo;
// 最後の得意先の処理
if prevCust <> '';
exsr outputCustBill;
endif;
*inlr = *on;
// ──────────────────────────────────
begsr outputCustBill;
// 請求ファイルに書込
bilRec.custId = prevCust;
bilRec.billDate = %date();
bilRec.amount = custTotal;
write BILFMT bilRec;
// 請求書印刷
chain prevCust CUSTPF;
exsr printBillHeader;
exsr printBillTotal;
endsr;
ブレイク処理パターン
ブレイク処理 = キー値が変わったタイミングで小計・合計を出力するパターン
RPGのブレイク処理: SQLでの対応:
1. キー順にREAD SELECT custId, SUM(amount)
2. 前回のキーと比較 FROM shipments
3. 変わったら小計出力 GROUP BY custId
4. 最後のレコード後にも小計出力
→ モダナイゼーション時は GROUP BY + Window関数 で置き換え可能
6. マスタメンテナンス
得意先マスタの照会・追加・更新・削除を行う対話型プログラム。
**free
ctl-opt dftactgrp(*no) actgrp(*caller);
dcl-f MSTDSP workstn(*ext) usage(*input:*output);
dcl-f CUSTPF disk(*ext) usage(*update:*delete:*output) keyed;
// 画面ループ
dou *inkc; // F3 で終了
exfmt SELSCR; // 選択画面
if *inkc; leave; endif;
select;
when action = '1'; // 照会
chain custId CUSTPF;
if %found(CUSTPF);
exfmt DTLSCR; // 詳細表示
else;
errMsg = '該当なし';
endif;
when action = '2'; // 追加
chain custId CUSTPF;
if %found(CUSTPF);
errMsg = '既に存在します';
else;
exfmt ADDSCR; // 入力画面
if not *inkc;
exsr writeCust;
endif;
endif;
when action = '3'; // 更新
chain custId CUSTPF;
if %found(CUSTPF);
exfmt UPDSCR; // 更新画面
if not *inkc;
exsr updateCust;
endif;
endif;
when action = '4'; // 削除
chain custId CUSTPF;
if %found(CUSTPF);
exfmt CFMSCR; // 確認画面
if confirm = 'Y';
delete CUSTFMT;
endif;
endif;
endsl;
enddo;
*inlr = *on;
AI解析での注目点
- CRUD操作が
select/whenで分岐 → REST APIの GET/POST/PUT/DELETE に自然に対応 exfmtによる画面遷移 → Angular のルーティング + コンポーネントに変換chain+%found()によるバリデーション → バリデーションサービスに抽出
7. バッチ連携パターン集
パターン1: マッチング処理(2ファイル突合)
// 受注ファイルと出荷ファイルをキー順に突合
read ORDFILE;
read SHPFILE;
dow not %eof(ORDFILE) or not %eof(SHPFILE);
select;
when ordRec.key < shpRec.key or %eof(SHPFILE);
// 受注あり・出荷なし(未出荷)
exsr processUnshipped;
read ORDFILE;
when ordRec.key > shpRec.key or %eof(ORDFILE);
// 出荷あり・受注なし(異常)
exsr processOrphanShip;
read SHPFILE;
when ordRec.key = shpRec.key;
// 一致(正常突合)
exsr processMatch;
read ORDFILE;
read SHPFILE;
endsl;
enddo;
→ モダナイゼーション: SQL の FULL OUTER JOIN + CASE WHEN で置換
パターン2: 集計バッチ(合計・件数・平均)
dcl-s totalAmt packed(13:2) inz(0);
dcl-s totalCnt int(10) inz(0);
read ORDFILE;
dow not %eof(ORDFILE);
totalAmt += ordRec.amount;
totalCnt += 1;
read ORDFILE;
enddo;
avgAmt = totalAmt / totalCnt;
→ モダナイゼーション: SELECT SUM(amount), COUNT(*), AVG(amount) FROM orders
パターン3: 一括更新バッチ
read INVFILE;
dow not %eof(INVFILE);
if invRec.onHand < invRec.safetyStock;
invRec.reorderFlag = 'Y';
update INVFMT invRec;
endif;
read INVFILE;
enddo;
→ モダナイゼーション: UPDATE inventory SET reorder_flag = 'Y' WHERE on_hand < safety_stock
関連記事
- COBOL 業務ロジック実装 — COBOL の対応する業務ロジック実装例
- RPG 文法基礎 — RPG IV の基本文法リファレンス
- RPG モジュール設計 — サブルーチンとモジュール化
- RPG × SQL 連携 — 埋め込み SQL によるデータベースアクセス
- RPG 本番運用 — IBM i での本番運用ガイド