Compare commits

...

275 Commits

Author SHA1 Message Date
朝倉 明日香
19f348ee2a Merge pull request #515 feature-NEWDWH2021-1932 into develop 2025-06-30 09:04:57 +09:00
yono
3266241ec3 fix:卸プルダウンに卸名が表示されないバグ修正 2025-06-27 14:38:12 +09:00
朝倉 明日香
c774c9aa3a Merge pull request #513 feature-NEWDWH2021-1928 into develop 2025-06-27 13:54:36 +09:00
朝倉 明日香
5940c872dc Merge pull request #514 feature-NEWDWH2021-1927 into develop 2025-06-27 12:40:02 +09:00
yono
61a86b6789 fix:フォルダ丸ごとzipされてしまうバグの解消 2025-06-21 22:26:27 +09:00
yono
b70974b28f fix:条件項目が文字列型8桁,6桁,日付型で来られても大丈夫なように修正 2025-06-21 22:20:34 +09:00
yono
686ee9378c fix:列幅を再修正 2025-06-21 16:33:28 +09:00
yono
6408c38bc3 fix:生物由来Excel出力時の列幅を修正 2025-06-21 01:50:54 +09:00
朝倉 明日香
05195b7b31 Merge pull request #510 feature-NEWDWH2021-1926 into develop 2025-06-20 09:27:54 +09:00
shimoda.m@nds-tyo.co.jp
e26180c820 fix: バグ修正。バッチステータス管理テーブルのレコードがdoneならないのを修正 2025-06-20 09:13:22 +09:00
下田雅人
d4186596f3 Merge pull request #509 feature-NEWDWH2021-1925 into develop 2025-06-19 18:10:28 +09:00
yono
69929a014f feat:タイムスタンプカラム削除対応 2025-06-19 17:37:29 +09:00
小野 祥照
df1ccf0e86 Merge pull request #508 featrue-NEWDWH2021-1869-fix-sql into develop 2025-06-19 16:14:26 +09:00
mori.k
77e6fd5e96 sqlのカラム名が間違っていたため修正 2025-06-19 16:03:28 +09:00
下田雅人
d967bccfa5 Merge pull request #507 featrue-NEWDWH2021-1923 into develop 2025-06-17 17:42:25 +09:00
mori.k
327ab9da78 csv出力時の値囲いに関する部分と改行コードが誤っていた部分の修正 2025-06-17 17:24:36 +09:00
下田雅人
724a5d6e53 Merge pull request #506 feature-NEWDWH2021-1922 into develop 2025-06-17 16:57:01 +09:00
mori.k
abeb325ec5 CSV出力時にinst_repre_cd,inst_repre_kana,inst_repreを出力しないよう変更 2025-06-17 16:29:29 +09:00
mori.k
691831742b 大文字を小文字に修正 2025-06-17 15:58:39 +09:00
mori.k
50c0ea95b3 実態に合わせたメソッド名と変数名のリファクタリング 2025-06-17 14:30:10 +09:00
mori.k
28d8fe1133 出力csvから移行先DCF施設コードを除外し、値囲いなしに変更 2025-06-17 13:59:30 +09:00
下田雅人
17b2f5bfb1 Merge pull request #505 feature-NEWDWH2021-1920 into develop 2025-06-16 17:08:05 +09:00
shimoda.m@nds-tyo.co.jp
8418c09d1e feat: レビュー指摘対応 2025-06-16 17:01:05 +09:00
shimoda.m@nds-tyo.co.jp
d2dc096468 feat: 実消化取込用の設定ファイルに拡張SQL実行フラグを追加 2025-06-16 16:23:33 +09:00
shimoda.m@nds-tyo.co.jp
2885b56c0c feat: 0バイトファイルの時に拡張SQLを実行するかどうかのフラグを追加 2025-06-16 16:13:13 +09:00
下田雅人
7b35ca9e97 Merge pull request #504 feature-NEWDWH2021-1921 into develop 2025-06-16 16:05:46 +09:00
shimoda.m@nds-tyo.co.jp
4995164d3f fix: 環境変数の読み込み不備を修正。例外がキャッチできていなかったため、Exceptionでキャッチするように修正。 2025-06-16 15:23:06 +09:00
下田雅人
ced1d110c5 Merge pull request #503 feature-NEWDWH2021-1873 into develop 2025-06-13 12:18:08 +09:00
下田雅人
6cb8024b8e Merge pull request #500 featrue-NEWDWH2021-1866 into develop 2025-06-13 12:17:26 +09:00
下田雅人
0d16f26f5c Merge pull request #502 feature-NEWDWH2021-1873-fix-file-row-cnt into develop 2025-06-13 12:16:58 +09:00
yono
646ab44a0b fix:バグ修正 2025-06-12 19:28:42 +09:00
shimoda.m@nds-tyo.co.jp
9bd19142ea format: フォーマット修正 2025-06-12 14:52:24 +09:00
mori.k
92f250abdc 起動条件を満たしていない場合のログを表示 2025-06-12 14:41:10 +09:00
mori.k
b7f20012f2 環境変数JSK_BACKUP_FOLDERの追加 2025-06-12 14:25:24 +09:00
mori.k
77b389bbe2 誤判定防止の修正 2025-06-12 13:37:35 +09:00
shimoda.m@nds-tyo.co.jp
11c6945473 fix: 1行コミットモードのデグレ修正。インデントがズレており、ループの1回目で結果を返すようになってしまっていた。 2025-06-11 21:13:41 +09:00
shimoda.m@nds-tyo.co.jp
277950ba8d fix: 処理件数と正常終了件数を個別で取得。件数に差がある場合は重複レコードがある可能性があるとワーニングを出力。 2025-06-11 19:23:56 +09:00
小野 祥照
fabd63d2d8 Merge pull request #501 NEWDWH2021-1903 into develop 2025-06-11 15:15:10 +09:00
mori.k
18643e0a22 環境変数が不足していた部分の修正 2025-06-11 14:02:31 +09:00
mori.k
05026c6213 誤った判定をしていた部分の修正とステータスをdoingに変更する部分の追加 2025-06-11 13:55:16 +09:00
shimoda.m@nds-tyo.co.jp
fd1d7bc7f2 fix: バグ修正。0Byteファイルだった場合に取込フォルダからファイルを削除する。 2025-06-11 11:47:25 +09:00
小野 祥照
c6d7344307 Merge pull request #498 feature-NEWDWH2021-1917 into develop 2025-06-11 08:39:01 +09:00
shimoda.m@nds-tyo.co.jp
846afc56dd feat: 個別設定ファイルの圧縮形式をgzipに変更 2025-06-10 16:30:03 +09:00
shimoda.m@nds-tyo.co.jp
363a177559 feat: gz解凍に対応 2025-06-10 16:13:37 +09:00
shimoda.m@nds-tyo.co.jp
6d7917a7f7 refactor: ファイル展開処理を共通化するにあたり、定数の重複をcommonに一本化。 2025-06-10 14:10:11 +09:00
下田雅人
db57fd22bc Merge pull request #497 featrue-NEWDWH2021-1876 into develop 2025-06-10 11:47:14 +09:00
mori.k
daecbd3464 指摘漏れの対応 2025-06-10 10:56:15 +09:00
mori.k
ec4c8e6463 構文エラーの部分の削除と設定ファイルの修正 2025-06-10 09:20:08 +09:00
shimoda.m@nds-tyo.co.jp
64c8178460 format: 未使用のimportと変数を削除。フォーマット適用。 2025-06-09 17:59:18 +09:00
mori.k
403ce3827e JskultBatchStatusManagerの引数を修正 2025-06-09 16:30:09 +09:00
mori.k
7abe373a95 Merge branch 'develop' into featrue-NEWDWH2021-1876 2025-06-09 14:51:34 +09:00
mori.k
fc5de5f81f SQL文の誤りを修正 2025-06-06 18:54:22 +09:00
朝倉 明日香
2091623df3 Merge pull request #496 feature-NEWDWH2021-1916 into develop 2025-06-06 18:29:55 +09:00
shimoda.m@nds-tyo.co.jp
e4c2a5c45d fix: アルトマークデータ取込が完了したら、バッチステータス管理は完了とする。
データ出力でエラーが起きてもバッチステータスは書き換えない。
2025-06-06 17:58:55 +09:00
shimoda.m@nds-tyo.co.jp
3e9d0c612d feat: アルトマークデータの転送処理も修正。 2025-06-06 17:58:17 +09:00
shimoda.m@nds-tyo.co.jp
1d4f20429e feat: 転送前にファイルプレフィックスの重複を確認するように修正。 2025-06-06 16:30:31 +09:00
shimoda.m@nds-tyo.co.jp
f05ec64f41 refactor: ファイル情報をdictで取り回していたが、意味ないためstrで取り回すように修正。不要なメソッドを削除。 2025-06-06 15:52:27 +09:00
朝倉 明日香
a3be8d39e3 Merge pull request #494 feaure-NEWDWH2021-1878 into develop 2025-06-06 11:15:55 +09:00
朝倉 明日香
f873854edc Merge pull request #495 feature-NEWDWH2021-1875 into develop 2025-06-06 11:15:26 +09:00
朝倉 明日香
5f7d409055 Merge pull request #493 feature-NEWDWH2021-1873 into develop 2025-06-06 11:14:33 +09:00
mori.k
2ad67967fa derived_mergeフラグに関する部分を削除 2025-06-06 09:02:25 +09:00
下田雅人
53e0c0148d Merge pull request #491 feature-NEWDWH2021-1874 into develop 2025-06-05 20:03:36 +09:00
yono
1ba9435dc1 fix;バグ修正 2025-06-05 18:30:57 +09:00
shimoda.m@nds-tyo.co.jp
6caf664830 feat: 個別設定ファイルに拡張SQLファイル名を追加 2025-06-05 17:57:52 +09:00
shimoda.m@nds-tyo.co.jp
aa5a6bfbdd feat: 拡張SQLを作成 2025-06-05 17:57:04 +09:00
mori.k
1cede4be06 ログが出ていなかった部分と定数の置き換えとバグ修正 2025-06-05 17:24:17 +09:00
shimoda.m@nds-tyo.co.jp
8ae3b91d5c fix: 起動条件を満たしていない場合のログ出力を追加 2025-06-05 15:48:42 +09:00
shimoda.m@nds-tyo.co.jp
108d6ff50b Merge branch 'develop' into feature-NEWDWH2021-1875 2025-06-05 13:46:40 +09:00
下田雅人
e47cbab72f Merge pull request #492 feature-NEWDWH2021-1865 into develop 2025-06-05 13:45:34 +09:00
shimoda.m@nds-tyo.co.jp
bb64d5d732 feat: フォーマット、コメント追加 2025-06-05 13:43:40 +09:00
shimoda.m@nds-tyo.co.jp
5581fb9141 feat: SQLにコメント追加 2025-06-05 13:42:27 +09:00
mori.k
80b4562a32 アーカイブ取得日を変更 2025-06-05 11:55:53 +09:00
mori.k
c8b1bf19a8 再レビュー結果の反映 2025-06-05 10:52:58 +09:00
shimoda.m@nds-tyo.co.jp
dc18487b17 feat: SQLの実行順序を設計書通りに変更 2025-06-05 10:06:16 +09:00
mori.k
5bde7acbd8 レビュー指摘対応 2025-06-05 09:54:34 +09:00
mori.k
0cb7ac281a 実消化転送データ一覧の取得、不足ファイルの判定と受領予定にないファイルの判定の実装 2025-06-04 16:43:37 +09:00
shimoda.m@nds-tyo.co.jp
2f4e2125ef fix: 転送データ一覧取得に失敗した場合returnするように修正 2025-06-04 13:48:21 +09:00
shimoda.m@nds-tyo.co.jp
3aab4bf68f fix: 転送ファイル一覧の取得に失敗したときにreturnしていなかったのを修正 2025-06-04 13:45:23 +09:00
shimoda.m@nds-tyo.co.jp
629482507a fix: 判定するカラム修正 2025-06-04 13:44:18 +09:00
mori.k
41ae0841f2 レビュー指摘対応:後続処理の実行が完了していない場合の処理 2025-06-04 10:52:57 +09:00
mori.k
ce1c7b6527 レビュー指摘対応 2025-06-04 10:27:59 +09:00
shimoda.m@nds-tyo.co.jp
b7c3b8ca11 fix: バグ修正 2025-06-04 10:08:44 +09:00
yono
60fa0ebfed fix:卸検索取得項目をロット分解に変更。卸検索時の検索をコードでなく卸名を画面から送るように変更 2025-06-04 09:27:49 +09:00
mori.k
fae67ae4e7 実消化データアーカイブ取得処理を実行する処理の実装とTODOの整理 2025-06-03 19:33:00 +09:00
shimoda.m@nds-tyo.co.jp
af6d995e6d refactor: リテラルを定数化。環境変数ファイルにフォーマット適用 2025-06-03 18:38:48 +09:00
mori.k
3607229dee 不要部分の削除 2025-06-03 18:37:08 +09:00
shimoda.m@nds-tyo.co.jp
31a8f79fca format: フォーマット適用 2025-06-03 18:27:32 +09:00
shimoda.m@nds-tyo.co.jp
bfac318785 Merge branch 'develop' into feature-NEWDWH2021-1874 2025-06-03 17:57:44 +09:00
mori.k
e8253f27da 不足ファイルの比較と受領予定にないファイルの比較以外の部分の実装とアーカイブ関連の取り込み 2025-06-03 17:46:41 +09:00
mori.k
2783da3328 日付テーブル更新 first commit 2025-06-03 10:00:49 +09:00
shimoda.m@nds-tyo.co.jp
7e8141a9d9 fix: バグ修正 2025-06-03 09:07:07 +09:00
森 一真
655e512f0d Merge pull request #490 featrue-NEWDWH2021-1869 into develop 2025-06-02 18:45:06 +09:00
mori.k
8b32d83bc8 閉じ括弧のインデント修正 2025-06-02 18:35:46 +09:00
mori.k
822d57e878 JOIN句をINNER JOINに変更し、タブ文字を排除 2025-06-02 18:27:51 +09:00
mori.k
02319c4876 inst_clas_cdの条件の修正 2025-06-02 18:14:53 +09:00
下田雅人
42fbde2190 Merge pull request #485 feature-NEWDWH2021-1864 into develop 2025-06-02 17:57:18 +09:00
mori.k
ca744f1eed JskultBatchRunManagerの引数とset_process_statusの引数の修正 2025-06-02 17:36:40 +09:00
mori.k
75d4f85bb2 独自施設マスタからのinsertの実装 2025-06-02 17:15:31 +09:00
小野 祥照
4f523c4e5f Merge pull request #489 feature-NEWDWH2021-1862 into develop 2025-06-02 16:56:51 +09:00
mori.k
a232923909 レビュー指摘対応とset_process_statusの引数を変更 2025-06-02 14:59:35 +09:00
yono
3e7b8b5497 feat: mst_instソース名修正漏れ 2025-06-02 14:58:18 +09:00
yono
9a23cb70a0 feat:zip形式対応、ミス修正、mst_instのソース名修正 2025-06-02 12:21:46 +09:00
mori.k
80da987224 COM_薬局からのinsert 2025-06-02 10:15:20 +09:00
下田雅人
2960df679d Merge pull request #488 feature-NEWDWH2021-1908 into develop 2025-06-02 08:40:13 +09:00
yono
0651b4372d feat:新実消化設定ファイル作成 2025-05-31 16:56:53 +09:00
小野 祥照
81edd98ee1 Merge pull request #487 feature-NEWDWH2021-1910 into develop 2025-05-31 14:40:49 +09:00
mori.k
77d1ca41f5 環境変数のバリデーションチェックの修正 2025-05-30 18:19:29 +09:00
mori.k
f5953877fc アルトマーク施設マスタのinsertの実装 2025-05-30 18:14:43 +09:00
shimoda.m@nds-tyo.co.jp
58abea45be fix: アルトマーク取込のバックアップ先がおかしかったので修正 2025-05-30 18:02:58 +09:00
shimoda.m@nds-tyo.co.jp
e912c5a080 ix: 動くように修正 2025-05-30 18:02:38 +09:00
mori.k
32a0c8d5c3 インスタンス化の部分の修正 2025-05-30 15:13:12 +09:00
mori.k
ed55a30bf1 環境変数のバリデーションチェックの実装 2025-05-30 15:08:15 +09:00
mori.k
fe26aa38cf feat: jskult-batch内の各機能事に使う環境変数を切り分けられるようにクラス化 2025-05-30 14:23:57 +09:00
mori.k
5a2afba6cc 環境変数バリデーションチェック 指摘対応対応 2025-05-30 14:10:30 +09:00
shimoda.m@nds-tyo.co.jp
cd21cbb79a feat: 環境変数の必須チェックはコンストラクタで行う 2025-05-30 13:43:53 +09:00
mori.k
40207bcad4 処理の始めに環境変数バリデーションチェックの追加 2025-05-30 13:22:45 +09:00
mori.k
7e778a62f9 feat: jskult-batch内の各機能事に使う環境変数を切り分けられるようにクラス化 生物由来の部分追加 2025-05-30 13:18:21 +09:00
shimoda.m@nds-tyo.co.jp
489faafe1b fix: 以下を修正。
・テーブル名、カラム名が大文字だったのを小文字に修正。
・DB接続、beginはSQL実行メソッドの外側で実行したいので、dbインスタンスを取り回すように修正。
・ログメッセージ修正。
・NOTICEでログ出力するように修正。
・SELECTメソッドの宣言位置を修正
2025-05-30 12:18:29 +09:00
shimoda.m@nds-tyo.co.jp
9907a3b6d3 feat: jskult-batch内の各機能事に使う環境変数を切り分けられるようにクラス化 2025-05-30 10:18:52 +09:00
mori.k
6034009480 メルク施設マスタ作成 first commit 2025-05-30 10:09:16 +09:00
shimoda.m@nds-tyo.co.jp
0c5eab44c2 fix: パフォーマンステスト実施中に発覚したバグを修正。ファイル内の空文字をNULLに変換。ログメッセージの不備を修正。 2025-05-30 08:58:34 +09:00
mori.k
397a8a0198 レビュー指摘対応 2025-05-29 18:42:09 +09:00
mori.k
3d50744e2c 施設情報セットの実装 2025-05-29 18:23:46 +09:00
mori.k
45ccc48b97 Merge branch 'develop' into feature-NEWDWH2021-1864 2025-05-29 15:52:21 +09:00
mori.k
e45bb1371b 施設情報セット途中コミット 2025-05-29 15:47:39 +09:00
yono
dee3a3b1cb feat:生物由来データ参照系の修正 2025-05-29 15:40:46 +09:00
下田雅人
df3bee1be1 Merge pull request #484 feature-NEWDWH2021-1847 into develop 2025-05-29 15:12:07 +09:00
shimoda.m@nds-tyo.co.jp
03df7fda74 Merge branch 'develop' into feature-NEWDWH2021-1847 2025-05-29 15:11:44 +09:00
下田雅人
d962a85cb4 Merge pull request #486 feature-NEWDWH2021-1913 into develop 2025-05-29 14:40:02 +09:00
shimoda.m@nds-tyo.co.jp
c0a0b2ffda feat: レビュー指摘修正 2025-05-29 14:38:23 +09:00
mori.k
1b4cff1509 未確定データ削除、データの作成それぞれの条件の変更 2025-05-29 14:21:04 +09:00
mori.k
75994577c6 レビュー指摘対応 2025-05-29 13:09:15 +09:00
mori.k
b03f8e2d08 _delete_empty_lot_recordの修正 2025-05-29 10:34:59 +09:00
mori.k
2a5b5e2876 生物由来ロット分解データの作成の結合条件の記載 2025-05-29 10:19:02 +09:00
mori.k
20907bc4bd 生物由来ロット分解データの作成の外部結合以外までのコミット 2025-05-28 20:54:33 +09:00
shimoda.m@nds-tyo.co.jp
1324408a97 feat: MAX_RUN_COUNTは文字列で受け取る 2025-05-28 20:04:44 +09:00
shimoda.m@nds-tyo.co.jp
288c73b50f feat: アーカイブ取得のステートマシンを追加 2025-05-28 20:02:57 +09:00
shimoda.m@nds-tyo.co.jp
d45f39850e feat: 日付テーブル更新のステートマシンを追加 2025-05-28 19:51:21 +09:00
shimoda.m@nds-tyo.co.jp
25a37e4552 feat: 生物由来ロット分解のステートマシンを追加 2025-05-28 19:40:03 +09:00
shimoda.m@nds-tyo.co.jp
9c4848aab7 feat: configの誤りを修正 2025-05-28 19:24:47 +09:00
shimoda.m@nds-tyo.co.jp
eda21bdc94 feat: 各タスク設定ファイルを作成 2025-05-28 19:24:27 +09:00
shimoda.m@nds-tyo.co.jp
e522279649 feat: メルク施設マスタ作成ステートマシンを追加 2025-05-28 19:24:06 +09:00
mori.k
bb015efe3a 生物由来ロット分解データの未確定データ削除 2025-05-28 19:12:22 +09:00
shimoda.m@nds-tyo.co.jp
75072eb024 feat: DCF削除新規マスタ作成のステートマシン定義を修正 2025-05-28 19:00:14 +09:00
mori.k
a49a616235 共通処理と参考元のソースコードの実装 2025-05-28 17:52:59 +09:00
shimoda.m@nds-tyo.co.jp
a0ffea1086 feat: DCF削除新規マスタ作成のステートマシン定義を修正 2025-05-28 17:14:35 +09:00
shimoda.m@nds-tyo.co.jp
4d2bffcf3b feat: DCF削除新規 開始ログを出す 2025-05-28 17:08:02 +09:00
下田雅人
7cff756d5a Merge pull request #483 feature-NEWDWH2021-1863 into develop 2025-05-28 14:56:42 +09:00
shimoda.m@nds-tyo.co.jp
8adec779b2 .env.exampleとタスク設定ファイルを作成 2025-05-28 14:55:32 +09:00
小野 祥照
3cd35ab696 Merge pull request #482 feature-NEWDWH2021-1902 into develop 2025-05-28 14:50:25 +09:00
yono
13ac61c682 feat:src05.bio_sales→src07.trn_result_data_bioSELECT項目修正 2025-05-28 14:10:30 +09:00
shimoda.m@nds-tyo.co.jp
95ce00a122 feat: 転送データリストを取得する部分を修正。 2025-05-28 13:58:44 +09:00
yono
019591b38a feat: src05.whs_mst_v→src07.mst_whlslr修正漏れ2 2025-05-28 13:56:05 +09:00
yono
31db8567c9 feat: src05.whs_mst_v→src07.mst_whlslr修正漏れ 2025-05-28 13:53:55 +09:00
yono
1ee92b8d1e feat: src05.whs_mst_v→src07.mst_whlslr 2025-05-28 13:30:37 +09:00
shimoda.m@nds-tyo.co.jp
bb2bb4857e feat: 通常時はありえないが、日本語名のファイルだった場合に正常動作しなくなるのを対処 2025-05-28 13:14:47 +09:00
yono
23f5093b32 feat:都道府県マスタに関する変更の取り消し 2025-05-28 13:14:15 +09:00
mori.k
d243768e58 レビュー指摘対応 2025-05-28 12:09:43 +09:00
shimoda.m@nds-tyo.co.jp
6d699c8cc0 feat: アルトマーク取込でバッチステータス管理テーブルへの書き込み処理を追加 2025-05-28 11:34:20 +09:00
yono
ca36186e6f Merge branch 'feature-NEWDWH2021-1902' of nds-tyo.git.backlog.com:/NEWDWH2021/newsdwh2021 into feature-NEWDWH2021-1902 2025-05-28 10:39:37 +09:00
yono
2a076e69c9 feat:不要部分削除(ユニットテスト部分)、readmeタイトル修正、エラー発生時のログレベル修正、JskultArchiveManagerのログメッセージ修正、ドキュメンテーションコメント追加、SQLの条件の値パラメータに変更、無駄なスペース削除 2025-05-28 10:27:46 +09:00
yono
d6d0d2ff0d feat:データ定義に合わせて変更 2025-05-28 09:39:38 +09:00
shimoda.m@nds-tyo.co.jp
198f35d6a7 format: フォーマット適用。未使用のimportを削除 2025-05-27 22:22:24 +09:00
shimoda.m@nds-tyo.co.jp
c475ad9008 refactor: NULL判定に、CASEではなくIFNULLを使う 2025-05-27 22:05:31 +09:00
shimoda.m@nds-tyo.co.jp
81b3135c80 refactor: 振り分け処理の処理名に定数を使用するように修正 2025-05-27 22:01:48 +09:00
shimoda.m@nds-tyo.co.jp
25d6e1818b refactor: mst-inst→mst-inst-allに修正 2025-05-27 21:59:35 +09:00
shimoda.m@nds-tyo.co.jp
5fe6697926 feat: モジュール振り分け処理のテスト実装 2025-05-27 21:58:28 +09:00
shimoda.m@nds-tyo.co.jp
3ceee58260 feat: 日付テーブル操作クラスの例外系のテストを実装 2025-05-27 21:47:33 +09:00
shimoda.m@nds-tyo.co.jp
50d715885c feat: アルトマーク取込完了判定のテスト実装 2025-05-27 21:40:51 +09:00
shimoda.m@nds-tyo.co.jp
8fab1d87e1 feat: 例外のケースを追加 2025-05-27 21:32:50 +09:00
shimoda.m@nds-tyo.co.jp
24c369b69e feat: can_run_business_day_updateのテスト実装 2025-05-27 20:46:03 +09:00
mori.k
0086486841 指摘対応 entrypoint実行済 DB接続の部分は未確認 2025-05-27 20:14:03 +09:00
yono
af2d86899c feat:ユーザマスタ定義変更対応 2025-05-27 18:02:49 +09:00
shimoda.m@nds-tyo.co.jp
881ebeb7e3 feat: バグ取りしながらテスト実装。can_run_processの判定がtrueになるパターンを実装。 2025-05-27 17:00:09 +09:00
mori.k
e50b827d9f 動作テスト前コミット 2025-05-27 16:38:47 +09:00
小野 祥照
f04455d803 Merge pull request #477 feature-NEWDWH2021-1868 into develop 2025-05-27 14:38:11 +09:00
shimoda.m@nds-tyo.co.jp
274c7abec1 feat: set_process_statusのテストを実装(Updateのケース) 2025-05-27 13:26:55 +09:00
shimoda.m@nds-tyo.co.jp
491ba963a8 feat: 修正しきれてなかったテストコードを修正 2025-05-27 13:24:54 +09:00
shimoda.m@nds-tyo.co.jp
bb82b8f7b6 feat: テストコード修正。バックアップのレコードがないときはスルー 2025-05-27 13:22:49 +09:00
shimoda.m@nds-tyo.co.jp
2237872020 feat: ステータス管理テーブルのユニットテスト実装中。set_process_statusのテストを実装 2025-05-27 13:13:41 +09:00
shimoda.m@nds-tyo.co.jp
eae82ac750 refactor: 日付テーブル操作クラスの不要なyield引数を削除 2025-05-27 13:13:06 +09:00
shimoda.m@nds-tyo.co.jp
c5c20b3725 style: ストアドプロシージャにフォーマット適用 2025-05-27 12:52:30 +09:00
shimoda.m@nds-tyo.co.jp
0de1b06e3e feat: ステータス管理テーブル操作クラスの実装を正式化。 2025-05-27 12:36:25 +09:00
shimoda.m@nds-tyo.co.jp
418b6e417e style: docコメント追加。余分なスペース削除。 2025-05-27 12:25:33 +09:00
yono
c246572a7f fix:integrityの設定値ミスの修正 2025-05-27 11:34:45 +09:00
shimoda.m@nds-tyo.co.jp
a6b17b0c78 feat: バッチ実行管理テーブルのユニットテスト実装完了 2025-05-27 11:19:15 +09:00
yono
45268db275 feat: integrityハッシュ値の更新 2025-05-27 10:02:59 +09:00
yono
d9ad3d9491 Merge remote-tracking branch 'origin/develop' into feature-NEWDWH2021-1868 2025-05-27 10:02:17 +09:00
mori.k
cd1e663b4a DCF施設削除新規マスタの作成とDCF施設統合マスタ(DCF_INST_MERGE)の取り込み、ログの出力 2025-05-26 19:54:23 +09:00
mori.k
b24d1b0eb9 誤って追加したファイルの削除 2025-05-26 19:52:09 +09:00
yono
705612032a feat: numpy = "==2.2.*"対応コミットし忘れ 2025-05-26 19:20:31 +09:00
yono
e9f6a90c01 feat: numpy = "==2.2.*" 2025-05-26 19:00:27 +09:00
yono
f4a7638ae1 feat:実消化過去データアーカイブ処理の新規実装 2025-05-26 18:28:38 +09:00
shimoda.m@nds-tyo.co.jp
61ff9f1159 feat: バッチ実行管理テーブル操作クラスのテスト実装(途中) 2025-05-26 18:10:31 +09:00
shimoda.m@nds-tyo.co.jp
9ec8b764ae feat: 日付テーブル操作クラスのユニットテストを実装 2025-05-26 17:26:11 +09:00
shimoda.m@nds-tyo.co.jp
306e393ccf feat: ユニットテストを実行できるように修正 2025-05-26 10:42:41 +09:00
mori.k
ebaa71842d first commit 2025-05-26 10:20:41 +09:00
下田雅人
71b587e03c Merge pull request #476 feature-NEWDWH2021-1845 into develop 2025-05-26 09:59:29 +09:00
下田雅人
9219b08872 Merge pull request #475 feature-NEWDWH2021-1858 into develop 2025-05-26 09:57:40 +09:00
mori.k
991176167a 日付テーブル操作クラスの追加 2025-05-23 15:32:41 +09:00
下田雅人
ce1d8956fa Merge pull request #480 master into develop 2025-05-23 15:20:18 +09:00
下田雅人
5a09cdb724 Merge pull request #481 merge-fix-20250523-dev into develop 2025-05-23 15:19:44 +09:00
shimoda.m@nds-tyo.co.jp
9081ff0a44 Merge branch 'master' into merge-fix-20250523-dev 2025-05-23 15:18:03 +09:00
mori.k
fdabeb9d3d DBのconnectの修正と文体の修正 2025-05-23 14:47:49 +09:00
shimoda.m@nds-tyo.co.jp
38a37c426e feat: 転送処理のlockファイルも修正 2025-05-23 09:08:22 +09:00
shimoda.m@nds-tyo.co.jp
570d70ccdd feat: 製造完了時点のlockファイルを追加 2025-05-23 09:05:45 +09:00
shimoda.m@nds-tyo.co.jp
d7d135e0cc feat: 脆弱性スキャンコマンドを追加。 2025-05-23 09:05:29 +09:00
shimoda.m@nds-tyo.co.jp
a559858d6a style: コメント修正 2025-05-23 08:44:50 +09:00
yono
de1764d764 style: 削除予定箇所にTODOを付与 2025-05-22 22:35:10 +09:00
mori.k
fa408d2a83 コードの修正 2025-05-22 19:51:33 +09:00
mori.k
800f79b825 コードの修正 2025-05-22 19:50:47 +09:00
mori.k
8214de77e4 バッチステータス管理テーブル管理クラス 2025-05-22 19:48:39 +09:00
yono
dd974f1d88 fix:マスタメンテ廃止に伴うバグ対応 2025-05-22 17:31:08 +09:00
yono
5112e42e45 feat:Python3.12対応 2025-05-22 17:29:32 +09:00
mori.k
e60124bec4 START TRANSACTIONとcommitの削除 2025-05-22 17:16:53 +09:00
shimoda.m@nds-tyo.co.jp
37d1b0dd3e Merge branch 'develop' into feature-NEWDWH2021-1858 2025-05-22 10:55:49 +09:00
yono
41d92378c2 feat:マスタメンテの廃止、不要になる箇所のコメントアウト 2025-05-22 09:51:03 +09:00
shimoda.m@nds-tyo.co.jp
5c5b40a6be fix: 転送処理のバグ修正。 2025-05-22 09:15:44 +09:00
shimoda.m@nds-tyo.co.jp
a54d08aedd feat: 動作確認中に発覚したバグを修正。 2025-05-22 09:15:26 +09:00
mori.k
db54af7252 変数のコメントを追加 2025-05-21 18:40:40 +09:00
mori.k
85647c2563 バッチ実行管理テーブル(DynamoDB)操作クラスの実装 2025-05-21 18:14:57 +09:00
mori.k
b6e3252dac 指摘事項の対応 2025-05-21 17:49:26 +09:00
shimoda.m@nds-tyo.co.jp
aa3c3f666f feat: 動作確認で発覚した不具合を修正。 2025-05-21 16:14:27 +09:00
mori.k
44764a7a26 update時の値の修正 2025-05-21 14:13:25 +09:00
mori.k
fce17870ce 内容の修正とコメントを記載 2025-05-21 14:01:54 +09:00
shimoda.m@nds-tyo.co.jp
89a57a1e04 feat: S3周りの処理を修正。 2025-05-21 13:32:34 +09:00
朝倉 明日香
522667970d Merge pull request #474 feature-NEWDWH2021-1860 into develop 2025-05-21 11:28:32 +09:00
mori.k
52d9b80649 バッチステータス管理テーブルupsertストアド 途中コミット 2025-05-20 18:48:03 +09:00
shimoda.m@nds-tyo.co.jp
9215c2a44d feat: 出力するファイル名は環境変数から取る 2025-05-20 18:35:24 +09:00
shimoda.m@nds-tyo.co.jp
2f384ae658 feat: タスク設定ファイルを追加 2025-05-20 18:34:19 +09:00
shimoda.m@nds-tyo.co.jp
cde3f1e9bc feat: README修正 2025-05-20 18:27:31 +09:00
shimoda.m@nds-tyo.co.jp
b1adaf92b3 feat: README修正 2025-05-20 18:26:42 +09:00
shimoda.m@nds-tyo.co.jp
32e0b940d1 feat: 環境変数編集。外側のtry-exceptはいらなそうなので消した 2025-05-20 15:35:58 +09:00
mori.k
acdb8f4d5e Merge branch 'develop' into feature-NEWDWH2021-1845 2025-05-20 15:18:19 +09:00
mori.k
21e42d8826 エントリーポイントの作成と振り分け処理作成 2025-05-20 14:42:14 +09:00
shimoda.m@nds-tyo.co.jp
0e191bf686 feat: 日付テーブルチェックを共通処理で行うように修正。DCFDSFファイル出力処理を修正。 2025-05-20 12:38:27 +09:00
shimoda.m@nds-tyo.co.jp
46e9828fdf Merge branch 'develop' into feature-NEWDWH2021-1858 2025-05-20 12:16:56 +09:00
shimoda.m@nds-tyo.co.jp
f722593d01 feat: アルトマーク取込関連のソースを日次バッチから持ってきて、不要なファイルを削除。 2025-05-20 12:03:59 +09:00
朝倉 明日香
66aad6d4af Merge pull request #473 feature-NEWDWH2021-1856 into develop 2025-05-20 11:29:09 +09:00
shimoda.m@nds-tyo.co.jp
c2344ee6c1 feat: アルトマーク取込のステートマシン定義を作成 2025-05-20 10:54:13 +09:00
shimoda.m@nds-tyo.co.jp
476d0f533b feat: アルトマーク取込起動処理追加 2025-05-20 09:17:42 +09:00
shimoda.m@nds-tyo.co.jp
a18570920c feat: レビュー指摘対応 2025-05-19 18:11:59 +09:00
shimoda.m@nds-tyo.co.jp
67c440055a feat: 脆弱性スキャンコマンドを修正 2025-05-19 18:10:51 +09:00
shimoda.m@nds-tyo.co.jp
63b1f951ce feat: スキーマフォルダ移動 2025-05-19 15:10:06 +09:00
shimoda.m@nds-tyo.co.jp
a406715659 feat: 日付取得ストアドファンクションをsrc07に作成 2025-05-19 15:05:28 +09:00
shimoda.m@nds-tyo.co.jp
cad2c94ff7 fix: 日付テーブルのスキーマをsrc07に変更 2025-05-19 15:04:40 +09:00
shimoda.m@nds-tyo.co.jp
d48bcea8a6 feat: src07のdump取得を追加。取得部分をメソッド化 2025-05-19 12:06:29 +09:00
shimoda.m@nds-tyo.co.jp
726ca9067b feat: python3.12にバージョンアップ 2025-05-19 12:03:13 +09:00
shimoda.m@nds-tyo.co.jp
66e5eeaa63 feat: 脆弱性スキャンコマンドに追加 2025-05-19 10:16:52 +09:00
shimoda.m@nds-tyo.co.jp
b96722d894 feat: ステートマシン定義を追加 2025-05-19 10:15:49 +09:00
下田雅人
dcf438297c Merge pull request #471 feature-NEWDWH2021-1857 into develop 2025-05-16 16:53:42 +09:00
shimoda.m@nds-tyo.co.jp
8819d036a9 fix: 動作確認し、動かなかった部分を修正。 2025-05-16 16:52:52 +09:00
shimoda.m@nds-tyo.co.jp
6714914dbf feat: Pipfile.lock追加 2025-05-16 14:54:28 +09:00
shimoda.m@nds-tyo.co.jp
38ebf964ee feat: README追加 2025-05-16 14:54:13 +09:00
shimoda.m@nds-tyo.co.jp
2e7c5d7c3f fix: 転送処理の起動条件を修正 2025-05-16 12:39:14 +09:00
shimoda.m@nds-tyo.co.jp
f099abbd54 feat: 共通処理を作り変えたため、いらないモジュールを削除 2025-05-16 12:38:52 +09:00
shimoda.m@nds-tyo.co.jp
09307c0142 feat: 日付テーブルに関する共通処理実装完了。処理に組み込み。 2025-05-16 10:20:59 +09:00
shimoda.m@nds-tyo.co.jp
fbd3bdb590 feat: 共通処理実装。can_run_processはこれから。 2025-05-15 19:11:40 +09:00
shimoda.m@nds-tyo.co.jp
0ab0bae0c2 feat: 実消化アルトマークデータ転送処理を実装。共通処理の実装に合わせてbatch_functionsはリファクタリングする 2025-05-14 19:44:56 +09:00
shimoda.m@nds-tyo.co.jp
72e0a18431 feat: 末尾行はcsvライブラリを使って読み込む。単純にスプリットした場合にカラム内のカンマを判別できないため 2025-05-14 14:03:35 +09:00
shimoda.m@nds-tyo.co.jp
11aee0f43a style: 更にコメント修正 2025-05-13 19:06:47 +09:00
shimoda.m@nds-tyo.co.jp
8e910e48f4 style: コメント修正 2025-05-13 19:04:06 +09:00
shimoda.m@nds-tyo.co.jp
bd788ed55e feat: レビュー指摘対応。新たに作った関数はリファクタリングする。 2025-05-13 18:09:50 +09:00
shimoda.m@nds-tyo.co.jp
e6ebb1fd32 feat: 一括登録モードを実装 2025-05-09 18:30:43 +09:00
shimoda.m@nds-tyo.co.jp
a3d72c20d3 feat: 一括登録フラグにより一行コミットか一括登録かを分岐するようにした。まずは一行コミットモードを関数に移植。 2025-05-08 13:57:11 +09:00
shimoda.m@nds-tyo.co.jp
06d741e994 feat: 圧縮フラグON/OFFにより使用するファイルバイトを判定するように修正。
refactor: DB接続時に任意のPORTを指定できるようにした。指定されていない場合は3306がデフォルト。
2025-05-08 13:48:40 +09:00
shimoda.m@nds-tyo.co.jp
df1da34628 feat: 設定ファイルオブジェクトにプロパティと予約行を追加 2025-05-08 10:19:06 +09:00
shimoda.m@nds-tyo.co.jp
841fc95651 refactor: 重複している記述を変数化してまとめた。 2025-05-08 10:17:41 +09:00
shimoda.m@nds-tyo.co.jp
e029c5641d refactor: フォーマットを適用し、長すぎる行を適度に改行した。 2025-05-08 09:44:28 +09:00
shimoda.m@nds-tyo.co.jp
70d61910cc feat: 不要なログ出力を削除 2025-05-07 18:14:51 +09:00
shimoda.m@nds-tyo.co.jp
ff26e52b86 fix: 予約行を空行で埋める処理を追加 2025-05-07 18:09:11 +09:00
shimoda.m@nds-tyo.co.jp
e31b20692c feat: ログ追加.変数名見直し 2025-05-07 18:04:33 +09:00
shimoda.m@nds-tyo.co.jp
f471a2d444 feat: チェック処理で圧縮ファイルの解凍を実装。 2025-05-07 17:53:45 +09:00
下田雅人
7ca2318277 Merge pull request #468 master into develop 2025-05-02 16:37:16 +09:00
下田雅人
7674a33a01 Merge pull request #467 develop-v5.1.0 into develop 2025-05-02 16:34:51 +09:00
742 changed files with 35030 additions and 3088 deletions

