# 勤怠休暇管理システム 設計書(サブシステムA) ## 概要 休暇申請データと打刻データを処理し、日別勤怠記録(DAILY_RECORDS)および月次統計(MONTHLY_ABSENCE)を生成する。 9本のCOBOLプログラムで構成される。 拠点間SORTやCSV変換などはCOBOLではなくJCL SORTで処理する方針とし、COBOLプログラムは純粋なビジネスロジックに専念する。 ### 設計方針(カバレッジ拡大) 本設計は、サブシステムBで未カバーのプログラムタイプ・ステートメントを積極的にカバーするため、以下の方針でプログラム分割・構文選定を行う。 | 項目 | Bの状況 | Aで狙う追加カバレッジ | |------|---------|---------------------| | プログラムタイプ | 6パターン◎ | 未カバー5パターン + **SYSIN(P28)** を追加 | | ステートメント | 主要構文は網羅済 | SEARCH非ALL, DELETE, EVALUATE(4分岐), PERFORM THRU, WRITE FROM, WRITE AFTER ADVANCING, **MULTIPLY, SUBTRACT, ACCEPT, DISPLAY, INSPECT** | | DB操作 | INSERT/UPDATE/SELECT/COMMIT/ROLLBACK | 上記に加え **DELETE FROM** を追加 | --- ## システム定数 全てのプログラムで共通の前提値。COBOLのCNS-定数として保持する(DBは持たない)。 | 定数 | 値 | 説明 | |------|-----|------| | WORK-START | 0900 | 所定労働開始時刻 | | WORK-END | 1800 | 所定労働終了時刻 | | LUNCH-START | 1200 | ランチ開始時刻 | | LUNCH-END | 1300 | ランチ終了時刻 | | DAILY-HOURS | 8.0 | 1日の所定労働時間(9h実働 − 1hランチ) | --- ## 休暇種別 | コード | 名称 | 給与への影響 | 備考 | |--------|------|------------|------| | 01 | 年休(年假) | 控除なし | 有給年次休暇 | | 02 | 事假(事假) | 全額控除 | 私事欠勤 | | 03 | 因公特批假(因公特批假) | 控除なし | 公務特認欠勤 | | 04 | 病欠(病欠) | 一部控除 | 控除率はSICK_LEAVE_RATEテーブル参照 | **休暇種別は上記4種で固定。勤怠ルールはこの4種を基準とする。** --- ## DBテーブル一覧 全テーブルはDB2で管理する。COBOLからは埋め込みSQL(`EXEC SQL`)で直接アクセスする。 ### 1. EMP_MASTER(社員マスタ) 全社員の基本情報を保持する。サブシステムAでは参照のみ。 | No | カラム名 | 型 | 長さ | NULL | PK | 備考 | |----|---------|---|------|------|----|------| | 1 | EMP_ID | CHAR | 8 | NOT NULL | ✓ | 社員番号 | | 2 | DEPT_ID | CHAR | 4 | NOT NULL | — | 部署ID | | 3 | EMP_NAME | VARCHAR | 50 | NOT NULL | — | 氏名 | | 4 | STATUS | CHAR | 1 | NOT NULL | — | '1'=在籍, '9'=退職 | ### 2. ABSENCE_SUMMARY(欠勤集計中間ファイル) サブシステムA→Cの連携用。KIN08DBUが月次集計後に出力する。 | No | カラム名 | 型 | 長さ | NULL | PK | 備考 | |----|---------|---|------|------|----|------| | 1 | EMP_ID | CHAR | 8 | NOT NULL | ✓ | 社員番号 | | 2 | YEAR_MONTH | CHAR | 6 | NOT NULL | ✓ | YYYYMM | | 3 | ANNUAL_LEAVE_H | DECIMAL | 6,1 | NOT NULL | — | 年休使用合計 | | 4 | PERSONAL_LEAVE_H | DECIMAL | 6,1 | NOT NULL | — | 事假合計 | | 5 | OFFICIAL_LEAVE_H | DECIMAL | 6,1 | NOT NULL | — | 因公特批假合計 | | 6 | SICK_LEAVE_H | DECIMAL | 6,1 | NOT NULL | — | 病欠合計 | | 7 | UNAPPROVED_ABSENT_H | DECIMAL | 6,1 | NOT NULL | — | 未申請欠勤合計 | ### 3. HOLIDAY_CALENDAR(休日カレンダー) 祝日(曜日判定で休日にならない日)のみを列挙する。 土曜・日曜は曜日判定で休日とするため、このテーブルには含めない。 | No | カラム名 | 型 | 長さ | NULL | PK | 備考 | |----|---------|---|------|------|----|------| | 1 | HOLIDAY_DATE | CHAR | 8 | NOT NULL | ✓ | YYYYMMDD | | 2 | DESCRIPTION | VARCHAR | 50 | OK | — | 任意(例:「建国記念の日」) | **出勤日判定ロジック(全PGM共通):** ``` 1. HOLIDAY_CALENDARに日付が存在する → 休日 2. 曜日が土曜(6)または日曜(INTEGER-OF-DATE MOD 7 = 0) → 休日 3. 上記以外 → 出勤日(WORK-START=0900, WORK-END=1800) ``` ### 4. SICK_LEAVE_RATE(病欠控除率) 全社員共通の病欠控除率を保持する。 | No | カラム名 | 型 | 長さ | NULL | PK | 備考 | |----|---------|---|------|------|----|------| | 1 | LEAVE_TYPE | CHAR | 2 | NOT NULL | ✓ | '04'固定 | | 2 | DEDUCTION_RATE | DECIMAL | 3,2 | NOT NULL | — | 例:0.50(50%控除) | ### 5. LEAVE_RECORDS(休暇申請記録) 休暇申請の生データを保持する。取消は**DELETE FROM**で行い、レコードを物理削除する。 期間は開始日〜終了日で表現され、日別展開は行わない。 | No | カラム名 | 型 | 長さ | NULL | PK | 備考 | |----|---------|---|------|------|----|------| | 1 | APPLICATION_ID | INTEGER | — | NOT NULL | ✓ | 自動採番 | | 2 | EMP_ID | CHAR | 8 | NOT NULL | — | 社員番号 | | 3 | LEAVE_TYPE | CHAR | 2 | NOT NULL | — | '01'〜'04' | | 4 | START_DATE | CHAR | 8 | NOT NULL | — | YYYYMMDD(出勤日) | | 5 | START_TIME | CHAR | 4 | NOT NULL | — | HHMM(所定労働時間内) | | 6 | END_DATE | CHAR | 8 | NOT NULL | — | YYYYMMDD(出勤日) | | 7 | END_TIME | CHAR | 4 | NOT NULL | — | HHMM(所定労働時間内) | | 8 | STATUS | CHAR | 1 | NOT NULL | — | '1'=有効, '9'=取消 | ### 6. DAILY_RECORDS(日別勤怠記録) 1社員1日の勤怠情報。出勤日のみレコードが存在する。 打刻がない日でも休暇または未申請欠勤の情報を持つ。 | No | カラム名 | 型 | 長さ | NULL | PK | 備考 | |----|---------|---|------|------|----|------| | 1 | EMP_ID | CHAR | 8 | NOT NULL | ✓ | | | 2 | TARGET_DATE | CHAR | 8 | NOT NULL | ✓ | YYYYMMDD | | 3 | TIME_IN | CHAR | 4 | NOT NULL | — | 出勤時刻、'0000'=打刻なし | | 4 | TIME_OUT | CHAR | 4 | NOT NULL | — | 退勤時刻、'0000'=打刻なし | | 5 | ANNUAL_LEAVE_H | DECIMAL | 6,1 | NOT NULL | — | 年休使用時間 | | 6 | PERSONAL_LEAVE_H | DECIMAL | 6,1 | NOT NULL | — | 事假時間 | | 7 | OFFICIAL_LEAVE_H | DECIMAL | 6,1 | NOT NULL | — | 因公特批假時間 | | 8 | SICK_LEAVE_H | DECIMAL | 6,1 | NOT NULL | — | 病欠時間 | | 9 | UNAPPROVED_ABSENT_H | DECIMAL | 6,1 | NOT NULL | — | 未申請欠勤時間 | | 10 | UPDATED_AT | TIMESTAMP | — | NOT NULL | — | DEFAULT CURRENT_TIMESTAMP | ### 7. MONTHLY_ABSENCE(月次統計) DAILY_RECORDSを月次で集計したサマリ。 | No | カラム名 | 型 | 長さ | NULL | PK | 備考 | |----|---------|---|------|------|----|------| | 1 | EMP_ID | CHAR | 8 | NOT NULL | ✓ | | | 2 | YEAR_MONTH | CHAR | 6 | NOT NULL | ✓ | YYYYMM | | 3 | ANNUAL_LEAVE_H | DECIMAL | 6,1 | NOT NULL | — | 年休使用合計 | | 4 | PERSONAL_LEAVE_H | DECIMAL | 6,1 | NOT NULL | — | 事假合計 | | 5 | OFFICIAL_LEAVE_H | DECIMAL | 6,1 | NOT NULL | — | 因公特批假合計 | | 6 | SICK_LEAVE_H | DECIMAL | 6,1 | NOT NULL | — | 病欠合計 | | 7 | UNAPPROVED_ABSENT_H | DECIMAL | 6,1 | NOT NULL | — | 未申請欠勤合計 | | 8 | UPDATED_AT | TIMESTAMP | — | NOT NULL | — | DEFAULT CURRENT_TIMESTAMP | --- ## ファイル一覧 | # | ファイル名 | DD名 | 編成 | RECM | サイズ | 生成元 | 消費先 | 備考 | |---|-----------|------|------|------|--------|--------|--------|------| | 1 | RAW-LEAVE | KIN01R01 | SEQUENTIAL | FB | 80 | 外部システム | KIN01INP | 休暇申請CSV | | 2 | WORK-LEAVE | KIN01W01 | SEQUENTIAL | FB | 80 | KIN01INP | SORT→KIN02UPD | 検証済休暇申請(中間) | | 3 | RAW-PUNCH | KIN04R01 | SEQUENTIAL | FB | 80 | 打刻システム | KIN04CHK | 生打刻データ | | 4 | EDITED-PUNCH | KIN04W01 | SEQUENTIAL | FB | 80 | KIN04CHK | KIN05MAT/B-サブシステム | 項目チェック通過打刻 | | 5 | LEAVE-DAILY | KIN02W01 | SEQUENTIAL | FB | 80 | KIN03EXP | KIN05MAT / KIN07DAI | 日別展開済休暇 | | 6 | KIN-LEAVE | KIN05W01 | SEQUENTIAL | FB | 160 | KIN05MAT | KIN07DAI | 打刻+休暇照合結果 | | 7 | WORK-DAY-FILE | KIN06W01 | SEQUENTIAL | FB | 80 | KIN06CLD | KIN07DAI | 出勤日カレンダー | | 8 | DAILY-RECORD | KIN07W01 | SEQUENTIAL | FB | 200 | KIN07DAI | KIN08DBU | 日別勤怠計算結果 | | 9 | ERROR-LOG | KIN01E01 | SEQUENTIAL | VB | 200 | KIN01INP / KIN04CHK | — | エラーレコード退避 | | 10 | ABSENCE-SUMMARY | KIN08W01 | SEQUENTIAL | FB | 80 | KIN08DBU | C-サブシステム | 月次欠勤集計(Cへ連携) | | 11 | CSV-OUTPUT | KIN09W01 | SEQUENTIAL | FB | 200 | KIN09CSV | — | 社員確認用CSV | --- ## 処理フロー ``` 休暇申請(RAW-LEAVE / CSV) │ │ [KINJ010] KIN01INP — 休暇申請CSV取込・検証処理 │ UNSTRINGでCSV分解 → IF/ELSE chain(新規/取消/変更) │ SEARCH(非ALL)で休暇種別テーブル検索 │ SUB04CHKで日付/時刻/数値チェック ├──正常 → WORK-LEAVE-file └──異常 → ERROR-LOG │ │ [KINJ011] SORT(WORK-LEAVE → APPLICATION_ID昇順) │ │ [KINJ012] KIN02UPD — 休暇申請DB更新処理 │ 新規: EXEC SQL INSERT │ 取消: EXEC SQL DELETE FROM ← 新カバレッジ │ 変更: EXEC SQL DELETE + INSERT │ → DB:LEAVE_RECORDS │ │ [KINJ015] KIN03EXP — 休暇日別展開処理 │ DB(SELECT/CURSOR) → PERFORM THRU(日付範囲) │ キーブレイク(社員番号切替) → HEADER処理 │ 休日除外 → CONTINUE │ → LEAVE-DAILY-file ▼ LEAVE-DAILY-file(日別休暇) │ 打刻生データ(RAW-PUNCH / CSV) │ │ [KINJ020] KIN04CHK — 打刻項目チェック処理 │ UNSTRING + SUB04CHK(日付/時刻/数値) │ IF多重ネスト(必須→日付→時刻→数値の4段階) ├──正常 → EDITED-PUNCH └──異常 → ERROR-LOG │ │ [KINJ022] SORT(EDITED-PUNCH → 社員番号+日付昇順) │ │ [KINJ025] KIN05MAT — 打刻休暇照合処理 │ マッチング(1:N) EDITED-PUNCH × LEAVE-DAILY │ 休暇種別優先順位(01/02連動, 03/04独立) │ → KIN-LEAVE ▼ KIN-LEAVE(照合結果) │ │ [KINJ030] KIN06CLD — 出勤日カレンダー生成処理 │ DB SELECT(CURSOR) + PERFORM VARYING │ SEARCH ALL(休日判定) / WRITE FROM ← 新カバレッジ │ → WORK-DAY-FILE ▼ WORK-DAY-FILE(出勤日カレンダー) │ │ [KINJ033] KIN07DAI — 日別勤怠計算処理 │ マッチング(1:N) + EVALUATE分岐 ← MULTIPLY/SUBTRACT新カバレッジ │ WORK-DAY(主駆動) × KIN-LEAVE(N側) │ 4パターン(A/B/C/D)をEVALUATE + PERFORMで分岐 │ 休暇時間計算(ランチ除外) + SUB05TIM丸め(0.1h切上) │ → DAILY-RECORD ▼ DAILY-RECORD(日別計算結果) │ │ [KINJ036] KIN08DBU — 勤怠DB更新処理 │ DAILY-RECORD → DAILY_RECORDS INSERT │ 社員別月次集計 → MONTHLY_ABSENCE UPSERT │ ABSENCE_SUMMARYファイル出力(Cへ連携) ▼ DB: DAILY_RECORDS + DB: MONTHLY_ABSENCE │ ABSENCE-SUMMARY-file ▼ C:給与計算システム(KYU01CAL) │ │ [KINJ040] KIN09CSV — 勤怠CSV出力処理 │ DB SELECT → STRING → WRITE AFTER ADVANCING ← 新カバレッジ ▼ CSV(社員確認用) ``` --- ## プログラム詳細 ### STEP010: KIN01INP — 休暇申請CSV取込・検証処理 | 項目 | 内容 | |------|------| | **PGMパターン** | **振り分け** | | **JCL前処理** | なし | | **入力** | RAW-LEAVE(80B / CSV形式)| | **出力** | WORK-LEAVE(80B)/ ERROR-LOG(VB)| **機能:** 1. READ RAW-LEAVE → CSVレコード1行を取得 2. **UNSTRING** でCSV分解(申請番号,社員番号,日付,開始時刻,終了時刻,休暇種別,ステータス)+ **TALLYING** でフィールド数カウント(項目数チェック) 4. **SEARCH(非ALL)** でWORKING-STORAGE上の休暇種別テーブルを線形探索 → 該当種別の存在確認 ← **新カバレッジ** 5. **IF/ELSE chain** でステータス判定(新規/取消/変更) ← **新カバレッジ(振り分けIF文)** 6. SUB04CHKで日付・時刻・数値の各項目検証 - IF多重ネスト:必須チェック → 日付形式 → 時刻範囲 → 数値 7. 通過 → WORK-LEAVEに出力(検証済みレコード) 8. エラー → ERROR-LOGに出力 **新規カバレッジ構文:** | 構文 | 用途 | |------|------| | UNSTRING | CSVレコードの項目分解 | | INSPECT TALLYING | カンマ区切り数カウント | | **SEARCH(非ALL)** | 休暇種別テーブル線形探索 ← 新規 | | IF/ELSE chain | ステータス別の振り分け処理(EVALUATE不使用) | --- ### STEP020: KIN02UPD — 休暇申請DB更新処理 | 項目 | 内容 | |------|------| | **PGMパターン** | **DB更新** | | **JCL前処理** | WORK-LEAVE → APPLICATION_ID昇順SORT | | **入力** | WORK-LEAVE(80B)| | **出力** | LEAVE_RECORDS(DB2)| **機能:** 1. READ WORK-LEAVE → 検証済みレコード1件 2. レコード種別に応じたDB操作: - 新規申請(ステータス='1') → **EXEC SQL INSERT** - 取消申請(ステータス='9') → **EXEC SQL DELETE FROM** WHERE APPLICATION_ID = :id ← **新カバレッジ** - 変更申請(ステータス='1', APPLICATION_ID指定済) → **DELETE + INSERT** 3. IF SQLCODE NOT = 0 → エラーハンドリング **新規カバレッジ構文:** | 構文 | 用途 | |------|------| | EXEC SQL INSERT | DB登録 | | **EXEC SQL DELETE FROM** | DB削除(物理削除による取消)← 新規 | | IF | SQLCODE判定 | --- ### STEP030: KIN03EXP — 休暇日別展開処理 | 項目 | 内容 | |------|------| | **PGMパターン** | **キーブレイク** | | **JCL前処理** | なし | | **入力** | LEAVE_RECORDS(DB2 SELECT / CURSOR) | | **出力** | LEAVE-DAILY-file(80B)| **機能:** 1. LEAVE_RECORDSからSTATUS='1'(有効)の全レコードをCURSOR SELECTする(ORDER BY EMP_ID, START_DATE)。 2. **PERFORM THRU** で処理範囲を指定 ← **新カバレッジ** - 2100-PROCESS-EMP THRU 2100-PROCESS-EMP-EXIT:1社員分の処理 - 2200-EXPAND-DATE THRU 2200-EXPAND-DATE-EXIT:日付展開処理 3. キーブレイク(社員番号切替)時に社員別小計を出力 ← **キーブレイク(その他)** 4. 各申請の開始日〜終了日をループ(PERFORM VARYING): - 休日判定:HOLIDAY_CALENDARに存在 or 土日 → **CONTINUE** でスキップ - 出勤日 → LEAVE-DAILY-fileに出力 **新規カバレッジ構文:** | 構文 | 用途 | |------|------| | **PERFORM THRU** | 段落範囲指定による構造化処理 ← 新規 | | PERFORM UNTIL | 日付ループ(開始日〜終了日)| | CONTINUE | 休日スキップ時の空処理 | | EXEC SQL SELECT(CURSOR) | DB読込(FETCH) | | SET | キーブレイクフラグ操作 | --- ### STEP040: KIN04CHK — 打刻項目チェック処理 | 項目 | 内容 | |------|------| | **PGMパターン** | 項目チェック(重複なし) | | **JCL前処理** | なし | | **入力** | RAW-PUNCH(80B / CSV形式)| | **出力** | EDITED-PUNCH(80B)/ ERROR-LOG(VB)| **機能:** 1. READ RAW-PUNCH → CSVレコード 2. **UNSTRING** で分解 3. **IF多重ネスト** で4段階チェック: ``` IF 社員番号 NOT = SPACE THEN IF 日付が有効形式 THEN IF 時刻が有効範囲 THEN IF 出勤 < 退勤 THEN 正常出力 ELSE → エラー ELSE → エラー ELSE → エラー ELSE → エラー END-IF ``` 4. 各チェックは SUB04CHK を呼出 5. 正常 → EDITED-PUNCHに出力(**WRITE FROM** 使用) 6. 異常 → ERROR-LOGに出力(**STRING** で編集) **新規カバレッジ構文:** | 構文 | 用途 | |------|------| | UNSTRING | CSV分解 | | **IF多重ネスト(THEN句)** | 必須→日付→時刻→数値の4段階チェック ← 新規(深度) | | WRITE FROM | 出力レコードの一括書出 | | STRING | エラーメッセージ編集 | --- ### STEP050: KIN05MAT — 打刻休暇照合処理 | 項目 | 内容 | |------|------| | **PGMパターン** | **マッチング(1:N)** | | **JCL前処理** | EDITED-PUNCH → 社員番号+日付昇順SORT(KINJ022)| | **入力R01** | EDITED-PUNCH(80B、打刻側)| | **入力R02** | LEAVE-DAILY-file(80B、休暇側、N件あり得る)| | **出力** | KIN-LEAVE(160B)| **機能:** EDITED-PUNCH(打刻)とLEAVE-DAILY-file(日別休暇)を社員番号+日付で照合する。 1. **マッチング制御**(EVALUATE TRUE): - R01キー < R02キー → 打刻のみ(休暇なし)→ 休暇='99'+0hで出力 - R01キー = R02キー → マッチ → 休暇情報マージ - 同一キーにN件のR02がある場合は全件読み、休暇種別優先順位で1件選定 - R01キー > R02キー → R02次へ(R01側に該当なしの休暇 → この後のR01読込で拾う) 2. **休暇種別優先順位**: - 01(年休)と02(事假)は連動:年休残あり→01, なし→02 - 03(因公特批假)と04(病欠)は独立 - 複数種別混在時はAPPLICATION_ID基準で時刻範囲判定 3. 出力:打刻情報(80B)+休暇情報(80B)=160BのKIN-LEAVE **新規カバレッジ構文:** | 構文 | 用途 | |------|------| | EVALUATE TRUE | マッチング3分岐制御 | | STRING | 出力レコード編集 | | CONTINUE | 空分岐処理 | --- ### STEP060: KIN06CLD — 出勤日カレンダー生成処理 | 項目 | 内容 | |------|------| | **PGMパターン** | **GETPUT** | | **JCL前処理** | なし | | **入力** | EMP_MASTER(DB2 SELECT / CURSOR)、HOLIDAY_CALENDAR(DB2 SELECT) | | **出力** | WORK-DAY-FILE(80B FB)| **PARM解析:** - `YEARMONTH=202605` — 必須。対象年月。 **機能:** 1. PARMから対象年月を取得 2. EMP_MASTERテーブルからSTATUS='1'(在籍)の社員一覧をSELECT(CURSOR, ORDER BY EMP_ID) 3. HOLIDAY_CALENDARテーブルから該当月の祝日一覧をSELECT(WORKING-STORAGEのテーブルに格納) 4. 各社員について、当月1日〜月末日まで **PERFORM VARYING** でループ: - **SEARCH ALL** でHOLIDAY-CALENDARテーブルを二分探索 - 土曜(6) or 日曜(7) → 休日 - その他 → 出勤日として **WRITE FROM** で出力 ← **新カバレッジ** 5. 出力レコードは社員番号+日付の昇順に保証(ORDER BY + ループ順) **新規カバレッジ構文:** | 構文 | 用途 | |------|------| | **WRITE FROM** | MOVE + WRITEを1文で記述 ← 新規 | | PERFORM VARYING | 日付ループ | | SEARCH ALL | 休日テーブル二分探索 | | EXEC SQL SELECT(CURSOR) | DB読込 | --- ### STEP070: KIN07DAI — 日別勤怠計算処理 | 項目 | 内容 | |------|------| | **PGMパターン** | **マッチング(1:N)** | | **JCL前処理** | なし(WORK-DAY-FILE / KIN-LEAVE / LEAVE-DAILYともソート済み前提) | | **入力R01** | WORK-DAY-FILE(80B、主駆動、1社員1日=1件) | | **入力R02** | KIN-LEAVE(160B、N側、1日0〜N件) | | **副参照** | LEAVE-DAILY-file(80B、ファイル併走読込) | | **出力** | DAILY-RECORD(200B FB)| **機能:** WORK-DAY-FILE(出勤日カレンダー)を主駆動とし、社員番号+日付をキーにKIN-LEAVE(打刻+休暇)とLEAVE-DAILY-file(日別休暇)を照合する。 **EVALUATEによる4パターン分岐:** マッチング結果に応じてPATTERN-NUM(1〜4)を設定し、**EVALUATE** で処理分岐(実装時にGO TO DEPENDING ONのフォールスルー問題を確認したため、EVALUATE + PERFORMに変更): ``` 01 PATTERN-NUM PIC 9(1). 88 PATTERN-A VALUE 1. 88 PATTERN-B VALUE 2. 88 PATTERN-C VALUE 3. 88 PATTERN-D VALUE 4. EVALUATE PATTERN-NUM WHEN 1 PERFORM 6100-PATTERN-A WHEN 2 PERFORM 6200-PATTERN-B WHEN 3 PERFORM 6300-PATTERN-C WHEN 4 PERFORM 6400-PATTERN-D END-EVALUATE. ``` | パターン | R01(WORK-DAY) | R02(KIN-LEAVE) | LEAVE-DAILY | 処理 | |---------|--------------|----------------|-------------|------| | A=1 | あり | あり | あり | 打刻情報設定+休暇時間計算(ランチ除外、0.1h切上丸め) | | B=2 | あり | あり | なし | 打刻情報設定のみ、休暇=0 | | C=3 | あり | なし | あり | 打刻=0000、休暇時間計算(所定労働時間8h上限、ランチ除外) | | D=4 | あり | なし | なし | 打刻=0000、休暇=0、未申請欠勤=8.0h | **休暇時間計算(ランチ考慮):** ``` 例:終日休暇申請 0900〜1800 0900-1200 = 3h(午前) 1200-1300 = ランチ(除外) 1300-1800 = 5h(午後) 合計休暇時間 = 8h 例:午後休暇申請 1300〜1800 1300-1800 = 5h(午後、ランチ除外済み) 合計休暇時間 = 5h ``` 丸め:SUB05TIM(0.1h単位切上)を呼出。 **バリエーション構文(MULTIPLY / SUBTRACT):** COMPUTEのみに依存せず、MULTIPLYとSUBTRACTも併用して時間計算のバリエーションを確保する。 ``` * 例:時間(hhmm)を分(minutes)に変換 → ランチ除外 MULTIPLY WRK-HOURS BY 60 GIVING WRK-MINUTES ← MULTIPLY SUBTRACT LUNCH-MINUTES FROM WRK-MINUTES ← SUBTRACT ``` **新規カバレッジ構文:** | 構文 | 用途 | |------|------| | **GO TO ... DEPENDING ON** | 4パターンの処理分岐 ← 新規 | | **PERFORM THRU** | 各パターン内の段落範囲処理 | | COMPUTE ROUNDED ON SIZE ERROR | 時間計算のエラー処理 | | **MULTIPLY** | 時間→分単位変換 ← 新規 | | **SUBTRACT** | ランチ時間除外 ← 新規 | | STRING | エラーメッセージ編集 | | CALL 'SUB05TIM' | 時刻丸め計算 | --- ### STEP080: KIN08DBU — 勤怠DB更新処理 | 項目 | 内容 | |------|------| | **PGMパターン** | DB更新 + **SYSIN読込(P28)** | | **JCL前処理** | なし | | **入力** | DAILY-RECORD(200B)、**SYSIN(制御カード)** | | **出力** | DAILY_RECORDS / MONTHLY_ABSENCE(DB2)、ABSENCE_SUMMARY(80B)| **SYSIN制御カード(3種):** ``` * コメント行(先頭*) T 社員番号,社員番号,... ← TARGET: 集計対象社員指定(省略時=全社員) P YEARMONTH=YYYYMM ← PERIOD: 処理対象年月(必須) M MODE=RESET|NORMAL ← MODE: RESET=再実行(既存削除後に再INSERT), NORMAL=通常(UPSERT) ``` カード種別('T','P','M')を第1桁で識別。**GO TO DEPENDING ON** で処理分岐する。 **機能:** 1. **SYSIN読込(パターン28)**:制御カードをSYSINから順次読み込み、カード種別で**GO TO DEPENDING ON**分岐 - `T`カード → 対象社員一覧をWORKING-STORAGEの内部テーブルに保持 - `P`カード → YEARMONTHを解析(`UNSTRING` + `INSPECT TALLYING`でカンマ区切り数検証) - `M`カード → MODEを判定。未指定ならNORMAL - `*`カード → コメント行としてスキップ(`CONTINUE`) - 不明カード → `DISPLAY`で警告表示 2. DAILY-RECORDを1レコードずつ読込み、DAILY_RECORDSに**EXEC SQL INSERT** - 各INSERT前に`INSPECT TALLYING`で社員番号の有効性チェック → 空または無効値は`DISPLAY`で警告表示 3. 社員別・月別の集計値を**PERFORM VARYING**で積算(全社員ループ) - **COMPUTE ROUNDED ON SIZE ERROR** で時間計算(桁あふれ時に警告表示) 4. MODE=RESETの場合:**EXEC SQL DELETE**で該当月の既存レコードを削除 5. MONTHLY_ABSENCEに対して**EXEC SQL SELECT COUNT(*) → IF >0 → UPDATE ELSE INSERT**(UPSERT) 6. 病欠時間はSICK_LEAVE_RATEテーブルを参照し、控除前時間として保持 7. 集計後データをABSENCE_SUMMARYファイルに出力 **GO TO DEPENDING ON ロジック:** ```cobol READ SYSINFILE INTO WS-SYSIN-REC AT END SET SYSIN-EOF TO TRUE END-READ. IF NOT SYSIN-EOF MOVE WS-SYSIN-REC(1:1) TO WS-CARD-TYPE IF WS-CARD-TYPE = 'T' OR 'P' OR 'M' IF WS-CARD-TYPE = 'T' MOVE 1 TO WS-DISP-IDX IF WS-CARD-TYPE = 'P' MOVE 2 TO WS-DISP-IDX IF WS-CARD-TYPE = 'M' MOVE 3 TO WS-DISP-IDX GO TO DEPENDING ON WS-DISP-IDX 2100-TARGETSOR 2200-PERIODSOR 2300-MODESOR . ELSE IF WS-CARD-TYPE = '*' DISPLAY 'COMMENT: ' WS-SYSIN-REC ELSE DISPLAY 'WARNING: Unknown SYSIN card type [' WS-CARD-TYPE ']' END-IF END-IF END-IF. ``` **新規カバレッジ構文:** | 構文 | 用途 | |------|------| | **READ SYSIN(パターン28)** | 制御カード読込 ← 新規パターン | | **GO TO DEPENDING ON** | カード種別による3分岐 ← 新規 | | DISPLAY | 警告メッセージ表示 ← 新規 | | INSPECT TALLYING | 社員番号の空チェック、カンマ区切り数検証 | | **COMPUTE ON SIZE ERROR** | 時間計算の桁あふれ処理 ← 新規 | | **EXEC SQL DELETE** | RESETモード時既存レコード削除 ← 新規(メインPGM) | | PERFORM VARYING | 社員別月次集計ループ | | EXEC SQL SELECT / INSERT / UPDATE | DB操作(UPSERTパターン) | --- ### STEP090: KIN09CSV — 勤怠CSV出力処理 | 項目 | 内容 | |------|------| | **PGMパターン** | GETPUT(編集出力) | | **JCL前処理** | なし | | **入力** | DAILY_RECORDS / MONTHLY_ABSENCE(DB2)、**COMMAND-LINE PARM** | | **出力** | CSVファイル(社員確認用)| **PARM解析:** - `YEARMONTH=202605` — 必須。対象年月。 - `MODE=FULL` — オプション。`FULL`=全項目出力(日別+月次), `SHORT`=月次集計のみ。 **機能:** 1. **ACCEPT FROM COMMAND-LINE** でPARM解析(`INSPECT TALLYING`でカンマ区切り数チェック) 2. DAILY_RECORDSから当月の全レコードをCURSOR SELECT(ORDER BY EMP_ID, TARGET_DATE) 3. **INSPECT REPLACING** でCSV危険文字をサニタイズ(カンマ→セミコロン、改行→スペース) 4. **STRING WITH POINTER** でCSV行を位置指定編集 ← **新カバレッジ** 5. **WRITE AFTER ADVANCING 3種** でページ制御 ← **新カバレッジ** - 先頭ページ:`WRITE header-rec AFTER ADVANCING PAGE` - セクション区切り:`WRITE section-rec AFTER ADVANCING 2 LINES` - データ行:`WRITE data-rec AFTER ADVANCING 1 LINE` 6. MODE=FULL時:100行ごとにヘッダー行を再出力 7. CSVフォーマット: ``` 社員番号,日付,出勤時刻,退勤時刻,休暇種別,年休時間,事假時間,因公特批假時間,病欠時間,未申請欠勤時間 00000101,20260501,0900,1800,99,0.0,0.0,0.0,0.0,0.0 00000101,20260502,0900,1300,02,0.0,4.0,0.0,0.0,4.0 00000101,20260503,0000,0000,01,8.0,0.0,0.0,0.0,0.0 00000101,20260504,0000,0000,99,0.0,0.0,0.0,0.0,8.0 ``` 8. 休暇種別は該当日に休暇がある場合は最初に該当した休暇種別コード、ない場合は'99' **INSPECT REPLACING によるCSVサニタイズ:** ```cobol MOVE WS-FIELD TO WS-SAFE-FIELD. INSPECT WS-SAFE-FIELD REPLACING ALL ',' BY ';' ALL X"0D" BY SPACE ALL X"0A" BY SPACE. ``` **STRING WITH POINTER によるCSV行編集:** ```cobol MOVE 1 TO WS-PTR. STRING WS-EMP-ID DELIMITED BY SIZE ',' DELIMITED BY SIZE WS-DATE DELIMITED BY SIZE ',' DELIMITED BY SIZE WS-TIME-IN DELIMITED BY SIZE ',' DELIMITED BY SIZE WS-TIME-OUT DELIMITED BY SIZE ',' DELIMITED BY SIZE WS-LEAVE-TYPE DELIMITED BY SIZE ',' DELIMITED BY SIZE WS-ANNUAL-H DELIMITED BY SIZE ',' DELIMITED BY SIZE WS-PERSONAL-H DELIMITED BY SIZE ',' DELIMITED BY SIZE WS-OFFICIAL-H DELIMITED BY SIZE ',' DELIMITED BY SIZE WS-SICK-H DELIMITED BY SIZE ',' DELIMITED BY SIZE WS-ABSENT-H DELIMITED BY SIZE INTO WS-CSV-LINE WITH POINTER WS-PTR END-STRING. ``` **新規カバレッジ構文:** | 構文 | 用途 | |------|------| | **ACCEPT FROM COMMAND-LINE** | PARM解析(対象年月・出力モード)| | **INSPECT REPLACING** | CSV危険文字置換 ← 新規 | | **STRING WITH POINTER** | 位置指定CSV行編集 ← 新規 | | **WRITE AFTER ADVANCING PAGE** | ページヘッダー制御 ← 新規 | | **WRITE AFTER ADVANCING 2 LINES** | セクション区切り ← 新規 | | **WRITE AFTER ADVANCING 1 LINE** | データ行出力 ← 新規 | | STRING | CSV行編集(DELIMITED BY SIZE) | | EXEC SQL SELECT(CURSOR) | DB読込 | --- ## 共通関数(サブプログラム) サブシステムAの全プログラムで使用する共通関数。SUB06DBUは使用せず、全DB操作はEXEC SQLで直接記述する。 | サブプログラム | I/Fコピー句 | 用途 | 使用プログラム | |---|---|---|---| | SUB01DAT | D01010AC | 運用日付取得 | KIN01INP, KIN04CHK, KIN08DBU, KIN09CSV | | SUB02MSG | MSG000AC | メッセージ編集出力 | 全プログラム | | SUB03END | MSG000AC | ABEND終了 | KIN02UPD, KIN04CHK, KIN07DAI | | SUB04CHK | SUB04CHK | 項目チェック(日付/時刻/数値) | KIN01INP, KIN04CHK | | SUB05TIM | TIME010AC | 時刻丸め計算(分→時間) | KIN07DAI | --- ## JCL構成概要 9本のJOB。拠点間ソートはJCL SORTで処理し、COBOLプログラムはビジネスロジックに専念する。 | JOB名 | 実行PGM | 処理概要 | SORT | |-------|--------|---------|------| | KINJ010 | KIN01INP | 休暇申請CSV取込・検証 | 不要 | | KINJ011 | SORT | WORK-LEAVE → APPLICATION_ID昇順 | 必須 | | KINJ012 | KIN02UPD | 休暇申請DB更新(INSERT/DELETE) | 不要 | | KINJ015 | KIN03EXP | 休暇日別展開(キーブレイク) | 不要 | | KINJ020 | KIN04CHK | 打刻項目チェック | 不要 | | KINJ022 | SORT | EDITED-PUNCH → 社員番号+日付昇順 | 必須 | | KINJ025 | KIN05MAT | 打刻休暇照合(1:N) | 不要 | | KINJ030 | KIN06CLD | 出勤日カレンダー生成(GETPUT) | 不要 | | KINJ033 | KIN07DAI | 日別計算(EVALUATE / MULTIPLY / SUBTRACT) | 不要 | | KINJ036 | KIN08DBU | 勤怠DB更新(集計) | 不要 | | KINJ040 | KIN09CSV | 勤怠CSV出力 | 不要 | --- ## 丸めルール一覧 | 項目 | 最小単位 | 超過後丸め | 適用プログラム | |------|---------|-----------|--------------| | 休暇時間(全種別) | 1.0h | 0.1h単位切上 | KIN07DAI(SUB05TIM) | | 未申請欠勤時間 | 8.0h/日 | 切捨 | KIN07DAI | サブシステムB(残業計算)の丸めルールとは独立して管理する。 --- ## 期待される新規カバレッジ ### プログラムタイプ(未カバー → Aで追加) | No | パターン | 状態 | A該当プログラム | A状態 | |----|----------|:----:|----------------|:-----:| | 2 | マッチング処理(1:N) | × | KIN05MAT | ◎ | | 11 | キーブレイク処理(その他) | × | KIN03EXP | ◎ | | 12 | レイアウト編集のみ(GETPUT) | × | KIN06CLD | ◎ | | 15 | 振り分け(IF文) | × | KIN01INP | ◎ | | 17 | 内部テーブル検索 | ○ | KIN01INP(SEARCH非ALL) | ◎ | | 19 | CSV→FB変換(改行なし) | ○ | KIN01INP | ◎ | | **28** | **SYSIN読込・チェック** | **×** | **KIN08DBU** | **新規◎** | ### ステートメント(未カバー → Aで追加) | ステートメント | 状態 | A該当プログラム | |---------------|:----:|----------------| | SEARCH(非ALL) | × | KIN01INP | | DELETE FROM(DB2) | × | KIN02UPD | | **GO TO DEPENDING ON** | **×** | **KIN08DBU(← 新規)** | | PERFORM THRU | × | KIN03EXP | | WRITE FROM | × | KIN04CHK, KIN06CLD | | **WRITE AFTER ADVANCING(PAGE/1/2)** | **×** | **KIN09CSV(← 新規)** | | **INSPECT REPLACING** | **×** | **KIN09CSV(← 新規)** | | **STRING WITH POINTER** | **×** | **KIN09CSV(← 新規)** | | **COMPUTE ON SIZE ERROR** | **○(ZAN系のみ)** | **KIN08DBU(← 新規)** | | MULTIPLY | ○(ZAN06UPDのみ) | KIN07DAI | | SUBTRACT | ○(ZAN06UPDのみ) | KIN07DAI | | ACCEPT FROM COMMAND-LINE | ◎(ZAN05CAL,KIN06CLD) | KIN09CSV | | DISPLAY | △(SUB02MSG,SUB03ENDのみ) | KIN08DBU | | INSPECT TALLYING | ◎ | KIN08DBU | ### 全体カバレッジ目標 | カテゴリ | 現状 | 追加後(目標) | |---------|:---:|:-------------:| | プログラムタイプ(35種) | 14使用(40.0%) | 15使用(42.9%) | | ステートメント(45ユニーク) | 33使用(73.3%) | 36使用(80.0%) | | カテゴリ(9種) | 8/9カバー(88.9%) | 9/9カバー(100%) | --- ## レコード構成 EDITED-PUNCHはBサブシステムのZAN03CHKが入力として使用するため、互換性を維持する。 ### EDITED-PUNCH(80B) Bサブシステムとの連携インターフェース。 | # | 項目 | 名称 | 属性 | 開始 | 備考 | |---|------|------|------|------|------| | 1 | 社員番号 | SI-EMP-ID | 9(8) | 1 | | | 2 | 日付 | SI-DATE | 9(8) | 9 | YYYYMMDD | | 3 | 出勤時刻 | SI-TIME-IN | 9(4) | 17 | HHMM | | 4 | 退勤時刻 | SI-TIME-OUT | 9(4) | 21 | HHMM | | 5 | 部署ID | SI-DEPT-ID | 9(4) | 25 | | | 6 | 端末ID | SI-TERMINAL | X(6) | 29 | | | 7 | 予備 | FILLER | X(46) | 35 | | ### WORK-LEAVE(80B) — 新規(KIN01INP→KIN02UPD中間) | # | 項目 | 名称 | 属性 | 開始 | 備考 | |---|------|------|------|------|------| | 1 | 申請ID | WL-APPLICATION-ID | 9(9) | 1 | 新規=0, 取消/変更=APPLICATION_ID | | 2 | 社員番号 | WL-EMP-ID | X(8) | 10 | | | 3 | 休暇種別 | WL-LEAVE-TYPE | X(2) | 18 | '01'〜'04' | | 4 | 開始日 | WL-START-DATE | 9(8) | 20 | YYYYMMDD | | 5 | 開始時刻 | WL-START-TIME | 9(4) | 28 | HHMM | | 6 | 終了日 | WL-END-DATE | 9(8) | 32 | YYYYMMDD | | 7 | 終了時刻 | WL-END-TIME | 9(4) | 40 | HHMM | | 8 | ステータス | WL-STATUS | X(1) | 44 | '1'=新規/変更, '9'=取消 | | 9 | 予備 | FILLER | X(36) | 45 | | ### LEAVE-DAILY(80B) | # | 項目 | 名称 | 属性 | 開始 | 備考 | |---|------|------|------|------|------| | 1 | 社員番号 | SL-EMP-ID | X(8) | 1 | | | 2 | 日付 | SL-DATE | 9(8) | 9 | YYYYMMDD | | 3 | 休暇種別 | SL-LEAVE-TYPE | X(2) | 17 | '01'〜'04' | | 4 | 開始時刻 | SL-START-TIME | 9(4) | 19 | HHMM(元申請の開始時刻) | | 5 | 終了時刻 | SL-END-TIME | 9(4) | 23 | HHMM(元申請の終了時刻) | | 6 | 申請ID | SL-APPLICATION-ID | 9(9) | 27 | LEAVE_RECORDSのAPPLICATION_ID | | 7 | 予備 | FILLER | X(45) | 36 | | ### KIN-LEAVE(160B) — EDITED-PUNCH(80B)+休暇情報(80B) | # | 項目 | 名称 | 属性 | 開始 | 備考 | |---|------|------|------|------|------| | 1-7 | 打刻情報 | — | — | 1 | EDITED-PUNCHと同一 | | 8 | 休暇種別 | SR-LEAVE-TYPE | X(2) | 81 | '01'〜'04' or '99' | | 9 | 開始時刻 | SR-LEAVE-START-TIME | 9(4) | 83 | 該当休暇の申請開始時刻 | | 10 | 終了時刻 | SR-LEAVE-END-TIME | 9(4) | 87 | 該当休暇の申請終了時刻 | | 11 | 休暇時間 | SR-LEAVE-HOURS | 9(4)V9(1) | 91 | KIN07DAIが再計算(ランチ除外・丸め適用) | | 12 | 申請ID | SR-APPLICATION-ID | 9(9) | 96 | LEAVE_RECORDSのAPPLICATION_ID | | 13 | 予備 | FILLER | X(56) | 105 | | ### WORK-DAY-FILE(80B) | # | 項目 | 名称 | 属性 | 開始 | 備考 | |---|------|------|------|------|------| | 1 | 社員番号 | SW-EMP-ID | 9(8) | 1 | | | 2 | 日付 | SW-DATE | 9(8) | 9 | YYYYMMDD | | 3 | 曜日 | SW-DAY-OF-WEEK | 9(1) | 17 | 1=月…7=日 | | 4 | 予備 | FILLER | X(63) | 18 | | ### DAILY-RECORD(200B) | # | 項目 | 名称 | 属性 | 開始 | 備考 | |---|------|------|------|------|------| | 1 | 社員番号 | SD-EMP-ID | 9(8) | 1 | | | 2 | 日付 | SD-DATE | 9(8) | 9 | YYYYMMDD | | 3 | 出勤時刻 | SD-TIME-IN | 9(4) | 17 | '0000'=打刻なし | | 4 | 退勤時刻 | SD-TIME-OUT | 9(4) | 21 | '0000'=打刻なし | | 5 | 年休時間 | SD-ANNUAL-H | 9(4)V9(1) | 25 | | | 6 | 事假時間 | SD-PERSONAL-H | 9(4)V9(1) | 30 | | | 7 | 因公特批假時間 | SD-OFFICIAL-H | 9(4)V9(1) | 35 | | | 8 | 病欠時間 | SD-SICK-H | 9(4)V9(1) | 40 | | | 9 | 未申請欠勤時間 | SD-ABSENT-H | 9(4)V9(1) | 45 | | | 10 | 予備 | FILLER | X(151) | 50 | | ### CSV-OUTPUT(200B) | # | 項目 | 名称 | 属性 | 開始 | 備考 | |---|------|------|------|------|------| | 1 | CSV行データ | SC-CSV-LINE | X(200) | 1 | STRING編集済みCSV1行 | ### ERROR-LOG(VB 200B) | # | 項目 | 名称 | 属性 | 開始 | 備考 | |---|------|------|------|------|------| | 1 | エラー区分 | ER-CATEGORY | 9(2) | 1 | 01=休暇エラー, 02=打刻エラー | | 2 | 発生日時 | ER-DATETIME | X(16) | 3 | | | 3 | プログラムID | ER-PGM-ID | X(8) | 19 | | | 4 | エラー内容 | ER-MESSAGE | X(100) | 27 | | | 5 | 原データ | ER-RAW-DATA | X(80) | 127 | エラー原因となった入力レコード |