Files
cobol-tna-system/基本設計書/02_残業統計管理システム_設計書(サブシステムB).md

30 KiB
Raw Permalink Blame History

残業統計管理システム 設計書(サブシステムB)

システム概要

本サブシステムは、社員からの加班申請データを元に、振り分け・重複チェック・打刻照合・取消マッチング・キーブレイク集約を行い、月次の加班統計データをDBに保存する。

サブシステム情報

項目 内容
サブシステムID ZAN(残業→ZANgyo
COBOLプログラム数 6
JCL数 6
DB 1OVERTIME-DB / DB2、2テーブル)

システム定数

定数 説明
WORK-START 0900 所定労働開始時刻
WORK-END 1800 所定労働終了時刻
DINNER-START 1830 食事時間開始(1830以前は加班不可)
MIN-OVT-HOURS 0.5 加班最小単位

入力CSV形式(OVT-APPLY

各レコードはCSV形式。

項目 内容
フォーマット 申請番号,社員番号,日付(YYYYMMDD),開始時刻(HHMM),終了時刻(HHMM),ステータス
ステータス 0 申請(新規)
ステータス 1 承認済(後続処理で状態更新)
ステータス 9 取消

ファイル一覧

# ファイル名 編成 RECM サイズ 用途 区分
1 OVT-APPLY SEQUENTIAL FB 80 加班申請CSV(入力) 新規
2 OVT-VALID SEQUENTIAL FB 80 振り分け通過(有効申請) 新規
3 OVT-CANCEL SEQUENTIAL FB 80 振り分け通過(取消) 新規
4 OVT-NODUP SEQUENTIAL FB 80 重複チェック通過データ 新規
5 OVT-CHECKED SEQUENTIAL FB 80 打刻照合通過(OVT-TYPE付加) 新規
6 OVT-MATCHED SEQUENTIAL FB 80 マッチング通過(処理番号付加) 新規
7 OVT-DBCLEAN SEQUENTIAL FB 80 孤立取消(DB削除対象) 新規
8 OVT-SUMMARY SEQUENTIAL FB 80 集約結果 新規
9 ERROR-LOG SEQUENTIAL VB 200 エラーレコード退避 Aと共用
10 EDITED-PUNCH SEQUENTIAL FB 80 打刻データ(Aシステム出力) Aから連携
11 HOLIDAY-FILE SEQUENTIAL FB 80 休日マスタファイル(Aシステム提供) Aから連携

DBテーブル管理方針

DB2インスタンスは全サブシステムで共有するが、テーブルはサブシステム別に機能分割する。 BサブシステムのテーブルはOVT-APPLICATIONS, OVT-MONTHLYの2つであり、これらの管理・更新はBのみが行う。 Aサブシステムのテーブル(DAILY_RECORDS, LEAVE_RECORDS等)は参照せず、A→Bの連携はEDITED-PUNCHファイル経由に限定する。 HOLIDAY_CALENDARテーブルについては、Aサブシステムによって提供されるHOLIDAY-FILEを使用することで参照を代替する。

DB二重対応

本サブシステムのDB操作はDB2の埋め込みSQL(EXEC SQL)で直接記述する。 ただし、休日マスタに関するDBアクセスはファイルベースで処理するため、 ZAN06UPD以外の全プログラムはDBアクセスを伴わない。 各プログラム内でEXEC SQL INSERT/UPDATE/SELECTを発行する。

共通関数利用方針

Aサブシステムの共通関数のうち、安定した汎用APISUB01DAT, SUB02MSG, SUB03END, SUB04CHK, SUB05TIM)はBでも利用する。 SUB06DBUはサブシステムAで使用するDB更新用サブプログラムであり、Bでは使用しない(EXEC SQLを直接記述)。


DB構成