2
.vscode/launch.json vendored
View File

@ -9,7 +9,7 @@
"type": "python",
"request": "launch",
// windows\
"program": "ecs\\dataimport\\dataimport\\controller.py",
"program": "ecs/jskult-batch-archive-jsk-data/entrypoint.py",
"console": "integratedTerminal",
"justMyCode": true,
"envFile": "${workspaceFolder}/.env"

View File

@ -1,43 +1,17 @@
import csv
import io
import os
import sys
from datetime import datetime
import boto3
from common import convert_quotechar, debug_log
import pymysql
from common import (DIRECTORY_SETTINGS, DIRECTORY_WORK, ERROR, INFO,
LINE_FEED_CODE, SETTINGS_ITEM, WARNING, convert_quotechar,
debug_log, uncompress_gzip, uncompress_zip)
from end import end
from error import error
# 定数
DIRECTORY_WORK = '/work/'
LOG_LEVEL = {'i': 'Info', 'e': 'Error'}
SETTINGS_ITEM = {
'dataSource': 0,
'delimiter': 1,
'charCode': 2,
'quotechar': 3,
'lineFeedCode': 4,
'headerFlag': 5,
'csvNumItems': 6,
'csvNameItems': 7,
'dbColumuName': 8,
'storageSchemaName': 9,
'loadSchemaName': 10,
'exSqlFileName': 11,
'commaReplaceColumns': 12,
'importManner': 13,
'reserved1': 14,
'reserved2': 15,
'reserved3': 16,
'reserved4': 17,
'reserved5': 18,
'reserved6': 19
}
LINE_FEED_CODE = {
'CR': '\r',
'LF': '\n',
'CRLF': '\r\n',
}
from pymysql.constants import CLIENT
# クラス変数
s3_client = boto3.client('s3')
@ -48,13 +22,14 @@ class CheckError(Exception):
pass
def check(bucket_name, target_data_source, target_file_name, settings_key, log_info, mode):
def check(bucket_name, target_data_source, target_file_name, settings_key, db_info, log_info, mode):
"""チェック処理
Args:
bucket_name : バケット名
target_data_source : 投入データのディレクトリ名よりデータソースに該当する部分
target_file_name : 投入データのファイル名
settings_key : 投入データに該当する個別設定ファイルのフルパス
db_info : データベース情報
log_info : ログに記載するデータソース名とファイル名
mode : 処理モード
Raises:
@ -63,26 +38,48 @@ def check(bucket_name, target_data_source, target_file_name, settings_key, log_i
try:
debug_log(f'引数 bucket_name : {bucket_name}', log_info, mode)
debug_log(f'引数 target_data_source : {target_data_source}', log_info, mode)
debug_log(
f'引数 target_data_source : {target_data_source}', log_info, mode)
debug_log(f'引数 target_file_name : {target_file_name}', log_info, mode)
debug_log(f'引数 settings_key : {settings_key}', log_info, mode)
debug_log(f'引数 log_info : {log_info}', log_info, mode)
debug_log(f'引数 mode : {mode}', log_info, mode)
# ① チェック処理開始ログを出力する
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-CHK-01 - チェック処理を開始します')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-01 - チェック処理を開始します')
# データ読込
settings_obj_response = s3_client.get_object(Bucket=bucket_name, Key=settings_key)
settings_obj_response = s3_client.get_object(
Bucket=bucket_name, Key=settings_key)
settings_list = []
for line in io.TextIOWrapper(io.BytesIO(settings_obj_response["Body"].read()), encoding='utf-8'):
settings_list.append(line.rstrip('\n'))
# 設定ファイルに記載のない行を空文字として扱い、予約行とする
for _ in range(len(SETTINGS_ITEM) - len(settings_list)):
settings_list.append('')
work_key = target_data_source + DIRECTORY_WORK + target_file_name
work_obj_response = s3_client.get_object(Bucket=bucket_name, Key=work_key)
work_data = io.TextIOWrapper(io.BytesIO(work_obj_response["Body"].read()), encoding=settings_list[SETTINGS_ITEM["charCode"]], newline=LINE_FEED_CODE[settings_list[SETTINGS_ITEM["lineFeedCode"]]])
work_obj_response = s3_client.get_object(
Bucket=bucket_name, Key=work_key)
work_obj_file = work_obj_response["Body"].read()
work_data_bytes = io.BytesIO(work_obj_file)
compressed_flag = settings_list[SETTINGS_ITEM["compressedFlag"]]
# ② ファイル圧縮フラグがONの場合、チェック対象ファイルの展開処理を行う。
if compressed_flag and compressed_flag == '1':
work_data_bytes = io.BytesIO(uncompress_file(
work_data_bytes, settings_list, log_info))
encoding = settings_list[SETTINGS_ITEM["charCode"]]
line_feed = LINE_FEED_CODE[settings_list[SETTINGS_ITEM["lineFeedCode"]]]
delimiter = settings_list[SETTINGS_ITEM["delimiter"]]
work_data = io.TextIOWrapper(work_data_bytes, encoding=encoding,
newline=line_feed)
work_csv_row = []
for i, line in enumerate(csv.reader(work_data, quotechar=convert_quotechar(settings_list[SETTINGS_ITEM["quotechar"]]), delimiter=settings_list[SETTINGS_ITEM["delimiter"]])):
for i, line in enumerate(csv.reader(work_data, quotechar=convert_quotechar(settings_list[SETTINGS_ITEM["quotechar"]]),
delimiter=delimiter)):
# ヘッダあり、かつ、1行目の場合
if int(settings_list[SETTINGS_ITEM["headerFlag"]]) == 1 and i == 0:
work_csv_row.append(line)
@ -90,41 +87,86 @@ def check(bucket_name, target_data_source, target_file_name, settings_key, log_i
work_csv_row.append(line)
break
# ② C-0のデータ件数チェックを開始する
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-CHK-02 - C-0のチェックを開始します')
# ③ C-0のデータ件数チェックを開始する
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-02 - C-0のチェックを開始します')
if is_empty_file(work_csv_row, settings_list):
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-CHK-03 - 投入ファイルが0バイトのため処理を終了します')
end(bucket_name, target_data_source, target_file_name, '', log_info, mode)
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-CHK-04 - 終了処理完了')
# 拡張SQL実行フラグがONになっている場合は拡張SQLを実行して処理終了する。
if settings_list[SETTINGS_ITEM["executeExSqlIfFileEmptyFlag"]] == '1':
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-15 - '
'投入ファイルがバイトです。バイト時の拡張SQL実行フラグが有効なため、拡張SQLを実行します。')
execute_ex_sql(bucket_name, target_data_source,
settings_list, db_info, log_info)
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-03 - 投入ファイルが0バイトのため処理を終了します')
end(bucket_name, target_data_source,
target_file_name, '', log_info, mode)
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-04 - 終了処理完了')
sys.exit()
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-CHK-05 - C-0正常終了')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-05 - C-0正常終了')
# ③ C-1の項目数チェックを開始する
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-CHK-06 - C-1のチェックを開始します')
# ④ C-1の項目数チェックを開始する
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-06 - C-1 項目数チェックを開始します')
work_csv_row_item_len = len(work_csv_row[0])
if work_csv_row_item_len == int(settings_list[SETTINGS_ITEM["csvNumItems"]]):
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-CHK-07 - C-1正常終了')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-07 - C-1 項目数チェック:正常終了')
else:
raise CheckError(f'E-CHK-01 - 項目数が一致しません 個別設定ファイル項目数:{settings_list[SETTINGS_ITEM["csvNumItems"]]} 投入データ項目数:{work_csv_row_item_len}')
raise CheckError(
f'E-CHK-01 - 項目数が一致しません 個別設定ファイル項目数:{settings_list[SETTINGS_ITEM["csvNumItems"]]} 投入データ項目数:{work_csv_row_item_len}')
# ④ C-2の項目並び順チェック開始する
if int(settings_list[SETTINGS_ITEM["headerFlag"]]) == True:
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-CHK-08 - C-2のチェックを開始します')
settings_header_list = settings_list[SETTINGS_ITEM["csvNameItems"]].rstrip().split(',')
# ⑤ C-2の項目並び順チェック開始する
if int(settings_list[SETTINGS_ITEM["headerFlag"]]) == 1:
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-08 - C-2 項目並び順チェックを開始します')
settings_header_list = settings_list[SETTINGS_ITEM["csvNameItems"]].rstrip(
).split(',')
work_header_list = work_csv_row[0]
for i in range(len(settings_header_list)):
if not settings_header_list[i] == work_header_list[i]:
raise CheckError(f'E-CHK-02 - 項目順序が一致しません {i + 1}番目の項目 個別設定ファイル項目:{settings_header_list[i]} 投入データ項目:{work_header_list[i]}')
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-CHK-09 - C-2正常終了')
raise CheckError(
f'E-CHK-02 - 項目順序が一致しません {i + 1}番目の項目 個別設定ファイル項目:{settings_header_list[i]} 投入データ項目:{work_header_list[i]}')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-09 - C-2 項目並び順チェック:正常終了')
# ⑤ チェック処理終了ログを出力する
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-CHK-10 - チェック処理を終了します')
# ⑥ C-3の末尾行項目数チェック開始する
if settings_list[SETTINGS_ITEM["bulkImportFlag"]] and int(settings_list[SETTINGS_ITEM["bulkImportFlag"]]) == 1:
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-13 - C-3 末尾行項目数チェックを開始します')
# ファイルの末尾行を取得し、ファイル項目数と比較する
last_line_work_data_bytes = next(reverse_readline_stream(
work_data_bytes, LINE_FEED_CODE[settings_list[SETTINGS_ITEM["lineFeedCode"]]]))
# 区切り文字例えばカンマを文字とデリミタで区別できるように、csvリーダーで読む
last_line_separated_data = [
row for row in csv.reader(
io.TextIOWrapper(io.BytesIO(last_line_work_data_bytes)),
quotechar=convert_quotechar(
settings_list[SETTINGS_ITEM["quotechar"]]),
delimiter=delimiter)
]
last_line_count = len(last_line_separated_data[0])
if last_line_count != int(settings_list[SETTINGS_ITEM["csvNumItems"]]):
raise CheckError(
f'E-CHK-03 - 投入データ末尾の項目数が一致しません 個別設定ファイル項目数:{settings_list[SETTINGS_ITEM["csvNumItems"]]} 投入データ項目数:{last_line_count}')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-14 - C-3 末尾行項目数チェック 正常終了')
# ⑦ チェック処理終了ログを出力する
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-10 - チェック処理を終了します')
except CheckError as e:
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["e"]} {e}')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {ERROR} {e}')
error(bucket_name, target_data_source, target_file_name, log_info)
except Exception as e:
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["e"]} E-CHK-99 - エラー内容:{e}')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {ERROR} E-CHK-99 - エラー内容:{e}')
error(bucket_name, target_data_source, target_file_name, log_info)
@ -147,14 +189,143 @@ def is_empty_file(work_csv_row: list, settings_list: list):
return len(work_csv_row) == 0
def uncompress_file(work_data_file: io.BytesIO, settings_list: list, log_info) -> bytes:
"""指定された形式で圧縮ファイルを展開し、ローカルに書き出す。
Args:
work_data_file (bytes): S3から読み込んだ登録
settings_list (list): 個別設定ファイルのリスト
log_info (str): ログに記載するデータソース名とファイル名
Returns:
bytes: 解凍後のファイルのバイト配列
"""
compression = settings_list[SETTINGS_ITEM['compression']]
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-11 - 投入ファイルが圧縮されているため、展開処理を行います。圧縮形式:{compression}')
file_bytes: bytes = None
if compression == 'zip':
# zipファイルを展開し、ファイルを書き出す。
file_bytes = uncompress_zip(work_data_file, settings_list, log_info)
elif compression == 'gzip':
file_bytes = uncompress_gzip(work_data_file, settings_list, log_info)
# MEMO: zip以外の圧縮形式に対応する際に追記すること
else:
raise ValueError("圧縮形式が一致しません")
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-12 - 投入ファイルの展開が正常終了しました')
return file_bytes
def reverse_readline_stream(f: io.BytesIO, line_feed: str, chunk_size=4096):
"""バイトモードのファイルストリームを後ろから読み、1行ずつ返すジェネレータ。
指定されたバイト単位でファイルを読み込み1行ずつにして返している
Args:
f (io.BytesIO): バイトモードのファイルストリーム
line_feed (str): 改行コード
chunk_size (int, optional): 読み込むファイルチャンク数(byte) Defaults to 4096.
Yields:
bytes: 末尾から1行分のレコード
"""
# ファイルのポインタを末尾に移動させてからポインタを取得する
f.seek(0, os.SEEK_END)
pointer = f.tell()
buffer = b''
yielded_any = False
while pointer > 0:
read_size = min(chunk_size, pointer)
# チャンク数分ファイルを読み込むために、ポインタをずらす
pointer -= read_size
f.seek(pointer)
chunk = f.read(read_size)
# 読み込んだチャンク + バッファ(途中行)
buffer = chunk + buffer
# 改行文字で区切る
parts = buffer.split(line_feed.encode())
# parts[0] は先頭途中行 → 次ループへ残す
buffer = parts[0]
# parts[1:] が「完全に揃った行」のリスト
# 改行文字で区切っているため、行途中のparts[1:] は空文字になるため、以下のループは素通りする。
for line in reversed(parts[1:]):
if not yielded_any and line == b'':
# 最初にだけ出てくる空行を飛ばす
continue
# 一度でも結果を返している場合にフラグを立てる
yielded_any = True
yield line
# ポインターがファイル先頭まで来たあとの残り1行
if not (not yielded_any and buffer == b''):
# 一度でも結果を返しているかつ、バッファにデータが残っている場合、先頭行のデータを返す
yield buffer
def execute_ex_sql(bucket_name, target_data_source, settings_list, db_info, log_info):
# 個別設定ファイルに拡張SQLファイル名が設定されているかチェック
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-16 - 拡張SQL設定が存在するかチェックします')
ex_sql_file_name = settings_list[SETTINGS_ITEM["exSqlFileName"]]
if ex_sql_file_name:
try:
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-17 - 拡張SQL設定の存在を確認しました')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-18 - 拡張SQLファイル名{ex_sql_file_name} の存在チェック')
ex_sql_key = target_data_source + DIRECTORY_SETTINGS + ex_sql_file_name
s3_client.head_object(Bucket=bucket_name, Key=ex_sql_key)
ex_sql_file_exists = True
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-19 - 拡張SQLファイル名の存在を確認しました')
except Exception:
ex_sql_file_exists = False
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {WARNING} W-CHK-02 - 拡張SQLファイルが存在しません')
try:
if ex_sql_file_exists:
# 拡張SQLファイルからSQL文生成
ex_sql_obj_response = s3_client.get_object(
Bucket=bucket_name, Key=ex_sql_key)
ex_sql = ''
for line in io.TextIOWrapper(io.BytesIO(ex_sql_obj_response["Body"].read()), encoding='utf-8'):
ex_sql = f'{ex_sql} {line.rstrip()}'
# DB接続を開始する
conn = pymysql.connect(host=db_info["host"], port=db_info["port"], user=db_info["user"], passwd=db_info["pass"],
db=db_info["name"], connect_timeout=5, client_flag=CLIENT.MULTI_STATEMENTS, local_infile=True)
# トランザクション開始
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-20 - 拡張SQL{ex_sql_file_name} のトランザクションを開始します')
with conn.cursor() as cur:
cur.execute(ex_sql)
conn.commit()
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-21 - 拡張SQL{ex_sql_file_name} のCOMMIT処理が正常終了しました')
conn.close()
except Exception as e:
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {WARNING} W-CHK-03 - 拡張SQLにエラーが発生しました{e}')
else:
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-CHK-22 - 拡張SQL設定の存在はありませんでした')
# ローカル実行用コード
# 値はよしなに変えてください
# if __name__ == '__main__':
# check(
# bucket_name='バケット名',
# target_data_source='データソース名',
# target_file_name='targetフォルダ内のファイル名',
# settings_key='個別設定ファイル名',
# log_info='Info',
# mode='i'
# )
if __name__ == '__main__':
check(
bucket_name='test-shimoda-bucket',
target_data_source='test',
target_file_name='compress_test.gz',
settings_key='test/settings/compress_test_gzip.txt',
log_info='Info',
mode='i'
)

View File

@ -1,16 +1,83 @@
import csv
import gzip
import io
import zipfile
from datetime import datetime
# 定数
LOG_LEVEL = {"d": 'Debug'}
LOG_LEVEL = {
"d": 'Debug',
'i': 'Info',
'e': 'Error',
'w': "Warning"
}
INFO = LOG_LEVEL["i"]
ERROR = LOG_LEVEL["e"]
WARNING = LOG_LEVEL["w"]
LINE_FEED_CODE = {
'CR': '\r',
'LF': '\n',
'CRLF': '\r\n',
}
# LOAD DATA文で文字コードを指定するために、個別設定ファイルの文字コード指定をMySQLの文字コード表記に変換する
MYSQL_CHARSET_CODE = {
'utf-8': 'utf8mb4',
'utf8': 'utf8mb4',
'utf-8-sig': 'utf8mb4',
'shift_jis': 'cp932',
'cp932': 'cp932',
}
MODE_TYPE = {
'n': 'normal',
'd': 'debug',
}
# 設定ファイルのの項目行数のマップ
SETTINGS_ITEM = {
'dataSource': 0,
'delimiter': 1,
'charCode': 2,
'quotechar': 3,
'lineFeedCode': 4,
'headerFlag': 5,
'csvNumItems': 6,
'csvNameItems': 7,
'dbColumuName': 8,
'storageSchemaName': 9,
'loadSchemaName': 10,
'exSqlFileName': 11,
'commaReplaceColumns': 12,
'importManner': 13,
'bulkImportFlag': 14,
'compressedFlag': 15,
'compression': 16,
'executeExSqlIfFileEmptyFlag': 17,
'reserved1': 18,
'reserved2': 19,
'reserved3': 20,
'reserved4': 21,
'reserved5': 22,
'reserved6': 23,
'reserved7': 24
}
DIRECTORY_WORK = '/work/'
DIRECTORY_SETTINGS = '/settings/'
LOCAL_DIRECTORY_TMP = '/tmp'
# チェック処理で解凍した圧縮ファイルの中身を格納するフォルダ
LOCAL_TEMPORARY_FILE_PATH = f'{LOCAL_DIRECTORY_TMP}/temporary_file.dat'
def debug_log(log, log_info, mode):
if MODE_TYPE['d'] == mode:
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["d"]} {log}')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["d"]} {log}')
def convert_quotechar(quotechar):
"""csvモジュールの囲い文字を変換する
@ -26,3 +93,105 @@ def convert_quotechar(quotechar):
return None
return quotechar
def uncompress_zip(work_data_file: io.BytesIO, settings_list: list, log_info) -> bytes:
"""zip圧縮されているファイルを展開する
Args:
work_data_file (io.BytesIO): 展開対象のバイナリ(.zip)
settings_list (list): 個別設定ファイルの情報
log_info (_type_): ログ情報
Raises:
Exception: 展開したものがファイルではなかった場合
Returns:
bytes: 展開後ファイルのバイナリ
"""
file_bytes = None
with zipfile.ZipFile(work_data_file, 'r') as zip_ref:
# 昇順でソートする。
file_list: list[str] = sorted(zip_ref.namelist())
if len(file_list) > 1:
# 圧縮ファイル内に複数ファイルが存在する場合、warningログを出力する。
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {WARNING}' +
f'W-CHK-01 - 圧縮データ内に複数ファイルが存在したため、{file_list[0]}のみ登録を行います。'
)
target_file_name = file_list[0]
# 末尾が「/」で終わるのはフォルダ
if target_file_name.endswith('/'):
# 圧縮ファイル内の先頭がフォルダの場合、エラー処理を行う。
raise Exception(
f'展開したデータはファイルではありません。ファイルパス: {target_file_name}')
# zipファイル内には1ファイルのみ
with zip_ref.open(target_file_name) as file:
file_bytes = file.read()
# ファイルを一時ディレクトリに書き出す。
encoding = settings_list[SETTINGS_ITEM["charCode"]]
line_feed = LINE_FEED_CODE[settings_list[SETTINGS_ITEM["lineFeedCode"]]]
delimiter = settings_list[SETTINGS_ITEM["delimiter"]]
quote_char = convert_quotechar(
settings_list[SETTINGS_ITEM["quotechar"]])
uncompressed_file = io.TextIOWrapper(io.BytesIO(file_bytes), encoding=encoding,
newline=line_feed)
csv_reader = csv.reader(uncompressed_file, quotechar=convert_quotechar(settings_list[SETTINGS_ITEM["quotechar"]]),
delimiter=delimiter)
with open(LOCAL_TEMPORARY_FILE_PATH, 'w', encoding=encoding, newline='') as csvfile:
csv_writer = csv.writer(csvfile, quotechar=quote_char,
delimiter=delimiter)
for row in csv_reader:
csv_writer.writerow(row)
def uncompress_gzip(work_data_file: io.BytesIO, settings_list: list, log_info) -> bytes:
"""gzip 圧縮されたファイルを展開する
Args:
work_data_file (io.BytesIO): 展開対象のバイナリ (.gz)
settings_list (list): 個別設定ファイルの情報
log_info (_type_): ログ情報
Raises:
Exception: 展開に失敗した場合
Returns:
bytes: 展開後ファイルのバイナリ
"""
gz_bytes = work_data_file.getvalue()
try:
# GZIP をバイト列ごと展開する
file_bytes = gzip.decompress(gz_bytes)
except (OSError, EOFError) as e:
raise Exception(f"GZIP 解凍に失敗しました: {e}")
# ファイルを一時ディレクトリに書き出す。
encoding = settings_list[SETTINGS_ITEM["charCode"]]
line_feed = LINE_FEED_CODE[settings_list[SETTINGS_ITEM["lineFeedCode"]]]
delimiter = settings_list[SETTINGS_ITEM["delimiter"]]
quote_char = convert_quotechar(settings_list[SETTINGS_ITEM["quotechar"]])
uncompressed_file = io.TextIOWrapper(
io.BytesIO(file_bytes),
encoding=encoding,
newline=line_feed
)
csv_reader = csv.reader(
uncompressed_file,
quotechar=convert_quotechar(settings_list[SETTINGS_ITEM["quotechar"]]),
delimiter=delimiter
)
with open(LOCAL_TEMPORARY_FILE_PATH, 'w', encoding=encoding, newline='') as csvfile:
csv_writer = csv.writer(
csvfile, quotechar=quote_char, delimiter=delimiter)
for row in csv_reader:
csv_writer.writerow(row)
return file_bytes

View File

@ -1,10 +1,11 @@
import os
from datetime import datetime
from ini import init
from chk import check
from main import main
from end import end
from error import error
from ini import init
from main import main
# 引数
BUCKET_NAME = os.environ["BUCKET_NAME"]
@ -18,7 +19,9 @@ DB_HOST = os.environ["DB_HOST"]
DB_NAME = os.environ["DB_NAME"]
DB_PASS = os.environ["DB_PASS"]
DB_USER = os.environ["DB_USER"]
DB_INFO = {"host": DB_HOST, "name": DB_NAME, "pass": DB_PASS, "user": DB_USER}
DB_PORT = int(os.environ.get("DB_PORT", 3306))
DB_INFO = {"host": DB_HOST, "port": DB_PORT,
"name": DB_NAME, "pass": DB_PASS, "user": DB_USER}
# 定数
LOG_LEVEL = {"i": 'Info'}
@ -33,26 +36,36 @@ LOG_INFO = f'{DATA_SOURCE_NAME} {FILE_NAME}'
try:
# ① データ取込処理開始ログを出力する
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {LOG_INFO} {LOG_LEVEL["i"]} I-CTRL-01 - データ取込処理を開始します')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {LOG_INFO} {LOG_LEVEL["i"]} I-CTRL-01 - データ取込処理を開始します')
# ② 初期処理を呼び出す
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {LOG_INFO} {LOG_LEVEL["i"]} I-CTRL-02 - 初期処理の呼び出し')
settings_key = init(BUCKET_NAME, TARGET_KEY, DATA_SOURCE_NAME, FILE_NAME, LOG_INFO, MODE)
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {LOG_INFO} {LOG_LEVEL["i"]} I-CTRL-02 - 初期処理の呼び出し')
settings_key = init(BUCKET_NAME, TARGET_KEY,
DATA_SOURCE_NAME, FILE_NAME, LOG_INFO, MODE)
# ③ チェック処理を呼び出す
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {LOG_INFO} {LOG_LEVEL["i"]} I-CTRL-03 - チェック処理の呼び出し')
check(BUCKET_NAME, DATA_SOURCE_NAME, FILE_NAME, settings_key, LOG_INFO, MODE)
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {LOG_INFO} {LOG_LEVEL["i"]} I-CTRL-03 - チェック処理の呼び出し')
check(BUCKET_NAME, DATA_SOURCE_NAME,
FILE_NAME, settings_key, DB_INFO, LOG_INFO, MODE)
# ④ メイン処理を呼び出す
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {LOG_INFO} {LOG_LEVEL["i"]} I-CTRL-04 - メイン処理の呼び出し')
warning_info = main(BUCKET_NAME, DATA_SOURCE_NAME, FILE_NAME, settings_key, DB_INFO, LOG_INFO, MODE)
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {LOG_INFO} {LOG_LEVEL["i"]} I-CTRL-04 - メイン処理の呼び出し')
warning_info = main(BUCKET_NAME, DATA_SOURCE_NAME,
FILE_NAME, settings_key, DB_INFO, LOG_INFO, MODE)
# ⑤ 終了処理を呼び出す
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {LOG_INFO} {LOG_LEVEL["i"]} I-CTRL-05 - 終了処理の呼び出し')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {LOG_INFO} {LOG_LEVEL["i"]} I-CTRL-05 - 終了処理の呼び出し')
end(BUCKET_NAME, DATA_SOURCE_NAME, FILE_NAME, warning_info, LOG_INFO, MODE)
# ⑥ データ取込処理終了ログを出力する
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {LOG_INFO} {LOG_LEVEL["i"]} I-CTRL-06 - データ取込処理を終了します')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {LOG_INFO} {LOG_LEVEL["i"]} I-CTRL-06 - データ取込処理を終了します')
except Exception as e:
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {LOG_INFO} {LOG_LEVEL["e"]} E-CTRL-99 - エラー内容:{e}')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {LOG_INFO} {LOG_LEVEL["e"]} E-CTRL-99 - エラー内容:{e}')
error(BUCKET_NAME, DATA_SOURCE_NAME, FILE_NAME, LOG_INFO)

View File

