From a49a6162354471801af7f961de7434323ad8798a Mon Sep 17 00:00:00 2001 From: "mori.k" Date: Wed, 28 May 2025 17:52:59 +0900 Subject: [PATCH] =?UTF-8?q?=E5=85=B1=E9=80=9A=E5=87=A6=E7=90=86=E3=81=A8?= =?UTF-8?q?=E5=8F=82=E8=80=83=E5=85=83=E3=81=AE=E3=82=BD=E3=83=BC=E3=82=B9?= =?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=89=E3=81=AE=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/batch/trn_result_data_bio_lot.py | 446 +++++++++++++++++- 1 file changed, 444 insertions(+), 2 deletions(-) diff --git a/ecs/jskult-batch/src/batch/trn_result_data_bio_lot.py b/ecs/jskult-batch/src/batch/trn_result_data_bio_lot.py index d0142cbc..df122320 100644 --- a/ecs/jskult-batch/src/batch/trn_result_data_bio_lot.py +++ b/ecs/jskult-batch/src/batch/trn_result_data_bio_lot.py @@ -1,10 +1,452 @@ +import json +from src.aws.s3 import JskTransferListBucket +from src.manager.jskult_batch_run_manager import JskultBatchRunManager +from src.manager.jskult_batch_status_manager import JskultBatchStatusManager +from src.manager.jskult_hdke_tbl_manager import JskultHdkeTblManager from src.batch.jskult_batch_entrypoint import JskultBatchEntrypoint +from src.db.database import Database +from src.error.exceptions import (BatchOperationException, + MaxRunCountReachedException) +from src.system_var import environment +from src.logging.get_logger import get_logger + + + +logger = get_logger('生物由来卸販売ロット分解') + class TrnResultDataBioLot(JskultBatchEntrypoint): def __init__(self): super().__init__() def execute(self): - # TODO: ここで生物由来ロット分解処理を実行する - pass + """生物由来卸販売ロット分解""" + logger.info('生物由来卸販売ロット分解処理開始') + + + jskult_hdke_tbl_manager = JskultHdkeTblManager() + jskult_batch_run_manager = JskultBatchRunManager( + environment.BATCH_EXECUTION_ID) + if not jskult_hdke_tbl_manager.can_run_process(): + logger.error( + '日次バッチ処理中またはdump取得が正常終了していないため、生物由来卸販売ロット分解処理を終了します。') + # バッチ実行管理テーブルをfailedで登録 + jskult_batch_run_manager.batch_failed() + return + + # 業務日付を取得 + _, _, process_date = jskult_hdke_tbl_manager.get_batch_statuses() + + # 転送ファイル一覧を取得し、転送件数を取得 + try: + transfer_list_bucket = JskTransferListBucket() + transfer_list_file_path = transfer_list_bucket.download_transfer_result_file( + process_date) + except Exception as e: + logger.exception(f'転送ファイル一覧の取得に失敗しました。 {e}') + # バッチ実行管理テーブルをfailedで登録 + jskult_batch_run_manager.batch_failed() + + with open(transfer_list_file_path) as f: + transfer_list = json.load(f) + + # 実消化データ + アルトマークデータの転送件数を合算し、受信ファイル件数とする + receive_file_count = len( + transfer_list['jsk_transfer_list']) + len(transfer_list['ult_transfer_list']) + + jskult_batch_status_manager = JskultBatchStatusManager( + environment.PROCESS_NAME, + # TODO チケットNEWDWH2021-1847の実装で作成した定数に置き換え + 'post_process', + environment.MAX_RUN_COUNT, + receive_file_count + ) + try: + + jskult_batch_status_manager.set_process_status("start") + try: + if not jskult_batch_status_manager.can_run_post_process(): + # 後続処理の起動条件を満たしていない場合 + # 処理ステータスを「処理待」に設定 + jskult_batch_status_manager.set_process_status("waiting") + + # バッチ実行管理テーブルに「retry」で登録 + jskult_batch_run_manager.batch_retry() + + return + except MaxRunCountReachedException: + logger.info('最大起動回数に到達したため、生物由来卸販売ロット分解処理を実行します。') + + jskult_batch_status_manager.set_process_status("doing") + db = Database.get_instance() + try: + db.connect() + db.begin() + # 生物由来ロット分解データの未確定データを削除する + self._delete_not_confirm_data_in_bio_sales_lot(db) + # 生物由来ロット分解データを作成する + self._insert_bio_sales_lot(db) + # 生物由来ロット分解データの不要レコードを削除する + self._delete_empty_lot_record(db) + # 製造ロット管理番号マスタから有効期限を生物由来ロット分解データにセットする + self._set_expr_dt_from_lot_num_mst(db) + db.commit() + logger.info('生物由来卸販売ロット分解処理終了') + return + except Exception as e: + db.rollback() + raise BatchOperationException(e) + finally: + db.disconnect() + + # 処理が全て正常終了した際に、バッチ実行管理テーブルに「success」で登録 + logger.info("生物由来卸販売ロット分解処理を正常終了します。") + jskult_batch_run_manager.batch_success() + jskult_batch_status_manager.set_process_status("done") + + return + + except Exception as e: + # 何らかのエラーが発生した際に、バッチ実行管理テーブルに「failed」で登録 + logger.exception(f'予期せぬエラーが発生したため、生物由来卸販売ロット分解処理を終了します。{e}') + jskult_batch_run_manager.batch_failed() + jskult_batch_status_manager.set_process_status("failed") + + + def _delete_not_confirm_data_in_bio_sales_lot(self, db: Database): + logger.info('生物由来ロット分解データの未確定データ削除開始') + try: + sql = """ + DELETE lot FROM src07.trn_result_data_bio_lot AS lot + INNER JOIN src07.trn_result_data_bio AS bio + ON bio.slip_mgt_num = lot.slip_mgt_num + AND DATE(bio.dwh_upd_dt) >= src07.get_syor_date() + """ + res = db.execute(sql) + except Exception as e: + logger.info('生物由来ロット分解データの未確定データ削除に失敗') + raise e + logger.info('生物由来ロット分解データの未確定データ削除に成功') + + + def _insert_bio_sales_lot(self, db: Database): + logger.info('生物由来ロット分解データの作成開始') + try: + sql = """ + INSERT INTO src07.bio_sales_lot + SELECT + bio.slip_mgt_num AS slip_mgt_num, + conv.conv_cd AS conv_cd, + bio.rec_whs_cd AS rec_whs_cd, + bio.rec_whs_sub_cd AS rec_whs_sub_cd, + bio.rec_whs_org_cd AS rec_whs_org_cd, + bio.rec_comm_cd AS rec_comm_cd, + bio.rec_tran_kbn AS rec_tran_kbn, + bio.rev_hsdnymd_srk AS rev_hsdnymd_srk, + bio.rec_urag_num AS rec_urag_num, + bio.rec_comm_name AS rec_comm_name, + bio.rec_nonyu_fcl_name AS rec_nonyu_fcl_name, + bio.rec_nonyu_fcl_addr AS rec_nonyu_fcl_addr, + -- 3レコードに分解する + CASE conv.conv_cd + WHEN 1 THEN bio.rec_lot_num1 + WHEN 2 THEN bio.rec_lot_num2 + WHEN 3 THEN bio.rec_lot_num3 + END AS rec_lot_num, + bio.rec_ymd AS rec_ymd, + bio.v_tran_cd AS v_tran_cd, + bio.tran_kbn_name AS tran_kbn_name, + bio.whs_org_cd AS whs_org_cd, + bio.v_whsorg_cd AS v_whsorg_cd, + bio.whs_org_name AS whs_org_name, + bio.v_whs_cd AS v_whs_cd, + bio.whs_name AS whs_name, + bio.nonyu_fcl_cd AS nonyu_fcl_cd, + bio.v_inst_cd AS v_inst_cd, + bio.v_inst_kn AS v_inst_kn, + bio.v_inst_name AS v_inst_name, + bio.v_inst_addr AS v_inst_addr, + bio.comm_cd AS comm_cd, + bio.product_name AS product_name, + bio.whs_rep_comm_name AS whs_rep_comm_name, + bio.whs_rep_nonyu_fcl_name AS whs_rep_nonyu_fcl_name, + bio.whs_rep_nonyu_fcl_addr AS whs_rep_nonyu_fcl_addr, + /* 製品名と製品コードは後ほどV製品マスタからセットする */ + -- 製品名 + NULL AS mkr_inf_1, + -- 製品コード + NULL AS mkr_cd, + -- 数量 + -- Veeva取引区分の先頭が「2」の場合、マイナス表示にする + CASE conv.conv_cd + WHEN 1 THEN + CASE + WHEN (LEFT(bio.v_tran_cd, 1) = 2 AND bio.qty1 >= 1) THEN -bio.qty1 + ELSE bio.qty1 + END + WHEN 2 THEN + CASE + WHEN (LEFT(bio.v_tran_cd, 1) = 2 AND bio.qty2 >= 1) THEN -bio.qty2 + ELSE bio.qty2 + END + WHEN 3 THEN + CASE + WHEN (LEFT(bio.v_tran_cd, 1) = 2 AND bio.qty3 >= 1) THEN -bio.qty3 + ELSE bio.qty3 + END + END AS qty, + bio.slip_org_kbn AS slip_org_kbn, + bio.bef_slip_mgt_num AS bef_slip_mgt_num, + CASE conv.conv_cd + WHEN 1 THEN bio.err_flg11 + WHEN 2 THEN bio.err_flg12 + WHEN 3 THEN bio.err_flg13 + END AS lot_no_err_flg, + CASE bio.err_flg20 + WHEN 'M' THEN '*' + ELSE NULL + END AS iko_flg, + CASE bio.rec_sts_kbn + WHEN '0' THEN bio.rec_sts_kbn + WHEN '1' THEN + CASE conv.conv_cd + WHEN 1 THEN bio.err_flg11 + WHEN 2 THEN bio.err_flg12 + WHEN 3 THEN bio.err_flg13 + END + END AS rec_sts_kbn, + CASE + WHEN bio.bef_slip_mgt_num IS NOT NULL THEN bio.ins_dt + ELSE NULL + END AS ins_dt, + CASE + WHEN bio.bef_slip_mgt_num IS NOT NULL THEN bio.ins_usr + ELSE NULL + END AS ins_usr, + bio.dwh_upd_dt AS dwh_upd_dt, + /* 施設情報は後ほどセットする */ + -- 施設コード + NULL AS inst_cd, + -- 正式施設名(漢字) + NULL AS inst_name_form, + -- 施設住所 + NULL AS address, + -- 施設電話番号 + NULL AS tel_num, + CASE conv.conv_cd + WHEN 1 THEN + CASE bio.err_flg11 + WHEN '0' THEN '正常' + WHEN '1' THEN 'ロットエラー' + WHEN '2' THEN 'ロットエラー' + WHEN '3' THEN 'エラー(解消済)' + WHEN '4' THEN 'ロット不明' + WHEN '5' THEN 'エラー(解消済)' + WHEN '6' THEN 'ロット不明' + WHEN '7' THEN '除外' + WHEN '8' THEN '除外' + WHEN 'Z' THEN '除外' + END + WHEN 2 THEN + CASE bio.err_flg12 + WHEN '0' THEN '正常' + WHEN '1' THEN 'ロットエラー' + WHEN '2' THEN 'ロットエラー' + WHEN '3' THEN 'エラー(解消済)' + WHEN '4' THEN 'ロット不明' + WHEN '5' THEN 'エラー(解消済)' + WHEN '6' THEN 'ロット不明' + WHEN '7' THEN '除外' + WHEN '8' THEN '除外' + WHEN 'Z' THEN '除外' + END + WHEN 3 THEN + CASE bio.err_flg13 + WHEN '0' THEN '正常' + WHEN '1' THEN 'ロットエラー' + WHEN '2' THEN 'ロットエラー' + WHEN '3' THEN 'エラー(解消済)' + WHEN '4' THEN 'ロット不明' + WHEN '5' THEN 'エラー(解消済)' + WHEN '6' THEN 'ロット不明' + WHEN '7' THEN '除外' + WHEN '8' THEN '除外' + WHEN 'Z' THEN '除外' + END + END AS data_kbn, + CASE bio.slip_org_kbn + WHEN 'J' THEN 'JD-NET' + WHEN 'N' THEN 'NHI' + WHEN 'H' THEN '手入力' + END AS data_kind, + CASE conv.conv_cd + WHEN 1 THEN + CASE bio.err_flg11 + WHEN '0' THEN '正常' + WHEN '1' THEN 'ロットエラー' + WHEN '2' THEN '日付エラー' + WHEN '3' THEN 'ロットエラー(解消済)' + WHEN '4' THEN 'ロットエラー(調査不能)' + WHEN '5' THEN '日付エラー(解消済)' + WHEN '6' THEN '日付エラー(調査不能)' + WHEN '7' THEN '除外(卸都合)' + WHEN '8' THEN '除外(再送信)' + WHEN 'Z' THEN '過去データ' + END + WHEN 2 THEN + CASE bio.err_flg12 + WHEN '0' THEN '正常' + WHEN '1' THEN 'ロットエラー' + WHEN '2' THEN '日付エラー' + WHEN '3' THEN 'ロットエラー(解消済)' + WHEN '4' THEN 'ロットエラー(調査不能)' + WHEN '5' THEN '日付エラー(解消済)' + WHEN '6' THEN '日付エラー(調査不能)' + WHEN '7' THEN '除外(卸都合)' + WHEN '8' THEN '除外(再送信)' + WHEN 'Z' THEN '過去データ' + END + WHEN 3 THEN + CASE bio.err_flg13 + WHEN '0' THEN '正常' + WHEN '1' THEN 'ロットエラー' + WHEN '2' THEN '日付エラー' + WHEN '3' THEN 'ロットエラー(解消済)' + WHEN '4' THEN 'ロットエラー(調査不能)' + WHEN '5' THEN '日付エラー(解消済)' + WHEN '6' THEN '日付エラー(調査不能)' + WHEN '7' THEN '除外(卸都合)' + WHEN '8' THEN '除外(再送信)' + WHEN 'Z' THEN '過去データ' + END + END AS err_dtl_kind, + NULL AS expr_dt + FROM + src05.bio_sales bio + -- 生物由来変換マスタ + CROSS JOIN src07.bio_conv conv + WHERE + bio.err_flg1 = '0' + AND bio.err_flg2 = '0' + AND bio.err_flg3 = '0' + AND bio.err_flg4 = '0' + AND bio.err_flg5 = '0' + AND bio.err_flg6 = '0' + AND bio.err_flg7 = '0' + AND bio.err_flg8 = '0' + AND bio.err_flg9 = '0' + AND bio.err_flg10 = '0' + AND bio.rec_sts_kbn <> '99' + AND DATE(bio.dwh_upd_dt) >= src05.get_syor_date() + """ + res = db.execute(sql) + + except Exception as e: + logger.info('生物由来ロット分解データの作成に失敗') + raise e + logger.info('生物由来ロット分解データの作成に成功') + + + def _delete_empty_lot_record(self, db: Database): + logger.info('生物由来ロット分解データの製造番号が空のレコードを削除開始') + try: + sql = """ + DELETE FROM src07.bio_sales_lot lot + WHERE + -- 空白15桁のデータはロット情報が空とみなして削除する + lot.rec_lot_num = REPEAT(' ', 15) OR lot.rec_lot_num IS NULL + """ + res = db.execute(sql) + except Exception as e: + logger.info('生物由来ロット分解データの製造番号が空のレコードを削除に失敗') + raise e + logger.info('生物由来ロット分解データの製造番号が空のレコードを削除に成功') + + + def _set_inst_info_from_mdb_or_mst_inst(self, db: Database): + logger.info('MDB変換マスタビュー(生物由来ロット分解処理用)、メルク施設マスタから施設情報を生物由来ロット分解データにセット開始') + try: + sql = """ + UPDATE + src07.bio_sales_lot bio + LEFT OUTER JOIN internal05.view_mdb_cnv_mst mdb + ON bio.v_inst_cd = mdb.hco_vid_v + LEFT OUTER JOIN src05.mst_inst inst + ON bio.v_inst_cd = inst.inst_cd + SET + -- 施設コード + bio.inst_cd = ( + CASE + WHEN mdb.mdb_cd IS NOT NULL THEN mdb.mdb_cd + ELSE bio.v_inst_cd + END + ), + -- 正式施設名(漢字) + bio.inst_name_form = ( + CASE + WHEN mdb.mdb_cd IS NOT NULL THEN mdb.inst_name_form + ELSE inst.inst_name_form + END + ), + -- 施設住所 + bio.address = ( + CASE + WHEN mdb.mdb_cd IS NOT NULL THEN mdb.address + ELSE inst.address + END + ), + -- 施設電話番号 + bio.tel_num = ( + CASE + WHEN mdb.mdb_cd IS NOT NULL THEN mdb.tel_num + ELSE inst.tel_num + END + ) + """ + res = db.execute(sql) + except Exception as e: + logger.info('MDB変換マスタビュー(生物由来ロット分解処理用)、メルク施設マスタから施設情報を生物由来ロット分解データにセットに失敗') + raise e + logger.info('MDB変換マスタビュー(生物由来ロット分解処理用)、メルク施設マスタから施設情報を生物由来ロット分解データにセットに成功') + + + def _set_prd_info_from_v_prd_mst(self, db: Database): + logger.info('V製品マスタから製品情報を生物由来ロット分解データにセット開始') + try: + sql = """ + UPDATE + src07.bio_sales_lot bio + LEFT OUTER JOIN src05.phm_prd_mst_v prd + ON bio.comm_cd = prd.prd_cd + AND STR_TO_DATE(bio.rev_hsdnymd_srk,'%Y%m%d') BETWEEN prd.start_date AND prd.end_date + AND prd.rec_sts_kbn <> '9' + SET + bio.mkr_inf_1 = prd.mkr_inf_1, + bio.mkr_cd = prd.mkr_cd + """ + res = db.execute(sql) + except Exception as e: + logger.info('V製品マスタから製品情報を生物由来ロット分解データにセットに失敗') + raise e + logger.info('V製品マスタから製品情報を生物由来ロット分解データにセットに成功') + + + def _set_expr_dt_from_lot_num_mst(self, db: Database): + # 製造ロット管理番号マスタから有効期限をセット + logger.info('製造ロット管理番号マスタから有効期限をセット開始') + try: + sql = """ + UPDATE + src07.bio_sales_lot bio + LEFT OUTER JOIN src05.lot_num_mst lot + ON bio.mkr_cd = lot.ser_num + AND bio.rec_lot_num = lot.lot_num + SET + bio.expr_dt = lot.expr_dt + """ + res = db.execute(sql) + except Exception as e: + logger.info('製造ロット管理番号マスタから有効期限をセットに失敗') + raise e + logger.info('製造ロット管理番号マスタから有効期限をセットに成功')