DB名称:残業統計データベース(OVERTIME-DB

テーブル1OVT-APPLICATIONS(個別加班申請テーブル)

カラム 内容
APPL-ID CHAR(8) 申請番号(PK
EMP-ID CHAR(8) 社員番号
APPL-DATE CHAR(8) 申請日 YYYYMMDD
OVT-TYPE CHAR(1) W=平日 / H=休日
START-TIME CHAR(4) 開始時刻 HHMM
END-TIME CHAR(4) 終了時刻 HHMM
OVT-HOURS DECIMAL(4,1) 加班時間
STATUS CHAR(1) 0=有効 / 9=取消
UPDATED-AT TIMESTAMP 更新日時

テーブル2:OVT-MONTHLY(月次集計テーブル)

カラム 内容
EMP-ID CHAR(8) 社員番号(PK
YEAR-MONTH CHAR(6) 対象年月 YYYYMMPK
OVT-TYPE CHAR(1) W=平日 / H=休日(PK
OVT-HOURS DECIMAL(6,1) 加班時間合計
OVT-COUNT INTEGER 加班回数
UPDATED-AT TIMESTAMP 更新日時

処理フロー

OVT-APPLYCSV、任意順)
 レコード: 申請番号,社員番号,日付,開始時刻,終了時刻,ステータス(0/1/9)
  │
  ╞══ ZANJ010 ═══════════════════════════════════╡
  │ ZAN01CHK(残業申請振分処理)— 振り分け
  │ UNSTRINGでCSV分解 / EVALUATEでステータス判定
  │ SUB04CHKで日付/時刻/数値チェック / 0.5h未満チェック
  ├── ステータス=0,1 → OVT-VALID
  ├── ステータス=9   → OVT-CANCEL
  └── 異常          → ERROR-LOG
  │
  ╞══ ZANJ012 ═══════════════════════════════════╡
  │ SORT(OVT-VALID → 社員番号+日付+開始時刻昇順)
  │
  │ ZAN02CHK(時間帯重複チェック処理)— 項目チェック
  │ 同社員+同日の前レコード終了時刻 > 現レコード開始時刻
  │ → 重複(境界接続は重複としない)
  ├── 通過 → OVT-NODUP
  └── 重複 → ERROR-LOG
  │
   ╞══ ZANJ013 ═══════════════════════════════════╡
   │ SORT(EDITED-PUNCH → 社員番号+日付昇順)
   │
    │ ZAN03CHK(打刻時間照合処理)— マッチング(N:1)
   │ OVT-NODUP + PUNCH-SORTED を社員番号+日付で突合
   │ 申請時間帯が出勤〜退勤の範囲内か確認
   │ HOLIDAY_CALENDAR検索+曜日関数で休日判定→OVT-TYPE(W/H)設定
   ├── 通過 → OVT-CHECKED
   └── 異常 → ERROR-LOG
  │
  ╞══ ZANJ015 ═══════════════════════════════════╡
  │ SORT(OVT-CHECKED → 申請番号昇順)
  │ SORT(OVT-CANCEL  → 申請番号昇順)
  │
  │ ZAN04MAT(取消マッチング処理)— マッチング1:1
  │ キー=申請番号で VALID vs CANCEL を突合
  ├── VALID有 + CANCEL無 → OVT-MATCHED
  ├── VALID有 + CANCEL有 → 消滅
  └── VALID無 + CANCEL有 → OVT-DBCLEAN
  │
  ╞══ ZANJ020 ═══════════════════════════════════╡
  │ SORT(OVT-MATCHED → 申請番号+処理番号昇順)
  │
   │ ZAN05CAL(残業時間集計処理)— キーブレイク集計
   │ 同一申請番号内の最終レコードを集計
  │ DIVIDE 分→時間変換 / SUB05TIMで丸め
  │ COMPUTE ROUNDED ON SIZE ERROR
  │ → OVT-SUMMARY
  │
  ╞══ ZANJ025 ═══════════════════════════════════╡
  │ ZAN06UPD(残業統計DB更新処理)— DB更新
  ├── OVT-SUMMARY → OVT-APPLICATIONS INSERT/UPDATE
  │               → OVT-MONTHLY UPSERT(平日/休日別)
  └── OVT-DBCLEAN → OVT-APPLICATIONS STATUS='9' UPDATE
                   → OVT-MONTHLY 減算UPDATE
                   → 該当なし → ERROR-LOG

JCL

ZANJ010 — 残業申請振分

//ZANJ010  JOB (ACCT),'残業申請振分',CLASS=A
//*
//*--- パラメータ定義 ---
//SETPARM  SET YEARMONTH=202605
//*
//*=====================================================================
//* STEP010: 振り分け(SORT不要)
//* 注:YEARMONTH PARMは他プログラムとの一貫性のため渡すが、ZAN01CHK内では未使用
//*=====================================================================
//STEP010  EXEC PGM=ZAN01CHK
//ZAN01R01  DD DSN=OVT-APPLY.DAT,DISP=SHR
//ZAN01W01  DD DSN=OVT-VALID.DAT,DISP=(NEW,PASS)
//ZAN01W02  DD DSN=OVT-CANCEL.DAT,DISP=(NEW,PASS)
//ZAN01W03  DD DSN=ERROR-LOG.DAT,DISP=(NEW,PASS)

ZANJ012 — 時間帯重複チェック

//ZANJ012  JOB (ACCT),'時間帯重複チェック',CLASS=A
//*
//*--- パラメータ定義 ---
//SETPARM  SET YEARMONTH=202605
//*
//*=====================================================================
//* STEP012S: 有効申請 SORT
//*=====================================================================
//STEP012S EXEC PGM=SORT
//SORTIN   DD DSN=OVT-VALID.DAT,DISP=(OLD,DELETE)
//SORTOUT  DD DSN=OVT-VSORT.DAT,DISP=(NEW,PASS)
//SYSIN    DD *
  SORT FIELDS=(9,8,CH,A,17,8,CH,A,25,4,CH,A),EQUALS
/*
//*
//*=====================================================================
//* STEP012: 重複チェック
//*=====================================================================
//STEP012  EXEC PGM=ZAN02CHK,PARM='YEARMONTH=&YEARMONTH'
//ZAN02R01  DD DSN=OVT-VSORT.DAT,DISP=(OLD,DELETE)
//ZAN02W01  DD DSN=OVT-NODUP.DAT,DISP=(NEW,PASS)
//ZAN02W02  DD DSN=ERROR-LOG.DAT,DISP=(NEW,PASS)

ZANJ013 — 打刻時間照合

//ZANJ013  JOB (ACCT),'打刻時間照合',CLASS=A
//*
//*--- パラメータ定義 ---
//SETPARM  SET YEARMONTH=202605
//*
//*=====================================================================
//* STEP013S: 打刻データ SORT
//*=====================================================================
//STEP013S EXEC PGM=SORT
//SORTIN   DD DSN=EDITED-PUNCH.DAT,DISP=SHR
//SORTOUT  DD DSN=PUNCH-SORTED.DAT,DISP=(NEW,PASS)
//SYSIN    DD *
  SORT FIELDS=(1,8,CH,A,9,8,CH,A),EQUALS
/*
//*
//*=====================================================================
//* STEP013: 打刻照合 + 曜日判定
//*=====================================================================
//STEP013  EXEC PGM=ZAN03CHK,PARM='YEARMONTH=&YEARMONTH'
//ZAN03R01  DD DSN=OVT-NODUP.DAT,DISP=(OLD,DELETE)
//ZAN03R02  DD DSN=PUNCH-SORTED.DAT,DISP=(OLD,DELETE)
//ZAN03R03  DD DSN=HOLIDAY-FILE.DAT,DISP=SHR
//ZAN03W01  DD DSN=OVT-CHECKED.DAT,DISP=(NEW,PASS)
//ZAN03W02  DD DSN=ERROR-LOG.DAT,DISP=(NEW,PASS)

ZANJ015 — 取消マッチング

//ZANJ015  JOB (ACCT),'取消マッチング',CLASS=A
//*
//*--- パラメータ定義 ---
//SETPARM  SET YEARMONTH=202605
//*
//*=====================================================================
//* STEP015S1: チェック済データ SORT
//*=====================================================================
//STEP015SA EXEC PGM=SORT
//SORTIN   DD DSN=OVT-CHECKED.DAT,DISP=(OLD,DELETE)
//SORTOUT  DD DSN=OVT-SORTED.DAT,DISP=(NEW,PASS)
//SYSIN    DD *
  SORT FIELDS=(1,8,CH,A),EQUALS
/*
//*
//*=====================================================================
//* STEP015S2: 取消データ SORT
//*=====================================================================
//STEP015SB EXEC PGM=SORT
//SORTIN   DD DSN=OVT-CANCEL.DAT,DISP=(OLD,DELETE)
//SORTOUT  DD DSN=OVT-CSORT.DAT,DISP=(NEW,PASS)
//SYSIN    DD *
  SORT FIELDS=(1,8,CH,A),EQUALS
/*
//*
//*=====================================================================
//* STEP015: マッチング
//*=====================================================================
//STEP015  EXEC PGM=ZAN04MAT,PARM='YEARMONTH=&YEARMONTH'
//ZAN04R01  DD DSN=OVT-SORTED.DAT,DISP=(OLD,DELETE)
//ZAN04R02  DD DSN=OVT-CSORT.DAT,DISP=(OLD,DELETE)
//ZAN04W01  DD DSN=OVT-MATCHED.DAT,DISP=(NEW,PASS)
//ZAN04W02  DD DSN=OVT-DBCLEAN.DAT,DISP=(NEW,PASS)
//ZAN04W03  DD DSN=ERROR-LOG.DAT,DISP=(NEW,PASS)

ZANJ020 — 残業時間集計

//ZANJ020  JOB (ACCT),'残業時間集計',CLASS=A
//*
//*--- パラメータ定義 ---
//SETPARM  SET YEARMONTH=202605
//*
//*=====================================================================
//* STEP020S: マッチング済データ SORT
//*=====================================================================
//STEP020S EXEC PGM=SORT
//SORTIN   DD DSN=OVT-MATCHED.DAT,DISP=(OLD,DELETE)
//SORTOUT  DD DSN=OVT-SORTED2.DAT,DISP=(NEW,PASS)
//SYSIN    DD *
  SORT FIELDS=(1,8,CH,A,35,2,CH,A),EQUALS
/*
//*
//*=====================================================================
//* STEP020: キーブレイク集計
//*=====================================================================
//STEP020  EXEC PGM=ZAN05CAL,PARM='YEARMONTH=&YEARMONTH'
//ZAN05R01  DD DSN=OVT-SORTED2.DAT,DISP=(OLD,DELETE)
//ZAN05W01  DD DSN=OVT-SUMMARY.DAT,DISP=(NEW,PASS)

ZANJ025 — 残業統計DB更新

//ZANJ025  JOB (ACCT),'残業統計DB更新',CLASS=A
//*
//*--- パラメータ定義 ---
//SETPARM  SET YEARMONTH=202605
//*
//*=====================================================================
//* STEP025: DB更新(SORT不要)
//*=====================================================================
//STEP025  EXEC PGM=ZAN06UPD,PARM='YEARMONTH=&YEARMONTH'
//ZAN06R01  DD DSN=OVT-SUMMARY.DAT,DISP=(OLD,DELETE)
//ZAN06R02  DD DSN=OVT-DBCLEAN.DAT,DISP=(OLD,DELETE)
//ZAN06W01  DD DSN=ERROR-LOG.DAT,DISP=(NEW,PASS)

実行順序

BサブシステムのJOBは、AサブシステムのKINJ020(打刻チェック)出力を入力とする。 そのためJCL起動時は以下の順序を保証すること。

  1. Aサブシステム KINJ020KIN03PCK)→ EDITED-PUNCH生成
  2. Bサブシステム ZANJ010〜ZANJ025(必要時順次実行)

KINJ030(日別計算)は各打刻確定後であればいつでも実行可能で、ZANJ系列との依存関係はない。


プログラム詳細

STEP010: ZAN01CHK(残業申請振分処理) — 振り分け

項目 内容
プログラム名称 残業申請振分処理
PGMパターン 振り分け
SORT前処理 不要
入力ファイル OVT-APPLY80B / CSV形式)
出力ファイル OVT-VALID80B/ OVT-CANCEL80B/ ERROR-LOGVB
件数変化 N件 → 有効M件 + 取消K件 + 異常L件(M+K+L=N
使用共通関数 SUB01DAT(運用日付), SUB02MSG(メッセージ), SUB03ENDABEND, SUB04CHK(項目チェック)

入力CSVレコード例: A001,EMP001,20260610,1800,2000,0

機能:

  1. READ OVT-APPLY
  2. UNSTRING でCSVレコードを各項目に分解
  3. UNSTRING TALLYING でカンマ区切り数をカウント(項目数妥当性確認)
  4. EVALUATE でステータスを判定
    • 0 or 1 → 有効申請として次へ
    • 9 → OVT-CANCEL に書出し
    • その他 → エラーとして処理
  5. SUB04CHK で日付(DATE8)・時刻(TIME4)・社員番号(NUMERIC)を検証
  6. 加班時間計算(時刻はHHMM形式のため分単位に変換してから減算)
    開始分 = (開始時刻 / 100) * 60 + (開始時刻 - (開始時刻 / 100) * 100)
    終了分 = (終了時刻 / 100) * 60 + (終了時刻 - (終了時刻 / 100) * 100)
    加班時間(分) = 終了分 - 開始分
    
    • 開始時刻 < DINNER-START1830 → エラー(18:30以前は食事時間のため加班不可)
    • 加班時間 < 30分 → エラー(0.5h未満)
    • 開始時刻 ≧ 終了時刻 → エラー
  7. 通過 → OVT-VALID に書出し
  8. エラー → 該当レコードをERROR-LOG用01レコードにMOVEしてWRITE出力

新規カバレッジ構文:

構文 用途
UNSTRING CSVレコードの項目分解(TALLYING句で区切り数カウント)
STRING エラーレコード編集

STEP012: ZAN02CHK(時間帯重複チェック処理) — 項目チェック

項目 内容
プログラム名称 時間帯重複チェック処理
PGMパターン 項目チェック
SORT前処理 OVT-VALID → 社員番号+日付+開始時刻昇順
入力ファイル OVT-VSORT80B
出力ファイル OVT-NODUP80B/ ERROR-LOGVB
件数変化 M件 → 通過K件 + 重複エラー(M-K)件
使用共通関数 SUB01DAT(運用日付), SUB02MSG(メッセージ), SUB03ENDABEND

機能:

OVT-VSORT は既に社員番号+日付+開始時刻でソート済。順次READしながら直前レコードと比較する。

  1. READ OVT-VSORT → 現レコード取得成功
  2. 直前レコードと同一社員番号+日付 かつ 前終了時刻 > 現開始時刻 の場合 → 時間帯重複
    • 境界接続(前終了時刻 = 現開始時刻)は重複としない
  3. 重複 → ERROR-LOG へ
  4. 重複なし → OVT-NODUP へ書出し
  5. 社員番号 or 日付が変わったら直前レコードをリセット
  6. SET で重複有無フラグを設定

新規カバレッジ構文:

構文 用途
SET 重複有無フラグ設定
CONTINUE リセット時の空処理

STEP013: ZAN03CHK(打刻時間照合処理) — マッチング(N:1)

項目 内容
プログラム名称 打刻時間照合処理
PGMパターン マッチング(N:1)
SORT前処理 EDITED-PUNCH → 社員番号+日付昇順
入力ファイル OVT-NODUP80B/ PUNCH-SORTED80B
出力ファイル OVT-CHECKED80B/ ERROR-LOGVB
件数変化 K件 → 通過P件 + エラー(K-P)件
使用共通関数 SUB02MSG(メッセージ)

機能:

Step1:打刻時間内チェック

OVT-NODUP と PUNCH-SORTED を社員番号+日付で突合(共にソート済のため順次READで処理可)。

  1. READ OVT-NODUP → 現レコード
  2. 該当社員番号+日付の打刻レコードを PUNCH-SORTED から READ
  3. 打刻データあり かつ 以下を両方満たすことを確認:
    • 申請開始時刻 ≧ 出勤時刻
    • 申請終了時刻 ≦ 退勤時刻
  4. 範囲外 または 打刻データなし → ERROR-LOG

Step2:曜日判定

SEARCH ALL で休日マスタファイル(WORKING-STORAGE)を検索し、申請日の種別を判定。 Aサブシステムと同一の休日定義に従う(HOLIDAY-FILEファイル相当のデータを保持)。

休日ファイル初期化手順

初期処理(1000ITTSOR)でHOLIDAY-FILEを全件READし、WORKING-STORAGEのHOLIDAY-TABLEに格納する。

* 休日データ取得(ファイル読込み)
   OPEN INPUT HOLIDAY-FILE
   READ HOLIDAY-FILE
   ... 逐次処理
   CLOSE HOLIDAY-FILE
01  HOLIDAY-TABLE.
    05  HOLIDAY-CNT         PIC 9(004).
    05  HOLIDAY-DATA OCCURS 1 TO 366 TIMES
        DEPENDING ON HOLIDAY-CNT
        INDEXED BY HD-IDX.
        10  HD-DATE          PIC 9(008).
        10  HD-TYPE          PIC X(001).
            88  HD-HOLIDAY   VALUE 'H'.
SET HD-IDX TO 1
SEARCH ALL HOLIDAY-DATA
  AT END
    SET OVT-TYPE TO 'W'
  WHEN HD-DATE(HD-IDX) = APPL-DATE
    IF HD-HOLIDAY(HD-IDX)
      SET OVT-TYPE TO 'H'
    ELSE
      SET OVT-TYPE TO 'W'
    END-IF
END-SEARCH
  • HOLIDAY-FILE該当 → OVT-TYPE='H'
  • 該当なし → OVT-TYPE='W'

MOVE で OVT-TYPE を設定。

全通過レコードは OVT-TYPE を付加して OVT-CHECKED に書出し。

新規カバレッジ構文:

構文 用途
SEARCH ALL 休日マスタテーブル二分探索
SET テーブル添字操作

STEP015: ZAN04MAT(取消マッチング処理) — マッチング1:1

項目 内容
プログラム名称 取消マッチング処理
PGMパターン マッチング(1:1)
SORT前処理 OVT-CHECKED → 申請番号昇順
OVT-CANCEL → 申請番号昇順
入力ファイル OVT-SORTED80B/ OVT-CSORT80B
出力ファイル OVT-MATCHED80B/ OVT-DBCLEAN80B/ ERROR-LOGVB
件数変化 有効P件 + 取消R件 → 通過Q件 + 消滅S件 + DB削除T件(P=Q+S, R=S+T
使用共通関数 SUB01DAT(運用日付), SUB02MSG(メッセージ), SUB03ENDABEND

機能:

キー=申請番号(APPL-ID で OVT-SORTED(有効申請)と OVT-CSORT(取消)をマッチング1:1。

マッチング制御の分岐:

条件 結果 処理
SORTED.APPL-ID < CSORT.APPL-ID 申請のみ(取消なし) OVT-MATCHEDへ
SORTED.APPL-ID = CSORT.APPL-ID 両方あり(取消済) 消滅(出力なし)。ただし監査のため取消情報をERROR-LOGに記録(エラー区分=03、取消申請番号+原本データ)
SORTED.APPL-ID > CSORT.APPL-ID 取消のみ(既DB登録済) OVT-DBCLEANへ

同一申請番号グループ内の出力順に 処理番号(OA-PROC-SEQ を1から付与する。

STRING で申請情報を編集して OVT-MATCHED に書出す。

新規カバレッジ構文:

構文 用途
STRING 申請情報編集出力

STEP020: ZAN05CAL(残業時間集計処理) — キーブレイク集計

項目 内容
プログラム名称 残業時間集計処理
PGMパターン キーブレイク(集計)
SORT前処理 OVT-MATCHED → 申請番号+処理番号昇順
入力ファイル OVT-SORTED280B
出力ファイル OVT-SUMMARY80B
件数変化 Q件 → 申請番号ユニーク数(L件、L≦Q)
使用共通関数 SUB01DAT(運用日付), SUB02MSG(メッセージ), SUB03ENDABEND, SUB05TIM(時刻丸め)

機能:

Step1:キーブレイク制御

同一申請番号内に複数レコード(例:申請(0) + 承認済(1))がある場合、グループ内の最終レコードを集約結果として採用する。

入力(申請番号+処理番号昇順):
A001,EMP01,6/10,1800,2000,0  ← 申請(処理番号1
A001,EMP01,6/10,1800,2000,1  ← 承認済(処理番号2 → 最新)

集約結果: 承認済(1) を採用、申請(0) は捨てる
  • READ → 申請番号が変わるまで読み進める
  • ブレイク(申請番号切替)時に、直前に保持していたレコードを出力
  • グループ内の途中レコードは CONTINUE で読み飛ばす
  • SET で集約結果の有無フラグを設定

Step2:加班時間計算

終了時刻 - 開始時刻 を分数で計算 → DIVIDE で時間に変換。

DIVIDE 分 BY 60 GIVING 時間 REMAINDER 剰余

SUB05TIMmode 20.1h単位切捨) を呼び出して丸め処理。加班の丸めは0.1h単位切捨が正となる。

COMPUTE ROUNDED ON SIZE ERROR で内部計算のエラー処理。

COMPUTE WRK-OVT-HOURS ROUNDED = WRK-MINUTES / 60
  ON SIZE ERROR
    CONTINUE
    MOVE ZERO TO WRK-OVT-HOURS
END-COMPUTE

新規カバレッジ構文:

構文 用途
COMPUTE ROUNDED ON SIZE ERROR 丸め計算+エラー処理
DIVIDE 分→時間変換
CONTINUE キーブレイク制御の空分岐
SET 集計結果フラグ設定
ACCEPT FROM DATE 処理日付取得

STEP025: ZAN06UPD(残業統計DB更新処理) — DB更新

項目 内容
プログラム名称 残業統計DB更新処理
PGMパターン DB更新
SORT前処理 不要
入力ファイル OVT-SUMMARY80B/ OVT-DBCLEAN80B
出力ファイル OVERTIME-DBDB2/ ERROR-LOGVB
使用共通関数 SUB01DAT(運用日付), SUB02MSG(メッセージ), SUB03ENDABEND

機能:

全DB操作は埋め込みSQLEXEC SQL)で直接記述する。

処理1OVT-SUMMARY → DB登録

EXEC SQL でDB2にINSERT/UPDATEを発行する。

     EXEC SQL
         INSERT INTO OVT-APPLICATIONS
             (APPL-ID, EMP-ID, APPL-DATE, OVT-TYPE,
              START-TIME, END-TIME, OVT-HOURS, STATUS)
         VALUES
             (:WRK-APPL-ID, :WRK-EMP-ID, :WRK-APPL-DATE,
              :WRK-OVT-TYPE, :WRK-START-TIME, :WRK-END-TIME,
              :WRK-OVT-HOURS, :WRK-STATUS)
     END-EXEC.

     IF SQLCODE NOT = 0
     *   同一APPL-ID存在 → UPDATEに変更
         EXEC SQL
             UPDATE OVT-APPLICATIONS SET
                 STATUS = :WRK-STATUS,
                 UPDATED-AT = CURRENT TIMESTAMP
             WHERE APPL-ID = :WRK-APPL-ID
         END-EXEC
     END-IF.

OVT-MONTHLY のUPSERTも同様。

     EXEC SQL
         SELECT OVT-HOURS, OVT-COUNT
             INTO :DB-OVT-HOURS, :DB-OVT-COUNT
             FROM OVT-MONTHLY
             WHERE EMP-ID = :WRK-EMP-ID
               AND YEAR-MONTH = :WRK-YEAR-MONTH
               AND OVT-TYPE = :WRK-OVT-TYPE
     END-EXEC.

     IF SQLCODE = 0
     *   UPDATE(加算)
         EXEC SQL
             UPDATE OVT-MONTHLY SET
                 OVT-HOURS = OVT-HOURS + :WRK-OVT-HOURS,
                 OVT-COUNT = OVT-COUNT + 1,
                 UPDATED-AT = CURRENT TIMESTAMP
             WHERE EMP-ID = :WRK-EMP-ID
               AND YEAR-MONTH = :WRK-YEAR-MONTH
               AND OVT-TYPE = :WRK-OVT-TYPE
         END-EXEC
     ELSE
     *   INSERT(新規)
         EXEC SQL
             INSERT INTO OVT-MONTHLY
                 (EMP-ID, YEAR-MONTH, OVT-TYPE,
                  OVT-HOURS, OVT-COUNT, UPDATED-AT)
             VALUES
                 (:WRK-EMP-ID, :WRK-YEAR-MONTH, :WRK-OVT-TYPE,
                  :WRK-OVT-HOURS, 1, CURRENT TIMESTAMP)
         END-EXEC
     END-IF.

処理2OVT-DBCLEAN → DB取消

     EXEC SQL
         UPDATE OVT-APPLICATIONS SET
             STATUS = '9',
             UPDATED-AT = CURRENT TIMESTAMP
         WHERE APPL-ID = :WRK-APPL-ID
     END-EXEC.

     IF SQLCODE NOT = 0
        該当なし → ERROR-LOG に書出し
        PERFORM 9999ABDSOR
     END-IF.

OVT-MONTHLY の減算UPDATE

     EXEC SQL
         UPDATE OVT-MONTHLY SET
             OVT-HOURS = OVT-HOURS - :WRK-OVT-HOURS,
             OVT-COUNT = OVT-COUNT - 1,
             UPDATED-AT = CURRENT TIMESTAMP
         WHERE EMP-ID = :WRK-EMP-ID
           AND YEAR-MONTH = :WRK-YEAR-MONTH
           AND OVT-TYPE = :WRK-OVT-TYPE
     END-EXEC.

     IF SQLCODE NOT = 0
     *   OVT-MONTHLYレコード不存在 → データ不整合の可能性
        該当エラー → ERROR-LOG に書出し
        PERFORM 9999ABDSOR
     END-IF.

注意: OVT-MONTHLY減算UPDATEの失敗時は、OVT-MONTHLYに対応レコードが存在しないことを意味する。 ファイルとDBの不整合としてエラーログに記録した上でABENDさせる。

SQLCODE でDB操作の成否を確認し、異常時は ERROR-LOG に出力。

新規カバレッジ構文:

構文 用途
EXEC SQL DB2埋め込みSQLによるDB操作
IF SQLCODE判定による分岐
PERFORM VARYING 月バリデーションループ(1〜12月)
PERFORM TEST AFTER OVT-MONTHLY減算リトライ制御
MULTIPLY 時間→分変換(MULTIPLY BY 60 GIVING
SUBTRACT 残容量検証(SUBTRACT FROM GIVING

レコード構成

OVT-VALID / OVT-CANCEL / OVT-NODUP / OVT-CHECKED80B

# 項目 名称 開始 長さ 属性 備考
1 申請番号 OA-APPL-ID 1 8 X(8)
2 社員番号 OA-EMP-ID 9 8 9(8)
3 申請日 OA-APPL-DATE 17 8 9(8) YYYYMMDD
4 開始時刻 OA-START-TIME 25 4 9(4) HHMM
5 終了時刻 OA-END-TIME 29 4 9(4) HHMM
6 ステータス OA-STATUS 33 1 X(1) 0/1/9
7 OVT-TYPE OA-OVT-TYPE 34 1 X(1) W/HOVT-CHECKED以降のみ有効)
8 予備 OA-FILLER 35 46 X(46)

OVT-MATCHED80B

# 項目 名称 開始 長さ 属性 備考
1 申請番号 OA-APPL-ID 1 8 X(8)
2 社員番号 OA-EMP-ID 9 8 9(8)
3 申請日 OA-APPL-DATE 17 8 9(8) YYYYMMDD
4 開始時刻 OA-START-TIME 25 4 9(4) HHMM
5 終了時刻 OA-END-TIME 29 4 9(4) HHMM
6 ステータス OA-STATUS 33 1 X(1) 0/1
7 OVT-TYPE OA-OVT-TYPE 34 1 X(1) W/H
8 処理番号 OA-PROC-SEQ 35 2 9(2) 同申請内連番
9 予備 OA-FILLER 37 44 X(44)

社員名・部署コードは DB2OVT-APPLICATIONSテーブル)側で保持する。

OVT-SUMMARY80B

# 項目 名称 開始 長さ 属性 備考
1 申請番号 OS-APPL-ID 1 8 X(8)
2 社員番号 OS-EMP-ID 9 8 9(8)
3 申請日 OS-APPL-DATE 17 8 9(8) YYYYMMDD
4 開始時刻 OS-START-TIME 25 4 9(4) HHMM
5 終了時刻 OS-END-TIME 29 4 9(4) HHMM
6 加班時間 OS-OVT-HOURS 33 5 9(4)V9(1) SUB05TIM丸め後
7 OVT-TYPE OS-OVT-TYPE 38 1 X(1) W/H
8 予備 OS-FILLER 39 42 X(42)

OVT-DBCLEAN80B

# 項目 名称 開始 長さ 属性
1 申請番号 OD-APPL-ID 1 8 X(8)
2 予備 OD-FILLER 9 72 X(72)

新規COBOL構文カバレッジ一覧(14種)

# 構文 ZAN01CHK ZAN02CHK ZAN03CHK ZAN04MAT ZAN05CAL ZAN06UPD
1 UNSTRING
2 STRING
3 SEARCH ALL
4 SET
5 COMPUTE ROUNDED ON SIZE ERROR
6 DIVIDE
7 CONTINUE
8 ACCEPT FROM DATE
9 EXEC SQLINSERT/UPDATE/SELECT/COMMIT/ROLLBACK
10 IFSQLCODE分岐)
11 PERFORM VARYING
12 PERFORM TEST AFTER
13 MULTIPLY
14 SUBTRACT

丸めルール

条件 ルール
加班開始時刻 < DINNER-START1830 エラー(申請不可、食事時間のため)
加班時間 < 30分 エラー(申請不可)
加班時間 ≧ 30分 かつ < 0.5h換算 0.5hに切上
加班時間 ≧ 0.5h 0.1h単位切捨(SUB05TIM mode 2

例:0.5h→0.5, 0.7h→0.7, 1.55h→1.5(切捨のため1.5、切上なら1.6)