@ -1,45 +1,18 @@
import csv
import io
import re
from datetime import datetime
import boto3
import pymysql
from common import convert_quotechar, debug_log
from common import (DIRECTORY_SETTINGS, DIRECTORY_WORK, ERROR, INFO,
LINE_FEED_CODE, LOCAL_TEMPORARY_FILE_PATH,
MYSQL_CHARSET_CODE, SETTINGS_ITEM, WARNING,
convert_quotechar, debug_log)
from error import error
from pymysql.constants import CLIENT
# 定数
DIRECTORY_WORK = '/work/'
LOG_LEVEL = {"i": 'Info', "e": 'Error', "w": 'Warning'}
SETTINGS_ITEM = {
'dataSource': 0,
'delimiter': 1,
'charCode': 2,
'quotechar': 3,
'lineFeedCode': 4,
'headerFlag': 5,
'csvNumItems': 6,
'csvNameItems': 7,
'dbColumuName': 8,
'storageSchemaName': 9,
'loadSchemaName': 10,
'exSqlFileName': 11,
'commaReplaceColumns': 12,
'importManner': 13,
'reserved1': 14,
'reserved2': 15,
'reserved3': 16,
'reserved4': 17,
'reserved5': 18,
'reserved6': 19
}
LINE_FEED_CODE = {
'CR': '\r',
'LF': '\n',
'CRLF': '\r\n',
}
DIRECTORY_SETTINGS = '/settings/'
TRUNCATE_SRC_TABLE_SYMBOL = 'truncate_src_table:'
TRUNCATE_SRC_TABLE_IDENTIFY_SYMBOL_FORMAT = f'{TRUNCATE_SRC_TABLE_SYMBOL}[蓄積スキーマのテーブル名]'
INVALID_CONFIG_EXCEPTION_MESSAGE = f'個別設定ファイルのインポート方法に不備がありました。 インポート方法は "{TRUNCATE_SRC_TABLE_IDENTIFY_SYMBOL_FORMAT}" のように設定してください'
@ -64,7 +37,8 @@ def main(bucket_name, target_data_source, target_file_name, settings_key, db_inf
try:
debug_log(f'引数 bucket_name : {bucket_name}', log_info, mode)
debug_log(f'引数 target_data_source : {target_data_source}', log_info, mode)
debug_log(
f'引数 target_data_source : {target_data_source}', log_info, mode)
debug_log(f'引数 target_file_name : {target_file_name}', log_info, mode)
debug_log(f'引数 settings_key : {settings_key}', log_info, mode)
debug_log(f'引数 db_info : {db_info}', log_info, mode)
@ -72,24 +46,30 @@ def main(bucket_name, target_data_source, target_file_name, settings_key, db_inf
debug_log(f'引数 mode : {mode}', log_info, mode)
# ① メイン処理開始ログを出力する
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-01 - メイン処理を開始します')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-01 - メイン処理を開始します')
# ② DB接続を開始する
conn = pymysql.connect(host=db_info["host"], user=db_info["user"], passwd=db_info["pass"], db=db_info["name"], connect_timeout=5, client_flag=CLIENT.MULTI_STATEMENTS)
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-02 - DB接続を開始しました')
conn = pymysql.connect(host=db_info["host"], port=db_info["port"], user=db_info["user"], passwd=db_info["pass"],
db=db_info["name"], connect_timeout=5, client_flag=CLIENT.MULTI_STATEMENTS, local_infile=True)
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-02 - DB接続を開始しました')
except Exception as e:
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["e"]} E-MAIN-99 - エラー内容:{e}')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {ERROR} E-MAIN-99 - エラー内容:{e}')
error(bucket_name, target_data_source, target_file_name, log_info)
try:
# ③ タイムゾーンを変更する
with conn.cursor() as cur:
cur.execute(f'SET time_zone = "+9:00"')
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-03 - タイムゾーンを変更しました')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-03 - タイムゾーンを変更しました')
# ④ 個別設定ファイルのロードスキーマのテーブル名に記載されているテーブルをTRUNCATEする
# 個別設定ファイルの読み込み
settings_response = s3_client.get_object(Bucket=bucket_name, Key=settings_key)
settings_response = s3_client.get_object(
Bucket=bucket_name, Key=settings_key)
settings_list = []
for line in io.TextIOWrapper(io.BytesIO(settings_response["Body"].read()), encoding='utf-8'):
settings_list.append(line.rstrip('\n'))
@ -99,106 +79,70 @@ def main(bucket_name, target_data_source, target_file_name, settings_key, db_inf
settings_list.append('')
# ロードスキーマのTRUNCATE
load_schema_name = settings_list[SETTINGS_ITEM["loadSchemaName"]]
with conn.cursor() as cur:
sql_truncate = f'TRUNCATE table {settings_list[SETTINGS_ITEM["loadSchemaName"]]}'
sql_truncate = f'TRUNCATE table {load_schema_name}'
cur.execute(sql_truncate)
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-04 - {settings_list[SETTINGS_ITEM["loadSchemaName"]]} をTRUNCATEしました')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO}' +
f' I-MAIN-04 - {load_schema_name} をTRUNCATEしました')
# ⑤ 投入データファイルを1行ごとにループする
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-05 - 投入データ {target_file_name} の読み込みを開始します')
work_key = target_data_source + DIRECTORY_WORK + target_file_name
work_response = s3_client.get_object(Bucket=bucket_name, Key=work_key)
work_data = io.TextIOWrapper(io.BytesIO(work_response["Body"].read()), encoding=settings_list[SETTINGS_ITEM["charCode"]], newline=LINE_FEED_CODE[settings_list[SETTINGS_ITEM["lineFeedCode"]]])
process_count = 0 # 処理件数カウンタ
normal_count = 0 # 正常終了件数カウンタ
warning_count = 0 # ワーニング終了件数カウンター
warning_info = '' # ワーニング情報
index = 0 # ループインデックス
settings_db_columu_list = settings_list[SETTINGS_ITEM["dbColumuName"]].rstrip().split(',')
settings_replace_comma_list = settings_list[SETTINGS_ITEM["commaReplaceColumns"]].rstrip().split(',')
for line in csv.reader(work_data, quotechar=convert_quotechar(settings_list[SETTINGS_ITEM["quotechar"]]), delimiter=settings_list[SETTINGS_ITEM["delimiter"]]):
try:
if int(settings_list[SETTINGS_ITEM["headerFlag"]]) == True and index == 0:
index += 1
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-06 - ヘッダー行をスキップします')
continue
# 処理件数カウント
process_count += 1
# SQL文生成
query_parameter_list = []
sql = f'INSERT INTO {settings_list[SETTINGS_ITEM["loadSchemaName"]]} ('
for db_column in settings_db_columu_list:
sql = f'{sql} {db_column},'
sql = f'{sql} file_name,' # システム項目:取込ファイル名
sql = f'{sql} file_row_cnt,' # システム項目:取込ファイル行番号
sql = f'{sql} delete_flg,' # システム項目:論理削除フラグ
sql = f'{sql} ins_user,' # システム項目:登録者
sql = f'{sql} ins_date,' # システム項目:登録日時
sql = f'{sql} upd_user,' # システム項目:更新者
sql = f'{sql} upd_date)' # システム項目:更新日時
sql = f'{sql} VALUES ('
for i in range(len(line)):
# データ項目値が0桁より大きいかチェックする
if len(line[i]) == 0:
# 0桁の場合
sql = f'{sql} NULL,'
continue
# データ項目値の変換処理(カンマ除去)
org_column_value = line[i]
current_settings_db_column_name = settings_db_columu_list[i]
column_value = convert_column_value(org_column_value, current_settings_db_column_name, settings_replace_comma_list)
# INSERT文のパラメータとそれに対応するプレースホルダーを設定する
query_parameter_list.append(column_value)
sql = f'{sql} %s,'
sql = f'{sql} "{target_file_name}",' # システム項目:取込ファイル名
sql = f'{sql} "{index + 1}",' # システム項目:取込ファイル行番号
sql = f'{sql} "0",' # システム項目:論理削除フラグ
sql = f'{sql} CURRENT_USER(),' # システム項目:登録者
sql = f'{sql} CURRENT_TIMESTAMP(),' # システム項目:登録日時
sql = f'{sql} NULL,' # システム項目:更新者
sql = f'{sql} NULL)' # システム項目:更新日時
index += 1
debug_log(sql, log_info, mode)
# ロードスキーマのトランザクション開始
with conn.cursor() as cur:
cur.execute(sql, query_parameter_list)
conn.commit()
normal_count += 1
except Exception as e:
warning_count += 1
warning_info = f'{warning_info}{index} ロードスキーマ登録時にエラーが発生しました {line} {e}\n'
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["w"]} W-MAIN-01 {index} ロードスキーマ登録時にエラーが発生しました {line} {e}')
org_import_process_result = None
bulk_import_flag = settings_list[SETTINGS_ITEM["bulkImportFlag"]]
if not bulk_import_flag or int(bulk_import_flag) == 0:
# ⑤-1 一括登録フラグが未設定、またはOFFの場合、行コミットモードでロードスキーマに登録を行う
org_import_process_result = import_data_with_commit_per_row(bucket_name, target_data_source, target_file_name, log_info, mode,
settings_list, conn)
elif bulk_import_flag and int(bulk_import_flag) == 1:
# ⑤-2 一括登録フラグがONの場合、一括登録モードでロードスキーマに登録を行う
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-22 - 一括登録モードが有効のため、一括INSERTを実行します')
org_import_process_result = import_data_with_bulk(bucket_name, target_data_source, target_file_name, log_info, mode,
settings_list, conn)
else:
# nop
pass
# 処理件数カウンタ
process_count = org_import_process_result['counts']['process']
# 正常終了件数カウンタ
normal_count = org_import_process_result['counts']['normal']
# ワーニング終了件数カウンター
warning_count = org_import_process_result['counts']['warning']
# ワーニング情報
warning_info = org_import_process_result['warning_info']
# ⑥ ⑤の処理結果件数をログ出力する
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-07 - 投入データ件数:{process_count} 正常終了件数:{normal_count}')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-07 - 投入データ件数:{process_count} 正常終了件数:{normal_count}')
if warning_info:
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["w"]} W-MAIN-02 - Warning終了件数{warning_count}')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {WARNING} W-MAIN-02 - Warning終了件数{warning_count}')
# ⑦ ロードスキーマのデータを蓄積スキーマにUPSERTする
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-08 - ロードスキーマ({settings_list[SETTINGS_ITEM["loadSchemaName"]]})のデータを蓄積スキーマ({settings_list[SETTINGS_ITEM["storageSchemaName"]]})に登録します')
storage_schema_name = settings_list[SETTINGS_ITEM["storageSchemaName"]]
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-08 - ' +
f'ロードスキーマ({load_schema_name})のデータを蓄積スキーマ({storage_schema_name})に登録します')
# インポート方法判断
try:
if truncate_judge(settings_list):
with conn.cursor() as cur:
sql_truncate = f'TRUNCATE table {settings_list[SETTINGS_ITEM["storageSchemaName"]]}'
sql_truncate = f'TRUNCATE table {storage_schema_name}'
cur.execute(sql_truncate)
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-20 - {settings_list[SETTINGS_ITEM["storageSchemaName"]]} をTRUNCATEしました')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO}' +
f' I-MAIN-20 - {storage_schema_name} をTRUNCATEしました')
except InvalidConfigException as e:
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["e"]} E-MAIN-01 - エラー内容:{e}')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {ERROR} E-MAIN-01 - エラー内容:{e}')
error(bucket_name, target_data_source, target_file_name, log_info)
# SQL文生成
sql = f'INSERT INTO {settings_list[SETTINGS_ITEM["storageSchemaName"]]} ('
settings_db_columu_list = settings_list[SETTINGS_ITEM["dbColumuName"]].rstrip(
).split(',')
sql = f'INSERT INTO {storage_schema_name} ('
for i in range(len(settings_db_columu_list)):
sql = f'{sql} {settings_db_columu_list[i]},'
sql = f'{sql} file_name,' # システム項目:取込ファイル名
@ -218,79 +162,357 @@ def main(bucket_name, target_data_source, target_file_name, settings_key, db_inf
sql = f'{sql} t.ins_date,' # システム項目:登録日時
sql = f'{sql} t.upd_user,' # システム項目:更新者
sql = f'{sql} t.upd_date' # システム項目:更新日時
sql = f'{sql} FROM {settings_list[SETTINGS_ITEM["loadSchemaName"]]} as t'
sql = f'{sql} FROM {load_schema_name} as t'
sql = f'{sql} ON DUPLICATE KEY UPDATE'
for i in range(len(settings_db_columu_list)):
sql = f'{sql} {settings_db_columu_list[i]}=t.{settings_db_columu_list[i]},'
sql = f'{sql} file_name=t.file_name,' # システム項目:取込ファイル名
sql = f'{sql} file_row_cnt=t.file_row_cnt,' # システム項目:取込ファイル行番号
sql = f'{sql} delete_flg={settings_list[SETTINGS_ITEM["storageSchemaName"]]}.delete_flg,' # システム項目:論理削除フラグ
sql = f'{sql} ins_user={settings_list[SETTINGS_ITEM["storageSchemaName"]]}.ins_user,' # システム項目:登録者
sql = f'{sql} ins_date={settings_list[SETTINGS_ITEM["storageSchemaName"]]}.ins_date,' # システム項目:登録日時
sql = f'{sql} upd_user=t.ins_user,' # システム項目:更新者
sql = f'{sql} upd_date=t.ins_date' # システム項目:更新日時
# システム項目:取込ファイル名
sql = f'{sql} file_name=t.file_name,'
# システム項目:取込ファイル行番号
sql = f'{sql} file_row_cnt=t.file_row_cnt,'
# システム項目:論理削除フラグ
sql = f'{sql} delete_flg={storage_schema_name}.delete_flg,'
# システム項目:登録者
sql = f'{sql} ins_user={storage_schema_name}.ins_user,'
# システム項目:登録日時
sql = f'{sql} ins_date={storage_schema_name}.ins_date,'
# システム項目:更新者
sql = f'{sql} upd_user=t.ins_user,'
# システム項目:更新日時
sql = f'{sql} upd_date=t.ins_date'
debug_log(sql, log_info, mode)
# トランザクション開始
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-09 - 標準SQL{settings_list[SETTINGS_ITEM["storageSchemaName"]]} のトランザクションを開始します')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-09 - ' +
f'標準SQL{storage_schema_name} のトランザクションを開始します')
with conn.cursor() as cur:
cur.execute(sql)
conn.commit()
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-10 - 標準SQL{settings_list[SETTINGS_ITEM["storageSchemaName"]]} のCOMIIT処理が正常終了しました')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-10 - ' +
f'標準SQL{storage_schema_name} のCOMMIT処理が正常終了しました')
# ⑧ 個別設定ファイルに拡張SQLファイル名が設定されているかチェック
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-11 - 拡張SQL設定が存在するかチェックします')
if settings_list[SETTINGS_ITEM["exSqlFileName"]]:
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-11 - 拡張SQL設定が存在するかチェックします')
ex_sql_file_name = settings_list[SETTINGS_ITEM["exSqlFileName"]]
if ex_sql_file_name:
try:
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-12 - 拡張SQL設定の存在を確認しました')
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-13 - 拡張SQLファイル名{settings_list[SETTINGS_ITEM["exSqlFileName"]]} の存在チェック')
ex_sql_key = target_data_source + DIRECTORY_SETTINGS + settings_list[SETTINGS_ITEM["exSqlFileName"]]
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-12 - 拡張SQL設定の存在を確認しました')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-13 - 拡張SQLファイル名{ex_sql_file_name} の存在チェック')
ex_sql_key = target_data_source + DIRECTORY_SETTINGS + ex_sql_file_name
s3_client.head_object(Bucket=bucket_name, Key=ex_sql_key)
ex_sql_file_exists = True
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-14 - 拡張SQLファイル名の存在を確認しました')
except Exception as e:
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-14 - 拡張SQLファイル名の存在を確認しました')
except Exception:
warning_info = f'{warning_info}- 拡張SQLファイルが存在しません\n'
ex_sql_file_exists = False
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["w"]} W-MAIN-03 - 拡張SQLファイルが存在しません')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {WARNING} W-MAIN-03 - 拡張SQLファイルが存在しません')
try:
if ex_sql_file_exists:
# 拡張SQLファイルからSQL文生成
ex_sql_obj_response = s3_client.get_object(Bucket=bucket_name, Key=ex_sql_key)
ex_sql_obj_response = s3_client.get_object(
Bucket=bucket_name, Key=ex_sql_key)
ex_sql = ''
for line in io.TextIOWrapper(io.BytesIO(ex_sql_obj_response["Body"].read()), encoding='utf-8'):
ex_sql = f'{ex_sql} {line.rstrip()}'
# トランザクション開始
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-15 - 拡張SQL{settings_list[SETTINGS_ITEM["storageSchemaName"]]} のトランザクションを開始します')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-15 - 拡張SQL{storage_schema_name} のトランザクションを開始します')
with conn.cursor() as cur:
cur.execute(ex_sql)
conn.commit()
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-16 - 拡張SQL{settings_list[SETTINGS_ITEM["storageSchemaName"]]} のCOMIIT処理が正常終了しました')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-16 - 拡張SQL{storage_schema_name} のCOMMIT処理が正常終了しました')
except Exception as e:
warning_info = f'{warning_info}- 拡張SQLにエラーが発生しました{e}\n'
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["w"]} W-MAIN-04 - 拡張SQLにエラーが発生しました{e}')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {WARNING} W-MAIN-04 - 拡張SQLにエラーが発生しました{e}')
else:
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-17 - 拡張SQL設定の存在はありませんでした')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-17 - 拡張SQL設定の存在はありませんでした')
# ⑨ DB接続を終了する
connection_close(conn, bucket_name, target_data_source, target_file_name, log_info)
connection_close(conn, bucket_name, target_data_source,
target_file_name, log_info)
except Exception as e:
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["e"]} E-MAIN-99 - エラー内容:{e}')
connection_close(conn, bucket_name, target_data_source, target_file_name, log_info)
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {ERROR} E-MAIN-99 - エラー内容:{e}')
connection_close(conn, bucket_name, target_data_source,
target_file_name, log_info)
error(bucket_name, target_data_source, target_file_name, log_info)
try:
# ⑩ メイン処理終了ログを出力する
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-19 - メイン処理を終了します')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-19 - メイン処理を終了します')
return warning_info
except Exception as e:
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["e"]} E-MAIN-99 - エラー内容:{e}')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {ERROR} E-MAIN-99 - エラー内容:{e}')
error(bucket_name, target_data_source, target_file_name, log_info)
def import_data_with_commit_per_row(
bucket_name: str,
target_data_source: str,
target_file_name: str,
log_info: str,
mode: str,
settings_list: list[dict],
conn: pymysql.Connection) -> dict:
"""一行コミットモードでロードスキーマに登録を行います
Args:
bucket_name (str): バケット名
target_data_source (str): 投入データのディレクトリ名よりデータソースに該当する部分
target_file_name (str): 投入データのファイル名
log_info (str): ログに記載するデータソース名とファイル名
mode (str): 処理モード
settings_list (list[dict]): 設定ファイル
conn (pymysql.Connection): DB接続
Returns:
dict: 処理件数投入データ件数正常終了件数ワーニング件数とワーニング情報の辞書オブジェクト
"""
# ⑤-1 投入データファイルを1行ごとにループする
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-05 - 投入データ {target_file_name} の読み込みを開始します')
import_data_bytes = None
compressed_flag = settings_list[SETTINGS_ITEM["compressedFlag"]]
if not compressed_flag or int(compressed_flag) == 0:
# 圧縮フラグが未設定、またはOFFの場合、S3バケット上の投入データファイルを読む
work_key = target_data_source + DIRECTORY_WORK + target_file_name
work_response = s3_client.get_object(
Bucket=bucket_name, Key=work_key)
import_data_bytes = work_response["Body"].read()
# 圧縮フラグがONの場合、チェック処理で展開済みのtmpディレクトリ内のファイルを読む
elif compressed_flag and int(compressed_flag) == 1:
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-21 - ファイルが圧縮されていたため、展開済みのファイルを利用します')
with open(LOCAL_TEMPORARY_FILE_PATH, 'rb') as f:
import_data_bytes = f.read()
else:
# nop
pass
work_data = io.TextIOWrapper(io.BytesIO(import_data_bytes), encoding=settings_list[SETTINGS_ITEM["charCode"]],
newline=LINE_FEED_CODE[settings_list[SETTINGS_ITEM["lineFeedCode"]]])
process_count = 0 # 処理件数カウンタ
normal_count = 0 # 正常終了件数カウンタ
warning_count = 0 # ワーニング終了件数カウンター
warning_info = '' # ワーニング情報
index = 0 # ループインデックス
settings_db_columu_list = settings_list[SETTINGS_ITEM["dbColumuName"]].rstrip(
).split(',')
settings_replace_comma_list = settings_list[SETTINGS_ITEM["commaReplaceColumns"]].rstrip(
).split(',')
for line in csv.reader(work_data, quotechar=convert_quotechar(settings_list[SETTINGS_ITEM["quotechar"]]),
delimiter=settings_list[SETTINGS_ITEM["delimiter"]]):
try:
if int(settings_list[SETTINGS_ITEM["headerFlag"]]) == 1 and index == 0:
index += 1
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-06 - ヘッダー行をスキップします')
continue
# 処理件数カウント
process_count += 1
# SQL文生成
query_parameter_list = []
sql = f'INSERT INTO {settings_list[SETTINGS_ITEM["loadSchemaName"]]} ('
for db_column in settings_db_columu_list:
sql = f'{sql} {db_column},'
sql = f'{sql} file_name,' # システム項目:取込ファイル名
sql = f'{sql} file_row_cnt,' # システム項目:取込ファイル行番号
sql = f'{sql} delete_flg,' # システム項目:論理削除フラグ
sql = f'{sql} ins_user,' # システム項目:登録者
sql = f'{sql} ins_date,' # システム項目:登録日時
sql = f'{sql} upd_user,' # システム項目:更新者
sql = f'{sql} upd_date)' # システム項目:更新日時
sql = f'{sql} VALUES ('
for i in range(len(line)):
# データ項目値が0桁より大きいかチェックする
if len(line[i]) == 0:
# 0桁の場合
sql = f'{sql} NULL,'
continue
# データ項目値の変換処理(カンマ除去)
org_column_value = line[i]
current_settings_db_column_name = settings_db_columu_list[i]
column_value = convert_column_value(
org_column_value, current_settings_db_column_name, settings_replace_comma_list)
# INSERT文のパラメータとそれに対応するプレースホルダーを設定する
query_parameter_list.append(column_value)
sql = f'{sql} %s,'
sql = f'{sql} "{target_file_name}",' # システム項目:取込ファイル名
sql = f'{sql} "{index + 1}",' # システム項目:取込ファイル行番号
sql = f'{sql} "0",' # システム項目:論理削除フラグ
sql = f'{sql} CURRENT_USER(),' # システム項目:登録者
sql = f'{sql} CURRENT_TIMESTAMP(),' # システム項目:登録日時
sql = f'{sql} NULL,' # システム項目:更新者
sql = f'{sql} NULL)' # システム項目:更新日時
index += 1
debug_log(sql, log_info, mode)
# ロードスキーマのトランザクション開始
with conn.cursor() as cur:
cur.execute(sql, query_parameter_list)
conn.commit()
normal_count += 1
except Exception as e:
warning_count += 1
warning_info = f'{warning_info}{index} ロードスキーマ登録時にエラーが発生しました {line} {e}\n'
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {WARNING} W-MAIN-01 {index} ロードスキーマ登録時にエラーが発生しました {line} {e}')
return {
"counts": {
"process": process_count,
"normal": normal_count,
"warning": warning_count
},
"warning_info": warning_info
}
def import_data_with_bulk(
bucket_name: str,
target_data_source: str,
target_file_name: str,
log_info: str,
mode: str,
settings_list: list[dict],
conn: pymysql.Connection) -> dict:
"""一括登録モードでロードスキーマに登録を行います
Args:
bucket_name (str): バケット名
target_data_source (str): 投入データのディレクトリ名よりデータソースに該当する部分
target_file_name (str): 投入データのファイル名
log_info (str): ログに記載するデータソース名とファイル名
mode (str): 処理モード
settings_list (list[dict]): 設定ファイル
conn (pymysql.Connection): DB接続
Returns:
dict: 処理件数投入データ件数正常終了件数ワーニング件数とワーニング情報の辞書オブジェクト
"""
# ⑤-2 一括登録を行う
compressed_flag = settings_list[SETTINGS_ITEM["compressedFlag"]]
if not compressed_flag or int(compressed_flag) == 0:
# 圧縮フラグがOFFの場合、投入データをtmpディレクトリにダウンロードする
work_key = target_data_source + DIRECTORY_WORK + target_file_name
s3_client.download_file(
Bucket=bucket_name, Key=work_key, Filename=LOCAL_TEMPORARY_FILE_PATH)
elif compressed_flag and int(compressed_flag) == 1:
# 圧縮フラグがONの場合、チェック処理で展開済みのtmpディレクトリ内のファイルを読むため、何もしない。
pass
else:
# nop
pass
process_count = 0 # 処理件数カウンタ
normal_count = 0 # 正常終了件数カウンタ
warning_count = 0 # ワーニング終了件数カウンター
warning_info = '' # ワーニング情報
load_schema_name = settings_list[SETTINGS_ITEM["loadSchemaName"]]
has_header = settings_list[SETTINGS_ITEM["headerFlag"]] or int(
settings_list[SETTINGS_ITEM["headerFlag"]]) == 1
enclosed_by = convert_quotechar(settings_list[SETTINGS_ITEM["quotechar"]])
settings_db_columu_list = settings_list[SETTINGS_ITEM["dbColumuName"]]\
.rstrip().split(',')
# データファイル内の空文字をNULLに変換するため、各カラムをパラメータ化
variables = [f"@{col_name}" for col_name in settings_db_columu_list]
sets = [f"`{col}` = NULLIF(@{col}, '')"
for col in settings_db_columu_list]
sql = f"""
SET @file_row_cnt = 1;
LOAD DATA LOCAL
INFILE %s
IGNORE
INTO TABLE {load_schema_name}
CHARACTER SET {MYSQL_CHARSET_CODE[settings_list[SETTINGS_ITEM["charCode"]]]}
FIELDS TERMINATED BY {repr(settings_list[SETTINGS_ITEM["delimiter"]])}
ENCLOSED BY {repr(enclosed_by)}
LINES TERMINATED BY {repr(LINE_FEED_CODE[settings_list[SETTINGS_ITEM["lineFeedCode"]]])}
{'IGNORE 1 LINES' if has_header else ''}
({','.join(variables)})
SET
{','.join(sets)},
-- 取込ファイル名
file_name = %s,
-- 取込ファイル行番号
file_row_cnt = (@file_row_cnt := @file_row_cnt + 1),
-- 論理削除フラグ
delete_flg = 0,
-- 登録者
ins_user = CURRENT_USER(),
-- 登録日時
ins_date = CURRENT_TIMESTAMP(),
-- 更新者
upd_user = NULL,
-- 更新日時
upd_date = NULL
;
"""
debug_log(sql, log_info, mode)
try:
# ロードスキーマのトランザクション開始
with conn.cursor() as cur:
cur.execute(sql, [LOCAL_TEMPORARY_FILE_PATH, target_file_name])
# 処理件数と成功件数を取得する
cur.execute("SELECT ROW_COUNT()")
normal_count = cur.fetchone()[0]
cur.execute("SELECT @file_row_cnt")
file_row_cnt = cur.fetchone()[0]
# ファイル行番号はヘッダがある時は-1して、データ行の行数と合わせる。
process_count = file_row_cnt - 1 if has_header else file_row_cnt
conn.commit()
except Exception as e:
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {ERROR} E-MAIN-02 - 一括登録モードのSQL実行に失敗しました。エラー内容 {e}')
error(bucket_name, target_data_source, target_file_name, log_info)
# 処理件数 - 登録件数をワーニング件数とする
warning_count = process_count - normal_count
# ワーニングが1件でもある場合、一部登録ができていないため、ワーニング情報を登録する
if warning_count > 0:
warning_info = f'一部レコードの登録に失敗しています。行が重複している可能性があります。 投入データ件数:{process_count}, 正常終了件数:{normal_count}'
return {
"counts": {
"process": process_count,
"normal": normal_count,
"warning": warning_count
},
"warning_info": warning_info
}
def connection_close(conn, bucket_name, target_data_source, target_file_name, log_info):
"""DB接続切断処理
Args:
@ -302,11 +524,14 @@ def connection_close(conn, bucket_name, target_data_source, target_file_name, lo
"""
try:
conn.close()
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["i"]} I-MAIN-18 - DB接続を終了しました')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {INFO} I-MAIN-18 - DB接続を終了しました')
except Exception as e:
print(f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {LOG_LEVEL["e"]} E-MAIN-99 - エラー内容:{e}')
print(
f'{datetime.now():%Y-%m-%d %H:%M:%S} {log_info} {ERROR} E-MAIN-99 - エラー内容:{e}')
error(bucket_name, target_data_source, target_file_name, log_info)
def convert_column_value(org_column_value, current_settings_db_column_name, settings_replace_comma_list):
"""データ項目値変換処理
- 数値内のカンマ除去処理
@ -320,8 +545,8 @@ def convert_column_value(org_column_value, current_settings_db_column_name, sett
"""
# 投入データのDB物理カラム名が設定ファイルの数値型のDBカラム物理名に含まれている場合、データ項目値の「,」を取り除く
converted_column_value = org_column_value
if current_settings_db_column_name in settings_replace_comma_list:
converted_column_value = converted_column_value.replace(',', '')
if current_settings_db_column_name in settings_replace_comma_list:
converted_column_value = converted_column_value.replace(',', '')
return converted_column_value
@ -335,15 +560,16 @@ def truncate_judge(settings_list):
Returns:
Bool: Truncate対象の場合TrueTruncate対象でない場合False
"""
import_manner = settings_list[SETTINGS_ITEM["importManner"]]
# upsert判定
if not settings_list[SETTINGS_ITEM["importManner"]]:
if not import_manner:
return False
# インポート方法設定チェック
if not settings_list[SETTINGS_ITEM["importManner"]].startswith(TRUNCATE_SRC_TABLE_SYMBOL):
if not import_manner.startswith(TRUNCATE_SRC_TABLE_SYMBOL):
raise InvalidConfigException(INVALID_CONFIG_EXCEPTION_MESSAGE)
import_manner_splitted_list = settings_list[SETTINGS_ITEM["importManner"]].split(':')
import_manner_splitted_list = import_manner.split(
':')
if len(import_manner_splitted_list) != 2:
raise InvalidConfigException(INVALID_CONFIG_EXCEPTION_MESSAGE)
if import_manner_splitted_list[1] != settings_list[SETTINGS_ITEM["storageSchemaName"]]:

View File

@ -0,0 +1,12 @@
tests/*
.coverage
.env
.env.example
.report/*
.vscode/*
.pytest_cache/*
*/__pychache__/*
Dockerfile
pytest.ini
README.md
*.sql

View File

@ -0,0 +1,15 @@
DB_HOST=****************
DB_PORT=****************
DB_USERNAME=****************
DB_PASSWORD=****************
DB_SCHEMA=****************
LOG_LEVEL=INFO
JSKULT_CONFIG_BUCKET=**********************
JSKULT_ARCHIVE_BUCKET=****************
DB_CONNECTION_MAX_RETRY_ATTEMPT=4
DB_CONNECTION_RETRY_INTERVAL_INIT=5
DB_CONNECTION_RETRY_INTERVAL_MIN_SECONDS=5
DB_CONNECTION_RETRY_INTERVAL_MAX_SECONDS=50

View File

@ -0,0 +1,10 @@
.vscode/settings.json
.env
# python
__pycache__
# python test
.pytest_cache
.coverage
.report/

View File

@ -0,0 +1,16 @@
{
// IntelliSense 使
//
// : https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(DEBUG)archive",
"type": "python",
"request": "launch",
"program": "entrypoint.py",
"console": "integratedTerminal",
"justMyCode": true
}
]
}

View File

@ -0,0 +1,31 @@
{
"[python]": {
"editor.defaultFormatter": null,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
}
},
//
"python.defaultInterpreterPath": "<pythonインタプリターのパス>",
"python.linting.lintOnSave": true,
"python.linting.enabled": true,
"python.linting.pylintEnabled": false,
"python.linting.flake8Enabled": true,
"python.linting.flake8Args": [
"--max-line-length=200",
"--ignore=F541"
],
"python.formatting.provider": "autopep8",
"python.formatting.autopep8Path": "autopep8",
"python.formatting.autopep8Args": [
"--max-line-length", "200",
"--ignore=F541"
],
"python.testing.pytestArgs": [
"tests/batch/"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}

View File

@ -0,0 +1,20 @@
FROM python:3.12-slim-bookworm
ENV TZ="Asia/Tokyo"
# pythonの標準出力をバッファリングしないフラグ
ENV PYTHONUNBUFFERED=1
# pythonのバイトコードを生成しないフラグ
ENV PYTHONDONTWRITEBYTECODE=1
WORKDIR /usr/src/app
COPY Pipfile Pipfile.lock ./
RUN \
apt update -y && \
pip install pipenv --no-cache-dir && \
pipenv install --system --deploy && \
pip uninstall -y pipenv virtualenv-clone virtualenv
COPY src ./src
COPY entrypoint.py entrypoint.py
CMD ["python", "entrypoint.py"]

View File

@ -0,0 +1,23 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
boto3 = "*"
PyMySQL = "*"
sqlalchemy = "*"
tenacity = "*"
[dev-packages]
autopep8 = "*"
flake8 = "*"
pytest = "*"
pytest-cov = "*"
boto3 = "*"
[requires]
python_version = "3.12"
[pipenv]
allow_prereleases = true

View File

@ -0,0 +1,447 @@
{
"_meta": {
"hash": {
"sha256": "aa2d1d97600fea225b7d249dae0d065190d00fdadbf85b20773e0c1d9862f5c1"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.12"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"boto3": {
"hashes": [
"sha256:70ab8364f1f6f0a7e0eaf97f62fbdacf9c1e4cc1de330faf1c146ef9ab01e7d0",
"sha256:bcf73aca469add09e165b8793be18e7578db8d2604d82505ab13dc2495bad982"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==1.38.23"
},
"botocore": {
"hashes": [
"sha256:29685c91050a870c3809238dc5da1ac65a48a3a20b4bca46b6057dcb6b39c72a",
"sha256:a7f818672f10d7a080c2c4558428011c3e0abc1039a047d27ac76ec846158457"
],
"markers": "python_version >= '3.9'",
"version": "==1.38.23"
},
"greenlet": {
"hashes": [
"sha256:00cd814b8959b95a546e47e8d589610534cfb71f19802ea8a2ad99d95d702057",
"sha256:02a98600899ca1ca5d3a2590974c9e3ec259503b2d6ba6527605fcd74e08e207",
"sha256:02f5972ff02c9cf615357c17ab713737cccfd0eaf69b951084a9fd43f39833d3",
"sha256:055916fafad3e3388d27dd68517478933a97edc2fc54ae79d3bec827de2c64c4",
"sha256:0a16fb934fcabfdfacf21d79e6fed81809d8cd97bc1be9d9c89f0e4567143d7b",
"sha256:1592a615b598643dbfd566bac8467f06c8c8ab6e56f069e573832ed1d5d528cc",
"sha256:1919cbdc1c53ef739c94cf2985056bcc0838c1f217b57647cbf4578576c63825",
"sha256:1e4747712c4365ef6765708f948acc9c10350719ca0545e362c24ab973017370",
"sha256:1e76106b6fc55fa3d6fe1c527f95ee65e324a13b62e243f77b48317346559708",
"sha256:1f72667cc341c95184f1c68f957cb2d4fc31eef81646e8e59358a10ce6689457",
"sha256:2593283bf81ca37d27d110956b79e8723f9aa50c4bcdc29d3c0543d4743d2763",
"sha256:2dc5c43bb65ec3669452af0ab10729e8fdc17f87a1f2ad7ec65d4aaaefabf6bf",
"sha256:3091bc45e6b0c73f225374fefa1536cd91b1e987377b12ef5b19129b07d93ebe",
"sha256:354f67445f5bed6604e493a06a9a49ad65675d3d03477d38a4db4a427e9aad0e",
"sha256:3885f85b61798f4192d544aac7b25a04ece5fe2704670b4ab73c2d2c14ab740d",
"sha256:3ab7194ee290302ca15449f601036007873028712e92ca15fc76597a0aeb4c59",
"sha256:3aeca9848d08ce5eb653cf16e15bb25beeab36e53eb71cc32569f5f3afb2a3aa",
"sha256:44671c29da26539a5f142257eaba5110f71887c24d40df3ac87f1117df589e0e",
"sha256:45f9f4853fb4cc46783085261c9ec4706628f3b57de3e68bae03e8f8b3c0de51",
"sha256:4bd139e4943547ce3a56ef4b8b1b9479f9e40bb47e72cc906f0f66b9d0d5cab3",
"sha256:4fefc7aa68b34b9224490dfda2e70ccf2131368493add64b4ef2d372955c207e",
"sha256:6629311595e3fe7304039c67f00d145cd1d38cf723bb5b99cc987b23c1433d61",
"sha256:6fadd183186db360b61cb34e81117a096bff91c072929cd1b529eb20dd46e6c5",
"sha256:71566302219b17ca354eb274dfd29b8da3c268e41b646f330e324e3967546a74",
"sha256:7409796591d879425997a518138889d8d17e63ada7c99edc0d7a1c22007d4907",
"sha256:752f0e79785e11180ebd2e726c8a88109ded3e2301d40abced2543aa5d164275",
"sha256:7791dcb496ec53d60c7f1c78eaa156c21f402dda38542a00afc3e20cae0f480f",
"sha256:782743700ab75716650b5238a4759f840bb2dcf7bff56917e9ffdf9f1f23ec59",
"sha256:7c9896249fbef2c615853b890ee854f22c671560226c9221cfd27c995db97e5c",
"sha256:85f3e248507125bf4af607a26fd6cb8578776197bd4b66e35229cdf5acf1dfbf",
"sha256:89c69e9a10670eb7a66b8cef6354c24671ba241f46152dd3eed447f79c29fb5b",
"sha256:8cb8553ee954536500d88a1a2f58fcb867e45125e600e80f586ade399b3f8819",
"sha256:9ae572c996ae4b5e122331e12bbb971ea49c08cc7c232d1bd43150800a2d6c65",
"sha256:9c7b15fb9b88d9ee07e076f5a683027bc3befd5bb5d25954bb633c385d8b737e",
"sha256:9ea5231428af34226c05f927e16fc7f6fa5e39e3ad3cd24ffa48ba53a47f4240",
"sha256:a31ead8411a027c2c4759113cf2bd473690517494f3d6e4bf67064589afcd3c5",
"sha256:a8fa80665b1a29faf76800173ff5325095f3e66a78e62999929809907aca5659",
"sha256:ad053d34421a2debba45aa3cc39acf454acbcd025b3fc1a9f8a0dee237abd485",
"sha256:b24c7844c0a0afc3ccbeb0b807adeefb7eff2b5599229ecedddcfeb0ef333bec",
"sha256:b50a8c5c162469c3209e5ec92ee4f95c8231b11db6a04db09bbe338176723bb8",
"sha256:ba30e88607fb6990544d84caf3c706c4b48f629e18853fc6a646f82db9629418",
"sha256:bf3fc9145141250907730886b031681dfcc0de1c158f3cc51c092223c0f381ce",
"sha256:c23ea227847c9dbe0b3910f5c0dd95658b607137614eb821e6cbaecd60d81cc6",
"sha256:c3cc1a3ed00ecfea8932477f729a9f616ad7347a5e55d50929efa50a86cb7be7",
"sha256:c49e9f7c6f625507ed83a7485366b46cbe325717c60837f7244fc99ba16ba9d6",
"sha256:d0cb7d47199001de7658c213419358aa8937df767936506db0db7ce1a71f4a2f",
"sha256:d8009ae46259e31bc73dc183e402f548e980c96f33a6ef58cc2e7865db012e13",
"sha256:da956d534a6d1b9841f95ad0f18ace637668f680b1339ca4dcfb2c1837880a0b",
"sha256:dcb9cebbf3f62cb1e5afacae90761ccce0effb3adaa32339a0670fe7805d8068",
"sha256:decb0658ec19e5c1f519faa9a160c0fc85a41a7e6654b3ce1b44b939f8bf1325",
"sha256:df4d1509efd4977e6a844ac96d8be0b9e5aa5d5c77aa27ca9f4d3f92d3fcf330",
"sha256:eeb27bece45c0c2a5842ac4c5a1b5c2ceaefe5711078eed4e8043159fa05c834",
"sha256:efcdfb9df109e8a3b475c016f60438fcd4be68cd13a365d42b35914cdab4bb2b",
"sha256:fd9fb7c941280e2c837b603850efc93c999ae58aae2b40765ed682a6907ebbc5",
"sha256:fe46d4f8e94e637634d54477b0cfabcf93c53f29eedcbdeecaf2af32029b4421"
],
"markers": "python_version >= '3.9'",
"version": "==3.2.2"
},
"jmespath": {
"hashes": [
"sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980",
"sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"
],
"markers": "python_version >= '3.7'",
"version": "==1.0.1"
},
"pymysql": {
"hashes": [
"sha256:4de15da4c61dc132f4fb9ab763063e693d521a80fd0e87943b9a453dd4c19d6c",
"sha256:e127611aaf2b417403c60bf4dc570124aeb4a57f5f37b8e95ae399a42f904cd0"
],
"index": "pypi",
"markers": "python_version >= '3.7'",
"version": "==1.1.1"
},
"python-dateutil": {
"hashes": [
"sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3",
"sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
"version": "==2.9.0.post0"
},
"s3transfer": {
"hashes": [
"sha256:0148ef34d6dd964d0d8cf4311b2b21c474693e57c2e069ec708ce043d2b527be",
"sha256:f5e6db74eb7776a37208001113ea7aa97695368242b364d73e91c981ac522177"
],
"markers": "python_version >= '3.9'",
"version": "==0.13.0"
},
"six": {
"hashes": [
"sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274",
"sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
"version": "==1.17.0"
},
"sqlalchemy": {
"hashes": [
"sha256:023b3ee6169969beea3bb72312e44d8b7c27c75b347942d943cf49397b7edeb5",
"sha256:03968a349db483936c249f4d9cd14ff2c296adfa1290b660ba6516f973139582",
"sha256:05132c906066142103b83d9c250b60508af556982a385d96c4eaa9fb9720ac2b",
"sha256:087b6b52de812741c27231b5a3586384d60c353fbd0e2f81405a814b5591dc8b",
"sha256:0b3dbf1e7e9bc95f4bac5e2fb6d3fb2f083254c3fdd20a1789af965caf2d2348",
"sha256:118c16cd3f1b00c76d69343e38602006c9cfb9998fa4f798606d28d63f23beda",
"sha256:1936af879e3db023601196a1684d28e12f19ccf93af01bf3280a3262c4b6b4e5",
"sha256:1e3f196a0c59b0cae9a0cd332eb1a4bda4696e863f4f1cf84ab0347992c548c2",
"sha256:23a8825495d8b195c4aa9ff1c430c28f2c821e8c5e2d98089228af887e5d7e29",
"sha256:293cd444d82b18da48c9f71cd7005844dbbd06ca19be1ccf6779154439eec0b8",
"sha256:32f9dc8c44acdee06c8fc6440db9eae8b4af8b01e4b1aee7bdd7241c22edff4f",
"sha256:34ea30ab3ec98355235972dadc497bb659cc75f8292b760394824fab9cf39826",
"sha256:3d3549fc3e40667ec7199033a4e40a2f669898a00a7b18a931d3efb4c7900504",
"sha256:41836fe661cc98abfae476e14ba1906220f92c4e528771a8a3ae6a151242d2ae",
"sha256:4d44522480e0bf34c3d63167b8cfa7289c1c54264c2950cc5fc26e7850967e45",
"sha256:4eeb195cdedaf17aab6b247894ff2734dcead6c08f748e617bfe05bd5a218443",
"sha256:4f67766965996e63bb46cfbf2ce5355fc32d9dd3b8ad7e536a920ff9ee422e23",
"sha256:57df5dc6fdb5ed1a88a1ed2195fd31927e705cad62dedd86b46972752a80f576",
"sha256:598d9ebc1e796431bbd068e41e4de4dc34312b7aa3292571bb3674a0cb415dd1",
"sha256:5b14e97886199c1f52c14629c11d90c11fbb09e9334fa7bb5f6d068d9ced0ce0",
"sha256:5e22575d169529ac3e0a120cf050ec9daa94b6a9597993d1702884f6954a7d71",
"sha256:60c578c45c949f909a4026b7807044e7e564adf793537fc762b2489d522f3d11",
"sha256:6145afea51ff0af7f2564a05fa95eb46f542919e6523729663a5d285ecb3cf5e",
"sha256:6375cd674fe82d7aa9816d1cb96ec592bac1726c11e0cafbf40eeee9a4516b5f",
"sha256:6854175807af57bdb6425e47adbce7d20a4d79bbfd6f6d6519cd10bb7109a7f8",
"sha256:6ab60a5089a8f02009f127806f777fca82581c49e127f08413a66056bd9166dd",
"sha256:725875a63abf7c399d4548e686debb65cdc2549e1825437096a0af1f7e374814",
"sha256:7492967c3386df69f80cf67efd665c0f667cee67032090fe01d7d74b0e19bb08",
"sha256:81965cc20848ab06583506ef54e37cf15c83c7e619df2ad16807c03100745dea",
"sha256:81c24e0c0fde47a9723c81d5806569cddef103aebbf79dbc9fcbb617153dea30",
"sha256:81eedafa609917040d39aa9332e25881a8e7a0862495fcdf2023a9667209deda",
"sha256:81f413674d85cfd0dfcd6512e10e0f33c19c21860342a4890c3a2b59479929f9",
"sha256:8280856dd7c6a68ab3a164b4a4b1c51f7691f6d04af4d4ca23d6ecf2261b7923",
"sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df",
"sha256:8b4af17bda11e907c51d10686eda89049f9ce5669b08fbe71a29747f1e876036",
"sha256:90144d3b0c8b139408da50196c5cad2a6909b51b23df1f0538411cd23ffa45d3",
"sha256:906e6b0d7d452e9a98e5ab8507c0da791856b2380fdee61b765632bb8698026f",
"sha256:90c11ceb9a1f482c752a71f203a81858625d8df5746d787a4786bca4ffdf71c6",
"sha256:911cc493ebd60de5f285bcae0491a60b4f2a9f0f5c270edd1c4dbaef7a38fc04",
"sha256:9a420a91913092d1e20c86a2f5f1fc85c1a8924dbcaf5e0586df8aceb09c9cc2",
"sha256:9f8c9fdd15a55d9465e590a402f42082705d66b05afc3ffd2d2eb3c6ba919560",
"sha256:a104c5694dfd2d864a6f91b0956eb5d5883234119cb40010115fd45a16da5e70",
"sha256:a373a400f3e9bac95ba2a06372c4fd1412a7cee53c37fc6c05f829bf672b8769",
"sha256:a62448526dd9ed3e3beedc93df9bb6b55a436ed1474db31a2af13b313a70a7e1",
"sha256:a8808d5cf866c781150d36a3c8eb3adccfa41a8105d031bf27e92c251e3969d6",
"sha256:b1f09b6821406ea1f94053f346f28f8215e293344209129a9c0fcc3578598d7b",
"sha256:b2ac41acfc8d965fb0c464eb8f44995770239668956dc4cdf502d1b1ffe0d747",
"sha256:b46fa6eae1cd1c20e6e6f44e19984d438b6b2d8616d21d783d150df714f44078",
"sha256:b50eab9994d64f4a823ff99a0ed28a6903224ddbe7fef56a6dd865eec9243440",
"sha256:bfc9064f6658a3d1cadeaa0ba07570b83ce6801a1314985bf98ec9b95d74e15f",
"sha256:c0b0e5e1b5d9f3586601048dd68f392dc0cc99a59bb5faf18aab057ce00d00b2",
"sha256:c153265408d18de4cc5ded1941dcd8315894572cddd3c58df5d5b5705b3fa28d",
"sha256:d4ae769b9c1c7757e4ccce94b0641bc203bbdf43ba7a2413ab2523d8d047d8dc",
"sha256:dc56c9788617b8964ad02e8fcfeed4001c1f8ba91a9e1f31483c0dffb207002a",
"sha256:dd5ec3aa6ae6e4d5b5de9357d2133c07be1aff6405b136dad753a16afb6717dd",
"sha256:edba70118c4be3c2b1f90754d308d0b79c6fe2c0fdc52d8ddf603916f83f4db9",
"sha256:ff8e80c4c4932c10493ff97028decfdb622de69cae87e0f127a7ebe32b4069c6"
],
"index": "pypi",
"markers": "python_version >= '3.7'",
"version": "==2.0.41"
},
"tenacity": {
"hashes": [
"sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb",
"sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==9.1.2"
},
"typing-extensions": {
"hashes": [
"sha256:6cd49c8b914bb3869a16ed9d1001e3d0ff1d84fae4838076fe3b361ab8b32b65",
"sha256:90196079d79b4658568e177f50c24c327b73a85e664c0af9f3937e2015b65956"
],
"markers": "python_version >= '3.9'",
"version": "==4.14.0rc1"
},
"urllib3": {
"hashes": [
"sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466",
"sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"
],
"markers": "python_version >= '3.9'",
"version": "==2.4.0"
}
},
"develop": {
"autopep8": {
"hashes": [
"sha256:89440a4f969197b69a995e4ce0661b031f455a9f776d2c5ba3dbd83466931758",
"sha256:ce8ad498672c845a0c3de2629c15b635ec2b05ef8177a6e7c91c74f3e9b51128"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==2.3.2"
},
"boto3": {
"hashes": [
"sha256:70ab8364f1f6f0a7e0eaf97f62fbdacf9c1e4cc1de330faf1c146ef9ab01e7d0",
"sha256:bcf73aca469add09e165b8793be18e7578db8d2604d82505ab13dc2495bad982"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==1.38.23"
},
"botocore": {
"hashes": [
"sha256:29685c91050a870c3809238dc5da1ac65a48a3a20b4bca46b6057dcb6b39c72a",
"sha256:a7f818672f10d7a080c2c4558428011c3e0abc1039a047d27ac76ec846158457"
],
"markers": "python_version >= '3.9'",
"version": "==1.38.23"
},
"coverage": {
"extras": [
"toml"
],
"hashes": [
"sha256:00f2e2f2e37f47e5f54423aeefd6c32a7dbcedc033fcd3928a4f4948e8b96af7",
"sha256:05364b9cc82f138cc86128dc4e2e1251c2981a2218bfcd556fe6b0fbaa3501be",
"sha256:0774df1e093acb6c9e4d58bce7f86656aeed6c132a16e2337692c12786b32404",
"sha256:07a989c867986c2a75f158f03fdb413128aad29aca9d4dbce5fc755672d96f11",
"sha256:0bdc8bf760459a4a4187b452213e04d039990211f98644c7292adf1e471162b5",
"sha256:0e49824808d4375ede9dd84e9961a59c47f9113039f1a525e6be170aa4f5c34d",
"sha256:145b07bea229821d51811bf15eeab346c236d523838eda395ea969d120d13347",
"sha256:159b81df53a5fcbc7d45dae3adad554fdbde9829a994e15227b3f9d816d00b36",
"sha256:1676628065a498943bd3f64f099bb573e08cf1bc6088bbe33cf4424e0876f4b3",
"sha256:1aec326ed237e5880bfe69ad41616d333712c7937bcefc1343145e972938f9b3",
"sha256:1e1448bb72b387755e1ff3ef1268a06617afd94188164960dba8d0245a46004b",
"sha256:1efa4166ba75ccefd647f2d78b64f53f14fb82622bc94c5a5cb0a622f50f1c9e",
"sha256:26a4636ddb666971345541b59899e969f3b301143dd86b0ddbb570bd591f1e85",
"sha256:2bd0a0a5054be160777a7920b731a0570284db5142abaaf81bcbb282b8d99279",
"sha256:2c08b05ee8d7861e45dc5a2cc4195c8c66dca5ac613144eb6ebeaff2d502e73d",
"sha256:2db10dedeb619a771ef0e2949ccba7b75e33905de959c2643a4607bef2f3fb3a",
"sha256:2f9bc608fbafaee40eb60a9a53dbfb90f53cc66d3d32c2849dc27cf5638a21e3",
"sha256:34759ee2c65362163699cc917bdb2a54114dd06d19bab860725f94ef45a3d9b7",
"sha256:3da9b771c98977a13fbc3830f6caa85cae6c9c83911d24cb2d218e9394259c57",
"sha256:3f5673888d3676d0a745c3d0e16da338c5eea300cb1f4ada9c872981265e76d8",
"sha256:4000a31c34932e7e4fa0381a3d6deb43dc0c8f458e3e7ea6502e6238e10be625",
"sha256:43ff5033d657cd51f83015c3b7a443287250dc14e69910577c3e03bd2e06f27b",
"sha256:46d532db4e5ff3979ce47d18e2fe8ecad283eeb7367726da0e5ef88e4fe64740",
"sha256:496948261eaac5ac9cf43f5d0a9f6eb7a6d4cb3bedb2c5d294138142f5c18f2a",
"sha256:4c26c2396674816deaeae7ded0e2b42c26537280f8fe313335858ffff35019be",
"sha256:5040536cf9b13fb033f76bcb5e1e5cb3b57c4807fef37db9e0ed129c6a094257",
"sha256:546e537d9e24efc765c9c891328f30f826e3e4808e31f5d0f87c4ba12bbd1622",
"sha256:5e818796f71702d7a13e50c70de2a1924f729228580bcba1607cccf32eea46e6",
"sha256:5feb7f2c3e6ea94d3b877def0270dff0947b8d8c04cfa34a17be0a4dc1836879",
"sha256:641988828bc18a6368fe72355df5f1703e44411adbe49bba5644b941ce6f2e3a",
"sha256:670a13249b957bb9050fab12d86acef7bf8f6a879b9d1a883799276e0d4c674a",
"sha256:6782a12bf76fa61ad9350d5a6ef5f3f020b57f5e6305cbc663803f2ebd0f270a",
"sha256:684ca9f58119b8e26bef860db33524ae0365601492e86ba0b71d513f525e7050",
"sha256:6e6c86888fd076d9e0fe848af0a2142bf606044dc5ceee0aa9eddb56e26895a0",
"sha256:726f32ee3713f7359696331a18daf0c3b3a70bb0ae71141b9d3c52be7c595e32",
"sha256:76090fab50610798cc05241bf83b603477c40ee87acd358b66196ab0ca44ffa1",
"sha256:8165584ddedb49204c4e18da083913bdf6a982bfb558632a79bdaadcdafd0d48",
"sha256:820157de3a589e992689ffcda8639fbabb313b323d26388d02e154164c57b07f",
"sha256:8369a7c8ef66bded2b6484053749ff220dbf83cba84f3398c84c51a6f748a008",
"sha256:86a323a275e9e44cdf228af9b71c5030861d4d2610886ab920d9945672a81223",
"sha256:876cbfd0b09ce09d81585d266c07a32657beb3eaec896f39484b631555be0fe2",
"sha256:8966a821e2083c74d88cca5b7dcccc0a3a888a596a04c0b9668a891de3a0cc53",
"sha256:8ab4a51cb39dc1933ba627e0875046d150e88478dbe22ce145a68393e9652975",
"sha256:8e1a26e7e50076e35f7afafde570ca2b4d7900a491174ca357d29dece5aacee7",
"sha256:94316e13f0981cbbba132c1f9f365cac1d26716aaac130866ca812006f662199",
"sha256:9a990f6510b3292686713bfef26d0049cd63b9c7bb17e0864f133cbfd2e6167f",
"sha256:9fe449ee461a3b0c7105690419d0b0aba1232f4ff6d120a9e241e58a556733f7",
"sha256:a886d531373a1f6ff9fad2a2ba4a045b68467b779ae729ee0b3b10ac20033b27",
"sha256:ab9b09a2349f58e73f8ebc06fac546dd623e23b063e5398343c5270072e3201c",
"sha256:b039ffddc99ad65d5078ef300e0c7eed08c270dc26570440e3ef18beb816c1ca",
"sha256:b069938961dfad881dc2f8d02b47645cd2f455d3809ba92a8a687bf513839787",
"sha256:b99058eef42e6a8dcd135afb068b3d53aff3921ce699e127602efff9956457a9",
"sha256:bd8ec21e1443fd7a447881332f7ce9d35b8fbd2849e761bb290b584535636b0a",
"sha256:bf8111cddd0f2b54d34e96613e7fbdd59a673f0cf5574b61134ae75b6f5a33b8",
"sha256:c9392773cffeb8d7e042a7b15b82a414011e9d2b5fdbbd3f7e6a6b17d5e21b20",
"sha256:cb86337a4fcdd0e598ff2caeb513ac604d2f3da6d53df2c8e368e07ee38e277d",
"sha256:da23ce9a3d356d0affe9c7036030b5c8f14556bd970c9b224f9c8205505e3b99",
"sha256:dc67994df9bcd7e0150a47ef41278b9e0a0ea187caba72414b71dc590b99a108",
"sha256:de77c3ba8bb686d1c411e78ee1b97e6e0b963fb98b1637658dd9ad2c875cf9d7",
"sha256:e2f6fe3654468d061942591aef56686131335b7a8325684eda85dacdf311356c",
"sha256:e6ea7dba4e92926b7b5f0990634b78ea02f208d04af520c73a7c876d5a8d36cb",
"sha256:e6fcbbd35a96192d042c691c9e0c49ef54bd7ed865846a3c9d624c30bb67ce46",
"sha256:ea561010914ec1c26ab4188aef8b1567272ef6de096312716f90e5baa79ef8ca",
"sha256:eacd2de0d30871eff893bab0b67840a96445edcb3c8fd915e6b11ac4b2f3fa6d",
"sha256:ec455eedf3ba0bbdf8f5a570012617eb305c63cb9f03428d39bf544cb2b94837",
"sha256:ef2f22795a7aca99fc3c84393a55a53dd18ab8c93fb431004e4d8f0774150f54",
"sha256:fd51355ab8a372d89fb0e6a31719e825cf8df8b6724bee942fb5b92c3f016ba3"
],
"markers": "python_version >= '3.9'",
"version": "==7.8.2"
},
"flake8": {
"hashes": [
"sha256:93b92ba5bdb60754a6da14fa3b93a9361fd00a59632ada61fd7b130436c40343",
"sha256:fa558ae3f6f7dbf2b4f22663e5343b6b6023620461f8d4ff2019ef4b5ee70426"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==7.2.0"
},
"iniconfig": {
"hashes": [
"sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7",
"sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"
],
"markers": "python_version >= '3.8'",
"version": "==2.1.0"
},
"jmespath": {
"hashes": [
"sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980",
"sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"
],
"markers": "python_version >= '3.7'",
"version": "==1.0.1"
},
"mccabe": {
"hashes": [
"sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
"sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
],
"markers": "python_version >= '3.6'",
"version": "==0.7.0"
},
"packaging": {
"hashes": [
"sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484",
"sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"
],
"markers": "python_version >= '3.8'",
"version": "==25.0"
},
"pluggy": {
"hashes": [
"sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3",
"sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"
],
"markers": "python_version >= '3.9'",
"version": "==1.6.0"
},
"pycodestyle": {
"hashes": [
"sha256:35863c5974a271c7a726ed228a14a4f6daf49df369d8c50cd9a6f58a5e143ba9",
"sha256:c8415bf09abe81d9c7f872502a6eee881fbe85d8763dd5b9924bb0a01d67efae"
],
"markers": "python_version >= '3.9'",
"version": "==2.13.0"
},
"pyflakes": {
"hashes": [
"sha256:5039c8339cbb1944045f4ee5466908906180f13cc99cc9949348d10f82a5c32a",
"sha256:6dfd61d87b97fba5dcfaaf781171ac16be16453be6d816147989e7f6e6a9576b"
],
"markers": "python_version >= '3.9'",
"version": "==3.3.2"
},
"pytest": {
"hashes": [
"sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820",
"sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
"version": "==8.3.5"
},
"pytest-cov": {
"hashes": [
"sha256:46935f7aaefba760e716c2ebfbe1c216240b9592966e7da99ea8292d4d3e2a0a",
"sha256:bddf29ed2d0ab6f4df17b4c55b0a657287db8684af9c42ea546b21b1041b3dde"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==6.1.1"
},
"python-dateutil": {
"hashes": [
"sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3",
"sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
"version": "==2.9.0.post0"
},
"s3transfer": {
"hashes": [
"sha256:0148ef34d6dd964d0d8cf4311b2b21c474693e57c2e069ec708ce043d2b527be",
"sha256:f5e6db74eb7776a37208001113ea7aa97695368242b364d73e91c981ac522177"
],
"markers": "python_version >= '3.9'",
"version": "==0.13.0"
},
"six": {
"hashes": [
"sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274",
"sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
"version": "==1.17.0"
},
"urllib3": {
"hashes": [
"sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466",
"sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"
],
"markers": "python_version >= '3.9'",
"version": "==2.4.0"
}
}
}

View File

@ -0,0 +1,72 @@
# 実消化過去データアーカイブ処理
## 概要
実消化過去データアーカイブ処理。
## 環境情報
- Python 3.12
- 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」で行っている。
## フォルダ構成
```text
.
├── Pipfile -- Pythonモジュールの依存関係を管理するファイル
├── Dockerfile -- Dockerイメージを作成するためのファイル
├── Pipfile -- Pythonモジュールの依存関係を管理するファイル
├── Pipfile.lock -- Pythonモジュールの依存関係バージョン固定用ファイル
├── README.md -- 当ファイル
├── entrypoint.py -- バッチ処理のエントリーポイントになるpythonファイル
└── src -- ソースコードの保管場所
├── aws -- AWS関連処理
│ └── s3.py -- S3クライアントとバケット処理
├── batch -- バッチ処理関連ソース置き場
│ ├── archive_jsk_data.py -- 実消化過去データアーカイブ処理
│ └── jskult_archive_manager.py -- アーカイブ管理テーブル操作処理
├── db
│ └── database.py -- データベース操作共通処理
├── error
│ └── exceptions.py -- カスタム例外
├── logging
│ └── get_logger.py -- ログ出力の共通処理
└── system_var
├── constants.py -- 定数
└── environment.py -- 環境変数

View File

@ -0,0 +1,10 @@
"""実消化過去データアーカイブ処理ののエントリーポイント"""
from src.batch import archive_jsk_data
if __name__ == '__main__':
# try:
exit(archive_jsk_data.exec())
# except Exception:
# エラーが起きても、正常系のコードで返す。
# エラーが起きた事実はbatch_process内でログを出す。
exit(0)

View File

@ -0,0 +1,3 @@
[pytest]
log_format = %(levelname)s %(asctime)s %(message)s
log_date_format = %Y-%m-%d %H:%M:%S

View File

@ -0,0 +1,61 @@
import boto3
from src.system_var import environment
class S3Client:
__s3_client = boto3.client('s3')
_bucket_name: str
def list_objects(self, bucket_name: str, folder_name: str):
response = self.__s3_client.list_objects_v2(
Bucket=bucket_name, Prefix=folder_name)
if response['KeyCount'] == 0:
return []
contents = response['Contents']
# 末尾がスラッシュで終わるものはフォルダとみなしてスキップする
objects = [{'filename': content['Key'], 'size': content['Size']}
for content in contents if not content['Key'].endswith('/')]
return objects
def copy(self, src_bucket: str, src_key: str, dest_bucket: str, dest_key: str) -> None:
copy_source = {'Bucket': src_bucket, 'Key': src_key}
self.__s3_client.copy(copy_source, dest_bucket, dest_key)
return
def download_file(self, bucket_name: str, file_key: str, file):
self.__s3_client.download_fileobj(
Bucket=bucket_name,
Key=file_key,
Fileobj=file
)
return
def upload_file(self, local_file_path: str, bucket_name: str, file_key: str):
self.__s3_client.upload_file(
local_file_path,
Bucket=bucket_name,
Key=file_key
)
def delete_file(self, bucket_name: str, file_key: str):
self.__s3_client.delete_object(
Bucket=bucket_name,
Key=file_key
)
class S3Bucket():
_s3_client = S3Client()
_bucket_name: str = None
class JskultArchiveBucket(S3Bucket):
_bucket_name = environment.JSKULT_ARCHIVE_BUCKET
def upload_archive_zip_file(self, archive_zip: str, archive_zip_path: str, send_folder: str):
# S3バケットにファイルを移動
archive_zip_name = f'{send_folder}/{archive_zip}'
s3_client = S3Client()
s3_client.upload_file(
archive_zip_path, self._bucket_name, archive_zip_name)
return f"{self._bucket_name}/{archive_zip_name}"

View File

@ -0,0 +1,82 @@
import csv
import os.path as path
import tempfile
import zipfile
from datetime import timedelta
from src.aws.s3 import JskultArchiveBucket
from src.batch.jskult_archive_manager import JskultArchiveManager
from src.logging.get_logger import get_logger
logger = get_logger("実消化_過去データアーカイブ処理")
def exec():
"""実消化_過去データアーカイブ処理"""
try:
logger.info("処理開始:実消化_過去データアーカイブ処理")
jskult_archive_manager = JskultArchiveManager()
# アーカイブ管理テーブルから対象テーブル、条件項目、条件年月、実行間隔(月)、前回条件年月、保存先を取得
jskult_archive_manage_data_list = jskult_archive_manager.get_archive_manage()
# 取得したレコード分繰り返す
for jskult_archive_manage_data in jskult_archive_manage_data_list:
# 対象テーブルで条件項目が条件年月以前のデータを取得
archive_data = jskult_archive_manager.get_archive_data(
jskult_archive_manage_data["target_table"],
jskult_archive_manage_data["filter_column_name"],
jskult_archive_manage_data["filter_column_type"],
jskult_archive_manage_data["filter_column_digit"],
jskult_archive_manage_data["filter_date"])
# 取得データが0件の場合、スキップする
if not archive_data:
logger.info(
f"アーカイブ対象データがありませんでした。対象テーブル:{jskult_archive_manage_data['target_table']} 条件年月:{jskult_archive_manage_data['filter_date']}")
continue
# 一時フォルダ作成
with tempfile.TemporaryDirectory() as temporary_dir:
# 取得したデータをCSVに出力
day_after_prev_filter_date = jskult_archive_manage_data["prev_filter_date"] + timedelta(
days=1)
file_name = f'{jskult_archive_manage_data["target_table"]}_{day_after_prev_filter_date.strftime('%Y%m%d')}_{jskult_archive_manage_data["filter_date"].strftime('%Y%m%d')}'
csv_file_path = path.join(temporary_dir, f"{file_name}.csv")
headers = archive_data[0].keys()
with open(csv_file_path, 'w', newline='') as file:
writer = csv.DictWriter(
file, fieldnames=headers, quoting=csv.QUOTE_ALL)
writer.writeheader()
writer.writerows(archive_data)
logger.info(f"CSVファイル作成に成功しました。{file_name}.csv")
# 作成したCSVをzip形式に圧縮
zip_file_path = path.join(temporary_dir, f"{file_name}.zip")
with zipfile.ZipFile(zip_file_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
arcname = path.basename(csv_file_path)
zipf.write(csv_file_path, arcname=arcname)
logger.info(f"zip形式への圧縮に成功しました。{file_name}.zip")
# 圧縮したCSVを保存先へアップロード
archive_bucket = JskultArchiveBucket()
upload_file_path = archive_bucket.upload_archive_zip_file(
f"{file_name}.zip", zip_file_path, jskult_archive_manage_data["archive_storage"])
logger.info(f"{upload_file_path}へのアップロードに成功しました。")
# アーカイブしたデータをDBから削除
jskult_archive_manager.delete_archive_data(
jskult_archive_manage_data["target_table"],
jskult_archive_manage_data["filter_column_name"],
jskult_archive_manage_data["filter_column_type"],
jskult_archive_manage_data["filter_column_digit"],
jskult_archive_manage_data["filter_date"])
logger.info(
f"アーカイブしたデータのDBから削除に成功しました。対象テーブル{jskult_archive_manage_data['target_table']} 条件年月:{jskult_archive_manage_data['filter_date']}")
# 次回に向けてアーカイブ管理テーブルを更新する
jskult_archive_manager.update_archive_manage(
jskult_archive_manage_data["target_table"])
logger.info(
f"アーカイブ管理テーブルの更新に成功しました。対象テーブル:{jskult_archive_manage_data['target_table']}")
logger.info("処理終了:実消化_過去データアーカイブ処理")
except Exception as e:
logger.exception(f"異常終了:実消化_過去データアーカイブ処理 {e}")

View File

@ -0,0 +1,143 @@
from src.db.database import Database
from src.logging.get_logger import get_logger
logger = get_logger("アーカイブ管理テーブル操作")
class JskultArchiveManager:
_db: Database = None
def __init__(self):
self._db = Database.get_instance()
def get_archive_manage(self):
"""対象テーブル、対象項目、対象年月、実行間隔(月)、前回対象年月、保存先を取得"""
try:
logger.info("処理開始get_archive_manage")
sql = """
select
target_table
, filter_column_name
, filter_column_type
, filter_column_digit
, filter_date
, run_interval_months
, prev_filter_date
, archive_storage
from
internal07.jskult_archive_manage;
"""
self._db.connect()
jskult_archive_manage_data = self._db.execute_select(sql)
logger.info("処理終了get_archive_manage")
return jskult_archive_manage_data
except Exception as e:
logger.info("異常終了get_archive_manage")
raise
finally:
self._db.disconnect()
def _filter_column_to_date(self,filter_column_name:str , filter_column_type:str, filter_column_digit:int):
""" filter_columnを日付型へ変換"""
try:
logger.info("処理開始_filter_column_to_date")
if filter_column_type == 'date':
filter_column = filter_column_name
elif filter_column_type == 'varchar' and filter_column_digit == 8:
filter_column = f"str_to_date({filter_column_name},'%Y%m%d')"
elif filter_column_type == 'varchar' and filter_column_digit == 6:
filter_column = f"str_to_date(concat({filter_column_name} , '01'),'%Y%m%d')"
else:
raise Exception("条件項目データ型もしくは条件項目桁数が不正です。")
logger.info("処理終了_filter_column_to_date")
return filter_column
except Exception as e:
logger.info("異常終了_filter_column_to_date")
raise
def get_archive_data(self,target_table:str, filter_column_name:str, filter_column_type:str, filter_column_digit:int, filter_date:str):
"""アーカイブするデータを取得"""
try:
logger.info("処理開始get_archive_data")
filter_column = self._filter_column_to_date(filter_column_name, filter_column_type, filter_column_digit)
sql = f"""
select
*
from
src07.{target_table}
where
{filter_column} <= :filter_date;
"""
self._db.connect()
parameter_dict = {'filter_date' : filter_date}
target_table_data = self._db.execute_select(sql, parameter_dict)
logger.info("処理終了get_archive_data")
return target_table_data
except Exception as e:
logger.info("異常終了get_archive_data")
raise
finally:
self._db.disconnect()
def delete_archive_data(self, target_table:str, filter_column_name:str, filter_column_type:str, filter_column_digit:int, filter_date:str):
"""アーカイブしたデータを削除"""
try:
logger.info("処理開始delete_archive_data")
filter_column = self._filter_column_to_date(filter_column_name, filter_column_type, filter_column_digit)
sql = f"""
delete from
src07.{target_table}
where
{filter_column} <= :filter_date;
"""
self._db.connect()
self._db.begin()
parameter_dict = {'filter_date' : filter_date}
self._db.execute(sql, parameter_dict)
self._db.commit()
logger.info("処理終了delete_archive_data")
return
except Exception as e:
self._db.rollback()
logger.info("異常終了delete_archive_data")
raise
finally:
self._db.disconnect()
def update_archive_manage(self, target_table:str):
"""アーカイブ管理テーブルの指定した対象テーブルのレコードを更新する"""
try:
logger.info("処理開始update_archive_manage")
sql = f"""
update internal07.jskult_archive_manage
set
prev_filter_date = filter_date
, filter_date = LAST_DAY(
DATE_ADD(filter_date, INTERVAL run_interval_months MONTH)
)
, upd_user = CURRENT_USER()
, upd_date = NOW()
where
target_table = '{target_table}';
"""
self._db.connect()
self._db.begin()
self._db.execute(sql)
self._db.commit()
logger.info("処理終了update_archive_manage")
return
except Exception as e:
self._db.rollback()
logger.info("異常終了update_archive_manage")
raise
finally:
self._db.disconnect()

View File

@ -0,0 +1,198 @@
from sqlalchemy import (Connection, CursorResult, Engine, QueuePool,
create_engine, text)
from sqlalchemy.engine.url import URL
from src.error.exceptions import DBException
from src.logging.get_logger import get_logger
from src.system_var import environment
from tenacity import retry, stop_after_attempt, wait_exponential
logger = get_logger(__name__)
class Database:
"""データベース操作クラス"""
__connection: Connection = None
__transactional_engine: Engine = None
__autocommit_engine: Engine = None
__host: str = None
__port: str = None
__username: str = None
__password: str = None
__schema: str = None
__autocommit: bool = None
__connection_string: str = None
def __init__(self, username: str, password: str, host: str, port: int, schema: str, autocommit: bool = False) -> None:
"""このクラスの新たなインスタンスを初期化します
Args:
username (str): DBユーザー名
password (str): DBパスワード
host (str): DBホスト名
port (int): DBポート
schema (str): DBスキーマ名
autocommit(bool): 自動コミットモードで接続するかどうか(Trueの場合トランザクションの有無に限らず即座にコミットされる). Defaults to False.
"""
self.__username = username
self.__password = password
self.__host = host
self.__port = int(port)
self.__schema = schema
self.__autocommit = autocommit
self.__connection_string = URL.create(
drivername='mysql+pymysql',
username=self.__username,
password=self.__password,
host=self.__host,
port=self.__port,
database=self.__schema,
query={"charset": "utf8mb4", "local_infile": "1"},
)
self.__transactional_engine = create_engine(
self.__connection_string,
pool_timeout=5,
poolclass=QueuePool
)
self.__autocommit_engine = self.__transactional_engine.execution_options(
isolation_level='AUTOCOMMIT')
@classmethod
def get_instance(cls, autocommit=False):
"""インスタンスを取得します
Args:
autocommit (bool, optional): 自動コミットモードで接続するかどうか(Trueの場合トランザクションの有無に限らず即座にコミットされる). Defaults to False.
Returns:
Database: DB操作クラスインスタンス
"""
return cls(
username=environment.DB_USERNAME,
password=environment.DB_PASSWORD,
host=environment.DB_HOST,
port=environment.DB_PORT,
schema=environment.DB_SCHEMA,
autocommit=autocommit
)
@retry(
wait=wait_exponential(
multiplier=environment.DB_CONNECTION_RETRY_INTERVAL_INIT,
min=environment.DB_CONNECTION_RETRY_INTERVAL_MIN_SECONDS,
max=environment.DB_CONNECTION_RETRY_INTERVAL_MAX_SECONDS
),
stop=stop_after_attempt(environment.DB_CONNECTION_MAX_RETRY_ATTEMPT),
retry_error_cls=DBException
)
def connect(self):
"""
DBに接続します接続に失敗した場合リトライします\n
インスタンスのautocommitがTrueの場合自動コミットモードで接続する明示的なトランザクションも無視される
Raises:
DBException: 接続失敗
"""
try:
self.__connection = (
self.__autocommit_engine.connect() if self.__autocommit is True
else self.__transactional_engine.connect())
except Exception as e:
raise DBException(e)
def execute_select(self, select_query: str, parameters=None) -> list[dict]:
"""SELECTクエリを実行します。
Args:
select_query (str): SELECT文
parameters (dict, optional): クエリのプレースホルダーに埋め込む変数の辞書. Defaults to None.
Raises:
DBException: DBエラー
Returns:
list[dict]: カラム名: 値の辞書リスト
"""
if self.__connection is None:
raise DBException('DBに接続していません')
result = None
try:
# トランザクションが開始している場合は、トランザクションを引き継ぐ
if self.__connection.in_transaction():
result = self.__connection.execute(
text(select_query), parameters)
else:
# トランザクションが明示的に開始していない場合は、クエリ単位でトランザクションをbegin-commitする。
result = self.__execute_with_transaction(
select_query, parameters)
except Exception as e:
raise DBException(f'SQL Error: {e}')
result_rows = result.mappings().all()
return result_rows
def execute(self, query: str, parameters=None) -> CursorResult:
"""SQLクエリを実行します。
Args:
query (str): SQL文
parameters (dict, optional): クエリのプレースホルダーに埋め込む変数の辞書. Defaults to None.
Raises:
DBException: DBエラー
Returns:
CursorResult: 取得結果
"""
if self.__connection is None:
raise DBException('DBに接続していません')
result = None
try:
# トランザクションが開始している場合は、トランザクションを引き継ぐ
if self.__connection.in_transaction():
result = self.__connection.execute(text(query), parameters)
else:
# トランザクションが明示的に開始していない場合は、クエリ単位でトランザクションをbegin-commitする。
result = self.__execute_with_transaction(query, parameters)
except Exception as e:
raise DBException(f'SQL Error: {e}')
return result
def begin(self):
"""トランザクションを開始します。"""
if not self.__connection.in_transaction():
self.__connection.begin()
def commit(self):
"""トランザクションをコミットします"""
if self.__connection.in_transaction():
self.__connection.commit()
def rollback(self):
"""トランザクションをロールバックします"""
if self.__connection.in_transaction():
self.__connection.rollback()
def disconnect(self):
"""DB接続を切断します。"""
if self.__connection is not None:
self.__connection.close()
self.__connection = None
def to_jst(self):
self.execute('SET time_zone = "+9:00"')
def __execute_with_transaction(self, query: str, parameters: dict):
# トランザクションを開始してクエリを実行する
with self.__connection.begin():
try:
result = self.__connection.execute(
text(query), parameters=parameters)
except Exception as e:
self.__connection.rollback()
raise e
# ここでコミットされる
return result

View File

@ -0,0 +1,6 @@
class MeDaCaException(Exception):
pass
class DBException(MeDaCaException):
pass

View File

@ -0,0 +1,37 @@
import logging
from src.system_var.environment import LOG_LEVEL
# boto3関連モジュールのログレベルを事前に個別指定し、モジュール内のDEBUGログの表示を抑止する
for name in ["boto3", "botocore", "s3transfer", "urllib3"]:
logging.getLogger(name).setLevel(logging.WARNING)
def get_logger(log_name: str) -> logging.Logger:
"""一意のログ出力モジュールを取得します。
Args:
log_name (str): ロガー名
Returns:
_type_: _description_
"""
logger = logging.getLogger(log_name)
level = logging.getLevelName(LOG_LEVEL)
if not isinstance(level, int):
level = logging.INFO
logger.setLevel(level)
if not logger.hasHandlers():
handler = logging.StreamHandler()
logger.addHandler(handler)
formatter = logging.Formatter(
'%(name)s\t[%(levelname)s]\t%(asctime)s\t%(message)s',
'%Y-%m-%d %H:%M:%S'
)
for handler in logger.handlers:
handler.setFormatter(formatter)
return logger

View File

@ -0,0 +1,2 @@
# バッチ正常終了コード
BATCH_EXIT_CODE_SUCCESS = 0

View File

@ -0,0 +1,22 @@
import os
# Database
DB_HOST = os.environ['DB_HOST']
DB_PORT = int(os.environ['DB_PORT'])
DB_USERNAME = os.environ['DB_USERNAME']
DB_PASSWORD = os.environ['DB_PASSWORD']
DB_SCHEMA = os.environ['DB_SCHEMA']
# AWS
JSKULT_ARCHIVE_BUCKET = os.environ['JSKULT_ARCHIVE_BUCKET']
# 初期値がある環境変数
LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO')
DB_CONNECTION_MAX_RETRY_ATTEMPT = int(
os.environ.get('DB_CONNECTION_MAX_RETRY_ATTEMPT', 4))
DB_CONNECTION_RETRY_INTERVAL_INIT = int(
os.environ.get('DB_CONNECTION_RETRY_INTERVAL', 5))
DB_CONNECTION_RETRY_INTERVAL_MIN_SECONDS = int(
os.environ.get('DB_CONNECTION_RETRY_MIN_SECONDS', 5))
DB_CONNECTION_RETRY_INTERVAL_MAX_SECONDS = int(
os.environ.get('DB_CONNECTION_RETRY_MAX_SECONDS', 50))

View File

@ -0,0 +1,12 @@
tests/*
.coverage
.env
.env.example
.report/*
.vscode/*
.pytest_cache/*
*/__pychache__/*
Dockerfile
pytest.ini
README.md
*.sql

View File

@ -0,0 +1,24 @@
DB_HOST=************
DB_PORT=************
DB_USERNAME=************
DB_PASSWORD=************
DB_SCHEMA=src05
LOG_LEVEL=INFO
PROCESS_NAME=jskult-batch-ultmarc-io
JSKULT_CONFIG_BUCKET=**********************
JSKULT_CONFIG_CONVERT_FOLDER=jskult/convert
JSKULT_ULTMARC_HEX_CONVERT_CONFIG_FILE_NAME=ultmarc_hex_convert_config.json
ULTMARC_DATA_BUCKET=****************
ULTMARC_DATA_FOLDER=import
JSK_IO_BUCKET=*************
JSK_DATA_SEND_FOLDER=send
JSKULT_BACKUP_BUCKET=****************
JSK_BACKUP_FOLDER=jsk/send
DCF_DSF_SEND_FILE_NAME=ult_dcf_dsf.csv
IMPORT_FILE_KEY=****************
DB_CONNECTION_MAX_RETRY_ATTEMPT=4
DB_CONNECTION_RETRY_INTERVAL_INIT=5
DB_CONNECTION_RETRY_INTERVAL_MIN_SECONDS=5
DB_CONNECTION_RETRY_INTERVAL_MAX_SECONDS=50

10
ecs/jskult-batch-ultmarc-io/.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
.vscode/settings.json
.env
# python
__pycache__
# python test
.pytest_cache
.coverage
.report/

View File

@ -0,0 +1,16 @@
{
// IntelliSense 使
//
// : https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(DEBUG)jskult ultmarc io",
"type": "python",
"request": "launch",
"program": "entrypoint.py",
"console": "integratedTerminal",
"justMyCode": true
}
]
}

View File

@ -0,0 +1,31 @@
{
"[python]": {
"editor.defaultFormatter": null,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
}
},
//
"python.defaultInterpreterPath": "<pythonインタプリターのパス>",
"python.linting.lintOnSave": true,
"python.linting.enabled": true,
"python.linting.pylintEnabled": false,
"python.linting.flake8Enabled": true,
"python.linting.flake8Args": [
"--max-line-length=200",
"--ignore=F541"
],
"python.formatting.provider": "autopep8",
"python.formatting.autopep8Path": "autopep8",
"python.formatting.autopep8Args": [
"--max-line-length", "200",
"--ignore=F541"
],
"python.testing.pytestArgs": [
"tests/batch/"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}

View File

@ -0,0 +1,20 @@
FROM python:3.12-slim-bookworm
ENV TZ="Asia/Tokyo"
# pythonの標準出力をバッファリングしないフラグ
ENV PYTHONUNBUFFERED=1
# pythonのバイトコードを生成しないフラグ
ENV PYTHONDONTWRITEBYTECODE=1
WORKDIR /usr/src/app
COPY Pipfile Pipfile.lock ./
RUN \
apt update -y && \
pip install pipenv --no-cache-dir && \
pipenv install --system --deploy && \
pip uninstall -y pipenv virtualenv-clone virtualenv
COPY src ./src
COPY entrypoint.py entrypoint.py
CMD [ "python", "entrypoint.py" ]

View File

@ -0,0 +1,27 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[scripts]
"test:ultmarc" = "pytest tests/batch/ultmarc/"
"test:ultmarc:cov" = "pytest --cov=src/batch/ultmarc/ --cov-branch --cov-report=term-missing tests/batch/ultmarc/"
[packages]
boto3 = "*"
PyMySQL = "*"
sqlalchemy = "*"
tenacity = "*"
[dev-packages]
autopep8 = "*"
flake8 = "*"
pytest = "*"
pytest-cov = "*"
boto3 = "*"
[requires]
python_version = "3.12"
[pipenv]
allow_prereleases = true

443
ecs/jskult-batch-ultmarc-io/Pipfile.lock generated Normal file
View File

@ -0,0 +1,443 @@
{
"_meta": {
"hash": {
"sha256": "aa2d1d97600fea225b7d249dae0d065190d00fdadbf85b20773e0c1d9862f5c1"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.12"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"boto3": {
"hashes": [
"sha256:008f6a7c2f9f306984f9bd00c331d70341124aaa7dfebcb0466ecbda6619884a",
"sha256:760c85ab6dd78f12aa669269ca917d313fe02378722dc3b8ab41a8dc13b2a999"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==1.38.22"
},
"botocore": {
"hashes": [
"sha256:0e524cc763eced7c87ab256338ebd247ce10d1eb11d5cc4f71a3bd82611739e8",
"sha256:3b464984674f97367ca1dfa29bdbce499327571208aaec2f9743f66e54d9ba05"
],
"markers": "python_version >= '3.9'",
"version": "==1.38.22"
},
"greenlet": {
"hashes": [
"sha256:00cd814b8959b95a546e47e8d589610534cfb71f19802ea8a2ad99d95d702057",
"sha256:02a98600899ca1ca5d3a2590974c9e3ec259503b2d6ba6527605fcd74e08e207",
"sha256:02f5972ff02c9cf615357c17ab713737cccfd0eaf69b951084a9fd43f39833d3",
"sha256:055916fafad3e3388d27dd68517478933a97edc2fc54ae79d3bec827de2c64c4",
"sha256:0a16fb934fcabfdfacf21d79e6fed81809d8cd97bc1be9d9c89f0e4567143d7b",
"sha256:1592a615b598643dbfd566bac8467f06c8c8ab6e56f069e573832ed1d5d528cc",
"sha256:1919cbdc1c53ef739c94cf2985056bcc0838c1f217b57647cbf4578576c63825",
"sha256:1e4747712c4365ef6765708f948acc9c10350719ca0545e362c24ab973017370",
"sha256:1e76106b6fc55fa3d6fe1c527f95ee65e324a13b62e243f77b48317346559708",
"sha256:1f72667cc341c95184f1c68f957cb2d4fc31eef81646e8e59358a10ce6689457",
"sha256:2593283bf81ca37d27d110956b79e8723f9aa50c4bcdc29d3c0543d4743d2763",
"sha256:2dc5c43bb65ec3669452af0ab10729e8fdc17f87a1f2ad7ec65d4aaaefabf6bf",
"sha256:3091bc45e6b0c73f225374fefa1536cd91b1e987377b12ef5b19129b07d93ebe",
"sha256:354f67445f5bed6604e493a06a9a49ad65675d3d03477d38a4db4a427e9aad0e",
"sha256:3885f85b61798f4192d544aac7b25a04ece5fe2704670b4ab73c2d2c14ab740d",
"sha256:3ab7194ee290302ca15449f601036007873028712e92ca15fc76597a0aeb4c59",
"sha256:3aeca9848d08ce5eb653cf16e15bb25beeab36e53eb71cc32569f5f3afb2a3aa",
"sha256:44671c29da26539a5f142257eaba5110f71887c24d40df3ac87f1117df589e0e",
"sha256:45f9f4853fb4cc46783085261c9ec4706628f3b57de3e68bae03e8f8b3c0de51",
"sha256:4bd139e4943547ce3a56ef4b8b1b9479f9e40bb47e72cc906f0f66b9d0d5cab3",
"sha256:4fefc7aa68b34b9224490dfda2e70ccf2131368493add64b4ef2d372955c207e",
"sha256:6629311595e3fe7304039c67f00d145cd1d38cf723bb5b99cc987b23c1433d61",
"sha256:6fadd183186db360b61cb34e81117a096bff91c072929cd1b529eb20dd46e6c5",
"sha256:71566302219b17ca354eb274dfd29b8da3c268e41b646f330e324e3967546a74",
"sha256:7409796591d879425997a518138889d8d17e63ada7c99edc0d7a1c22007d4907",
"sha256:752f0e79785e11180ebd2e726c8a88109ded3e2301d40abced2543aa5d164275",
"sha256:7791dcb496ec53d60c7f1c78eaa156c21f402dda38542a00afc3e20cae0f480f",
"sha256:782743700ab75716650b5238a4759f840bb2dcf7bff56917e9ffdf9f1f23ec59",
"sha256:7c9896249fbef2c615853b890ee854f22c671560226c9221cfd27c995db97e5c",
"sha256:85f3e248507125bf4af607a26fd6cb8578776197bd4b66e35229cdf5acf1dfbf",
"sha256:89c69e9a10670eb7a66b8cef6354c24671ba241f46152dd3eed447f79c29fb5b",
"sha256:8cb8553ee954536500d88a1a2f58fcb867e45125e600e80f586ade399b3f8819",
"sha256:9ae572c996ae4b5e122331e12bbb971ea49c08cc7c232d1bd43150800a2d6c65",
"sha256:9c7b15fb9b88d9ee07e076f5a683027bc3befd5bb5d25954bb633c385d8b737e",
"sha256:9ea5231428af34226c05f927e16fc7f6fa5e39e3ad3cd24ffa48ba53a47f4240",
"sha256:a31ead8411a027c2c4759113cf2bd473690517494f3d6e4bf67064589afcd3c5",
"sha256:a8fa80665b1a29faf76800173ff5325095f3e66a78e62999929809907aca5659",
"sha256:ad053d34421a2debba45aa3cc39acf454acbcd025b3fc1a9f8a0dee237abd485",
"sha256:b24c7844c0a0afc3ccbeb0b807adeefb7eff2b5599229ecedddcfeb0ef333bec",
"sha256:b50a8c5c162469c3209e5ec92ee4f95c8231b11db6a04db09bbe338176723bb8",
"sha256:ba30e88607fb6990544d84caf3c706c4b48f629e18853fc6a646f82db9629418",
"sha256:bf3fc9145141250907730886b031681dfcc0de1c158f3cc51c092223c0f381ce",
"sha256:c23ea227847c9dbe0b3910f5c0dd95658b607137614eb821e6cbaecd60d81cc6",
"sha256:c3cc1a3ed00ecfea8932477f729a9f616ad7347a5e55d50929efa50a86cb7be7",
"sha256:c49e9f7c6f625507ed83a7485366b46cbe325717c60837f7244fc99ba16ba9d6",
"sha256:d0cb7d47199001de7658c213419358aa8937df767936506db0db7ce1a71f4a2f",
"sha256:d8009ae46259e31bc73dc183e402f548e980c96f33a6ef58cc2e7865db012e13",
"sha256:da956d534a6d1b9841f95ad0f18ace637668f680b1339ca4dcfb2c1837880a0b",
"sha256:dcb9cebbf3f62cb1e5afacae90761ccce0effb3adaa32339a0670fe7805d8068",
"sha256:decb0658ec19e5c1f519faa9a160c0fc85a41a7e6654b3ce1b44b939f8bf1325",
"sha256:df4d1509efd4977e6a844ac96d8be0b9e5aa5d5c77aa27ca9f4d3f92d3fcf330",
"sha256:eeb27bece45c0c2a5842ac4c5a1b5c2ceaefe5711078eed4e8043159fa05c834",
"sha256:efcdfb9df109e8a3b475c016f60438fcd4be68cd13a365d42b35914cdab4bb2b",
"sha256:fd9fb7c941280e2c837b603850efc93c999ae58aae2b40765ed682a6907ebbc5",
"sha256:fe46d4f8e94e637634d54477b0cfabcf93c53f29eedcbdeecaf2af32029b4421"
],
"markers": "python_version < '3.14' and (platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32'))))))",
"version": "==3.2.2"
},
"jmespath": {
"hashes": [
"sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980",
"sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"
],
"markers": "python_version >= '3.7'",
"version": "==1.0.1"
},
"pymysql": {
"hashes": [
"sha256:4de15da4c61dc132f4fb9ab763063e693d521a80fd0e87943b9a453dd4c19d6c",
"sha256:e127611aaf2b417403c60bf4dc570124aeb4a57f5f37b8e95ae399a42f904cd0"
],
"index": "pypi",
"markers": "python_version >= '3.7'",
"version": "==1.1.1"
},
"python-dateutil": {
"hashes": [
"sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3",
"sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
"version": "==2.9.0.post0"
},
"s3transfer": {
"hashes": [
"sha256:0148ef34d6dd964d0d8cf4311b2b21c474693e57c2e069ec708ce043d2b527be",
"sha256:f5e6db74eb7776a37208001113ea7aa97695368242b364d73e91c981ac522177"
],
"markers": "python_version >= '3.9'",
"version": "==0.13.0"
},
"six": {
"hashes": [
"sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274",
"sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
"version": "==1.17.0"
},
"sqlalchemy": {
"hashes": [
"sha256:023b3ee6169969beea3bb72312e44d8b7c27c75b347942d943cf49397b7edeb5",
"sha256:03968a349db483936c249f4d9cd14ff2c296adfa1290b660ba6516f973139582",
"sha256:05132c906066142103b83d9c250b60508af556982a385d96c4eaa9fb9720ac2b",
"sha256:087b6b52de812741c27231b5a3586384d60c353fbd0e2f81405a814b5591dc8b",
"sha256:0b3dbf1e7e9bc95f4bac5e2fb6d3fb2f083254c3fdd20a1789af965caf2d2348",
"sha256:118c16cd3f1b00c76d69343e38602006c9cfb9998fa4f798606d28d63f23beda",
"sha256:1936af879e3db023601196a1684d28e12f19ccf93af01bf3280a3262c4b6b4e5",
"sha256:1e3f196a0c59b0cae9a0cd332eb1a4bda4696e863f4f1cf84ab0347992c548c2",
"sha256:23a8825495d8b195c4aa9ff1c430c28f2c821e8c5e2d98089228af887e5d7e29",
"sha256:293cd444d82b18da48c9f71cd7005844dbbd06ca19be1ccf6779154439eec0b8",
"sha256:32f9dc8c44acdee06c8fc6440db9eae8b4af8b01e4b1aee7bdd7241c22edff4f",
"sha256:34ea30ab3ec98355235972dadc497bb659cc75f8292b760394824fab9cf39826",
"sha256:3d3549fc3e40667ec7199033a4e40a2f669898a00a7b18a931d3efb4c7900504",
"sha256:41836fe661cc98abfae476e14ba1906220f92c4e528771a8a3ae6a151242d2ae",
"sha256:4d44522480e0bf34c3d63167b8cfa7289c1c54264c2950cc5fc26e7850967e45",
"sha256:4eeb195cdedaf17aab6b247894ff2734dcead6c08f748e617bfe05bd5a218443",
"sha256:4f67766965996e63bb46cfbf2ce5355fc32d9dd3b8ad7e536a920ff9ee422e23",
"sha256:57df5dc6fdb5ed1a88a1ed2195fd31927e705cad62dedd86b46972752a80f576",
"sha256:598d9ebc1e796431bbd068e41e4de4dc34312b7aa3292571bb3674a0cb415dd1",
"sha256:5b14e97886199c1f52c14629c11d90c11fbb09e9334fa7bb5f6d068d9ced0ce0",
"sha256:5e22575d169529ac3e0a120cf050ec9daa94b6a9597993d1702884f6954a7d71",
"sha256:60c578c45c949f909a4026b7807044e7e564adf793537fc762b2489d522f3d11",
"sha256:6145afea51ff0af7f2564a05fa95eb46f542919e6523729663a5d285ecb3cf5e",
"sha256:6375cd674fe82d7aa9816d1cb96ec592bac1726c11e0cafbf40eeee9a4516b5f",
"sha256:6854175807af57bdb6425e47adbce7d20a4d79bbfd6f6d6519cd10bb7109a7f8",
"sha256:6ab60a5089a8f02009f127806f777fca82581c49e127f08413a66056bd9166dd",
"sha256:725875a63abf7c399d4548e686debb65cdc2549e1825437096a0af1f7e374814",
"sha256:7492967c3386df69f80cf67efd665c0f667cee67032090fe01d7d74b0e19bb08",
"sha256:81965cc20848ab06583506ef54e37cf15c83c7e619df2ad16807c03100745dea",
"sha256:81c24e0c0fde47a9723c81d5806569cddef103aebbf79dbc9fcbb617153dea30",
"sha256:81eedafa609917040d39aa9332e25881a8e7a0862495fcdf2023a9667209deda",
"sha256:81f413674d85cfd0dfcd6512e10e0f33c19c21860342a4890c3a2b59479929f9",
"sha256:8280856dd7c6a68ab3a164b4a4b1c51f7691f6d04af4d4ca23d6ecf2261b7923",
"sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df",
"sha256:8b4af17bda11e907c51d10686eda89049f9ce5669b08fbe71a29747f1e876036",
"sha256:90144d3b0c8b139408da50196c5cad2a6909b51b23df1f0538411cd23ffa45d3",
"sha256:906e6b0d7d452e9a98e5ab8507c0da791856b2380fdee61b765632bb8698026f",
"sha256:90c11ceb9a1f482c752a71f203a81858625d8df5746d787a4786bca4ffdf71c6",
"sha256:911cc493ebd60de5f285bcae0491a60b4f2a9f0f5c270edd1c4dbaef7a38fc04",
"sha256:9a420a91913092d1e20c86a2f5f1fc85c1a8924dbcaf5e0586df8aceb09c9cc2",
"sha256:9f8c9fdd15a55d9465e590a402f42082705d66b05afc3ffd2d2eb3c6ba919560",
"sha256:a104c5694dfd2d864a6f91b0956eb5d5883234119cb40010115fd45a16da5e70",
"sha256:a373a400f3e9bac95ba2a06372c4fd1412a7cee53c37fc6c05f829bf672b8769",
"sha256:a62448526dd9ed3e3beedc93df9bb6b55a436ed1474db31a2af13b313a70a7e1",
"sha256:a8808d5cf866c781150d36a3c8eb3adccfa41a8105d031bf27e92c251e3969d6",
"sha256:b1f09b6821406ea1f94053f346f28f8215e293344209129a9c0fcc3578598d7b",
"sha256:b2ac41acfc8d965fb0c464eb8f44995770239668956dc4cdf502d1b1ffe0d747",
"sha256:b46fa6eae1cd1c20e6e6f44e19984d438b6b2d8616d21d783d150df714f44078",
"sha256:b50eab9994d64f4a823ff99a0ed28a6903224ddbe7fef56a6dd865eec9243440",
"sha256:bfc9064f6658a3d1cadeaa0ba07570b83ce6801a1314985bf98ec9b95d74e15f",
"sha256:c0b0e5e1b5d9f3586601048dd68f392dc0cc99a59bb5faf18aab057ce00d00b2",
"sha256:c153265408d18de4cc5ded1941dcd8315894572cddd3c58df5d5b5705b3fa28d",
"sha256:d4ae769b9c1c7757e4ccce94b0641bc203bbdf43ba7a2413ab2523d8d047d8dc",
"sha256:dc56c9788617b8964ad02e8fcfeed4001c1f8ba91a9e1f31483c0dffb207002a",
"sha256:dd5ec3aa6ae6e4d5b5de9357d2133c07be1aff6405b136dad753a16afb6717dd",
"sha256:edba70118c4be3c2b1f90754d308d0b79c6fe2c0fdc52d8ddf603916f83f4db9",
"sha256:ff8e80c4c4932c10493ff97028decfdb622de69cae87e0f127a7ebe32b4069c6"
],
"index": "pypi",
"markers": "python_version >= '3.7'",
"version": "==2.0.41"
},
"tenacity": {
"hashes": [
"sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb",
"sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==9.1.2"
},
"typing-extensions": {
"hashes": [
"sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c",
"sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"
],
"markers": "python_version >= '3.8'",
"version": "==4.13.2"
},
"urllib3": {
"hashes": [
"sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466",
"sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"
],
"markers": "python_version >= '3.10'",
"version": "==2.4.0"
}
},
"develop": {
"autopep8": {
"hashes": [
"sha256:89440a4f969197b69a995e4ce0661b031f455a9f776d2c5ba3dbd83466931758",
"sha256:ce8ad498672c845a0c3de2629c15b635ec2b05ef8177a6e7c91c74f3e9b51128"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==2.3.2"
},
"boto3": {
"hashes": [
"sha256:008f6a7c2f9f306984f9bd00c331d70341124aaa7dfebcb0466ecbda6619884a",
"sha256:760c85ab6dd78f12aa669269ca917d313fe02378722dc3b8ab41a8dc13b2a999"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==1.38.22"
},
"botocore": {
"hashes": [
"sha256:0e524cc763eced7c87ab256338ebd247ce10d1eb11d5cc4f71a3bd82611739e8",
"sha256:3b464984674f97367ca1dfa29bdbce499327571208aaec2f9743f66e54d9ba05"
],
"markers": "python_version >= '3.9'",
"version": "==1.38.22"
},
"coverage": {
"extras": [
"toml"
],
"hashes": [
"sha256:0034ceec8e91fdaf77350901cc48f47efd00f23c220a3f9fc1187774ddf307cb",
"sha256:061a3bf679dc38fe34d3822f10a9977d548de86b440010beb1e3b44ba93d20f7",
"sha256:07fff2f2ce465fae27447432d39ce733476fbf8478de51fb4034c201e0c5da6d",
"sha256:11e5ea0acd8cc5d23030c34dfb2eb6638ad886328df18cc69f8eefab73d1ece5",
"sha256:12950b6373dc9dfe1ce22a8506ec29c82bfc5b38146ced0a222f38cf5d99a56d",
"sha256:173e16969f990688aae4b4487717c44330bc57fd8b61a6216ce8eeb827eb5c0d",
"sha256:1cc6bebc15c3b275174c66cf4e1c949a94c5c2a3edaa2f193a1225548c52c771",
"sha256:21645788c5c2afa3df2d4b607638d86207b84cb495503b71e80e16b4c6b44e80",
"sha256:2d8f844e837374a9497e11722d9eb9dfeb33b1b5d31136786c39a4c1a3073c6d",
"sha256:35dd5d405a1d378c39f3f30f628a25b0b99f1b8e5bdd78275df2e7b0404892d7",
"sha256:3763b9a4bc128f72da5dcfd7fcc7c7d6644ed28e8f2db473ce1ef0dd37a43fa9",
"sha256:3bd8e3753257e95e94f38c058627aba1581d51f674e3badf226283b2bdb8f8ca",
"sha256:41d142eefbc0bb3be160a77b2c0fbec76f345387676265052e224eb6c67b7af3",
"sha256:452f3831c64f5f50260e18a89e613594590d6ceac5206a9b7d76ba43586b01b3",
"sha256:4fc4f7cff2495d6d112353c33a439230a6de0b7cd0c2578f1e8d75326f63d783",
"sha256:62a13b372b65fa6e11685df9ca924bed23bab1d0f277f9b67be7536f253aaf17",
"sha256:6ce2606a171f9cf7c15a77ca61f979ffc0e0d92cd2fb18767cead58c1d19f58e",
"sha256:6f24a1e2c373a77afae21bc512466a91e31251685c271c5309ee3e557f6e3e03",
"sha256:76a4e1d62505a21971968be61ae17cbdc5e0c483265a37f7ddbbc050f9c0b8ec",
"sha256:82db9344a07dd9106796b9fe8805425633146a7ea7fed5ed07c65a64d0bb79e1",
"sha256:87284f272746e31919302ab6211b16b41135109822c498f6e7b40a2f828e7836",
"sha256:87b86a87f8de2e1bd0bcd45faf1b1edf54f988c8857157300e0336efcfb8ede6",
"sha256:8bcfafb2809cd01be8ffe5f962e01b0fbe4cc1d74513434c52ff2dd05b86d492",
"sha256:9296df6a33b8539cd753765eb5b47308602263a14b124a099cbcf5f770d7cf90",
"sha256:958b513e23286178b513a6b4d975fe9e7cddbcea6e5ebe8d836e4ef067577154",
"sha256:9772c9e266b2ca4999180c12b90c8efb4c5c9ad3e55f301d78bc579af6467ad9",
"sha256:9b31756ea647b6ef53190f6b708ad0c4c2ea879bc17799ba5b0699eee59ecf7b",
"sha256:9cd54a762667c32112df5d6f059c5d61fa532ee06460948cc5bcbf60c502f5c9",
"sha256:9dabc70012fd7b58a8040a7bc1b5f71fd0e62e2138aefdd8367d3d24bf82c349",
"sha256:adafe9d71a940927dd3ad8d487f521f11277f133568b7da622666ebd08923191",
"sha256:ae5e557aa92565d72f6d3196e878e7cbd6a6380e02a15eafe0af781bd767c10d",
"sha256:af6b8cdf0857fd4e6460dd6639c37c3f82163127f6112c1942b5e6a52a477676",
"sha256:b37729ba34c116a3b2b6fb99df5c37a4ca40e96f430070488fd7a1077ad44907",
"sha256:b6424c716f4c38ff8f62b602e6b94cde478dadda542a1cb3fe2fe2520cc2aae3",
"sha256:b8f105631835fdf191c971c4da93d27e732e028d73ecaa1a88f458d497d026cf",
"sha256:be2b1a455b3ecfee20638289bb091a95216887d44924a41c28a601efac0916e8",
"sha256:c04a7903644ccea8fa07c3e76db43ca31c8d453f93c5c94c0f9b82efca225543",
"sha256:c0d6290a466a6f3fadf6add2dd4ec11deba4e1a6e3db2dd284edd497aadf802f",
"sha256:c5757a7b25fe48040fa120ba6597f5f885b01e323e0d13fe21ff95a70c0f76b7",
"sha256:ccad4e29ac1b6f75bfeedb2cac4860fe5bd9e0a2f04c3e3218f661fa389ab101",
"sha256:cd21de85aa0e247b79c6c41f8b5541b54285550f2da6a9448d82b53234d3611b",
"sha256:ce4553a573edb363d5db12be1c044826878bec039159d6d4eafe826ef773396d",
"sha256:d074380f587360d2500f3b065232c67ae248aaf739267807adbcd29b88bdf864",
"sha256:d41d4da5f2871b1782c6b74948d2d37aac3a5b39b43a6ba31d736b97a02ae1f1",
"sha256:d5102e17b81158de17d4b5bc363fcffd15231a38ef3f50b8e6fa01f0c6911194",
"sha256:d52d79dfd3b410b153b6d65b0e3afe834eca2b969377f55ad73c67156d35af0d",
"sha256:d591f2ddad432b794f77dc1e94334a80015a3fc7fa07fd6aed8f40362083be5b",
"sha256:d616b5a543c7d4deffa25eb8d8ae3d0d95097f08ac8b131600bb7fbf967ea0e2",
"sha256:d7af3990490982fbd2437156c69edbe82b7edf99bc60302cceeeaf79afb886b8",
"sha256:d8a6c35afd5b912101fabf42975d92d750cfce33c571508a82ff334a133c40d5",
"sha256:db181a1896e0bad75b3bf4916c49fd3cf6751f9cc203fe0e0ecbee1fc43590fa",
"sha256:dd5c305faa2e69334a53061b3168987847dadc2449bab95735242a9bde92fde8",
"sha256:e1f8e96455907496b3e4ea16f63bb578da31e17d2805278b193525e7714f17f2",
"sha256:e233a56bbf99e4cb134c4f8e63b16c77714e3987daf2c5aa10c3ba8c4232d730",
"sha256:e3f65da9701648d226b6b24ded3e2528b72075e48d7540968cd857c3bd4c5321",
"sha256:e4e893c7f7fb12271a667d5c1876710fae06d7580343afdb5f3fc4488b73209e",
"sha256:e54b80885b0e61d346accc5709daf8762471a452345521cc9281604a907162c2",
"sha256:e93f36a5c9d995f40e9c4cd9bbabd83fd78705792fa250980256c93accd07bb6",
"sha256:ebdf212e1ed85af63fa1a76d556c0a3c7b34348ffba6e145a64b15f003ad0a2b",
"sha256:f7a95b0dce364535a63fde0ec1b1ca36400037175d3b62ce04d85dbca5e33832",
"sha256:f82c1a1c1897d2293cb6c50f20fe8a9ea2add1a228eff479380917a1fe7bbb68",
"sha256:fe4877c24711458f7990392181be30166cc3ae72158036ecb48a73c30c99fb6f",
"sha256:ff619c58322d9d6df0a859dc76c3532d7bdbc125cb040f7cd642141446b4f654"
],
"markers": "python_version >= '3.9'",
"version": "==7.8.1"
},
"flake8": {
"hashes": [
"sha256:93b92ba5bdb60754a6da14fa3b93a9361fd00a59632ada61fd7b130436c40343",
"sha256:fa558ae3f6f7dbf2b4f22663e5343b6b6023620461f8d4ff2019ef4b5ee70426"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==7.2.0"
},
"iniconfig": {
"hashes": [
"sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7",
"sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"
],
"markers": "python_version >= '3.8'",
"version": "==2.1.0"
},
"jmespath": {
"hashes": [
"sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980",
"sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"
],
"markers": "python_version >= '3.7'",
"version": "==1.0.1"
},
"mccabe": {
"hashes": [
"sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
"sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
],
"markers": "python_version >= '3.6'",
"version": "==0.7.0"
},
"packaging": {
"hashes": [
"sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484",
"sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"
],
"markers": "python_version >= '3.8'",
"version": "==25.0"
},
"pluggy": {
"hashes": [
"sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3",
"sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"
],
"markers": "python_version >= '3.9'",
"version": "==1.6.0"
},
"pycodestyle": {
"hashes": [
"sha256:35863c5974a271c7a726ed228a14a4f6daf49df369d8c50cd9a6f58a5e143ba9",
"sha256:c8415bf09abe81d9c7f872502a6eee881fbe85d8763dd5b9924bb0a01d67efae"
],
"markers": "python_version >= '3.9'",
"version": "==2.13.0"
},
"pyflakes": {
"hashes": [
"sha256:5039c8339cbb1944045f4ee5466908906180f13cc99cc9949348d10f82a5c32a",
"sha256:6dfd61d87b97fba5dcfaaf781171ac16be16453be6d816147989e7f6e6a9576b"
],
"markers": "python_version >= '3.9'",
"version": "==3.3.2"
},
"pytest": {
"hashes": [
"sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820",
"sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
"version": "==8.3.5"
},
"pytest-cov": {
"hashes": [
"sha256:46935f7aaefba760e716c2ebfbe1c216240b9592966e7da99ea8292d4d3e2a0a",
"sha256:bddf29ed2d0ab6f4df17b4c55b0a657287db8684af9c42ea546b21b1041b3dde"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==6.1.1"
},
"python-dateutil": {
"hashes": [
"sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3",
"sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
"version": "==2.9.0.post0"
},
"s3transfer": {
"hashes": [
"sha256:0148ef34d6dd964d0d8cf4311b2b21c474693e57c2e069ec708ce043d2b527be",
"sha256:f5e6db74eb7776a37208001113ea7aa97695368242b364d73e91c981ac522177"
],
"markers": "python_version >= '3.9'",
"version": "==0.13.0"
},
"six": {
"hashes": [
"sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274",
"sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
"version": "==1.17.0"
},
"urllib3": {
"hashes": [
"sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466",
"sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"
],
"markers": "python_version >= '3.10'",
"version": "==2.4.0"
}
}
}

View File

@ -0,0 +1,215 @@
# 実消化&アルトマーク アルトマーク取込/データ出力処理
## 概要
実消化&アルトマークのアルトマーク取込/データ出力処理
## 環境情報
- Python 3.12
- 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に指定したカラムは、呼び出し元のテストコード内で個別に突き合わせする
## フォルダ構成
```text
.
├── Pipfile -- Pythonモジュールの依存関係を管理するファイル
├── Dockerfile -- Dockerイメージを作成するためのファイル
├── Pipfile -- Pythonモジュールの依存関係を管理するファイル
├── Pipfile.lock -- Pythonモジュールの依存関係バージョン固定用ファイル
├── README.md -- 当ファイル
├── entrypoint.py -- バッチ処理のエントリーポイントになるpythonファイル
├── src -- ソースコードの保管場所
│ ├── aws -- AWS関連処理
│ │ └── s3.py -- S3クライアントとバケット処理
│ ├── batch -- バッチ処理関連ソース置き場
│ │ └── ultmarc -- アルトマーク関連処理
│ │ ├── import_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 -- カスタム例外
│ ├── main.py -- アルトマーク取込処理のエントリーポイント。「entrypoint.py」 から呼ばれる。
│ ├── logging
│ │ └── get_logger.py -- ログ出力の共通処理
│ ├── system_var
│ │ ├── constants.py -- 定数
│ │ └── environment.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で用意する。
│ │ ...
│ └── conftest.py -- テスト内で共通利用できるフィクスチャを宣言する(執筆時点ではDBのみ)
├── testing_utility.py -- テストの共通関数
└── testing_vjsk_utility.py -- テストの共通関数(実消化データ取込処理関連)
```

View File

@ -0,0 +1,10 @@
"""実消化&アルトマーク 日次バッチのエントリーポイント"""
from src import main
if __name__ == '__main__':
try:
exit(main.exec())
except Exception:
# エラーが起きても、正常系のコードで返す。
# エラーが起きた事実はbatch_process内でログを出す。
exit(0)

View File

@ -0,0 +1,3 @@
[pytest]
log_format = %(levelname)s %(asctime)s %(message)s
log_date_format = %Y-%m-%d %H:%M:%S

View File

@ -0,0 +1,113 @@
import os.path as path
import tempfile
import boto3
from src.system_var import environment
class S3Client:
__s3_client = boto3.client('s3')
_bucket_name: str
def list_objects(self, bucket_name: str, folder_name: str):
response = self.__s3_client.list_objects_v2(Bucket=bucket_name, Prefix=folder_name)
if response['KeyCount'] == 0:
return []
contents = response['Contents']
# 末尾がスラッシュで終わるものはフォルダとみなしてスキップする
objects = [{'filename': content['Key'], 'size': content['Size']}
for content in contents if not content['Key'].endswith('/')]
return objects
def copy(self, src_bucket: str, src_key: str, dest_bucket: str, dest_key: str) -> None:
copy_source = {'Bucket': src_bucket, 'Key': src_key}
self.__s3_client.copy(copy_source, dest_bucket, dest_key)
return
def download_file(self, bucket_name: str, file_key: str, file):
self.__s3_client.download_fileobj(
Bucket=bucket_name,
Key=file_key,
Fileobj=file
)
return
def upload_file(self, local_file_path: str, bucket_name: str, file_key: str):
self.__s3_client.upload_file(
local_file_path,
Bucket=bucket_name,
Key=file_key
)
def delete_file(self, bucket_name: str, file_key: str):
self.__s3_client.delete_object(
Bucket=bucket_name,
Key=file_key
)
class S3Bucket():
_s3_client = S3Client()
_bucket_name: str = None
class UltmarcBucket(S3Bucket):
_bucket_name = environment.ULTMARC_DATA_BUCKET
_folder = environment.ULTMARC_DATA_FOLDER
def list_dat_file(self):
return self._s3_client.list_objects(self._bucket_name, self._folder)
def download_dat_file(self, dat_filename: str):
# 一時ファイルとして保存する
temporary_dir = tempfile.mkdtemp()
temporary_file_path = path.join(temporary_dir, f'{dat_filename.replace(f"{self._folder}/", "")}')
with open(temporary_file_path, mode='wb') as f:
self._s3_client.download_file(self._bucket_name, dat_filename, f)
f.seek(0)
return temporary_file_path
def delete_dat_file(self, dat_file_key: str):
self._s3_client.delete_file(self._bucket_name, dat_file_key)
class ConfigBucket(S3Bucket):
_bucket_name = environment.JSKULT_CONFIG_BUCKET
def download_ultmarc_hex_convert_config(self):
# 一時ファイルとして保存する
temporary_dir = tempfile.mkdtemp()
temporary_file_path = path.join(temporary_dir, environment.JSKULT_ULTMARC_HEX_CONVERT_CONFIG_FILE_NAME)
hex_convert_config_key = f'{environment.JSKULT_CONFIG_CONVERT_FOLDER}/{environment.JSKULT_ULTMARC_HEX_CONVERT_CONFIG_FILE_NAME}'
with open(temporary_file_path, mode='wb') as f:
self._s3_client.download_file(self._bucket_name, hex_convert_config_key, f)
f.seek(0)
return temporary_file_path
class JskUltBackupBucket(S3Bucket):
_bucket_name = environment.JSKULT_BACKUP_BUCKET
class VjskBackupBucket(JskUltBackupBucket):
_folder = environment.JSK_BACKUP_FOLDER
class VjskSendBucket(S3Bucket):
_bucket_name = environment.JSK_IO_BUCKET
_send_folder = environment.JSK_DATA_SEND_FOLDER
def upload_dcf_dsf_csv_file(self, vjsk_create_csv: str, csv_file_path: str):
# S3バケットにファイルを移動
csv_file_name = f'{self._send_folder}/{vjsk_create_csv}'
s3_client = S3Client()
s3_client.upload_file(csv_file_path, self._bucket_name, csv_file_name)
return
def backup_dcf_dsf_csv_file(self, dat_file_key: str, datetime_key: str):
# バックアップバケットにコピー
vjsk_backup_bucket = VjskBackupBucket()
dat_key = f'{self._send_folder}/{dat_file_key}'
backup_key = f'{vjsk_backup_bucket._folder}/{datetime_key}/{dat_file_key.replace(f"{self._send_folder}/", "")}'
self._s3_client.copy(self._bucket_name, dat_key, vjsk_backup_bucket._bucket_name, backup_key)

View File

@ -0,0 +1,17 @@
class BatchContext:
__instance = None
__syor_date: str # 処理日(yyyy/mm/dd形式)
@classmethod
def get_instance(cls):
if cls.__instance is None:
cls.__instance = cls()
return cls.__instance
@property
def syor_date(self):
return self.__syor_date
@syor_date.setter
def syor_date(self, syor_date_str: str):
self.__syor_date = syor_date_str

View File

@ -0,0 +1,60 @@
import csv
from io import TextIOWrapper
class DatFileLine:
layout_class: str
records: list[str]
def __init__(self, dat_line: list[str]) -> None:
self.layout_class = dat_line[0]
self.records = dat_line
class DatFile:
"""アルトマークデータファイル"""
lines: list[DatFileLine]
success_count: int = 0
error_count: int = 0
total_count: int = 0
__i: int = 0
def __iter__(self):
return self
def __next__(self) -> DatFileLine:
if self.__i == len(self.lines):
raise StopIteration()
line = self.lines[self.__i]
self.__i += 1
return line
def __init__(self, file: TextIOWrapper) -> None:
reader = csv.reader(file)
csv_rows = [DatFileLine(row) for row in reader]
self.lines = csv_rows
self.total_count = len(csv_rows)
def count_up_success(self):
self.success_count += 1
def count_up_error(self):
self.error_count += 1
@classmethod
def from_path(cls, local_file_path: str):
"""アルトマークデータファイルを読み込み、新しいインスタンスを作成する
Args:
local_file_path (str): ローカルのファイルパス
Returns:
DatFile: このクラスのインスタンス
"""
# cp932(Shift-JIS Windows拡張)でファイルを読み込む
file = open(local_file_path, encoding='cp932')
instance = cls(file)
file.close()
return instance

View File

@ -0,0 +1,153 @@
"""アルトマークデータ処理"""
import json
from urllib.parse import unquote
from src.aws.s3 import ConfigBucket, UltmarcBucket
from src.batch.ultmarc.datfile import DatFile
from src.batch.ultmarc.utmp_tables.ultmarc_table_mapper_factory import \
UltmarcTableMapperFactory
from src.db.database import Database
from src.error.exceptions import BatchOperationException
from src.logging.get_logger import get_logger
from src.system_var import environment
logger = get_logger('アルトマーク取込')
ultmarc_bucket = UltmarcBucket()
config_bucket = ConfigBucket()
def exec_import():
"""アルトマーク取り込み処理"""
try:
logger.info('アルトマーク取込処理: 開始')
# datファイルをS3から取得する
dat_file_list = ultmarc_bucket.list_dat_file()
# ファイルがS3に存在しない場合、起動していること自体が異常のためエラーとする
if len(dat_file_list) == 0:
raise BatchOperationException(f'取込ファイルが見つからないため、異常終了 ファイル一覧:{dat_file_list}')
# ファイルが複数ある場合はエラーとする
if len(dat_file_list) > 1:
raise BatchOperationException(f'複数の取込ファイルがあるため、異常終了 ファイル一覧:{dat_file_list}')
# ファイルの件数は必ず1件になる
dat_file_info = dat_file_list[0]
dat_file_name = dat_file_info['filename']
# ファイル名が日本語のとき、URLエンコードされるているため、デコードする
decoded_import_file_key = unquote(environment.IMPORT_FILE_KEY, encoding='utf-8', errors='replace')
if decoded_import_file_key != dat_file_name:
raise BatchOperationException(f'取込対象のファイルが見つからないため、異常終了 ファイル名:{environment.IMPORT_FILE_KEY}')
# 0Byteの場合、
if dat_file_info['size'] == 0:
logger.info(f'0Byteファイルのため、処理をスキップします。ファイル名={dat_file_info["filename"]}')
# 次回取込時に複数ファイルエラーにならないよう、S3からファイルを削除する
ultmarc_bucket.delete_dat_file(dat_file_name)
return
logger.info(f"{dat_file_name}を取り込みます")
# datファイルをダウンロード
local_file_path = ultmarc_bucket.download_dat_file(dat_file_name)
# 文字コード変換設定ファイルをダウンロード
convert_config_file_path = config_bucket.download_ultmarc_hex_convert_config()
# 文字コードを変換
converted_file_path = _convert_character_hex(local_file_path, convert_config_file_path)
dat_file = DatFile.from_path(converted_file_path)
# アルトマーク取り込み実行
_import_to_ultmarc_table(dat_file)
# 取込完了後、S3からファイルを削除
ultmarc_bucket.delete_dat_file(dat_file_name)
logger.info('アルトマーク取込処理: 終了')
except Exception as e:
raise BatchOperationException(e)
def _convert_character_hex(dat_file_path: str, config_file_path: str) -> str:
"""_summary_
アルトマークデータファイルを読みバイトレベルで文字コードを変換して新しいファイルに書き出す
Args:
dat_file_path (str): 変換前のアルトマークデータファイル
config_file_path (str): 変換設定
Returns:
str: 文字コード変換後のアルトマークデータファイルのパス
"""
logger.debug('文字コード変換開始')
# 変換設定ファイルを読み込む
with open(config_file_path, 'r', encoding='utf-8') as f:
hex_convert_config_dict: dict = json.load(f)
with open(dat_file_path, 'rb') as org_file, open(f'{dat_file_path}.converted', 'wb') as dest_file:
while True:
first_byte = org_file.read(1)
# ファイルの末尾まで読んだらループ終了
if not first_byte:
break
# 読みだした1バイトが、Shift_JIS の日本語範囲(2バイト文字)に含まれる場合、もう1バイト読む
if 0x81 <= first_byte[0] <= 0x9F or 0xE0 <= first_byte[0] <= 0xFC:
second_byte = org_file.read(1)
# ファイルの末尾まで読んだらループ終了
if not second_byte:
break
# 2バイトを結合して、HEXの4桁(大文字)に変換
japanese_bytes = first_byte + second_byte
japanese_hex = ''.join([hex(b)[2:].zfill(2).upper() for b in japanese_bytes])
# 変換対象の文字を変換設定に基づいて変換する
processed_hex = hex_convert_config_dict.get(japanese_hex)
if processed_hex is None:
processed_hex = japanese_hex
# HEXの4桁をバイト列に戻して書き出す
processed_bytes = bytes.fromhex(processed_hex)
dest_file.write(processed_bytes)
else:
# 1バイト文字はそのまま書き出す
dest_file.write(first_byte)
logger.debug('文字コード変換終了')
return f'{dat_file_path}.converted'
def _import_to_ultmarc_table(dat_file: DatFile):
db = Database.get_instance()
try:
# DB接続
db.connect()
# ファイル単位でトランザクションを行う
db.begin()
mapper_factory = UltmarcTableMapperFactory()
# datファイルを1行ずつ処理し、各テーブルへ登録
for line in dat_file:
try:
# 書き込み先のテーブルを特定
mapper_class = mapper_factory.create(
line.layout_class,
line.records,
db
)
mapper_class.make_query()
mapper_class.execute_queries()
dat_file.count_up_success()
except Exception as e:
logger.info(e)
record = line.records
log_message = ','.join([f'"{r}"' for r in record])
logger.info(f'ERROR_LINE: {log_message}')
dat_file.count_up_error()
# 処理結果をログに出力する
logger.info(f'ultmarc import process RESULT')
logger.info(f'SUCCESS_COUNT={dat_file.success_count}')
logger.info(f'ERROR_COUNT={dat_file.error_count}')
logger.info(f'ALL_COUNT={dat_file.total_count}')
# 1件でもエラーがあれば、通知用にログに出力する
if dat_file.error_count > 0:
logger.warning('取り込みに失敗した行があります。詳細は`ERROR_LINE:`の行を確認してください。')
finally:
# 終了時に必ずコミットする
db.commit()
db.disconnect()
return

View File

@ -0,0 +1,227 @@
"""DCF DSFデータ作成処理"""
import csv
import os.path as path
import tempfile
from src.aws.s3 import VjskSendBucket
from src.batch.common.batch_context import BatchContext
from src.db.database import Database
from src.error.exceptions import BatchOperationException
from src.logging.get_logger import get_logger
from src.system_var import environment
logger = get_logger('DCF_DSFデータ作成処理')
def exec():
csv_file_name = environment.DCF_DSF_SEND_FILE_NAME
# バッチ共通設定を取得
batch_context = BatchContext.get_instance()
db = Database.get_instance()
try:
logger.info('処理開始')
# DB接続
db.connect()
# CSVファイルの作成用のSQL実行(施設)
record_dcf = select_dcf_record(db)
# CSVファイルの作成用のSQL実行(薬局)
record_dsf = select_dsf_record(db)
# CSVファイル作成
csv_file_path = make_csv_data(record_dcf, record_dsf, csv_file_name)
# s3へアップロード
jsk_bucket = VjskSendBucket()
jsk_bucket.upload_dcf_dsf_csv_file(csv_file_name, csv_file_path)
# 連携ファイルをバックアップ
jsk_bucket.backup_dcf_dsf_csv_file(csv_file_name, batch_context.syor_date)
csv_count = len(record_dcf) + len(record_dsf)
logger.info(f'CSV出力件数: {csv_count}')
logger.info('正常終了')
except Exception as e:
raise BatchOperationException(e)
finally:
db.disconnect()
return
def select_dcf_record(db):
# CSVファイル作成用のSQL実行(DCF施設)
sql = """\
SELECT dcf_dsf_inst_cd,
inst_div_cd,
addr_unknown_reason_cd,
form_inst_name_kana,
inst_name_kana,
form_inst_name_kanji,
inst_name_kanji,
rltd_univ_prnt_cd,
bed_num,
close_flg,
estab_sche_flg,
close_start_ym,
estab_sche_ym,
ward_abolish_flg,
phone_number_non_flg,
unconf_flg,
inst_phone_number,
inst_addr_kana,
inst_addr,
postal_number,
village_cd,
prefc_cd,
city_cd,
addr_display_number,
addr_cnt_kana,
addr_cnt,
manage_cd,
delete_sche_reason_cd,
hp_assrt_cd,
dup_opp_cd,
insp_item_micrb,
insp_item_serum,
insp_item_blood,
insp_item_patho,
insp_item_paras,
insp_item_biochem,
insp_item_ri,
re_exam_cd,
prmit_bed_num_other,
prmit_bed_num_mental,
prmit_bed_num_tuber,
prmit_bed_num_infection,
prmit_bed_num_sum,
prmit_bed_num_gen,
prmit_bed_num_rcup,
prmit_bed_maint_ymd,
inst_pharm_div,
abolish_ymd,
delete_flg,
filler_1,
filler_2,
filler_3,
filler_4,
filler_5,
regist_date,
create_user,
update_date,
update_user,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
FROM src05.com_inst ORDER BY dcf_dsf_inst_cd
"""
return db.execute_select(sql)
def select_dsf_record(db):
# CSVファイル作成用のSQL実行(DSF薬局)
sql = """\
SELECT dcf_dsf_inst_cd,
inst_div_cd,
addr_unknown_reason_cd,
form_inst_name_kana,
inst_name_kana,
form_inst_name_kanji,
inst_name_kanji,
'' AS rltd_univ_prnt_cd,
'' AS bed_num,
close_flg,
estab_sche_flg,
close_start_ym,
estab_sche_ym,
'' AS ward_abolish_flg,
phone_number_non_flg,
unconf_flg,
inst_phone_number,
inst_addr_kana,
inst_addr,
postal_number,
village_cd,
prefc_cd,
city_cd,
addr_display_number,
addr_cnt_kana,
addr_cnt,
manage_cd,
delete_sche_reason_cd,
'' AS hp_assrt_cd,
dup_opp_cd,
'' AS insp_item_micrb,
'' AS insp_item_serum,
'' AS insp_item_blood,
'' AS insp_item_patho,
'' AS insp_item_paras,
'' AS insp_item_biochem,
'' AS insp_item_ri,
'' AS re_exam_cd,
'' AS prmit_bed_num_other,
'' AS prmit_bed_num_mental,
'' AS prmit_bed_num_tuber,
'' AS prmit_bed_num_infection,
'' AS prmit_bed_num_sum,
'' AS prmit_bed_num_gen,
'' AS prmit_bed_num_rcup,
'' AS prmit_bed_maint_ymd,
inst_pharm_div,
abolish_ymd,
delete_flg,
filler_1,
filler_2,
filler_3,
filler_4,
filler_5,
regist_date,
create_user,
update_date,
update_user,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
FROM src05.com_pharm ORDER BY dcf_dsf_inst_cd
"""
return db.execute_select(sql)
def make_csv_data(record_inst: list, record_pharm: list, csv_file_name: str):
# CSVファイルを作成する
temporary_dir = tempfile.mkdtemp()
csv_file_path = path.join(temporary_dir, csv_file_name)
head_str = ['DCF_DSF_INST_CD', 'INST_DIV_CD', 'ADDR_UNKNOWN_REASON_CD', 'FORM_INST_NAME_KANA', 'INST_NAME_KANA',
'FORM_INST_NAME_KANJI', 'INST_NAME_KANJI', 'RLTD_UNIV_PRNT_CD', 'BED_NUM', 'CLOSE_FLG', 'ESTAB_SCHE_FLG',
'CLOSE_START_YM', 'ESTAB_SCHE_YM', 'WARD_ABOLISH_FLG', 'PHONE_NUMBER_NON_FLG', 'UNCONF_FLG', 'INST_PHONE_NUMBER',
'INST_ADDR_KANA', 'INST_ADDR', 'POSTAL_NUMBER', 'VILLAGE_CD', 'PREFC_CD', 'CITY_CD', 'ADDR_DISPLAY_NUMBER',
'ADDR_CNT_KANA', 'ADDR_CNT', 'MANAGE_CD', 'DELETE_SCHE_REASON_CD', 'HP_ASSRT_CD', 'DUP_OPP_CD', 'INSP_ITEM_MICRB',
'INSP_ITEM_SERUM', 'INSP_ITEM_BLOOD', 'INSP_ITEM_PATHO', 'INSP_ITEM_PARAS', 'INSP_ITEM_BIOCHEM', 'INSP_ITEM_RI',
'RE_EXAM_CD', 'PRMIT_BED_NUM_OTHER', 'PRMIT_BED_NUM_MENTAL', 'PRMIT_BED_NUM_TUBER', 'PRMIT_BED_NUM_INFECTION',
'PRMIT_BED_NUM_SUM', 'PRMIT_BED_NUM_GEN', 'PRMIT_BED_NUM_RCUP', 'PRMIT_BED_MAINT_YMD', 'INST_PHARM_DIV', 'ABOLISH_YMD',
'DELETE_FLG', 'FILLER_1', 'FILLER_2', 'FILLER_3', 'FILLER_4', 'FILLER_5', 'REGIST_DATE', 'CREATE_USER', 'UPDATE_DATE',
'UPDATE_USER', 'SYS_REGIST_DATE', 'REGIST_PRGM_ID', 'SYS_UPDATE_DATE', 'UPDATE_PRGM_ID']
with open(csv_file_path, mode='w', encoding='UTF-8') as csv_file:
# UTF-8、CRLF、価囲いなしで書き込む
writer = csv.writer(csv_file, delimiter=',', lineterminator='\r\n',
quoting=csv.QUOTE_NONE,
strict=True
)
writer.writerow(head_str)
# データ部分書き込み
for record_inst_data in record_inst:
record_inst_value = list(record_inst_data.values())
csv_data = ['' if n is None else n for n in record_inst_value]
writer.writerow(csv_data)
# データ部分書き込み(薬局)
for record_pharm_data in record_pharm:
record_pharm_value = list(record_pharm_data.values())
csv_data = ['' if n is None else n for n in record_pharm_value]
writer.writerow(csv_data)
return csv_file_path

View File

@ -0,0 +1,107 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_alma_depart_disc import ComAlmaDepartDisc
class ComAlmaDepartDiscMapper(UltmarcTableMapper):
"""レイアウト区分003: COM_出身校学部識別 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_alma_depart_disc
WHERE
alma_cd = :alma_cd
AND
depart_disc_cd = :depart_disc_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_alma_depart_disc
(
alma_cd,
depart_disc_cd,
estab_e,
estab_y,
alma_name,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:alma_cd,
:depart_disc_cd,
:estab_e,
:estab_y,
:alma_name,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 更新用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_alma_depart_disc
SET
estab_e = :estab_e,
estab_y = :estab_y,
alma_name = :alma_name,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
alma_cd = :alma_cd
AND
depart_disc_cd = :depart_disc_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_alma_depart_disc
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
alma_cd = :alma_cd
AND
depart_disc_cd = :depart_disc_cd
"""
record: ComAlmaDepartDisc
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComAlmaDepartDisc)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,92 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_alma import ComAlma
class ComAlmaMapper(UltmarcTableMapper):
"""レイアウト区分004: COM_出身校 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_alma
WHERE
alma_cd = :alma_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_alma
(
alma_cd,
alma,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:alma_cd,
:alma,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
UPDATE_QUERY = """\
UPDATE
src05.com_alma
SET
alma = :alma,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
alma_cd = :alma_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_alma
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
alma_cd = :alma_cd
"""
record: ComAlma
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComAlma)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,105 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_blng_sec import ComBlngSec
class ComBlngSecMapper(UltmarcTableMapper):
"""レイアウト区分008: COM_所属部科 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_blng_sec
WHERE
blng_sec_cd = :blng_sec_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_blng_sec
(
blng_sec_cd,
blng_sec_kana,
blng_sec_name,
inst_category,
trt_category,
category_sort,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:blng_sec_cd,
:blng_sec_kana,
:blng_sec_name,
:inst_category,
:trt_category,
:category_sort,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 変更用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_blng_sec
SET
blng_sec_kana = :blng_sec_kana,
blng_sec_name = :blng_sec_name,
inst_category = :inst_category,
trt_category = :trt_category,
category_sort = :category_sort,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
blng_sec_cd = :blng_sec_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_blng_sec
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
blng_sec_cd = :blng_sec_cd
"""
record: ComBlngSec
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComBlngSec)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,108 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_cop_hp import ComCopHp
class ComCopHpMapper(UltmarcTableMapper):
"""レイアウト区分112: COM_臨床研修病院 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_cop_hp
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
cophp_cd = :cophp_code
AND
openyear = :open_year
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_cop_hp
(
dcf_dsf_inst_cd,
cophp_cd,
openyear,
sortkey,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:dcfdsf_inst_code,
:cophp_code,
:open_year,
:sort_key,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# データ変更用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_cop_hp
SET
sortkey = :sort_key,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
cophp_cd = :cophp_code
AND
openyear = :open_year
"""
# 削除『修正区分がB(修正)かつ追加削除区分が1(退職)』の場合、物理削除
PHYSICAL_DELETE_QUERY = """\
DELETE FROM
src05.com_cop_hp
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
cophp_cd = :cophp_code
AND
openyear = :open_year
"""
record: ComCopHp
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComCopHp)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 削除『修正区分がB(修正)かつ追加削除区分が1(退職)』の場合、物理削除
if self.record.maint_flag == 'B' and self.record.adddel_div == '1':
self.queries.append(self.PHYSICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
# 更新する値が空の場合は、更新処理を行わない
if self.record.sort_key == '':
return None
else:
return self.UPDATE_QUERY

View File

@ -0,0 +1,480 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_dr import ComDr
class ComDrMapper(UltmarcTableMapper):
"""レイアウト区分501: COM_医師 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_dr
WHERE
dcf_pcf_dr_cd = :dcf_pcf_dr_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_dr
(
dcf_pcf_dr_cd,
dr_name_kana,
dr_name,
birthday_era,
birthday_year,
birthday_month,
birthday_day,
birthday,
hometown_cd,
estab_era,
estab_year,
estab_y,
home_phone_number,
home_addr_kana,
home_addr,
home_postal_number,
addr_village_cd,
prefc_cd,
city_cd,
addr_display_number,
addr_cnt_kana,
addr_cnt,
dr_circle_cd,
estab_div_cd,
sex_cd,
delete_sche_reason_cd,
addr_unknown_reason_cd,
alma_cd,
depart_disc_cd,
grad_era,
grad_year,
grad_y,
lump_regist_flg,
opp_dup_cd,
dr_ph_div,
use_stop_div,
use_stop_reason_cd,
use_stop_regist_ymd,
use_stop_cancel_ymd,
drday_era,
drday_year,
drday_y,
abolish_ymd,
delete_flg,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:dcf_pcf_dr_cd,
:dr_name_kana,
:dr_name,
:birthday_era,
:birthday_year,
:birthday_month,
:birthday_day,
:birth_day,
:home_town_code,
:pract_yearera,
:pract_year,
:estab_y,
:dr_tel,
:dr_addr_kana,
:dr_addr,
:dr_zip_code,
:addr_village_cd,
:pref_code,
:city_code,
:dr_addr_num,
:addr_cnt_kana,
:addr_cnt,
:medassoci_code,
:pract_class_code,
:sex_code,
:drdel_code,
:dr_addr_lost_code,
:graduniv_code,
:graduniv_dept_code,
:grad_yearera,
:grad_year,
:grad_y,
:bskregst_flag,
:opp_dup_code,
1,
:use_stop_flag,
:use_stopc_ode,
:cre_stop_date,
:release_date,
:drda_yera,
:drday_year,
:drday_y,
NULL,
0,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
UPDATE_QUERY = """\
UPDATE
src05.com_dr
SET
{update_columns}
dr_ph_div = 1,
abolish_ymd = NULL,
delete_flg = 0,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
dcf_pcf_dr_cd = :dcf_pcf_dr_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_dr
SET
abolish_ymd = :maint_date,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
dcf_pcf_dr_cd = :dcf_pcf_dr_cd
"""
# 西暦取得SQL
YEAR_GET_QUERY = """\
SELECT
year AS year
FROM
src05.com_era
WHERE
era_cd = :era_cd
"""
# COM_医師診療科目の物理削除SQL
PHYSICAL_DELETE_QUERY_TRT = """\
DELETE FROM
src05.com_dr_trt_course
WHERE
dcf_pcf_dr_cd = :dcf_pcf_dr_cd
"""
# COM_医師診療科目の登録用SQL
INSERT_QUERY_TRT = """\
INSERT INTO src05.com_dr_trt_course
(
trt_course_cd,
sequence,
dcf_pcf_dr_cd,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
{trt_course_code},
{trt_sequence},
:dcf_pcf_dr_cd,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
record: ComDr
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComDr)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.__make_upsert_query()
return
def __make_upsert_query(self):
# 西暦の取得
self.__set_era()
# 「@」による項目クリアを設定
self.__set_clearing_item()
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
self.queries.append(self.INSERT_QUERY)
# COM_医師診療科目 削除登録
self.__make_delete_insert_trt_query()
return
# 存在する場合ではUpdate
# COM_医師診療科目 削除登録
self.__make_delete_insert_trt_query()
update_columns = ','.join(self.__make_update_query())
# 何も更新項目が無い場合はNoneとする更新処理は行わない
if len(update_columns) == 0:
self.queries.append(None)
return
else:
# 末尾にカンマを付けてSET句を完成させる
update_columns += ','
update_query = self.UPDATE_QUERY.format(
update_columns=update_columns
)
self.queries.append(update_query)
return
def __make_update_query(self):
set_clauses = [] # 設定項目
# 削除予定理由
if len(self.record.drdel_code) > 0:
set_clauses.append('delete_sche_reason_cd = :drdel_code')
# 重複時相手先コード
if len(self.record.opp_dup_code) > 0:
set_clauses.append('opp_dup_cd = :opp_dup_code')
# 医師名(漢字)
if len(self.record.dr_name) > 0:
set_clauses.append('dr_name = :dr_name')
# 医師名(カナ)
if len(self.record.dr_name_kana) > 0:
set_clauses.append('dr_name_kana = :dr_name_kana')
# 性別
if len(self.record.sex_code) > 0:
set_clauses.append('sex_cd = :sex_code')
# 生年月日
if len(self.record.birthday_era + self.record.birthday_year + self.record.birthday_month + self.record.birthday_day) > 0:
set_clauses.append('birthday_era = :birthday_era')
set_clauses.append('birthday_year = :birthday_year')
set_clauses.append('birthday_month = :birthday_month')
set_clauses.append('birthday_day = :birthday_day')
set_clauses.append('birthday = :birth_day')
# 出身都道府県コード
if len(self.record.home_town_code) > 0:
set_clauses.append('hometown_cd = :home_town_code')
# 医師会コード
if len(self.record.medassoci_code) > 0:
set_clauses.append('dr_circle_cd = :medassoci_code')
# 卒年
if len(self.record.grad_yearera + self.record.grad_year) > 0:
set_clauses.append('grad_year = :grad_year')
set_clauses.append('grad_era = :grad_yearera')
set_clauses.append('grad_y = :grad_y')
# 出身校コード
if len(self.record.graduniv_code) > 0:
set_clauses.append('alma_cd = :graduniv_code')
# 出身校学部識別コード
if len(self.record.graduniv_dept_code) > 0:
set_clauses.append('depart_disc_cd = :graduniv_dept_code')
# 登録年
if len(self.record.drda_yera + self.record.drday_year) > 0:
set_clauses.append('drday_era = :drda_yera')
set_clauses.append('drday_year = :drday_year')
set_clauses.append('drday_y = :drday_y')
# 住所不明
if len(self.record.dr_addr_lost_code) > 0:
set_clauses.append('addr_unknown_reason_cd = :dr_addr_lost_code')
# 住所
# 集合項目のいずれかに入力がある場合に更新
if sum(len(item) for item in self.record.address_aggregation_items) > 0:
set_clauses.append('home_addr_kana = :dr_addr_kana')
set_clauses.append('home_addr = :dr_addr')
set_clauses.append('home_postal_number = :dr_zip_code')
set_clauses.append('addr_village_cd = :addr_village_cd')
set_clauses.append('prefc_cd = :pref_code')
set_clauses.append('city_cd = :city_code')
set_clauses.append('addr_display_number = :dr_addr_num')
set_clauses.append('addr_cnt_kana = :addr_cnt_kana')
set_clauses.append('addr_cnt = :addr_cnt')
# 自宅電話番号
if len(self.record.dr_tel) > 0:
set_clauses.append('home_phone_number = :dr_tel')
# 利用停止区分
if len(self.record.use_stop_flag) > 0:
set_clauses.append('use_stop_div = :use_stop_flag')
# 利用停止理由
if len(self.record.use_stopc_ode) > 0:
set_clauses.append('use_stop_reason_cd = :use_stopc_ode')
# 利用停止登録年月日
if len(self.record.cre_stop_date) > 0:
set_clauses.append('use_stop_regist_ymd = :cre_stop_date')
# 利用停止解除年月日
if len(self.record.release_date) > 0:
set_clauses.append('use_stop_cancel_ymd = :release_date')
# 開勤区分
if len(self.record.pract_class_code) > 0:
set_clauses.append('estab_div_cd = :pract_class_code')
# 開業年
if len(self.record.pract_yearera + self.record.pract_year) > 0:
set_clauses.append('estab_era = :pract_yearera')
set_clauses.append('estab_year = :pract_year')
set_clauses.append('estab_y = :estab_y')
# 一括登録フラグ
if len(self.record.bskregst_flag) > 0:
set_clauses.append('lump_regist_flg = :bskregst_flag')
return set_clauses
def __make_delete_insert_trt_query(self):
# 診療科目(集合項目)のいずれかに入力がある場合
if sum(len(item) for item in self.record.medsbj_code_items) == 0:
return
# 削除
self.queries.append(self.PHYSICAL_DELETE_QUERY_TRT)
# @マークの場合は、登録しない
if self.record.medsbj_code1 == '@':
return
# 登録
for num, m_code in enumerate(self.record.medsbj_code_items, start=1):
if len(m_code) > 0:
insert_trt_query = self.INSERT_QUERY_TRT.format(
trt_course_code=f':medsbj_code{num}',
trt_sequence=num
)
self.queries.append(insert_trt_query)
return
def __set_era(self):
# 西暦の取得
# 生年月日(西暦)
western_year: str = ""
if self.record.birthday_era != "@" and len(self.record.birthday_era) > 0 and len(self.record.birthday_year) > 0:
self.query_parameter['era_cd'] = self.record.birthday_era
record_year = self.db.execute_select(self.YEAR_GET_QUERY, self.query_parameter)
western_year = str(int(record_year[0]['year']) + int(self.record.birthday_year))
# 生年月日の設定
self.query_parameter['birth_day'] = self.__set_birthday(western_year)
# 開業年(西暦)
if self.record.pract_yearera != "@" and len(self.record.pract_yearera) > 0 and len(self.record.pract_year) > 0:
self.query_parameter['era_cd'] = self.record.pract_yearera
record_year = self.db.execute_select(self.YEAR_GET_QUERY, self.query_parameter)
self.query_parameter['estab_y'] = str(int(record_year[0]['year']) + int(self.record.pract_year))
# 卒業年(西暦)
if self.record.grad_yearera != "@" and len(self.record.grad_yearera) > 0 and len(self.record.grad_year) > 0:
self.query_parameter['era_cd'] = self.record.grad_yearera
record_year = self.db.execute_select(self.YEAR_GET_QUERY, self.query_parameter)
self.query_parameter['grad_y'] = str(int(record_year[0]['year']) + int(self.record.grad_year))
# 登録年(西暦)
if self.record.drda_yera != "@" and len(self.record.drda_yera) > 0 and len(self.record.drday_year) > 0:
self.query_parameter['era_cd'] = self.record.drda_yera
record_year = self.db.execute_select(self.YEAR_GET_QUERY, self.query_parameter)
self.query_parameter['drday_y'] = str(int(record_year[0]['year']) + int(self.record.drday_year))
return
def __set_birthday(self, western_year: str = ""):
# 生年月日を設定
# 年(西暦)、月、日を連結
birth_day = ''.join([western_year, self.record.birthday_month, self.record.birthday_day])
# 年(西暦)、月、日が全て揃っている場合
if len(birth_day) == 8:
return birth_day
# 西暦が空の場合、先頭に半角スペース4つで連結
if len(western_year) == 0 and len(self.record.birthday_month) > 0 and len(self.record.birthday_day) > 0:
return f' {self.record.birthday_month}{self.record.birthday_day}'
# 月日も空の場合、生年月日は空
return ''
def __set_clearing_item(self):
# 削除予定理由
if self.record.drdel_code == '@':
self.query_parameter['drdel_code'] = None
# 重複時相手先コード
if self.record.reptdr_id == '@':
self.query_parameter['opp_dup_code'] = None
# 生年月日
if self.record.birthday_era == '@':
self.query_parameter['birthday_era'] = None
self.query_parameter['birthday_year'] = None
self.query_parameter['birthday_month'] = None
self.query_parameter['birthday_day'] = None
self.query_parameter['birth_day'] = None
# 卒年
if self.record.grad_yearera == '@':
self.query_parameter['grad_yearera'] = None
self.query_parameter['grad_year'] = None
self.query_parameter['grad_y'] = None
# 登録年
if self.record.drda_yera == '@':
self.query_parameter['drda_yera'] = None
self.query_parameter['drday_year'] = None
self.query_parameter['drday_y'] = None
# 住所不明
if self.record.dr_addr_lost_code == '@':
self.query_parameter['dr_addr_lost_code'] = None
# 自宅電話番号
if self.record.dr_tel == '@':
self.query_parameter['dr_tel'] = None
# 利用停止区分
if self.record.use_stop_flag == '@':
self.query_parameter['use_stop_flag'] = None
# 利用停止理由
if self.record.use_stopc_ode == '@':
self.query_parameter['use_stopc_ode'] = None
# 利用停止登録年月日
if self.record.cre_stop_date == '@':
self.query_parameter['cre_stop_date'] = None
# 利用停止解除年月日
if self.record.release_date == '@':
self.query_parameter['release_date'] = None
# 開業年
if self.record.pract_yearera == '@':
self.query_parameter['pract_yearera'] = None
self.query_parameter['pract_year'] = None
self.query_parameter['estab_y'] = None
return

View File

@ -0,0 +1,97 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_dr_sosiety import ComDrSosiety
class ComDrSosietyMapper(UltmarcTableMapper):
"""レイアウト区分521: COM_所属学会 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_dr_sosiety
WHERE
sosiety_cd = :sosiety_cd
AND
dcf_pcf_dr_cd = :dcf_pcf_dr_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_dr_sosiety
(
sosiety_cd,
dcf_pcf_dr_cd,
sosiety_f,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:sosiety_cd,
:dcf_pcf_dr_cd,
:sosiety_f,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
UPDATE_QUERY = """\
UPDATE
src05.com_dr_sosiety
SET
sosiety_f = :sosiety_f,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
sosiety_cd = :sosiety_cd
AND
dcf_pcf_dr_cd = :dcf_pcf_dr_cd
"""
# 削除『修正区分がB(修正)かつ追加削除区分が1(退職)』SQL
PHYSICAL_DELETE_QUERY = """\
DELETE FROM
src05.com_dr_sosiety
WHERE
sosiety_cd = :sosiety_cd
AND
dcf_pcf_dr_cd = :dcf_pcf_dr_cd
"""
record: ComDrSosiety
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComDrSosiety)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 削除『修正区分がB(修正)かつ追加削除区分が1(退職)』
if self.record.maint_flag == 'B' and self.record.cont_flag == '1':
self.queries.append(self.PHYSICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,281 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_dr_wrkplace import ComDrWrkplace
class ComDrWrkplaceMapper(UltmarcTableMapper):
"""レイアウト区分502:COM_医師勤務先 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_dr_wrkplace
WHERE
dcf_pcf_dr_cd = :full_dcfdr_code
AND dcf_dsf_inst_cd = :full_hp_code
"""
# COM_所属部課から所属部科カナと所属部科名を取得するSQL
GET_NAME_FROM_COM_BLNG_SEC_QUERY = """\
SELECT
blng_sec_kana,
blng_sec_name
FROM
src05.com_blng_sec
WHERE
blng_sec_cd = :sectcode
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_dr_wrkplace (
dcf_dsf_inst_cd,
dcf_pcf_dr_cd,
blng_sec_cd,
post_cd,
identity_cd,
aply_start_ymd,
blng_sec_name_kana,
blng_sec_name,
notdm_flg,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:full_hp_code,
:full_dcfdr_code,
:sectcode,
:postcode,
:identitycode,
:syor_date,
:sectname_kana,
:sectname,
:notdm_flg,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 更新用SQL
UPDATE_QUERY = """\
UPDATE src05.com_dr_wrkplace
SET
{update_columns}
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
DCF_PCF_DR_CD= :full_dcfdr_code
AND DCF_DSF_INST_CD = :full_hp_code
"""
# 更新・削除の場合に該当のデータを履歴テーブルに退避するSQL
TO_HISTORY_QUERY = """\
INSERT INTO src05.com_dr_wrkplace_his (
dcf_dsf_inst_cd,
dcf_pcf_dr_cd,
blng_sec_cd,
post_cd,
identity_cd,
aply_start_ymd,
blng_sec_name_kana,
blng_sec_name,
notdm_flg,
aply_end_ymd,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
SELECT
dcf_dsf_inst_cd,
dcf_pcf_dr_cd,
(
CASE
WHEN blng_sec_cd = '' THEN '9999'
ELSE blng_sec_cd
END
) AS blng_sec_cd,
(
CASE
WHEN post_cd = '' THEN '999'
ELSE post_cd
END
) AS post_cd,
(
CASE
WHEN identity_cd = '' THEN '999'
ELSE identity_cd
END
) AS identity_cd,
DATE_FORMAT(aply_start_ymd, '%Y%m%d'),
blng_sec_name_kana,
blng_sec_name,
notdm_flg,
(
CASE
WHEN DATE_FORMAT(aply_start_ymd, '%Y%m%d') > DATE_FORMAT(DATE_SUB(:syor_date, INTERVAL 1 DAY), '%Y%m%d') THEN DATE_FORMAT(aply_start_ymd, '%Y%m%d')
ELSE DATE_FORMAT(DATE_SUB(:syor_date, INTERVAL 1 DAY), '%Y%m%d')
END
) AS aply_end_ymd,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
FROM
src05.com_dr_wrkplace
WHERE
dcf_pcf_dr_cd = :full_dcfdr_code
AND dcf_dsf_inst_cd = :full_hp_code
AND aply_start_ymd < :syor_date
"""
# 退職レコードの場合、物理削除するSQL
PHYSICAL_DELETE_FOR_RETIREMENT_QUERY = """\
DELETE FROM src05.com_dr_wrkplace
WHERE
dcf_pcf_dr_cd = :full_dcfdr_code
AND dcf_dsf_inst_cd = :full_hp_code
"""
record: ComDrWrkplace
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComDrWrkplace)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 所属部科を取得し、所属部科カナと所属部科名を設定する
self.__set_sect_name_and_sect_name_kana()
# 追加/更新クエリを生成
# 履歴へのレコード登録もあるため、リストで返る
self.queries = self.__make_queries()
return
def __set_sect_name_and_sect_name_kana(self):
# 所属部科を取得し、所属部科カナと所属部科名を設定する
com_blng_sec_records = self.db.execute_select(self.GET_NAME_FROM_COM_BLNG_SEC_QUERY, self.query_parameter)
if len(com_blng_sec_records) == 0:
return
# 必ず1件
com_blng_sec_record = com_blng_sec_records[0]
if com_blng_sec_record['blng_sec_kana'] != '' and com_blng_sec_record['blng_sec_kana'] is not None:
self.record.sectname_kana = com_blng_sec_record['blng_sec_kana']
self.query_parameter['sectname_kana'] = com_blng_sec_record['blng_sec_kana']
if com_blng_sec_record['blng_sec_name'] != '' and com_blng_sec_record['blng_sec_name'] is not None:
self.record.sectname = com_blng_sec_record['blng_sec_name']
self.query_parameter['sectname'] = com_blng_sec_record['blng_sec_name']
def __make_queries(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 「@」による項目クリアを設定
self.__set_clearing_item()
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return [self.INSERT_QUERY]
# 存在する場合はUpdate
# 予備/退職異動区分が1(削除:退職)の場合、退職済みのレコードとして処理
if self.record.drretflag == '1':
# 履歴への移動と、退職レコードの物理削除
return [self.TO_HISTORY_QUERY, self.PHYSICAL_DELETE_FOR_RETIREMENT_QUERY]
# 履歴への移動+更新クエリ生成
return self.__make_update_query()
def __make_update_query(self):
make_history_query = None
# 履歴レコード作成判断となる、UPDATE SET句を作成
set_clauses_with_historical = self.__make_update_columns_with_historical()
# 履歴レコード作成判断とならない、UPDATE SET句
set_clause_without_historical = []
# DM不可フラグの値をセット
# 履歴レコード作成判断とならないため、後から設定
if self.record.notdm_flg != '':
set_clause_without_historical.append(f'notdm_flg = :notdm_flg')
# 何かしら更新がある場合、履歴作成クエリを作成
if len(set_clauses_with_historical) != 0:
make_history_query = self.TO_HISTORY_QUERY
update_columns = ','.join(set_clauses_with_historical + set_clause_without_historical)
if len(update_columns) == 0:
update_query = None
else:
# 何かしら更新がある場合、末尾にカンマを付けてSET句を完成させる
update_columns += ','
update_query = self.UPDATE_QUERY.format(
update_columns=update_columns
)
return [make_history_query, update_query]
def __make_update_columns_with_historical(self):
# 履歴レコードの作成有無を判断するカラムの更新設定
# DM不可フラグは、履歴レコードの作成判断に使わないため、この関数の外で判定する
set_clauses = []
# 役職コード
if self.record.postcode != '':
set_clauses.append('post_cd = :postcode')
# 大学順位
if self.record.identitycode != '':
set_clauses.append('identity_cd = :identitycode')
# 所属部科(集合項目)
if self.record.sectcode != '':
# 所属部科コード
set_clauses.append('blng_sec_cd = :sectcode')
# 所属部科(カナ)
set_clauses.append(f'blng_sec_name_kana = :sectname_kana')
# 所属部科(漢字)
set_clauses.append(f'blng_sec_name = :sectname')
# 何かしら更新がある場合、適用開始日をセットする
if len(set_clauses) != 0:
# 処理日はパラメータに設定済み
set_clauses.append("aply_start_ymd = DATE_FORMAT(:syor_date, '%Y%m%d')")
return set_clauses
def __set_clearing_item(self):
# 役職コード
if self.record.postcode == '@':
# NOT NULLのため、空文字をセット
self.query_parameter['postcode'] = ''
# 大学順位
if self.record.identitycode == '@':
# NOT NULLのため、空文字をセット
self.query_parameter['identitycode'] = ''
# DM不可フラグ
if self.record.notdm_flg == '@':
self.query_parameter['notdm_flg'] = None
# 以下、実際には項目のクリアが発生しない為不要なロジックだが、現行踏襲の為残しておく
# 所属部科コード
if self.record.sectcode == '@':
# NOT NULLのため、固定の所属部科コードをセット
self.query_parameter['sectcode'] = '9999'
# 所属部科(カナ)
if self.record.sectname_kana == '@':
self.query_parameter['sectname_kana'] = None
# 所属部科(漢字)
# 全角の項目なので、修正項目値として全角@が連携される
if self.record.sectname == '':
self.query_parameter['sectname'] = None
return

View File

@ -0,0 +1,95 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_forfront_med_equip import ComForfrontMedEquip
class ComForfrontMedEquipMapper(UltmarcTableMapper):
"""レイアウト区分022: COM_先端医療機器 登録処理 """
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_forfront_med_equip
WHERE
forfront_med_equip_cd = :hi_medicmach_code
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_forfront_med_equip
(
forfront_med_equip_cd,
forfront_med_equip_name,
regist_ymd,
delete_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:hi_medicmach_code,
:hi_medicmach_name,
:execute_date_str_ymd,
NULL,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 更新用SQL
UPDATE_QUERY = """\
UPDATE src05.com_forfront_med_equip
SET
forfront_med_equip_name = :hi_medicmach_name,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
forfront_med_equip_cd = :hi_medicmach_code
"""
# 修正区分が「C(削除)」の場合の更新SQL
# 削除年月日 ← システム日付
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_forfront_med_equip
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
forfront_med_equip_cd = :hi_medicmach_code
"""
record: ComForfrontMedEquip
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComForfrontMedEquip)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合はUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,96 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_hamtec import ComHamtec
class ComHamtecMapper(UltmarcTableMapper):
"""レイアウト区分021: COM_高度先進医療 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_hamtec
WHERE
hamtec_cd = :hamtec_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_hamtec
(
hamtec_cd,
hamtec_div,
hamtec_name,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:hamtec_cd,
:hamtec_div,
:hamtec_name,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 更新用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_hamtec
SET
hamtec_div = :hamtec_div,
hamtec_name = :hamtec_name,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
hamtec_cd = :hamtec_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_hamtec
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
hamtec_cd = :hamtec_cd
"""
record: ComHamtec
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComHamtec)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合はUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,93 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_hp_assrt import ComHpAssrt
class ComHpAssrtMapper(UltmarcTableMapper):
"""レイアウト区分002: COM_病院種別 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_hp_assrt
WHERE
hp_assrt_cd = :hp_assrt_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_hp_assrt
(
hp_assrt_cd,
hp_assrt_name,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:hp_assrt_cd,
:hp_assrt_name,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 更新用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_hp_assrt
SET
hp_assrt_name = :hp_assrt_name,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
hp_assrt_cd = :hp_assrt_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_hp_assrt
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
hp_assrt_cd = :hp_assrt_cd
"""
record: ComHpAssrt
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComHpAssrt)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,93 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_inst_div import ComInstDiv
class ComInstDivMapper(UltmarcTableMapper):
"""レイアウト区分011: COM_施設区分 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_inst_div
WHERE
inst_div_cd = :inst_div_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_inst_div
(
inst_div_cd,
inst_div_name,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:inst_div_cd,
:inst_div_name,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 変更用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_inst_div
SET
inst_div_name = :inst_div_name,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
inst_div_cd = :inst_div_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_inst_div
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
inst_div_cd = :inst_div_cd
"""
record: ComInstDiv
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComInstDiv)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,563 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_inst import ComInst
class ComInstMapper(UltmarcTableMapper):
"""レイアウト区分101: COM_施設 登録処理"""
# レコード存在確認SQL(COM_施設)
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_inst
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
"""
# データ登録用SQL(COM_施設)
INSERT_INST_QUERY = """\
INSERT INTO src05.com_inst
(
dcf_dsf_inst_cd,
inst_div_cd,
addr_unknown_reason_cd,
form_inst_name_kana,
inst_name_kana,
form_inst_name_kanji,
inst_name_kanji,
rltd_univ_prnt_cd,
bed_num,
close_flg,
estab_sche_flg,
close_start_ym,
estab_sche_ym,
ward_abolish_flg,
inst_repre_cd,
inst_repre_kana,
inst_repre,
phone_number_non_flg,
unconf_flg,
inst_phone_number,
inst_addr_kana,
inst_addr,
postal_number,
village_cd,
prefc_cd,
city_cd,
addr_display_number,
addr_cnt_kana,
addr_cnt,
manage_cd,
delete_sche_reason_cd,
hp_assrt_cd,
dup_opp_cd,
insp_item_micrb,
insp_item_serum,
insp_item_blood,
insp_item_patho,
insp_item_paras,
insp_item_biochem,
insp_item_ri,
re_exam_cd,
prmit_bed_num_other,
prmit_bed_num_mental,
prmit_bed_num_tuber,
prmit_bed_num_infection,
prmit_bed_num_sum,
prmit_bed_num_gen,
prmit_bed_num_rcup,
prmit_bed_maint_ymd,
inst_pharm_div,
abolish_ymd,
delete_flg,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:dcfdsf_inst_code,
:hp_class_code,
:hp_addr_lost_code,
:hp_name_kana,
:hp_ryaku_name_kana,
:hp_name,
:hp_ryaku_name,
:univ_prnt_code,
:bed_num,
:close_flag,
:open_flag,
:close_year_month,
:open_year_month,
:close_flag2,
:inst_repre_code,
:president_kana,
:president,
:tel_nothing_flag,
:uncheck_flag,
:hp_tel,
:hp_addr_kana,
:hp_addr,
:hp_zip_code,
:village_code,
:pref_code,
:city_code,
:hp_addr_number,
:addr_cnt_kana,
:addr_cnt,
:mgt_class_code,
:hpdel_code,
:hp_kind_code,
:dup_opp_code,
:inspect_code1,
:inspect_code2,
:inspect_code3,
:inspect_code4,
:inspect_code5,
:inspect_code6,
:inspect_code7,
:reexam_flag,
:bed_num_gen,
:bed_num_psy,
:bed_num_tub,
:bed_num_epi,
:bed_num_sum,
:bed_num_gen2,
:bed_num_rest,
:bed_class_maint_date,
1,
NULL,
0,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# データ更新用SQL(COM_施設)
UPDATE_INST_QUERY = """\
UPDATE
src05.com_inst
SET
{update_columns}
abolish_ymd = NULL,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_inst
SET
abolish_ymd = :maint_date,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
"""
# データ登録用SQL(COM_施設診療科目)
INSERT_INST_TRT_QUERY = """\
INSERT INTO src05.com_inst_trt_course
(
dcf_dsf_inst_cd,
trt_course_cd,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:dcfdsf_inst_code,
{trt_course_cd},
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# データ削除用SQL(COM_施設診療科目)
PHYSICAL_DELETE_TRT_QUERY = """\
DELETE FROM
src05.com_inst_trt_course
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
"""
# レコード存在確認SQL(COM_特養医務室)
RECORD_EXISTS_SPCARE_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_spcare_med_office_dat
WHERE
dcf_chld_inst_cd = :dcfdsf_inst_code
"""
# データ更新用SQL(COM_特養医務室)
UPDATE_SPCARE_QUERY = """\
UPDATE
src05.com_spcare_med_office_dat
SET
dcf_prnt_inst_cd = :dcf_prnt_inst_code,
update_ymd = :execute_date_str_ymd,
delete_ymd = :delete_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
dcf_chld_inst_cd = :dcfdsf_inst_code
"""
# データ登録用SQL(COM_特養医務室)
INSERT_SPCARE_QUERY = """\
INSERT INTO src05.com_spcare_med_office_dat
(
dcf_chld_inst_cd,
dcf_prnt_inst_cd,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:dcfdsf_inst_code,
:dcf_prnt_inst_code,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
record: ComInst
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComInst)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.__make_upsert_query()
return
def __make_upsert_query(self):
# レコードの存在確認(施設)
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 「@」による項目クリアを設定
self.__set_clearing_item()
if record_count[0]['count_num'] == 0:
# 存在しない場合はInsert
self.queries.append(self.INSERT_INST_QUERY)
else:
# 存在する場合はUpdate(施設)
self.__make_update_query()
# 施設診療科目の削除挿入
self.__make_delete_insert_trt_query()
# 特養医務室の追加更新
self.__make_upsert_spcare_query()
return
def __make_update_query(self):
# 存在する場合はUpdate(施設)
set_clauses = [] # 設定項目
# 施設区分コード
if len(self.record.hp_class_code) > 0:
set_clauses.append('inst_div_cd = :hp_class_code')
# 正式施設名(カナ)
if len(self.record.hp_name_kana) > 0:
set_clauses.append('form_inst_name_kana = :hp_name_kana')
# 略式施設名(カナ)
if len(self.record.hp_ryaku_name_kana) > 0:
set_clauses.append('inst_name_kana = :hp_ryaku_name_kana')
# 正式施設名(漢字)
if len(self.record.hp_name) > 0:
set_clauses.append('form_inst_name_kanji = :hp_name')
# 略式施設名(漢字)
if len(self.record.hp_ryaku_name) > 0:
set_clauses.append('inst_name_kanji = :hp_ryaku_name')
# 施設住所カナ
if len(self.record.hp_addr_kana) > 0:
set_clauses.append('inst_addr_kana = :hp_addr_kana')
# 施設住所
if len(self.record.hp_addr) > 0:
set_clauses.append('inst_addr = :hp_addr')
# 郵便番号
if len(self.record.hp_zip_code) > 0:
set_clauses.append('postal_number = :hp_zip_code')
# 町字コード・都道府県コード・市区町村コード
if len(self.record.village_code + self.record.pref_code + self.record.city_code) > 0:
set_clauses.append('village_cd = :village_code')
set_clauses.append('prefc_cd = :pref_code')
set_clauses.append('city_cd = :city_code')
# 住所カウント
if len(self.record.pref_code) > 0:
set_clauses.append('addr_cnt_kana = :addr_cnt_kana')
set_clauses.append('addr_cnt = :addr_cnt')
# 住所表示番号
if len(self.record.hp_addr_number) > 0:
set_clauses.append('addr_display_number = :hp_addr_number')
# 経営体コード
if len(self.record.mgt_class_code) > 0:
set_clauses.append('manage_cd = :mgt_class_code')
# 病院種別
if len(self.record.hp_kind_code) > 0:
set_clauses.append('hp_assrt_cd = :hp_kind_code')
# 再審査コード
if len(self.record.reexam_flag) > 0:
set_clauses.append('re_exam_cd = :reexam_flag')
# 未確認フラグ
if len(self.record.uncheck_flag) > 0:
set_clauses.append('unconf_flg = :uncheck_flag')
# 削除予定理由コード
if len(self.record.hpdel_code) > 0:
set_clauses.append('delete_sche_reason_cd = :hpdel_code')
# 重複時相手先コード
if len(self.record.dup_opp_code) > 0:
set_clauses.append('dup_opp_cd = :dup_opp_code')
# 住所不明理由コード
if len(self.record.hp_addr_lost_code) > 0:
set_clauses.append('addr_unknown_reason_cd = :hp_addr_lost_code')
# 電話番号なしフラグ
if len(self.record.tel_nothing_flag) > 0:
set_clauses.append('phone_number_non_flg = :tel_nothing_flag')
# 電話番号
if len(self.record.hp_tel) > 0:
set_clauses.append('inst_phone_number = :hp_tel')
# 施設代表者コード
if len(self.record.inst_repre_code) > 0:
set_clauses.append('inst_repre_cd = :inst_repre_code')
# 代表者(カナ)
if len(self.record.president_kana) > 0:
set_clauses.append('inst_repre_kana = :president_kana')
# 代表者(漢字) ※「@」が大文字
if len(self.record.president) > 0:
set_clauses.append('inst_repre = :president')
# 開業予定フラグ・開業予定年月
if len(self.record.open_flag + self.record.open_year_month) > 0:
set_clauses.append('estab_sche_flg = :open_flag')
set_clauses.append('estab_sche_ym = :open_year_month')
# 休院フラグ・休院開始年月
if len(self.record.close_flag + self.record.close_year_month) > 0:
set_clauses.append('close_flg = :close_flag')
set_clauses.append('close_start_ym = :close_year_month')
# 関連大学親コード
if len(self.record.univ_prnt_code) > 0:
set_clauses.append('rltd_univ_prnt_cd = :univ_prnt_code')
# 病棟閉鎖フラグ
if len(self.record.close_flag2) > 0:
set_clauses.append('ward_abolish_flg = :close_flag2')
# 病床数(定員)
if self.record.bed_num is not None:
set_clauses.append('bed_num = :bed_num')
# 許可病床メンテ日付
if len(self.record.bed_class_maint_date) > 0:
set_clauses.append('prmit_bed_maint_ymd = :bed_class_maint_date')
# 許可ベッド数(合計、精神、結核、感染、その他、一般病床、療養病床)
if not self.record.prmit_bed.count(None) == len(self.record.prmit_bed):
set_clauses.append('prmit_bed_num_sum = :bed_num_sum')
set_clauses.append('prmit_bed_num_mental = :bed_num_psy')
set_clauses.append('prmit_bed_num_tuber = :bed_num_tub')
set_clauses.append('prmit_bed_num_infection = :bed_num_epi')
set_clauses.append('prmit_bed_num_other = :bed_num_gen')
set_clauses.append('prmit_bed_num_gen = :bed_num_gen2')
set_clauses.append('prmit_bed_num_rcup = :bed_num_rest')
# 検査項目(微生物、血清、血液、病理、寄生虫、生化、RI)
if sum(len(item) for item in self.record.insp_item) > 0:
set_clauses.append('insp_item_micrb = :inspect_code1')
set_clauses.append('insp_item_serum = :inspect_code2')
set_clauses.append('insp_item_blood = :inspect_code3')
set_clauses.append('insp_item_patho = :inspect_code4')
set_clauses.append('insp_item_paras = :inspect_code5')
set_clauses.append('insp_item_biochem = :inspect_code6')
set_clauses.append('insp_item_ri = :inspect_code7')
update_columns = ','.join(set_clauses)
# 何も更新項目が無い場合は更新処理は行わない
if len(update_columns) == 0:
self.queries.append(None)
return
else:
update_columns += ','
update_query = self.UPDATE_INST_QUERY.format(
update_columns=update_columns
)
self.queries.append(update_query)
return
def __make_delete_insert_trt_query(self):
# 施設診療科目の削除挿入
# 診療科目(集合項目)のいずれも入力がない場合、何もしない
if sum(len(item) for item in self.record.medsbj_code) == 0:
return
# 削除
self.queries.append(self.PHYSICAL_DELETE_TRT_QUERY)
# 診療科目の1つ目の値がクリアマーク@)の場合、診療科目を登録しない
if self.record.medsbj_code[0] == "@":
return
# 診療科目160
for medsbj_code in self.record.medsbj_code:
if len(medsbj_code) > 0:
insert_query = self.INSERT_INST_TRT_QUERY.format(
trt_course_cd=f"'{medsbj_code}'"
)
self.queries.append(insert_query)
return
def __make_upsert_spcare_query(self):
# 特養医務室の追加、更新
# DCF親施設コードがない場合、何もしない
if (self.record.dcf_prnt_inst_code == "00" or len(self.record.dcf_prnt_inst_code) == 0):
return
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_SPCARE_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
# 特養医務室の集合項目の値がクリアマーク(@)の場合、登録しない
if self.record.dcfhp_92id == "@":
return
self.queries.append(self.INSERT_SPCARE_QUERY)
return
# 存在する場合はUpdate
# 特養医務室の集合項目の値がクリアマーク(@)の場合、DCF親施設コードをクリアし、削除日を設定
if self.record.dcfhp_92id == "@":
self.query_parameter['dcf_prnt_inst_code'] = None
self.query_parameter['delete_ymd'] = self.query_parameter['execute_date_str_ymd']
else:
self.query_parameter['delete_ymd'] = None
self.queries.append(self.UPDATE_SPCARE_QUERY)
return
def __set_clearing_item(self):
# 未確認フラグ
if self.record.uncheck_flag == '@':
self.query_parameter['uncheck_flag'] = None
# 削除予定理由コード
if self.record.hpdel_code == '@':
self.query_parameter['hpdel_code'] = None
# 重複時相手先コード
if self.record.duphp_id == '@':
self.query_parameter['dup_opp_code'] = None
# 住所不明理由コード
if self.record.hp_addr_lost_code == '@':
self.query_parameter['hp_addr_lost_code'] = None
# 電話番号なしフラグ
if self.record.tel_nothing_flag == '@':
self.query_parameter['tel_nothing_flag'] = None
# 電話番号
if self.record.hp_tel == '@':
self.query_parameter['hp_tel'] = None
# 施設代表者コード
if self.record.president_id == '@':
self.query_parameter['inst_repre_code'] = None
# 代表者(カナ)
if self.record.president_kana == '@':
self.query_parameter['president_kana'] = None
# 代表者(漢字) ※全角文字のため、クリアマーク「@」が大文字
if self.record.president == '':
self.query_parameter['president'] = None
# 開業予定フラグ・開業予定年月
if self.record.open_flag == '@':
self.query_parameter['open_flag'] = None
self.query_parameter['open_year_month'] = None
# 休院フラグ・休院開始年月
if self.record.close_flag == '@':
self.query_parameter['close_flag'] = None
self.query_parameter['close_year_month'] = None
# 関連大学親コード
if self.record.assoc_parrent_id == '@':
self.query_parameter['univ_prnt_code'] = None
# 病棟閉鎖フラグ
if self.record.close_flag2 == '@':
self.query_parameter['close_flag2'] = None
# 病床数(定員)
if self.record.bed_num == '@':
self.query_parameter['bed_num'] = None
# 許可病床メンテ日付
if self.record.bed_class_maint_date == '@':
self.query_parameter['bed_class_maint_date'] = None
# 許可ベッド数(合計、精神、結核、感染、その他、一般病床、療養病床)
if self.record.bed_num_sum == '@':
self.query_parameter['bed_num_sum'] = None
self.query_parameter['bed_num_psy'] = None
self.query_parameter['bed_num_tub'] = None
self.query_parameter['bed_num_epi'] = None
self.query_parameter['bed_num_gen'] = None
self.query_parameter['bed_num_gen2'] = None
self.query_parameter['bed_num_rest'] = None
# 検査項目(微生物、血清、血液、病理、寄生虫、生化、RI)
if self.record.inspect_code1 == '@':
self.query_parameter['inspect_code1'] = None
self.query_parameter['inspect_code2'] = None
self.query_parameter['inspect_code3'] = None
self.query_parameter['inspect_code4'] = None
self.query_parameter['inspect_code5'] = None
self.query_parameter['inspect_code6'] = None
self.query_parameter['inspect_code7'] = None
return

View File

@ -0,0 +1,94 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_manage import ComManage
class ComManageMapper(UltmarcTableMapper):
"""レイアウト区分007: COM_経営体 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_manage
WHERE
manage_cd = :manage_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_manage
(
manage_cd,
manage_name,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:manage_cd,
:manage_name,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 更新用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_manage
SET
manage_name = :manage_name,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
manage_cd = :manage_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_manage
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
manage_cd = :manage_cd
"""
record: ComManage
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComManage)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,117 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_med_area_city import ComMedAreaCity
class ComMedAreaCityMapper(UltmarcTableMapper):
"""レイアウト区分124: COM_医療圏都道府県市町村対応表 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_med_area_city
WHERE
prefc_cd = :prefc_cd
AND
med_sphe_cd = :med_sphe_cd
AND
jis_prefc_cd = :jis_prefc_cd
AND
jis_city_cd = :jis_city_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_med_area_city
(
prefc_cd,
med_sphe_cd,
jis_prefc_cd,
jis_city_cd,
zen_prefcode,
zen_medareacode,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:prefc_cd,
:med_sphe_cd,
:jis_prefc_cd,
:jis_city_cd,
:zen_prefcode,
:zen_medareacode,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# データ更新用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_med_area_city
SET
zen_prefcode = :zen_prefcode,
zen_medareacode = :zen_medareacode,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
prefc_cd = :prefc_cd
AND
med_sphe_cd = :med_sphe_cd
AND
jis_prefc_cd = :jis_prefc_cd
AND
jis_city_cd = :jis_city_cd
"""
# 『修正区分がB(修正)かつ追加削除区分が1(退職)』の場合、物理削除
PHYSICAL_DELETE_QUERY = """\
DELETE FROM
src05.com_med_area_city
WHERE
prefc_cd = :prefc_cd
AND
med_sphe_cd = :med_sphe_cd
AND
jis_prefc_cd = :jis_prefc_cd
AND
jis_city_cd = :jis_city_cd
"""
record: ComMedAreaCity
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComMedAreaCity)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 『修正区分がB(修正)かつ追加削除区分が1(退職)』の場合、物理削除
if self.record.maintflag == 'B' and self.record.addDelDiv == '1':
self.queries.append(self.PHYSICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合はUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,97 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_med_func_valuation import ComMedFuncValuation
class ComMedFuncValuationMapper(UltmarcTableMapper):
"""レイアウト区分024: COM_医療機器評価 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_med_func_valuation
WHERE
med_func_valuation_cd = :med_func_valuation_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_med_func_valuation
(
med_func_valuation_cd,
med_func_valuation_name,
regist_ymd,
update_ymd,
delete_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:med_func_valuation_cd,
:med_func_valuation_name,
:execute_date_str_ymd,
:execute_date_str_ymd,
NULL,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
UPDATE_QUERY = """\
UPDATE
src05.com_med_func_valuation
SET
med_func_valuation_name = :med_func_valuation_name,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
med_func_valuation_cd = :med_func_valuation_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_med_func_valuation
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
med_func_valuation_cd = :med_func_valuation_cd
"""
record: ComMedFuncValuation
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComMedFuncValuation)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合はUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,129 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_med_prefc import ComMedPrefc
class ComMedPrefcMapper(UltmarcTableMapper):
"""レイアウト区分121: COM_医療圏都道府県 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_med_prefc
WHERE
pref_code = :pref_code
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_med_prefc
(
pref_code,
rev_date,
post_date,
psy_bednumtg,
psy_bednumgen,
psy_bednumdate,
psy_eqbednum,
tb_bednumtg,
tb_bednumgen,
tb_bednumdate,
tb_eqbednum,
inf_bednumtg,
inf_bednumgen,
inf_bednumdate,
inf_eqbednum,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:pref_code,
:rev_date,
:post_date,
:psy_bednum_tg,
:psy_bednum_gen,
:psy_bednum_date,
:psy_eqbed_num,
:tb_bednum_tg,
:tb_bednum_gen,
:tb_bednum_date,
:tb_eqbed_num,
:inf_bednum_tg,
:inf_bednum_gen,
:inf_bednum_date,
:inf_eqbed_num,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# データ更新用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_med_prefc
SET
rev_date = :rev_date,
post_date = :post_date,
psy_bednumtg = :psy_bednum_tg,
psy_bednumgen = :psy_bednum_gen,
psy_bednumdate = :psy_bednum_date,
psy_eqbednum = :psy_eqbed_num,
tb_bednumtg = :tb_bednum_tg,
tb_bednumgen = :tb_bednum_gen,
tb_bednumdate = :tb_bednum_date,
tb_eqbednum = :tb_eqbed_num,
inf_bednumtg = :inf_bednum_tg,
inf_bednumgen = :inf_bednum_gen,
inf_bednumdate = :inf_bednum_date,
inf_eqbednum = :inf_eqbed_num,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
pref_code = :pref_code
"""
# 修正区分が「C(削除)」の場合、物理削除
PHYSICAL_DELETE_QUERY = """\
DELETE FROM
src05.com_med_prefc
WHERE
pref_code = :pref_code
"""
record: ComMedPrefc
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComMedPrefc)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、物理削除
if self.record.maintflag == 'C':
self.queries.append(self.PHYSICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合はUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,95 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_nurse_assrt import ComNurseAssrt
class ComNurseAssrtMapper(UltmarcTableMapper):
"""レイアウト区分023: COM_看護種別 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_nurse_assrt
WHERE
nurse_assrt_cd = :nurse_assrt_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_nurse_assrt
(
nurse_assrt_cd,
nurse_assrt_name,
regist_ymd,
delete_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:nurse_assrt_cd,
:nurse_assrt_name,
:execute_date_str_ymd,
NULL,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 更新用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_nurse_assrt
SET
nurse_assrt_name = :nurse_assrt_name,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
nurse_assrt_cd = :nurse_assrt_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_nurse_assrt
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
nurse_assrt_cd = :nurse_assrt_cd
"""
record: ComNurseAssrt
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComNurseAssrt)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合はupdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,327 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_pharm import ComPharm
class ComPharmMapper(UltmarcTableMapper):
"""レイアウト区分102: COM_薬局 登録処理 """
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_pharm
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_pharm
(
dcf_dsf_inst_cd,
inst_div_cd,
addr_unknown_reason_cd,
form_inst_name_kana,
inst_name_kana,
form_inst_name_kanji,
inst_name_kanji,
close_flg,
estab_sche_flg,
close_start_ym,
estab_sche_ym,
inst_repre_kana,
inst_repre,
phone_number_non_flg,
unconf_flg,
inst_phone_number,
inst_addr_kana,
inst_addr,
postal_number,
village_cd,
prefc_cd,
city_cd,
addr_display_number,
addr_cnt_kana,
addr_cnt,
manage_cd,
delete_sche_reason_cd,
dup_opp_cd,
supervising_pharmacist,
supervising_pharmacist_kana,
franchise_hq_cd,
inst_pharm_div,
abolish_ymd,
delete_flg,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:dcfdsf_inst_cd,
:hpclass_code,
:hp_addr_lost_code,
:hp_name_kana,
:hp_ryaku_name_kana,
:hp_name,
:hp_ryaku_name,
:close_flg,
:open_flag,
:close_yearmonth,
:open_yearmonth,
:president_Kana,
:president,
:tel_nothing_flag,
:unconf_flg,
:tel_number,
:addr_kana,
:addr,
:zip_code,
:village_code,
:prefc_cd,
:city_cd,
:addr_number,
:addr_count_kana,
:addr_count,
:mgtclass_code,
:del_cd,
:dup_opp_cd,
:pharmacist,
:pharmacist_kana,
:franchise_hq_cd,
2,
NULL,
0,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 更新用SQL
UPDATE_QUERY = """\
UPDATE src05.com_pharm
SET
{update_columns}
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
# 廃業年月日 ← メンテナンス年月日
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_pharm
SET
abolish_ymd = :maintdate,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_cd
"""
record: ComPharm
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComPharm)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# 「@」による項目クリアを設定
self.__set_clearing_item()
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 更新の場合
update_columns = ','.join(self.__make_update_query())
# 何も更新項目が無い場合はNoneとする更新処理は行わない
if len(update_columns) == 0:
return None
else:
# 末尾にカンマを付けてSET句を完成させる
update_columns += ','
update_query = self.UPDATE_QUERY.format(
update_columns=update_columns
)
return update_query
def __make_update_query(self):
set_clauses = [] # 設定項目
# 設定項目の判定
# DCFDSF施設コード(主キーなので更新対象外)
# 施設区分コード
if self.record.hpclass_code != '':
set_clauses.append('inst_div_cd = :hpclass_code')
# 住所不明理由コード
if self.record.hp_addr_lost_code != '':
set_clauses.append('addr_unknown_reason_cd = :hp_addr_lost_code')
# 正式施設名カナ
if self.record.hp_name_kana != '':
set_clauses.append('form_inst_name_kana = :hp_name_kana')
# 施設名カナ
if self.record.hp_ryaku_name_kana != '':
set_clauses.append('inst_name_kana = :hp_ryaku_name_kana')
# 正式施設名(漢字)
if self.record.hp_name != '':
set_clauses.append('form_inst_name_kanji = :hp_name')
# 施設名(漢字)
if self.record.hp_ryaku_name != '':
set_clauses.append('inst_name_kanji = :hp_ryaku_name')
# 休院フラグ、休院予定年月
if len(self.record.close_flg + self.record.close_yearmonth) > 0:
set_clauses.append('close_flg = :close_flg')
set_clauses.append('close_start_ym = :close_yearmonth')
# 開業予定フラグ、開業予定年月
if len(self.record.open_flag + self.record.open_yearmonth) > 0:
set_clauses.append('estab_sche_flg = :open_flag')
set_clauses.append('estab_sche_ym = :open_yearmonth')
# 施設代表者カナ
if self.record.president_Kana != '':
set_clauses.append('inst_repre_kana = :president_Kana')
# 施設代表者
if self.record.president != '':
set_clauses.append('inst_repre = :president')
# 電話番号なしフラグ
if self.record.tel_nothing_flag != '':
set_clauses.append('phone_number_non_flg = :tel_nothing_flag')
# 未確認フラグ
if self.record.unconf_flg != '':
set_clauses.append('unconf_flg = :unconf_flg')
# 施設電話番号
if self.record.tel_number != '':
set_clauses.append('inst_phone_number = :tel_number')
# 施設住所カナ
if self.record.addr_kana != '':
set_clauses.append('inst_addr_kana = :addr_kana')
# 施設住所
if self.record.addr != '':
set_clauses.append('inst_addr = :addr')
# 郵便番号
if self.record.zip_code != '':
set_clauses.append('postal_number = :zip_code')
# 町字コード(住所コード)
if len(self.record.village_code) > 0:
set_clauses.append('village_cd = :village_code') # 住所コード
set_clauses.append('prefc_cd = :prefc_cd') # 都道府県コード
set_clauses.append('city_cd = :city_cd') # 市区町村コード
# 住所表示番号
if self.record.addr_number != '':
set_clauses.append('addr_display_number = :addr_number')
# 住所カウント(集合項目である県コードが入っていればカウントをセットする)
if len(self.record.prefc_cd) > 0:
set_clauses.append('addr_cnt = :addr_count') # 住所カウント
set_clauses.append('addr_cnt_kana = :addr_count_kana') # 住所カウントカナ
# 経営体コード
if self.record.mgtclass_code != '':
set_clauses.append('manage_cd = :mgtclass_code')
# 削除予定理由コード
if self.record.del_cd != '':
set_clauses.append('delete_sche_reason_cd = :del_cd')
# 重複時相手先コード
if self.record.dup_opp_cd != '':
set_clauses.append('dup_opp_cd = :dup_opp_cd')
# 管理薬剤師名(漢字)※@が大文字
if self.record.pharmacist != '':
set_clauses.append('supervising_pharmacist = :pharmacist')
# 管理薬剤師名(カナ)
if self.record.pharmacist_kana != '':
set_clauses.append('supervising_pharmacist_kana = :pharmacist_kana')
# チェーン店本部コード
if self.record.franchise_hq_id != '':
set_clauses.append('franchise_hq_cd = :franchise_hq_cd')
return set_clauses
def __set_clearing_item(self):
# 住所不明理由コード
if self.record.hp_addr_lost_code == '@':
self.query_parameter['hp_addr_lost_code'] = None
# 休院フラグ、休院予定年月
if self.record.close_flg == '@':
self.query_parameter['close_flg'] = None
self.query_parameter['close_yearmonth'] = None
# 開業予定フラグ、開業予定年月
if self.record.open_flag == '@':
self.query_parameter['open_flag'] = None
self.query_parameter['open_yearmonth'] = None
# 施設代表者カナ
if self.record.president_Kana == '@':
self.query_parameter['president_Kana'] = None
# 施設代表者 ※@が大文字
if self.record.president == '':
self.query_parameter['president'] = None
# 電話番号なしフラグ
if self.record.tel_nothing_flag == '@':
self.query_parameter['tel_nothing_flag'] = None
# 未確認フラグ
if self.record.unconf_flg == '@':
self.query_parameter['unconf_flg'] = None
# 施設電話番号
if self.record.tel_number == '@':
self.query_parameter['tel_number'] = None
# 住所表示番号
if self.record.addr_number == '@':
self.query_parameter['addr_number'] = None
# 削除予定理由コード
if self.record.del_cd == '@':
self.query_parameter['del_cd'] = None
# 重複時相手先コード
if self.record.duphp_id == '@':
self.query_parameter['dup_opp_cd'] = None
# 管理薬剤師名(漢字) ※@が大文字
if self.record.pharmacist == '':
self.query_parameter['pharmacist'] = None
# 管理薬剤師名(カナ)
if self.record.pharmacist_kana == '@':
self.query_parameter['pharmacist_kana'] = None
# チェーン店本部コード
if self.record.franchise_hq_id == '@':
self.query_parameter['franchise_hq_cd'] = None
return

View File

@ -0,0 +1,96 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_policy_med import ComPolicyMed
class ComPolicyMedMapper(UltmarcTableMapper):
"""レイアウト区分028: COM_政策医療 登録処理 """
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_policy_med
WHERE
policy_med_cd = :policy_med_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_policy_med
(
policy_med_cd,
field_name,
regist_ymd,
delete_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:policy_med_cd,
:field_name,
:execute_date_str_ymd,
NULL,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 更新用SQL
UPDATE_QUERY = """\
UPDATE src05.com_policy_med
SET
field_name = :field_name,
update_ymd = :execute_date_str_ymd,
delete_ymd = NULL,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
policy_med_cd = :policy_med_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
# 削除年月日 ← システム日付
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_policy_med
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
policy_med_cd = :policy_med_cd
"""
record: ComPolicyMed
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComPolicyMed)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合はUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,92 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_post import ComPost
class ComPostMapper(UltmarcTableMapper):
"""レイアウト区分005: COM_役職 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_post
WHERE
post_cd = :post_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_post
(
post_cd,
form_post_name,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:post_cd,
:form_post_name,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
UPDATE_QUERY = """\
UPDATE
src05.com_post
SET
form_post_name = :form_post_name,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
post_cd = :post_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_post
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
post_cd = :post_cd
"""
record: ComPost
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComPost)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,489 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_prefc_med_base import \
ComPrefcMedBase
class ComPrefcMedBaseMapper(UltmarcTableMapper):
"""レイアウト区分132: COM_都道府県医療機能情報(基本)"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_prefc_med_base
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_prefc_med_base
(
dcf_dsf_inst_cd,
info_date,
home_page,
hppre_flg,
expre_flg,
trial_flg,
trial_contcount,
trialwhet_from,
trialwhet_to,
equipment_flg,
cos_disease_flg,
cos_surgery,
specialclinic_flg,
establishment_flg,
critical_flg,
cop_system,
sys_exists_flg,
sys_inspection,
sys_prescription,
sys_reserv,
icduse_flg,
echart_flg,
fulltime_flg,
fulltime_count,
ge_patient_avg,
mt_patient_avg,
mc_patient_avg,
ca_patient_avg,
pys_patient_avg,
tub_patient_avg,
inf_patient_avg,
patient_avg_sum,
patient_avg_from,
patient_avg_to,
cl_patient_avg,
cl_patient_avg_from,
cl_patient_avg_to,
hm_patient_avg,
hm_patient_avg_from,
hm_patient_avg_to,
ge_patient_ex,
mt_patient_ex,
mc_patient_ex,
ca_patient_ex,
pys_patient_ex,
tub_patient_ex,
inf_patient_ex,
patient_ex_sum,
patient_ex_from,
patient_ex_to,
cl_patient_ex,
cl_patient_ex_from,
cl_patient_ex_to,
hm_patient_ex,
hm_patient_ex_from,
hm_patient_ex_to,
ge_stay_avg,
mt_stay_avg,
mc_stay_avg,
ca_stay_avg,
pys_stay_avg,
tub_stay_avg,
inf_stay_avg,
stay_avg_sum,
stay_avg_from,
stay_avg_to,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:dcfdsf_inst_code,
:info_date,
:home_page,
:hppre_flg,
:expre_flg,
:trial_flg,
:trial_cont_count,
:trial_whet_from,
:trial_whet_to,
:equipment_flg,
:cos_disease_flg,
:cos_surgery,
:specialclinic_flg,
:establishment_flg,
:critical_flg,
:cop_system,
:sys_exists_flg,
:sys_inspection,
:sys_prescription,
:sys_reserv,
:icduse_flg,
:echart_flg,
:fulltime_flg,
:fulltime_count,
:ge_patient_avg,
:mt_patient_avg,
:mc_patient_avg,
:ca_patient_avg,
:pys_patient_avg,
:tub_patient_avg,
:inf_patient_avg,
:patient_avg_sum,
:patient_avg_from,
:patient_avg_to,
:cl_patient_avg,
:cl_patient_avg_from,
:cl_patient_avg_to,
:hm_patient_avg,
:hm_patient_avg_from,
:hm_patient_avg_to,
:ge_patient_ex,
:mt_patient_ex,
:mc_patient_ex,
:ca_patient_ex,
:pys_patient_ex,
:tub_patient_ex,
:inf_patient_ex,
:patient_ex_sum,
:patient_ex_from,
:patient_ex_to,
:cl_patient_ex,
:cl_patient_ex_from,
:cl_patient_ex_to,
:hm_patient_ex,
:hm_patient_ex_from,
:hm_patient_ex_to,
:ge_stay_avg,
:mt_stay_avg,
:mc_stay_avg,
:ca_stay_avg,
:pys_stay_avg,
:tub_stay_avg,
:inf_stay_avg,
:stay_avg_sum,
:stay_avg_from,
:stay_avg_to,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# データ変更用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_prefc_med_base
SET
{update_columns}
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
"""
# 『修正区分がB(修正)かつ追加削除区分が1(退職)』の場合、物理削除
PHYSICAL_DELETE_QUERY = """\
DELETE FROM
src05.com_prefc_med_base
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
"""
record: ComPrefcMedBase
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComPrefcMedBase)
program_name = __name__.split(".")[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter["program_name"] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {
**self.query_parameter,
**self.record.to_sql_parameter(),
}
def make_query(self):
# 『修正区分がB(修正)かつ追加削除区分が1(退職)』の場合、物理削除
if self.record.maint_flag == "B" and self.record.adddel_div == "1":
self.queries.append(self.PHYSICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# 「@」による項目クリアを設定
self.__set_clearing_item()
# レコードの存在確認
record_count = self.db.execute_select(
self.RECORD_EXISTS_QUERY, self.query_parameter
)
# 存在しない場合はInsert
if record_count[0]["count_num"] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
return self.__make_update_query()
def __make_update_query(self):
set_clauses = [] # 設定項目
# 情報年月日
if len(self.record.info_date) > 0:
set_clauses.append("info_date = :info_date")
# 案内用ホームページアドレス
if len(self.record.home_page) > 0:
set_clauses.append("home_page = :home_page")
# 院内処方フラグ
if len(self.record.hppre_flg) > 0:
set_clauses.append("hppre_flg = :hppre_flg")
# 院外処方フラグ
if len(self.record.expre_flg) > 0:
set_clauses.append("expre_flg = :expre_flg")
# 治験の実施
if len(self.record.trial_flg) > 0:
set_clauses.append("trial_flg = :trial_flg")
set_clauses.append("trial_contcount = :trial_cont_count")
set_clauses.append("trialwhet_from = :trial_whet_from")
set_clauses.append("trialwhet_to = :trial_whet_to")
# 保有する施設設備フラグ
if len(self.record.equipment_flg) > 0:
set_clauses.append("equipment_flg = :equipment_flg")
# 対応することができる疾患・治療の内容フラグ
if len(self.record.cos_disease_flg) > 0:
set_clauses.append("cos_disease_flg = :cos_disease_flg")
# 対応することができる短期滞在手術フラグ
if len(self.record.cos_surgery) > 0:
set_clauses.append("cos_surgery = :cos_surgery")
# 専門外来フラグ
if len(self.record.specialclinic_flg) > 0:
set_clauses.append("specialclinic_flg = :specialclinic_flg")
# 地域医療連携体制_窓口設置フラグ
if len(self.record.establishment_flg) > 0:
set_clauses.append("establishment_flg = :establishment_flg")
# 地域医療連携体制_地域連携パスフラグ
if len(self.record.critical_flg) > 0:
set_clauses.append("critical_flg = :critical_flg")
# 入院診療計画策定時における院内の連携体制
if len(self.record.cop_system) > 0:
set_clauses.append("cop_system = :cop_system")
# オーダリングシステム
if len(self.record.sys_exists_flg) > 0:
set_clauses.append("sys_exists_flg = :sys_exists_flg")
set_clauses.append("sys_inspection = :sys_inspection")
set_clauses.append("sys_prescription = :sys_prescription")
set_clauses.append("sys_reserv = :sys_reserv")
# ICDコード利用フラグ
if len(self.record.icduse_flg) > 0:
set_clauses.append("icduse_flg = :icduse_flg")
# 電子カルテフラク
if len(self.record.echart_flg) > 0:
set_clauses.append("echart_flg = :echart_flg")
# 専任従事者
if len(self.record.fulltime_flg) > 0:
set_clauses.append("fulltime_flg = :fulltime_flg")
set_clauses.append("fulltime_count = :fulltime_count")
# 病床患者数平均
if len(self.record.ge_patient_avg) > 0:
set_clauses.append("ge_patient_avg = :ge_patient_avg")
set_clauses.append("mt_patient_avg = :mt_patient_avg")
set_clauses.append("mc_patient_avg = :mc_patient_avg")
set_clauses.append("ca_patient_avg = :ca_patient_avg")
set_clauses.append("pys_patient_avg = :pys_patient_avg")
set_clauses.append("tub_patient_avg = :inf_patient_avg")
set_clauses.append("inf_patient_avg = :tub_patient_avg")
set_clauses.append("patient_avg_sum = :patient_avg_sum")
set_clauses.append("patient_avg_from = :patient_avg_from")
set_clauses.append("patient_avg_to = :patient_avg_to")
# 患者数平均
if len(self.record.cl_patient_avg) > 0:
set_clauses.append("cl_patient_avg = :cl_patient_avg")
set_clauses.append("cl_patient_avg_from = :cl_patient_avg_from")
set_clauses.append("cl_patient_avg_to = :cl_patient_avg_to")
# 患者数平均
if len(self.record.hm_patient_avg) > 0:
set_clauses.append("hm_patient_avg = :hm_patient_avg")
set_clauses.append("hm_patient_avg_from = :hm_patient_avg_from")
set_clauses.append("hm_patient_avg_to = :hm_patient_avg_to")
# 患者数延数
if len(self.record.ge_patient_ex) > 0:
set_clauses.append("ge_patient_ex = :ge_patient_ex")
set_clauses.append("mt_patient_ex = :mt_patient_ex")
set_clauses.append("mc_patient_ex = :mc_patient_ex")
set_clauses.append("ca_patient_ex = :ca_patient_ex")
set_clauses.append("pys_patient_ex = :pys_patient_ex")
set_clauses.append("tub_patient_ex = :tub_patient_ex")
set_clauses.append("inf_patient_ex = :inf_patient_ex")
set_clauses.append("patient_ex_sum = :patient_ex_sum")
set_clauses.append("patient_ex_from = :patient_ex_from")
set_clauses.append("patient_ex_to = :patient_ex_to")
# 患者数延数
if len(self.record.cl_patient_ex) > 0:
set_clauses.append("cl_patient_ex = :cl_patient_ex")
set_clauses.append("cl_patient_ex_from = :cl_patient_ex_from")
set_clauses.append("cl_patient_ex_to = :cl_patient_ex_to")
# 患者数延数
if len(self.record.hm_patient_ex) > 0:
set_clauses.append("hm_patient_ex = :hm_patient_ex")
set_clauses.append("hm_patient_ex_from = :hm_patient_ex_from")
set_clauses.append("hm_patient_ex_to = :hm_patient_ex_to")
# 平均在院日数
if len(self.record.ge_stay_avg) > 0:
set_clauses.append("ge_stay_avg = :ge_stay_avg")
set_clauses.append("mt_stay_avg = :mt_stay_avg")
set_clauses.append("mc_stay_avg = :mc_stay_avg")
set_clauses.append("ca_stay_avg = :ca_stay_avg")
set_clauses.append("pys_stay_avg = :pys_stay_avg")
set_clauses.append("tub_stay_avg = :tub_stay_avg")
set_clauses.append("inf_stay_avg = :inf_stay_avg")
set_clauses.append("stay_avg_sum = :stay_avg_sum")
set_clauses.append("stay_avg_from = :stay_avg_from")
set_clauses.append("stay_avg_to = :stay_avg_to")
update_columns = ",".join(set_clauses)
# 何も更新項目が無い場合はNoneとする更新処理は行わない
if len(update_columns) == 0:
return None
else:
# 末尾にカンマを付けてSET句を完成させる
update_columns += ","
update_query = self.UPDATE_QUERY.format(update_columns=update_columns)
return update_query
def __set_clearing_item(self):
# 情報年月日
if self.record.info_date == "@":
self.query_parameter["info_date"] = None
# 案内用ホームページアドレス
if self.record.home_page == "@":
self.query_parameter["home_page"] = None
# 院内処方フラグ
if self.record.hppre_flg == "@":
self.query_parameter["hppre_flg"] = None
# 院外処方フラグ
if self.record.expre_flg == "@":
self.query_parameter["expre_flg"] = None
# 治験の実施
if self.record.trial_flg == "@":
self.query_parameter["trial_flg"] = None
self.query_parameter["trial_cont_count"] = None
self.query_parameter["trial_whet_from"] = None
self.query_parameter["trial_whet_to"] = None
# 保有する施設設備フラグ
if self.record.equipment_flg == "@":
self.query_parameter["equipment_flg"] = None
# 対応することができる疾患・治療の内容フラグ
if self.record.cos_disease_flg == "@":
self.query_parameter["cos_disease_flg"] = None
# 対応することができる短期滞在手術フラグ
if self.record.cos_surgery == "@":
self.query_parameter["cos_surgery"] = None
# 専門外来フラグ
if self.record.specialclinic_flg == "@":
self.query_parameter["specialclinic_flg"] = None
# 地域医療連携体制_窓口設置フラグ
if self.record.establishment_flg == "@":
self.query_parameter["establishment_flg"] = None
# 地域医療連携体制_地域連携パスフラグ
if self.record.critical_flg == "@":
self.query_parameter["critical_flg"] = None
# 入院診療計画策定時における院内の連携体制
if self.record.cop_system == "@":
self.query_parameter["cop_system"] = None
# オーダリングシステム
if self.record.sys_exists_flg == "@":
self.query_parameter["sys_exists_flg"] = None
self.query_parameter["sys_inspection"] = None
self.query_parameter["sys_prescription"] = None
self.query_parameter["sys_reserv"] = None
# ICDコード利用フラグ
if self.record.icduse_flg == "@":
self.query_parameter["icduse_flg"] = None
# 電子カルテフラク
if self.record.echart_flg == "@":
self.query_parameter["echart_flg"] = None
# 専任従事者
if self.record.fulltime_flg == "@":
self.query_parameter["fulltime_flg"] = None
self.query_parameter["fulltime_count"] = None
# 病床患者数平均
if self.record.ge_patient_avg == "@":
self.query_parameter["ge_patient_avg"] = None
self.query_parameter["mt_patient_avg"] = None
self.query_parameter["mc_patient_avg"] = None
self.query_parameter["ca_patient_avg"] = None
self.query_parameter["pys_patient_avg"] = None
self.query_parameter["inf_patient_avg"] = None
self.query_parameter["tub_patient_avg"] = None
self.query_parameter["patient_avg_sum"] = None
self.query_parameter["patient_avg_from"] = None
self.query_parameter["patient_avg_to"] = None
# 患者数平均
if self.record.cl_patient_avg == "@":
self.query_parameter["cl_patient_avg"] = None
self.query_parameter["cl_patient_avg_from"] = None
self.query_parameter["cl_patient_avg_to"] = None
# 患者数平均
if self.record.hm_patient_avg == "@":
self.query_parameter["hm_patient_avg"] = None
self.query_parameter["hm_patient_avg_from"] = None
self.query_parameter["hm_patient_avg_to"] = None
# 患者数延数
if self.record.ge_patient_ex == "@":
self.query_parameter["ge_patient_ex"] = None
self.query_parameter["mt_patient_ex"] = None
self.query_parameter["mc_patient_ex"] = None
self.query_parameter["ca_patient_ex"] = None
self.query_parameter["pys_patient_ex"] = None
self.query_parameter["tub_patient_ex"] = None
self.query_parameter["inf_patient_ex"] = None
self.query_parameter["patient_ex_sum"] = None
self.query_parameter["patient_ex_from"] = None
self.query_parameter["patient_ex_to"] = None
# 患者数延数
if self.record.cl_patient_ex == "@":
self.query_parameter["cl_patient_ex"] = None
self.query_parameter["cl_patient_ex_from"] = None
self.query_parameter["cl_patient_ex_to"] = None
# 患者数延数
if self.record.hm_patient_ex == "@":
self.query_parameter["hm_patient_ex"] = None
self.query_parameter["hm_patient_ex_from"] = None
self.query_parameter["hm_patient_ex_to"] = None
# 平均在院日数
if self.record.ge_stay_avg == "@":
self.query_parameter["ge_stay_avg"] = None
self.query_parameter["mt_stay_avg"] = None
self.query_parameter["mc_stay_avg"] = None
self.query_parameter["ca_stay_avg"] = None
self.query_parameter["pys_stay_avg"] = None
self.query_parameter["tub_stay_avg"] = None
self.query_parameter["inf_stay_avg"] = None
self.query_parameter["stay_avg_sum"] = None
self.query_parameter["stay_avg_from"] = None
self.query_parameter["stay_avg_to"] = None
return

View File

@ -0,0 +1,106 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_prefc_med_dis_treat import \
ComPrefcMedDisTreat
class ComPrefcMedDisTreatMapper(UltmarcTableMapper):
"""レイアウト区分134: COM_都道府県医療機能情報(疾患治療)"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_prefc_med_dis_treat
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
treatment_code = :treatment_code
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_prefc_med_dis_treat
(
dcf_dsf_inst_cd,
treatment_code,
pre_num,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:dcfdsf_inst_code,
:treatment_code,
:pre_num,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# データ変更用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_prefc_med_dis_treat
SET
pre_num = :pre_num,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
treatment_code = :treatment_code
"""
# 『修正区分がB(修正)かつ追加削除区分が1(退職)』の場合、物理削除
PHYSICAL_DELETE_QUERY = """\
DELETE FROM
src05.com_prefc_med_dis_treat
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
treatment_code = :treatment_code
"""
record: ComPrefcMedDisTreat
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComPrefcMedDisTreat)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 『修正区分がB(修正)かつ追加削除区分が1(退職)』の場合、物理削除
if self.record.maint_flag == 'B' and self.record.adddel_div == '1':
self.queries.append(self.PHYSICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# 修正のレコードだった場合はNULLに変換する
if self.record.pre_num == '@':
self.query_parameter['pre_num'] = None
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合はUpdate
if self.record.is_pre_num_not_empty:
return self.UPDATE_QUERY
else:
return None

View File

@ -0,0 +1,107 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_prefc_med_equpment import \
ComPrefcMedEqupment
class ComPrefcMedEqupmentMapper(UltmarcTableMapper):
"""レイアウト区分133: COM_都道府県医療機能情報(施設設備)"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_prefc_med_equpment
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
equipment_code = :equipment_code
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_prefc_med_equpment
(
dcf_dsf_inst_cd,
equipment_code,
bednum,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:dcfdsf_inst_code,
:equipment_code,
:bed_num,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# データ変更用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_prefc_med_equpment
SET
bednum = :bed_num,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
equipment_code = :equipment_code
"""
# 『修正区分がB(修正)かつ追加削除区分が1(退職)』の場合、物理削除
PHYSICAL_DELETE_QUERY = """\
DELETE FROM
src05.com_prefc_med_equpment
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
equipment_code = :equipment_code
"""
record: ComPrefcMedEqupment
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComPrefcMedEqupment)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 『修正区分がB(修正)かつ追加削除区分が1(退職)』の場合、物理削除
if self.record.maint_flag == 'B' and self.record.adddel_div == '1':
self.queries.append(self.PHYSICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# 修正のレコードだった場合はNULLに変換する
if self.record.bed_num == '@':
self.query_parameter['bed_num'] = None
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合はUpdate
# 病床数が空の場合は更新しない
if self.record.is_bed_num_not_empty:
return self.UPDATE_QUERY
else:
return None

View File

@ -0,0 +1,95 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_prefc_med_sojourn_ope import ComPrefcMedSojournOpe
class ComPrefcMedSojournOpeMapper(UltmarcTableMapper):
"""レイアウト区分135: COM_都道府県医療機能情報(短期滞在手術)"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_prefc_med_sojourn_ope
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
cos_surgery_code = :cos_surgery_code
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_prefc_med_sojourn_ope
(
dcf_dsf_inst_cd,
cos_surgery_code,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:dcfdsf_inst_code,
:cos_surgery_code,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# データ変更用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_prefc_med_sojourn_ope
SET
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
cos_surgery_code = :cos_surgery_code
"""
# 『修正区分がB(修正)かつ追加削除区分が1(退職)』の場合、物理削除
PHYSICAL_DELETE_QUERY = """\
DELETE FROM
src05.com_prefc_med_sojourn_ope
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
cos_surgery_code = :cos_surgery_code
"""
record: ComPrefcMedSojournOpe
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComPrefcMedSojournOpe)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 『修正区分がB(修正)かつ追加削除区分が1(退職)』の場合、物理削除
if self.record.maint_flag == 'B' and self.record.adddel_div == '1':
self.queries.append(self.PHYSICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合はUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,133 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import (
UltmarcTableMapper,
)
from src.batch.ultmarc.utmp_tables.tables.com_prefc_med_sp_outpat import (
ComPrefcMedSpOutpat,
)
class ComPrefcMedSpOutpatMapper(UltmarcTableMapper):
"""レイアウト区分136: COM_都道府県医療機能情報(専門外来)"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_prefc_med_sp_outpat
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
specialclinic_name = :specialclinic_name
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_prefc_med_sp_outpat
(
dcf_dsf_inst_cd,
specialclinic_name,
sort_key,
sectsub_cd,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:dcfdsf_inst_code,
:specialclinic_name,
:sort_key,
:sectsub_cd,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# データ変更用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_prefc_med_sp_outpat
SET
{update_columns}
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
specialclinic_name = :specialclinic_name
"""
# 『修正区分がB(修正)かつ追加削除区分が1(退職)』の場合、物理削除
PHYSICAL_DELETE_QUERY = """\
DELETE FROM
src05.com_prefc_med_sp_outpat
WHERE
dcf_dsf_inst_cd = :dcfdsf_inst_code
AND
specialclinic_name = :specialclinic_name
"""
record: ComPrefcMedSpOutpat
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComPrefcMedSpOutpat)
program_name = __name__.split(".")[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter["program_name"] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {
**self.query_parameter,
**self.record.to_sql_parameter(),
}
def make_query(self):
# 『修正区分がB(修正)かつ追加削除区分が1(退職)』の場合、物理削除
if self.record.maint_flag == "B" and self.record.adddel_div == "1":
self.queries.append(self.PHYSICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# 修正のレコードだった場合はNULLに変換する
if self.record.sectsub_cd == "@":
self.query_parameter["sectsub_cd"] = None
# レコードの存在確認
record_count = self.db.execute_select(
self.RECORD_EXISTS_QUERY, self.query_parameter
)
# 存在しない場合はInsert
if record_count[0]["count_num"] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
return self.__make_update_query()
def __make_update_query(self):
set_clauses = [] # 設定項目
# ソートキー
if len(self.record.sort_key) > 0:
set_clauses.append("sort_key = :sort_key")
# 分類補助コード
if len(self.record.sectsub_cd) > 0:
set_clauses.append("sectsub_cd = :sectsub_cd")
update_columns = ",".join(set_clauses)
# 何も更新項目が無い場合はNoneとする更新処理は行わない
if len(update_columns) == 0:
return None
else:
# 末尾にカンマを付けてSET句を完成させる
update_columns += ","
update_query = self.UPDATE_QUERY.format(update_columns=update_columns)
return update_query

View File

@ -0,0 +1,95 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_regn_critic_pass import ComRegnCriticPass
class ComRegnCriticPassMapper(UltmarcTableMapper):
"""レイアウト区分026: COM_地域クリティカルパス 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_regn_critic_pass
WHERE
regn_co_critic_pass_cd = :regn_co_critic_pass_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_regn_critic_pass
(
regn_co_critic_pass_cd,
disease_name_kanji,
regist_ymd,
delete_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:regn_co_critic_pass_cd,
:disease_name_kanji,
:execute_date_str_ymd,
NULL,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 更新用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_regn_critic_pass
SET
disease_name_kanji = :disease_name_kanji,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
regn_co_critic_pass_cd = :regn_co_critic_pass_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_regn_critic_pass
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
regn_co_critic_pass_cd = :regn_co_critic_pass_cd
"""
record: ComRegnCriticPass
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComRegnCriticPass)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合はUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,94 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_rehabili import ComRehabili
class ComRehabiliMapper(UltmarcTableMapper):
"""レイアウト区分027: COM_疾患別リハビリテーション科 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_rehabili
WHERE
rehabili_cd = :rehabili_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_rehabili
(
rehabili_cd,
rehabili_name,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:rehabili_cd,
:rehabili_name,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 更新用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_rehabili
SET
rehabili_name = :rehabili_name,
update_ymd = :execute_date_str_ymd,
delete_ymd = NULL,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
rehabili_cd = :rehabili_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_rehabili
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
rehabili_cd = :rehabili_cd
"""
record: ComRehabili
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComRehabili)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合はUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,113 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_snd_med_sphe import ComSndMedSphe
class ComSndMedSpheMapper(UltmarcTableMapper):
"""レイアウト区分123: COM_医療圏二次医療圏 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_snd_med_sphe
WHERE
prefc_cd = :prefc_cd
AND
med_sphe_cd = :med_sphe_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_snd_med_sphe
(
prefc_cd,
med_sphe_cd,
thrd_cd,
snd_med_sphe_name,
requd_bed_or_equip_target,
exist_bed_num,
exist_bed_num_regist_ymd,
plsmns_bed_num,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:prefc_cd,
:med_sphe_cd,
:thrd_cd,
:snd_med_sphe_name,
:requd_bed_or_equip_target,
:exist_bed_num,
:exist_bed_num_regist_ymd,
:plsmns_bed_num,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# データ更新用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_snd_med_sphe
SET
thrd_cd = :thrd_cd,
snd_med_sphe_name = :snd_med_sphe_name,
requd_bed_or_equip_target = :requd_bed_or_equip_target,
exist_bed_num = :exist_bed_num,
exist_bed_num_regist_ymd = :exist_bed_num_regist_ymd,
plsmns_bed_num = :plsmns_bed_num,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
prefc_cd = :prefc_cd
AND
med_sphe_cd = :med_sphe_cd
"""
# 修正区分が「C(削除)」の場合、物理削除
PHYSICAL_DELETE_QUERY = """\
DELETE FROM
src05.com_snd_med_sphe
WHERE
prefc_cd = :prefc_cd
AND
med_sphe_cd = :med_sphe_cd
"""
record: ComSndMedSphe
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComSndMedSphe)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、物理削除
if self.record.maintflag == 'C':
self.queries.append(self.PHYSICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合はUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,93 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_sosiety import ComSosiety
class ComSosietyMapper(UltmarcTableMapper):
"""レイアウト区分009: COM_学会 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_sosiety
WHERE
sosiety_cd = :sosiety_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_sosiety
(
sosiety_cd,
sosiety_name,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:sosiety_cd,
:sosiety_name,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 変更用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_sosiety
SET
sosiety_name = :sosiety_name,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
sosiety_cd = :sosiety_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_sosiety
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
sosiety_cd = :sosiety_cd
"""
record: ComSosiety
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComSosiety)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,158 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_sp_field import ComSpField
class ComSpFieldMapper(UltmarcTableMapper):
"""レイアウト区分511: COM_専門分野 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_sp_field
WHERE
dcf_pcf_dr_cd = :dcf_pcf_dr_cd
and
specialist_cd = :specialist_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_sp_field
(
dcf_pcf_dr_cd,
specialist_cd,
specialist_maint_div,
specialist_flg,
specialist_publsh_ymd,
ackn_med_flg,
ackn_med_publsh_ymd,
guide_med_flg,
guide_med_publsh_ymd,
regist_ymd,
delete_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:dcf_pcf_dr_cd,
:specialist_cd,
:specialist_maint_div,
:specialist_flg,
:specialist_publsh_ymd,
:ackn_med_flg,
:ackn_med_publsh_ymd,
:guide_med_flg,
:guide_med_publsh_ymd,
:execute_date_str_ymd,
NULL,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
UPDATE_QUERY = """\
UPDATE
src05.com_sp_field
SET
{update_columns}
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
dcf_pcf_dr_cd = :dcf_pcf_dr_cd
and
specialist_cd = :specialist_cd
"""
# 『修正区分がB(修正)かつ専門医メンテナンス区分が1(退職)』の場合、物理削除
PHYSICAL_DELETE_QUERY = """\
DELETE FROM
src05.com_sp_field
WHERE
dcf_pcf_dr_cd = :dcf_pcf_dr_cd
and
specialist_cd = :specialist_cd
"""
record: ComSpField
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComSpField)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 『修正区分がB(修正)かつ専門医メンテナンス区分が1(退職)』の場合、物理削除
if self.record.maint_flag == 'B' and self.record.specialist_maint_div == '1':
self.queries.append(self.PHYSICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
set_clauses = [] # 設定項目
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 「@」による項目クリアを設定
self.__set_clearing_item()
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
if len(self.record.specialist_maint_div) > 0:
set_clauses.append('specialist_maint_div = :specialist_maint_div')
if len(self.record.specialist_flg) > 0:
set_clauses.append('specialist_flg = :specialist_flg')
set_clauses.append('specialist_publsh_ymd = :specialist_publsh_ymd')
if len(self.record.ackn_med_flg) > 0:
set_clauses.append('ackn_med_flg = :ackn_med_flg')
set_clauses.append('ackn_med_publsh_ymd = :ackn_med_publsh_ymd')
if len(self.record.guide_med_flg) > 0:
set_clauses.append('guide_med_flg = :guide_med_flg')
set_clauses.append('guide_med_publsh_ymd = :guide_med_publsh_ymd')
update_columns = ','.join(set_clauses)
# 何も更新項目が無い場合はNoneとする更新処理は行わない
if len(update_columns) == 0:
return None
else:
# 末尾にカンマを付けてSET句を完成させる
update_columns += ','
update_query = self.UPDATE_QUERY.format(
update_columns=update_columns
)
return update_query
def __set_clearing_item(self):
# 専門医の集合項目クリア
if self.record.specialist_flg == '@':
self.query_parameter['specialist_flg'] = None
self.query_parameter['specialist_publsh_ymd'] = None
# 認定医の集合項目クリア
if self.record.ackn_med_flg == '@':
self.query_parameter['ackn_med_flg'] = None
self.query_parameter['ackn_med_publsh_ymd'] = None
# 指導医の集合項目クリア
if self.record.guide_med_flg == '@':
self.query_parameter['guide_med_flg'] = None
self.query_parameter['guide_med_publsh_ymd'] = None
return

View File

@ -0,0 +1,93 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_specialist_license import ComSpecialistLicense
class ComSpecialistLicenseMapper(UltmarcTableMapper):
"""レイアウト区分010: COM_専門医資格 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_specialist_license
WHERE
specialist_cd = :specialist_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_specialist_license
(
specialist_cd,
specialist_license_name,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:specialist_cd,
:specialist_license_name,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 変更用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_specialist_license
SET
specialist_license_name = :specialist_license_name,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
specialist_cd = :specialist_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_specialist_license
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
specialist_cd = :specialist_cd
"""
record: ComSpecialistLicense
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComSpecialistLicense)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,98 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_thrd_med import ComThrdMed
class ComThrdMedMapper(UltmarcTableMapper):
"""レイアウト区分122: COM_医療圏3次マスタ 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_thrd_med
WHERE
prefcode = :pref_code
AND
thrd_cd = :thrd_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_thrd_med
(
prefcode,
thrd_cd,
thrd_med_sphe_name,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:pref_code,
:thrd_cd,
:thrd_med_sphe_name,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# データ更新用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_thrd_med
SET
thrd_med_sphe_name = :thrd_med_sphe_name,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
prefcode = :pref_code
AND
thrd_cd = :thrd_cd
"""
# 修正区分が「C(削除)」の場合、物理削除
PHYSICAL_DELETE_QUERY = """\
DELETE FROM
src05.com_thrd_med
WHERE
prefcode = :pref_code
AND
thrd_cd = :thrd_cd
"""
record: ComThrdMed
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComThrdMed)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、物理削除
if self.record.maintflag == 'C':
self.queries.append(self.PHYSICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合はUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,99 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_trt_course import ComTrtCourse
class ComTrtCourseMapper(UltmarcTableMapper):
"""レイアウト区分001: COM_診療科目 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.com_trt_course
WHERE
trt_course_cd = :trt_course_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.com_trt_course
(
trt_course_cd,
trt_course_name_kana,
trt_course_name_abb,
trt_course_name,
regist_ymd,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:trt_course_cd,
:trt_course_name_kana,
:trt_course_name_abb,
:trt_course_name,
:execute_date_str_ymd,
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 更新用SQL
UPDATE_QUERY = """\
UPDATE
src05.com_trt_course
SET
trt_course_name_kana = :trt_course_name_kana,
trt_course_name_abb = :trt_course_name_abb,
trt_course_name = :trt_course_name,
update_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
trt_course_cd = :trt_course_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.com_trt_course
SET
delete_ymd = :execute_date_str_ymd,
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
trt_course_cd = :trt_course_cd
"""
record: ComTrtCourse
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, ComTrtCourse)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,96 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.mst_prefc import MstPrefc
class MstPrefcMapper(UltmarcTableMapper):
"""レイアウト区分006: 都道府県マスタ 登録処理"""
# レコード存在確認SQL
RECORD_EXISTS_QUERY = """\
SELECT
COUNT(*) AS count_num
FROM
src05.mst_prefc
WHERE
prefc_cd = :prefc_cd
"""
# データ登録用SQL
INSERT_QUERY = """\
INSERT INTO src05.mst_prefc
(
prefc_cd,
prefc_name,
prefc_name_kana,
delete_flg,
sys_regist_date,
regist_prgm_id,
sys_update_date,
update_prgm_id
)
VALUES (
:prefc_cd,
:prefc_name,
'',
'0',
:execute_datetime,
:program_name,
:execute_datetime,
:program_name
)
"""
# 更新用SQL
UPDATE_QUERY = """\
UPDATE
src05.mst_prefc
SET
prefc_name = :prefc_name,
delete_flg = '0',
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
prefc_cd = :prefc_cd
"""
# 修正区分が「C(削除)」の場合の更新SQL
LOGICAL_DELETE_QUERY = """\
UPDATE
src05.mst_prefc
SET
delete_flg = '1',
sys_update_date = :execute_datetime,
update_prgm_id = :program_name
WHERE
prefc_cd = :prefc_cd
"""
record: MstPrefc
def __init__(self, record: list[str], db) -> None:
super().__init__(record, db, MstPrefc)
program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている)
# モジュール名をクエリパラメータに設定
self.query_parameter['program_name'] = program_name
# 読み込んだレコード値もクエリパラメータに追加
self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}
def make_query(self):
# 修正区分がC(削除)の場合、論理削除
if self.record.maint_flag == 'C':
self.queries.append(self.LOGICAL_DELETE_QUERY)
return
# 追加、更新の場合
self.queries.append(self.__make_upsert_query())
return
def __make_upsert_query(self):
# レコードの存在確認
record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
# 存在しない場合はInsert
if record_count[0]['count_num'] == 0:
return self.INSERT_QUERY
# 存在する場合ではUpdate
return self.UPDATE_QUERY

View File

@ -0,0 +1,8 @@
from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
UltmarcTableMapper
class NullMapper(UltmarcTableMapper):
def make_query(self):
return super().make_query()

View File

@ -0,0 +1,50 @@
from abc import ABCMeta, abstractmethod
from datetime import datetime
from src.batch.common.batch_context import BatchContext
from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable
from src.db.database import Database
# 処理日を使用するために、configを使用
batch_context = BatchContext.get_instance()
class UltmarcTableMapper(metaclass=ABCMeta):
"""アルトマークテーブルへの登録処理の抽象クラス"""
record: UltmarcTable
db: Database
queries: list[str]
query_parameter: dict
def __init__(self, record: list[str], db: Database, table_class: type[UltmarcTable]) -> None:
self.record = table_class(record)
self.db = db
# 実行年月日(文字列)、実行年月日時分秒を設定
now = datetime.now()
execute_date_str_ymd = now.strftime('%Y%m%d')
execute_datetime = now.strftime('%Y/%m/%d %H:%M:%S')
# クエリリストを初期化
self.queries = []
# 共通クエリパラメータを設定
self.query_parameter = {
'execute_date_str_ymd': execute_date_str_ymd,
'execute_datetime': execute_datetime,
# バッチ共通設定から処理日を取得
'syor_date': batch_context.syor_date
}
@abstractmethod
def make_query(self):
pass
def execute_queries(self):
if len(self.queries) == 0:
raise Exception('make_queryを呼び出してから実行してください')
for query in self.queries:
if query is None:
continue
self.db.execute(query, self.query_parameter)

View File

@ -0,0 +1,14 @@
from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable
class ComAlma(UltmarcTable):
"""レイアウト区分004: COM_出身校"""
maint_flag: str # 修正区分
alma_cd: str # 出身校コード
alma: str # 出身校
def __init__(self, record: list[str]):
super().__init__(record)
self.maint_flag = record[2]
self.alma_cd = record[1]
self.alma = record[5]

View File

@ -0,0 +1,20 @@
from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable
class ComAlmaDepartDisc(UltmarcTable):
"""レイアウト区分003: COM_出身校学部識別"""
alma_cd: str # 出身校コード
depart_disc_cd: str # 学部識別コード
estab_e: str # 創立元号
estab_y: str # 創立年
alma_name: str # 出身校名
maint_flag: str # 修正区分
def __init__(self, record: list[str]):
super().__init__(record)
self.alma_cd = record[1]
self.depart_disc_cd = record[2]
self.maint_flag = record[3]
self.alma_name = record[6]
self.estab_e = record[7]
self.estab_y = record[8]

View File

@ -0,0 +1,22 @@
from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable
class ComBlngSec(UltmarcTable):
"""レイアウト区分008: COM_所属部科"""
blng_sec_cd: str # 所属部科コード
blng_sec_kana: str # 所属部科カナ
blng_sec_name: str # 所属部科名
inst_category: str # 分類補助コード(施設分類)
trt_category: str # 分類補助コード(診療分野分類)
category_sort: str # 分類補助コード(ソートコード)
maint_flag: str # 修正区分
def __init__(self, record: list[str]):
super().__init__(record)
self.blng_sec_cd = record[1]
self.maint_flag = record[2]
self.blng_sec_name = record[5]
self.blng_sec_kana = record[6]
self.inst_category = record[7]
self.trt_category = record[8]
self.category_sort = record[9]

View File

@ -0,0 +1,36 @@
from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable
class ComCopHp(UltmarcTable):
"""レイアウト区分112: COM_臨床研修病院"""
dcfhp_id: str # DCFコードレコードID
dcfhp_code: str # DCFコード施設コード
dcfhp_yobi: str # DCFコード予備
cophp_id: str # 協力型病院コードID
cophp_code: str # 協力型病院コード(コード)
cophp_yobi: str # 協力型病院コード(予備)
open_year: str # 開始年度
sort_key: str # ソートキー
adddel_div: str # 追加削除区分
maint_flag: str # 修正区分
dcfdsf_inst_code: str # DCFDSF施設コード
cophp_code: str # 協力型病院コード
def __init__(self, record: list[str]):
super().__init__(record)
self.dcfhp_id = record[1]
self.dcfhp_code = record[2]
self.dcfhp_yobi = record[3]
self.maint_flag = record[4]
self.cophp_id = record[5]
self.cophp_code = record[6]
self.cophp_yobi = record[7]
self.open_year = record[8]
self.adddel_div = record[9]
self.sort_key = record[12]
# DCFDSF施設コード
self.dcfdsf_inst_code = ''.join([self.dcfhp_id, self.dcfhp_code, self.dcfhp_yobi])
# 協力型病院コード
self.cophp_code = ''.join([self.cophp_id, self.cophp_code, self.cophp_yobi])

View File

@ -0,0 +1,183 @@
from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable
class ComDr(UltmarcTable):
"""レイアウト区分501: COM_医師"""
dcfdr_id: str # 個人コードレコードID
dcfdr_code: str # 個人コード(個人コード)
dcfd_yobi: str # 個人コード(予備)
maint_flag: str # 修正区分
maint_date: str # メンテナンス年月日
trn_date: str # 予備/転送年月日
drdel_code: str # 削除予定理由
reptdr_id: str # 重複時相手先コードレコードID
reptdr_code: str # 重複時相手先コード(個人コード)
reptdr_yobi: str # 重複時相手先コード(予備)
dr_name: str # 医師名(漢字)
dr_name_kana: str # 医師名(カナ)
sex_code: str # 性別
birthday_era: str # 生年月日(元号)
birthday_year: str # 生年月日(年)
birthday_month: str # 生年月日(月)
birthday_day: str # 生年月日(日)
home_town_code: str # 出身都道府県コード
medassoci_code: str # 医師会コード
grad_yearera: str # 卒年_元号
grad_year: str # 卒年_年
graduniv_code: str # 出身校コード
graduniv_dept_code: str # 出身校学部識別コード
drda_yera: str # 登録年_元号
drday_year: str # 登録年_年
medsbj_code1: str # 診療科目1
medsbj_code2: str # 診療科目2
medsbj_code3: str # 診療科目3
medsbj_code4: str # 診療科目4
medsbj_code5: str # 診療科目5
dr_addr_lost_code: str # 住所不明
pref_code: str # 住所コード(県コード)
city_code: str # 住所コード(市区町村コード)
addr_code1: str # 住所コード(大字・通称コード)
addr_code2: str # 住所コード(字・丁目コード)
dr_zip_code: str # 郵便番号
dr_addr: str # 自宅住所(漢字)
dr_addr_kana: str # 自宅住所(カナ)
dr_addr_num: str # 住所表示番号
dr_addr_kanj_cnt1: str # 住所カウント_漢字
dr_addr_kanj_cnt2: str # 住所カウント_漢字市区町村
dr_addr_kanj_cnt3: str # 住所カウント_漢字大字・通称
dr_addr_kanj_cnt4: str # 住所カウント_漢字字・丁目
dr_addr_kana_cnt1: str # 住所カウント_カナ
dr_addr_kana_cnt2: str # 住所カウント_カナ市区町村
dr_addr_kana_cnt3: str # 住所カウント_カナ大字・通称
dr_addr_kana_cnt4: str # 住所カウント_カナ字・丁目
dr_tel: str # 自宅電話番号
use_stop_flag: str # 利用停止区分
use_stopc_ode: str # 利用停止理由
cre_stop_date: str # 利用停止登録年月日
release_date: str # 利用停止解除年月日
pract_class_code: str # 開勤区分
pract_yearera: str # 開業年(元号)
pract_year: str # 開業年(年)
bskregst_flag: str # 一括登録フラグ
dcf_pcf_dr_cd: str # DCFPCF医師コード
addr_village_cd: str # 住所(町字)コード
addr_cnt_kana: str # 住所カウントカナ
addr_cnt: str # 住所カウント
opp_dup_code: str # 相手先重複コード
birth_day: str # 生年月日(西暦)
estab_y: str # 開業年(西暦)
grad_y: str # 卒業年(西暦)
drday_y: str # 登録年(西暦)
era_cd: str # 元号コード
# 住所(集合項目)
address_aggregation_items: list
# 診療科目(集合項目)
medsbj_code_items: list
def __init__(self, record: list[str]):
super().__init__(record)
self.dcfdr_id = record[1]
self.dcfdr_code = record[2]
self.dcfd_yobi = record[3].strip()
self.maint_flag = record[4]
self.maint_date = record[5]
self.trn_date = record[6]
self.drdel_code = record[7].strip()
self.reptdr_id = record[8].strip()
self.reptdr_code = record[9].strip()
self.reptdr_yobi = record[10].strip()
self.dr_name = record[11].strip()
self.dr_name_kana = record[12].strip()
self.sex_code = record[13].strip()
self.birthday_era = record[14].strip()
self.birthday_year = record[15].strip()
self.birthday_month = record[16].strip()
self.birthday_day = record[17].strip()
self.home_town_code = record[18].strip()
self.medassoci_code = record[19].strip()
self.grad_yearera = record[20].strip()
self.grad_year = record[21].strip()
self.graduniv_code = record[22].strip()
self.graduniv_dept_code = record[23].strip()
self.drda_yera = record[24].strip()
self.drday_year = record[25].strip()
self.medsbj_code1 = record[26].strip()
self.medsbj_code2 = record[27].strip()
self.medsbj_code3 = record[28].strip()
self.medsbj_code4 = record[29].strip()
self.medsbj_code5 = record[30].strip()
self.dr_addr_lost_code = record[31].strip()
self.pref_code = record[32].strip()
self.city_code = record[33].strip()
self.addr_code1 = record[34].strip()
self.addr_code2 = record[35].strip()
self.dr_zip_code = record[36].strip()
self.dr_addr = record[37].strip()
self.dr_addr_kana = record[38].strip()
self.dr_addr_num = record[39]
self.dr_addr_kanj_cnt1 = record[40]
self.dr_addr_kanj_cnt2 = record[41]
self.dr_addr_kanj_cnt3 = record[42]
self.dr_addr_kanj_cnt4 = record[43]
self.dr_addr_kana_cnt1 = record[44]
self.dr_addr_kana_cnt2 = record[45]
self.dr_addr_kana_cnt3 = record[46]
self.dr_addr_kana_cnt4 = record[47]
self.dr_tel = record[48].strip()
self.use_stop_flag = record[49].strip()
self.use_stopc_ode = record[50].strip()
self.cre_stop_date = record[51].strip()
self.release_date = record[52].strip()
self.pract_class_code = record[53].strip()
self.pract_yearera = record[54].strip()
self.pract_year = record[55].strip()
self.bskregst_flag = record[56].strip()
# DCFPCF医師コード
self.dcf_pcf_dr_cd = ''.join([self.dcfdr_id, self.dcfdr_code, self.dcfd_yobi])
# 住所(町字)コード
self.addr_village_cd = ''.join([self.pref_code, self.city_code, self.addr_code1, self.addr_code2])
# 住所カウントカナ
self.addr_cnt_kana = ''.join([self.dr_addr_kana_cnt1.zfill(2), self.dr_addr_kana_cnt2.zfill(2), self.dr_addr_kana_cnt3.zfill(2), self.dr_addr_kana_cnt4.zfill(2)])
# 住所カウント
self.addr_cnt = ''.join([self.dr_addr_kanj_cnt1.zfill(2), self.dr_addr_kanj_cnt2.zfill(2), self.dr_addr_kanj_cnt3.zfill(2), self.dr_addr_kanj_cnt4.zfill(2)])
# 相手先重複コード
self.opp_dup_code = ''.join([self.reptdr_id, self.reptdr_code, self.reptdr_yobi])
self.birth_day = '' # 生年月日(西暦)
self.estab_y = '' # 開業年(西暦)
self.grad_y = '' # 卒業年(西暦)
self.drday_y = '' # 登録年(西暦)
self.era_cd = '' # 元号コード
# 住所(集合項目)
self.address_aggregation_items = [
self.pref_code,
self.city_code,
self.addr_code1,
self.addr_code2,
self.dr_zip_code,
self.dr_addr_kana,
self.dr_addr_num,
self.dr_addr_kanj_cnt1,
self.dr_addr_kanj_cnt2,
self.dr_addr_kanj_cnt3,
self.dr_addr_kanj_cnt4,
self.dr_addr_kana_cnt1,
self.dr_addr_kana_cnt2,
self.dr_addr_kana_cnt3,
self.dr_addr_kana_cnt4
]
# 診療科目(集合項目)
self.medsbj_code_items = [
self.medsbj_code1,
self.medsbj_code2,
self.medsbj_code3,
self.medsbj_code4,
self.medsbj_code5]

View File

@ -0,0 +1,28 @@
from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable
class ComDrSosiety(UltmarcTable):
"""レイアウト区分521: COM_所属学会"""
dcf_dr_id: str # レコードID
dcf_dr_code: str # 個人コード
dcf_dr_yobi: str # 個人コード(予備)
maint_flag: str # 修正区分
sosiety_cd: str # 学会コード
cont_flag: str # 予備/所属学会メンテ区分
sosiety_f: str # 学会年度
dcf_pcf_dr_cd: str # DCFPCF医師コード
# メンテナンス年月日 と 予備/転送年月日 は未使用
def __init__(self, record: list[str]):
super().__init__(record)
self.dcf_dr_id = record[1]
self.dcf_dr_code = record[2]
self.dcf_dr_yobi = record[3].strip()
self.maint_flag = record[4]
self.sosiety_cd = record[5]
self.cont_flag = record[6]
self.sosiety_f = record[9]
# DCFPCF医師コード(レコードID + 個人コード + 個人コード(予備))
self.dcf_pcf_dr_cd = ''.join([self.dcf_dr_id, self.dcf_dr_code, self.dcf_dr_yobi])

View File

@ -0,0 +1,49 @@
from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable
class ComDrWrkplace(UltmarcTable):
"""レイアウト区分502 :COM_医師勤務先"""
maint_flag: str # 修正区分
dcfdr_id: str # 個人コードID
dcfdr_code: str # 個人コード(個人コード)
dcfdr_yobi: str # 個人コード(予備)
hp_id: str # 施設コードID
hp_code: str # 施設コード(施設コード)
hp_yobi: str # 施設コード(予備)
drretflag: str # 予備/退職異動区分
maintdate: str # メンテナンス年月日
trndate: str # 予備/転送年月日
postcode: str # 役職コード
identitycode: str # 大学職位
sectcode: str # 所属部科コード
sectname: str # 所属部科(漢字)
sectname_kana: str # 所属部科(カナ)
notdm_flg: str # DM不可フラグ
full_dcfdr_code: str # 個人ID+個人コード+個人コード予備
full_hp_code: str # 施設ID+施設コード+施設コード予備
def __init__(self, record: list[str]):
super().__init__(record)
self.maintflag = record[4]
self.dcfdr_id = record[1]
self.dcfdr_code = record[2]
self.dcfdr_yobi = record[3].strip()
self.hp_id = record[5]
self.hp_code = record[6]
self.hp_yobi = record[7].strip()
self.drretflag = record[8]
self.maintdate = record[9]
self.trndate = record[10]
self.postcode = record[11].strip()
self.identitycode = record[12].strip()
# 所属部科の集合項目
self.sectcode = record[13].strip()
self.sectname = record[14].strip()
self.sectname_kana = record[15].strip()
self.notdm_flg = record[16].strip()
# ID、コード、予備を結合してフル桁コードに変換
self.full_dcfdr_code = ''.join([self.dcfdr_id, self.dcfdr_code, self.dcfdr_yobi])
self.full_hp_code = ''.join([self.hp_id, self.hp_code, self.hp_yobi])

View File

@ -0,0 +1,14 @@
from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable
class ComForfrontMedEquip(UltmarcTable):
"""レイアウト区分022: COM_先端医療機器"""
hi_medicmach_code: str # 先進医療機器コード
hi_medicmach_name: str # 先端医療機器名
maint_flag: str # 修正区分
def __init__(self, record: list[str]):
super().__init__(record)
self.hi_medicmach_code = record[1]
self.hi_medicmach_name = record[5]
self.maint_flag = record[2]

View File

@ -0,0 +1,16 @@
from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable
class ComHamtec(UltmarcTable):
"""レイアウト区分021: COM_高度先進医療"""
maint_flag: str # 修正区分
hamtec_cd: str # 高度先進医療コード
hamtec_div: str # 高度先進医療区分
hamtec_name: str # 高度先進医療名
def __init__(self, record: list[str]):
super().__init__(record)
self.maint_flag = record[3]
self.hamtec_cd = record[1]
self.hamtec_div = record[2]
self.hamtec_name = record[6]

View File

@ -0,0 +1,14 @@
from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable
class ComHpAssrt(UltmarcTable):
"""レイアウト区分002: 病院種別"""
hp_assrt_cd: str # 病院種別コード
hp_assrt_name: str # 病院種別名
maint_flag: str # 修正区分
def __init__(self, record: list[str]):
super().__init__(record)
self.hp_assrt_cd = record[1]
self.maint_flag = record[2]
self.hp_assrt_name = record[5]

Some files were not shown because too many files have changed in this diff Show More