567 lines
24 KiB
Java
567 lines
24 KiB
Java
import java.io.BufferedReader;
|
||
import java.io.FileInputStream;
|
||
import java.io.FileOutputStream;
|
||
import java.io.IOException;
|
||
import java.io.InputStreamReader;
|
||
import java.io.OutputStreamWriter;
|
||
import java.io.PrintWriter;
|
||
import java.io.UncheckedIOException;
|
||
import java.time.LocalDateTime;
|
||
import java.time.format.DateTimeFormatter;
|
||
|
||
import dto.Kin02Rec;
|
||
import dto.Kin03Rec;
|
||
import dto.Kin04Rec;
|
||
import dto.ZanendacPar;
|
||
import dto.ZanmsgacPar;
|
||
import util.ConvUtil;
|
||
|
||
/**
|
||
* ============================================================
|
||
* 【COBOL→Java】KIN05MAT 打刻休暇照合処理
|
||
* ============================================================
|
||
* PROGRAM-ID. KIN05MAT → 类 Kin05MatMain(PGMパターン:マッチング(1:N))
|
||
*
|
||
* 使用文件(SELECT ASSIGN → 路径常量):
|
||
* R01INNFIL(KIN04W01 EDITED-PUNCH F80B) → R01INN_FILE(COPY KIN04REC → dto.Kin04Rec)
|
||
* R02INNFIL(KIN02W01 LEAVE-DAILY F80B) → R02INN_FILE(COPY KIN02REC → dto.Kin02Rec)
|
||
* W01OUTFIL(KIN05W01 KIN-LEAVE F160B)→ W01OUT_FILE(COPY KIN03REC → dto.Kin03Rec)
|
||
* 使用SUB(CALL → 类#execute):
|
||
* SUB02MSG→Sub02MsgSub / SUB03END→Sub03EndSub
|
||
* 段落对应:
|
||
* 0000MAJCOLSOR→run() 1000ITTSOR→initPara() 1100R01INNSOR→readR01Para()
|
||
* 1200R02INNSOR→readR02Para() 2000MAJSOR→majPara() 2020MATCHSOR→matchPara()
|
||
* 2030PRIOSOR→prioSor() 2100R01ONLYSOR→r01OnlyPara() 2200R02ONLYSOR→r02OnlyPara()
|
||
* 3000STPSOR→termPara() 4000MSGOUTSOR→msgOutPara() 9999ABDSOR→abendPara()
|
||
*
|
||
* 与原代码的差异(详见 doc\conv\KIN05MAT_对照表.md 疑问·回答记录):
|
||
* #Q1 照合キー(EMP-ID+DATE)はグループ項目のバイト比較と等価なため、文字列連結で比較。
|
||
* #Q2 優先順位選定(2030PRIOSOR)は COBOL の EVALUATE TRUE を if/else で忠実に再現。
|
||
* #Q3 COBOL は WRK-BEST-* を 2020MATCHSOR と 1000ITTSOR のみ初期化し、
|
||
* R01単独出力(2100R01ONLYSOR)ではリセットしないため、前件マッチの休暇情報が
|
||
* 継続する不具合がある(設計書 2-1/3-5「R01単独→LEAVE-TYPE='99'」と矛盾)。
|
||
* ⇒ Java は【設計書準拠】とし、每条 R01 処理前(majPara先頭)に WRK-BEST-* を
|
||
* '99'/0 に初期化する(resetBest())。COBOL の不整合は本ファイル内コメントで指摘。
|
||
* #Q4 FUNCTION WHEN-COMPILED → 程序启动时刻代替。
|
||
*/
|
||
public class Kin05MatMain {
|
||
|
||
// ==================== コンスタント領域 CNSARA ====================
|
||
|
||
/** 03 CNS-PRGIDX PIC X(008) VALUE 'KIN05MAT'. */
|
||
private static final String CST_PRGIDX = "KIN05MAT";
|
||
/** 03 CNS-MSGSTR PIC 9(003) VALUE 001. 開始メッセージ */
|
||
private static final int CST_MSGSTR = 1;
|
||
/** 03 CNS-MSGFIN PIC 9(003) VALUE 002. 終了メッセージ */
|
||
private static final int CST_MSGFIN = 2;
|
||
/** 03 CNS-MSGIINKES PIC 9(003) VALUE 006. 入力件数 */
|
||
private static final int CST_MSGIINKES = 6;
|
||
/** 03 CNS-MSGOUTKES PIC 9(003) VALUE 007. 出力件数 */
|
||
private static final int CST_MSGOUTKES = 7;
|
||
/** 03 CNS-MSGKEYINF PIC 9(003) VALUE 033. コンパイル日時 */
|
||
private static final int CST_MSGKEYINF = 33;
|
||
/** 03 CNS-KN0002 PIC 9(001) VALUE 2. */
|
||
private static final int CST_KN0002 = 2;
|
||
/** 03 CNS-ABD999 PIC 9(003) VALUE 999. */
|
||
private static final int CST_ABD999 = 999;
|
||
/** 03 CNS-NO-LEAVE PIC X(002) VALUE '99'. 休暇なし */
|
||
private static final String CST_NO_LEAVE = "99";
|
||
/** 03 CNS-LEAVE-01 PIC X(002) VALUE '01'. */
|
||
private static final String CST_LEAVE_01 = "01";
|
||
/** 03 CNS-LEAVE-02 PIC X(002) VALUE '02'. */
|
||
private static final String CST_LEAVE_02 = "02";
|
||
/** 03 CNS-LEAVE-03 PIC X(002) VALUE '03'. */
|
||
private static final String CST_LEAVE_03 = "03";
|
||
/** 03 CNS-LEAVE-04 PIC X(002) VALUE '04'. */
|
||
private static final String CST_LEAVE_04 = "04";
|
||
|
||
// ==================== ファイル定義(SELECT ASSIGN 相当) ====================
|
||
|
||
/** SELECT R01INNFIL ASSIGN TO KIN04W01.(EDITED-PUNCH入力) */
|
||
private static final String R01INN_FILE = "data/KIN04W01.dat";
|
||
/** SELECT R02INNFIL ASSIGN TO KIN02W01.(LEAVE-DAILY入力) */
|
||
private static final String R02INN_FILE = "data/KIN02W01.dat";
|
||
/** SELECT W01OUTFIL ASSIGN TO KIN05W01.(KIN-LEAVE出力) */
|
||
private static final String W01OUT_FILE = "data/KIN05W01.dat";
|
||
|
||
// ==================== カウンタ領域 CUNARA(COMP-3 → long) ====================
|
||
|
||
/** 03 CUN-R01INN PIC S9(009) COMP-3 VALUE ZERO. */
|
||
private long cunR01Inn;
|
||
/** 03 CUN-R02INN PIC S9(009) COMP-3 VALUE ZERO. */
|
||
private long cunR02Inn;
|
||
/** 03 CUN-W01OUT PIC S9(009) COMP-3 VALUE ZERO. */
|
||
private long cunW01Out;
|
||
|
||
// ==================== 作業領域 WRKARA ====================
|
||
|
||
/** 03 WS-R01-STATUS PIC X(002).(OPENチェック用、Javaは例外で代替) */
|
||
private String wsR01Status = "00";
|
||
/** 03 WS-R02-STATUS PIC X(002). */
|
||
private String wsR02Status = "00";
|
||
/** 03 WS-W01-STATUS PIC X(002). */
|
||
private String wsW01Status = "00";
|
||
/** 03 WRK-R01EOF PIC X(001). 読込フラグ */
|
||
private String wrkR01Eof = "0";
|
||
/** 03 WRK-R02EOF PIC X(001). 読込フラグ */
|
||
private String wrkR02Eof = "0";
|
||
/** 03 WRK-R01KEY(EMP-ID 8 + DATE 8) */
|
||
private String wrkR01Key = "";
|
||
/** 03 WRK-R02KEY(EMP-ID 8 + DATE 8) */
|
||
private String wrkR02Key = "";
|
||
/** 03 WRK-BEST-TYPE PIC X(002). 選定休暇種別 */
|
||
private String wrkBestType = CST_NO_LEAVE;
|
||
/** 03 WRK-BEST-STR-TIME PIC 9(004). */
|
||
private int wrkBestStrTime;
|
||
/** 03 WRK-BEST-END-TIME PIC 9(004). */
|
||
private int wrkBestEndTime;
|
||
/** 03 WRK-BEST-APPL-ID PIC 9(009). */
|
||
private int wrkBestApplId;
|
||
/** 03 WRK-BEST-FOUND PIC X(001). 選定済フラグ */
|
||
private String wrkBestFound = "0";
|
||
|
||
/** 88 WRK-BEST-IS-FOUND VALUE '1'. */
|
||
private boolean isBestFound() {
|
||
return "1".equals(wrkBestFound);
|
||
}
|
||
|
||
// ==================== サブプログラム連絡領域(LINKAGE COPY → DTO) ====================
|
||
|
||
/** COPY ZANMSGAC.(SUB02MSG用) */
|
||
private final ZanmsgacPar m00MhoPar = new ZanmsgacPar();
|
||
/** COPY ZANENDAC.(SUB03END用) */
|
||
private final ZanendacPar e01AbdPar = new ZanendacPar();
|
||
|
||
// ==================== 入出力レコード(FILE SECTION → DTO) ====================
|
||
|
||
/** FD R01INNFIL の 01 R01INNREC.(現在レコードバッファ) */
|
||
private final Kin04Rec r01 = new Kin04Rec();
|
||
/** FD R02INNFIL の 01 R02OUTREC.(現在レコードバッファ) */
|
||
private final Kin02Rec r02 = new Kin02Rec();
|
||
/** FD W01OUTFIL の 01 W01OUTREC. */
|
||
private final Kin03Rec w01 = new Kin03Rec();
|
||
|
||
// ==================== ファイルハンドル(OPEN/CLOSE 相当) ====================
|
||
|
||
private BufferedReader r01InnFil;
|
||
private BufferedReader r02InnFil;
|
||
private PrintWriter w01OutFil;
|
||
|
||
/** 入力ファイルパス(R01/R02/W01)。引数で上書き可。 */
|
||
private final String r01InnFile;
|
||
private final String r02InnFile;
|
||
private final String w01OutFile;
|
||
|
||
// ==================== PROCEDURE DIVISION ====================
|
||
|
||
public static void main(String[] args) {
|
||
final String r1 = (args != null && args.length > 0) ? args[0] : R01INN_FILE;
|
||
final String r2 = (args != null && args.length > 1) ? args[1] : R02INN_FILE;
|
||
final String w1 = (args != null && args.length > 2) ? args[2] : W01OUT_FILE;
|
||
new Kin05MatMain(r1, r2, w1).run(); // PERFORM 0000MAJCOLSOR 相当
|
||
}
|
||
|
||
/** 引数付コンストラクタ:各ファイルパスを指定(テスト等で使用)。 */
|
||
public Kin05MatMain(final String r01InnFile, final String r02InnFile, final String w01OutFile) {
|
||
this.r01InnFile = r01InnFile;
|
||
this.r02InnFile = r02InnFile;
|
||
this.w01OutFile = w01OutFile;
|
||
}
|
||
|
||
/**
|
||
* 段落 0000MAJCOLSOR:制御処理。
|
||
* PERFORM 1000ITTSOR → PERFORM 2000MAJSOR UNTIL R01-EOF → PERFORM 3000STPSOR → GOBACK.
|
||
*/
|
||
private void run() {
|
||
try {
|
||
initPara();
|
||
while (!"1".equals(wrkR01Eof)) { // PERFORM 2000MAJSOR UNTIL WRK-R01-EOF
|
||
majPara();
|
||
}
|
||
termPara();
|
||
} finally {
|
||
closeFiles();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 段落 1000ITTSOR:初期処理。
|
||
* 開始メッセージ→コンパイル日時→BEST領域初期化→OPEN→OPENチェック→初回読込。
|
||
*/
|
||
private void initPara() {
|
||
// *** 開始メッセージ出力
|
||
msgOutPara(CST_MSGSTR, null, null);
|
||
|
||
// *** コンパイル日時出力 ※疑问#Q4:WHEN-COMPILED→启动时刻代替
|
||
String compiled = LocalDateTime.now()
|
||
.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
||
msgOutPara(CST_MSGKEYINF, compiled, "COMPILED");
|
||
|
||
// *** ワークエリア初期化 INITIALIZE WRKARA.
|
||
wrkR01Eof = "0";
|
||
wrkR02Eof = "0";
|
||
wrkR01Key = "";
|
||
wrkR02Key = "";
|
||
// *** BEST領域初期化(R01のみ出力時に使用)
|
||
wrkBestFound = "0"; // MOVE '0' TO WRK-BEST-FOUND.
|
||
wrkBestType = CST_NO_LEAVE; // MOVE CNS-NO-LEAVE TO WRK-BEST-TYPE.
|
||
wrkBestStrTime = 0; // MOVE ZERO TO WRK-BEST-STR-TIME.
|
||
wrkBestEndTime = 0; // MOVE ZERO TO WRK-BEST-END-TIME.
|
||
wrkBestApplId = 0; // MOVE ZERO TO WRK-BEST-APPL-ID.
|
||
|
||
// *** 入出力ファイル OPEN INPUT R01/R02 / OUTPUT W01.
|
||
openFiles();
|
||
|
||
// *** OPENチェック(STATUS≠'00' → ABEND 999)
|
||
if (!"00".equals(wsR01Status) || !"00".equals(wsR02Status) || !"00".equals(wsW01Status)) {
|
||
abendPara();
|
||
}
|
||
|
||
// *** R01/R02を読み込み
|
||
readR01Para();
|
||
readR02Para();
|
||
}
|
||
|
||
/**
|
||
* 段落 1100R01INNSOR:##R01##読込処理。
|
||
* READ AT END / NOT AT END のマッピング。
|
||
*/
|
||
private void readR01Para() {
|
||
try {
|
||
String line = r01InnFil.readLine();
|
||
if (line == null) {
|
||
wrkR01Eof = "1"; // AT END: MOVE '1' TO WRK-R01EOF.
|
||
} else {
|
||
r01.fromRecordLine(line); // FD R01INNREC への転送.
|
||
cunR01Inn++; // ADD 1 TO CUN-R01INN.
|
||
}
|
||
} catch (IOException e) {
|
||
throw new UncheckedIOException(e); // READ異常 ≈ ABEND
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 段落 1200R02INNSOR:##R02##読込処理。
|
||
* READ AT END / NOT AT END のマッピング. AT END→EOF、NOT AT END→件数++.
|
||
*/
|
||
private void readR02Para() {
|
||
try {
|
||
String line = r02InnFil.readLine();
|
||
if (line == null) {
|
||
wrkR02Eof = "1"; // AT END: MOVE '1' TO WRK-R02EOF.
|
||
} else {
|
||
r02.fromRecordLine(line); // FD R02OUTREC への転送.
|
||
cunR02Inn++; // ADD 1 TO CUN-R02INN.
|
||
}
|
||
} catch (IOException e) {
|
||
throw new UncheckedIOException(e); // READ異常 ≈ ABEND
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 段落 2000MAJSOR:主処理(マッチング制御)。
|
||
* R01キー設定→R02キー設定(有効時)→EVALUATE TRUE で3分岐。
|
||
*/
|
||
private void majPara() {
|
||
// *** 設計書準拠:每条打刻(R01)は独立に判定。COBOL(KIN05MAT.cbl)は
|
||
// WRK-BEST-* を 2020MATCHSOR と 1000ITTSOR のみ初期化し、
|
||
// R01単独出力(2100R01ONLYSOR)ではリセットしないため、前件マッチの
|
||
// 休暇情報が継続する不具合がある。Java は設計書意図(='99')どおり、
|
||
// 每条 R01 処理前に WRK-BEST-* を初期化する。
|
||
resetBest();
|
||
|
||
// *** R01キー設定
|
||
setR01Key();
|
||
// *** R02キー設定(有効な場合)
|
||
if (!"1".equals(wrkR02Eof)) {
|
||
setR02Key();
|
||
}
|
||
|
||
// *** EVALUATE TRUE マッチング3分岐(COBOL の WHEN 順序を if/else で再現)
|
||
if ("1".equals(wrkR02Eof)) {
|
||
// WHEN WRK-R02-EOF → R01のみ出力+R01次読込
|
||
r01OnlyPara();
|
||
readR01Para();
|
||
} else if (wrkR01Key.compareTo(wrkR02Key) < 0) {
|
||
// WHEN WRK-R01KEY < WRK-R02KEY → R01のみ出力+R01次読込
|
||
r01OnlyPara();
|
||
readR01Para();
|
||
} else if (wrkR01Key.compareTo(wrkR02Key) == 0) {
|
||
// WHEN WRK-R01KEY = WRK-R02KEY → マッチング処理+R01次読込
|
||
matchPara();
|
||
readR01Para();
|
||
} else {
|
||
// WHEN WRK-R01KEY > WRK-R02KEY → R02のみスキップ+R02次読込
|
||
r02OnlyPara();
|
||
readR02Para();
|
||
}
|
||
}
|
||
|
||
/** WRK-R01KEY = R01EMP-ID(8) + R01WORK-DATE(8)(グループ比較と等価)。 */
|
||
private void setR01Key() {
|
||
wrkR01Key = r01.getEmpId() + r01.getWorkDate();
|
||
}
|
||
|
||
/** WRK-R02KEY = R02EMP-ID(8) + R02DATE(8)(グループ比較と等価)。 */
|
||
private void setR02Key() {
|
||
wrkR02Key = r02.getEmpId() + ConvUtil.padLeftZero(r02.getDate(), 8);
|
||
}
|
||
|
||
/**
|
||
* WRK-BEST-* 初期化('99'/0)。
|
||
* 設計書(KIN05MAT)準拠:每条打刻(R01)の処理前に実施し、前件マッチの
|
||
* 休暇情報が継続しないよう保証する。COBOL は本初期化を 2020MATCHSOR と
|
||
* 1000ITTSOR のみに記述し R01単独出力で漏れたため、無休假打刻に前件の
|
||
* 休暇種別が残る不具合がある(#Q3)。
|
||
*/
|
||
private void resetBest() {
|
||
wrkBestFound = "0"; // MOVE '0' TO WRK-BEST-FOUND.
|
||
wrkBestType = CST_NO_LEAVE; // MOVE CNS-NO-LEAVE TO WRK-BEST-TYPE.
|
||
wrkBestStrTime = 0; // MOVE ZERO TO WRK-BEST-STR-TIME.
|
||
wrkBestEndTime = 0; // MOVE ZERO TO WRK-BEST-END-TIME.
|
||
wrkBestApplId = 0; // MOVE ZERO TO WRK-BEST-APPL-ID.
|
||
}
|
||
|
||
/**
|
||
* 段落 2020MATCHSOR:マッチング処理(N:1ループレ)。
|
||
* 一致キーの全R02を読込み、最適休暇を選定した上で KIN-LEAVE 出力。
|
||
* ※ majPara() 先頭の resetBest() で既に '99'/0 初期化済だが、COBOL 互換の
|
||
* 位置でも再初期化(冪等)。設計書準拠の挙動は majPara() 側で保証される。
|
||
*/
|
||
private void matchPara() {
|
||
// *** 選定領域初期化(majPara() での初期化と同一内容)
|
||
resetBest();
|
||
|
||
// *** N:1ループ 一致するR02を全件処理
|
||
while (true) {
|
||
if ("1".equals(wrkR02Eof)) {
|
||
break; // WRK-R02-EOF
|
||
}
|
||
if (!wrkR01Key.equals(wrkR02Key)) {
|
||
break; // WRK-R01KEY < WRK-R02KEY OR WRK-R01KEY > WRK-R02KEY
|
||
}
|
||
// *** ベスト選定
|
||
if (!isBestFound()) {
|
||
// 初回 → ベストとして保持
|
||
wrkBestFound = "1"; // MOVE '1' TO WRK-BEST-FOUND.
|
||
wrkBestType = r02.getLeaveType();
|
||
wrkBestStrTime = r02.getStartTime();
|
||
wrkBestEndTime = r02.getEndTime();
|
||
wrkBestApplId = r02.getApplId();
|
||
} else {
|
||
prioSor(r02.getLeaveType(), r02.getStartTime(),
|
||
r02.getEndTime(), r02.getApplId());
|
||
}
|
||
// *** R02次読込
|
||
readR02Para();
|
||
// *** R02キー再設定(有効な場合)
|
||
if (!"1".equals(wrkR02Eof)) {
|
||
setR02Key();
|
||
}
|
||
}
|
||
|
||
// *** KIN-LEAVE出力(R01のみ出力サブルーチンを共用)
|
||
r01OnlyPara();
|
||
}
|
||
|
||
/**
|
||
* 段落 2030PRIOSOR:優先順位判定。
|
||
* 優先順位 01 > 02 > 03 > 04。同種別は APPL-ID の小さい方を採用。
|
||
* COBOL の EVALUATE TRUE を if/else で忠実に再現(WHEN OTHER→CONTINUE)。
|
||
*/
|
||
private void prioSor(final String r02Type, final int r02Str,
|
||
final int r02End, final int r02Appl) {
|
||
// EVALUATE TRUE(R02LEAVE-TYPE で分岐)
|
||
if (CST_LEAVE_01.equals(r02Type)) {
|
||
if (!CST_LEAVE_01.equals(wrkBestType)) {
|
||
wrkBestType = r02Type;
|
||
wrkBestStrTime = r02Str;
|
||
wrkBestEndTime = r02End;
|
||
wrkBestApplId = r02Appl;
|
||
} else if (r02Appl < wrkBestApplId) {
|
||
wrkBestStrTime = r02Str;
|
||
wrkBestEndTime = r02End;
|
||
wrkBestApplId = r02Appl;
|
||
}
|
||
} else if (CST_LEAVE_02.equals(r02Type)) {
|
||
if (CST_LEAVE_01.equals(wrkBestType)) {
|
||
// CONTINUE(01 が優先)
|
||
} else if (CST_LEAVE_02.equals(wrkBestType)) {
|
||
if (r02Appl < wrkBestApplId) {
|
||
wrkBestStrTime = r02Str;
|
||
wrkBestEndTime = r02End;
|
||
wrkBestApplId = r02Appl;
|
||
}
|
||
} else {
|
||
wrkBestType = r02Type;
|
||
wrkBestStrTime = r02Str;
|
||
wrkBestEndTime = r02End;
|
||
wrkBestApplId = r02Appl;
|
||
}
|
||
} else if (CST_LEAVE_03.equals(r02Type)) {
|
||
if (CST_LEAVE_01.equals(wrkBestType)) {
|
||
// CONTINUE
|
||
} else if (CST_LEAVE_02.equals(wrkBestType)) {
|
||
// CONTINUE
|
||
} else if (CST_LEAVE_03.equals(wrkBestType)) {
|
||
if (r02Appl < wrkBestApplId) {
|
||
wrkBestStrTime = r02Str;
|
||
wrkBestEndTime = r02End;
|
||
wrkBestApplId = r02Appl;
|
||
}
|
||
} else {
|
||
wrkBestType = r02Type;
|
||
wrkBestStrTime = r02Str;
|
||
wrkBestEndTime = r02End;
|
||
wrkBestApplId = r02Appl;
|
||
}
|
||
} else if (CST_LEAVE_04.equals(r02Type)) {
|
||
if (CST_LEAVE_01.equals(wrkBestType)) {
|
||
// CONTINUE
|
||
} else if (CST_LEAVE_02.equals(wrkBestType)) {
|
||
// CONTINUE
|
||
} else if (CST_LEAVE_03.equals(wrkBestType)) {
|
||
// CONTINUE
|
||
} else if (CST_LEAVE_04.equals(wrkBestType)) {
|
||
if (r02Appl < wrkBestApplId) {
|
||
wrkBestStrTime = r02Str;
|
||
wrkBestEndTime = r02End;
|
||
wrkBestApplId = r02Appl;
|
||
}
|
||
} else {
|
||
wrkBestType = r02Type;
|
||
wrkBestStrTime = r02Str;
|
||
wrkBestEndTime = r02End;
|
||
wrkBestApplId = r02Appl;
|
||
}
|
||
} else {
|
||
// WHEN OTHER → CONTINUE(未知種別は無視)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 段落 2100R01ONLYSOR:R01のみ出力(またはマッチ結果出力)。
|
||
* 打刻情報(1-80B)+休暇情報(81-160B、WRK-BEST-* を使用)を KIN-LEAVE に出力。
|
||
*/
|
||
private void r01OnlyPara() {
|
||
// *** KIN-LEAVEレコード編集
|
||
w01.reset(); // INITIALIZE W01OUTREC.
|
||
// *** 打刻情報(1-80B)
|
||
w01.setEmpId(r01.getEmpId()); // MOVE R01EMP-ID TO W01EMP-ID.
|
||
w01.setWorkDate(r01.getWorkDate()); // MOVE R01WORK-DATE TO W01WORK-DATE.
|
||
w01.setStrTime(r01.getStrTime()); // MOVE R01STR-TIME TO W01STR-TIME.
|
||
w01.setEndTime(r01.getEndTime()); // MOVE R01END-TIME TO W01END-TIME.
|
||
w01.setDeptId(r01.getDeptId()); // MOVE R01DEPT-ID TO W01DEPT-ID.
|
||
w01.setTerminal(r01.getTerminal()); // MOVE R01TERMINAL TO W01TERMINAL.
|
||
// *** 休暇情報(81-160B)
|
||
w01.setLeaveType(wrkBestType); // MOVE WRK-BEST-TYPE TO W01LEAVE-TYPE.
|
||
w01.setLeaveStrTime(wrkBestStrTime); // MOVE WRK-BEST-STR-TIME TO W01LEAVE-STR-TIME.
|
||
w01.setLeaveEndTime(wrkBestEndTime); // MOVE WRK-BEST-END-TIME TO W01LEAVE-END-TIME.
|
||
w01.setLeaveHours(0); // MOVE ZERO TO W01LEAVE-HOURS.
|
||
w01.setApplicationId(wrkBestApplId); // MOVE WRK-BEST-APPL-ID TO W01APPLICATION-ID.
|
||
|
||
writeW01(); // WRITE W01OUTREC./ADD 1 TO CUN-W01OUT.
|
||
}
|
||
|
||
/**
|
||
* 段落 2200R02ONLYSOR:R02のみスキップ(該当打刻のない休暇レコードは出力しない)。
|
||
*/
|
||
private void r02OnlyPara() {
|
||
// PERFORM 1200R02INNSOR は呼出元(majPara)で実施済(CONTINUE)。
|
||
}
|
||
|
||
/**
|
||
* 段落 3000STPSOR:終了処理。
|
||
* CLOSE→入出力件数メッセージ×3→終了メッセージ。
|
||
*/
|
||
private void termPara() {
|
||
// *** 入出力ファイル CLOSE
|
||
closeFiles();
|
||
|
||
// *** 入出力ファイル件数出力(数値→X(30)転送は9桁ゼロ埋め表示形)
|
||
msgOutPara(CST_MSGIINKES, "KIN04W01", ConvUtil.padLeftZero(cunR01Inn, 9));
|
||
msgOutPara(CST_MSGIINKES, "KIN02W01", ConvUtil.padLeftZero(cunR02Inn, 9));
|
||
msgOutPara(CST_MSGOUTKES, "KIN05W01", ConvUtil.padLeftZero(cunW01Out, 9));
|
||
|
||
// *** 終了メッセージ出力
|
||
msgOutPara(CST_MSGFIN, null, null);
|
||
}
|
||
|
||
/**
|
||
* 段落 4000MSGOUTSOR:メッセージ編集出力処理。
|
||
* M00UMKDATS22-03(1:1)/-04(1:1) に '2'、-05 にプログラムIDを設定し SUB02MSG を呼ぶ。
|
||
*/
|
||
private void msgOutPara(final int msgCod, final String p1, final String p2) {
|
||
m00MhoPar.reset(); // INITIALIZE M00MHOPAR.
|
||
m00MhoPar.setM00MsgCod(msgCod); // MOVE ... TO M00MSGCOD.
|
||
if (p1 != null) {
|
||
m00MhoPar.setM00Umkdats2201(p1); // MOVE ... TO M00UMKDATS22-01.
|
||
}
|
||
if (p2 != null) {
|
||
m00MhoPar.setM00Umkdats2202(p2); // MOVE ... TO M00UMKDATS22-02.
|
||
}
|
||
// MOVE CNS-KN0002 TO M00UMKDATS22-03(1:1).(参照修改→先頭1桁上書き、残り29桁はSPACE)
|
||
m00MhoPar.setM00Umkdats2203(ConvUtil.padRight(Integer.toString(CST_KN0002), 30));
|
||
m00MhoPar.setM00Umkdats2204(ConvUtil.padRight(Integer.toString(CST_KN0002), 30));
|
||
m00MhoPar.setM00Umkdats2205(CST_PRGIDX); // MOVE CNS-PRGIDX TO ...-05.
|
||
Sub02MsgSub.execute(m00MhoPar); // CALL 'SUB02MSG' USING M00MHOPAR.
|
||
}
|
||
|
||
/**
|
||
* 段落 9999ABDSOR:ABEND処理。
|
||
* MOVE 999 TO E01ABDCOD./CALL 'SUB03END' USING E01ABDPAR.
|
||
*/
|
||
private void abendPara() {
|
||
e01AbdPar.reset();
|
||
e01AbdPar.setE01AbdCod(CST_ABD999); // MOVE CNS-ABD999 TO E01ABDCOD.
|
||
Sub03EndSub.execute(e01AbdPar); // CALL 'SUB03END'.
|
||
}
|
||
|
||
// ==================== ファイル操作補助(OPEN/CLOSE/WRITE 相当) ====================
|
||
|
||
/** OPEN INPUT R01INNFIL/R02INNFIL / OUTPUT W01OUTFIL(失敗時は STATUS='99'→ABEND)。 */
|
||
private void openFiles() {
|
||
try {
|
||
r01InnFil = new BufferedReader(
|
||
new InputStreamReader(new FileInputStream(r01InnFile), "UTF-8"));
|
||
r02InnFil = new BufferedReader(
|
||
new InputStreamReader(new FileInputStream(r02InnFile), "UTF-8"));
|
||
w01OutFil = new PrintWriter(
|
||
new OutputStreamWriter(new FileOutputStream(w01OutFile), "UTF-8"));
|
||
} catch (IOException e) {
|
||
// OPEN失敗相当:FILE STATUS ≠ '00'(後続の OPENチェックで ABEND 999)
|
||
wsR01Status = "99";
|
||
wsR02Status = "99";
|
||
wsW01Status = "99";
|
||
}
|
||
}
|
||
|
||
/** WRITE W01OUTREC./ADD 1 TO CUN-W01OUT. */
|
||
private void writeW01() {
|
||
w01OutFil.println(w01.toRecordLine());
|
||
cunW01Out++;
|
||
}
|
||
|
||
/** CLOSE R01INNFIL R02INNFIL W01OUTFIL. */
|
||
private void closeFiles() {
|
||
closeQuiet(r01InnFil);
|
||
closeQuiet(r02InnFil);
|
||
closeQuiet(w01OutFil);
|
||
r01InnFil = null;
|
||
r02InnFil = null;
|
||
w01OutFil = null;
|
||
}
|
||
|
||
private static void closeQuiet(final Object handle) {
|
||
try {
|
||
if (handle instanceof BufferedReader) {
|
||
((BufferedReader) handle).close();
|
||
} else if (handle instanceof PrintWriter) {
|
||
((PrintWriter) handle).close();
|
||
}
|
||
} catch (IOException e) {
|
||
// CLOSE異常は無視(原程序もFILE STATUS未管理)
|
||
}
|
||
}
|
||
}
|