diff --git a/ecs/jskult-webapp/src/controller/bio_download.py b/ecs/jskult-webapp/src/controller/bio_download.py index 454ff857..8ff711c8 100644 --- a/ecs/jskult-webapp/src/controller/bio_download.py +++ b/ecs/jskult-webapp/src/controller/bio_download.py @@ -60,8 +60,12 @@ async def download_bio_data( logger.info('検索結果が0件です') return {'status': 'ok', 'download_url': None} + # ファイルに打ち出すカラムを抽出 + # TODO: SQLクエリを修正するため、この処理は不要になる + extract_df = _extract_output_df(search_result_df) + # ファイルを書き出し(Excel or CSV) - local_file_path = _write_bio_data_to_file(bio_service, download_param, search_result_df, download_file_name) + local_file_path = _write_bio_data_to_file(bio_service, download_param, extract_df, download_file_name) # ローカルファイルからS3にアップロードし、ダウンロード用URLを取得する try: @@ -112,6 +116,27 @@ def _search_bio_data(bio_service: BioViewService, search_param: BioModel, user_i return search_result_df, query +def _extract_output_df(search_result_df: pd.DataFrame) -> pd.DataFrame: + extract_df = search_result_df[constants.BIO_EXTRACT_COLUMNS] + + # 値を変換 + # データ種別の正式名を設定 + extract_df.loc[:, 'slip_org_kbn'] = extract_df['slip_org_kbn'].apply( + lambda key: constants.SLIP_ORG_KBN_FULL_NAME.get(key)) + # データ区分の区分の日本語名を設定 + extract_df.loc[:, 'data_kbn'] = extract_df['data_kbn'].apply(lambda key: constants.DATA_KBN_JP_NAME.get(key)) + # ロット番号エラーフラグの日本語名を設定 + extract_df.loc[:, 'lot_num_err_flg'] = extract_df['lot_num_err_flg'].apply( + lambda key: constants.LOT_NO_ERR_FLG_JP_NAME.get(key)) + # 訂正前伝票管理番号がセットされているときのみ修正日時、修正者、エラー詳細種別をセット + extract_df.loc[:, 'ins_dt'] = extract_df['bef_slip_mgt_num'].apply( + lambda bef_slip_mgt_num: extract_df['ins_dt'] if bef_slip_mgt_num is not None else '') + extract_df.loc[:, 'ins_usr'] = extract_df['bef_slip_mgt_num'].apply( + lambda bef_slip_mgt_num: extract_df['ins_usr'] if bef_slip_mgt_num is not None else '') + + return extract_df + + def _write_bio_data_to_file( bio_service: BioViewService, download_param: BioDownloadModel, diff --git a/ecs/jskult-webapp/src/data/BioData_template.xlsx b/ecs/jskult-webapp/src/data/BioData_template.xlsx index ec1575a2..4a6292ff 100644 Binary files a/ecs/jskult-webapp/src/data/BioData_template.xlsx and b/ecs/jskult-webapp/src/data/BioData_template.xlsx differ diff --git a/ecs/jskult-webapp/src/model/db/bio_sales_lot.py b/ecs/jskult-webapp/src/model/db/bio_sales_view.py similarity index 61% rename from ecs/jskult-webapp/src/model/db/bio_sales_lot.py rename to ecs/jskult-webapp/src/model/db/bio_sales_view.py index ff62af4b..325ccbbc 100644 --- a/ecs/jskult-webapp/src/model/db/bio_sales_lot.py +++ b/ecs/jskult-webapp/src/model/db/bio_sales_view.py @@ -4,54 +4,71 @@ from typing import Optional from src.model.db.base_db_model import BaseDBModel -class BioSalesLotDBModel(BaseDBModel): - slip_mgt_num: Optional[str] +class BioSalesViewModel(BaseDBModel): conv_cd: Optional[int] + rec_data: Optional[str] rec_whs_cd: Optional[str] rec_whs_sub_cd: Optional[str] rec_whs_org_cd: Optional[str] + rec_cust_cd: Optional[str] rec_comm_cd: Optional[str] rec_tran_kbn: Optional[str] + rev_hsdnymd_wrk: Optional[str] rev_hsdnymd_srk: Optional[str] rec_urag_num: Optional[str] rec_comm_name: Optional[str] rec_nonyu_fcl_name: Optional[str] rec_nonyu_fcl_addr: Optional[str] rec_lot_num: Optional[str] + rec_qty: Optional[str] rec_ymd: Optional[str] + sale_data_cat: Optional[str] + slip_file_name: Optional[str] + slip_mgt_num: Optional[str] + row_num: Optional[int] + hsdn_ymd: Optional[str] + exec_dt: Optional[str] v_tran_cd: Optional[int] tran_kbn_name: Optional[str] whs_org_cd: Optional[str] - v_whsorg_cd: Optional[int] + v_whsorg_cd: Optional[str] whs_org_name: Optional[str] + whs_org_kn: Optional[str] v_whs_cd: Optional[int] whs_name: Optional[str] nonyu_fcl_cd: Optional[str] v_inst_cd: Optional[str] v_inst_kn: Optional[str] - v_inst_name: Optional[str] + v_inst_nm: Optional[str] v_inst_addr: Optional[str] comm_cd: Optional[str] product_name: Optional[str] - whs_rep_comm_name: Optional[str] - whs_rep_nonyu_fcl_name: Optional[str] - whs_rep_nonyu_fcl_addr: Optional[str] + whs_rep_comm_nm: Optional[str] + whs_rep_nnskfcl_nm: Optional[str] + whs_rep_nnsk_fcl_addr: Optional[str] mkr_inf_1: Optional[str] mkr_cd: Optional[str] - qty: Optional[int] + htdnymd_err_kbn: Optional[str] + prd_exis_kbn: Optional[str] + fcl_exis_kbn: Optional[str] + amt: Optional[int] slip_org_kbn: Optional[str] bef_slip_mgt_num: Optional[str] lot_no_err_flg: Optional[str] iko_flg: Optional[str] + kjyo_ym: Optional[str] + tksnbk_kbn: Optional[str] + fcl_exec_kbn: Optional[str] rec_sts_kbn: Optional[str] ins_dt: Optional[datetime] ins_usr: Optional[str] - dwh_upd_dt: Optional[datetime] + dcf_inst_cd: Optional[str] inst_cd: Optional[str] inst_name_form: Optional[str] address: Optional[str] - tel_num: Optional[str] + tel_no: Optional[str] data_kbn: Optional[str] - data_kind: Optional[str] - err_dtl_kind: Optional[str] + ser_no: Optional[str] + lot_num: Optional[str] expr_dt: Optional[date] + amt_fugo: Optional[str] diff --git a/ecs/jskult-webapp/src/model/db/pharmacy_product_master.py b/ecs/jskult-webapp/src/model/db/pharmacy_product_master.py index 35181012..2f498246 100644 --- a/ecs/jskult-webapp/src/model/db/pharmacy_product_master.py +++ b/ecs/jskult-webapp/src/model/db/pharmacy_product_master.py @@ -4,5 +4,4 @@ from src.model.db.base_db_model import BaseDBModel class PharmacyProductMasterModel(BaseDBModel): - mkr_cd: Optional[str] mkr_cd_name: Optional[str] diff --git a/ecs/jskult-webapp/src/model/view/bio_disp_model.py b/ecs/jskult-webapp/src/model/view/bio_disp_model.py index dd9c2bb0..e78d4f29 100644 --- a/ecs/jskult-webapp/src/model/view/bio_disp_model.py +++ b/ecs/jskult-webapp/src/model/view/bio_disp_model.py @@ -1,8 +1,19 @@ -from src.model.db.bio_sales_lot import BioSalesLotDBModel +from src.model.db.bio_sales_view import BioSalesViewModel +from src.system_var import constants from src.util.sanitize import sanitize @sanitize -class BisDisplayModel(BioSalesLotDBModel): - def __init__(self, param: BioSalesLotDBModel) -> None: +class BisDisplayModel(BioSalesViewModel): + def __init__(self, param: BioSalesViewModel) -> None: super().__init__(**param.dict()) + + # 区分・フラグの正式名称を設定 + self.slip_org_kbn = constants.SLIP_ORG_KBN_FULL_NAME.get(self.slip_org_kbn) + self.data_kbn = constants.DATA_KBN_JP_NAME.get(self.data_kbn) + self.lot_no_err_flg = constants.LOT_NO_ERR_FLG_JP_NAME.get(self.lot_no_err_flg) + + # 訂正前伝票管理番号がセットされているときのみ修正日時、修正者、エラー詳細種別をセット + if (self.bef_slip_mgt_num is None): + self.ins_dt = "" + self.ins_usr = "" diff --git a/ecs/jskult-webapp/src/model/view/bio_view_model.py b/ecs/jskult-webapp/src/model/view/bio_view_model.py index 57d5f153..8f5e4875 100644 --- a/ecs/jskult-webapp/src/model/view/bio_view_model.py +++ b/ecs/jskult-webapp/src/model/view/bio_view_model.py @@ -23,7 +23,7 @@ class BioViewModel(BaseModel): def display_wholesaler_names(self): display_names = [ - f'{whs_model.rec_whs_cd}-{whs_model.rec_whs_sub_cd}:{whs_model.name or ""}' + f'{whs_model.rec_whs_cd}-{whs_model.rec_whs_sub_cd}:{whs_model.name}' for whs_model in self.whs_models ] return display_names @@ -45,38 +45,15 @@ class BioViewModel(BaseModel): '0': '正常', '1': 'ロットエラー', '3': 'ロット不明', - '9': 'エラー(解消済み)', + '9': 'エラー(解消済)', '2': '除外' } ) def bio_data_json_str(self): - """生物由来ロット分解データの検索結果を指定された件数ごとに分割しながら返す""" def date_handler(obj): - """json.dumpsの日付項目のフォーマットハンドラ""" return obj.isoformat() if hasattr(obj, 'isoformat') else obj - - search_data_list = [model.dict() for model in self.bio_data] - search_data_len = len(search_data_list) - # 呼び出し一回あたりの分割数 - part_size = 500 - for i in range(0, search_data_len, part_size): - json_str = json.dumps(search_data_list[i:i + part_size], ensure_ascii=False, default=date_handler) - # JavaScriptに埋め込むため、クォートをエスケープ - json_str = json_str.replace("'", "\\'") - json_str = json_str.replace('\\"', '\\\\"') - yield json_str - - def make_whs_name(self): - if not self.is_form_submitted(): - return '' - if self.form_data.rec_whs_cd is None: - return '' - - form_wholesaler_full_name = \ - f'{self.form_data.rec_whs_cd}-{self.form_data.rec_whs_sub_cd}:{self.form_data.whs_name}' - - return form_wholesaler_full_name + return json.dumps([model.dict() for model in self.bio_data], ensure_ascii=False, default=date_handler) def is_selected_whs_name(self, selected_wholesaler): if not self.is_form_submitted(): diff --git a/ecs/jskult-webapp/src/repositories/bio_sales_lot_repository.py b/ecs/jskult-webapp/src/repositories/bio_sales_view_repository.py similarity index 75% rename from ecs/jskult-webapp/src/repositories/bio_sales_lot_repository.py rename to ecs/jskult-webapp/src/repositories/bio_sales_view_repository.py index 28a59ea5..46eb2b91 100644 --- a/ecs/jskult-webapp/src/repositories/bio_sales_lot_repository.py +++ b/ecs/jskult-webapp/src/repositories/bio_sales_view_repository.py @@ -1,7 +1,7 @@ from src.db import sql_condition as condition from src.db.sql_condition import SQLCondition from src.logging.get_logger import get_logger -from src.model.db.bio_sales_lot import BioSalesLotDBModel +from src.model.db.bio_sales_view import BioSalesViewModel from src.model.request.bio import BioModel from src.repositories.base_repository import BaseRepository from src.util.string_util import is_not_empty @@ -9,59 +9,37 @@ from src.util.string_util import is_not_empty logger = get_logger('生物由来参照') -class BioSalesLotRepository(BaseRepository): +class BioSalesViewRepository(BaseRepository): FETCH_SQL = """\ SELECT - data_kind, - slip_mgt_num, - rec_ymd, - rec_whs_cd, - rec_whs_sub_cd, - whs_name, - rec_whs_org_cd, - rec_urag_num, - rev_hsdnymd_srk, - rec_tran_kbn, - tran_kbn_name, - mkr_cd, - rec_comm_cd, - product_name, - whs_rep_comm_name, - nonyu_fcl_cd, - rec_nonyu_fcl_name, - whs_rep_nonyu_fcl_name, - rec_nonyu_fcl_addr, - whs_rep_nonyu_fcl_addr, - rec_lot_num, - qty, - expr_dt, - data_kbn, - err_dtl_kind, - bef_slip_mgt_num, - ins_usr, - ins_dt, - inst_cd, - inst_name_form, - address, - tel_num, - v_whs_cd, - v_whsorg_cd, - whs_org_name, - v_tran_cd, - iko_flg + ( + CASE + WHEN LEFT(bs.v_tran_cd, 1) = 2 + AND bs.qty >= 1 THEN CONCAT('-', bs.qty) + ELSE bs.qty + END + ) AS amt_fugo, + bs.*, + ln.ser_num, + ln.lot_num, + ln.expr_dt FROM - src05.bio_sales_lot + src05.bio_sales_view bs + LEFT OUTER JOIN + src05.lot_num_mst ln + ON bs.mkr_cd = ln.ser_num + AND bs.rec_lot_num = ln.lot_num WHERE {where_clause} ORDER BY - rec_whs_cd, - rec_whs_sub_cd, - rev_hsdnymd_srk, - slip_mgt_num + bs.rec_whs_cd, + bs.rec_whs_sub_cd, + bs.rev_hsdnymd_srk, + bs.slip_mgt_num ASC\ """ - def fetch_many(self, parameter: BioModel) -> list[BioSalesLotDBModel]: + def fetch_many(self, parameter: BioModel) -> list[BioSalesViewModel]: try: self._database.connect() logger.debug('DB参照実行') @@ -70,7 +48,7 @@ class BioSalesLotRepository(BaseRepository): logger.debug(f'SQL: {query}') result = self._database.execute_select(query, parameter.dict()) logger.debug(f'count= {len(result)}') - models = [BioSalesLotDBModel(**r) for r in result] + models = [BioSalesViewModel(**r) for r in result] return models except Exception as e: logger.exception(f"DB Error : Exception={e.args}") @@ -115,8 +93,8 @@ class BioSalesLotRepository(BaseRepository): if is_not_empty(parameter.rec_lot_num): rec_lot_num = parameter.rec_lot_num # あいまい検索文字列('%')が含まれる場合は'LIKE'、でなければ'='で検索 - rec_lot_num_comparator = condition.LIKE if '%' in rec_lot_num else condition.EQ - where_clauses.append(SQLCondition('TRIM(rec_lot_num)', rec_lot_num_comparator, 'rec_lot_num')) + rec_lot_num_comparator = condition.LIKE if rec_lot_num in '%' else condition.EQ + where_clauses.append(SQLCondition('rec_lot_num', rec_lot_num_comparator, 'rec_lot_num')) # データ区分 if is_not_empty(parameter.data_kbn): where_clauses.append(SQLCondition('data_kbn', condition.EQ, 'data_kbn')) diff --git a/ecs/jskult-webapp/src/repositories/pharmacy_product_master_repository.py b/ecs/jskult-webapp/src/repositories/pharmacy_product_master_repository.py index c2bd95ed..a430ee67 100644 --- a/ecs/jskult-webapp/src/repositories/pharmacy_product_master_repository.py +++ b/ecs/jskult-webapp/src/repositories/pharmacy_product_master_repository.py @@ -9,7 +9,6 @@ class PharmacyProductMasterRepository(BaseRepository): FETCH_SQL = """\ SELECT - t1.mkr_cd, CONCAT(IFNULL(t1.mkr_cd, ''), ' ', IFNULL(t1.mkr_inf_1, '')) AS mkr_cd_name FROM src05.phm_prd_mst_v t1 diff --git a/ecs/jskult-webapp/src/services/bio_view_service.py b/ecs/jskult-webapp/src/services/bio_view_service.py index f77a6a5b..d1102598 100644 --- a/ecs/jskult-webapp/src/services/bio_view_service.py +++ b/ecs/jskult-webapp/src/services/bio_view_service.py @@ -12,7 +12,7 @@ from src.model.request.bio import BioModel from src.model.view.bio_disp_model import BisDisplayModel from src.model.view.bio_view_model import BioViewModel from src.repositories.base_repository import BaseRepository -from src.repositories.bio_sales_lot_repository import BioSalesLotRepository +from src.repositories.bio_sales_view_repository import BioSalesViewRepository from src.repositories.pharmacy_product_master_repository import \ PharmacyProductMasterRepository from src.repositories.wholesaler_master_repository import \ @@ -27,7 +27,7 @@ class BioViewService(BaseService): REPOSITORIES = { 'whs_repository': WholesalerMasterRepository, 'phm_repository': PharmacyProductMasterRepository, - 'bio_sales_repository': BioSalesLotRepository + 'bio_sales_repository': BioSalesViewRepository } CLIENTS = { @@ -36,7 +36,7 @@ class BioViewService(BaseService): whs_repository: WholesalerMasterRepository phm_repository: PharmacyProductMasterRepository - bio_sales_repository: BioSalesLotRepository + bio_sales_repository: BioSalesViewRepository s3_client: S3Client def __init__(self, repositories: dict[str, BaseRepository], clients: dict[str, AWSAPIClient]) -> None: @@ -119,9 +119,6 @@ class BioViewService(BaseService): logger.info(parameter_message) access_logger.info(parameter_message) - # ログファイルクローズ - access_log_handler.close() - # S3にアップロード self.upload_bio_access_log_file(access_log_file_path) @@ -156,16 +153,14 @@ class BioViewService(BaseService): header_df = pd.DataFrame([header_data], index=None) output_df = pd.concat([header_df, data_frame]) # ヘッダー行としてではなく、1レコードとして出力する - output_df.to_csv(output_file_path, index=False, header=False, encoding="utf-8_sig") + output_df.to_csv(output_file_path, index=False, header=False) return output_file_path def upload_bio_data_file(self, local_file_path: str) -> None: bucket_name = environment.BIO_ACCESS_LOG_BUCKET - - dt_now = datetime.now() - ymd = f'{dt_now.year}/{dt_now.strftime("%m")}/{dt_now.strftime("%d")}' - file_key = f'data/{ymd}/{os.path.basename(local_file_path)}' + # TODO: ファイルパスにYYYY/MM/DDを加える + file_key = f'data/{os.path.basename(local_file_path)}' self.s3_client.upload_file(local_file_path, bucket_name, file_key) # アップロード後、ローカルからは削除する @@ -173,10 +168,8 @@ class BioViewService(BaseService): def upload_bio_access_log_file(self, local_file_path: str) -> None: bucket_name = environment.BIO_ACCESS_LOG_BUCKET - - dt_now = datetime.now() - ymd = f'{dt_now.year}/{dt_now.strftime("%m")}/{dt_now.strftime("%d")}' - file_key = f'log/{ymd}/{os.path.basename(local_file_path)}' + # TODO: ファイルパスにYYYY/MM/DDを加える + file_key = f'log/{os.path.basename(local_file_path)}' self.s3_client.upload_file(local_file_path, bucket_name, file_key) # アップロード後、ローカルからは削除する @@ -184,10 +177,8 @@ class BioViewService(BaseService): def generate_download_file_url(self, local_file_path: str, user_id: str, kind: str) -> str: bucket_name = environment.BIO_ACCESS_LOG_BUCKET - - dt_now = datetime.now() - ymd = f'{dt_now.year}/{dt_now.strftime("%m")}/{dt_now.strftime("%d")}' - file_key = f'data/{ymd}/{os.path.basename(local_file_path)}' + # TODO: ファイルパスにYYYY/MM/DDを加える + file_key = f'data/{os.path.basename(local_file_path)}' download_filename = f'{user_id}_生物由来卸販売データ.{kind}' return self.s3_client.generate_presigned_url(bucket_name, file_key, download_filename) diff --git a/ecs/jskult-webapp/src/static/css/bioStyle.css b/ecs/jskult-webapp/src/static/css/bioStyle.css index 0eadc543..7ecde3c5 100644 --- a/ecs/jskult-webapp/src/static/css/bioStyle.css +++ b/ecs/jskult-webapp/src/static/css/bioStyle.css @@ -81,25 +81,9 @@ table{ .bioScroll_div { overflow: auto; - white-space: nowrap; margin-top: 1%; - margin-bottom: 1%; - width: 100%; height: 250px; -} -.bioScroll_div::-webkit-scrollbar { - height: 5px; - width: 10px; -} - -.bioScroll_div::-webkit-scrollbar-track { - border-radius: 5px; - background: #eee; -} - -.bioScroll_div::-webkit-scrollbar-thumb { - border-radius: 5px; - background: #666; + width: 1132px; } .noLine{ diff --git a/ecs/jskult-webapp/src/system_var/constants.py b/ecs/jskult-webapp/src/system_var/constants.py index 7be637b9..a50d498e 100644 --- a/ecs/jskult-webapp/src/system_var/constants.py +++ b/ecs/jskult-webapp/src/system_var/constants.py @@ -5,11 +5,49 @@ BATCH_STATUS_PROCESSING = '1' # 日付テーブル.dump取得状態区分:未処理 DUMP_STATUS_UNPROCESSED = '0' -# 生物由来照会 - BIO_TEMPORARY_FILE_DIR_PATH = path.join(path.curdir, 'src', 'data') BIO_EXCEL_TEMPLATE_FILE_PATH = path.join(BIO_TEMPORARY_FILE_DIR_PATH, 'BioData_template.xlsx') +BIO_EXTRACT_COLUMNS = [ + 'slip_org_kbn', + 'slip_mgt_num', + 'rec_ymd', + 'rec_whs_cd', + 'rec_whs_sub_cd', + 'whs_name', + 'rec_whs_org_cd', + 'rec_urag_num', + 'rev_hsdnymd_srk', + 'rec_tran_kbn', + 'tran_kbn_name', + 'mkr_cd', + 'rec_comm_cd', + 'product_name', + 'whs_rep_comm_name', + 'nonyu_fcl_cd', + 'rec_nonyu_fcl_name', + 'whs_rep_nonyu_fcl_name', + 'rec_nonyu_fcl_addr', + 'whs_rep_nonyu_fcl_addr', + 'rec_lot_num', + 'amt_fugo', + 'expr_dt', + 'data_kbn', + 'lot_num_err_flg', + 'bef_slip_mgt_num', + 'ins_usr', + 'ins_dt', + 'inst_cd', + 'inst_name_form', + 'address', + 'tel_num', + 'v_whs_cd', + 'v_whsorg_cd', + 'whs_org_name', + 'v_tran_cd', + 'iko_flg' +] + BIO_CSV_HEADER = [ 'データ種別', '伝票管理NO', @@ -47,7 +85,7 @@ BIO_CSV_HEADER = [ 'Veeva卸組織コード', '卸組織名', 'Veeva取引区分コード', - '2017年11月以前データ' + '移行' ] SLIP_ORG_KBN_FULL_NAME = { diff --git a/ecs/jskult-webapp/src/templates/bioSearchList.html b/ecs/jskult-webapp/src/templates/bioSearchList.html index 4dafce34..ae7a3d7c 100644 --- a/ecs/jskult-webapp/src/templates/bioSearchList.html +++ b/ecs/jskult-webapp/src/templates/bioSearchList.html @@ -5,16 +5,16 @@ {% include '_header.html' %} {% endwith %} - - @@ -52,14 +52,16 @@ 処理日: - ~ - @@ -74,7 +76,7 @@ @@ -84,7 +86,7 @@ {% for phm in bio.phm_models %} {% endfor %} @@ -94,14 +96,16 @@ 発伝年月日: - ~ - @@ -126,9 +130,9 @@
- +
- + @@ -165,7 +169,7 @@ - + @@ -182,18 +186,6 @@ {% endif %} - - - - - - - - - - - -
データ種別 伝票管理NO 処理日Veeva卸組織コード 卸組織名 Veeva取引区分コード2017年11月以前データ移行