Files
cobol-tna-system/基本設計書/01_勤怠休暇管理システム_設計書(サブシステムA).md

889 lines
37 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 勤怠休暇管理システム 設計書(サブシステム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.5050%控除) |
### 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-LEAVE80B / CSV形式)|
| **出力** | WORK-LEAVE80B/ ERROR-LOGVB|
**機能:**
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-LEAVE80B|
| **出力** | LEAVE_RECORDSDB2|
**機能:**
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_RECORDSDB2 SELECT / CURSOR |
| **出力** | LEAVE-DAILY-file80B|
**機能:**
1. LEAVE_RECORDSからSTATUS='1'(有効)の全レコードをCURSOR SELECTする(ORDER BY EMP_ID, START_DATE)。
2. **PERFORM THRU** で処理範囲を指定 ← **新カバレッジ**
- 2100-PROCESS-EMP THRU 2100-PROCESS-EMP-EXIT1社員分の処理
- 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-PUNCH80B / CSV形式)|
| **出力** | EDITED-PUNCH80B/ ERROR-LOGVB|
**機能:**
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 → 社員番号+日付昇順SORTKINJ022|
| **入力R01** | EDITED-PUNCH80B、打刻側)|
| **入力R02** | LEAVE-DAILY-file80B、休暇側、N件あり得る)|
| **出力** | KIN-LEAVE160B|
**機能:**
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_MASTERDB2 SELECT / CURSOR)、HOLIDAY_CALENDARDB2 SELECT |
| **出力** | WORK-DAY-FILE80B FB|
**PARM解析:**
- `YEARMONTH=202605` — 必須。対象年月。
**機能:**
1. PARMから対象年月を取得
2. EMP_MASTERテーブルからSTATUS='1'(在籍)の社員一覧をSELECTCURSOR, ORDER BY EMP_ID
3. HOLIDAY_CALENDARテーブルから該当月の祝日一覧をSELECTWORKING-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-FILE80B、主駆動、1社員1日=1件) |
| **入力R02** | KIN-LEAVE160B、N側、1日0〜N件) |
| **副参照** | LEAVE-DAILY-file80B、ファイル併走読込) |
| **出力** | DAILY-RECORD200B FB|
**機能:**
WORK-DAY-FILE(出勤日カレンダー)を主駆動とし、社員番号+日付をキーにKIN-LEAVE(打刻+休暇)とLEAVE-DAILY-file(日別休暇)を照合する。
**EVALUATEによる4パターン分岐:**
マッチング結果に応じてPATTERN-NUM1〜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-RECORD200B)、**SYSIN(制御カード)** |
| **出力** | DAILY_RECORDS / MONTHLY_ABSENCEDB2)、ABSENCE_SUMMARY80B|
**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_ABSENCEDB2)、**COMMAND-LINE PARM** |
| **出力** | CSVファイル(社員確認用)|
**PARM解析:**
- `YEARMONTH=202605` — 必須。対象年月。
- `MODE=FULL` — オプション。`FULL`=全項目出力(日別+月次), `SHORT`=月次集計のみ。
**機能:**
1. **ACCEPT FROM COMMAND-LINE** でPARM解析(`INSPECT TALLYING`でカンマ区切り数チェック)
2. DAILY_RECORDSから当月の全レコードをCURSOR SELECTORDER 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単位切上 | KIN07DAISUB05TIM |
| 未申請欠勤時間 | 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 ADVANCINGPAGE/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-PUNCH80B
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-LEAVE80B — 新規(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-DAILY80B
| # | 項目 | 名称 | 属性 | 開始 | 備考 |
|---|------|------|------|------|------|
| 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-LEAVE160B — 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-FILE80B
| # | 項目 | 名称 | 属性 | 開始 | 備考 |
|---|------|------|------|------|------|
| 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-RECORD200B
| # | 項目 | 名称 | 属性 | 開始 | 備考 |
|---|------|------|------|------|------|
| 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-OUTPUT200B
| # | 項目 | 名称 | 属性 | 開始 | 備考 |
|---|------|------|------|------|------|
| 1 | CSV行データ | SC-CSV-LINE | X(200) | 1 | STRING編集済みCSV1行 |
### ERROR-LOGVB 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 | エラー原因となった入力レコード |