# 実消化&アルトマーク 日次バッチ

## 概要

実消化&アルトマークの日次バッチ処理。

## 環境情報

- Python 3.9
- MySQL 8.23
- VSCode

## 環境構築

- Python の構築

  - Merck_NewDWH 開発 2021 の Wiki、[Python 環境構築](https://nds-tyo.backlog.com/alias/wiki/1874930)を参照
    - 「Pipenv の導入」までを行っておくこと
  - 構築完了後、プロジェクト配下で以下のコマンドを実行し、Python の仮想環境を作成する
    - `pipenv install --dev --python <pyenvでインストールしたpythonバージョン>`
    - この手順で出力される仮想環境のパスは、後述する VSCode の設定手順で使用するため、控えておく

- MySQL の環境構築
  - Windows の場合、以下のリンクからダウンロードする
    - <https://dev.mysql.com/downloads/installer/>
  - Docker を利用する場合、「newsdwh-tools」リポジトリの MySQL 設定を使用すると便利
    - 「crm-table-to-ddl」フォルダ内で以下のコマンドを実行すると
      - `docker-compose up -d`
      - Docker の構築手順は、[Docker のセットアップ手順](https://nds-tyo.backlog.com/alias/wiki/1754332)を参照のこと
  - データを投入する
    - 立ち上げたデータベースに「src05」スキーマを作成する
    - [ローカル開発用データ](https://ndstokyo.sharepoint.com/:f:/r/sites/merck-new-dwh-team/Shared%20Documents/03.NewDWH%E6%A7%8B%E7%AF%89%E3%83%95%E3%82%A7%E3%83%BC%E3%82%BA3/02.%E9%96%8B%E7%99%BA/90.%E9%96%8B%E7%99%BA%E5%85%B1%E6%9C%89/%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E9%96%8B%E7%99%BA%E7%94%A8%E3%83%87%E3%83%BC%E3%82%BF?csf=1&web=1&e=VVcRUs)をダウンロードし、mysql コマンドを使用して復元する
      - `mysql -h <ホスト名> -P <ポート> -u <ユーザー名> -p src05 < src05_dump.sql`
- 環境変数の設定
  - 「.env.example」ファイルをコピーし、「.env」ファイルを作成する
  - 環境変数を設定する。設定内容は PRJ メンバーより共有を受けてください
- VSCode の設定
  - 「.vscode/recommended_settings.json」ファイルをコピーし、「settings.json」ファイルを作成する
  - 「python.defaultInterpreterPath」を、Python の構築手順で作成した仮想環境のパスに変更する

## 実行

- VSCode 上で「F5」キーを押下すると、バッチ処理が起動する。
- 「entrypoint.py」が、バッチ処理のエントリーポイント。
- 実際の処理は、「src/jobctrl_daily.py」で行っている。

## 単体テスト(アルトマーク取込処理)

アルトマーク取込処理は、単体テストコードを使用してテスト自動化を行う

### テスト準備

- VSCodeで以下の拡張機能をインストールする
  - Python
  - Python Test Explorer for Visual Studio Code
  - Test Explorer UI
- VSCode 上でショートカット「ctrl」+「shift」+「P」でコマンドパレットを開く
- コマンドパレットの検索窓に「Python」と入力し、「Python: テストを構成する」を押下する
- 現在のワークスペースを選び、「pytest」を選択する
- 「tests」フォルダを選択する
- バックグランドで、pytest モジュールのインストールが始まれば成功

### テスト用のサブコマンド一覧

- `pipenv run`のあとに、サブコマンドとしてユーザー定義スクリプトを実行できる
  - `Pipfile`内の「scripts」セクションに宣言されている

| コマンド         | 概要                                                                                         |
| ---------------- | -------------------------------------------------------------------------------------------- |
| test:ultmarc     | tests/batch/ultmarc フォルダ配下のユニットテストを実行する                                   |
| test:ultmarc:cov | tests/batch/ultmarc フォルダ配下のユニットテストを実行し、テストカバレッジを取得する(C0, C1) |

### テスト共通関数の仕様

- tests/testing_utility.py内の共通関数の仕様について記載する

#### create_ultmarc_test_data_from_csv

- 引数
  - file_path: str
- 戻り値
  - src.batch.ultmarc.datfile.DatFileのインスタンス
- 処理概要
  - CSVファイルから、アルトマークのインプットデータを作成する
  - データフォーマットは以下
    - 文字コード: UTF-8
    - 改行コード：LF
    - ヘッダ: なし
    - 値囲い: ダブルクォート
  - アルトマークデータと文字コードを合わせるため、指定されたファイルを一時ディレクトリに、文字コード「cp932」で書き出してからテストデータとして読み込む
  - テストデータそのものはUTF-8の文字コードで作成すること

### create_db_data_from_csv

- 引数
  - file_path: str
- 戻り値
  - テーブルのレコードに相当する辞書のリスト
- 処理概要
  - CSVファイルから、アルトマークテーブルに相当するテストデータを作成する
  - テストの初期データ、期待値データを作成するのに利用する
  - データフォーマットは以下
    - 文字コード: UTF-8
    - 改行コード：LF
    - ヘッダ: なし
    - 値囲い: ダブルクォート
  - ファイル内の、以下の形式のデータを自動的に変換する
    - `NULL`
      - `None`に変換される
    - `yyyy-mm-dd`もしくは、`yyyy/mm/dd`の文字
      - Date型に変換される
    - `yyyy-mm-dd hh:mm:ss`もしくは、`yyyy/mm/dd hh:mm:ss`の文字
      - DateTime型に変換される

### create_insert_sql_with_parameter

- 引数
  - table_name: str テーブル名
  - column_names: list[str] カラム名のリスト
  - test_data: list[str]: 値のリスト
- 戻り値
  - INSERT文とバインドパラメータ辞書
- 処理概要
  - 引数を使用して、`src.db.Database#execute`メソッドで実行可能な形でINSERT文、バインドパラメータを作成する

### create_delete_sql_with_parameter

- 引数
  - table_name: str テーブル名
  - column_names: list[str] カラム名のリスト
  - test_data: list[str]: 値のリスト
- 戻り値
  - DELETE文とバインドパラメータ辞書
- 処理概要
  - 引数を使用して、`src.db.Database#execute`メソッドで実行可能な形でDELETE文、バインドパラメータを作成する

### create_ultmarc_table_mapper_sut

- 引数
  - line: src.batch.ultmarc.datfile.DatFileLine アルトマークデータファイルの1行
  - db: src.db.Database データベース操作クラス
- 戻り値
  - マッパークラス
- 処理概要
  - src.batch.ultmarc.utmp_tables.ultmarc_table_mapper_factory.UltmarcTableMapperFactoryを通じて、テスト対象のマッパークラスを生成して返す

### assert_table_results

- 引数
  - actual_rows: list[dict] テスト結果の辞書リスト
  - expect_rows: list[dict] 期待値の辞書リスト
  - ignore_col_name: list 比較を無視するDBのカラム名. Default None.
- 戻り値
  - なし
- 処理概要
  - テスト結果データと期待値データを突き合わせ、期待値どおりとなっているかを確認する
  - ignore_col_nameに指定したカラムは、呼び出し元のテストコード内で個別に突き合わせする


## 単体テスト(実消化データ取込処理)

実消化データは、単体テストコードを使用してテスト自動化を行う

### テスト準備

※単体テスト(アルトマーク取込処理)と同じ

### テスト用のサブコマンド一覧

- `pipenv run`のあとに、サブコマンドとしてユーザー定義スクリプトを実行できる
  - `Pipfile`内の「scripts」セクションに宣言されている

| コマンド         | 概要                                                                                         |
| ---------------- | -------------------------------------------------------------------------------------------- |
| test:vjsk     | tests/batch/vjsk フォルダ配下のユニットテストを実行する                                   |
| test:vjsk:cov | tests/batch/vjsk フォルダ配下のユニットテストを実行し、テストカバレッジを取得する(C0, C1) |

### テスト共通関数の仕様

- tests/testing_vjsk_utility.py内の共通関数の仕様について記載する

#### create_vjsk_assertion_list

- 概要
  - DB登録期待値リストを作成する
- Args:
  - file_path (str): DB登録期待値ファイル(tsvファイル)のパス
    - memo: ※DB登録期待値ファイルの前提
    - memo:   受領データファイルと同じ
    - memo:   BOM付きtsv形式
    - memo:   一行目はカラム名になっているヘッダ行
  - Returns:
    - List(dict) DB登録期待値辞書リスト


## フォルダ構成

```text
.
├── Pipfile                                                     -- Pythonモジュールの依存関係を管理するファイル
├── Dockerfile                                                  -- Dockerイメージを作成するためのファイル
├── Pipfile                                                     -- Pythonモジュールの依存関係を管理するファイル
├── Pipfile.lock                                                -- Pythonモジュールの依存関係バージョン固定用ファイル
├── README.md                                                   -- 当ファイル
├── entrypoint.py                                               -- バッチ処理のエントリーポイントになるpythonファイル
├── src                                                         -- ソースコードの保管場所
│   ├── aws                                                     -- AWS関連処理
│   │   └── s3.py                                               -- S3クライアントとバケット処理
│   ├── batch                                                   -- バッチ処理関連ソース置き場
│   │   ├── batch_functions.py                                  -- バッチ処理共通関数置き場
│   │   ├── datachange                                          -- 実績洗替関連ソース置き場
│   │   │   └── emp_chg_inst_lau.py                             -- 施設担当者マスタ洗替
│   │   └── jissekiaraigae.py                                   -- 実績洗替処理のエントリーポイント
│   │   └── ultmarc                                             -- アルトマーク関連処理
│   │       ├── ultmarc_process.py                              -- アルトマーク関連処理のエントリーポイント
│   │       ├── datfile.py                                      -- データファイル読込
│   │       └── utmp_tables                                     -- アルトマークテーブルへの登録関連
│   │           ├── table_mapper                                -- テーブルへのデータマッピング処理
│   │           │   ├── concrete                                -- テーブルマッパーのマッピング処理を行う具象クラス(全テーブル分)
│   │           │   │   ├── com_alma_mapper.py
│   │           │   │   ├── ...
│   │           │   │   └── null_mapper.py                      -- テスト用、空振りするマッパークラス
│   │           │   └── ultmarc_table_mapper.py                 -- テーブルへの登録処理を行う抽象クラス
│   │           ├── tables                                      -- アルトマークデータのDTOクラス(全テーブル分)
│   │           │   ├── com_alma.py
│   │           │   ├── ...
│   │           │   └── ultmarc_table.py                        -- アルトマークテーブルの抽象クラス
│   │           └── ultmarc_table_mapper_factory.py             -- テーブルマッパー生成クラス
│   ├── db
│   │   └── database.py                                         -- データベース操作共通処理
│   ├── error
│   │   └── exceptions.py                                       -- カスタム例外
│   ├── jobctrl_daily.py                                        -- 日次バッチ処理のエントリーポイント。「entrypoint.py」 から呼ばれる。
│   ├── logging
│   │   └── get_logger.py                                       -- ログ出力の共通処理
│   ├── system_var
│   │   └── environment.py                                      -- 環境変数
│   └── time
│       └── elapsed_time.py                                     -- 実行時間計測用
└── tests                                                       -- ユニットテストのルートディレクト
    ├── batch
    │   └── ultmarc                                             -- アルトマーク関連のユニットテストを格納する
    │   │  └── utmp_tables
    │   │      └── table_mapper                                -- 以下、マッパークラス単位でフォルダを切る
    │   │          └── com_alma
    │   │              ├── test_com_alma_mapper.py             -- テストコード本体
    │   │              ├── com_alma_insert.csv                 -- S3に配置される想定のテストCSVデータ。ケースごとに用意する。
    │   │              ...
    │   │              ├── db_com_alma_before_update.csv       -- テスト時に事前にDBに登録しておくデータ。CSVで用意する。
    │   │              ...
    │   │              ├── expect_com_alma_insert.csv          -- テストの期待値データ。CSVで用意する。
    │   │              ...
    │   └─vjsk                                                 -- 実消化データ取込処理関連のユニットテストを格納する
    │       │
    │       ├─vjsk_file_check                                  -- 受領ファイルチェック処理関連のユニットテストを格納する
    │       │  ├─conftest.py                                    -- テスト内で共通利用できるフィクスチャの宣言
    │       │  └─test_vjsk_file_check.py                        -- テストクラス本体
    │       │
    │       └─vjsk_load                                        -- 受領データ登録処理関連のユニットテストを格納する
    │           │  conftest.py                                  -- テスト内で共通利用できるフィクスチャの宣言
    │           │  test_vjsk_load.py                            -- テストクラス本体
    │           │  
    │           └─testdata                                     -- テストモジュールが使用するテストデータを格納する
    │               │  bio_slip_data_202304280000.tsv           -- 正常ケースの単体確認用
    │               │  ...                                      -- *20230428* は新規4件の登録確認用
    │               │  whs_mst_202304290000.tsv                 -- *20230429* は更新2件+追加新規2件の登録確認用
    │               │  
    │               ├─NoData                                   -- 正常ケースの単体確認用
    │               │      bio_slip_data_nodatarecord.tsv       -- ヘッダ行のみでデータが0件の動作確認用
    │               │      ...
    │               │      whs_mst_nodatarecord.tsv
    │               │      
    │               ├─TestFormatErrorFile                      -- 異常ケースの単体確認用
    │               │      bio_slip_data_formaterror.tsv        -- 末尾行のタブ数が想定と異なる(ファイル欠落がある)ときの動作確認用
    │               │      ...
    │               │      whs_mst_formaterror.tsv
    │               │      
    │               ├─TestImportFileToDb                       -- 正常ケースの単体確認用
    │               │      bio_slip_data_202304270000.gz        -- 対向元システムから送られてきた状態(gz圧縮)の受領データファイルの動作確認用
    │               │      ...
    │               │      whs_mst_202304270000.gz
    │               │      
    │               └─UnzipError                               -- 異常ケースの単体確認用
    │                       bio_slip_data_202304270000.gz       -- gz圧縮ファイルが解凍できないときの動作確認用
    │                       ...
    │                       whs_mst_202304270000.gz
    │                       
    ├── conftest.py                                             -- テスト内で共通利用できるフィクスチャを宣言する(執筆時点ではDBのみ)
    ├── testing_utility.py                                      -- テストの共通関数
    └── testing_vjsk_utility.py                                 -- テストの共通関数(実消化データ取込処理関連)
```

